Skip to content

Canonical-pipeline drift-audit — S240 end-of-session

Canonical-pipeline drift-audit — S240 end-of-session

Section titled “Canonical-pipeline drift-audit — S240 end-of-session”

Date: 15/05/2026 (S240 end-of-session) Scope: Drift between docs/specs/id-31-0.9-canonical-pipeline/{PRODUCT,TECH}.md and landed Wave 2 architecture sub-docs (02-data-flow.md + 04-workspace-types.md + 05-qa-flow.md). Preparatory for S241 implementation kickoff. Auditor: background worktree drift-audit agent (S240 end-of-session) Rubric: 6 drift dimensions (schemas / flow stages / Q&A / §11 STILL-OPEN / reserved-seats forward-ref / tier-vocabulary)


Total drift items: 19 across 6 dimensions. Priority breakdown: 3 P1 (block-implementation), 9 P2 (should-fix-pre-implementation), 7 P3 (nice-to-have). The most critical single item (P1-A) is the stale [STILL-OPEN] for RLS-PATTERN destination in TECH.md §11 — an implementing agent reading the spec today would treat a resolved question as open, misallocating investigation budget at the start of S241. The spec pair is implementation-ready for the majority of invariants once the P1 fixes are applied; no structural rework is required.


Checking PRODUCT.md + TECH.md claims against landed 04-workspace-types.md schemas.

1.1 q_a_pairs corpus-level shape — ALIGNED

Section titled “1.1 q_a_pairs corpus-level shape — ALIGNED”

PRODUCT.md P-20 (docs/specs/id-31-0.9-canonical-pipeline/PRODUCT.md line 133-141) states: “corpus-level: NO direct workspace FK; nullable source_workspace_id for provenance audit only.” This matches 04-workspace-types.md §5.1-§5.3 verbatim: corpus-level shape, scope_tag overlap query, nullable source_workspace_id as audit-trail column per Q-OQR1-07. TECH.md P-20 (lines 163-188) provides a column list: scope_tags[], anti_scope_tag[], source_workspace_id (nullable). The 04 §5 column list matches. No drift.

1.2 application_types instance table — ALIGNED

Section titled “1.2 application_types instance table — ALIGNED”

PRODUCT.md P-43 (lines 227-234) states Option (c) hybrid, 6 core-provenance baseline rows. TECH.md P-43 (lines 308-322) gives column sketch: id, key, label, description, provenance enum (core vs client), default_color, default_icon, route, state_machine_name, satellite_table_name. 04-workspace-types.md §3.1 deliberately defers column enumeration to migration SQL (“Detailed columns are not enumerated in this sub-doc — the table is created in the Q-OQR1-16 combined-PR migration; column-level SQL is the migration’s scope”). TECH.md’s column list is therefore ahead of 04’s intentional deferral. Minor gap (P3): TECH.md P-43 carries satellite_table_name as a column, but 04 §3.2 does not enumerate it in the table row for application_types — it lists satellite names in the companion table, not as a column on application_types. This may create implementer confusion. Recommendation: add a parenthetical in TECH.md P-43 noting “column list is spec-level; authoritative schema lives in the combined-PR migration SQL.”

Drift item 1.2-a (P3): TECH.md P-43 column list claims satellite_table_name as an application_types column; 04-workspace-types.md §3.1 defers column enumeration to migration DDL and does not name this column. Risk: implementing agent adds the column based on TECH.md; migration DDL may differ. Fix: add note to TECH.md P-43 that the column list is illustrative; migration SQL is authoritative.

1.3 Satellite pattern — PARTIAL DRIFT (P2)

Section titled “1.3 Satellite pattern — PARTIAL DRIFT (P2)”

PRODUCT.md P-40 item 1 (line 186-192) refers to the combined-PR scope including “application_types instance table + 6 baseline core-provenance seed rows”. PRODUCT.md P-42 and P-43 handle the procurement rename and application_types table. However, neither PRODUCT.md nor TECH.md references the 5 reserved satellite seat tables (intelligence_workspaces, sales_proposal_workspaces, product_guide_workspaces, competitor_research_workspaces, training_onboarding_workspaces) as a forward-ref to docs/specs/reserved-workspace-seats/. 04-workspace-types.md §4.2 explicitly names this as the canonical source: “Seat-shape spec source-of-truth: docs/specs/reserved-workspace-seats/{PRODUCT,TECH}.md (NEW-S240 spec pair).”

Drift item 1.3-a (P2): PRODUCT.md §5 (IMS naming cleanup) discusses the combined-PR scope at P-40 but does not forward-reference docs/specs/reserved-workspace-seats/ for the 5 non-procurement satellite seat tables. An implementer relying on canonical-pipeline PRODUCT.md alone would not know the seat-shape spec exists. Fix: add a sentence to P-40 or a new P-44 stub: “Reserved workspace seats (5 non-procurement satellites): see docs/specs/reserved-workspace-seats/PRODUCT.md + TECH.md (NEW-S240) for the upfront seat-creation invariants. These tables are created by the combined PR with PK + FK + RLS only; per-app columns land per feature spec.”

1.4 source_documents.workspace_id nullable — ALIGNED

Section titled “1.4 source_documents.workspace_id nullable — ALIGNED”

TECH.md P-10 (lines 93-98) states: “source_documents adopts Option α (slim-and-keep) + nullable source_documents.workspace_id for admin-shared binaries (Q-OQR1-09)”. 04-workspace-types.md §9.1 confirms: “source_documents.workspace_id becomes NULLABLE per Q-OQR1-09”. 02-data-flow.md §2.2 confirms: “Per Q-OQR1-09, source_documents.workspace_id is NULLABLE.” No drift.

1.5 citations table — PARTIAL DRIFT (P3)

Section titled “1.5 citations table — PARTIAL DRIFT (P3)”

TECH.md P-22 (lines 210-218) describes the polymorphic citations table as: “citations.citing_entity enum” with 5 values. However, TECH.md P-22 line 212 states “Full schema detail is deferred” without citing the specific section in 04-workspace-types.md or 05-qa-flow.md. 05-qa-flow.md §6.2 now owns the citations table description: “citing_entity_id UUID (FK to the specific citing row — not a single typed FK, but a polymorphic reference indexed per enum value), and a cited_q_a_pair_id UUID referencing q_a_pairs.” TECH.md does not forward-reference this section.

Drift item 1.5-a (P3): TECH.md P-22 says “Full schema detail is deferred” but does not cite the landed destination (05-qa-flow.md §6). Fix: update TECH.md P-22 to: “Full schema detail: 05-qa-flow.md §6.2 (citations table) and 04-workspace-types.md §5 (q_a_pairs forward-ref). Schema anchored post-Wave 2 split landing.”

1.6 provenance enum across hybrid vocabularies — ALIGNED

Section titled “1.6 provenance enum across hybrid vocabularies — ALIGNED”

PRODUCT.md §13.1 (lines 419-422) lists the provenance enum across application_types, form_types, form_template_requirements, guides, coverage_targets, and notes entity_aliases.categoryprovenance rename. 04-workspace-types.md §9.2 lists the same set with the same sources (Q-OQR1-11, 00-synthesis-v2.md §3.7). No drift.


Checking TECH.md claims against landed 02-data-flow.md flow topology.

2.1 Cocoindex flow stages — ALIGNED WITH GAPS

Section titled “2.1 Cocoindex flow stages — ALIGNED WITH GAPS”

PRODUCT.md P-1, P-2 (lines 62-77) describe cocoindex ExtractByLlm as the recurring runtime adapter; Cloud Run sidecar for Docling. TECH.md P-1 target state (lines 55-57): “cocoindex flow with external-folder source binding + configurable poll cadence per workspace. pullmd as URL adapter inside the flow. Cloud Run sidecar hosts Docling per §3.1 / §3.2”. 02-data-flow.md §3.1 provides the 6-stage table (source walk → binary conversion → LLM extraction → embedding → entity resolution → Postgres UPSERT). TECH.md §1 / §2 do not reference this 6-stage table; the description is consistent in direction but less granular.

Drift item 2.1-a (P3): TECH.md P-1 target state mentions “cocoindex flow with external-folder source binding” but does not cite 02-data-flow.md §3 for the 6 named stages. After the Wave 2 split, the 6-stage topology is the authoritative breakdown. Fix: add to TECH.md P-1 “Full cocoindex stage topology (6 stages: source walk → binary conversion → LLM extraction → embedding → entity resolution → Postgres UPSERT): docs/plans/phase-0-investigation/architecture/02-data-flow.md §3.”

2.2 Cloud Run sidecar architecture — ALIGNED

Section titled “2.2 Cloud Run sidecar architecture — ALIGNED”

TECH.md P-1 target state: “Cloud Run sidecar hosts Docling per §3.1 / §3.2 (Docling 1.8 GB > Vercel 250 MB)”. 02-data-flow.md §4.1 confirms: “Docling’s 1.8 GB on-disk footprint exceeds Vercel’s 250 MB function-bundle limit. The Cloud Run sidecar is therefore mandatory.” TECH.md’s forward-reference to “§3.1 / §3.2” is a dead ref — it cites sections of 0.9-intended-architecture.md (now OUTDATED per S237), not 02-data-flow.md.

Drift item 2.2-a (P2): TECH.md P-1 target state (lines 56-57) forward-references “Cloud Run sidecar per §3.1 / §3.2” — these are 0.9-intended-architecture.md section numbers, which is the OUTDATED doc per S237. The landed destination is 02-data-flow.md §4. An implementing agent following these refs reaches the wrong doc. Fix: update to “02-data-flow.md §4 (Cloud Run sidecar architecture).“

2.3 audit_log + op_id hybrid — PARTIALLY ALIGNED (P2)

Section titled “2.3 audit_log + op_id hybrid — PARTIALLY ALIGNED (P2)”

PRODUCT.md §13.4 (line 484) states: “op_id propagation: trigger-driven for platform-wide audit cohesion + cocoindex per-flow op_id for pipeline-side correlation (principled hybrid).” TECH.md P-31 (lines 234-244) mentions “Supabase auto-RLS event trigger” but does not describe the hybrid op_id pattern. 02-data-flow.md §5.1 now carries the definitive hybrid pattern description (N7 RESOLVED-S236): cocoindex per-flow op_id propagated into Postgres target rows + trigger-driven audit_log for governance cohesion.

Drift item 2.3-a (P2): TECH.md has no entry corresponding to the op_id hybrid pattern. PRODUCT.md §13.4 mentions it at line 484 but only as a one-liner. Neither PRODUCT.md nor TECH.md forward-references 02-data-flow.md §5 for the full hybrid pattern description. An S241 implementing agent writing the content_items schema addition for op_id column would not know where the canonical description lives. Fix: add a T-P-30a or equivalent item to TECH.md §4 (KG / memory model): “Hybrid op_id propagation: cocoindex per-flow op_id into target row columns + trigger-driven audit_log. Full pattern: 02-data-flow.md §5. Column addition: content_items.op_id (and other cocoindex target tables) as part of Q-OQR1-16 combined-PR scope per 0.9-decision-graph.md §11.4.1.”

2.4 pipeline_failures DO-NOT-BUILD — ALIGNED

Section titled “2.4 pipeline_failures DO-NOT-BUILD — ALIGNED”

PRODUCT.md §13.2 (line 444): “pipeline_failures table DO-NOT-BUILD; cocoindex retry/back-off/DLQ subsumes”. 02-data-flow.md §7.3 carries [RATIFIED-DO-NOT-BUILD] per COCO.7. No drift.

2.5 Freshness substrate separation — NOT IN CANONICAL-PIPELINE SPEC (P3)

Section titled “2.5 Freshness substrate separation — NOT IN CANONICAL-PIPELINE SPEC (P3)”

02-data-flow.md §9 describes the freshness-substrate separation: cocoindex ingest-latency vs governance freshness (content_items.freshness enum). This distinction is a Wave 2 addition that landed in S240. Neither PRODUCT.md nor TECH.md mentions this separation explicitly.

Drift item 2.5-a (P3): The freshness-substrate separation (cocoindex ingest-latency ≠ governance freshness) is a meaningful implementation constraint — re-ingesting a stale record does not reset governance freshness. It is not mentioned in canonical-pipeline PRODUCT.md or TECH.md. For v1 implementation, an agent not consulting 02-data-flow.md §9 might incorrectly couple cocoindex re-ingest to freshness state changes. Fix (nice-to-have): add a note to PRODUCT.md §13.2 or a new P-3a: “Cocoindex ingest does not update content_items.freshness (governance freshness). Freshness scoring is a separate substrate — details: 02-data-flow.md §9.”

2.6 Edit re-classification trigger policy (Theme C) — ABSENT IN CANONICAL-PIPELINE (P2)

Section titled “2.6 Edit re-classification trigger policy (Theme C) — ABSENT IN CANONICAL-PIPELINE (P2)”

02-data-flow.md §8 introduces the edit_intent Layer-1 CV as the trigger-or-skip signal for cocoindex re-classification: cosmetic (skip) / data / structural (re-run). This is Theme C RESOLVED-DIRECTIONAL. Canonical-pipeline PRODUCT.md and TECH.md do not describe the edit_intent → cocoindex re-run mapping at all. The UC edit flows in P-11 / TECH.md P-11 describe the seven UCs but not the intent-to-reclass mapping.

Drift item 2.6-a (P2): The edit_intent CV and its cocoindex trigger mapping is absent from canonical-pipeline PRODUCT/TECH. An S241 agent implementing UC1/UC4 would not know that edit_intent='cosmetic' skips cocoindex re-run (a significant implementation consequence). The Wave 2 sub-doc (02-data-flow.md §8) owns this detail; canonical-pipeline should forward-ref it. Fix: add to TECH.md P-11 target state under UC1/UC4: “Edit re-classification trigger: edit_intent value written at save time governs cocoindex re-run (cosmetic → skip; data / structural → trigger re-run). Full policy: 02-data-flow.md §8.”


Checking against landed 05-qa-flow.md (380 lines).

3.1 Markdown sidecar v1 pattern — ALIGNED BUT MISSING FORWARD-REF (P3)

Section titled “3.1 Markdown sidecar v1 pattern — ALIGNED BUT MISSING FORWARD-REF (P3)”

PRODUCT.md §11 (lines 341-345) lists “Markdown sidecar materialisation for approved Q&A pairs (UC5 4.6.Q7 + UC6 4.3.Q7) — DEFERRED-v1.1; v1 keeps approved Q&A pairs KH-DB-only.” TECH.md P-11 UC6 (lines 130-135) references “mempalace Shape A temporal columns record version transition” for user-direct UC6 revision. 05-qa-flow.md §4 now carries the full sidecar v1 pattern including the CLOSED-CONDITIONAL promotion gate + layered fn-shape requirement. Neither PRODUCT.md nor TECH.md forward-references 05-qa-flow.md §4.

Drift item 3.1-a (P3): TECH.md P-2 (markdown ingest end-to-end) carries “Spike S9 RESOLVED-PARTIAL (95% confidence)” + “Memo scoping per-component-path, not global content-hash” but does not cite 05-qa-flow.md §5 (cocoindex idempotency section) as the definitive record of the sidecar idempotency constraints. Fix: add to TECH.md P-2 “Idempotency detail (sidecar v1 pattern, layered fn-shape constraint): 05-qa-flow.md §4 + §5.”

3.2 question_matches table name — DRIFT (P1)

Section titled “3.2 question_matches table name — DRIFT (P1)”

PRODUCT.md P-21 (lines 143-149) uses bid_question_matches explicitly: “bid_question_matches carries separate embedding_score + fulltext_score columns”. TECH.md P-21 (lines 196-206) says: “bid_question_matches (renaming to question_matches per 0.9-collapse-candidates.md §12.5 row 4) carries separate embedding_score + fulltext_score columns”.

05-qa-flow.md §7.1 states the rename is settled — the table is never built under the old name: “The table is never built under the old name — it is created with the new name per the combined-PR direction.” 05-qa-flow.md §11 anti-patterns carries [RATIFIED-RENAME] on bid_question_matches.

Drift item 3.2-a (P1 — block-implementation): PRODUCT.md P-21 still refers to “bid_question_matches” by the old name without the rename parenthetical. TECH.md P-21 has the rename parenthetical but still lists the old name first. A fresh implementing agent reading PRODUCT.md P-21 would write code referencing bid_question_matches (the superseded name). 05-qa-flow.md §7 is unambiguous: the table is built as question_matches from day one. Fix (before S241 kickoff): update PRODUCT.md P-21 to use question_matches throughout, with a note “(formerly bid_question_matches — renamed pre-build per Q-OQR1-02; the old name was never built)”. Update TECH.md P-21 current-state / target-state to lead with question_matches.

3.3 question_kind discriminator — ABSENT FROM CANONICAL-PIPELINE (P2)

Section titled “3.3 question_kind discriminator — ABSENT FROM CANONICAL-PIPELINE (P2)”

05-qa-flow.md §7.2 describes question_matches.question_kind as the form-type discriminator (“holds the form-type discriminator… For v1 procurement workspaces, the value is 'bid' / 'rfp' / 'pqq' etc.”). TECH.md P-21 target state mentions ““question_kinddiscriminator added" (line 203) but does not explain what the column does or its alignment withform_typesvocabulary. PRODUCT.md P-21 does not mentionquestion_kind` at all.

Drift item 3.3-a (P2): question_kind discriminator is mentioned in TECH.md but not explained; absent from PRODUCT.md. An implementing agent would need to consult 05-qa-flow.md §7.2 to understand what values question_kind holds and why. Fix: add to PRODUCT.md P-21: “The question_matches table carries a question_kind column (aligned with the form_types vocabulary per Q-OQR1-02) discriminating by form type — 'bid' / 'rfp' / 'pqq' etc. for procurement workspaces. Full detail: 05-qa-flow.md §7.2.”

3.4 q_a_extractions derived cache — ABSENT FROM CANONICAL-PIPELINE (P2)

Section titled “3.4 q_a_extractions derived cache — ABSENT FROM CANONICAL-PIPELINE (P2)”

05-qa-flow.md §3 introduces q_a_extractions as a first-class table: a derived cache that cocoindex UPSERTs into, with promoted_to_pair_id lineage, invalidated_at on source change, extractor_kind enum. Canonical-pipeline PRODUCT.md and TECH.md do not mention q_a_extractions at all. The only references to Q&A extraction in TECH.md P-20 describe the q_a_pairs table as the cocoindex UPSERT target, which is the two-tier model’s q_a_pairs side — but q_a_extractions is the intermediate cache that cocoindex actually writes.

Drift item 3.4-a (P2): Canonical-pipeline TECH.md P-20 describes q_a_pairs as the cocoindex UPSERT target (lines 170-182) but 05-qa-flow.md §3.4 clarifies: “cocoindex UPSERTs into q_a_extractions via postgres.mount_table_target(managed_by='user')” — the extractions table is the direct cocoindex target; q_a_pairs is the curated golden record produced from manual promotion of extraction rows. This is a meaningful schema distinction for S241 implementation. Fix: add to TECH.md P-20 target state: “Cocoindex UPSERT target: q_a_extractions (derived cache per 05-qa-flow.md §3.4). q_a_pairs is the promoted golden record — cocoindex does not write directly to q_a_pairs. Two-tier model: extractions feed the review queue; curator promotes to q_a_pairs.”

3.5 UC5 / UC6 promotion-UI gaps — CONSISTENT WITH 05

Section titled “3.5 UC5 / UC6 promotion-UI gaps — CONSISTENT WITH 05”

PRODUCT.md P-11 UC5 and UC6 entries (lines 106-116) match 05-qa-flow.md §8 + §9 in direction. The 05-qa-flow.md §9.3 gap flag (UC5 promotion-UI shape: product spec needed for 3 sub-decisions) is not duplicated in canonical-pipeline PRODUCT.md — this is correct omission, not drift. No drift.


Per implementation-readiness audit §3 finding D1+D2. TECH.md §11 (lines 449-478) carries 8 open implementation questions.

4.1 Stale RLS-PATTERN destination entry — P1

Section titled “4.1 Stale RLS-PATTERN destination entry — P1”

TECH.md §11 (lines 465-468):

- **RLS-PATTERN.md destination** `[STILL-OPEN — Liam discretion]` — separate doc vs section within
`architecture/04-workspace-types`. Cite `00-synthesis-v2.md` §3.16. Working recommendation per
`INV-architecture-split-readiness.md` §7.4: standalone `docs/specs/rls-pattern/PRODUCT.md` + `TECH.md`.

This is factually resolved: docs/specs/rls-pattern/PRODUCT.md and docs/specs/rls-pattern/TECH.md landed S239 (confirmed by reading these files — they exist and carry [CURRENT-CANONICAL] status). The [STILL-OPEN] tag is stale. An S241 agent reading §11 would incorrectly treat this as unresolved investigative work.

Drift item 4.1-a (P1 — block-implementation): Update TECH.md §11 RLS-PATTERN entry to:

- **RLS-PATTERN.md destination** `[RESOLVED-S239]` — standalone spec pair:
`docs/specs/rls-pattern/PRODUCT.md` + `docs/specs/rls-pattern/TECH.md`. Both CURRENT-CANONICAL.
Liam ratified at S239 Wave 2 dispatch per `INV-architecture-split-readiness.md` §7.4. Cite
`00-synthesis-v2.md` §3.16 for the substrate; the spec pair is the implementation destination.

4.2 The 4 uncategorised STILL-OPEN items — P1 cluster

Section titled “4.2 The 4 uncategorised STILL-OPEN items — P1 cluster”

Per implementation-readiness audit D1 finding: four items in TECH.md §11 lack construction-guide §5.3 format (no category, no sources-checked note, no prerequisite work).

Item 4.2-a: Q&A migration rollback window [STILL-OPEN] (TECH.md lines 461-464)

  • Category: Ratification needed — Liam pre-decision on retention period before migration can include a hard-delete schedule.
  • Sources checked: 00-synthesis-v2.md §3.6 (q_a_pair migration rationale), 0.9-decision-graph.md §11.4, 0.9-edit-flow-investigation.md §6 — no retention period decision found.
  • Prerequisite work: Add a row to 00-synthesis-v2.md §5.2 STILL-OPEN register: “Q&A soft-archive retention window — Liam pre-decision required (options: 90 days / 1 year / indefinite). Compliance note: UK data-protection guidance recommends minimum 1-year retention for audit records.”
  • Priority: P1 (blocks migration completion — P-70 in PRODUCT.md depends on knowing how long soft-archived rows persist).

Item 4.2-b: Discriminated-union Pydantic with ExtractByLlm (Q-EX2) [STILL-OPEN] (TECH.md lines 473-474)

  • Category: Tech spec needed — implementation schema design for how ExtractByLlm typed output_type handles multi-entity discriminated unions (e.g. Q&A + entity mentions in one pass vs separate passes).
  • Sources checked: phase-b-prerequisite-2-cocoindex-deep-dive.md §4 Recommendation 1 (typed output_type recommendation), 00-synthesis-v2.md §3.1, 0.9-spike-S9-cocoindex-idempotency.md — no discriminated-union resolution found.
  • Prerequisite work: Suggested location: sub-section in docs/specs/id-31-0.9-canonical-pipeline/TECH.md §2 expansion (P-2 target state) or standalone docs/specs/id-36-cocoindex-extraction-contract/TECH.md. This gates TECH.md P-2 fully (cocoindex ExtractByLlm typed output shape).
  • Priority: P2 (does not block the start of S241 implementation; blocks the cocoindex extraction stage completion).

Item 4.2-c: Anthropic prompt-cache passthrough verification [STILL-OPEN] (TECH.md lines 475-476)

  • Category: Investigation needed — verify that the ExtractByLlm calls inside the cocoindex pipeline use prompt caching correctly (Anthropic API cache control headers in the extraction request shape).
  • Sources checked: 00-synthesis-v2.md §3.1, phase-b-prerequisite-2-cocoindex-deep-dive.md §4, CLAUDE.md claude-api skill guidance — no prompt-cache passthrough verification decision found.
  • Prerequisite work: Short spike (1-2h): write a test ExtractByLlm call that includes a cache_control block on the system prompt; confirm cache hit in the Anthropic API response. CLAUDE.md claude-api skill notes: “Apps built with this skill should include prompt caching.”
  • Priority: P2 (cost-projection concern, not a correctness gate; implementation can proceed without it).

Item 4.2-d: TS-facing API for cocoindex per-flow-run ledger [STILL-OPEN] (TECH.md lines 476-478)

  • Category: Tech spec needed — how the KH TypeScript API surface exposes per-flow-run metadata from cocoindex’s internal LMDB ledger (e.g. for the pipeline history UI, for the pipeline_runs rollup).
  • Sources checked: 02-data-flow.md §7.2 (N6 RESOLVED — pipeline_runs retained as KH-side rollup), phase-b-prerequisite-2-cocoindex-deep-dive.md §3.3, 00-synthesis-v2.md §5.2 row 5 — notes it as STILL-OPEN pending cocoindex TS API design.
  • Prerequisite work: 02-data-flow.md §7.2 (now landed S240) clarifies: “pipeline_runs insulates the KH UI from cocoindex schema changes.” The TS-facing API question is partially addressed — pipeline_runs is the KH-side rollup; the cocoindex internal ledger is not exposed. Update TECH.md §11 to reflect this partial resolution: “PARTIALLY-RESOLVED by 02-data-flow.md §7.2 (N6 RESOLVED — pipeline_runs retained as KH-side rollup). Remaining open: whether per-stage metrics from cocoindex LMDB are surfaced to the KH UI beyond pipeline_runs rollup. Category: tech spec needed. Prerequisite: docs/specs/pipeline-observability/TECH.md (future).”
  • Priority: P2 (does not block S241 kickoff; blocks full pipeline-observability story).

5.1 Forward-ref absent from PRODUCT.md — P2

Section titled “5.1 Forward-ref absent from PRODUCT.md — P2”

PRODUCT.md §5 (IMS naming cleanup) covers the combined-PR scope in P-40 (lines 183-211). P-40 lists 10 items verbatim from 0.9-decision-graph.md §11.3. Item 10 is: “q_a_pairs schema sketch update” — no satellite seat table forward-ref. The S240 addition of the reserved-workspace-seats spec pair (docs/specs/reserved-workspace-seats/PRODUCT.md + TECH.md) is not reflected anywhere in canonical-pipeline PRODUCT.md or TECH.md.

Drift item 5.1-a (P2): The canonical-pipeline PRODUCT.md P-40 combined-PR scope 10-item list does not include or reference the reserved satellite seats. An S241 agent scoping the combined PR from canonical-pipeline PRODUCT.md alone would not know the 5 seat tables are in scope for the same migration. Fix: add a forward-ref sentence after P-40 item 10: “Satellite seat tables (5 non-procurement): intelligence_workspaces, sales_proposal_workspaces, product_guide_workspaces, competitor_research_workspaces, training_onboarding_workspaces — created upfront with PK + FK + RLS only per docs/specs/reserved-workspace-seats/PRODUCT.md S-1 (NEW-S240 spec pair). These are an addendum to the 10-item combined-PR scope, ratified S240.”

5.2 TECH.md P-43 carries stale “TBD” satellite reference — P2

Section titled “5.2 TECH.md P-43 carries stale “TBD” satellite reference — P2”

TECH.md P-43 (lines 311-322) defines the application_types instance table target state. Column satellite_table_name is listed. However, there is no reference to the reserved-workspace-seats spec for how the satellite tables are actually created. The prior framing in TECH.md was written before the reserved-seats spec existed; now that 04-workspace-types.md §4.2 delegates to docs/specs/reserved-workspace-seats/ for the seat-shape invariants, TECH.md P-43 should cross-reference it.

Drift item 5.2-a (P2): TECH.md P-43 does not forward-reference docs/specs/reserved-workspace-seats/TECH.md for the per-seat DDL and migration shape. Fix: add to TECH.md P-43 Spike Requirement or Validation section: “Satellite table DDL + migration shape: docs/specs/reserved-workspace-seats/TECH.md (NEW-S240). Per-seat schema: PK + FK + RLS only at v1; per-app columns added via feature-spec ALTER.”


Checking whether canonical-pipeline uses the canonical S239 6-tag vocabulary or stale per-session-suffix tags.

PRODUCT.md §11 uses DEFERRED-v1.1 throughout (lines 329-365). TECH.md §10 references PRODUCT.md §11 correctly. The S239 canonical vocabulary includes [DEFERRED-v1.1]. No drift.

6.2 RATIFIED-RETIRE / RATIFIED-DO-NOT-BUILD — ABSENT (P3)

Section titled “6.2 RATIFIED-RETIRE / RATIFIED-DO-NOT-BUILD — ABSENT (P3)”

05-qa-flow.md §11 and 04-workspace-types.md §11 use the 6-tag vocabulary extensively: [RATIFIED-RETIRE], [RATIFIED-DO-NOT-BUILD], [RATIFIED-RENAME], [DEFERRED-v1.1], [CONDITIONAL-RETIRE]. Canonical-pipeline PRODUCT.md and TECH.md use [RATIFIED-S2XX] and [STILL-OPEN] tags from the S238 reconciliation pass, but do not use the 6-tag vocabulary for retired / do-not-build patterns.

For example, PRODUCT.md §11 mentions “Pattern A/B retires post-Phew-migration” without a [RATIFIED-RETIRE] tier marker. TECH.md §10 references PRODUCT.md §11 items without tier markers.

Drift item 6.2-a (P3): Canonical-pipeline uses the pre-S239 vocabulary ([RATIFIED-S2XX] / [STILL-OPEN]) throughout. The Wave 2 sub-docs use the 6-tag vocabulary ([RATIFIED-RETIRE] etc.) which is the canonical S239 standard. This creates vocabulary inconsistency if an S241 agent consults both doc families. Fix (nice-to-have, not P1): where canonical-pipeline PRODUCT.md §11 + §14 describe retired / deferred patterns, add the tier tag. E.g., “Pattern A/B retires” → “Pattern A/B [RATIFIED-RETIRE]”.

6.3 Per-session-suffix tags — NOT PRESENT (CLEAN)

Section titled “6.3 Per-session-suffix tags — NOT PRESENT (CLEAN)”

No *-S235, *-S237 per-session-suffix tags found in PRODUCT.md or TECH.md. The S238 reconciliation correctly used [RATIFIED-S234], [RATIFIED-S235] etc. as source-attribution markers, not per-session-suffix tiers. These are different from the stale per-session-suffix tier vocabulary. No drift on this axis.

6.4 [LOCKSTEP-WITH-MIGRATION] — ABSENT (P3)

Section titled “6.4 [LOCKSTEP-WITH-MIGRATION] — ABSENT (P3)”

04-workspace-types.md §6 uses [RATIFIED-RETIRE] for kb_section retirement noting “drop value from old CHECK pre-FK swap”. Canonical-pipeline PRODUCT.md P-40 item 3 describes the same retirement but without a tier tag. The [LOCKSTEP-WITH-MIGRATION] tag (part of the S239 6-tag vocabulary) would be appropriate for the CV 16 firecrawl and capability retire entries in §13.6 (lines 504-508) — these both say “pruned when CHECK migration drops it”.

Drift item 6.4-a (P3): Several PRODUCT.md §13.6 items describe lockstep-with-migration retires without the [LOCKSTEP-WITH-MIGRATION] tier tag. Fix (nice-to-have): tag capability retire (line 505-507) and firecrawl prune (line 521-523) as [LOCKSTEP-WITH-MIGRATION] for consistency with the S239 vocabulary used in 04-workspace-types.md §6.


#PriorityFile:sectionDrift itemRecommended edit
1P1TECH.md §11 lines 465-468Stale [STILL-OPEN] for RLS-PATTERN destinationReplace with [RESOLVED-S239] + cross-ref to docs/specs/rls-pattern/PRODUCT.md + TECH.md
2P1PRODUCT.md P-21 lines 143-149bid_question_matches old name used without rename-primary framingRewrite to question_matches throughout; add parenthetical “(renamed from bid_question_matches per Q-OQR1-02; never built under old name)“
3P1TECH.md §11 lines 461-464Q&A migration rollback window — no category/prerequisiteAdd: “Category: ratification needed. Prerequisite: Liam pre-decision on retention period (options: 90d / 1yr / indefinite). Add row to 00-synthesis-v2.md §5.2 STILL-OPEN register.”
4P2TECH.md P-1 lines 55-57Dead §-ref to 0.9-intended-architecture.md for Cloud Run sidecarReplace “§3.1 / §3.2” with “02-data-flow.md §4 (Cloud Run sidecar architecture)“
5P2PRODUCT.md P-40, after item 10No reserved-seats forward-ref in combined-PR scopeAdd addendum sentence referencing docs/specs/reserved-workspace-seats/PRODUCT.md S-1 (NEW-S240)
6P2TECH.md P-43No reserved-seats forward-ref for satellite DDLAdd “Satellite table DDL: docs/specs/reserved-workspace-seats/TECH.md (NEW-S240)“
7P2TECH.md §11 lines 473-474Q-EX2 Pydantic discriminated union — no category/prerequisiteAdd: “Category: tech spec needed. Prerequisite: docs/specs/id-36-cocoindex-extraction-contract/TECH.md or P-2 target state expansion.”
8P2TECH.md §11 lines 475-476Prompt-cache passthrough — no category/prerequisiteAdd: “Category: investigation needed. Prerequisite: short spike confirming ExtractByLlm request shape supports cache_control block.”
9P2TECH.md §11 lines 476-478TS-facing cocoindex ledger API — partially resolved by 02-data-flow.md §7.2Update to “PARTIALLY-RESOLVED by N6 RESOLVED (pipeline_runs retained). Remaining: per-stage metrics beyond rollup. Category: tech spec needed.”
10P2PRODUCT.md P-40, TECH.md P-43Satellite pattern — no forward-ref to 04-workspace-types.md §4 for the upfront-seats rationaleAdd cross-ref to 04-workspace-types.md §4.2 for the S240 upfront-seats ratification
11P2TECH.md P-11 UC1/UC4 target stateedit_intent → cocoindex re-run mapping absentAdd to UC1/UC4: “Re-classification trigger: edit_intent='cosmetic' → skip; data / structural → re-run. Full policy: 02-data-flow.md §8.”
12P2TECH.md P-21 lines 196-206question_kind column not explainedAdd explanation aligned with 05-qa-flow.md §7.2: form-type discriminator values
13P2TECH.md P-20 target stateq_a_extractions derived cache absentAdd: “Cocoindex UPSERT target: q_a_extractions (derived cache). q_a_pairs is the promoted golden record. Two-tier model: 05-qa-flow.md §3.”
14P2TECH.md P-21bid_question_matches rename parenthetical — old name still leadsRewrite target state to lead with question_matches; demote old name to historical note
15P2TECH.md P-31 line 237lib/mcp/tools/kg.ts TBC inlineReplace with “Checked lib/mcp/tools/ — no kg.ts present as of S238. KG workspace scoping via RLS on entity_mentions today.” (per implementation-readiness audit P5)
16P3TECH.md P-22No forward-ref to landed 05-qa-flow.md §6.2 for citations table detailAdd: “Full schema: 05-qa-flow.md §6.2.”
17P3TECH.md P-43satellite_table_name column — ahead of 04-workspace-types.md §3.1 intentional deferralAdd note: “Column list is spec-level; authoritative schema in the combined-PR migration SQL.”
18P3PRODUCT.md §13.2, TECH.md P-1Freshness-substrate separation not mentionedAdd note: “Cocoindex does not update content_items.freshness. Separate substrate: 02-data-flow.md §9.”
19P3PRODUCT.md §11, §13.6S239 6-tag vocabulary not applied to retire/lockstep itemsAdd [RATIFIED-RETIRE] / [LOCKSTEP-WITH-MIGRATION] to Pattern A/B retire, capability retire, firecrawl prune

P1 fixes are mandatory before S241 implementation kickoff. The stale [STILL-OPEN] for RLS-PATTERN destination (item 1) and the bid_question_matches naming drift (item 2) are the most dangerous: an S241 agent reading the spec without consulting Wave 2 sub-docs would either (a) investigate a question that is already settled, wasting budget, or (b) write code referencing the wrong table name. The Q&A rollback-window categorisation (item 3) gates the P-70 migration completion — an agent cannot complete the migration spec without knowing the retention period. These three fixes are 15-minute edits to TECH.md; they are not structural changes.

P2 fixes should be applied at S241 kickoff, not deferred. The missing reserved-seats forward-refs (items 5, 6), the dead Cloud Run sidecar §-ref (item 4), and the absent edit_intent → cocoindex re-run mapping (item 11) are all implementation-consequence gaps — an agent implementing UC1/UC4 without knowing the edit_intent trigger policy would build the wrong behaviour. The q_a_extractions two-tier model gap (item 13) is critical for the cocoindex stage implementation: an agent writing the cocoindex flow would target q_a_pairs directly instead of q_a_extractions, inverting the two-tier model. These P2 fixes can be applied by a single focused agent in S241 Phase 1 (doc-alignment pass before implementation begins).

Overall readiness verdict: ready after P1 + P2 fixes. The canonical-pipeline spec pair is architecturally sound — all P-N invariants are ratified, the tier vocabulary is correctly applied for the S238 reconciliation items, and the TECH.md code refs are grounded. The drift is principally a cross-doc forward-reference gap: the Wave 2 sub-docs landed significant new detail (6-stage cocoindex topology, edit_intent trigger policy, q_a_extractions two-tier model, reserved-seats spec pair, freshness-substrate separation) that the canonical-pipeline spec was not updated to reference. No invariant is at variance with the Wave 2 sub-docs; the canonical-pipeline spec is behind, not wrong. Applying the P1 + P2 forward-refs brings it fully into alignment with the landed architecture.