S528 census — Lane 4: test debt on retired concepts
Lane 4 — tests that assert retired concepts, and skipped tests that should not be repointed
Section titled “Lane 4 — tests that assert retired concepts, and skipped tests that should not be repointed”Census only. No file was edited. The integration suite was not run. Method: static analysis + targeted reading. Every line number below was opened by hand.
Frame: .user-scratch/s528-census/GROUNDING.md + .user-scratch/stale-codebase-concepts-and-context-rot.md.
Target model established from okf-platform/corpus-reframe-review.html R1/R5 and
reference/entity-glossary.md before any verdict was formed.
Verdict vocabulary (this lane’s four values, per the lane brief):
| Verdict | Meaning |
|---|---|
DELETE | the test’s subject is retired — there is nothing to repoint it at |
REWRITE-FROM-TARGET-MODEL | subject is live, framing/naming encodes a retired concept |
REPOINT | subject and framing both current — id-415’s scheduled work is correct |
KEEP | correct as-is; no action |
UNDECIDABLE | evidence insufficient — the settling evidence is named |
Counts: DELETE 14 · REWRITE-FROM-TARGET-MODEL 21 · REPOINT 4 · KEEP 6 · UNDECIDABLE 3.
0. The two anchors I judged against
Section titled “0. The two anchors I judged against”Before anything else, because every “framing” verdict below rests on these:
- R5 (corpus-reframe-review.html:360): “
source_documentsrows are the permanent provenance register: never deleted (tombstoned for GDPR erasure), meaningful even when bytes are discarded.” A source document is a register entry, a first-class permanent entity — not one half of a compound. - R1 (:336): L-raw is redefined as the source bindings + the permanent provenance register. The canonical layers are the client database (records) and the OKF bundle (concepts).
reference/entity-glossary.md:15:workspace= LEGACY tier (DR-038, S452), removed from the containment chain. The containment chain (:19) is tenant ⊃ application_type ⊃ activity ⊃ child records; q_a_pairs are corpus-level.reference/entity-glossary.md:16: “‘bid’ is a form_type, not an application.”
“evidence pair” has NO entry in reference/entity-glossary.md and appears nowhere in
the whole reference/ tree (grepped reference/ and reference/decisions/: zero hits).
Per GROUNDING §2.4, a term that only ever appeared in a task spec is a drift risk, not
vocabulary. It originates in the ID-75 TECH spec and has since propagated into production
code (scripts/cocoindex_pipeline/flow.py:2656, app/api/ingest/url/route.ts:270,337,
lib/source-documents/uploader-attribution.ts:50) and 12 test sites.
The owner’s ruling is correct and better-grounded than the code. A reference item is a
first-class entity the same way a source document is. This is DR-104 trap #4 exactly: every
identifier in url-landing-set binds a live table, and the concept is still retired.
1. DELETE THESE NOW — zero ambiguity
Section titled “1. DELETE THESE NOW — zero ambiguity”These have no judgement content. Each is either (a) querying a column that does not exist, or (b) asserting parity with a mint that was ratified retired.
1.1 url-landing-set.integration.test.ts §5.4 — selects a DROPPED column
Section titled “1.1 url-landing-set.integration.test.ts §5.4 — selects a DROPPED column”| Field | Value |
|---|---|
| Target | __tests__/integration/cocoindex/url-landing-set.integration.test.ts:271, :278, :284 |
| Verdict | DELETE (the whole it() block) |
| Confidence | high |
| Evidence | supabase/migrations/20260706110000_id131_drops.sql:232 — ALTER TABLE "public"."feed_articles" DROP COLUMN IF EXISTS "content_item_id"; (STEP 4, ID-131 M6). No later migration re-adds it (feed_articles is touched only by 20260617130000_squash_baseline, …id112, …id115, …id129, …id131_drops, then view-regen files). The test issues .select('id, reference_item_id, content_item_id, passed') against the public table, not an api view. |
| Blast radius | The it() block only. reference_item_id (squash_baseline.sql:8930/9656) survives — the backlink half of the assertion is real and should move into a renamed case. |
| Owner action | Delete lines 271–286; re-add the backlink assertion as it('backlinks every ledger row to the reference item') selecting id, reference_item_id, passed only. |
This is a live nightly failure, not a latent one. cocoindex-nightly.yml:975-976 runs
vitest run --config vitest.integration.config.ts __tests__/integration/cocoindex — the
whole directory. The suite’s gate (:168 ENABLED = HAS_LIVE_DB && HAS_WALK_ENV) is
satisfied there (COCOINDEX_STAGING_URL + PIPELINE_TRIGGER_SECRET are set at
cocoindex-nightly.yml:342,360). PostgREST returns 42703 for the unknown column, so
expect(error).toBeNull() at :280 fails. This is the only live-DB read of a dropped
column anywhere in __tests__/integration/, e2e/ or scripts/tests/ — I grepped for it
specifically.
1.2 The ci: uuid5 parity case — asserts a mint that was ratified retired
Section titled “1.2 The ci: uuid5 parity case — asserts a mint that was ratified retired”| Field | Value |
|---|---|
| Target | __tests__/integration/cocoindex/url-landing-set.integration.test.ts:126-127 (ciIdFor), :145-148 (it('derives the ci: id')) |
| Verdict | DELETE |
| Confidence | high |
| Evidence | DR-034 / {127.25}: the ci: derived seed is RETIRED. scripts/cocoindex_pipeline/flow.py mints only sd: and ri: (:3961-3962, :2077-2078, :1314) — zero ci: seeds. scripts/tests/test_cocoindex_identity_core.py:293-295 states it verbatim: “the ci: (content_items) derived seed is RETIRED … the formula is dead code, not merely unused”. |
| Blast radius | Two consts + one it(). The sd:/ri: derivation cases (:138-143) are load-bearing and stay. |
| Owner action | Delete ciIdFor and its it(). |
Why this matters more than its size: this case is in the file’s pure suite — no env
gate — so it runs on every bun run test. It is permanently green against a hardcoded
expected uuid, proving parity with a formula that no longer exists on either side. It is the
purest example in the tree of a test that costs maintenance and buys nothing.
1.3 The vacuous ci: module-source guard (Python)
Section titled “1.3 The vacuous ci: module-source guard (Python)”| Field | Value |
|---|---|
| Target | scripts/tests/test_cocoindex_url_write_path.py:937-958 |
| Verdict | DELETE |
| Confidence | high |
| Evidence | Same DR-034 / {127.25}. The test’s own comment at :948 says it “passes VACUOUSLY because there is no ci: seed left to derive from”. A guard that documents its own vacuity. |
| Blast radius | One test fn. |
| Owner action | Delete the block. Reintroduction is impossible without a new CREATE TABLE, which is a louder signal than this guard. |
1.4 The taxonomy snapshot freshness guard — a self-cancelling test
Section titled “1.4 The taxonomy snapshot freshness guard — a self-cancelling test”| Field | Value |
|---|---|
| Target | __tests__/validation/taxonomy-consistency.test.ts:251-266 |
| Verdict | DELETE |
| Confidence | high |
| Evidence | The skip comment is the evidence: “SKIPPED (S435): the committed snapshot fixture is a maintenance artefact; the durable fix is regenerating it … deferred pending the id-131..135 taxonomy/OKF rework.” It asserts a fixture is <30 days old, was skipped because it isn’t, and the rework it defers to is the very thing this census is scoping. |
| Blast radius | One it.skip. |
| Owner action | Delete lines 251–266 regardless of Lane 1’s ruling on the rest of the file. |
1.5 plugin-taxonomy-consistency.test.ts — unreachable AND the owner has ruled the subject out
Section titled “1.5 plugin-taxonomy-consistency.test.ts — unreachable AND the owner has ruled the subject out”| Field | Value |
|---|---|
| Target | __tests__/mcp/plugin-taxonomy-consistency.test.ts (whole file, 168 lines); gate at :50-51 |
| Verdict | DELETE |
| Confidence | high |
| Evidence | (i) RUN_PARITY = process.env.VITEST_PRIVATE_DOCS === '1' && PLUGIN_EXISTS && PROMPT_EXISTS. VITEST_PRIVATE_DOCS is set in exactly one place in the repo — package.json:32 (test:private-docs) — and no workflow under .github/workflows/ invokes it (grepped all 17). The file has never run in CI. (ii) Its subject is parity between .claude/plugins/knowledge-hub/1.0.0/skills/classification/SKILL.md and the private classification-prompt.md. Owner directive (feedback §“knowledge-hub plugin”): “hasn’t been reviewed/updated since pre-rename to canonical, and wouldn’t be a justification for retaining e.g., the taxonomy concepts in their current form.” |
| Blast radius | The file; the test:private-docs script (package.json:32) loses one of its two targets; scripts/lib/taxonomy-parser.ts exports parsePluginTaxonomy / parsePluginDomainSlugs / parsePluginContentTypes which may become dead (check with knip). |
| Owner action | Delete the file. It is a never-run guard over a pre-rename plugin. |
1.6 test_cocoindex_stage_5_crossrun_integration.py — gated on an env var set nowhere
Section titled “1.6 test_cocoindex_stage_5_crossrun_integration.py — gated on an env var set nowhere”| Field | Value |
|---|---|
| Target | scripts/tests/test_cocoindex_stage_5_crossrun_integration.py:54,63 |
| Verdict | UNDECIDABLE — see §6.3. Listed here only so the unreachability is on the record. |
| Confidence | high on unreachability, low on disposition |
| Evidence | _INTEGRATION_ENABLED = bool(os.getenv("KH_RUN_STAGE5_INTEGRATION")); pytestmark = pytest.mark.skipif(...). KH_RUN_STAGE5_INTEGRATION appears in no workflow, no package.json script, no shell script — only in its own two files. Never executed anywhere, by anyone, ever. |
| Owner action | Decide: wire it into pytest-nightly.yml with a DSN, or delete it. Do not leave it as-is. |
2. content_items — the dropped table, still the vocabulary
Section titled “2. content_items — the dropped table, still the vocabulary”content_items was DROPPED at ID-131 M6 (S450). The tests were retargeted at the row
level and left un-renamed at the concept level. This is the single largest framing debt in
the test tree.
2.1 op-id-stamping.integration.test.ts — the owner’s seed example
Section titled “2.1 op-id-stamping.integration.test.ts — the owner’s seed example”| Field | Value |
|---|---|
| Target | __tests__/integration/cocoindex/op-id-stamping.integration.test.ts:12-20 (Inv-11 verbatim), :113 (case name), :133-138, :169-171 |
| Verdict | REWRITE-FROM-TARGET-MODEL |
| Confidence | high |
| Evidence | The subject (op_id stamped on every pipeline-produced row; op_id resolves to exactly one pipeline_runs row) is live — source_documents.op_id and q_a_extractions.op_id both exist, and id-400 HARNESS §4 keeps pipeline_runs telemetry by design (cited at :104-107). The framing is dead: the case is named 'content_items.op_id matches q_a_extractions.op_id…', the Inv-11 quotation at :12-20 opens “Every content_items row produced or updated by a cocoindex pipeline run…”, and the body already reads source_documents (:171-174). |
| Blast radius | The case name; the two verbatim invariant quotations (which means specs/id-28-cocoindex-flow-scaffolding/PRODUCT.md Inv-11/Inv-12 need amending too — the test is faithfully quoting a stale spec); the local contentRow / seededContentIds identifiers. |
| Owner action | Rename the case to 'source_documents.op_id matches q_a_extractions.op_id for rows from the same run'; restate Inv-11/Inv-12 in id-28 PRODUCT.md in source_documents terms; rename the locals. Do this in the same change as id-415’s fixture swap — see §5. |
2.2 pollContentItemsFor — the retired name, 24 call sites
Section titled “2.2 pollContentItemsFor — the retired name, 24 call sites”| Field | Value |
|---|---|
| Target | __tests__/integration/cocoindex/_helpers/fixture-staging.ts:190,248 (definition), :486 (contentIds field), :500-521 (the retirement note) |
| Verdict | REWRITE-FROM-TARGET-MODEL |
| Confidence | high |
| Evidence | The helper’s own doc-comment (:17-23) says it: “content_items was DROPPED at M6. pollContentItemsFor / dropFixture are retained under their existing names…”. It polls source_documents.filename (:230-231). dropFixture’s contentIds field is documented (:481-486) as “Named contentIds for caller-signature stability” — i.e. the name was knowingly kept to avoid churn. That decision predates this census; the census says take the churn. |
| Blast radius | 24 call sites across 23 integration test files (enumerated by grep for pollContentItemsFor). Plus test-helpers.ts:11,103, latency-budget.integration.test.ts:73, and every seededContentIds local in the suite. |
| Owner action | pollContentItemsFor → pollSourceDocumentsFor; contentIds → sourceDocumentIds; seededContentIds → seededSourceDocumentIds. Use GitNexus rename (DR-071 — it is the rename authority here), not sed. Land it with id-415, which is already opening 16 of these files. |
Why this is not cosmetic. The comment at fixture-staging.ts:500-521 is ~22 lines of
prose explaining why a name no longer matches what the function does. Per GROUNDING §1, “a
comment explaining why something was forced to fit is a finding in itself.” The rename
deletes the comment.
2.3 content_items as a live API/response field name — 11 tests mirror it
Section titled “2.3 content_items as a live API/response field name — 11 tests mirror it”| Field | Value |
|---|---|
| Target | __tests__/api/certifications.test.ts:263 · __tests__/api/guides.test.ts:412,414 · __tests__/hooks/use-entity-detail.test.ts:45,469,516,542 · __tests__/mcp/expiring-content.test.ts:99,136,144,152,182,196,214,227,260 · __tests__/components/certification-summary-card.test.tsx:44,69,89,506,531 · __tests__/components/date-extraction-ui.test.tsx:65,87,218 · __tests__/components/entity-management/entity-detail-panel.test.tsx:87,194 · __tests__/app/guide/guide-content.test.tsx:89 · __tests__/app/guide/guide-content-mobile.test.tsx:150 · __tests__/lib/validation/r-wp17-response-schemas.test.ts:301,316 |
| Verdict | REWRITE-FROM-TARGET-MODEL (blocked on the prod rename) |
| Confidence | medium — high that the vocabulary is retired, medium on what the replacement key should be |
| Evidence | The key is live on 8 production surfaces: app/api/certifications/route.ts:27,39,49,83,94,103,303,324,334 · app/api/guides/[slug]/route.ts:87,110,116 · app/api/entities/[canonical_name]/route.ts:147 · lib/mcp/formatters/dashboard.ts:32,331-336 · components/dashboard/certification-summary-card.tsx:59,71 · components/dashboard/framework-summary-card.tsx:39,94-99 · components/guide/guide-section.tsx:31,103,137 · app/guide/[slug]/guide-content.tsx:55,270,336,380 · lib/validation/schemas.ts:2640. The payloads are real; the name is the dropped table’s. Note framework-summary-card.tsx:99 builds /documents/${...} from content_items[0].id — the id is a source_documents id wearing the old key. |
| Blast radius | ~9 production files + these 11 test files + lib/validation/schemas.ts:2640 (a Zod schema, so the rename is type-checked end to end). |
| Owner action | One rename pass: content_items → source_documents (or documents if you prefer the UI-facing word) across the response shapes, then the tests follow mechanically. Not urgent, but do not let a future task “repoint” one of these files without doing it. |
2.4 Negative guards against a table that cannot come back
Section titled “2.4 Negative guards against a table that cannot come back”| Field | Value |
|---|---|
| Target | __tests__/app/api/q-a-pairs/batch/route.test.ts:228,239 · __tests__/hooks/use-batch-create.test.ts:360,374 · __tests__/hooks/use-library-data.test.ts:98 · __tests__/lib/template-coverage.test.ts:493,572 · __tests__/lib/intelligence/pipeline.test.ts:571,707 · __tests__/supabase/migrations/id131-attention-counts-rewrite.test.ts:52,59 |
| Verdict | DELETE (the negative assertions only, not the host files) |
| Confidence | medium |
| Evidence | Each asserts some code path never calls .from('content_items') or never joins it. The table is gone from every environment (20260706110000_id131_drops.sql). Reintroducing it requires a new CREATE TABLE migration, which schema-parity and the migration review catch far earlier and louder than a mocked expect(mockFrom).not.toHaveBeenCalledWith('content_items'). |
| Blast radius | ~6 assertions inside otherwise-live tests. id131-attention-counts-rewrite.test.ts may be wholly a migration-era guard — check whether anything else in it is live before deleting the file. |
| Owner action | Strip the never queries content_items assertions. Keep the host tests. |
| Caveat | This is the one place where I would accept a KEEP argument (ratchets are cheap). I am calling DELETE because GROUNDING §1 says half-retirement is the debt, and a ratchet against an impossible regression is exactly that. Flagging it as the softest verdict in the report. |
3. “Evidence pair” / “half” — retired framing, live subject
Section titled “3. “Evidence pair” / “half” — retired framing, live subject”3.1 The seed example — url-landing-set.integration.test.ts
Section titled “3.1 The seed example — url-landing-set.integration.test.ts”| Field | Value |
|---|---|
| Target | __tests__/integration/cocoindex/url-landing-set.integration.test.ts:16 (This file asserts the EVIDENCE PAIR…), :191 (lands the source_documents half of the evidence pair), :212 (lands the reference_items half of the evidence pair), :264 |
| Verdict | REWRITE-FROM-TARGET-MODEL |
| Confidence | high |
| Evidence | ”evidence pair” appears nowhere in reference/ — not the glossary, not the decision register, not reference/decisions/. R5 (corpus-reframe-review.html:360) makes source_documents the permanent provenance register, a first-class entity in its own right; R1 (:336) makes the client database (records) and the OKF bundle (concepts) the canonical layers. Neither ruling constructs a two-halves object. Owner ruling, S528: “a reference item is a first-class entity, the same way a source document is.” Every identifier in the file binds a live table — DR-104 trap #4. |
| Blast radius | Test framing: 4 sites in this file + _helpers/url-landing-seed.ts:7 + __tests__/api/ingest/url-reference.test.ts:4 + e2e/tests/content-ingestion-url.spec.ts:7,67,86,217 + scripts/tests/test_cocoindex_url_write_path.py:279,306 + scripts/tests/test_cocoindex_flow_failure_mode.py:2372. Production framing (out of my lane but load-bearing for the rename): scripts/cocoindex_pipeline/flow.py:2656, app/api/ingest/url/route.ts:270,337, lib/source-documents/uploader-attribution.ts:50. |
| Owner action | Rename the two cases to 'lands the source_documents provenance register row (§5.1)' and 'lands the reference_items record (§5.2)'. Retire the phrase “evidence pair” repo-wide; the honest replacement for the transactional property is “both rows land in one transaction” — say that where atomicity is the point (e.g. content-ingestion-url.spec.ts:86), and say nothing where it isn’t. |
What survives the rename, and it is most of the file. §5.1’s assertions
(source_url = storage_path = normalisedUrl, populated filename/mime_type/file_size,
extraction_method ∈ {trafilatura, docling}) are exactly R5’s register semantics. §5.2’s
source_document_id = sdId is id-370 §5’s live FK. §5.5’s idempotency counts are real. This
is a REWRITE, not a DELETE — but a rewrite whose §5.4 case must be deleted (§1.1) and
whose ci: case must be deleted (§1.2).
3.2 The unreconciled conflict — flagged, NOT resolved
Section titled “3.2 The unreconciled conflict — flagged, NOT resolved”This is the item the lane brief told me to report and not settle. I have not settled it.
| Field | Value |
|---|---|
| Target | url-landing-set.integration.test.ts:212-226 — specifically expect(ri.source_document_id).toBe(sdId) at :228 |
| Verdict | UNDECIDABLE |
| Confidence | n/a |
The two positions, stated exactly:
- S507 row 4.2 marked this file’s
reference_itemsassertions “not ratified”, on the expectation thatreference_items.source_document_idwould GO. - id-370 RESEARCH §5 (
specs/id-370-unanswered-question-routing/RESEARCH.md:102-114, read in full) rules the FK live provenance, with four load-bearing facts:- schema:
NOT NULL(squash_baseline.sql:7232), FKON DELETE RESTRICT(:9921) - writer:
reference_ingest()mints the sd row first, same transaction, explicitly for this FK (20260708160000_id139…:124-152— the migration comment names it) - readers are increasing:
reference_list(),app/reference/[id]/page.tsx:104-131,lib/query/fetchers.ts:264,295-296; and “id-392’s M6 retarget moved MORE reads onto reference_items — coupling is increasing” - verdict: “live FK — provenance, not identity”
- schema:
- But id-370 §5 explicitly does not close the question it appears to close. It ends: “The real residual question (‘should a reference_item mint a synthetic 1:1 source_documents row at all’) is id-364 F1’s question, not id-370’s sweep.”
What is genuinely unreconciled: id-370 answered “is the FK live?” (yes). S507 was
asking “should the sd row exist?” — which id-370 routed to id-364 F1 and nobody has
answered. The two are not in contradiction; they are answering different questions, and the
one S507 asked is still open. A verdict on :228 is therefore not available today.
What would settle it — one decision, not a measurement: an owner/DR ruling on
id-364 F1: does a URL-ingested reference item mint a synthetic 1:1 source_documents
row, or is a reference item’s provenance carried on the reference item itself? Note which
way R5 leans without deciding: if source_documents is the permanent provenance register,
a synthetic row per reference is the register working as designed, not residue. That is an
argument, not a ruling — and I am not making it.
Consequence for id-415 and any repoint: do not touch :228 until id-364 F1 is
ruled. It is the one assertion in the file whose disposition is genuinely unknown.
4. workspace as a scoping boundary in the cocoindex suite
Section titled “4. workspace as a scoping boundary in the cocoindex suite”4.1 cross-workspace-isolation.integration.test.ts — the whole file
Section titled “4.1 cross-workspace-isolation.integration.test.ts — the whole file”| Field | Value |
|---|---|
| Target | __tests__/integration/cocoindex/cross-workspace-isolation.integration.test.ts (whole file, 137 lines); framing at :1-2, :9-15, :90-91, :128-131 |
| Verdict | REWRITE-FROM-TARGET-MODEL — and once rewritten it is a duplicate; see the action |
| Confidence | high on the framing; medium on the duplication |
| Evidence | (i) entity-glossary.md:15: workspace is the LEGACY tier, removed from the containment chain (DR-038, S452); procurement_workspaces etc. were dropped in ID-145 W1. (ii) There is no workspace anywhere in this test’s mechanism — I read the whole file. W1 and W2 are two directory prefixes (inv-21-w1/, inv-21-w2/, :72,:79) and two markdown fixtures. The assertion chain is: distinct runs → distinct op_id (:112) → Stage-5 resolution is op_id-scoped (:132). (iii) The glossary’s real boundary is tenant = one DB per client (:19) — across which entity merge is impossible by construction, so the “no cross-tenant merge” clause in the header (:1) is not tested and cannot be tested from one database. |
| Blast radius | The file. Its Inv-21 statement in specs/id-53-stage-5-entity-resolution/PRODUCT.md needs restating (it is quoted faithfully at :9-15). |
| Owner action | The behaviour it actually proves — “Stage-5 UPDATEs only rows carrying the current run’s op_id” — is Inv-5, already covered by op-id-scoping.integration.test.ts (read :1-28: same mechanism, same fixtures pattern, stronger assertion — it snapshots run A’s canonical_name and re-reads it byte-identical after run B). Recommend: DELETE this file and keep op-id-scoping. Rewriting it produces a weaker copy of a test that already exists. |
Confidence note. I am calling REWRITE in the table and recommending DELETE in the
action because the duplication judgement rests on reading both files’ strategies, not on a
ratified anchor. If the owner wants a distinct “two separate walks” case (vs op-id-scoping’s
“two runs over one corpus”), rename it two-walk-op-id-isolation and drop every mention of
workspace. Either way, “workspace” must go.
4.2 cross_workspace / workspace residue in other cocoindex tests
Section titled “4.2 cross_workspace / workspace residue in other cocoindex tests”Grepped __tests__/integration/cocoindex/*.ts for workspace: the only hits are in
cross-workspace-isolation.integration.test.ts. The rest of the suite is clean. Good news
worth stating: the workspace retirement landed properly everywhere except this one file.
5. id-415 COLLISION LIST — scheduled repoints my verdicts change
Section titled “5. id-415 COLLISION LIST — scheduled repoints my verdicts change”This is the section the lane exists to produce. id-415’s acceptance criteria (read in
full from tasks/id-415.md) schedule a fixture repoint over the 16 CSP-staging tests plus
sidecar-mime-coverage and cross-document-dedup. All 16 carry the id-412-authored
PLANE MISMATCH — id-415's work list marker; I verified the marker and the
import { FORM_TEMPLATE } line in each.
5.1 id-415 should NOT repoint these — the file or its case dies instead
Section titled “5.1 id-415 should NOT repoint these — the file or its case dies instead”| File | id-415’s plan | My verdict | Why |
|---|---|---|---|
cross-workspace-isolation.integration.test.ts | not named, but carries no PLANE MISMATCH marker and is a Stage-5 sibling — in scope under “sweep the sibling Stage-5 files” | DELETE (§4.1) | Subject retired (workspace) + duplicates op-id-scoping. Repointing its fixture spends effort on a file that should not exist. |
url-landing-set.integration.test.ts §5.4 (:271-286) | referenced by id-415’s budget sweep (the file’s own :182-183 comment cites “the inverted-budget defect W6/id-415 is fixing elsewhere in this suite”) | DELETE the case (§1.1) | Selects a dropped column. Fixing its budget makes a broken assertion fail more reliably. |
url-landing-set.integration.test.ts ci: case (:145-148) | in-file, would survive a budget-only pass | DELETE (§1.2) | Asserts a retired mint. |
url-landing-set.integration.test.ts :228 | in-file | UNDECIDABLE — DO NOT TOUCH (§3.2) | id-364 F1 is unruled. |
5.2 id-415 SHOULD repoint these, but must rename in the same pass
Section titled “5.2 id-415 SHOULD repoint these, but must rename in the same pass”Repointing the fixture without renaming leaves a test called content_items.op_id … pointed
at a fresh corpus doc — the exact wasted-effort loop this census exists to end.
| File | Repoint (id-415) | Plus (Lane 4) |
|---|---|---|
op-id-stamping.integration.test.ts | FORM_TEMPLATE.cspChecklistXlsx → CONTENT.sectorSpendXlsx | rename case :113; restate Inv-11/12 (§2.1) |
op-id-scoping.integration.test.ts | same | pollContentItemsFor rename (§2.2) |
op-id-round-trip.integration.test.ts | same | ditto |
stage-5-attach-point.integration.test.ts | same | ditto |
stage-5-op-id-memo.integration.test.ts | same | ditto |
stage-5-row-counter.integration.test.ts | same | ditto |
stage-5-failure-non-destructive.integration.test.ts | same | ditto |
per-doc-canonicalisation.integration.test.ts | same | ditto |
pair-resolver-determinism.integration.test.ts | same | ditto |
context-snippet-populated.integration.test.ts | same | ditto |
unresolved-mention-retains-canonical.integration.test.ts | same | ditto |
legacy-alias-preload.integration.test.ts | same | ditto |
admin-merge-coexistence.integration.test.ts | same | ditto |
idempotency-memo-hit.integration.test.ts | same | ditto |
extract-contract-honour.integration.test.ts | same | ditto |
Verdict for all 15: REWRITE-FROM-TARGET-MODEL (= id-415’s repoint plus the rename).
5.3 One id-415 target where the subject IS classification — defer to Lane 1
Section titled “5.3 One id-415 target where the subject IS classification — defer to Lane 1”| File | id-415’s plan | My verdict |
|---|---|---|
classify-content-coexistence.integration.test.ts | repoint fixture | UNDECIDABLE pending Lane 1 |
Its subject is Inv-8: “the classifyContent delete-before-insert path … INSERTs
entity_mentions rows with NULL op_id … while a pipeline run is in flight, a
classifyContent invocation on a DIFFERENT content_item completes successfully”
(:9-14). Two retired concepts in one invariant: content_item, and classifyContent
itself if Lane 1 retires the classification path. Its local is literally
nullOpContentItemId (:71). If Lane 1 retires classification, this file is DELETE and
id-415 should not touch it. If Lane 1 keeps it, it is REWRITE. Do not repoint it
speculatively.
5.4 id-415 targets I confirm as clean REPOINT
Section titled “5.4 id-415 targets I confirm as clean REPOINT”| File | Verdict | Note |
|---|---|---|
sidecar-mime-coverage.integration.test.ts | REPOINT | Subject (per-MIME extraction → non-empty content_chunks) is live and correctly framed; id-392’s extracted_text retarget already landed (documented at :26-32). Its four fixtures are still hardcoded literals at :90,:96,:102,:108, three of them under form-templates/ — exactly id-415 AC-1. id-415’s work on this file stands, in full. |
cross-document-dedup.integration.test.ts | REPOINT (budget only) | Already retargeted off the CSP form at S507 to entity-variants/*.md (:60-78) and imports nothing from _helpers/fixtures.ts. So id-415’s fixture claim here is largely spent; what remains is real: the budget inversion at :79 (beforeAll 60_000) vs :84 (afterAll 600_000) — I confirmed both lines. Minor framing residue: // Wait for BOTH content_items to land at :92. |
extract-memoisation.integration.test.ts | REPOINT | Not in the 16; consumes pollContentItemsFor only. Rename-only. |
stage5-canonical-name-freshness.integration.test.ts | REPOINT | Same. |
5.5 id-392 / id-415 double-claim on sidecar-mime-coverage — no conflict left
Section titled “5.5 id-392 / id-415 double-claim on sidecar-mime-coverage — no conflict left”id-415’s Notes say id-392’s AC-2 (content_chunks.content instead of
source_documents.extracted_text) merged in PR #148 and that id-398 discharged AC-5. I
verified AC-2 in the file (:26-32). The two tasks no longer collide on this file — id-392’s
half is done, id-415 owns the fixture half. Nothing to arbitrate.
6. Skipped and never-run tests — the full inventory
Section titled “6. Skipped and never-run tests — the full inventory”6.1 Never-activated scaffolds — describe.skip with a commented-out or prose-only setup
Section titled “6.1 Never-activated scaffolds — describe.skip with a commented-out or prose-only setup”These are not “skipped tests”. They are test-shaped documents. Neither has ever executed.
| Field | Value |
|---|---|
| Target | __tests__/integration/cocoindex/nested-corpus.integration.test.ts (whole file, 145 lines) — :52-61 (the beforeAll is a commented-out // FUTURE: block), :77 (describe.skip), :141-145 (export const _NESTED_SUFFIX_REF — an export that exists only to silence an unused-const lint) |
| Verdict | DELETE |
| Confidence | medium-high |
| Evidence | The seed step was never written; the skip comment (:72-76) says so: “the beforeAll’s stageFixture call above is still commented out as FUTURE — no nested fixture ever lands.” The behaviour it wants (recursive walk) is already proven elsewhere: scripts/cocoindex_pipeline/flow.py:4291-4297 sets recursive=True with the gotcha named, and scripts/tests/test_file_branch_memo_fingerprint.py:238,345,349 exercises localfs.walk_dir(SRC, live=True, recursive=True) directly. Its Inv-5 quotation (:13) still says “confirm a content_items row is produced”. |
| Blast radius | The file. specs/id-28-cocoindex-flow-scaffolding/PRODUCT.md Inv-5 should be marked covered-by-python or retired. |
| Owner action | Delete. If nested-corpus coverage is wanted at the integration tier, note that the real Platform corpus (scripts/cocoindex_pipeline/fixtures/platform-corpus/) is already nested — content/, qa/, edge/ — so a walk of it is a nested-corpus proof for free. Write that as one assertion in an existing walk test rather than reviving 145 lines. |
| Field | Value |
|---|---|
| Target | __tests__/integration/cocoindex/extract-validation-failure.integration.test.ts:243-249 (describe.skip), and the whole describe body to end of file. :205-208 is the prose-only beforeAll. |
| Verdict | DELETE (the skipped describe; :210-237’s afterAll goes with it) |
| Confidence | medium-high |
| Evidence | The skip comment is explicit: “the beforeAll above is prose-only (Approach A/B harness deferred to 28.18) — observedOpIdRef.current is never assigned and no fixture is ever seeded, so all three cases fail in cascade (the third even sends the literal string "null" to PostgREST → 22P02).” The 28.18 failure-injection harness never landed (S258 → today). Case name at :309: 'no partial extraction rows written for the failed **content_items_id**' — retired vocabulary. Inv-22’s subject is covered: scripts/tests/test_cocoindex_flow_failure_mode.py (~2,400 lines of failure-mode coverage) plus persistent-failure-dlq.integration.test.ts. |
| Blast radius | The file (check whether anything above :243 is a live non-skipped case before deleting the whole file — I read :195-330, which is all inside the scaffold). |
| Owner action | Delete the skipped describe and its afterAll. If an integration-tier Inv-22 proof is wanted later, it needs a failure-injection primitive that does not exist — mint that as a task, not as a permanently-red test body. |
6.2 Deliberate named gap markers — KEEP
Section titled “6.2 Deliberate named gap markers — KEEP”| Target | Verdict | Why |
|---|---|---|
legacy-mime-coverage.integration.test.ts:141-145 — it.skip('SKIPPED[no-legacy-adapter-route]: …'), empty body | KEEP | Honest, named, counted-by-the-census marker for a live open decision (legacy OLE adapter route; id-404 owns it per _helpers/fixtures.ts:131-134). The file’s non-skipped case above it is real and asserts containment. |
lineage-ingest-once.integration.test.ts:135-138 — it.skip('SKIPPED[no-corpus-removal-primitive]: …'), empty body | KEEP | Same shape; blocked on a corpus-delete route the harness lacks (id-396/TECH.md:55-59). |
One observation, not a verdict: both are empty bodies whose entire content is a TODO
string. That is the task ledger’s job (ordna, ${KH_PRIVATE_DOCS_DIR}/tasks/id-N.md),
not the test suite’s. They are cheap and the convention is deliberate, so I am not calling
them stale — but if the owner wants zero test-shaped documentation, these are the two to cut,
and the gaps should land as ledger rows instead.
6.3 Env-gated tests where the env is never set
Section titled “6.3 Env-gated tests where the env is never set”| Target | Gate | Set anywhere? | Verdict |
|---|---|---|---|
__tests__/mcp/plugin-taxonomy-consistency.test.ts:50-51 | VITEST_PRIVATE_DOCS=1 | package.json:32 only, no workflow | DELETE — §1.5 |
__tests__/validation/taxonomy-consistency.test.ts:82 (describePromptParity) | SNAPSHOT_EXISTS && PROMPT_EXISTS — both in-repo, so this does run | n/a | see §7 (Lane 1) |
scripts/tests/test_cocoindex_stage_5_crossrun_integration.py:54,63 | KH_RUN_STAGE5_INTEGRATION | nowhere in the repo | UNDECIDABLE |
The ~40 __tests__/integration/cocoindex/* files | COCOINDEX_* + live DB | cocoindex-nightly.yml:342,360 only — integration-nightly.yml:136 explicitly excludes them (“COCOINDEX_ here — cocoindex suites stay skipped (128.3 scope)”*) | KEEP the gate — correctly scoped |
On test_cocoindex_stage_5_crossrun_integration.py: UNDECIDABLE because its subject
(cross-run Stage-5 guard behaviour against a real Postgres) is live and non-trivial, and its
sibling test_cocoindex_stage_5_crossrun_guard.py:5-7 explicitly exists as the unit half
because this one never runs. Settling evidence: whether pytest-nightly.yml can be given
a Postgres DSN. If yes → wire it and it becomes KEEP. If no → DELETE, because a test that
has never run once has never proven anything.
6.4 Conditional skips that are correct — KEEP
Section titled “6.4 Conditional skips that are correct — KEEP”Viewport-conditional Playwright skips are legitimate parameterisation, not debt. All verified
as isMobileViewport(page) guards: e2e/tests/bid-export.spec.ts:32,58,87,123,170,222,266 ·
dashboard.spec.ts:412 · content-creation.spec.ts:180 · qa-library.spec.ts:715,746 ·
bid-pipeline.spec.ts:630 · bid-questions.spec.ts:297 · bid-session.spec.ts:167,195,227,243,263 ·
provenance.spec.ts:131 · provenance-audit-export.spec.ts:17. Verdict KEEP for all.
e2e/tests/settings-mutations.spec.ts:93,129 are comments recording removed silent
conditional skips — i.e. a defect already fixed. KEEP.
6.5 Permanently-skipped tests with an empty body kept as documentation
Section titled “6.5 Permanently-skipped tests with an empty body kept as documentation”| Target | Verdict | Why |
|---|---|---|
e2e/tests/publication-bulk-action.e2e.spec.ts:677-686 — test.skip(true, '…covered by the component test…') + a no-op test() body | DELETE | An unconditional test.skip(true, …) whose reason is “this is a duplicate of the component test”. The reason is correct; the correct expression of it is deleting the test, not shipping an empty one plus a 9-line rationale comment (:668-676). |
__tests__/scripts/codemods/wrap-define-route.test.ts:1868 — it.skip('second consecutive apply run produces no further modifications [TODO: PLAN §32.14 …]'), empty body | DELETE | Deferred to “Subtask 32.14” of id-32, a task well below the DR-106 ~130 waterline; the file’s own header (:1762-1764) says the sibling non-skipped case “covers the same contract at the discovery-loop level”. Self-declared duplicate of a live test, blocked on a subtask nobody is doing. |
7. Taxonomy / classification test surface — sized, deferred to Lane 1
Section titled “7. Taxonomy / classification test surface — sized, deferred to Lane 1”Boundary respected: Lane 1 owns whether the taxonomy/classification concept survives. I am not ruling on it. What I owe this census is the test-side blast radius, so the owner can price Lane 1’s ruling.
If Lane 1 retires classification, these die with it (7,276 lines, measured by wc -l):
| File | Lines |
|---|---|
__tests__/lib/ai-classify-entities.test.ts | 1,366 |
__tests__/lib/queue/handlers/batch-reclassify.test.ts | 1,316 |
__tests__/integration/queue/batch-reclassify.integration.test.ts | 1,155 |
__tests__/lib/classify-two-pass.test.ts | 735 |
__tests__/lib/ai-classify-skill.test.ts | 536 |
__tests__/api/admin/batch-reclassify/route.test.ts | 527 |
__tests__/eval/classification-eval.test.ts | 347 |
__tests__/lib/topic-inference.test.ts | 296 |
__tests__/eval/entity-classification-eval.test.ts | 292 |
__tests__/validation/taxonomy-consistency.test.ts | 266 |
__tests__/lib/ai-classify-filter-canonicalise.test.ts | 215 |
__tests__/mcp/plugin-taxonomy-consistency.test.ts | 168 |
__tests__/lib/ai-classify-subtopic-coercion.test.ts | 57 |
Plus __tests__/lib/taxonomy/sync-trigger.test.ts and the taxonomy-field fixtures scattered
across ~40 further test files (grep for primary_domain|primary_subtopic|classification_confidence).
One I will rule on now, independent of Lane 1:
| Field | Value |
|---|---|
| Target | __tests__/lib/ai-classify-subtopic-coercion.test.ts (whole file, 57 lines) |
| Verdict | DELETE |
| Confidence | high |
| Evidence | Every doc it cites is gone. Header :18-21 cites docs/specs/classifycontent-subtopic-contract-spec.md, docs/audits/si-classification-verification-s156.md, docs/reference/product-roadmap.md §2.1.11 — all three resolve nowhere, neither in the in-repo docs/ (which contains only reference/, reports/, extend-registry-provenance.md) nor in the docs-site (checked). Its subject (:5-10) is “two content_items rows … with primary_subtopic = ''” — a table that no longer exists. Its one-off cleanup migration (20260409164245_backfill_empty_subtopics_to_null.sql) ran in April. Its fixture value is 'school-funding' (:47,:51) — an IMS/sector-intelligence-era subtopic. |
| Blast radius | The file. coerceSubtopic in lib/ai/classify.ts keeps whatever coverage classify-two-pass.test.ts gives it; check with knip whether the export survives Lane 1. |
| Owner action | Delete. This is the canonical specimen of GROUNDING §1’s “forced to fit” artefact: a 57-line regression guard for an S159 empty-string defect on a dropped table, citing three dead documents. |
Two coverage tests that die with coverage_targets (DR-034):
| Target | Verdict | Confidence | Evidence |
|---|---|---|---|
__tests__/mcp/mcp-app-trigger-tools.test.ts:362-368 (mocks a coverage_targets query returning []) | DELETE (assertion + mock arm) | medium | DR-034: “the content_items-era coverage feature is RETIRED, not re-pointed.” GROUNDING §3: coverage_targets has 0 rows. Live consumer is lib/mcp/tools/apps.ts:302 — that code is Lane 1/2’s to retire; the mock arm dies with it. |
__tests__/scripts/export-user-data.test.ts:401 (coverage_targets in EXPECTED_ATTRIBUTED_CONTENT_TABLES) | DELETE (that entry) | medium | Same. Live consumer scripts/export-user-data.ts:543,825,844. Note the same list at :403 contains workspaces — legacy tier per the glossary — so this expectation array carries two retired entries. |
e2e/tests/coverage-page.spec.ts — UNDECIDABLE. Its header (:5-18) claims the
DR-034 retirement left /coverage rendering “the single surviving template-completion view
directly” with “no tab shell”. The code disagrees: app/coverage/page.tsx:2 still
imports and renders CoveragePageTabs from ./coverage-tabs, and
e2e/tests/guide-pages.spec.ts:140 calls the tab param “UI-inert post-DR-034”. So either
the retirement is incomplete or the comment is stale — I could not tell which from static
reading, and the surface is Lane 1/2’s. Settling evidence: open app/coverage/coverage-tabs.tsx
and determine whether it renders more than one tab. The test itself (a heading + subtitle
smoke check) is harmless either way.
8. Cross-cutting observation: dead citations in test headers
Section titled “8. Cross-cutting observation: dead citations in test headers”Not a per-file verdict, but a systemic finding the owner should see, because it is how context rot enters the test tree.
Test file headers cite specs as authority. Four cited paths resolve nowhere (checked
against both the in-repo docs/ and ${KH_PRIVATE_DOCS_DIR}/src/content/docs/):
| Cited path | Cited at |
|---|---|
docs/plans/phase-0-investigation/architecture/02-data-flow.md §5.1 | op-id-stamping.integration.test.ts:38-39 |
docs/specs/classifycontent-subtopic-contract-spec.md | ai-classify-subtopic-coercion.test.ts:19 |
docs/audits/si-classification-verification-s156.md | ai-classify-subtopic-coercion.test.ts:20 |
docs/reference/product-roadmap.md §2.1.11 | ai-classify-subtopic-coercion.test.ts:21 |
The first is doubly bad: phase-0-investigation/** is a DR-106 presumed-STALE family, so
even had it resolved it could not be cited as authority. A test header citing a stale doc is
the same error as citing code (DR-106), and it is the mechanism by which a reader “confirms”
a retired invariant is ratified.
Owner action: when the id-28 Inv-11/Inv-12 restatement lands (§2.1), drop the
02-data-flow.md reference rather than repointing it.
9. What I could NOT cover
Section titled “9. What I could NOT cover”Stated plainly so this does not read as full coverage.
- I did not execute anything. No vitest, no pytest, no integration suite (per the
brief). Every “this would fail” claim is derived from schema + workflow reading, and I
name the migration line for each. The
url-landing-set:278breakage (§1.1) is the one I am most confident of and the one worth confirming first on the next nightly. scripts/tests/got a vocabulary sweep, not a file-by-file audit. It is ~60 Python files. I swept forcontent_items/qa_sidecar/evidence pair/ci:/coverage_targets/ skip markers and read the hits. I did not assess whether each Python test’s subject is current. Giventest_cocoindex_flow_failure_mode.pyalone is ~2,400 lines, that is a lane of its own.- e2e
bid-*filenames — flagged, not verdicted. Six files (bid-draft-all,bid-draft-stream,bid-export,bid-pipeline,bid-questions,bid-session) are named for a concept the glossary demotes (“‘bid’ is a form_type, not an application” —entity-glossary.md:16) while theirdescribeblocks already say “Procurement” (bid-pipeline.spec.ts:623,bid-questions.spec.ts:290). A rename is probably right; I did not read all six bodies, so I am not issuing a verdict on a file I have not opened. __tests__/validation/no-bid-regression-guard.test.ts— I read it in full and it is a finding, but its disposition needs an owner call. It enforces the S248 renamebid_workspaces → procurement_workspaces(:62-68) and bans bareproject_idin favour ofworkspace_id(:120-141). Both rename targets have since been dropped:procurement_workspacesandform_questions.workspace_idwent in ID-145 W1 (glossary:15-16). Its failure message (:115,:139) instructs a future developer to “rename toworkspace_id” — advice that would reintroduce a dropped column. It also citesspecs/id-31-…/TECH.md, a sub-130 spec (DR-106). VerdictREWRITE-FROM-TARGET-MODEL, confidence medium — the guard’s purpose (don’t regress the umbrella rename) may still be worth something, but its targets and its remediation advice are both stale. I flag rather than callDELETEbecause I have not established whether any live code could regress towardBID_STATES.- The
content_items-as-payload-key rename (§2.3) is scoped, not designed. I named the ~9 production files but did not choose the replacement key. That is a product-naming call. e2e/global-teardown.ts,e2e/helpers/data-factory.ts,e2e/fixtures/test-data*.tsall referencecontent_items, but these are seeding surfaces — Lane 2’s boundary. I left them alone deliberately; note that they will appear in Lane 2’s report and the verdicts should be reconciled.
10. Anything that contradicted the owner’s framing
Section titled “10. Anything that contradicted the owner’s framing”Honesty check, per GROUNDING §“a finding that contradicts them and IS well-evidenced is exactly what we want.”
- Nothing contradicted the owner’s two seed rulings. Both were confirmed and one was
stronger than stated:
url-landing-setis not merely mis-framed, it queries a dropped column and would fail on the next nightly. - One partial qualification on “many skipped tests certainly aren’t required in their current form”: it is true, but the count is smaller than it looks. Of ~60 skip sites, the large majority (§6.4) are legitimate viewport parameterisation. The real skip debt is six items: two never-activated scaffolds (§6.1), two unreachable env gates (§1.5, §6.3), and two empty documentation-tests (§6.5). The bigger debt is not in skipped tests at all — it is in the ~21 running tests whose framing is retired (§2, §3, §4).
- One thing I expected to find and did not:
qa_sidecar(DR-086a) is cleanly retired from the test tree. Every hit (test_cocoindex_flow_fork_routing.py:11,23,24,29,test_cocoindex_flow_live_ingest.py:168,test_cocoindex_flow_failure_mode.py:1303) is a retirement note describing what was deleted, not a live assertion. Worth stating because id-370 §6 flags “Q&A sidecar residue NOT swept for specifically — treat ‘no sidecar code found’ as unverified, not clean.” For the test tree specifically, it is now swept and it is clean. One residue:__tests__/lib/q-a-pairs/promote-corpus.test.ts:7,1368citesspecs/id-59-…/TECH-qa-sidecar-canonical.md— a stale citation on a live test, same class as §8. extracted_text(id-392) is further along than the brief implied. Every hit in the test tree is a “legacy — permanently NULL on the pipeline path” note, not a live read. The retarget landed. No verdicts needed.