Design review · rebuttal

rdfs:domain doesn’t check a subject — it converts it.

Design-choices §2.6 says: declare rdfs:domain and rdfs:range on every property, so tools can read the property’s signature and reasoners can use the type inference. This rebuttal makes one narrow claim: a domain declaration is an inference rule, not a signature and not a check. Signatures belong in metadata. Checking belongs in SHACL. The axiom should be the deliberate exception — because over messy integration data, one bad triple can make the whole model inconsistent.

01 — THE DECISION, AND WHAT’S ACTUALLY CONTESTED

Agreed: every property needs a signature. Contested: the signature as an axiom.

design-choices §2.6 — as written

Declare rdfs:domain and rdfs:range on every property. Exception: when a property’s valid subjects span unrelated classes, omit rdfs:domain and add an rdfs:comment naming the intended union.

Its supports: (1) declaring domain/range “makes the type inferences available to reasoners”; (2) it “helps map generators understand the property’s signature”; (3) union domains are avoided because “anything that uses the property would be inferred to be a member of the union type” — a comment is “the safer choice.”

Much of this is right, and it stays. Every property should say what it applies to. Tools should be able to read that. And the exception — cross-cutting properties get no domain — is the right instinct. Even §2.6’s opening “critical nuance” is exemplary: it says plainly that domain and range are inferential, not validating, and that the reasoner “does not reject the assertion” — it re-types the subject instead. The dispute is only with the sentence that follows all of that: “declare them on every property” — and with hiding the excepted signatures in free-text comments.

Thesis

A signature documents a property. A validation rule checks data. rdfs:domain does neither — it tells the reasoner to re-type whatever uses the property. Declare signatures with schema:domainIncludes/rangeIncludes, enforce them with SHACL, and keep domain/range axioms for the few properties where that inference is actually wanted.

02 — THE ROOT ISSUE

A domain axiom infers types; it does not check them

In OWL, rdfs:domain C on property P means: everything that uses P as a subject is a C — so infer that. It never filters, never warns, never rejects. The rule most modelers actually have in mind — “only policies should carry a policy number” — is a rule about what data is allowed. The axiom cannot express that. §2.6’s own “critical nuance” paragraph says exactly this; the decision then mandates the axiom everywhere anyway.

Now put that in this ontology’s real environment. Its stated purpose is integrating messy source systems (the “Definition of Good” companion is entirely about imperfect source schemas). §2.3 declares disjointness between sibling classes across the model, and §4.1 runs OWL consistency checks. Finding F4 traces what happens when those three rules meet one bad triple: a source feed uses a property on the wrong kind of subject → the domain axiom silently re-types that subject → the new type clashes with a disjointness axiom → the whole ontology becomes inconsistent. In OWL, an inconsistent ontology entails everything — every query answer and every inference, model-wide, is now meaningless. One bad record does not fail; the model does.

  • What the modeler meant: “flag any non-policy that carries policyNumber.” A per-record check with a clear error message — a SHACL shape.
  • What the axiom does: “whatever carries policyNumber is a Policy.” A silent re-typing — until disjointness turns it into a model-wide failure.

§2.6 writes the warning into its own “critical nuance” — then applies the hazard to every property and points it at integration data.

03 — THE RATIONALE, ANSWERED

Three supports, three problems

Claim 1

“Declaring domain/range makes the type inferences available to reasoners.”

Rebuttal

“Available” is not the same as “useful.” Name the inference before you pay for it. The only thing a domain axiom does with data is conclude: “this subject used the property, so it must belong to the domain class.” On clean, deliberate data that can help. On integration data, it converts data errors into schema facts:

# §2.6 pattern, live over a source feed ins:policyNumber rdfs:domain ins:Policy ; rdfs:range xsd:string . # one glitched triple from a migration: pandc:building-77 ins:policyNumber "P-88112-A" . # → inferred: building-77 a ins:Policy (the domain fires) # → §2.3: Building disjoint with Policy (disjointness fires) # → the ontology is INCONSISTENT — and now entails everything

The same intent written in SHACL gives a per-record report instead of a model-wide failure. sh:targetSubjectsOf states the rule the domain only hints at:

# "only a Policy may carry policyNumber" — said properly ins:PolicyNumberSubjectShape a sh:NodeShape ; sh:targetSubjectsOf ins:policyNumber ; sh:class ins:Policy ; sh:message "Only a Policy may carry policyNumber." . # validator report — one record, named, fixable: # building-77 → sh:ClassConstraintComponent: not an ins:Policy

Where implicit typing genuinely is wanted — a stable structural property fed by trusted data — a domain axiom earns its place. That is a per-property decision, not a default stamped onto every identifier and code field in the model.

Claim 2

“…and helps map generators understand the property’s signature.”

Rebuttal

Tools need metadata, not logic. A signature for generators is structured documentation — exactly what schema:domainIncludes/schema:rangeIncludes provide: machine-readable, able to list several classes, and carrying no inference at all. The schema prefix is already in §1.1’s standard stack. Using a logical axiom as tool documentation is a comment with side effects.

The design’s own exception gives this away. When §2.6 omits a domain, the signature moves into a free-text rdfs:comment (“Domain is union of Policy, Location, Building, Organization…”) — the least machine-readable option available (F20). If map generators really depended on rdfs:domain, every excepted property would break them. If a prose comment is good enough there, the signature never needed to be an axiom anywhere.

Claim 3

“A union domain can cause unintended inference — anything that uses the property would be inferred to be a member of the union type. Omitting the domain and documenting it in a comment is the safer choice.”

Rebuttal

The feared inference is correct — it is exactly what a union domain means (F20). “The subject is one of Policy, Location, Building, or Organization” is the intended statement, correctly inferred. The real defect — that the axiom validates nothing — applies just as much to single-class domains, and more aggressively: rdfs:domain ins:Policy re-types a wrong subject into one specific class instead of a broad union. §2.6 fears the weaker axiom and mandates the stronger one on everything else.

Follow the exception’s own logic and the rule disappears. If a union domain is rejected for “over-constraining inference,” then every rdfs:domain over dirty data over-constrains — the exception is §2.6 behaving correctly, once. And if the subject set really is that union, say it in a checkable way: SHACL sh:or to enforce it, or repeated schema:domainIncludes to document it. A prose comment is neither checkable nor readable by the very generators Claim 2 relies on.

04 — THE SAME PROPERTY, BOTH WAYS

Concretely

The cross-cutting property §2.6 uses as its own example, both ways. As decided — the signature lives in prose:

# §2.6 exception: domain omitted, intent parked in a comment ra:hasRiskObservation a owl:ObjectProperty ; rdfs:range ra:RiskObservation ; rdfs:comment "Domain is union of ins:Policy, pandc:Location, pandc:Building, ins:Organization. OWL union domain omitted to avoid over-constraining inference." . # not enforceable, invisible to generators, impossible to verify — # while every *other* property still carries a live re-typing axiom

Signature as metadata, rule as shape — machine-readable, enforced, and with no inference risk anywhere:

# advisory signature: several classes allowed, no inference ra:hasRiskObservation a owl:ObjectProperty ; schema:domainIncludes ins:Policy , pandc:Location , pandc:Building , ins:Organization ; schema:rangeIncludes ra:RiskObservation . # the enforceable union — checked, not inferred ra:RiskObservationSubjectShape a sh:NodeShape ; sh:targetSubjectsOf ra:hasRiskObservation ; sh:or ( [ sh:class ins:Policy ] [ sh:class pandc:Location ] [ sh:class pandc:Building ] [ sh:class ins:Organization ] ) ; sh:message "Subject must be a Policy, Location, Building, or Organization." . # validator output — violations, not re-typing: # claim-4471 → sh:OrConstraintComponent: subject not in the allowed union

rdfs:domain on every property

  • Silently re-types any wrong subject
  • + §2.3 disjointness: one bad triple breaks the whole model
  • Errors surface far from the record that caused them
  • The check the modeler meant is never actually made
  • Exception hides signatures in free-text comments
  • Cannot express the unions it needs, under its own rule

domainIncludes + SHACL shapes

  • Data errors can never re-type a subject
  • Violations are per-record, named, and fixable
  • Signature readable by generators
  • Unions work: sh:or + repeated domainIncludes
  • Reasoner does only the inference you chose
  • §4.2’s split — OWL reasons, SHACL validates — actually honoured
05 — THE DESIGN AGAINST ITSELF

§2.6 disagrees with its own paragraphs — and with the rest of the doc

As with the code-list decision, most of this argument comes from the design document itself:

  • §2.6’s “critical nuance” already concedes the whole argument: domain/range are “inferential, not validating … the reasoner does not reject the assertion. For validation, use SHACL.” The decision two paragraphs later mandates the non-validating construct on every property.
  • §2.6’s own cross-reference points to “§4.2 (SHACL validates domain constraints that OWL only infers)” — naming SHACL as the layer that does the actual job.
  • §2.6’s own exception is the rule behaving correctly. Its showcase property, ra:hasRiskObservation, ships without a domain — the best-behaved property in the document is the one that breaks the rule.
  • §2.5 already teaches the same lesson for property characteristics: “these are inference rules, not constraints — FunctionalProperty does not reject a second value; it infers the two values are identical.” The identical logic applies to domains; §2.6 forgets it one section later.
  • §2.3’s stated goal is “a loud inconsistency report” instead of silent nonsense — but domain + disjointness delivers neither: silent re-typing when there is no clash, a model-wide failure when there is. A SHACL violation is the loud, local report §2.3 actually wants.
  • F4 (High) flags the live interaction — domain everywhere (§2.6) + disjointness everywhere (§2.3) + OWL consistency checks over integrated data (§4.1) — and recommends exactly this split: the reasoner checks the schema (T-Box); SHACL checks the data (A-Box).
  • F20 (Minor) flags the union rationale as a misreading that teaches authors to fear a sound construct — while the comment-based escape hatch is the least machine-readable option on the table.
06 — THE REVISED RULE

Swap the default and the exception

This is a correction, not a purge: rdfs:domain/rdfs:range keep a legitimate, narrow role. The test is simple — if the reason for the axiom is “documentation” or “validation,” it should not be an axiom. A domain earns its place only where you want its inference to fire.

Proposed §2.6 (revised)

Default: every property declares a machine-readable signature — schema:domainIncludes / schema:rangeIncludes (already in §1.1’s stack) — and the enforceable rule as SHACL: sh:targetSubjectsOf + sh:class (or sh:or for unions), sh:datatype for literals.

Exception: declare rdfs:domain/rdfs:range only where the type inference is deliberately wanted, the property is fed by trusted data (not raw integration feeds), and the domain class has been checked against §2.3’s disjointness axioms. Record the intended inference in the term’s comment.

Datatype ranges: rdfs:range xsd:* on datatype properties can stay — conventional and low-risk — with sh:datatype as the loud, validating twin.

Reasoning discipline (clarify in §4.1): the DL reasoner checks the schema (T-Box); SHACL checks the data (A-Box). The reasoner is never the data-quality gate for integrated instance data.

NeedUse
Tool-readable property signature — the defaultschema:domainIncludes / schema:rangeIncludes
Enforce “only X may carry this property”sh:targetSubjectsOf + sh:class
Cross-cutting subjects (Policy ∪ Location ∪ …)sh:or shape + repeated domainIncludes
Enforce a literal’s typesh:datatype (with rdfs:range xsd:* as convention)
Type inference you actually want, on trusted datardfs:domain / rdfs:range — documented, disjointness-checked

The revision keeps everything §2.6 got right — a signature on every property, the cross-cutting exception’s instinct, SHACL as the validation layer — and gives each job to the construct built for it: metadata for tools, shapes for checking, axioms for the inference you actually chose.