From d0c60bc008f18dfdbd996a79ff4f7753d0252c85 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 10:27:00 +0000 Subject: [PATCH] docs(db): record the execution traps and the parallel-session coordination rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The playbook is already the multi-session guide, so this extends it rather than adding a fourth overlapping document — CLAUDE.md's whole argument for keeping AGENTS.md, CLAUDE.md and codebase-index.md non-overlapping is what stops five AI systems drifting apart, and a separate coordination file would have duplicated the phase list, refs and status and gone stale the moment one was updated alone. What the playbook did not carry is the failure knowledge. Two additions: Traps this programme has already hit — all observed, none hypothetical: - the newest migration mentioning a match_* function often only re-asserts grants and contains no body at all (20260724130000, 20260724120000), while the functions are redefined 2-16 times each; - joining manifest signatures to live regprocedure text reports all 93 functions as simultaneously missing and extra, which is a join failure and not a finding; - ledger rows must be resolved by exact title AND confirmed still in the open table — the anchor was once cited as #312, an unrelated row, and a close for #333 matched the archived row and threw "#333 is already archived", which red-lined docs:check-links for a whole branch; - Node 24 is mandatory under engine-strict, and a container shipping Node 20/22 fails npm ci with EBADENGINE and leaves tsx unresolvable; - two tooling failures are already fixed in PR #1978, so their symptoms should be recognised rather than re-diagnosed. Running two phases at once: phases with different targets can run concurrently, but the collision surface is the ledger, not the database. One ledger row per session assigned explicitly in the prompt; one reconciliation at a time from a fresh base; never merge main into a PR carrying a reconciliation; and verify merged content on main rather than the commit title (#324). Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01BKNFogaYfCQBvFVqFQnfRt --- docs/database-remediation-playbook.md | 42 +++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/docs/database-remediation-playbook.md b/docs/database-remediation-playbook.md index 0c8deceb92..28851e5223 100644 --- a/docs/database-remediation-playbook.md +++ b/docs/database-remediation-playbook.md @@ -73,11 +73,53 @@ against a pinned canonical definition, and only then marks a fail-fast guard mig attestation apply), `#025` (webhook inert), `#183` (missing SUPABASE_ACCESS_TOKEN), `#188`/`#196`–`#200` (DR gaps), `#191` (ACL consolidation — last), `#098`/`#099` (round trips). +**Traps this programme has already hit.** Each cost real time; none is hypothetical. + +- **The newest migration mentioning a function often does not define it.** These `match_*` functions + are redefined 2–16 times across migrations, and + `20260724130000_explicit_base_match_rpc_execute_grants.sql` — the newest file mentioning several of + them — contains **zero** `create or replace function`; it only re-asserts grants. Same shape for + `20260724120000_table_facts_plpgsql_execute.sql`. Select the latest migration carrying an actual + `as $$ … $$` body, not merely a reference. +- **Normalize before joining live functions to the manifest.** Joining manifest signatures to live + `p.oid::regprocedure::text` reports all 93 functions as simultaneously missing _and_ extra, because + the manifest stores `public.fn(extensions.vector,…)` while a live session renders `fn(vector,…)`. + That is a join failure, not a finding. Strip `public.`, fold `extensions.vector` → `vector`, then + test each surviving mismatch against the qualification variants before calling it divergence. +- **Resolve ledger rows by exact title, and check the row is still in the _open_ table.** The + tracking anchor was cited as `#312` in an early prompt; `#312` is an unrelated row. Separately, a + close request for `#333` was queued after confirming a `#333` row existed — but the match was the + **archived** row, and the invalid request threw `#333 is already archived`, red-lining + `docs:check-links` for the whole branch. +- **Node 24 is mandatory** (`engine-strict`). A cloud container may ship Node 20/22; `npm ci` then + fails `EBADENGINE` and leaves `tsx` unresolvable, which fails `check:runtime`. Install Node 24 + before anything else. +- **Two known tooling failures are fixed — recognise the symptoms rather than re-diagnosing them.** + `cancel request … targets missing pending request` was the ledger cancel-race (fixed in PR #1978; + a cancellation whose target was already applied is now a loud no-op). A force-push rejected with + "removed without an audit record" was `guardBaseForRange` comparing against abandoned history + (also #1978; it now falls back to the merge base). Neither should need an override. + **Session hygiene for every phase:** start from a fresh worktree off latest `origin/main` (`newtask` skill), one branch per phase (`claude/db-remediation-phase-N`), record evidence in `docs/audit/live-drift-forensics-2026-08.md`, hand off via the `handoff` skill, and update the live-drift tracking item via `npm run issues:update` before the session ends. +**Running two phases at once.** Phases whose targets differ (for example Phase 1.2 read-only against +production and Phase 2 mutating staging) can safely run concurrently — but the **ledger**, not the +database, is where they collide: + +- **Assign one ledger row per session, explicitly, in the prompt.** Two pending mutations on the same + row make the inbox refuse the whole batch until someone queues an explicit cancellation. Phase 1.2 + owns the live-drift tracking item; Phase 2 owns `#056`. +- **One reconciliation at a time, from a fresh-base branch.** Three ran in parallel on 2026-08-14 and + collided. `npm run issues:reconcile` is the only thing that may edit `docs/outstanding-issues.md`. +- **Never merge `main` into a PR that carries a reconciliation** — it turns a complete transaction + into a partial one and the guard correctly rejects it. +- **After a PR lands, verify the content on `main`, not the commit title** (`#324`): no gate catches + a merge resolution silently reverting merged work, and this programme's branches have been through + enough force-pushes and third-party commits for that to be a live risk. + **Model guidance:** Fable for Phases 1, 3, 6 (and #191 later) — judgment-heavy, expensive mistakes. Opus is sufficient for Phases 0, 2, 4, 5, 7 — execution against this playbook.