Surfaced while fixing the class-save data loss (CatholicOS/ontokit-web#361). Not the data-loss bug itself — that one is being fixed separately — but the same family, and worth recording rather than leaving as folklore.
The divergence
get_class_detail has two implementations:
- indexed (
ontokit/services/ontology_index.py) returns whatever the indexer captured, so it surfaces any annotation predicate present on the class.
- RDFLib fallback (
ontokit/services/ontology.py, _class_to_response) iterates the fixed ANNOTATION_PROPERTIES allowlist.
The allowlist is narrower. Verified: skos:related (and by the same logic skos:broader, skos:narrower, and anything else outside the dict) is not in ANNOTATION_PROPERTIES. So for a class carrying skos:related, the indexed path returns it and the fallback does not.
The same class returns a different predicate set depending on whether the index happens to be warm.
How it surfaced
The parity test added alongside the #361 fix originally included skos:related in its fixture and failed on exactly this. The implementing worker removed that triple as an "invalid fixture assumption" — a defensible call to keep the fix focused, and it reported the removal honestly rather than hiding it. But the underlying inconsistency is real and is now untested.
Severity: lower than it looks, but non-zero
The web-side fix for #361 makes updateClassInTurtle round-trip safe, so a predicate missing from the API response is no longer destroyed on save — it is merely invisible in the editor. That downgrades this from data loss to a display/consistency gap.
It still matters because:
- the response is non-deterministic from the client's perspective — same class, different answer depending on index warmth;
- it is the identical shape as the #361 root cause: two code paths that are supposed to agree, silently disagreeing, with the discrepancy only appearing under real-world conditions;
- any future consumer that trusts the annotation set (export, diff, validation, translation coverage) inherits the inconsistency.
Suggested direction
Pick one and make it explicit:
- Widen the fallback to return all annotation predicates rather than an allowlist, matching the indexed path; or
- Narrow the indexed path to the same allowlist, if the allowlist is a deliberate product decision about what counts as an annotation.
Either way, derive both paths from one definition so they cannot drift, and restore skos:related to the parity fixture so the guarantee is tested.
Option 1 is likely correct — an allowlist that silently hides predicates present in the user's ontology is surprising, especially for a tool whose job is round-tripping OWL.
Surfaced while fixing the class-save data loss (CatholicOS/ontokit-web#361). Not the data-loss bug itself — that one is being fixed separately — but the same family, and worth recording rather than leaving as folklore.
The divergence
get_class_detailhas two implementations:ontokit/services/ontology_index.py) returns whatever the indexer captured, so it surfaces any annotation predicate present on the class.ontokit/services/ontology.py,_class_to_response) iterates the fixedANNOTATION_PROPERTIESallowlist.The allowlist is narrower. Verified:
skos:related(and by the same logicskos:broader,skos:narrower, and anything else outside the dict) is not inANNOTATION_PROPERTIES. So for a class carryingskos:related, the indexed path returns it and the fallback does not.The same class returns a different predicate set depending on whether the index happens to be warm.
How it surfaced
The parity test added alongside the #361 fix originally included
skos:relatedin its fixture and failed on exactly this. The implementing worker removed that triple as an "invalid fixture assumption" — a defensible call to keep the fix focused, and it reported the removal honestly rather than hiding it. But the underlying inconsistency is real and is now untested.Severity: lower than it looks, but non-zero
The web-side fix for #361 makes
updateClassInTurtleround-trip safe, so a predicate missing from the API response is no longer destroyed on save — it is merely invisible in the editor. That downgrades this from data loss to a display/consistency gap.It still matters because:
Suggested direction
Pick one and make it explicit:
Either way, derive both paths from one definition so they cannot drift, and restore
skos:relatedto the parity fixture so the guarantee is tested.Option 1 is likely correct — an allowlist that silently hides predicates present in the user's ontology is surprising, especially for a tool whose job is round-tripping OWL.