RESEARCH — {427.1} OKF producer inversion: substrate index + delta measurements
RESEARCH — {427.1} OKF producer inversion
Section titled “RESEARCH — {427.1} OKF producer inversion”Task: id-427 — enumerate over the corpus, not over a type vocabulary. Spec-chain artefact: {427.1} RESEARCH (of {427.1}→{427.2}→{427.3}→PLAN). Date: 09/08/2026 (S546 spec wave). Posture: this is an index, not a re-measurement. The measured substrate already exists and is preserved point-in-time. This document names where each fact lives, records the delta measurements this pass executed that the substrate does not carry, and records the substrate interpretations it challenged.
1. The substrate — read this first, in this order
Section titled “1. The substrate — read this first, in this order”| # | Document | What it carries |
|---|---|---|
| 1 | notes/s546-producer-current-state-audit.md | The measured current state: seven enumeration branches, four closed registries, the two holes verified by mechanism, the RunSummary finding, the wired-sites blast radius (§2), the index/ontology surfaces (§3/§4), review-set verdicts (§5–10), and its own coverage statement. Every file:line in this task starts here. |
| 2 | tasks/id-427.md | Goal, ACs, the S545 minting note and the S546 Progress note — the latter carries the three ratified spec directions and the two fold-ins. Those are owner rulings, not suggestions. |
| 3 | tasks/id-422.md | The scope_tag interlock: the publication gate that closes hole 1 by construction, and its deadlock guard (the gate lands with a write path, never before it). |
| 4 | ../id-426-okf-v02-upgrade/notes/s546-okf-v02-spec-delta.md | The v0.2 emission this task’s output must be shaped for: generated:{by,at}, sources[], [^id] footnotes, no # Citations trailer, no top-level resource: for DB-backed concepts, okf_version: "0.2". In flight now; treated as landed target state. |
2. Ratified inputs (DR-104: these outrank the code)
Section titled “2. Ratified inputs (DR-104: these outrank the code)”| DR | What it binds here |
|---|---|
| DR-141 | This task’s decision record. Enumeration corpus-complete by construction; type labels, never gates. The load-bearing consequence is the negative answer. |
| DR-019 (as amended S545/S546) | Divergence 1 — the closed validator-enforced type taxonomy — withdrawn. Version target v0.2. The CONFORMANCE.md house rule is re-opened (id-431). |
| DR-027 (as amended S546) | ontology.json reduces to the client-overlay carrier; the bundle-shipped base snapshot retires. The platform-repo half is unchanged. Implementation rides this task’s wave. |
| DR-050 | The ingestion content_type axis is a different vocabulary. It is never merged into concept types, in either direction. |
| DR-054 / DR-079 | The client-overlay contract and the four bundle classes. The overlay class gate (only client_business may compose a client overlay) is a live, separate requirement — it survives this task untouched. |
| DR-140 | Entity resolution sharpens the entity-keyed grains; it does not close the coverage hole. Orthogonal, and not a dependency. |
| DR-139 / DR-123 | An invariant, a task directive, a spec, or a DR’s own ratifying text is evidence of intent at that time, never of correctness. Schema and functionality change is on the table. |
| DR-060 | A drafting-config or output-shape change is a manual version= bump on enrich_concept, recorded in the bundle log.md — never an automatic invalidation. This task triggers it (see TECH §5). |
| DR-016 / DR-025 / DR-047 | Client ownership; the knowledge-admission (promotion) gate as the published-only read posture; the narrowly-scoped degrade posture (failed rather than abort). |
Ratified product framing: initiatives/core-product/knowledge-base-foundations/okf-platform/bundle-doctrine.md
(id-71 affordances A17/A19/A21, four bundle classes, two production paths).
3. Interlocks — what this task must not decide for someone else
Section titled “3. Interlocks — what this task must not decide for someone else”| Task | Interlock |
|---|---|
| id-422 | Ratified: the residual grain is designed for hole 2; hole 1 closes by construction under id-422’s publication gate and is enumerated defensively until that gate lands. This task does not touch scope_tag’s write path or the CHECK constraint. |
| id-426 | Owns the v0.2 frontmatter migration. This task emits into that shape and must not re-litigate sources[]/generated. Sequencing: id-426 first, or the two coordinate on frontmatter.py. |
| id-428 | Owns the trust slot (confidence → verified/status). This task makes confidence: no-content reachable for the first time; id-428 maps it to status: draft. Named coupling, not a dependency. |
| id-429 | Owns the index axis. This task fixes the directory axis it will index (TECH §2.4) — the coupling is named explicitly for the id-429 designer. |
| id-430 | Closed (research). Its ruling — ontology.json overlay-only — is executed here. |
| id-431 | Owns CONFORMANCE.md’s fate. This task withdraws superset 1 only and leaves the file’s existence to id-431. |
| id-358 | Re-scoped to a rename executed in this task’s rework. The BI-28 slot stays. |
| id-362 F1 | Closed as a named design input here: unify enrich_concept over the Source protocol, not over l_records’s concrete types. |
| id-163 | Paused. This task changes gate mechanics only on system_baseline; it does not re-author that lane. |
4. Delta measurements executed by this pass
Section titled “4. Delta measurements executed by this pass”Everything below was read at the cited file:line in /Users/liamj/Documents/development/canonical
at main d1e6e14ad during this pass. These are not in the substrate.
| # | Measurement | Why it is load-bearing |
|---|---|---|
| M1 | type is producer-authored, never model-authored: enrich.py:939 passes type=key.concept_type into build_concept_frontmatter. The model’s Pass-1 envelope supplies title/description/tags/body/citations + the three hints — never type. | Opening the vocabulary does not hand type-minting to the model. The label stays deterministic and memo-stable. |
| M2 | policy, capability, metric and dataset are emitted by no code path anywhere — they exist only inside RECOGNISED_FACET_TAGS (validator.py:147-149). The only facet tag actually emitted is reference (web_pass.py:169, applied :674). playbook is emitted only as a type, by the system-baseline lane (validator.py:246; repo_docs.py:18,30). | ”Resolve the three bends as types” is, for policy/capability, a registry deletion, not an emission change. Only reference has a live emitter to re-point. |
| M3 | canonical_facet_tag / normalise_facet_tags (validator.py:160-175) have no production caller — the only references repo-wide are scripts/tests/test_producer_validator.py:449-493. | The alias-fold mechanism is test-only. Retiring it moves no production behaviour. |
| M4 | CONCEPT_TYPE_VALUES (lib/ontology/concept-schema.ts:70) has no runtime consumer — only its own module docstring and __tests__/lib/ontology/concept-schema.test.ts:73. The live colour legend is a separate array, lib/okf/concept-type-tokens.ts:38-48 KNOWN_TYPES. | The “TS legend” registry is a duplicate legend with no reader; the legend duty is already discharged elsewhere. |
| M5 | Bundle directories are grain constants, not type derivations: hard-coded literals at l_records.py:845 (topics/), :864 (products/), :891 (company/overview.md), :924 (certifications/), :949+:982 (case-studies/). Only the feeder grain derives a directory from a type string (:815, f"{concept_type}/…"), and its own docstring already rules that an arbitrary type name has no principled English-plural rule. | The layout needs no type→path function. See C2. |
| M6 | q_a_pairs.source_document_id is nullable and is NULL for derived_from_form_response pairs (supabase/migrations/20260621105625_id59_qa_pairs_source_document_id.sql:5-6,24). q_a_pairs.source_form_instance_id exists and is the won-bid lineage column (l_records.py:511,517). | A published pair may have no parent document. The residual attribution is a three-step cascade, not a single document key. |
| M7 | _REPO_DOCS_BUNDLE_CLASSES (flow_def.py:138, consumed :519) selects which Source class a run instantiates (bundle-doctrine’s two production paths). It contains no concept type. | Substrate §2 lists it under “must change”. Requirement-first it is untouched by DR-141 — see C1. |
| M8 | derive_concept_confidence (frontmatter.py:167-193) returns only strong/partial; _CONFIDENCE_VALUES (frontmatter.py:158) admits no-content/needs-SME, currently unreachable from any producer path. | The residual grain gives no-content its first real producer — the honest signal for a concept with nothing distilled in it. |
| M9 | RunSummary (bundle_writer.py:528-570) carries no denominator: write_bundle derives removed as previous_paths − written − moved − failed (:1351), and every other field from drafts that already exist (:1325-1348). | Confirms the substrate: there is no field a corpus item could appear in without first becoming a ConceptKey. The fix must add the denominator, not another failure bucket. |
| M10 | iri_projection._DIMENSIONS (:76-80) classifies base-vs-overlay per dimension using ALLOWED_CONCEPT_TYPES / ALLOWED_ENTITY_TYPES / ALLOWED_RELATIONSHIP_TYPES; project_context (:227-245) drops every overlay term when client_id is None. | Retiring ALLOWED_CONCEPT_TYPES removes the classifier for one of the three projected dimensions. context.jsonld cannot be left to fall through. |
| M11 | The showcase bundle holds 19 concept .md files across the five directories plus case-studies/won-bid/ (find … -name '*.md' minus the three reserved files). There is no references/ directory — Pass-2 has minted no reference concept into the shipped bundle. | Migration surface is exactly these 19 files; the reference-as-type change has no shipped artefact to migrate. |
| M12 | write_bundle raises on a physical write-path collision before any write in the run (bundle_writer.py:1310-1320). | The residual grain’s rel_paths must be collision-free by construction, not by luck. |
| M13 | _won_bid_case_study_redirect / bundle_write_path / bundle_write_path_for_key (bundle_writer.py:224-284) exist solely because two case_study grains were forced to share one directory. | Once a grain owns its directory, the whole identity≠physical-path mechanism dissolves. |
| M14 | repo_docs.py:117-119 computes SYSTEM_BASELINE_CONCEPT_TYPES from EffectiveOntology.base_for_class("system_baseline"), and RepoConceptKey.__post_init__:192-201 gates on it. repo_docs.py:234-242 declares its own duplicate Source protocol. | The fourth registry has a downstream in the second Source; id-362 F1’s protocol unification has a second, unrecorded duplicate to collapse. |
5. Substrate interpretations this pass challenged
Section titled “5. Substrate interpretations this pass challenged”The substrate is measured; its interpretations are not automatically right (DR-104 applies to ratified docs, not to an agent report). Four were checked.
-
C1 —
flow_def.py:519-533is listed as “must change”. Challenged and reversed. Requirement-first: it serves source selection (whichSourcea bundle class runs — bundle-doctrine’s Path 1 / Path 2), current sourcebundle-doctrine.md§“Two production paths”. DR-141 says nothing about it. Disposition: KEPT, with the rename ripple only. -
C2 — “the type-derived directory layout” (substrate §1). Challenged and corrected. Measured (M5), the layout is grain-derived; type and directory coincide today only because each grain emits exactly one type. This is the single most consequential correction in this document: the open-vocabulary design needs no type→directory function, and the existing five directories need no migration.
-
C3 — “the facet-tag vocabulary … as a materialisation” to be amended. Challenged. The registry states its own two requirements (
validator.py:120-133): (a) name the facets the producer treats as first-class for downstream consumers, and (b) keep the enumerated type set and the facet vocabulary from silently diverging. (b)‘s subject stops existing under DR-141. (a) is discharged today only by the TS colour legend (M4). Neither requirement survives in Python. Disposition: deletion, not amendment — while facet tags themselves survive as free-formtags:entries, which never needed a registry (check_concepthas never rejected an unregistered tag). -
C4 — DR-141’s “every published unit lands in exactly one concept”. Challenged on measurement. A published pair carrying a
scope_tagand a pattern-matched parent document already lands in two concepts today: the topic grain clusters it by tag, and the product/case_study/certification reads pull it via_SQL_QA_BY_SOURCE_DOCS_OR_ENTITY(l_records.py:377-382,source_document_id = ANY($1)). Partition (=1) is not the current behaviour and is not what the product needs; coverage (≥1) is. TECH §2.1 decides for coverage and recommends a DR-141 rider recording it.
6. What this pass did not cover
Section titled “6. What this pass did not cover”- No database was queried and no producer run was executed. Every claim is static.
- Test bodies unread beyond the four assertions grepped for M3 (
test_producer_validator.py:449-493) and M4. The substrate’s test-file list is filenames only; assertion counts remain unswept. - The vendored SPEC was not re-read this pass — id-426’s S546 delta note is relied on for every v0.2 claim.
.claude/worktrees/agent-*stale producer copies unswept (still open from the substrate).specs/id-132-*DR-141 propagation unchecked (still open from the substrate).parse-index.ts/parse-log.tsinternals and the/okfrender path unswept — the census additions tolog.md(TECH §5) touch a surface whose parser this pass did not read. Flagged in TECH §7 as a subtask-level check, not an assumption.- No live
context.jsonldinstance exists to diff against (the showcase publish predates{132.44}), so the F6 projection change is verified against the writer only.
No repo file was edited and no database write was performed by this pass.