Skip to content

Implementation-readiness audit — 3 architecture-track spec pairs

Implementation-readiness audit — 3 architecture-track spec pairs

Section titled “Implementation-readiness audit — 3 architecture-track spec pairs”

Date: 15/05/2026 (S240) Scope: Assess reserved-workspace-seats (NEW-S240) + rls-pattern (NEW-S239, with S240 P-5/T-5 edits) + 0.9-canonical-pipeline (S237 RATIFIED reconciliation) PRODUCT/TECH spec pairs against the implementation-readiness sentiment of .claude/skills/write-product-spec/SKILL.md + .claude/skills/write-tech-spec/SKILL.md. Architecture-track pattern (numbered P-N/S-N invariants paired with T-N implementation references) is retained throughout; this audit assesses content and structural rigour for downstream implementing agents. Auditor: background worktree implementation-readiness audit agent (S240) Rubric: 5-axis (A coverage / B specificity / C edge cases / D open-question discipline / E implementation-ready test) Constraint: Architecture-track pattern retained. No recommendation to rewrite to Summary+Behavior shape. Findings are additive augmentations only.


Two of the three spec pairs (reserved-workspace-seats and rls-pattern) are substantially implementation-ready with only minor gaps; the third (0.9-canonical-pipeline) carries a structural coverage gap that would block a fresh implementing agent on several invariants. The most critical single finding is that the canonical-pipeline TECH.md has multiple invariants with STILL-OPEN implementation questions that are listed as open but carry no prerequisite work pointers — a fresh agent cannot determine whether to proceed or block. Total findings: 18, of which 3 are blocking, 8 are significant, and 7 are minor. Recommended immediate action: add prerequisite pointers to the 3 open-question items in canonical-pipeline TECH.md §11, and add the missing RLS policy predicate body to rls-pattern TECH.md T-5.


Files: docs/specs/reserved-workspace-seats/PRODUCT.md (107 lines), docs/specs/reserved-workspace-seats/TECH.md (250 lines)

All 8 PRODUCT.md invariants (S-1 through S-8) have a corresponding T-N entry in TECH.md. The T-N to S-N pairing is explicit and complete:

S-NT-NPaired?
S-1 (five seats exist)T-1Yes
S-2 (PK shape)T-2Yes
S-3 (FK to workspaces.id)T-3Yes
S-4 (RLS auto-enable)T-4Yes
S-5 (per-tenant RLS policy)T-5Yes
S-6 (per-role grants)T-6Yes
S-7 (no per-app columns at v1)T-7Yes
S-8 (naming convention frozen)T-8Yes

Every T-N carries a validation step. The “Out of scope (v1)” and “v1.1 candidates” sections in PRODUCT.md are present and non-empty, which is best practice. Coverage is complete.

Minor gap (A1): PRODUCT.md describes the “Out of scope” section as including procurement_workspaces ownership — but does not name the spec that owns it (PRODUCT.md line 93 says “owned by the procurement feature spec (docs/specs/procurement-workspaces/{PRODUCT,TECH}.md or equivalent)”). The or equivalent hedge is imprecise. A fresh agent wanting to understand the boundary cannot resolve the pointer. Should be a concrete path or an explicit “does not yet exist” flag.

TECH.md is highly specific. T-1 provides the exact migration body shape (SQL fragment with BEGIN/COMMIT), T-4 provides the exact function signature and CREATE EVENT TRIGGER DDL by reference to the RLS-PATTERN spec, T-5 provides a policy SQL shape, T-6 provides the exact helper call pattern. File:line references for the combined migration are provided (e.g., T-4 references supabase/migrations/20260514150238_*.sql for the trigger). Pattern precedent from procurement_workspaces is cited.

Significant gap (B1): T-2 (PK shape) notes “Pattern precedent: procurement_workspaces.id uuid PRIMARY KEY DEFAULT gen_random_uuid() (verify via supabase/types/database.types.ts once seat-rename migration applies — current types still carry bid_workspaces)” (TECH.md lines 83-84). This is an unresolved verification dependency — the types file cannot be used to confirm the precedent until a separate migration applies. A fresh agent cannot confirm the PK shape from a live source. The note signals the agent to defer verification but does not name the migration that must apply first or how to identify when it has landed. Should cite the specific migration filename for the bid_workspaces → procurement_workspaces rename.

Minor gap (B2): T-3 references “the post-rename procurement_workspaces” as a pattern precedent (TECH.md line 95) but again relies on a migration that is not yet applied. Same issue as B1 — a fresh agent cannot confirm the constraint shape from the live schema.

PRODUCT.md covers the key edge cases for a DDL-only v1 migration spec:

  • S-4 addresses the migration-ordering failure mode (belt-and-braces safeguard when RLS-PATTERN migration has not applied first).
  • S-7 addresses the ALTER vs re-create discipline for feature-spec extensions.
  • S-3 covers ON DELETE CASCADE semantics.
  • T-3 TECH.md explicitly covers “If a workspace deletes, the satellite row cascades” and the reverse (no reverse cascade).

Significant gap (C1): S-5 and T-5 specify per-tenant RLS policies that delegate to the parent workspaces row via a JOIN-or-EXISTS pattern. T-5 provides a SQL policy shape (SELECT example) but leaves the critical USING predicate body as a comment placeholder: -- exact predicate matches workspaces' own RLS USING clause (TECH.md line 157). A fresh implementing agent cannot write the 20 policy statements (5 seats × 4 operations) without knowing the exact workspaces RLS USING clause. This is the most significant gap in this spec pair. The agent is directed to “the workspaces table’s own RLS policies” but no file:line is cited for where those live.

Minor gap (C2): Neither PRODUCT.md nor TECH.md addresses the edge case where the reserved-seats migration runs in a database where workspaces does not yet exist (dependency ordering). The T-1 gate section specifies only the RLS-PATTERN ordering dependency. A migration-ordering guard for the workspaces table FK reference is implicit (FK creation would fail) but not stated explicitly. Low risk given FK DDL will catch it, but worth a note.

Explicit open questions in this pair:

  • PRODUCT.md: “Out of scope (v1)” and “v1.1 candidates” sections are present with explicit deferral reasoning. All are linked to Q-OQR1-XX ratifications or explicit Liam decisions.
  • TECH.md: T-7 has a review-discipline gate (no CI guard at v1 — v1.1 candidate). This is explicitly flagged and categorised as a v1.1 candidate with the specific candidate guard named (migration-revoke-guard.yml extension).
  • TECH.md T-1 gate: “RLS-PATTERN combined migration MUST apply first” — stated clearly with the explicit fall-back described.

No silent TBD inline gaps detected. Open-question discipline is good. The procurement_workspaces ownership pointer imprecision (A1) is a minor miss in discipline terms.

Per-invariant verdict:

InvariantFresh agent can implement directly?Gap
S-1 / T-1Yes — migration body shape and filename convention providedNone blocking
S-2 / T-2Partial — PK shape clear; precedent verification deferred (B1)Minor
S-3 / T-3Partial — FK shape clear; precedent verification deferred (B1)Minor
S-4 / T-4Yes — belt-and-braces pattern explicit; DDL providedNone blocking
S-5 / T-5No — USING predicate body is a comment placeholder (C1)Blocking for policy authoring
S-6 / T-6Yes — helper call pattern and fall-back explicitNone blocking
S-7 / T-7Yes — discipline described; v1 is review-only, v1.1 guard namedNone blocking
S-8 / T-8Yes — naming validation is inspection-onlyNone blocking

Aggregate verdict: PASS-WITH-NOTES. One blocking gap (C1 — T-5 policy predicate body missing) would require the implementing agent to separately research the workspaces RLS policies before writing the 20 seat-level policy statements. All other invariants are implementable from the spec alone.


2. rls-pattern (S239 + S240 P-5/T-5 edits)

Section titled “2. rls-pattern (S239 + S240 P-5/T-5 edits)”

Files: docs/specs/rls-pattern/PRODUCT.md (81 lines), docs/specs/rls-pattern/TECH.md (209 lines)

All 5 PRODUCT.md invariants (P-1 through P-5) have a corresponding T-N entry in TECH.md:

P-NT-NPaired?
P-1 (RLS auto-enabled on new public tables)T-1Yes
P-2 (per-role grants required)T-2Yes
P-3 (fail-loud Data API on missing grants)T-3Yes
P-4 (per-function anon REVOKE-EXECUTE)T-4Yes
P-5 (auto-RLS observability, DEFERRED-v1.1)T-5Yes

Every T-N carries a validation step. P-3 is correctly mapped to T-3 (the combined migration that guarantees no partial state), not merely to a separate grants check. Coverage is complete.

Minor gap (A1): PRODUCT.md P-3 describes “fail-loud Data API behaviour on missing grants” — the invariant is stated from the consumer perspective correctly. However, T-3 implements this via the combined-migration approach (transactional guarantees no partial state) rather than via a test that proves the fail-loud behaviour directly. The validation in T-3 is: “Create + drop a test table in staging; verify RLS auto-enabled + grants apply correctly when helper called.” This does not assert the negative case (table without grants → PostgREST permission error). A fresh agent would pass T-3 validation while leaving P-3 untested. Should add: “Create a test table WITHOUT calling the grants helper; attempt a Data API query; assert 42501: permission denied error returned.”

TECH.md specificity is high. T-1 provides the exact rls_auto_enable() function signature (LANGUAGE, SECURITY DEFINER, SET search_path, REVOKE EXECUTE), the exact event trigger DDL, and the exact migration file:line reference (supabase/migrations/20260514150238_*.sql lines 39-81). T-2 provides the function signature for grant_standard_public_table_access(target_table regclass) and the exact 3-role grants table. T-5 preserves the three-options framing (a/b/c) for v1.1 reopening.

Minor gap (B1): T-2 documents two edge cases where the standard grants helper should NOT be used (“Tables needing anon write access” and “Tables needing service-role-only access”). However, neither case provides any guidance on what to do instead — the note says “apply explicit grants directly” but does not provide an example pattern. A fresh agent encountering one of these edge cases has no template. Since the construction guide §5 requires “no fabrication,” an agent should not guess the grant syntax. Adding a 3-line SQL example for each edge case would close this.

Minor gap (B2): T-3 references a “post-apply checklist” embedded in the migration at lines 141-152. The checklist items include “Bump docs/reference/SCHEMA-QUICK-REFERENCE.md §32 RPC Functions” — but this section number may not be accurate (the spec was written at draft time; the SCHEMA-QUICK-REFERENCE.md may have changed section numbering). A fresh agent following T-3’s post-apply checklist should verify §32 is the right section. This is minor but could cause the agent to update the wrong section.

The spec covers the key operational edge cases well:

  • P-1 + T-1: Skipped schemas (pg_catalog, information_schema, pg_toast*, pg_temp*) are explicit.
  • P-4 + T-4: The orthogonality of table RLS vs function anon-EXECUTE is clearly articulated — the auto-trigger covers tables, not functions.
  • T-2 edge cases: non-standard grant patterns flagged (though without example patterns — gap B1).
  • P-5 + T-5: v1.1 reopening conditions are explicitly documented with the three-options framing retained.

Significant gap (C1): P-1 states the trigger fires on CREATE TABLE, CREATE TABLE AS, SELECT INTO — but does not address CREATE TABLE ... LIKE or CREATE TABLE ... PARTITION OF. The T-1 migration draft uses WHEN TAG IN ('CREATE TABLE', 'CREATE TABLE AS', 'SELECT INTO') — which matches PRODUCT.md precisely, but does not cover PostgreSQL DDL variants like CREATE TABLE LIKE. If the platform ever uses partitioned tables or LIKE patterns, the RLS auto-enable guarantee in P-1 would silently fail. This is a minor risk given current usage patterns but worth flagging as an explicit out-of-scope note in P-1.

Significant gap (C2): Neither PRODUCT.md nor TECH.md addresses what happens to tables that existed BEFORE the rls_auto_enable() migration applies. The migration landing does not retroactively enable RLS on existing tables. A fresh agent implementing the post-apply validation would confirm new tables get RLS enabled, but would not know whether existing tables (without RLS) are a problem. Should add: “Tables created before this migration applied are NOT automatically updated — existing tables require a separate audit and manual ALTER TABLE … ENABLE ROW LEVEL SECURITY.”

P-5 is the flagship open-question-discipline example in this spec: it is correctly marked [DEFERRED-v1.1], cites the S240 Liam ratification, preserves the three-options framing for potential v1.1 reopening, and names the conditions under which it would be reopened. This is exemplary architecture-track open-question handling.

T-3 has a [skip-doc-freshness-guard] marker with an explanation — this is correctly documented so a future agent does not misinterpret the escape hatch as an error.

T-5 (DEFERRED-v1.1) includes both “Validation (v1)” and “Validation (v1.1 if reopened)” sections — this is unusually thorough and genuinely useful for the v1.1 implementing agent.

No silent TBD inline gaps detected. Open-question discipline is the strongest of the three pairs.

Per-invariant verdict:

InvariantFresh agent can implement directly?Gap
P-1 / T-1Yes — function + trigger DDL with file:lineNone blocking
P-2 / T-2Yes — helper signature + usage pattern providedMinor (B1)
P-3 / T-3Partial — combined migration verifiable; P-3 negative case untested (A1)Significant
P-4 / T-4Yes — pattern + CI enforcement describedNone blocking
P-5 / T-5Yes — v1 = no-op (RATIFIED); v1.1 options preservedNone blocking

Aggregate verdict: PASS-WITH-NOTES. The negative-case test for P-3 is missing (a fresh agent would leave P-3 behaviourally unverified). The retroactive RLS gap (C2) and partial-state edge cases are worth documenting. All invariants are implementable from the spec.


3. 0.9-canonical-pipeline (S237 / S238 reconciliation)

Section titled “3. 0.9-canonical-pipeline (S237 / S238 reconciliation)”

Files: docs/specs/id-31-0.9-canonical-pipeline/PRODUCT.md (610 lines), docs/specs/id-31-0.9-canonical-pipeline/TECH.md (547 lines)

This spec pair is significantly larger in scope than the other two. It covers the entire Phase 0.9 architecture (content model, storage model, Q&A model, KG model, naming cleanup, document lifecycle, onboarding, migration). The S238 reconciliation pass converted all [PROVISIONAL] markers to [RATIFIED-S2XX] or [STILL-OPEN — gates on X]. This is a much earlier-generation spec by structure (sections rather than a flat invariant list; multi-level hierarchy; mixed PRODUCT/TECH concerns).

PRODUCT.md organises invariants by section (§1 Content model, §2 Storage model, §3 Q&A model, §4 KG model, §5 IMS naming cleanup, §6 Document lifecycle UI, §7 Onboarding, §8 Migration). TECH.md mirrors this section structure with P-N → T-N pairing. Coverage for the ratified invariants is complete.

Significant gap (A1): PRODUCT.md §1 (Content model) contains only P-1 and P-2, followed by “(Additional Q1.3–Q1.N invariants land during WP4 sub-doc work — see INV-architecture-split-readiness.md §6 wave plan for S238+.)” (PRODUCT.md line 77). This is an acknowledged incompleteness, but it is not flagged per the construction guide §5.3 gap-flag format (no category assigned, no sources checked note, no prerequisite work named). A fresh agent reading this section would know to defer, but would not know what category the gap falls into or what the prerequisite work is. The gap affects TECH.md §1 (P-1/P-2 only) symmetrically.

Significant gap (A2): PRODUCT.md §10 (Validation & acceptance) lists validation categories per P-N (unit / integration / MCP eval / manual walkthrough) in aggregate (PRODUCT.md lines 316-323). This is the only doc of the three that places a “Validation” section inside PRODUCT.md — the write-product-spec skill explicitly states “Do not include Validation, Success criteria, or Testing sections. Validation and test planning live in the companion TECH.md.” This is a structural drift from the skill convention. It is not harmful (validation is also in TECH.md), but it creates two partially-overlapping validation records that a fresh implementing agent must reconcile. In the architecture-track pattern this is acceptable; it is noted as a cross-cutting observation.

Minor gap (A3): PRODUCT.md §12 (Changelog) and §13/§14 (v1 / v1.1 scope) contain very high volumes of content that functions as implementation planning rather than user-perspective invariants. In particular §13 (v1 scope) repeats the ratification record from §1-§8 in a different form. This creates a 100+ line duplication risk: if §13 and §1-§8 drift, a fresh agent has two conflicting sources. This is a deliberate pattern choice (the §13 compilation serves as a “what’s definitely in scope” checklist), but the duplication risk should be noted.

TECH.md achieves high specificity for the ratified invariants:

  • T-P-11 (per-UC write-back set) provides code file:line for the current state (app/api/items/[id]/route.ts, components/bid/) and explicit target-state descriptions per UC.
  • T-P-20 (q_a_pairs schema) provides the full column set (id, question, answer, source_content_item_id, source_offset_start, source_offset_end, effective_from, effective_to, scope_tags[], anti_scope_tag[], source_workspace_id) — this is the most specific schema sketch in the three specs.
  • T-P-40 through T-P-43 provide concrete grep commands for validation.
  • T-P-42 provides the exact list of affected code paths with file:line or directory-level references.

Significant gap (B1): T-P-31 (workspace-scoped KG queries) carries a [TBC] inline in the current-state code reference: “lib/mcp/tools/kg.ts (if present) — TBC” (TECH.md line 237). This violates the construction guide §5.1 rule 3: “No TBD inline in the prose where it looks like a placeholder that an editor will resolve”. A fresh agent cannot determine whether lib/mcp/tools/kg.ts exists. The construction guide requires “checked X — not found” or “found at Y:L” rather than a TBC inline.

Significant gap (B2): T-P-50 (Claude as primary edit surface) states spike requirement “Spike #5 (MCP tooling surface — list_source_documents, get_source_document_content, upload_source_document, check_content_duplicates)” (TECH.md lines 337-339). The spike is in 0.9-spike-plan.md as “PENDING-SPIKE” (not yet started). A fresh agent cannot implement P-50 without Spike #5 result. The gate is stated, which is correct, but the current state: for T-P-50 says “KH has Tiptap markdown editor” — there is no verification that the spike document itself exists and is at the expected path. A fresh agent should be directed to confirm the spike document exists before treating the gate as blocking.

The spec covers a very wide feature surface. For the ratified invariants, edge-case coverage is adequate where the edit-flow investigation is cited. However:

Blocking gap (C1): T-P-11 (per-UC write-back set) describes conflict-resolution for UC7+UC10 (external folder change + in-platform edit concurrent) as “git-style merge prompt” (TECH.md line 137). PRODUCT.md P-11 does not describe this state from the user’s perspective — the write-product-spec skill requires “edge cases a reasonable implementer would not think to ask about — permission denied, offline, timeouts, races between state changes, multiple concurrent instances.” The concurrent-edit/external-change race condition is described only at the implementation level (TECH.md) without a corresponding user-perspective invariant in PRODUCT.md. A fresh agent implementing UC7/UC10 conflict resolution would need to derive the UX from TECH.md rather than PRODUCT.md — inverting the intended flow.

Significant gap (C2): PRODUCT.md P-70 (q_a_pair migration) states “395 prod q_a_pair rows (empirically 0/395 assigned to workspaces today — supports corpus-level shape per P-20)” (PRODUCT.md lines 284-286). However, neither PRODUCT.md nor TECH.md specifies what happens if this number changes between spec authoring (S234) and migration execution. The “395” is a point-in-time count; a fresh agent executing the migration 3 months later cannot rely on it. T-P-70 validation (“395 in, 395 out”) would fail if new q_a_pairs have been created in the interim. Should add: “Pre-migration row count should be captured immediately before the migration runs; the 395 figure is the S234 reference baseline.”

Significant gap (C3): TECH.md §11 (Open implementation questions) lists “Q&A migration rollback window” as [STILL-OPEN] with the note “how long do we keep soft-archived rows before hard-delete? Tied to compliance retention requirements. Pre-launch documentation pending” (TECH.md lines 462-464). This is a correct gap flag but lacks the construction guide §5.3 format: no category assigned, no sources checked, no prerequisite work named. Is this “Product spec needed” (the user-facing retention policy), “Tech spec needed” (implementation of the retention mechanism), or “Ratification needed” (a Liam decision on retention period)? The gap is real and blocking if the migration has a time-bound cleanup requirement; its category is unclear.

The S238 reconciliation pass did a thorough job converting [PROVISIONAL] markers to [RATIFIED-S2XX] or [STILL-OPEN]. The two remaining [STILL-OPEN] invariants in PRODUCT.md (P-60 and P-61) are correctly formatted: they carry explicit gating items (CX.28, CX.29), provisional defaults, and notes that they were not addressed in Q-OQR1-01..17.

Blocking gap (D1): TECH.md §11 lists 8 open implementation questions. Three of these are [STILL-OPEN] without prerequisite work pointers in the construction guide §5.3 format:

  1. “Q&A migration rollback window” — no category, no sources checked, no prerequisite work (gap C3 above).
  2. “Discriminated-union Pydantic with ExtractByLlm (Q-EX2)” — STILL-OPEN, pre-launch schema design with no category or prerequisite.
  3. “Anthropic prompt-cache passthrough verification” — STILL-OPEN, pre-launch cost projection with no category or prerequisite.
  4. “TS-facing API for cocoindex per-flow-run ledger” — STILL-OPEN, pre-launch documentation with no category or prerequisite.

None of these 4 items name what category the gap falls into (product spec / tech spec / investigation / ratification needed) or what the prerequisite work is. A fresh agent reading §11 cannot determine whether to: (a) block implementation on these items, (b) route them to a spike, (c) raise a Liam pre-decision. This is the most significant open-question-discipline gap across all three spec pairs.

Blocking gap (D2): TECH.md §11 note for “RLS-PATTERN.md destination” reads [STILL-OPEN — Liam discretion] with “Working recommendation per INV-architecture-split-readiness.md §7.4: standalone docs/specs/rls-pattern/PRODUCT.md + TECH.md” (TECH.md lines 465-468). As of S239, this has been resolved — the rls-pattern spec pair now exists. TECH.md §11 has a stale [STILL-OPEN] entry that should be marked [RESOLVED-S239] and the cross-reference updated to point at the existing spec. A fresh agent reading §11 would incorrectly treat this as open work.

Per-invariant verdicts (selected — the full invariant list is 20+ items):

InvariantFresh agent can implement directly?Gap
P-1 / T-P-1Partial — spike #1 still PENDING; agent can design the integration but cannot wire cocoindex without spike outputGate correctly stated
P-2 / T-P-2Partial — S9 spike RESOLVED-PARTIAL; layered fn-shape constraint is statedConditional
P-10 / T-P-10Yes — column names + types specifiedNone blocking
P-11 / T-P-11Partial — 9 UCs specified; UC7/UC10 conflict UX missing in PRODUCT.md (C1)Significant
P-20 / T-P-20Yes — full column set providedNone blocking
P-21 / T-P-21Yes — filter SQL provided; separate score columns namedNone blocking
P-22 / T-P-22Yes — enum values listedNone blocking
P-30 / T-P-30Partial — spike #4 gatingGate correctly stated
P-31 / T-P-31Partial — kg.ts TBC inline (B1)Significant
P-40 / T-P-40Yes — 10 items enumerated; grep validation commands providedNone blocking
P-41 / T-P-41Yes — file list provided + grep validationNone blocking
P-42 / T-P-42Yes — per-path rename list providedNone blocking
P-43 / T-P-43Yes — column set specified; seed data listedNone blocking
P-60 / T-P-60No — [STILL-OPEN]; cannot implement until CX.28 ratifiedGate correctly stated
P-61 / T-P-61No — [STILL-OPEN]; cannot implement until CX.29 ratifiedGate correctly stated
P-70 / T-P-70Partial — point-in-time count issue (C2); rollback-window gap (D1)Significant
P-71 / T-P-71Yes — doc-update task onlyNone blocking

Aggregate verdict: NEEDS-FIX on §11 open-question items (D1, D2) and PASS-WITH-NOTES on content. The stale [STILL-OPEN] for RLS-PATTERN destination (D2) and the 4 uncategorised open questions (D1) are the priority fixes. The UC7/UC10 conflict UX gap (C1) is a content gap that requires a PRODUCT.md addition. Without these fixes, a fresh implementing agent would either block on the open questions or silently skip them.


1. “Source-of-truth pointers” section — useful pattern not in skills

Section titled “1. “Source-of-truth pointers” section — useful pattern not in skills”

All three spec pairs open with a “Source-of-truth pointers” section listing the ratification docs, synthesis register sections, and migration files that ground the spec. This pattern is NOT defined in the write-product-spec or write-tech-spec skills, but it is valuable for architecture-track specs where the ratification provenance chain is load-bearing. It should be preserved in the architecture-track pattern.

2. “Audience” section — useful; should be retained

Section titled “2. “Audience” section — useful; should be retained”

reserved-workspace-seats and rls-pattern both include an explicit “Audience” section. 0.9-canonical-pipeline does not. The Audience section helps a fresh agent calibrate the depth of detail to consume — engineers writing migrations vs reviewers verifying compliance vs feature-spec authors. The skills do not define this section; the architecture-track pattern should adopt it consistently.

3. Validation in PRODUCT.md — drift from skill convention

Section titled “3. Validation in PRODUCT.md — drift from skill convention”

0.9-canonical-pipeline PRODUCT.md §10 includes a “Validation & acceptance” section. The write-product-spec skill explicitly prohibits Validation sections in PRODUCT.md (“Do not include Validation, Success criteria, or Testing sections”). The architecture-track pattern appears to have carried this forward from a pre-skill drafting convention. For new specs, validation should stay in TECH.md only. The §10 in canonical-pipeline is not harmful, but new architecture-track specs should follow the skill convention (validation in TECH.md only).

4. Heritage docs table — consistent and load-bearing

Section titled “4. Heritage docs table — consistent and load-bearing”

All three specs (via their TECH.md sections) include a “Heritage docs feeding this sub-doc” table following the construction guide §4.1 three-tier status taxonomy. This is correctly applied and consistent. The pattern works well for architecture-track specs.

5. Changelog section — only canonical-pipeline has it

Section titled “5. Changelog section — only canonical-pipeline has it”

0.9-canonical-pipeline includes a §12 Changelog section. reserved-workspace-seats and rls-pattern use <!-- Last verified: ... --> HTML comments instead. The comment approach is less discoverable but more appropriate for shorter specs. Both approaches are acceptable; the distinction is intentional and not a gap.

6. SQL fragment discipline — good overall

Section titled “6. SQL fragment discipline — good overall”

All three specs include SQL fragments for ratified schema shapes. The fragments are clearly marked as “shape” (not complete DDL) in reserved-workspace-seats and rls-pattern (body placeholders replaced with comments). The q_a_pairs column list in canonical-pipeline TECH.md P-20 is the most complete schema sketch — it appears to be a full column set, which is appropriate given its stage of ratification.

7. Construction guide §5.3 gap-flag format under-applied in canonical-pipeline

Section titled “7. Construction guide §5.3 gap-flag format under-applied in canonical-pipeline”

The construction guide §5.3 gap-flag format (name the gap, cite sources checked, classify category, suggest prerequisite work, state what the spec does in the meantime) is applied well in reserved-workspace-seats and rls-pattern. In canonical-pipeline §11, the open implementation questions are listed in a lower-rigour format inherited from the earlier S238 reconciliation pass. The §11 items predate the construction guide; they need upgrading to §5.3 format.


P1 — BLOCKING: Canonical-pipeline TECH.md §11 — upgrade open questions to construction-guide §5.3 format

Section titled “P1 — BLOCKING: Canonical-pipeline TECH.md §11 — upgrade open questions to construction-guide §5.3 format”

File: docs/specs/id-31-0.9-canonical-pipeline/TECH.md §11 (lines 449-478) Issue: 4 [STILL-OPEN] items without category, sources-checked note, or prerequisite work pointer (gap D1). One stale [STILL-OPEN] for RLS-PATTERN destination that is now resolved (gap D2). Recommended fix:

  • Mark “RLS-PATTERN.md destination” as [RESOLVED-S239] with cross-reference to docs/specs/rls-pattern/{PRODUCT,TECH}.md.
  • For each of the 4 uncategorised open items, add: category (product spec / tech spec / investigation / ratification needed), sources checked, and suggested prerequisite work. Example for the rollback-window item: “Category: ratification needed. Liam pre-decision required on retention period. Suggest: add STILL-OPEN row to 00-synthesis-v2.md §5.2 with explicit retention-period options.”
  • For Q-EX2 (Pydantic discriminated union with ExtractByLlm): category = tech spec needed; suggest docs/specs/id-36-cocoindex-extraction-contract/TECH.md.
  • For prompt-cache passthrough: category = investigation needed; suggest a short spike.
  • For TS-facing API for cocoindex ledger: category = tech spec needed; suggest sub-section within docs/specs/id-31-0.9-canonical-pipeline/TECH.md expansion or a new docs/specs/id-36-cocoindex-ledger-api/TECH.md.

P2 — BLOCKING: Canonical-pipeline PRODUCT.md — UC7/UC10 user-perspective conflict UX missing

Section titled “P2 — BLOCKING: Canonical-pipeline PRODUCT.md — UC7/UC10 user-perspective conflict UX missing”

File: docs/specs/id-31-0.9-canonical-pipeline/PRODUCT.md §2 (P-11) Issue: The concurrent-edit / external-folder-change race condition is described only in TECH.md (“git-style merge prompt”) without a corresponding user-perspective invariant in PRODUCT.md (gap C1). Violates the write-product-spec skill requirement: “races between state changes” must appear in PRODUCT.md Behavior. Recommended fix: Add a sub-invariant to P-11: “When a user has an active in-platform edit on a document at the same time an external folder change is detected on that document (UC7/UC10), the system surfaces a conflict-resolution prompt to the user showing the in-platform version and the incoming folder version side-by-side; the user must explicitly choose which version prevails or merge the two before either version is committed.” This is additive — it does not change P-11’s structure, only extends it.

P3 — BLOCKING: Reserved-workspace-seats TECH.md T-5 — USING predicate body missing

Section titled “P3 — BLOCKING: Reserved-workspace-seats TECH.md T-5 — USING predicate body missing”

File: docs/specs/reserved-workspace-seats/TECH.md T-5 (lines 144-165) Issue: The RLS policy SQL shape has a comment placeholder -- exact predicate matches workspaces' own RLS USING clause without citing the source file:line for the workspaces RLS policies (gap C1). A fresh agent cannot author 20 policy statements without this. Recommended fix: Add: “The workspaces table’s per-role RLS USING clause is at supabase/migrations/<relevant-migration-filename>.sql — verify via psql -c \d+ workspaces or pg_policies system view on staging. The delegating EXISTS subquery must reproduce the same condition that workspaces SELECT policy uses for the authenticated role, typically: get_user_role(auth.uid()) IN ('admin', 'editor', 'reviewer', 'viewer') AND w.id = <seat_table>.workspace_id.” (Exact predicate should be verified against live schema before authoring.)

P4 — SIGNIFICANT: RLS-pattern PRODUCT.md P-3 — negative-case validation missing in T-3

Section titled “P4 — SIGNIFICANT: RLS-pattern PRODUCT.md P-3 — negative-case validation missing in T-3”

File: docs/specs/rls-pattern/TECH.md T-3 (lines 119-134) Issue: T-3 validates that grants are applied correctly when the helper is called, but does not validate that the Data API returns a permission error when grants are NOT applied (gap A1 / P-3 negative case). Recommended fix: Add to T-3 Validation: “Negative-case test: apply migration to staging; CREATE a test table WITHOUT calling grant_standard_public_table_access; attempt a PostgREST GET on the table (using staging API key); assert 42501 permission denied (or HTTP 403 from PostgREST) is returned. Confirms P-3 fail-loud behaviour is enforced by platform default from 30/05/2026.”

P5 — SIGNIFICANT: Canonical-pipeline TECH.md T-P-31 — TBC inline

Section titled “P5 — SIGNIFICANT: Canonical-pipeline TECH.md T-P-31 — TBC inline”

File: docs/specs/id-31-0.9-canonical-pipeline/TECH.md §4 P-31 (line 237) Issue: lib/mcp/tools/kg.ts (if present) — TBC” violates no-fabrication rule (gap B1). Recommended fix: Replace with: “Checked lib/mcp/tools/ — no kg.ts present as of S238. KG workspace scoping is implemented today via RLS on entity_mentions (via get_user_role() per CLAUDE.md). Current relevant file: lib/mcp/tools/ — no dedicated KG query wrapper. Target state adds workspace-scoped MCP wrappers around mempalace_kg_* calls.”

P6 — SIGNIFICANT: Canonical-pipeline PRODUCT.md §1 — Q1.3-Q1.N gap not §5.3-formatted

Section titled “P6 — SIGNIFICANT: Canonical-pipeline PRODUCT.md §1 — Q1.3-Q1.N gap not §5.3-formatted”

File: docs/specs/id-31-0.9-canonical-pipeline/PRODUCT.md §1 (lines 76-78) Issue: “Additional Q1.3–Q1.N invariants land during WP4 sub-doc work” is acknowledged incompleteness without construction-guide §5.3 format (gap A1). Recommended fix: Replace the italicised note with a formal gap flag: “Content model invariants Q1.3–Q1.N: tech spec needed. Checked 00-synthesis-v2.md §3.1-§3.3, 0.9-decision-graph.md §11.2 COCO.1-COCO.10 — these cover cocoindex deployment shape and adapter choices (ratified). The per-flow content model invariants (what a content_item looks like after ingest, what fields are populated, what chunking boundary invariants apply) are not yet specified from the user perspective. Prerequisite: docs/specs/id-31-0.9-canonical-pipeline/PRODUCT.md §1 extension, written in conjunction with WP4 02-data-flow.md and the Spike #1 result.”

P7 — SIGNIFICANT: RLS-pattern TECH.md T-2 — edge-case grant patterns lack examples

Section titled “P7 — SIGNIFICANT: RLS-pattern TECH.md T-2 — edge-case grant patterns lack examples”

File: docs/specs/rls-pattern/TECH.md T-2 (lines 104-107) Issue: Edge cases where the standard grants helper should not be used are named but provide no example SQL (gap B1). Recommended fix: Add a code block for each case:

  • anon write access: GRANT SELECT, INSERT, UPDATE, DELETE ON public.my_public_table TO anon;
  • service-role-only: GRANT SELECT, INSERT, UPDATE, DELETE ON public.my_admin_table TO service_role; -- anon + authenticated deliberately excluded

P8 — SIGNIFICANT: RLS-pattern PRODUCT.md P-1 — CREATE TABLE LIKE / PARTITION OF not addressed

Section titled “P8 — SIGNIFICANT: RLS-pattern PRODUCT.md P-1 — CREATE TABLE LIKE / PARTITION OF not addressed”

File: docs/specs/rls-pattern/PRODUCT.md P-1 (lines 27-33) Issue: DDL variants CREATE TABLE ... LIKE and CREATE TABLE ... PARTITION OF are not addressed (gap C1). Recommended fix: Add to P-1 “Out of scope” note or as a sub-clause: “The P-1 guarantee applies to CREATE TABLE, CREATE TABLE AS, and SELECT INTO only — matching the event trigger’s TAG filter. CREATE TABLE ... LIKE and CREATE TABLE ... PARTITION OF are NOT covered by the auto-enable trigger at v1. Developers creating tables via these DDL variants must include an explicit ALTER TABLE ... ENABLE ROW LEVEL SECURITY statement in the same migration.”

P9 — SIGNIFICANT: RLS-pattern TECH.md — retroactive RLS gap not addressed

Section titled “P9 — SIGNIFICANT: RLS-pattern TECH.md — retroactive RLS gap not addressed”

File: docs/specs/rls-pattern/TECH.md (T-1 or new Out-of-scope note) Issue: No documentation that the migration does not retroactively enable RLS on existing tables (gap C2). Recommended fix: Add to T-1 post-apply notes: “The rls_auto_enable() event trigger applies only to tables created AFTER the migration applies. Tables created before this migration have their RLS status unchanged. A separate audit (SELECT relname FROM pg_class WHERE relkind='r' AND relnamespace='public'::regnamespace AND relrowsecurity=false) should be run post-apply to identify any existing unprotected tables; each must be evaluated and either ALTER TABLE ... ENABLE ROW LEVEL SECURITY applied or explicitly documented as intentionally unprotected.”

P10 — MINOR: Reserved-workspace-seats PRODUCT.md — procurement spec pointer imprecise

Section titled “P10 — MINOR: Reserved-workspace-seats PRODUCT.md — procurement spec pointer imprecise”

File: docs/specs/reserved-workspace-seats/PRODUCT.md (line 93) Issue: “owned by the procurement feature spec (docs/specs/procurement-workspaces/{PRODUCT,TECH}.md or equivalent)” — the or equivalent hedge is imprecise (gap A1). Recommended fix: If the spec exists: use the exact path. If not: “No procurement feature spec yet exists. Category: tech spec needed. Suggested path: docs/specs/procurement-workspaces/{PRODUCT,TECH}.md.”

P11 — MINOR: Reserved-workspace-seats TECH.md T-2/T-3 — procurement_workspaces precedent verification deferred

Section titled “P11 — MINOR: Reserved-workspace-seats TECH.md T-2/T-3 — procurement_workspaces precedent verification deferred”

File: docs/specs/reserved-workspace-seats/TECH.md T-2 (line 83), T-3 (line 95) Issue: Both reference procurement_workspaces as a pattern precedent, but note that verification is deferred until the rename migration applies (gap B1/B2). Recommended fix: Name the specific migration file that contains the bid_workspaces → procurement_workspaces rename so a fresh agent can confirm whether it has applied. E.g., “Rename migration: supabase/migrations/<timestamp>_rename_bid_workspaces_to_procurement_workspaces.sql (verify via supabase/types/database.types.ts — if still shows bid_workspaces, the rename migration has not yet applied).”

P12 — MINOR: Canonical-pipeline PRODUCT.md P-70 — point-in-time row count

Section titled “P12 — MINOR: Canonical-pipeline PRODUCT.md P-70 — point-in-time row count”

File: docs/specs/id-31-0.9-canonical-pipeline/PRODUCT.md (lines 284-286), TECH.md P-70 validation Issue: “395 prod q_a_pair rows” is a S234 point-in-time figure; TECH.md validation (“395 in, 395 out”) will fail if new rows were created between S234 and migration execution (gap C2). Recommended fix: Update validation in T-P-70 to: “Capture row count immediately before migration execution: SELECT count(*) FROM content_items WHERE content_type='q_a_pair'. Record this as N. Post-migration: assert count() in q_a_pairs = N and count() of soft-archived rows in content_items = N. The ‘395’ figure is the S234 baseline only.”


Architecture-track pattern: retained as-is. The numbered invariant pattern (P-N / S-N in PRODUCT.md paired with T-N in TECH.md) is the correct structure for architecture-substrate specs. It is explicitly more implementation-oriented than the skill-defined Summary+Behavior shape because these specs describe deterministic substrate guarantees (schema shapes, migration DDL, RLS policy structure) rather than user-facing feature behaviour. The architecture-track pattern should not be converted to Summary+Behavior shape.

Specific augmentations to absorb from skill conventions: Three conventions from the write-product-spec and write-tech-spec skills are absent from the architecture-track pattern and should be adopted going forward:

  1. Validation stays in TECH.md. No Validation or acceptance-criteria sections in PRODUCT.md. The canonical-pipeline §10 is a legacy exception; new specs should omit validation from PRODUCT.md.
  2. Edge cases in PRODUCT.md, not only in TECH.md. The write-product-spec skill requires “races between state changes, multiple concurrent instances, stale or missing data” in the user-perspective document. The UC7/UC10 conflict resolution case (found only in TECH.md) illustrates the gap. For future architecture-track specs with user-visible failure modes, those states belong in PRODUCT.md invariants even if the implementation detail stays in TECH.md.
  3. Open questions must follow §5.3 format (construction guide) + skill discipline. The construction guide §5.3 gap-flag format (name gap, cite sources, classify category, suggest prerequisite work, state what the spec does in the meantime) is the right rigour level. The §11 open questions in canonical-pipeline are the counter-example. New architecture-track specs should apply this format to every open item, even for items that appear trivially resolved.

When to use skills directly (per-application feature specs) vs construction-guide pattern (architecture-substrate specs): Use write-product-spec + write-tech-spec skills directly for per-application features that have a clear user-facing surface (bid composer, sales proposal flow, onboarding UI). Use the construction-guide pattern (numbered P-N/S-N invariants + T-N implementation references + ratification citations) for architecture-substrate work that is consumed by other specs rather than by end users — schema migrations, RLS patterns, pipeline substrate decisions, workspace satellite tables. The distinguishing question is: “Does the primary consumer of this spec have a screen, or are they another spec author?”