Skip to content

RESEARCH — ID-397 verification-lane target

RESEARCH — ID-397 Verification-lane target: what the nightly proves under the corpus-reframe model

Section titled “RESEARCH — ID-397 Verification-lane target: what the nightly proves under the corpus-reframe model”

{397 .1-precursor} artefact, authored S513 from a four-lane parallel research pass (id-62 contract · id-396/id-399 target model · nightly-harness + census-#41 grounding · Inv-N/C-N namespace resolution). Findings only; verdicts belong to {397.1}, design to {397.2}. All file:line cites verified at read time; repo @ b0b72a0c.

  • Workflow: .github/workflows/cocoindex-nightly.ymlschedule: "0 6 * * *" + workflow_dispatch with llm_tier (mock|openrouter|anthropic, default mock) (:243-256). Job shape (:339-852): pack-build local sidecar image (~9 min, no cross-run cache) → mock-llm container → cocoindex sidecar → /health gate → docker cp docs/testing/. → stage via verify_driver --fixtures templates (loopback /stage) → initial /walk (1800 s deadline) → background walk pump: POST /walk every 10 s (:709-729) → Vitest (:744-750, sequential, fileParallelism: false) → teardown with {138.9} lease quiesce.
  • Census-tracked test set: 43 files under __tests__/integration/cocoindex/ + form-extraction{,-rls} = 86 tests. Census #41 (run 30490593136, mock tier, post-#155): 19F/57P/10S vs #40’s 26F/50P/10S; zero UniqueViolations (#40: 423) — F4 storm dead, real surface visible (tasks/id-128.md:979-1010).
  • Two sibling nightlies carry Inv-cites too: pytest-nightly.yml (07:00, python3 -m pytest scripts/tests/) and integration-nightly.yml (whole vitest.integration.config.ts superset). Neither is the numbered-census lane; scope decision below (OQ-397-1).

The invariant landscape — the {397.1} universe

Section titled “The invariant landscape — the {397.1} universe”

Inv-N is a per-spec namespace. The S512 pre-research sweep (id-397 journal) under-scoped it: not ~46 files but 122 repo files carrying 1,262 Inv-N cites, plus 17 files / 45 cites of C-N. The S512 framing “id-62 PRODUCT.md = the ratified lane contract (Inv-1..29)” is true only of the staging-harness half; the nightly’s behaviour assertions overwhelmingly cite other registers.

Defining homes (nightly-relevant; format + range):

NamespaceDefining homeRangeRôle in the lane
id-28 cocoindex-flow-scaffoldingspecs/id-28-cocoindex-flow-scaffolding/PRODUCT.md:56-132Inv-1..27Dominant behaviour register (op_id, memo, pipeline_runs, DLQ, partial writes)
id-53 stage-5-entity-resolutionspecs/id-53-stage-5-entity-resolution/PRODUCT.md:47Inv-1..21Stage-5/entity-identity assertions
id-36 extraction-contractspecs/id-36-cocoindex-extraction-contract/PRODUCT.md:24-90 (bare list — citers add the Inv-N gloss)1..26 (19..26 incl. three RATIFIED-DO-NOT-BUILDs + two OPENs)Extractor contract
id-62 fixture-staging-infraspecs/id-62-fixture-staging-infra/PRODUCT.md:157-544 + TECH.md:443-471 mapInv-1..29Harness contract (stage route, driver, activation, cleanup, trigger policy)
id-52 form-extractionspecs/id-52-form-extraction/ACCEPTANCE.md:66-90 (only enumerated register; PRODUCT cross-cites)1..26form-extraction{,-rls}
id-81 canonical-stabilityspecs/id-81-canonical-stability/PRODUCT.md:56,1301..21pytest cross-run surface
id-63 ontology-cvspecs/id-63-ontology-cv-integration/PRODUCT.md:761..17taxonomy-miss counters
id-101 entity-relationshipPRODUCT bare list :184-289; TECH.md:12 declares the Inv-gloss1..16flow.py write-site cites
id-56 content-model (C-N)specs/id-56-content-model-invariants/PRODUCT.md:49-119C-1..62chunking C-10..13/21/22/30/31/54

Corrections to prior framing: id-80 owns no register80.2-forms-content-separation.md:435 inherits id-52 Inv-17/19; the “id-80 Inv-19” of the S512 journal resolves to id-52 PRODUCT Inv-19. id-36 defines no Inv-11. id-9 (52 ids, docs-site scope) has zero nightly intersection — exclude as noise.

id-62 harness contract + the P4 precedent (format authority for {397.1})

Section titled “id-62 harness contract + the P4 precedent (format authority for {397.1})”

id-62’s Inv-1..29 groups: A /stage route (Inv-1..6), B driver (7..12), C network posture (13..14), D corpus activation (15..17), E Vitest assertion surface (18..20), F shared {42.10} invocation (21..23), G carried TECH constraints (24..27), H trigger policy + launch-flip (28..29). Full per-invariant map: id-62/TECH.md:443-471.

specs/id-62-fixture-staging-infra/P4-RECONCILIATION.md is the in-house precedent for a survive/reframe/retire pass: quantified verdict drives the wholesale-vs-surgical call (“:60-61 — the count is the argument”); §2 SURVIVES as a 3-column table (surface / invariants / why); §3 per-invariant arrow verdicts under surface-scoped headings; vocabulary SURVIVES / SURVIVE in spirit / REFRAME / MOOT / DELETE / RE-ARCHITECT / PORT AS-IS with the MOOT-vs-DELETE distinction load-bearing (MOOT = surface no longer exists; DELETE = removed, not replaced); authored as a non-mutating delta doc, specs wholesale re-authored downstream. Trap: P4 uses the OLD 35-invariant numbering; the ratified register has 29 (old Inv-10..17 → new 7..12 etc.) — any P4 cite must state old-vs-new. id-62 PRODUCT itself still carries one unmigrated old-numbering cite (PRODUCT.md:132 “Inv-21” vs def #21 at :448).

The target model (id-396 TECH — corpus model of record)

Section titled “The target model (id-396 TECH — corpus model of record)”
  • Retention classes, two axes: test-side fixture_class (staged-ephemeral — swept per run, never asserted across runs; durable-seed — never swept; vendored-read-only — never staged) TECH.md:54-67; product-side binding-gate classes ingest-once vs keep-and-watch, derived rows of ingest-once sources must outlive engine orphan-cleanup (TECH.md:55-59; id-138…/notes/s440-corpus-durable-home-decision.md:126-161).
  • R4 proof obligation: the corpus declares one ingest-once lineage (walked once, derived rows asserted to SURVIVE later walks + orphan cleanup) and one keep-and-watch lineage (re-walked on byte change). “Today’s corpus tests neither — new proof surface for id-397 to specify” (TECH.md:68-72).
  • Promotion boundary (R3): walks never mutate promoted records; engine writes stop at the staging layer (TECH.md:105; s440…:139-144).
  • Upsert-absorb (D1, ratified S511): byte-identical re-staging is designed upsert-absorb, not a reset-boundary error; same-bytes staging is reserved for tests whose subject is hash identity and their correctness “rides id-398’s PK re-seed, not fixture changes” (TECH.md:79-83, 88-96). Full-DB reset rejected — it would mask the ingest-once-survival semantics the lane must prove.
  • Pre-run sweep (D1): new nightly step before /stage, deletes fixture-prefixed rows only (VERIFY-* + declared per-test dest prefixes); closes the 19/41 no-dropFixture gap centrally; per-spec dropFixture demoted to hygiene (TECH.md:100-104). Showcase/platform content is never sweep-eligible — Platform staging persists as showcase + promote-to-client surface (owner amendment, TECH.md:105-111).
  • Census comparability comes from id-396, not id-399: telemetry accumulates (“comparability requires history”), sweep ⇒ known starting fixture population ⇒ run-over-run deltas are signal (TECH.md:106-113).
  • Lane boundary (D4): ingestion lane proves corpus→rows; e2e proves app behaviour around programmatically-manufactured states; the e2e fixture fix rides the S8 mint (TECH.md:128-133).
  • D3: two adopted orphans (ITT Evaluation Matrix.xls, rfp_onlinetdcops.doc) mint legacy .xls/.doc mime-coverage tests — new lane test surface id-397 inherits (TECH.md:48-52).
  • WALK SHAPE IS NOT RULED. Grep-verified: id-396 TECH contains no full-replace/stage-while-walking/incremental ruling; it hands id-397 “lane proof targets over this corpus (R4 lineages, class-2 disposition)” (TECH.md:181). The “legacy walk shape” framing traces to the S507 triage (id-128…/notes/S507-audit-triage-owner-rulings.md:65-75), not the corpus model. id-397 owns the walk-shape decision.

specs/id-399-census-protocol/census-protocol.md is the schema-wiring census (per-column verdicts; zero occurrences of “nightly”). The numbered #36–#41 series is the nightly-run census (id-128 journal artefacts). Real couplings only: (i) the drop standard — “static absence plus a live population check is the drop standard” (census-protocol.md:127-129) makes the nightly lane the de-facto live-population producer, so a lane-scope reduction is a census input change; (ii) the R8 schema-presence gate (five protected source_documents columns, --verify fails if any leaves the schema, :131-143); (iii) any lane-emitted census evidence must be v1 sidecar rows — “evidence changes, not rules” (:28-32).

Assert sites + owning namespace (full log preserved: notes/census-41-vitest-run-30490593136.log, this dir; mechanism classes (a)–(e) under Issues):

#Test (file:line)Invariant (owner)Observed mechanism
1admin-merge-coexistence…:147Inv-9 (id-53)run B reverted admin merge to 'mock org 023238694247' — mock-tier entity collapse (e)
2audit-log-shipping…:201Inv-13 v1.1 FUTURE (id-28)broken skip-guard — dead test (Issues §1)
3chunking…:209C-11/C-12 + “Inv-11 elevation” (id-56 borrow)readStageCount hit the in_progress row → zeros (b)/(c)
4chunking…:271C-31 (id-56)vectors differ ~1e-5 after memo re-ingest — genuine re-embed
5–6, 12, 14, 16–17six pollContentItemsFor timeoutsid-53 Inv-8/17/5/1/11, id-28 Inv-7back-half starvation (d)
7cross-workspace-isolation…:112Inv-21 (id-53)identical op_id both workspaces — flow-scope op_id (a)
8file-change-detection…:157Inv-1 (id-28)per-file run claim vs corpus-level key (a)
9legacy-alias-preload…:122Inv-10 (id-53)mock-tier entity collapse (e)
10memo-hit-pipeline-run…:169Inv-15+16 (id-28)asserts non-existent JSONB path — dead test (Issues §1)
11op-id-round-trip…:73Inv-6 (id-53)150 s timeout (d)
13op-id-stamping…:148Inv-11+12 (id-28)read skew across a walk boundary (b), atop retired doctrine (Issues §2)
15sidecar-version-metadata…:146Inv-8 (id-28)op_id moving target (b); latent stale key list (Issues §1)
18stage-topology…:155Inv-3+17 (id-28)op_id moving target (b)
19stage-topology…:200Inv-3 embedding half (id-28)0 record_embeddings for owner_kind='source_document' — candidate real breach

Candidate real breaches: at most #1, #4, #9, #19; the rest are harness-mechanics artefacts. The Inv-11 discrepancy is resolved: the S512 prompt’s “Inv-11” = id-28 Inv-11 (#13’s test names it in its title); but note #17 cites id-53 Inv-11 and #3 cites the id-56 “elevation” borrow — three different invariants sharing one token.

Each with a resolve-first vs build-on call. None is a hot-fix — S512 ruled adjudication precedes patching, and all three “dead tests” are {397.1} rows first.

  1. Three dead/stale tests inflate the failure count — (i) memo-hit-pipeline-run…:159-167 filters pipeline_runs on result.context.file_path, which no producer writes (route BodySchema app/api/internal/pipeline-runs/record/route.ts:87-196, composer :243-264; flow.py payload likewise) → beforeCount structurally 0, the Inv-16 “+1” assert can never run honestly — Inv-16 has never been genuinely proven. (ii) audit-log-shipping…:154-172 guards on if (probeError) only; the correct table-absent guard (probeError || probeCount === null) exists verbatim in memo-hit-pipeline-run…:218-237, observed live 2026-07-28; audit_log has zero migrations. (iii) sidecar-version-metadata EXTRACTOR_ID_KEYS (:68-75) omits extractor_version — the very key the route writes (route.ts:246) — so it fails even on a perfect run once its poll is fixed. Call: triage-table verdicts (retire or reshape at S2-execute), not pre-adjudication patches; owner visibility required since they change the honest red/green count.
  2. The memo/op_id doctrine is a three-layer conflict, and the bottom layer is owner-ratified. Layer 1 (normative, RATIFIED by Liam S265, OQ-A): id-28 Inv-11’s rider — “op_id records the run that last materially produced or changed this row… a no-op re-ingest does NOT re-stamp op_id; a full_reprocess run DOES re-stamp every row” (id-28/PRODUCT.md:84, empirical basis id-28 RESEARCH §R4); restated by id-53 Inv-7 (id-53/PRODUCT.md:63) and id-56 C-21/C-31. Layer 2 (empirical, later): {75.17}/bl-239 — the outer component memo is busted every walk (flow_op_id kwarg is a memo input; app_main mints a fresh op_id per walk) — “a true memo-hit happens only WITHIN one walk, never across walks” (scripts/cocoindex_pipeline/flow.py:1793-1802; scripts/tests/test_file_branch_memo_fingerprint.py:9-32); _upsert_source_document “always writes op_id=run_op_id onto every row it touches” (flow.py:3812-3815). Layer 3 (target model): id-396 D1 upsert-absorb accepts that re-declares happen every walk and makes them idempotent (the id-398 PK re-seed) — leaning toward the installed reality, without ruling on what op_id then means. The {397.1} verdict on this class is therefore an OWNER FORK, not a technical reshape: either the S265 semantic stands (→ the flow_op_id-in-the-memo-fingerprint shape is the defect) or upsert-absorb supersedes it (→ Inv-11/Inv-15, id-53 Inv-7, C-21/C-31 reshape and the S265 ratification is formally superseded). Consequence either way: id-53 Inv-9’s admin-curation protection rests on op_id scoping (id-53/PRODUCT.md:59,69) and collapses if every walk re-stamps — census #41 failure #1 (admin merge reverted) is the live symptom; under the reshape branch a replacement protection mechanism must be minted (the R3 promotion-boundary analogue at the entity layer). C-31’s “memo no-op re-ingest does not re-stamp” and Inv-11’s “unchanged re-ingest does not re-stamp” describe a cross-walk skip that does not exist. The pre-correction doctrine is written into the spec text itself, not only the tests: id-56/PRODUCT.md:81 (C-21 “a memo-hit no-op re-ingest does NOT re-stamp it”) and :91 (C-31 “op_id not re-stamped”), with the acceptance row id-56/TECH.md:204 asserting “op_id unchanged AND embedding unchanged” on re-ingest. Call: resolve-first — {397.1} must rule from the corrected doctrine; this is the core reshape evidence for the memo/idempotency class (spec-level, not just test-level), and aligns with id-396 §3’s criterion (collision/delete-recreate under re-stage = legacy; memo-hit + in-place upsert with stable derived rows = target).
  3. Five structural harness defects generate ~14 of the 19 failures — design inputs for {397.2}, not per-test fixes: (a) op_id is flow-scope, one per whole-corpus walk (flow.py:3871; server.py:805,835) — “distinct fixture → distinct op_id” is false whenever two fixtures precede one walk; (b) the 10 s walk pump makes source_documents.op_id a moving target with no quiescence gate — any read-then-join on op_id races; (c) readStageCount/readEntityResolutionStageCount use .maybeSingle() with no status filter (test-helpers.ts:~305,330-353) — resolves the in_progress row whose stage_counts is all zeros; (d) monotonic corpus growth + catch-up-mode walks (cocoindex SKILL.md:195-197 — each call scans all sources) starve back-half polls at exactly their budget ceilings; (e) the mock tier’s canned entities collapse cross-document identity, making entity-identity invariants (id-53 Inv-9/10/21 cluster) untestable under the scheduled default. Call: build-on for {397.2} — the harness shape must absorb all five or the same failures reappear renamed.
  4. Namespace hazards make token-level anchors unusable. flow.py alone carries 16 distinct Inv-N across ≥6 namespaces (Inv-7 has THREE owners: id-63/id-101/id-53; Inv-11 four: id-53/id-56-borrow/id-28/{75.17}); Inv-27 collides id-28 vs id-62 inside the same nightly directory; the shared helper fixture-staging.ts mixes id-62 + id-53 + id-56 cites; “Inv-11 elevation” (chunking) is a floating id-53 borrow with no defining home; stage_5.py interleaves id-53/id-81/id-101 and under-declares; id-101 TECH itself leaks id-28’s Inv-17 (TECH.md:261 vs range decl :12). Orphans: taxonomy-consistency.test.ts:14,72 cites an Inv-30 no spec defines; a display-name C-1 (6 files incl. the squash baseline :3668) sources to a spec-verification report absent from the docs-site; a second orphan C-1 (markdown double-escape) in pipeline.test.ts:779,883. Stale spec paths (missing id-NN- prefixes) are systemic (pair_resolver.py:34-35, form_extractors/shared.py:18,21, id-56/TECH.md:202,230,231). Call: build-on with a hard convention — every {397.1} verdict anchors as <file>:<line> → <owning-spec>/<artefact>:<line>; token-only anchors are ambiguous in this repo by construction. Orphans get home-or-retire rows, not lookups.
  5. The pre-run sweep does not exist yet — it is a D1 design item landing with S2-execute. Until it lands, run-over-run census deltas remain partially noise (accumulated fixture rows), and staged-ephemeral’s “never asserted across runs” rule is unenforced. Call: build-on; {397.2} sequences it.
  • Format: adopt the P4-RECONCILIATION shape for {397.1} — quantified verdict first, SURVIVES table, per-invariant arrow verdicts grouped by surface, MOOT ≠ DELETE, non-mutating delta artefact; plus the id-62/id-42 lesson: cross-spec references use an explicit id-NN Inv-N prefix, never bare tokens.
  • Anti-drift assertions: copy the census F1 pattern — assert on the producer’s own rows, not merged downstream state, so app-code drift cannot silently satisfy a lane fixture (census-protocol.md:166-169).
  • cocoindex engine facts constraining {397.2} (from scripts/.claude/skills/cocoindex/SKILL.md): catch-up mode scans all sources per call (:195-197); memo=True skips only on unchanged inputs+code — flow_op_id as kwarg defeats it by design (:109-112); memo needs stable component paths (:433-443); a deliberate full_reprocess walk already exists as a harness primitive (server.py:835; SKILL:411); live mode (update_blocking(live=True)) is the alternative to the 10 s pump but shares the flow-scope-op_id property (:205-217).
  • Census evidence discipline: if the lane emits census evidence it does so as v1 sidecar rows; verdict rules never change per-producer (census-protocol.md:28-32).
  • Register age (owner steer, S513): every register in the universe — id-28, id-53, id-36, id-52, id-56, id-62, id-101 — pre-dates id-127; the default triage posture is therefore verify against the corpus-reframe model before ruling SURVIVE, not survive-unless-contradicted. The two authority docs: initiatives/core-product/knowledge-base-foundations/okf-platform/corpus-reframe-review.html (S441 ratified reframe — evidence/provenance/authority three-way split; the gate moved to promotion; “walks never touch promoted records”; ingest-once “what survives the engine” contract; id-131 kills content_items) and …/okf-platform/bundle-doctrine.md (two-loop separation — the bundle is never pipeline input; producer rides the promotion loop). Consequence: register rows binding content_items-era substrate (id-28 Inv-2/11 text, id-36 Inv-15/16, id-56 C-13/C-21) need a substrate-binding verify independent of their behaviour verdict — the op-id-stamping title/poll seam was only half-retargeted at M6.
  • In force and binding here: DR-014 (forms manual-upload; walk stays out — re-confirmed S511 D6), DR-023/024/025/026 (source-binding home, hash-first resolver, corpus reframe, promotion boundary), DR-047 (memo-deserialisation degrades to re-extraction, never item failure), DR-060 (producer memo delta-determinism), DR-093 (delete-don’t-backfill), DR-018 (OKF producer chains off successful walk), DR-050 (owner_kind grain), DR-036 (record_embeddings single home — bears on failure #19), DR-034 (coverage retired), DR-099 (scoped queue claims), DR-102 (declaration-only ≠ wired), DR-096 (e2e substrate = local stack). No DR names upsert-absorb — its authority is id-396 TECH D1 + the preserved S511 board.
  • Board rulings D1–D9 (id-396 TECH + reports/s511-id396-corpus-rulings-board.html); D5: id-397 lane targets touching reference_items/q_a_extractions are downstream of id-370’s rulings (now landed); D7: the 370/363/364 single-function collision class — watch for lane analogues.
  • {75.17}/bl-239 — the Inv-11 doctrine correction (Issues §2); the single most important prior finding for the memo/idempotency class.
  • S507 triage — class-2 (ownership give-ups) disposition rides this task; census #40 was vacuous for class-2 (walks died first); #41 is the first observable signal.
  • Census #40/#41 baselines: id-128 journal; #41 classification pass only, nothing adjudicated; the op-id-stamping test is deliberately double-listed (class 1 seam + class 2 op_id-equality half).
  • Related specs: id-62 (harness contract + P4 precedent), id-396 (corpus model), id-399 (wiring census + R8 gate), id-28/53/36/52/81/63/101/56 (invariant homes), id-395 (mock-residue landing zone; D2 tier-joins-cache-key rides {395.4}), id-398 (upsert-absorb write path, done), id-370 (promotion-candidates predicate, done).
  • Tier is a triage dimension. Under the scheduled mock default, the entity-identity cluster is structurally untestable (Issues §3e). Every {397.1} verdict needs a “provable at which tier” column, or the table silently promises proofs the scheduled lane cannot deliver. cross-workspace-isolation was already retargeted once for exactly this (S507).
  • The lane is a census input. Dropping a staged surface flips wiring-census columns from live-population-checkable to un-checkable (census-protocol.md:127-129). Lane scope changes need a census-impact note.
  • Accumulation vs assertion tension. pipeline_runs history accumulates by design (comparability), while today’s helpers read it maybeSingle()-by-op_id with no status filter — the target harness needs an explicit run-selection idiom or history growth re-breaks assertions later.
  • Quiescence is an unowned concept. No primitive exists to say “the walk the test cares about has completed and no newer walk started”. Most op_id races reduce to this missing gate.
  • New surfaces arrive with the model: R4’s two lineage proofs, D3’s .xls/.doc mime tests, and post-sweep run-over-run assertions for non-ephemeral classes — the triage table must mint rows for proof surface that has no test today, not only triage existing tests.
  • Three nightlies, one census. pytest-nightly and integration-nightly carry Inv-citing surfaces (id-81 cross-run, id-101-via-id-109 parity, orphan C-1 cluster) outside the numbered census. Leaving them out of {397.1} is defensible but must be an explicit scope ruling, not an omission.
  • entity_mentions cleanup stays best-effort while ID-49.5 is deferred (id-62/TECH.md:376-378) — a standing partial-cleanup source the sweep design should note.
  1. Most likely: {397.2} keeps the whole-corpus-walk + pump shape without absorbing root causes (a)–(d). The 14 mechanism-failures reappear under new invariant names, and the lane is red-but-honest forever. The design must either give tests a quiescence/run-selection primitive or change the walk trigger model — naming that fork is {397.2}‘s first job.
  2. Token-anchored verdicts drift. A future session greps “Inv-16”, lands in the wrong namespace (three live collisions inside flow.py today), and “fixes” the wrong invariant. Mitigation is mechanical: the <file>:<line> → <spec>:<line> anchor format, plus home-or-retire for the orphans.
  3. Mock-tier flap. If the entity-identity cluster stays in the scheduled lane un-quarantined, admin-merge/alias/isolation verdicts oscillate with mock behaviour and erode trust in the census series.
  4. Sweep slippage. If S2-execute lands the harness rebase without the D1 pre-run sweep, staged-ephemeral accumulation quietly re-couples runs and census deltas go back to noise.
  • OQ-397-1 (owner): {397.1} universe boundary — cocoindex-nightly only, or include pytest-nightly + integration-nightly invariant surfaces? (Recommend: cocoindex-nightly as the ruled universe; siblings listed as out-of-scope with one-line dispositions.)
  • OQ-397-2 (owner): mock-tier disposition for the entity-identity cluster — quarantine (skip at mock, prove at real-tier dispatch) vs make the mock per-fixture-deterministic? Interacts with id-395/D2.
  • OQ-397-3 (design, {397.2}): walk trigger model — keep whole-corpus catch-up walks
    • add a quiescence gate, per-stage explicit walks, or live-mode watch? All three must answer root causes (a)–(d).
  • OQ-397-4 (owner): the three dead tests (#2, #10, #15) — retire/reshape verdicts ride {397.1}, but do their mechanical fixes land at S2-execute or earlier? (#10 matters most: Inv-16 has never been honestly proven.)
  • OQ-397-5 (owner): orphan invariants (Inv-30 taxonomy-consistency, display-name C-1, markdown C-1) — mint a home or retire the citations? Out-of-lane but surfaced here; cheap to route to the S6 sweep.
  • OQ-397-6 (process): class-2 (ownership give-ups) reading of census #41 — {397.1} rules the disposition; confirm the reader is this task, not id-128.