Filed for the record and deliberately P2. Nothing here blocks anything today.
What was measured
The rule-set docs list owl:propertyChainAxiom among the rules that materialize in practice. On 0.6.22 it does not fire. Canonical OWL spec example, otherwise-empty graph:
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix ex: <http://example.org/pc#> .
ex:hasParent a owl:ObjectProperty .
ex:hasBrother a owl:ObjectProperty .
ex:hasUncle a owl:ObjectProperty ; owl:propertyChainAxiom ( ex:hasParent ex:hasBrother ) .
ex:alice ex:hasParent ex:bob . ex:bob ex:hasBrother ex:carl .
asserted triples 10
rdf:first / rdf:rest present 4 the collection parsed correctly
materialize(g,'owl-rl') 11 inferred
reasoner_errors NONE
ex:alice ex:hasUncle ?x NOTHING
It reports success and does not do the thing. No error, healthy JSONB. A caller cannot distinguish fired from ignored without asserting the expected triple and checking for it.
Tested three ways before filing: inline in a mixed fixture, standalone with every property typed owl:ObjectProperty, and the minimal canonical case above. Six other entailments derive correctly in the same graph — hasValue, someValuesFrom, TransitiveProperty, inverseOf, equivalentClass, subClassOf transitivity — so the reasoner is running and the fixture is sound.
Cause — not a fork, not a version
My first guess was the pinned fork. That was wrong. The crate source settles it:
reasonable, across lib/ cli/ python/
propertyChainAxiom / property_chain 0 mentions
hasValue 18
inverseOf 11
TransitiveProperty 3
Never implemented, in any version. The engine behaves exactly as built. The docs describe OWL 2 RL the profile — which does include property chains — rather than the rules the crate implements.
Ask, in order of cost
- Correct the docs. Separate "OWL 2 RL, the specification" from "the rules this engine implements", and name property chains as out of scope. Cheapest, and it is the part that actually cost something: a downstream design decision was made on the strength of the measurement, and had the docs been trusted instead, a vocabulary would have shipped that silently derives nothing.
- Optionally raise it upstream on the reasoner crate with this fixture attached. Someone who is not us may implement it.
- Only if module composition later demands it — a scoped 2-hop rule. The general n-hop case is genuinely hard in Datalog; 2-hop is a fixed-arity join and covers essentially every practical use. Not recommended now.
Workaround in use
A SPARQL sequence path is not available as a fallback:
?x ex:hasParent/ex:hasBrother ?z ERROR: sparql: blank-node object in query not supported
?x ex:hasParent* ?z works
?x ex:hasParent ?y . ?y ex:hasBrother ?z works
The error message is misleading — that query contains no blank node; a sequence path is presumably desugared to an intermediate bnode and the check fires on the desugared form. * paths work, so it is specific to sequence.
We are proceeding with the explicit one-hop join and asserting the closure where needed. Correct, forfeits the for free property, and costs one triple per instance. At the current number of modules that is not measurable.
A self-testing fixture is available on request.
Filed for the record and deliberately P2. Nothing here blocks anything today.
What was measured
The rule-set docs list
owl:propertyChainAxiomamong the rules that materialize in practice. On0.6.22it does not fire. Canonical OWL spec example, otherwise-empty graph:It reports success and does not do the thing. No error, healthy JSONB. A caller cannot distinguish fired from ignored without asserting the expected triple and checking for it.
Tested three ways before filing: inline in a mixed fixture, standalone with every property typed
owl:ObjectProperty, and the minimal canonical case above. Six other entailments derive correctly in the same graph —hasValue,someValuesFrom,TransitiveProperty,inverseOf,equivalentClass,subClassOftransitivity — so the reasoner is running and the fixture is sound.Cause — not a fork, not a version
My first guess was the pinned fork. That was wrong. The crate source settles it:
Never implemented, in any version. The engine behaves exactly as built. The docs describe OWL 2 RL the profile — which does include property chains — rather than the rules the crate implements.
Ask, in order of cost
Workaround in use
A SPARQL sequence path is not available as a fallback:
The error message is misleading — that query contains no blank node; a sequence path is presumably desugared to an intermediate bnode and the check fires on the desugared form.
*paths work, so it is specific to sequence.We are proceeding with the explicit one-hop join and asserting the closure where needed. Correct, forfeits the for free property, and costs one triple per instance. At the current number of modules that is not measurable.
A self-testing fixture is available on request.