ID-132 SPEC — G-OVERLAY-CV: client-overlay ontology path ({132.34})
ID-132 SPEC — G-OVERLAY-CV client-overlay ontology path
Section titled “ID-132 SPEC — G-OVERLAY-CV client-overlay ontology path”Kind: Spec slice — a standalone, ratifiable PRODUCT-level slice that defines numbered,
testable overlay invariants (OV-N) the Orchestrator can ratify and later dispatch
implementation from. It does not implement; it specifies the client-CV-overlay path over
the already-landed DR-027 base-ontology seam (bundle_writer.py:write_ontology_artefact).
Authored: 11/07/2026 · Task Planner (fresh dispatch, {132.34} DESIGN-FIRST slice).
Owner-ratified frame (DR-027 / S441 board R6): “Base system CVs shipped by the product,
client-configured overlays in the client’s repo, both versioned and linted together.”
Governing rulings to respect (cite, not re-litigate): DR-027 (ontology CV medium —
effective ontology ships in the bundle; base source-of-truth in the platform repo; client
overlay client-owned), DR-016 (client-owned bundle git repo; human edits are additive
producer overrides, never destructive mutations), DR-019 (OKF superset posture — the
closed validator-enforced taxonomy is spec-legal producer-side strictness), DR-020 (corpus
two-tier admission; per-value client-widening of the allowed set is legitimate), DR-047
(pipeline degrade-to-re-extraction posture — scoped narrowly; contrasted at OV-5). This slice
formalises; it does not re-open any of those.
Empirical-verification note. This slice introduces no new external-library symbol. The composition path uses Python stdlib only —
json(already imported,bundle_writer.py:139),hashlib(sha256 provenance),pathlib(already imported). The one external-library call in the seam,localfs.declare_file, is unchanged and already carries an EXECUTOR-VERIFY empirical finding against the realcocoindex==1.0.7engine (bundle_writer.py:34-62). All other symbols cited here are internal Canonical Platform surfaces (import-and-call check N/A). NoABSENT/SIGNATURE_DRIFTrisk applies.
Context
Section titled “Context”Code-intelligence orientation (verbatim; repo:'canonical'). Per the Planner code-intel
binding rule; tool outputs quoted verbatim and cross-checked against direct file reads.
gitnexus_query({query:'ontology overlay bundle writer', repo:'canonical'})→"processes": [],"process_symbols": [].definitionssurfaced the exact seam this slice extends, verbatim:Function:…/bundle_writer.py:write_ontology_artefact(startLine 560, endLine 585, module "Producer"),Function:…/bundle_writer.py:write_bundle(615–716), and the two already-shipped overlay testsFunction:…/test_producer_bundle_writer.py:test_write_ontology_artefact_base_only_when_no_overlay(537–545) +…:test_write_ontology_artefact_with_client_overlay(548–554). It also surfaced the linter-side tests…/test_producer_validator.py:test_ontology_lint_rejects_relationship_outside_closed_set(202–204) and…:test_ontology_has_exactly_12_entity_types_and_10_relationship_types(211–213). No overlay read path, format, or lint composition symbol exists — confirming this is net-new capability over an existing write seam.gitnexus_context({name:'write_ontology_artefact', repo:'canonical'})→"uid": "Function:…/bundle_writer.py:write_ontology_artefact","incoming": { "calls": [ { "name": "write_bundle" } ] },"outgoing": { "calls": [ { "name": "_base_ontology_snapshot" } ] },"processes": []. The sole caller iswrite_bundle; the sole callee is_base_ontology_snapshot. So the overlay read/compose layer wires in at exactly one call site (write_bundle) and the base half is a single function (_base_ontology_snapshot).ccc searchfallback: not required — gitnexus + direct read both returned the real surface (a single write seam with two existing tests). No greenfield disclaimer applies.
Direct reads (cross-check) — the seams this slice extends:
bundle_writer.py:545-558_base_ontology_snapshot()— materialises DR-027’s pinned base snapshot fromproducer/validator.py’sALLOWED_ENTITY_TYPES/ALLOWED_RELATIONSHIP_TYPESfrozensets (the SAME closed 12-entity/10-relation register BI-13 gates every concept write against). Returns{"entity_types": sorted(...), "relationship_types": sorted(...)}. It does not currently carry the concept-typevocabulary (ALLOWED_CONCEPT_TYPES).bundle_writer.py:560-585write_ontology_artefact(bundle_dir, *, client_overlay=None)— already accepts aclient_overlaymapping and nests it under theoverlaykey; shipsoverlay: nullas an explicit FLAGGED placeholder when none is supplied (:580) so a consumer can detect “no overlay shipped yet”.- The overlay pass-through is ALREADY landed one level up.
write_bundlealready carries aclient_ontology_overlaykeyword (bundle_writer.py:624) and forwards it verbatim —write_ontology_artefact(bundle_dir, client_overlay=client_ontology_overlay)(bundle_writer.py:714). The actual gaps are therefore not insidewrite_bundle: (a) the sole production callerproducer/flow_def.py:379-385invokeswrite_bundle(resolved_bundle_dir, drafts, reference_drafts, theme_config=…, timestamp=…)and never suppliesclient_ontology_overlay; and (b) nothing readsontology-overlay.jsonfrom the bundle dir to produce that mapping. The whole overlay CHAIN below the read is wired; only the read + its wiring at the flow_def seam is missing (see OV-4, checklist item 2). bundle_writer.py:156-163_RESERVED_BUNDLE_FILENAMES = frozenset({"index.md", "log.md", "ontology.json"})— the bundle-level filenames_existing_concept_paths’srglob("*.md")previous-run keyset scan (:594-613) must never treat as a concept file..jsonfiles are already glob-excluded;.mdbundle-level files (README, index, log) must be listed here or they surface as falseRunSummary.removedentries (this is Rider R1 below).validator.py:177-207the closed register (ALLOWED_ENTITY_TYPES12,ALLOWED_RELATIONSHIP_TYPES10);validator.py:105-107ALLOWED_CONCEPT_TYPES(5:topic/product/company/certification/case_study).validator.py:386-416lint_entity_relation_mentionsreads the two frozensets directly (module constants, no injection point).validator.py:277-285check_type_membershipreadsALLOWED_CONCEPT_TYPESdirectly.validator.py:419-453check_concept/validate_concept— the BI-13 gate; “No concept is written or published unless it passes this gate.”- The linter is a HARD-reject legality gate (
themes/okf-platform/semantic-linter-gate.md, checker-verified 11/07/2026): closed vocabulary → HARD-reject; open dimension → SOFT-WARN. entity_type / relationship / concepttypeare all closed (HARD-reject). This is the load-bearing fact behind OV-5’s fail-loud posture.
Problem. DR-027 ratified a two-part effective ontology: a pinned base snapshot (shipped
by the product, source-of-truth in the canonical repo — landed as _base_ontology_snapshot)
plus a client-configured overlay (client-owned, in the client’s bundle repo). Today only
the base half exists. The per-bundle ontology.json ships overlay: null as an explicit
FLAGGED placeholder; the overlay pass-through through write_bundle → write_ontology_ artefact is landed but fed nothing (the sole production caller flow_def.py:379-385 never
supplies it); and no overlay source format, no producer read path, and no linter composition
exist. This slice specifies all four legs — format+location, producer read/compose, linter
composition, and platform-bundle behaviour — plus two same-module hygiene riders (R1/R2).
Non-goals.
- Blocking {45.9} first client publication. A base-only effective ontology (
overlay: null) is a complete, valid, publishable effective ontology per DR-027’s pinned-snapshot rule (see OV-12). The overlay path is additive capability, never a precondition for the first client to publish. This slice does not gate {45.9}. - Composing the overlay into the id-131 EXTRACTION gate. The extraction-side gate
(
extraction.py’sEntityMentionExtraction.entity_type/RelationshipExtraction. relationshipPydanticLiterals) runs at INGEST, upstream of the producer, and does not have the bundle overlay in hand; per-run extension of PydanticLiterals is an id-131/id-133 design question. This slice wires only the producer-side concept-write gate (see OV-9, OQ-OV-2).extraction.pyis unchanged. - Extending concept-type ROUTING / emission / TS mirror. Overlay-added concept
types are composed into the concept-write GATE’s acceptance only (OV-8). The downstream consumers of concepttype—bundle_write_pathrouting (bundle_writer.py:64-108), frontmatter emission, the TS mirrorlib/ontology/concept-schema.ts, and the OKFCONFORMANCE.md— are not taught overlay types by this slice (see OQ-OV-3). - Editing the base register. The overlay is a per-run additive layer; the base
validator.pyfrozensets and their parity guard (validator.py ↔ extraction.py ↔schemas.ts) are untouched (OV-13). - The accept/edit/reject review UI / human-override store. DR-016-adjacent, id-135 territory. Out of scope.
Behaviour — Overlay invariants (OV-N)
Section titled “Behaviour — Overlay invariants (OV-N)”Scope reality — read at ratification (honest framing). This slice ships a gate + a composed, self-describing artefact, pre-wired for follow-ons — it does not ship an end-to-end-useful custom-ontology capability today, for either dimension:
- Concept
types: the concept-write gate can be taught to accept an overlay-added type (OV-8), but the soleConceptKeyfeeder (sources/l_records.py:list_concepts, six hard-coded per-type methods) never CONSTRUCTS one — so no published concept of a new type appears until a feeder is added (OQ-OV-3).- Entity / relationship types: the concept-write gate can accept overlay-added mentions, but the id-131 EXTRACTION side (Pydantic
Literals) never EMITS them — so no concept carries a new mention until the extraction gate is composed too (OV-9, OQ-OV-2). What this slice DOES deliver and is worth ratifying now: the overlay source contract (format/location/additivity/failure semantics, OV-1..7), the self-describing composedontology.json(OV-6/11 — portable, auditable, DR-027’s whole point), the gate injection point every follow-on needs (OV-8), and platform-bundle + non-blocking guarantees (OV-10/12). The follow-ons (a concept feeder; extraction-gate composition) are named, not hidden.
Each invariant carries an inline
(per DR-NNN)tag where a ruling drives it, and a*Test:*clause the Checker uses as its acceptance criterion. OV-N numbers are append-only.
Overlay source — format + location
Section titled “Overlay source — format + location”-
OV-1 (reserved overlay file at bundle root — DR-016 / DR-027). The client-authored overlay source is a single JSON file at a reserved bundle-root path, recommended
ontology-overlay.json(OQ-OV-1 ratifies the exact name), distinct from the producer-writtenontology.json. It lives IN the client-owned bundle git repo (DR-016), is authored/committed by the client (neverdeclare_file-written by the producer, so it is never orphan-deleted by cocoindex’s reconcile), and is added to_RESERVED_BUNDLE_FILENAMESso no previous-run keyset scan mistakes it for a concept file. Test: a fixture bundle repo withontology-overlay.jsonat its root is read by the producer; the file is in_RESERVED_BUNDLE_FILENAMES; the producer never declares/deletes it; JSON is the accepted format. -
OV-2 (closed additive overlay schema). The overlay is a JSON object with up to two optional keys —
entity_types,relationship_types— each a list of strings (additional vocabulary terms). Missing keys default to empty (no extension for that dimension). The schema is closed: any unknown top-level key (including a singular typo likeentity_type) or a non-list/non-string-list value is a validation failure handled per OV-5 (fail-loud), never silently ignored (OQ-OV-4). Test: an overlay with{"entity_types": ["widget"], "relationship_types": ["partners_with"]}parses; an overlay with an unknown key{"entity_type": ["widget"]}or a non-list value fails per OV-5.AMENDED 2026-08-10 (S550 owner ruling, executed at canonical
20b644468; recorded by id-427 {427.13}). This clause read three optional keys,concept_typesfirst among them, from ratification until now.concept_typesis RETIRED from the overlay. The ground is DR-054 meeting DR-141, not disuse: an overlay dimension exists so a client may WIDEN legality, and DR-141 withdrew the closed, validator-enforced concept-type taxonomy — so there is no legality left for this dimension to widen. DR-141’s own Consequences already name DR-054 as in scope for exactly this amendment.entity_types/relationship_typesstay because they still widen a real gate (validator.EffectiveOntologycomposes them and the BI-13 lint enforces the result).“Nothing reads it” is NOT the ground and must not be re-derived as one — that is the claim DR-027’s S548 amendment exists to stop being re-derived, having been measured false on this same artefact family.
Consequence for the producer.
bundle_writer._validate_overlay_schemanow REFUSES aconcept_typeskey. Because this clause was still ratified and still handed to clients, the refusal shipped a targeted message naming DR-141 rather than the generic unknown-key text, so an author following this document would not be told their key was “unknown”. That contingency is now discharged by this amendment: the targeted branch (_RETIRED_OVERLAY_DIMENSIONSand itsretired_keysarm) is retirable, and removing it is a behaviour change routed to a future subtask, not taken here. -
OV-3 (additive-only — no removal, no redefinition — DR-027 / DR-019 / DR-016). The overlay may only ADD terms to the effective ontology; it may NOT remove or redefine a base term. Justification: (a) the linter is a legality gate, and an additive-only overlay can only widen what is legal — so adding an overlay can never retroactively invalidate an already-published base concept; (b) removal would break the base parity guarantee (validator.py ↔ extraction.py ↔
schemas.ts) and could silently un-gate a term the extraction side still emits (DR-019); (c) it mirrors DR-016’s grain — client input layers additively over the base, never destructively mutates it. An overlay term that restates a base term is an idempotent union no-op (tolerated; MAY soft-warn as a signal of overlay confusion). An overlay that attempts removal (any mechanism — aremove/excludekey, a negation) is a validation failure per OV-5. Test: an overlay restating a base entity type composes to the same effective set (idempotent, no error); an overlay expressing removal fails loudly.
Producer read path + composed artefact
Section titled “Producer read path + composed artefact”-
OV-4 (read the overlay + supply it at the
flow_defseam — DR-027). The overlay pass-through below the read is already landed (write_bundle’sclient_ontology_overlaykwarg:624→write_ontology_artefact:714); the net-new work is the read and its wiring at the producer flow seam. During a producer run, beforeontology.jsonis written, the producer readsontology-overlay.jsonfrom the resolved bundle dir, parses+validates it (OV-2/OV-3/OV-5), and supplies the resulting mapping so it reacheswrite_bundle(..., client_ontology_overlay=<mapping>)— closing the gap that the sole production callerproducer/flow_def.py:379-385currently leaves (it never passes the kwarg). The composed effective ontology is base ∪ overlay per dimension. When the file is absent, the mapping isNoneand the artefact is base-only (overlay: null) — not an error (OV-11, OV-12). Read-site decision (take a position, not an OQ): place the read inwrite_bundleitself — it already performs bundle-dir filesystem reads (_existing_ concept_paths’srgloboverbundle_dir,:594-613) and already owns_RESERVED_BUNDLE_ FILENAMES, so reading one more reserved bundle-root file is cohesive there and keepsflow_def.pya thin composition layer; the alternative (read inflow_def.pyand pass the mapping down) needlessly re-plumbs the kwarg through the call site for no benefit. The base half (_base_ontology_snapshot) and the artefact writer keep their contracts. Test: with an overlay file in the bundle dir,write_bundlecomposes base+overlay intoontology.json; with it absent,ontology.jsonis base-only withoverlay: null;flow_def.py’s producer run exercises the read end-to-end (not only a directwrite_bundleunit call). -
OV-5 (parse/validation failure = FAIL-LOUD, contra DR-047). A present-but-invalid overlay file (invalid JSON, wrong shape, non-list values, unknown key per OV-2, or a removal attempt per OV-3) ABORTS the producer run for that bundle with a clear, actionable error; it never degrades to a base-only or partial ontology silently. Rationale — and the deliberate departure from DR-047: DR-047’s degrade-to-re-extraction is scoped narrowly to
DeserializationErroron memo HITs (stale LMDB cache) and explicitly keeps failure semantics for other errors; it is not a general “degrade on any error” posture. Ontology composition gates legality (HARD-reject gate,semantic-linter-gate.md): a silently-degraded overlay would either over-reject every overlay-dependent concept (base-only gate) or, if the gate fell open, admit illegal concepts — both are silent legality corruption of a published, client-owned artefact. Fail-loud mirrorsresolve-bundle-root.ts’s fail-loud-when-unset posture andvalidate_concept’s raise-on-violation posture. An absent file is NOT a failure (OV-4). Test: a bundle with a malformedontology-overlay.jsonaborts the run with a clear error and publishes no bundle; a bundle with no overlay file runs to a base-only bundle. -
OV-6 (composed-artefact provenance — DR-027 as amended). The materialised
ontology.jsonis self-describing: (a) when an overlay is applied, theoverlaykey records the composed overlay plus provenance — the source filename and a content sha256 — so a consumer can tell base-only from composed and audit which overlay produced the effective set (recommended shape at OQ-OV-6); (b)overlayisnullwhen no file is present. The artefact stays deterministic (json.dumps(..., indent=2, sort_keys=True), already in place). Test: with an overlay present,overlaycarries the overlay terms +source+sha256; absent →null.AMENDED 2026-08-10 (recorded by id-427 {427.13}), in two steps that landed separately. This clause was titled “composed-artefact provenance + all-three-dimension base” and its limb (a) required
_base_ontology_snapshotto be extended to carry all three CV dimensions,concept_typesfromALLOWED_CONCEPT_TYPESalongsideentity_types/relationship_types, “so every dimension is uniformly overlay-extensible”. Its Test requiredontology.json’sbaseto carry all three.- The
basehalf is gone (id-427 {427.11}, executing DR-027’s S546 amendment)._base_ontology_snapshotis DELETED andontology.jsonhas nobasekey at all — the platform’s entity/relationship CVs stay in this repo, versioned with the linter that enforces them, and are no longer asserted to bundle consumers. The old limb (a) and thebaseclause of the Test are therefore unsatisfiable, not merely narrowed. - The
concept_typesdimension is gone (S550 owner ruling). See OV-2’s amendment above for the ground.
What survives is the provenance limb, renumbered above.
overlay: nullis preserved deliberately (OV-10, andlib/okf/bundle-graph.ts’sreadBundleClassSignalreads the present-and-null key rather than falling through to'unknown'). - The
-
OV-7 (effective ontology = deterministic sorted union). For each dimension the effective allowed set is
sorted(set(base) | set(overlay_terms))— a de-duplicated, deterministically ordered union — matching the existing sorted base snapshot so bundle-to-bundle diffs stay stable. Test: base["a","b"]+ overlay["b","c"]composes to effective["a","b","c"](sorted, de-duplicated); re-running with the same inputs yields byte-identicalontology.json.
Linter composition (concept-write gate)
Section titled “Linter composition (concept-write gate)”-
OV-8 (concept-write gate lints against the effective set — DR-020). For a run that composed an overlay, the BI-13 concept-write gate lints against base ∪ overlay, not the bare base frozensets:
check_concept/validate_conceptaccept an optional effective-ontology argument (an object carrying the run’s effectiveentity_types/relationship_types), threaded intolint_entity_relation_mentions(entity/relationship mentions). It defaults to base-only when no overlay is supplied, so every existing call site is unchanged. This is the mechanism by which DR-020’s “a client legitimately widens the allowed set” is realised for concept writes. Test: an overlay-addedentity_type: "widget"passes the gate only when the run’s overlay includes it; the base-only gate (no overlay) rejects the same value. This is the core testStrategy assertion.AMENDED 2026-08-10 (recorded by id-427 {427.13}). This clause was NOT on {427.13}‘s brief; it was found by re-deriving rather than by walking the list, and it was false in two independent ways. As ratified it said the effective-ontology argument carries
concept_types/entity_types/relationship_typesand is “threaded intocheck_type_membership(concepttype) andlint_entity_relation_mentions”, and its Test offered “(or an overlay-added concepttype)” as an alternative subject.check_type_membershipdoes not exist. id-427 {427.5} replaced it withvalidator.check_type_shape, which takes no effective ontology: a concepttypeis a shape-validated open label under DR-141, with no vocabulary to compose against.check_conceptdeliberately no longer threads the argument into the type check at all.EffectiveOntologyhas noconcept_typesfield — it carries exactly two dimensions.
The mechanism OV-8 describes is intact for the two dimensions that still gate anything; only the concept-type limb is withdrawn. This matters beyond the document: the producer docstrings that cite OV-8 (
validator.lint_entity_relation_mentions,bundle_writer.declare_concept,bundle_writer.write_bundle,producer/iri_projection.py’s module docstring) are accurate about what those functions do, and were pointing readers at a clause that was not. -
OV-9 (extraction gate out of scope — non-regression). This slice composes the overlay into the concept-write gate only. The id-131 extraction gate (
extraction.pyPydanticLiterals) is unchanged — its per-run extensibility is an id-131/id-133 coordination follow-on (OQ-OV-2), because extraction runs at ingest, upstream of the producer and the bundle overlay. Test:extraction.py’s entity/relationshipLiterals and its parity tests are untouched by this slice’s diff.
Platform bundle + null/empty semantics
Section titled “Platform bundle + null/empty semantics”-
OV-10 (platform bundle is overlay-less by construction — DR-027). The platform bundle ships
overlay: null, base-only, always: it is the base authority (DR-027 — base source-of-truth in the canonical repo), never a client-overlay consumer. Anontology-overlay.jsonappearing in the platform bundle repo is a configuration error, recommended to fail loudly (OQ-OV-5). Test: a platform-bundle run producesontology.jsonwithoverlay: null; no overlay is composed for the platform bundle. -
OV-11 (
overlay: nullvs empty-overlay are distinct observable states).overlay: nullmeans no overlay file present (or platform bundle) → base-only. A present overlay file that adds nothing (empty object{}or all-empty lists) composes to a base-identical effective set but stamps provenance recording the overlay was present-and-empty (a non-nulloverlayobject with empty term lists +source/sha256). The distinction lets the OKF landing / audit tell “no overlay authored” from “overlay authored, currently adds nothing”. Test: absent file →overlay: null; present-empty file → non-nulloverlayobject with empty term lists and provenance, identical effective allowed-sets to base.
Non-blocking + parity
Section titled “Non-blocking + parity”-
OV-12 ({45.9} non-blocking — DR-027 pinned-snapshot rule). A base-only effective ontology is a complete, valid, publishable effective ontology. A client with no
ontology-overlay.jsonpublishes a base-only bundle (overlay: null), which fully satisfies DR-027. The overlay is additive capability layered on later; it is never a precondition for first client publication ({45.9}). Test: a bundle with no overlay file publishes successfully with a base-onlyontology.json; {45.9} does not depend on this slice landing. -
OV-13 (base parity untouched). The overlay is a per-run additive layer; the base
validator.pyfrozensets (ALLOWED_ENTITY_TYPES/ALLOWED_RELATIONSHIP_TYPES/ALLOWED_CONCEPT_TYPES) and their hand-mirrored parity guard againstextraction.pyandlib/validation/schemas.tsare unchanged. Overlay composition happens over the base at read/compose time, never by editing the base sets. Test: the base frozensets and the validator↔extraction↔schemas parity tests are untouched by this slice’s diff.
Riders (same-module hygiene — S464, fold into the implementation checklist)
Section titled “Riders (same-module hygiene — S464, fold into the implementation checklist)”Two same-module (bundle_writer.py scope) hygiene riders were declared for this subtask’s
dispatch ({132.34} journal, S464, from {132.33} findings). They are empirically durable
regardless of the overlay work but ride this slice because they touch the same file/namespace:
-
Rider R1 (
README.md→_RESERVED_BUNDLE_FILENAMES). Add"README.md"to_RESERVED_BUNDLE_FILENAMES(bundle_writer.py:163) so the committed bundle README stops appearing inRunSummary.removed/ the false"Removed: README.md"log.mdline each run.README.mdis a.mdfile, so — unlikeontology.json— it IS scanned by_existing_concept_paths’srglob("*.md")and MUST be reserved to be excluded (log hygiene + boundary tightening). Fold the newontology-overlay.json(OV-1) into the same reserved set in the same edit for consistency (it is.json, already glob-excluded, but belongs in the reserved set semantically). Test: a bundle run with a committedREADME.mdreports noRemoved: README.mdinlog.md;README.mdandontology-overlay.jsonare both in_RESERVED_BUNDLE_FILENAMES. -
Rider R2 (re-pin ALL stale
flow.py:1665citations →flow.py:1708). The_KH_PIPELINE_DOC_NSnamespace constant now lives atflow.py:1708(verified:grep -n _KH_PIPELINE_DOC_NS scripts/cocoindex_pipeline/flow.py→1708:_KH_PIPELINE_DOC_NS = uuid.UUID("fbfaf1ff-1ee4-583c-9757-1674465b2ec1")). The staleflow.py:1665citation is not a pair — agrep -rn "flow.py:1665"sweep finds at least five live citations, so this rider closes on the grep, not a hand-enumerated list. Known live sites (illustrative, not exhaustive): (i)producer/resource_uri.py:37docstring; (ii)producer/resource_uri.py:74(_seed_contract_namespacedocstring); (iii)scripts/tests/test_producer_resource_uri.py:6; (iv)__tests__/integration/id138-erasure-cascade.integration.test.ts:112(comment); (v) docs-sitespecs/id-138-corpus-durable-home/SEED-CONTRACT.md§2 (line 44). Re-pin every one toflow.py:1708. Explicitly OUT of scope (do NOT rewrite): the ledger provenance records that legitimately narrate the fix history —ledgers/task-list.json+ledgers/tasks/ID-132.md(they record “flow.py 1665->1708” as what WAS fixed) — and this spec’s own R2 text. Test:grep -rn "flow.py:1665"overscripts/,__tests__/,lib/, and the docs-sitespecs/tree returns ZERO hits (excluding the ledger provenance records and this rider’s own text); every re-pinned site now readsflow.py:1708.
Implementation checklist (dispatch order for {132.34+})
Section titled “Implementation checklist (dispatch order for {132.34+})”- Overlay reader + validator (new,
producer/— likelybundle_writer.pyor a small sibling): readontology-overlay.jsonfrom bundle root; parse; enforce OV-2 (closed schema)- OV-3 (additive-only) + OV-5 (fail-loud on invalid, absent =
None); stamp OV-6 provenance (source+ sha256). Returns the overlay mapping orNone.
- OV-3 (additive-only) + OV-5 (fail-loud on invalid, absent =
- Base snapshot + artefact + the actual wiring gap: extend
_base_ontology_snapshotto addconcept_types(OV-6). Note thewrite_bundle→write_ontology_artefactpass-through is already landed (client_ontology_overlaykwarg:624→:714) — do not re-plumb it. The net-new wiring is (a) calling the step-1 reader (recommended read-site: insidewrite_bundle, which already readsbundle_dir, per OV-4) and (b) ensuring the composed overlay reaches the artefact for a real producer run — i.e.producer/flow_def.py:379-385’swrite_bundle(...)call now exercises a supplied overlay (whether via the in-write_bundleread or an explicit kwarg). Keepwrite_ontology_artefact’s echo contract (existing test evolves per OQ-OV-6). - Concept-write gate composition (
validator.py): thread an optional effective-ontology arg throughcheck_concept/validate_concept→check_type_membership/lint_entity_relation_mentions; default base-only (OV-8). Producer passes the run’s effective set to the gate. - Rider R1:
README.md+ontology-overlay.json→_RESERVED_BUNDLE_FILENAMES. - Rider R2: re-pin every live
flow.py:1665→flow.py:1708(≥5 sites:resource_uri.py:37:74,test_producer_resource_uri.py:6,id138-erasure-cascade.integration.test.ts:112,SEED-CONTRACT.md§2); close ongrep -rn "flow.py:1665"= ZERO (excluding ledger provenance- this spec).
- Tests (behaviour-first,
test-philosophy.md): the testStrategy fixture (below) + OV-5 fail-loud + OV-11 null-vs-empty + OV-10 platform-overlay-less + OV-13 parity-untouched.
testStrategy (the slice must make this satisfiable): A client repo overlay fixture composes
into ontology.json (base + overlay) and extends the linter register for that run; the platform
bundle is unchanged; the frontmatter validator accepts overlay-added concept types only when the
overlay is present. — satisfied by OV-4/OV-6/OV-7 (compose), OV-8 (register extension +
present-only acceptance), OV-10 (platform unchanged).
Coordination notes (implementation-time, not owner questions)
Section titled “Coordination notes (implementation-time, not owner questions)”- C-1 (OKF landing / LI-16 machine-facing treatment).
ontology-overlay.jsonis machine-facing JSON, likeontology.json. The OKF landing file explorer (OKF-LANDING.md LI-16: render-excluded, may-be-listed) should give it the same treatment — listable in the tree, never rendered as human/markdown content. Non-blocking; {132.32} owns the landing. - C-2 (existing tests evolve).
test_write_ontology_artefact_with_client_overlay(test_producer_bundle_writer.py:548-554) assertspayload["overlay"] == overlayfor a raw dict; if OQ-OV-6 provenance-wrapping is ratified, that assertion evolves. The base-only test (:537-545, assertsoverlay is None) stays green. Flag at dispatch. - C-3 (git-sync ordering). The overlay is a client-authored file that predates the
producer run — the git-sync flow ({132.12}) checks out the client bundle repo (carrying the
client’s overlay commit), the producer reads it, composes, writes
ontology.json, commits its output. The producer never authors the overlay. DR-016-coherent.
Open questions (OQ-OV-N) — recommendations; owner ratifies
Section titled “Open questions (OQ-OV-N) — recommendations; owner ratifies”- OQ-OV-1 (reserved overlay filename). Recommend
ontology-overlay.json(pairs withontology.json, flat bundle root, self-documenting). Alternatives:overlay.json,.okf/overlay.json. Recommendation:ontology-overlay.json. - OQ-OV-2 (extraction-gate composition / end-to-end usefulness). Overlay entity/relationship
types are only end-to-end useful if the id-131 extraction side can EMIT them (its Pydantic
Literals) — until then a gate that ACCEPTSentity_type: "widget"never sees awidgetmention, so the entity/relation dimension is inert end-to-end today, exactly as the concept-typedimension is (OQ-OV-3). Recommend deferring extraction-gate composition to an id-131/id-133 coordination follow-on; {132.34} wires the concept-write gate +ontology.jsononly (OV-9). Recommendation: defer; concept-write-gate + artefact composition ships now, extraction-gate extension tracked separately (see Scope reality note). - OQ-OV-3 (concept-type overlay blast radius + end-to-end inertness). Extending concept
type(vs entity/relation) also touchesbundle_write_pathrouting, frontmatter emission,concept-schema.ts(TS mirror), OKFCONFORMANCE.md, and the OKF landing render. It is also inert end-to-end today for a reason the owner must weigh: the soleConceptKeyfeeder issources/l_records.pyLRecordsSource.list_concepts()(:452), which fans out to six hard-coded per-type methods (_list_topic_concepts:466,_list_product_concepts:489,_list_company_concepts:500,_list_certification_concepts:508,_list_case_study_ concepts:521,_list_won_bid_case_study_concepts:534). No path constructs an overlay-added 6th type, regardless of whatcheck_type_membershipis taught to accept — so gate-composing concept types produces zero observable published concepts of a new type until a feeder emits one. Recommend {132.34} composes concept-type extension into the concept-write gate only (OV-8, per testStrategy); routing/emission/TS-mirror and a feeder for overlay concept types is a follow-on. Recommendation: gate-only for concept types this slice, with the inertness stated plainly (see Scope reality note). - OQ-OV-4 (unknown-key / removal handling = fail-loud). Recommend reject (fail-loud) on
unknown top-level keys (guards silent
entity_type-vs-entity_typestypos) and any removal/redefinition attempt (OV-3/OV-5), over lenient-ignore. Recommendation: fail-loud closed schema. - OQ-OV-5 (overlay in the platform bundle repo). Recommend hard-reject: the platform
bundle is the base authority (DR-027) and must not self-overlay; an
ontology-overlay.jsonin the platform repo is a config error → fail loudly (OV-10). Recommendation: reject. - OQ-OV-6 (provenance stamp shape). Recommend
overlay: { "source": "ontology-overlay.json", "sha256": "…", "concept_types": [...], "entity_types": [...], "relationship_types": [...] }when present;nullwhen absent (OV-6/OV-11). Recommendation: provenance-wrapped overlay object; evolve the one affected existing test (C-2).
DR-intent (for the Orchestrator, on main — not written in-branch)
Section titled “DR-intent (for the Orchestrator, on main — not written in-branch)”If the owner ratifies OQ-OV-1/3/4/5/6 as recommended, a new binding ruling is warranted to
record the client-CV-overlay contract: reserved bundle-root JSON source; additive-only
(no removal/redefinition); fail-loud composition (contra DR-047’s narrowly-scoped degrade);
provenance-stamped composed artefact; concept-write-gate composition with extraction-gate
deferred. This refines DR-027 (which named the medium but not the format/failure/additivity
semantics). Surfaced as intent only — the Orchestrator writes it on main per the
decision-register discipline.