Ontology sync mechanics
Ontology sync mechanics
Section titled “Ontology sync mechanics”Mechanic 3 of 5. How the closed base vocabulary and a future client overlay combine into
the ontology.json that ships inside every bundle, so a bundle is self-describing and
portable.
Source of truth: scripts/cocoindex_pipeline/producer/bundle_writer.py:762-791
(materialisation); scripts/cocoindex_pipeline/producer/validator.py:182-212 (the base
register); lib/ontology/ (the TS register + generated tuple); DR-027
(reference/decision-register.md).
The DR-027 ruling
Section titled “The DR-027 ruling”DR-027 (accepted S441): the base system controlled vocabularies move out of the docs-site into the canonical repo — they version with the linter that enforces them, because Platform functionality must not couple to the docs-site. Client overlay CVs are client-owned. And crucially: every bundle repo carries the materialised effective ontology (pinned base snapshot + client overlay) so a bundle is self-describing without reaching back to any Platform system.
There are therefore three ontology surfaces, and it is important not to conflate them:
| Surface | Where | Role |
|---|---|---|
| Base register (Python) | validator.py ALLOWED_ENTITY_TYPES / ALLOWED_RELATIONSHIP_TYPES (:182-212) | the closed vocabulary the linter gates against, and the materialisation source |
| Register (docs-site markdown + TS) | ${KH_PRIVATE_DOCS_DIR}/…/ontology/*.md, lib/ontology/ | the human contract + build-time tuple; a development mirror post-DR-027 |
Materialised ontology.json | inside each bundle | the shipped, self-describing effective ontology (base + overlay) |
The materialised artefact
Section titled “The materialised artefact”Every run writes one ontology.json at the bundle root (write_ontology_artefact,
bundle_writer.py:762-791). Its shape is deliberately plain JSON, not a bespoke ontology
DSL — the {132.10} brief was explicit not to invent an ontology format, only to serialise
the already-ratified vocabulary:
{ "base": { "entity_types": [ "capability", "certification", "framework", "methodology", "organisation", "person", "product", "project", "regulation", "sector", "standard", "technology" ], "relationship_types": [ "complies_with", "delivers_to", "demonstrated_by", "evidences", "holds", "part_of", "references", "requires", "supersedes", "uses" ] }, "overlay": null}That is the actual ontology.json from the published Platform bundle: 12 entity types +
10 relationship types under base, and overlay: null.
Where base comes from
Section titled “Where base comes from”_base_ontology_snapshot (bundle_writer.py:660-677) sources the base directly from
validator.py’s ALLOWED_ENTITY_TYPES / ALLOWED_RELATIONSHIP_TYPES — the same closed
12-entity / 10-relation register the linter already gates every concept write against (see
Semantic-linter gate). It is not invented in the writer; it is a
serialisation of the ratified vocabulary. This closes the loop: the ontology a bundle
declares is exactly the ontology its concepts were validated against.
The client overlay is currently stubbed
Section titled “The client overlay is currently stubbed”overlay is nested under its own key when supplied by a future per-client config
(write_ontology_artefact, bundle_writer.py:762-791). No such config exists in-repo
yet — the code flags this explicitly, and the writer emits an explicit overlay: null
placeholder rather than omitting the key:
# bundle_writer.py:783-786payload = { "base": _base_ontology_snapshot(), "overlay": dict(client_overlay) if client_overlay is not None else None,}The null is deliberate signalling, not an accident: a bundle consumer can distinguish “no
overlay shipped yet” (overlay: null) from “a base-only artefact IS the full effective
ontology” — it is never left to silently assume the latter.
Populating the overlay is {132.34} (pending). Until it lands, every bundle ships
overlay: null. Do not document a client-overlay flow as if it were live.
PENDING: self-contained JSON-LD projection (bl-457)
Section titled “PENDING: self-contained JSON-LD projection (bl-457)”Decided 2026-07-15; implementation is a next-session concern — this is NOT live. bl-457
adds a self-contained JSON-LD @context / IRI projection over ontology.json: an additive
layer that gives every base and overlay term a stable IRI, so a bundle’s ontology is
consumable as linked data without a network fetch. The base+overlay split extends to
namespaces — base terms resolve to a platform-owned shared stable namespace, client/overlay
terms to a per-client namespace, with deterministic auto-mint and overlay→base promotion
keeping a sameAs link; base IRIs are version-less. Namespace authority is central
(platform-owned) — the bundle carries only a materialised inline copy of the @context,
in keeping with DR-027’s self-carrying posture. Do not document a JSON-LD flow as if it were
shipped; until bl-457 lands, ontology.json remains the plain base/overlay JSON above.
Provenance-consumable-source nuance (traceable)
Section titled “Provenance-consumable-source nuance (traceable)”The materialisation reads the Python frozensets in validator.py, not the TS
lib/ontology/concept-schema.ts, because the TS register has no Python-consumable export
yet (_base_ontology_snapshot docstring, bundle_writer.py:660-677; the {132.10} brief).
When id-133 promotes the register to a first-class allowed_types / allowed_relations
register with a Python-consumable export, the two constants are meant to be swapped for a load
from that export with no call-site change. Today they are hand-mirrored frozensets kept in
lockstep with extraction.py’s Pydantic Literals by the parity guards described in
Semantic-linter gate.
Deploy-time seeding is a separate concern
Section titled “Deploy-time seeding is a separate concern”Materialising ontology.json into a bundle at producer run time (this mechanic) is distinct
from seeding the ontology into a new client deploy, which is owned by {45.10} (see the
{132.15} journal S453 note: the ontology becomes part of a new client deploy, and the
Platform private OKF repo is the promotion source client deploys promote FROM). This page
documents the per-bundle materialised artefact only; deploy-time seeding is future work
tracked elsewhere — do not author it here.