databrickslabs / databrickslabs/ontobricks
SWRL rules with builtin atoms (e.g. swrlb:greaterThanOrEqual) silently infer zero triples — four stacked defects, including a Postgres syntax error on the default Lakebase backend
@benoitcayladbx is already working on this.
Since Sep 17, 2026.
- Dominant language
- Python
- Stars
- 377
- Forks
- 69
- Avg merge
- 7h 42m
- Merged PRs (30d)
- 5
Description
Summary
Attribute-conditioned SWRL rules created in the graphical Business Rules editor never produce inferred triples. The run reports success ("N inferred, 0 errors" — the N being unrelated OWL RL schema entailments), so the failure is silent. We traced it to four independent defects, each fatal on its own, and verified fixes end-to-end.
Reproduction
v0.8.0, any domain with a datatype attribute. Editor-generated rule:
Sailing(?x) ∧ nights(?x, ?nights) ∧ swrlb:greaterThanOrEqual(?nights, 10) → LongSailing(?x)
Run Inference. Expected: one LongSailing type triple per matching instance. Actual: 0, no error surfaced.
A standalone repro script (safe-rule validation, a 3-row fixture whose correct answer is 2, generated-SQL printing) is included in the linked PR as scripts/repro_swrl_builtin_defects.py.
The four defects
SWRLBuiltinRegistrynever matches the editor's own output. Registry keys are bare lowercase names; the editor emits the standardswrlb:prefix.is_builtin("swrlb:greaterThanOrEqual")returns False, so the builtin degrades into a triple-pattern atom.SWRLEngine._build_uri_mapskips datatype properties. Object properties are normalised to the data namespace (<base>/prop) to match the predicates the R2RML sync writes, but classdataPropertiesnever enter the map, sonights(?x, ?n)resolves to the ontology#URI and matches nothing.build_inference_sqlandbuild_materialization_sqlpartition atoms by arity only. A builtin atom becomes a JOIN on a predicate like<base>#greaterThanOrEqual, which cannot exist. (build_violation_sqlalready partitions builtins correctly and routes them through_build_builtin_filters— the inference/materialization builders never got that wiring.)- Builtin
sql_templates are Databricks-dialect only.TRY_CAST(... AS DOUBLE)— Postgres has neitherTRY_CASTnor bareDOUBLE, andLakebaseBase.get_query_translator()returns the generic translator with no dialect. So even with 1–3 fixed, every builtin filter is a syntax error on the default (Lakebase) backend.
Generated SQL before the fix (defects visible):
JOIN <t> a2 ON a2.predicate = 'https://.../PCP#nights' ... -- defect 2 (# vs /)
JOIN <t> a3 ON a3.predicate = 'https://.../PCP#greaterThanOrEqual' ...-- defects 1+3
Verification
- Pristine v0.8.0 + 3-row fixture (expected 2): 0 inferred.
- Fixed branch + fixture: 2/2.
- Fixed branch + a real 2,846-instance graph, expected count computed independently from the source table before any fix: 263/263.
- Existing test suite: the 373 swrl/reasoning/builtin/lakebase unit tests pass unchanged.
Why the existing suite did not catch this
Not a reproach — the gap pattern is worth naming so the fix can close it:
execute_rules is unit-tested against a MagicMock store, so generated SQL
never executes; build_inference_sql is asserted once in the whole suite
(empty params → None, in a Neo4j test); parser tests use only bare builtin
names, never the swrlb: prefix the editor emits; and
test_greater_than_uses_try_cast pins the Databricks-only template as
expected behaviour, which enshrines defect 4. The attached PR adds a
regression file covering all four defects at the translator/registry/engine
level, plus the standalone end-to-end harness.
Environment
v0.8.0 tag, Lakebase (Postgres) graph backend, SQL inference path.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.