From b369d985af077ddefaf77dea12c2eee67df974dc Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 20:41:24 +0000 Subject: [PATCH 1/2] docs(issues): reconcile 19 queued ledger requests into the canonical ledger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Applies every pending inbox request, including this session's four, and moves each to the immutable applied/ audit trail. Two of the nineteen are cancellation decisions, one of them retiring my own earlier record whose diagnosis was partly wrong. Ran with --allow-concurrent, which needs justifying rather than assuming. The guard refused because four reconcile-shaped branches sit unmerged on origin, and it infers "in flight" from the branch name. All four were checked against main request by request, and every one is fully superseded: claude/issues-reconcile-2026-08-19 94 marked applied, 94 already on main claude/ledger-reconcile-2026-08-21 29 marked applied, 29 already on main claude/ledger-reconcile-issues-c1trbj 274 marked applied, 274 already on main claude/rag-r0-reconcile-inbox 268 marked applied, 268 already on main Not one carries an unlanded reconciliation, none has an open PR, and they are 123, 123, 4636 and 4631 commits adrift. The concurrency the guard exists to prevent (#EH9VA6) is therefore not present: there is no second live reconcile to collide with. The 2026-08-21 branch additionally no longer merges cleanly, which is expected — a reconcile transaction is computed against its base, so a stale one cannot be landed by merging and has to be redone from a fresh base, which is what this is. Those four branches should still be deleted so the next session is not blocked by the same false signal. That is a destructive act on other sessions' branches and is left for the owner. Run from a fresh base: HEAD was exactly origin/main (226bd32c) with a clean tree. check:outstanding-issues passes — 0 pending, 504 applied, 431 rows, 72 open, no ids deleted from base. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01JEzkroXdtL9kYo8rW5eZh2 --- .../004ed2f3-a95e-4569-800d-d2cbfd3f8a8e.json | 0 .../05bd88ac-f24f-464a-8853-5d7ff55b375b.json | 0 .../0a0ab127-0cc1-4b14-b4ce-fd839a98386c.json | 0 .../0cf72f07-7f15-4138-81bc-4f425182f0de.json | 0 .../1c89922d-3d01-4811-a255-ed78e2ed11c3.json | 0 .../2040d1fb-6d26-4977-902f-d4a3c2c404c2.json | 0 .../3c71ce2a-b752-4f1b-a8ef-4870f8027bf7.json | 0 .../4fede43d-fb12-4d85-ba7d-856c46b183f2.json | 0 .../51b7e3d4-9c38-4fd7-9aa8-70d46086fde9.json | 0 .../58670ffd-3e20-434a-b728-67f98f0a10d6.json | 0 .../5d987a3d-3869-4864-8af0-de0a6145b682.json | 0 .../67bf71cf-25cb-40d9-a8a2-bbf993bf6b29.json | 0 .../6ef54215-950c-4d68-8af9-b2ff5aaedb83.json | 0 .../84f3e5c9-2fdb-43bd-80ca-a58bc10f6ec5.json | 0 .../8dfc4aaf-c22f-45fd-a7f1-0edbd34bf569.json | 0 .../98e6ae7f-4190-49f3-a64d-fbf632ef6643.json | 0 .../c1f99542-526a-4218-b8e6-87bf136d7567.json | 0 .../d873ec0d-e25d-41fe-b24c-d2c3aa9375ee.json | 0 .../e271b2da-5c74-4d84-96f3-bc96821d2d94.json | 0 docs/outstanding-issues.md | 22 +++++++++++++------ 20 files changed, 15 insertions(+), 7 deletions(-) rename docs/outstanding-issues-inbox/{ => applied}/004ed2f3-a95e-4569-800d-d2cbfd3f8a8e.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/05bd88ac-f24f-464a-8853-5d7ff55b375b.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/0a0ab127-0cc1-4b14-b4ce-fd839a98386c.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/0cf72f07-7f15-4138-81bc-4f425182f0de.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/1c89922d-3d01-4811-a255-ed78e2ed11c3.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/2040d1fb-6d26-4977-902f-d4a3c2c404c2.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/3c71ce2a-b752-4f1b-a8ef-4870f8027bf7.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/4fede43d-fb12-4d85-ba7d-856c46b183f2.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/51b7e3d4-9c38-4fd7-9aa8-70d46086fde9.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/58670ffd-3e20-434a-b728-67f98f0a10d6.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/5d987a3d-3869-4864-8af0-de0a6145b682.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/67bf71cf-25cb-40d9-a8a2-bbf993bf6b29.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/6ef54215-950c-4d68-8af9-b2ff5aaedb83.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/84f3e5c9-2fdb-43bd-80ca-a58bc10f6ec5.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/8dfc4aaf-c22f-45fd-a7f1-0edbd34bf569.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/98e6ae7f-4190-49f3-a64d-fbf632ef6643.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/c1f99542-526a-4218-b8e6-87bf136d7567.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/d873ec0d-e25d-41fe-b24c-d2c3aa9375ee.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/e271b2da-5c74-4d84-96f3-bc96821d2d94.json (100%) diff --git a/docs/outstanding-issues-inbox/004ed2f3-a95e-4569-800d-d2cbfd3f8a8e.json b/docs/outstanding-issues-inbox/applied/004ed2f3-a95e-4569-800d-d2cbfd3f8a8e.json similarity index 100% rename from docs/outstanding-issues-inbox/004ed2f3-a95e-4569-800d-d2cbfd3f8a8e.json rename to docs/outstanding-issues-inbox/applied/004ed2f3-a95e-4569-800d-d2cbfd3f8a8e.json diff --git a/docs/outstanding-issues-inbox/05bd88ac-f24f-464a-8853-5d7ff55b375b.json b/docs/outstanding-issues-inbox/applied/05bd88ac-f24f-464a-8853-5d7ff55b375b.json similarity index 100% rename from docs/outstanding-issues-inbox/05bd88ac-f24f-464a-8853-5d7ff55b375b.json rename to docs/outstanding-issues-inbox/applied/05bd88ac-f24f-464a-8853-5d7ff55b375b.json diff --git a/docs/outstanding-issues-inbox/0a0ab127-0cc1-4b14-b4ce-fd839a98386c.json b/docs/outstanding-issues-inbox/applied/0a0ab127-0cc1-4b14-b4ce-fd839a98386c.json similarity index 100% rename from docs/outstanding-issues-inbox/0a0ab127-0cc1-4b14-b4ce-fd839a98386c.json rename to docs/outstanding-issues-inbox/applied/0a0ab127-0cc1-4b14-b4ce-fd839a98386c.json diff --git a/docs/outstanding-issues-inbox/0cf72f07-7f15-4138-81bc-4f425182f0de.json b/docs/outstanding-issues-inbox/applied/0cf72f07-7f15-4138-81bc-4f425182f0de.json similarity index 100% rename from docs/outstanding-issues-inbox/0cf72f07-7f15-4138-81bc-4f425182f0de.json rename to docs/outstanding-issues-inbox/applied/0cf72f07-7f15-4138-81bc-4f425182f0de.json diff --git a/docs/outstanding-issues-inbox/1c89922d-3d01-4811-a255-ed78e2ed11c3.json b/docs/outstanding-issues-inbox/applied/1c89922d-3d01-4811-a255-ed78e2ed11c3.json similarity index 100% rename from docs/outstanding-issues-inbox/1c89922d-3d01-4811-a255-ed78e2ed11c3.json rename to docs/outstanding-issues-inbox/applied/1c89922d-3d01-4811-a255-ed78e2ed11c3.json diff --git a/docs/outstanding-issues-inbox/2040d1fb-6d26-4977-902f-d4a3c2c404c2.json b/docs/outstanding-issues-inbox/applied/2040d1fb-6d26-4977-902f-d4a3c2c404c2.json similarity index 100% rename from docs/outstanding-issues-inbox/2040d1fb-6d26-4977-902f-d4a3c2c404c2.json rename to docs/outstanding-issues-inbox/applied/2040d1fb-6d26-4977-902f-d4a3c2c404c2.json diff --git a/docs/outstanding-issues-inbox/3c71ce2a-b752-4f1b-a8ef-4870f8027bf7.json b/docs/outstanding-issues-inbox/applied/3c71ce2a-b752-4f1b-a8ef-4870f8027bf7.json similarity index 100% rename from docs/outstanding-issues-inbox/3c71ce2a-b752-4f1b-a8ef-4870f8027bf7.json rename to docs/outstanding-issues-inbox/applied/3c71ce2a-b752-4f1b-a8ef-4870f8027bf7.json diff --git a/docs/outstanding-issues-inbox/4fede43d-fb12-4d85-ba7d-856c46b183f2.json b/docs/outstanding-issues-inbox/applied/4fede43d-fb12-4d85-ba7d-856c46b183f2.json similarity index 100% rename from docs/outstanding-issues-inbox/4fede43d-fb12-4d85-ba7d-856c46b183f2.json rename to docs/outstanding-issues-inbox/applied/4fede43d-fb12-4d85-ba7d-856c46b183f2.json diff --git a/docs/outstanding-issues-inbox/51b7e3d4-9c38-4fd7-9aa8-70d46086fde9.json b/docs/outstanding-issues-inbox/applied/51b7e3d4-9c38-4fd7-9aa8-70d46086fde9.json similarity index 100% rename from docs/outstanding-issues-inbox/51b7e3d4-9c38-4fd7-9aa8-70d46086fde9.json rename to docs/outstanding-issues-inbox/applied/51b7e3d4-9c38-4fd7-9aa8-70d46086fde9.json diff --git a/docs/outstanding-issues-inbox/58670ffd-3e20-434a-b728-67f98f0a10d6.json b/docs/outstanding-issues-inbox/applied/58670ffd-3e20-434a-b728-67f98f0a10d6.json similarity index 100% rename from docs/outstanding-issues-inbox/58670ffd-3e20-434a-b728-67f98f0a10d6.json rename to docs/outstanding-issues-inbox/applied/58670ffd-3e20-434a-b728-67f98f0a10d6.json diff --git a/docs/outstanding-issues-inbox/5d987a3d-3869-4864-8af0-de0a6145b682.json b/docs/outstanding-issues-inbox/applied/5d987a3d-3869-4864-8af0-de0a6145b682.json similarity index 100% rename from docs/outstanding-issues-inbox/5d987a3d-3869-4864-8af0-de0a6145b682.json rename to docs/outstanding-issues-inbox/applied/5d987a3d-3869-4864-8af0-de0a6145b682.json diff --git a/docs/outstanding-issues-inbox/67bf71cf-25cb-40d9-a8a2-bbf993bf6b29.json b/docs/outstanding-issues-inbox/applied/67bf71cf-25cb-40d9-a8a2-bbf993bf6b29.json similarity index 100% rename from docs/outstanding-issues-inbox/67bf71cf-25cb-40d9-a8a2-bbf993bf6b29.json rename to docs/outstanding-issues-inbox/applied/67bf71cf-25cb-40d9-a8a2-bbf993bf6b29.json diff --git a/docs/outstanding-issues-inbox/6ef54215-950c-4d68-8af9-b2ff5aaedb83.json b/docs/outstanding-issues-inbox/applied/6ef54215-950c-4d68-8af9-b2ff5aaedb83.json similarity index 100% rename from docs/outstanding-issues-inbox/6ef54215-950c-4d68-8af9-b2ff5aaedb83.json rename to docs/outstanding-issues-inbox/applied/6ef54215-950c-4d68-8af9-b2ff5aaedb83.json diff --git a/docs/outstanding-issues-inbox/84f3e5c9-2fdb-43bd-80ca-a58bc10f6ec5.json b/docs/outstanding-issues-inbox/applied/84f3e5c9-2fdb-43bd-80ca-a58bc10f6ec5.json similarity index 100% rename from docs/outstanding-issues-inbox/84f3e5c9-2fdb-43bd-80ca-a58bc10f6ec5.json rename to docs/outstanding-issues-inbox/applied/84f3e5c9-2fdb-43bd-80ca-a58bc10f6ec5.json diff --git a/docs/outstanding-issues-inbox/8dfc4aaf-c22f-45fd-a7f1-0edbd34bf569.json b/docs/outstanding-issues-inbox/applied/8dfc4aaf-c22f-45fd-a7f1-0edbd34bf569.json similarity index 100% rename from docs/outstanding-issues-inbox/8dfc4aaf-c22f-45fd-a7f1-0edbd34bf569.json rename to docs/outstanding-issues-inbox/applied/8dfc4aaf-c22f-45fd-a7f1-0edbd34bf569.json diff --git a/docs/outstanding-issues-inbox/98e6ae7f-4190-49f3-a64d-fbf632ef6643.json b/docs/outstanding-issues-inbox/applied/98e6ae7f-4190-49f3-a64d-fbf632ef6643.json similarity index 100% rename from docs/outstanding-issues-inbox/98e6ae7f-4190-49f3-a64d-fbf632ef6643.json rename to docs/outstanding-issues-inbox/applied/98e6ae7f-4190-49f3-a64d-fbf632ef6643.json diff --git a/docs/outstanding-issues-inbox/c1f99542-526a-4218-b8e6-87bf136d7567.json b/docs/outstanding-issues-inbox/applied/c1f99542-526a-4218-b8e6-87bf136d7567.json similarity index 100% rename from docs/outstanding-issues-inbox/c1f99542-526a-4218-b8e6-87bf136d7567.json rename to docs/outstanding-issues-inbox/applied/c1f99542-526a-4218-b8e6-87bf136d7567.json diff --git a/docs/outstanding-issues-inbox/d873ec0d-e25d-41fe-b24c-d2c3aa9375ee.json b/docs/outstanding-issues-inbox/applied/d873ec0d-e25d-41fe-b24c-d2c3aa9375ee.json similarity index 100% rename from docs/outstanding-issues-inbox/d873ec0d-e25d-41fe-b24c-d2c3aa9375ee.json rename to docs/outstanding-issues-inbox/applied/d873ec0d-e25d-41fe-b24c-d2c3aa9375ee.json diff --git a/docs/outstanding-issues-inbox/e271b2da-5c74-4d84-96f3-bc96821d2d94.json b/docs/outstanding-issues-inbox/applied/e271b2da-5c74-4d84-96f3-bc96821d2d94.json similarity index 100% rename from docs/outstanding-issues-inbox/e271b2da-5c74-4d84-96f3-bc96821d2d94.json rename to docs/outstanding-issues-inbox/applied/e271b2da-5c74-4d84-96f3-bc96821d2d94.json diff --git a/docs/outstanding-issues.md b/docs/outstanding-issues.md index f88ee8531..4790d3416 100644 --- a/docs/outstanding-issues.md +++ b/docs/outstanding-issues.md @@ -94,11 +94,9 @@ removed after current-main verification; it is not missing recommended work. | #100 | P2 | rec | Buffered answer generation has no incremental verified delivery | UPDATE 2026-08-21 (repo read on main at 1cc0d2987, no provider access): the client-side half has landed. NEXT_PUBLIC_RAG_INCREMENTAL_EVIDENCE_PREVIEW_RENDER is present in .env.example (commented, default false) and is consumed by src/lib/client-env.ts, so the Phase 1 client parsing/rendering flag exists alongside the server-side RAG_INCREMENTAL_EVIDENCE_PREVIEW=false. Remaining scope is therefore narrower than recorded: verify:ui proof of the client render path, then the design's provider-backed acceptance gates before production enablement. Phase 2 stays provider-gated. Not verified: whether the render path is actually exercised by a UI journey. | `docs/verified-answer-incremental-delivery-design.md`; `docs/audit/latency-audit-2026-07-28.md` L0-1; `src/lib/answer-stream-contract.ts:18-21` | 2026-07-30 | | #102 | P3 | task | Apply the additive `documents` index debt (operator) | UPDATE 2026-08-21 (read-only Supabase MCP get_advisors performance lint against production ref sjrfecxgysukkwxsowpy): documents_title_trgm_idx exists on public.documents and is reported by the unused_index lint as never used. TREAT THAT AS WEAK EVIDENCE, NOT CONFIRMATION: 20260819100200_restore_search_health_trigram_indexes was applied two days earlier and recreating an index resets its usage statistics, so a zero-use reading is expected regardless of whether the bare-column ILIKE predicates can reach it. The same lint currently reports 31 unused indexes, several of them freshly restored in the 20260819100000-100300 batch, which is consistent with a stats reset rather than dead indexing. The row's actual claim - that the index covers a CONCATENATED expression and so cannot serve the bare-column predicates in the documents API route and rag-candidate-sources - was NOT tested, because that needs EXPLAIN or a pg_indexes read and SQL execution was blocked in this session. Re-measure with EXPLAIN in the operator window before applying the prepared runbook. | `docs/audit/latency-audit-2026-07-28.md` L2-3/L2-5; `docs/operator-apply-performance-latency-remediation.md` | 2026-07-29 | | #191 | P3 | task | X5: ACL-migration consolidation (provider-gated) | **Outcome:** ACL-related migrations are consolidated per maturity work-order X5 without weakening owner-scope/RLS. **Next:** DB-owner approved window only; live-DB provider confirmation required before apply. **Stop:** no hosted apply from an agent session without explicit approval. | docs/maturity-backlog-workorders.md X5; #086 | 2026-07-31 | -| #231 | P2 | issue | Generation fallbacks no longer stick in answer cache; lithium generation quality still falls back safely | S1 (#2022), S1b (#2035), S1d (#2054) landed with green canary pairs: generation-quality false rejections and the finalizer gap hole are fixed. Residual R4: chronic ~30 s strong-route provider_timeout on metformin-renal-dosing and valproate-pregnancy (measured 4/4 at v18 4ea310e48 and 2/4 at v19 main on 2026-08-18; safe source-backed extractive fallback, never model synthesis). Route-budget stop condition unchanged. Remediation-plan Phase 5.2 (re-test #231 after the trigram-index restore) is satisfied by S1's 2026-08-17 healthy-latency probes; live-drift #316 Phase 1.2 classified all ten RPC divergences as attribute-only, so canaries since 2026-08-14 measure a reconstructable path. Re-graded P1 -> P2. Next: prompt/context trimming for complex classes, or accept the extractive fallback as the durable answer for these two classes. Do not add a separate R4 row — this update supersedes that need. | docs/rag-improvement/HANDOVER.md secs 1-2; docs/rag-improvement/COORDINATION.md sec 7; docs/database-remediation-plan.md Phase 5.2; docs/audit/live-drift-forensics-2026-08.md sec on Phase 1.2 classification; ledger rows #316 / #248 / #231 / #342; session 2026-08-18 | 2026-08-04 | +| #231 | P2 | issue | Generation fallbacks no longer stick in answer cache; lithium generation quality still falls back safely | PHASE 5.2 CONFIRMED SATISFIED with fresh data 2026-08-22 Perth (2026-08-21 UTC), not reopened. This row already recorded that remediation-plan Phase 5.2 is satisfied by S1's 2026-08-17 healthy-latency probes; the Phase 5 close-out re-measured production end to end and confirms it. Retrieval now costs 955 ms on the text fast path and 6,720 ms on hybrid (from 31,610 ms and 21,757 ms at the incident), against answerRouteBudgetMs.fast of 25,000 ms -- so retrieval consumes 4-27% of the fast budget and is no longer capable of binding it. The 2026-08-14 verdict that pre-generation latency WAS the binding cause stands for that window and is now closed out. Residual R4 (chronic ~30 s strong-route provider_timeout on metformin-renal-dosing and valproate-pregnancy, with a safe source-backed extractive fallback) is generation-side and unchanged; no separate R4 row was created, per this row's own instruction. INCONSISTENCY TO FIX AT RECONCILE: the recommended-execution-queue row for #231 still presents it as A1 / 'immediate approved live investigation' with the old framing ('live answers degrade to source-only when answerRouteBudgetMs.fast binds while retrieval is healthy'), which contradicts the P1 -> P2 re-grade recorded in this detail row. The queue entry should be re-graded to match P2 and re-scoped to the R4 generation-side residual, so the queue stops advertising a retrieval investigation that the measurements have closed. | docs/audit/live-drift-forensics-2026-08.md Phase 5 close-out 5.1(a) and 5.2; production probes 2026-08-22 Perth (2026-08-21 UTC) | 2026-08-04 | | #308 | P3 | issue | Desktop /documents/search CLS is 0.119, above threshold and stable across runs and baselines | Measured 2026-08-12 during the #147 close-out, twice, on the offline Lighthouse harness (Chromium 141): desktop /documents/search CLS **0.119**, against a committed baseline that also reads **0.119**. So this is long-standing and deterministic, not a regression — and it is above the 0.1 threshold. It sits outside #147's scope, which was mobile only, and it contradicts that row's claim that 'desktop passes everywhere: 0.016-0.097' — that range is stale. Companion desktop values from the same runs, all passing: /dsm 0.014, /forms 0.059-0.064, / 0.006, /therapy-compass 0.000. Desktop attribution completed 2026-08-14: a Playwright + PerformanceObserver(layout-shift) harness against an offline production build at 1350x940 DPR 1 recorded **0.118** CLS. This is a separate attribution measurement, not a replacement for the canonical 0.119 Lighthouse value. One first-paint+~0.3-0.5s event contributed ~99.98% of that harness total: MasterSearchHeader's composer-adoption effect portals the search composer into GlobalSearchShell's desktop slot, while the header shrinks 184px and the slot grows 0 -> 184px. This is shared desktop search-chrome timing, not page-local. Next: reserve the settled height at the adoption boundary under the one-composer/hidden-means-zero-reserve contracts, then re-measure with the same harness. Stop: do not raise the CLS budget; do not read local LCP or TBT from the loopback harness; and do not use a blanket min-height that hides the shift without matching the header reserve. | Local offline verify:lighthouse runs 2026-08-12 (two runs, identical CLS); #147 close-out; lighthouse-budget.json. Attribution: session 2026-08-14, PR branch codex/visual-layout-polish; desktop CLS script adapted from scripts/measure-cls-attribution.mjs (offline, not committed). | 2026-08-12 | -| #316 | P1 | issue | Live DB has 20 currently missing repo-defined indexes and 10 retrieval RPC bodies diverge; weekly live-drift has been red since 2026-07-26 with no routing | CORRECTION 2026-08-21 -- READ THIS FIRST, THE D4 SENTENCE BELOW IS SUPERSEDED. This row states "D4 IS NOW DECIDED: auto-deploy is OFF", inferred on 2026-08-19 from four migrations sitting pending on production. AGENTS.md was updated 2026-08-21 (PR #2213, after #2205) from a direct dashboard read recording the OPPOSITE: the Supabase GitHub integration has "Deploy to production" ENABLED with production branch main, so a migration merged to main reaches the live clinical database automatically within seconds (34 s measured, forensics 3.7). A dashboard read beats an inference from observed pending state, and AGENTS.md notes two earlier sessions inferred this wrongly in BOTH directions -- this row is one of them. Treat AGENTS.md "Supabase project safety" as authoritative. CONSEQUENCE NOT RECORDED ANYWHERE ELSE: auto-deploy is ON while PITR is OFF on the same project (see the PITR row: pitr_enabled false, daily physical backups only, worst-case ~24h RPO across 2851 documents and 70120 chunks), so a bad migration merged to main reaches the live corpus unattended and cannot be restored to a fine-grained point. PARTIAL MITIGATION LANDED WITH THIS CORRECTION: scripts/guard-push.mjs now hard-blocks a push to a PR branch touching supabase/migrations/** while auto-merge is armed (reason auto-merge-armed-migration, no override env var), pinned by four cases in tests/guard-push.test.ts. supabase/schema.sql is deliberately NOT treated as a migration path -- it is a mirror the integration does not apply. That closes the automation path ONLY: a human can still arm auto-merge or press Merge, so the operative controls remain the AGENTS.md rule and the PITR decision. ORIGINAL RECORD FOLLOWS UNCHANGED: PHASE 4 COMPLETE 2026-08-19; the RPC track of this row closed 2026-08-18. BOTH HALVES OF THIS ROW ARE NOW CLOSED. (A) RPC divergence, from the 2026-08-18 window (PR #2123, forensics 3.7): the authorised window's pre-flight found the pending set EMPTY -- all five 20260818 migrations were already applied with executed statements (3/11/12/5/4, the CLI db push shape, not mark-applied) -- so db push was never run, no migration repair, no vault reads, zero production writes. Manifest def_hash equals live for all ten match_* functions, and live-drift 32131517648 showed 0 function mismatches. CAUSE, platform finding since resolved: the Supabase GitHub integration (Branching, production bound to git main, branch record 2026-06-27) was auto-applying every migration merged to main -- push-triggered live-drift bracketed 110000-112000 to 34 s after #2106's squash-merge. D4 IS NOW DECIDED: auto-deploy is OFF, confirmed empirically on 2026-08-19 when the four new 20260819 migrations sat pending on production after the branch existed and reached it only via an explicit db push. Not established: who enabled the integration or when, or whether the July mark-applied rows trace to it. (B) Index restoration, 2026-08-19 owner-authorized off-peak window: all 20 missing_live indexes rebuilt with CREATE INDEX CONCURRENTLY from canonical definitions cross-read against their defining migrations -- Batch A 14/14, Batch B 6/6, every one indisvalid AND indisready with normalized pg_get_indexdef matching canonical, zero invalid builds, zero retries, zero skips, zero lock waits (pg_locks read between every Batch B build). No transactional build was ever attempted; #102's bare-column indexes held out. Both unexpected_live indexes were DROPPED CONCURRENTLY rather than codified, because the chain already commands both drops and each is a strict leading-column subset of a present canonical index: document_table_facts_document_id_idx (superseded per 20260620000000) and storage_cleanup_jobs_owner_id_idx (superseded per 20260703030000/20260708000000). Live now reports 210 public indexes against the manifest's 210, zero invalid anywhere. Codified in five migrations applied by real supabase db push (never migration repair; every history row carries executed statements): 20260819100000/100100 guard Batch A/B, 20260819100200 discharges the plan 4.4 debt by guarding the two trigram indexes restored 2026-08-14 that 20260804110240 never checked, 20260819100300 takes search_schema_health() required_indexes 22->30 adopting all 8 Phase 6.3 monitor-candidates (unmonitored list 44->36, no monitor-candidate left; production ok true), and 20260819100150 repairs a chain defect the guard itself caught -- see below. Live-drift 32171070287: UNEXPECTED DRIFT 37->16, missing_live 20->ZERO, unexpected_live 2->ZERO. Staging brought to full parity in the same task; its drift comparison is GREEN with ZERO unexpected drift (was 19), corpus untouched, --prune-stale correctly not used. THE GUARD EARNED ITS KEEP: 20260819100200 failed the Supabase Preview check on PR #2151 because a preview branch builds from the migration chain alone, and the chain permanently produced the WRONG document_chunks_content_trgm_idx -- 20260606000000 creates it first without coalesce(content,''), and both later correct creators use IF NOT EXISTS so they no-op, with no migration ever dropping it. Forensics 3.3(d) had scoped this as staging-only and hand-repaired it there; it was never staging-only (db reset, DR replay, CI migration replay, preview branches all get the wrong index, which is NULL for rows with NULL content and so silently omits those chunks). Fixed by 20260819100150, conditional so it no-ops when canonical, rebuilds only on an empty table, and raises rather than run a write-blocking build on a populated one; proven by replaying the whole chain into a scratch Postgres (fails without it exactly as CI did, 204/204 with it) and the no-op path proven on production itself (index OID unchanged at 1491258 across the push). TWO ESCALATIONS FOR THE OWNER, neither absorbed. (1) PITR IS NOT ENABLED on production (pitr_enabled false, walg_enabled true, daily physical backups only, latest 2026-08-17T20:33:28Z), so the plan's standing 'restore point before any mutating phase' rule cannot be met; Phase 4 proceeded only because every statement was index-only with an exact one-statement inverse, and no future window that mutates DATA should proceed on that precedent. Queued separately as its own P2. (2) The migration_history block did NOT drop and no allowlist entry was written -- measured, not skipped: of the 15 no-statements versions, 6 are index-shaped and the intersection between the objects they create and the 22 these guards validate is EMPTY (near-misses are distinct objects, e.g. audit_logs_owner_id_idx vs audit_logs_owner_created_idx). The 15 stay unallowlisted and remain #Q5JHBJ's work. REMAINING FOR THIS ROW: nothing on the index or RPC tracks. Phase 5 measurement (after-EXPLAIN set, #231 re-test on healthy latency, check:production-readiness) is the only follow-on. Full evidence with dates, run IDs and pasted output in docs/audit/live-drift-forensics-2026-08.md sections 3.7 and 'Phase 4 completion'. Session traps still current: the main checkout D:\Repos\Database is linked to STAGING, so link a dedicated worktree for production and unlink after; supabase db query --linked --project-ref works read-only via the management API without a DB password; db query parses a leading -- as a flag, so pass SQL that starts with a comment via --file; production has no track_commit_timestamp. | PR #2151 (Phase 4) and PR #2123 (window 3.7); live-drift runs 32171070287 and 32131517648; forensics sections 3.7 and 'Phase 4 completion' | 2026-08-13 | | #321 | P3 | task | Four follow-up groups cover nine controls after #291 | PARTIAL 18 August 2026. Of the four follow-up groups: (1) the filmstrip 'Page unknown' control is FIXED — document-image-filmstrip.tsx converted its data-driven disabled state from native disabled to aria-disabled=true + ignoreUnavailableActivation + an sr-only reason, per docs/wiring-conventions.md's stated-reason pattern (settles this one control from #291's follow-up list); tests/document-image-filmstrip.dom.test.tsx gained a focused case (aria-disabled, not natively disabled, accessible description, click is a no-op), vitest run: 3 passed. The other three groups are unchanged and still not single-PR-sized: the six differential comparison page controls remain coupled to its own planned rewrite and pinned density test; DocumentViewer's persistent-access-reason/transient-loading split is a classification design decision, not yet made; the pin-limit control remains a capacity-state judgement call. Stays open for those three. | PR #1778 body; verified against main 2d27039 | 2026-08-14 | -| #4TBHS8 | P3 | issue | Advisory UI mockup spec 'phone filter sheet follows the shared local-filter behavior' fails on main | UPDATE 2026-08-21 (repo read on main at 1cc0d2987): the specific failure mode recorded here - waiting for the exact text 2 showing inside the tools-search-filter-sheet testid - can no longer occur, because that string has zero occurrences in tests/ui-tools-search-mode-mockup.spec.ts. The test itself still exists and was rewritten. NOT VERIFIED: whether it passes. Re-run before closing. Tracked with #SZGPAH, which names the same file. | session 2026-08-18; PR #2060 Advisory UI run 32090358678; reproduced on origin/main dc7e518 | 2026-08-18 | | #2AB2NJ | P3 | task | Owner decision: enable RAG_TELEMETRY_EXTENDED (verification_latency_ms projection) in production once a dashboard consumer exists | Packet S5 (PR #2056, merge 093f9340c) landed the B1 telemetry gap assessment: the one proven gap is verification_latency_ms, now persisted behind RAG_TELEMETRY_EXTENDED (typed, default false) via the allow-listed projection module with canary-absence tests. Enabling it in production is an owner decision gated on a dashboard consumer existing (no consumer today), and is a Railway env change (provider-backed, explicit approval; rollback = set false). Next: when a dashboard question needs verification latency, set RAG_TELEMETRY_EXTENDED=true on the Database service after confirming the canary-absence tests are still green on main. Stop: do not enable speculatively; do not add unproven fields. | RAG programme coordinator, packet S5 (PR #2056) follow-ups, 2026-08-17 | 2026-08-17 | | #C2D9JF | P2 | issue | Adversarial divergence (S5 harness pin): scope-other-owner-document — abstains in substance but the review fallback still cites in-scope evidence | Pinned in tests/rag-adversarial-harness.test.ts KNOWN_DIVERGENCES (self-expiring). Observed shape: grounded false, confidence unsupported, but cited chunk ids [syn-scope-owner-a] — the answer correctly abstains from the other-owner document, yet the review fallback attaches an in-scope citation to an unsupported answer. Fixture: scripts/fixtures/rag-adversarial-cases.v1.json case scope-other-owner-document (category scope_or_tenant). Tenancy/no-read invariant held (the other-owner content is never read). Next: decide whether an unsupported abstention may carry any citation; if not, strip citations on the abstention path (RAG-surface change; own PR; harness pin flips; canary pair). Stop: do not delete the pin without the behaviour change. | RAG programme coordinator, packet S5 (PR #2056) follow-ups, 2026-08-17 | 2026-08-17 | | #71NT23 | P2 | task | No mobile-WebKit or display-mode:standalone Playwright project exists; phone coverage is a narrow viewport on desktop engines | UPDATE 2026-08-21 (repo read on main at 1cc0d2987): partially advanced. playwright.config.ts now carries a documented phone-PWA standalone emulation strategy annotated with this issue id, and defines chromium, chromium-mockups, firefox and webkit projects. What still appears absent is a genuinely mobile-WebKit project - the webkit entry is the desktop engine - and no display-mode standalone project was found. Re-measure the exact project list before scoping the work; physical iPhone Safari/PWA acceptance remains out of scope for any container evidence. | PR #2046 phone/PWA answer-progress animation defect, 2026-08-17 | 2026-08-17 | @@ -108,18 +106,17 @@ removed after current-main verification; it is not missing recommended work. | #75JA0P | P2 | issue | Playwright runs the whole suite with reducedMotion:"reduce", so no gate reflects the default user configuration | playwright.config.ts:61 sets contextOptions: { reducedMotion: "reduce" } suite-wide, and every motion assertion has to opt out per-test via page.emulateMedia({ reducedMotion: "no-preference" }). That inversion is why three consecutive PRs (#1974, #1989, #1995) shipped green while a physical iPhone with OS Reduce Motion on showed a frozen, blank answer-progress panel: the suite never exercised the reported configuration. PR #2046 added tests/ui-phone-motion.spec.ts to cover that one surface, but the suite-wide default remains inverted for every other motion behaviour. Next: decide whether the suite default should be no-preference with reduce opted into per-test (the safer direction), or keep the current default and add a contract test that fails when a motion assertion has no explicit emulateMedia call. | PR #2046 phone/PWA answer-progress animation defect, 2026-08-17 | 2026-08-17 | | #1PN5BM | P3 | issue | H5a residual: whether a constant similarity of 1 may contribute to a confidence label is still open, and after G1 it lives only in the hazard doc | Packet G1 (PR #2053, merged 2026-08-17) implemented owner decision Option B: buildDocumentSummaryResults now stamps similarity_origin "document_context" on document-summary rows, deriveConfidence is unchanged, and document summaries still reach "high". That closed the LEGIBILITY half of the H5a live residual -- the fabricated 1.0 is no longer indistinguishable from a perfect cosine at any surface that reads a row. It did NOT answer the underlying governance question: may a score nobody measured contribute to the confidence label a clinician reads at all? Option B was chosen because tagging has no measured safety cost while Option A (tag as synthetic_text, capping summaries at "medium") is a label downgrade without measured gain -- so the question was deferred deliberately, not resolved. The paired question row #J912J9 is being closed by G1, so once that closure reconciles this knowledge survives only in docs/clinical-hazard-analysis.md H5a and not in the queue anyone reads. NEXT: no action required unless a measured signal appears; if it does, the tag is what makes the fix cheap -- any future gate can now discriminate the document-summary route without re-deriving provenance. Guard rails already in place: tests/rag-score.test.ts pins the discriminating pair (two document_context citations >= 0.82 -> "high"; the identical scores tagged synthetic_text -> "medium"), so a silent change in either direction goes red. | Packet G1 session 2026-08-17 (PR #2053); docs/clinical-hazard-analysis.md H5a; closes-with #J912J9 | 2026-08-18 | | #QSHHGK | P2 | rec | Nothing schedules a bundle-budget baseline refresh, so accumulated growth fails whichever unrelated PR lands last | The production baseline sat at ca788d41 (2026-08-13) untouched while main grew +8.03% by 2026-08-18, leaving ~2 points of headroom. PR #2096 (Dictionary) then failed Build at +10.5% for 2.7 points of its own weight. Re-baselined once in docs/evidence/bundle-budget-production-rebaseline-2026-08-18.md, but the same squeeze recurs unless a refresh has an owner or a trigger: options are a scheduled job that re-measures and opens a PR, a drift warning threshold below the failure threshold, or recording the baseline commit distance in the check output so staleness is visible before it blocks someone. | PR review of #2095/#2096, 2026-08-18 | 2026-08-18 | -| #SZGPAH | P2 | issue | tests/ui-tools-search-mode-mockup.spec.ts has two assertions stale on main, so the advisory lane is red for every UI PR | UPDATE 2026-08-21 (repo read on main at 1cc0d2987): one of the two named assertions is provably gone. The phone test for the shared local-filter behaviour still exists but no longer asserts the exact text 2 showing anywhere in the file - that string has zero occurrences in tests/ui-tools-search-mode-mockup.spec.ts. The desktop test that keeps results beside the selected-tool panel still exists at line 24. NOT VERIFIED: whether the spec now passes - that needs node scripts/run-playwright.mjs --project=chromium-mockups on this file, which was not run. Re-measure before closing or quarantining. | Copilot review triage on #2095/#2096, 2026-08-18 | 2026-08-18 | | #6SMMB4 | P3 | task | Confirm D:\.npm-cache is a registered Dev Drive trusted cache, or Defender is scanning every npm ci | The repo lives on a Windows Dev Drive (D:, ReFS, 50 GB) and npm config get cache resolves to D:\.npm-cache, which is correctly on the same volume. Whether that path is registered as a Dev Drive TRUSTED cache is unverified: 'fsutil devdrv query D:' returns 'Failed to open the volume. Error 5: Access is denied' without elevation, and the non-elevated registry fallback (HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem, FilterAttachModeOnDevDrive and DevDriveTrustSetting) reads empty. If it is not registered, Microsoft Defender real-time scanning runs over every npm ci — and this machine performs a lot of them: 21 D: worktrees each carry their own ~0.89 GB / 51,735-file node_modules, because npm extracts fresh copies rather than hardlinking from cache (ReFS does support hardlinks here, probed directly, but npm does not use them). Next: from an ELEVATED prompt run 'fsutil devdrv query D:' and, if the cache is not listed as trusted, 'fsutil devdrv trust D:\.npm-cache'. Cheap, one-off, no code change. Not blocking anything. | session 2026-08-18; fsutil Error 5 without elevation | 2026-08-18 | | #GKFK9V | P3 | rec | Where the RAG improvement programme board lives, and to check it before starting RAG-surface work | The RAG improvement programme board lives at docs/rag-improvement/README.md (design), HANDOVER.md (packet status table + prompts) and COORDINATION.md (coordinator manual). Before starting any RAG-surface item, check that status table AND the open PR list (#292); packets S1-S3, G1, S4-S6 landed 2026-08-17/18; Track A complete. | docs/rag-improvement/README.md, HANDOVER.md, COORDINATION.md; session 2026-08-18 | 2026-08-18 | | #RZQQBT | P3 | task | Confirm from its own log whether the PreCompact hook's output actually reaches model context | UPDATE 2026-08-21 (measured on this machine): still unanswered, and now with a concrete reason. The hook's own log has never been written - neither the main repository's .git/claude-precompact.log nor the per-worktree claude-precompact.log under the .git/worktrees admin directory exists. So no compaction has fired the hook in an inspectable session yet, and the question stays open rather than answered-negative. Next: after the next compaction in a session using this checkout, read that path; an entry proves the hook ran, and its absence in model context would then be the separate question. | PR #2113 .claude/hooks/precompact-issues-capture.sh | 2026-08-18 | -| #CCZ4HB | P1 | rec | PR churn has exhausted the review-bot budget, so PRs are now landing with no automated review at all | CodeRabbit on PR #2113: '101 included PR reviews in the past 7 days; at that activity level, included reviews refill at 1 review per hour. Your organization has reached its usage spending cap.' The Codex connector reported its own usage limit on the same PR. Net effect: #2113 received ZERO automated review, and so will subsequent PRs until the cap resets or credits are added. AGENTS.md 'PR bundling' already measured the CI half of this cost on 2026-07-30 (437 PR-triggered runs over ~3 days, ~40% cancelled mid-run, ~12 Production-UI-hours burned on runs that never completed). This is the second bill for the same behaviour and the more dangerous one, because CI waste is money while missing review is undetected defects — and the PRs most likely to need review are the ones landing during a churn spike. The bundling rule exists as prose in AGENTS.md and is evidently not binding; the newtask skill also asks the question in prose. Decide whether it gets a gate. Note the repo has already learned this lesson once in a different area: .claude/hooks/pr-handoff-stop.sh states in its own header that 'prose rules in AGENTS.md have not held, a denied tool call does.' Next: decide between (a) a push/PR-creation gate that refuses a new branch when an open PR of the same scope exists, (b) raising the bot spending cap, or (c) accepting unreviewed merges deliberately rather than by accident. Stop rule: do not weaken any required check to compensate for missing bot review. | CodeRabbit + Codex connector comments on PR #2113, 2026-08-18; AGENTS.md 'PR bundling (reduce one-task-one-PR churn)' | 2026-08-18 | +| #CCZ4HB | P1 | rec | PR churn has exhausted the review-bot budget, so PRs are now landing with no automated review at all | UPDATE 2026-08-21 (second session, three PRs later): STILL HAPPENING, and now measured on consecutive PRs rather than one. CodeRabbit skipped review on PR #2252, #2255 and #2256 — every PR opened in that session — reporting: 'Your 88 included PR review attempts over the past 7 days set your current allowance at 1 review per hour' and 'Your organization has reached its usage spending cap.' Countdown observed shrinking across the session (48 minutes -> 32 -> 27), i.e. the hourly allowance was being consumed as fast as it refilled. Two refinements to the row below. (1) The 2026-08-18 reading was 101 reviews/7 days; this one is 88 attempts/7 days, so the trailing window is falling but the spending cap is the binding constraint now, not the rate limit — raising the cap is therefore the lever, and it is an account/billing decision the repo cannot gate its way out of. (2) Draft PRs are skipped outright ('Review skipped. Draft detected'), so the repo's own default of opening PRs as drafts guarantees no bot review until someone undrafts — and undrafting mid-CI also cancels the in-flight run and reds the required aggregate (observed on #2255 and #2256). That interaction is worth stating in AGENTS.md: the draft default, the review-bot budget, and the cancel-in-progress churn are the same problem seen from three sides. Next unchanged: decide between a churn gate, raising the cap, or accepting unreviewed merges deliberately. PRIOR RECORD: CodeRabbit on PR #2113: '101 included PR reviews in the past 7 days; at that activity level, included reviews refill at 1 review per hour. Your organization has reached its usage spending cap.' The Codex connector reported its own usage limit on the same PR. Net effect: #2113 received ZERO automated review, and so will subsequent PRs until the cap resets or credits are added. AGENTS.md 'PR bundling' already measured the CI half of this cost on 2026-07-30 (437 PR-triggered runs over ~3 days, ~40% cancelled mid-run, ~12 Production-UI-hours burned on runs that never completed). This is the second bill for the same behaviour and the more dangerous one, because CI waste is money while missing review is undetected defects — and the PRs most likely to need review are the ones landing during a churn spike. The bundling rule exists as prose in AGENTS.md and is evidently not binding; the newtask skill also asks the question in prose. Decide whether it gets a gate. Note the repo has already learned this lesson once in a different area: .claude/hooks/pr-handoff-stop.sh states in its own header that 'prose rules in AGENTS.md have not held, a denied tool call does.' Next: decide between (a) a push/PR-creation gate that refuses a new branch when an open PR of the same scope exists, (b) raising the bot spending cap, or (c) accepting unreviewed merges deliberately rather than by accident. Stop rule: do not weaken any required check to compensate for missing bot review. | CodeRabbit comments on PRs #2252, #2255, #2256 (2026-08-21); prior evidence PR #2113 (2026-08-18) | 2026-08-18 | | #164Z0H | P3 | task | Confirm on a real Claude Code web session that the session-start hook now runs, after the exec-bit fix | UPDATE 2026-08-21 (repo read on main at 1cc0d2987): the repo-side half is now proven green. git ls-files -s .claude/hooks/ reports mode 100755 for all five hooks, session-start.sh included, so the 100644 asymmetry recorded here is fixed in the index rather than only on disk. What remains is exactly what this row was filed for and cannot be proven from Windows: one real Claude Code web/container session confirming the hook actually runs and provisions Node 24. | PR #2113; AGENTS.md 'Claude Code hook scripts' | 2026-08-18 | -| #6GW95D | P2 | task | Nine landed worktrees are still on disk holding ~4.5 GB on a 51%-full Dev Drive; removal was deferred because the fleet was live | UPDATE 2026-08-21 (measured on this machine): the figure recorded here is badly understated and moving the wrong way. git worktree list reported 69 registered worktrees under .claude/worktrees, not nine. At the ~0.89 GB / 51,735-file node_modules per worktree measured in #6SMMB4, even partial installs put this well beyond the 4.5 GB recorded, on a Dev Drive noted as 51% full. SAFETY, learned the hard way on 2026-08-21: a sweep removed an in-use worktree during this very session and destroyed its uncommitted work - see the separate row filed for that. Re-measure actual on-disk size, then prune, but confirm each worktree is landed, holds no uncommitted or unpushed work, AND is not currently checked out by a live agent session before removing it. | PR #2113 scripts/clean-worktree.mjs; live fleet re-verification 2026-08-18 | 2026-08-18 | +| #6GW95D | P2 | task | Nine landed worktrees are still on disk holding ~4.5 GB on a 51%-full Dev Drive; removal was deferred because the fleet was live | UPDATE 2026-08-21 (later the same day): the scope is wider than .claude/worktrees, and the previous update's 69 is itself a floor. An accidental `npx vitest run` issued from C:/Users/joshs instead of the repo root enumerated 253 copies of just TWO test files across the home directory, i.e. 253 separate checkouts of this repository, spread over at least six distinct roots: .codex/worktrees, .gemini/antigravity/worktrees, .copilot/repos/copilot-worktrees, .local/share/opencode/worktree, Documents/Codex///work, and an AppData/Local/pnpm store projects directory (which also contained its own .worktrees). Temp copies under AppData/Local/Temp/guard-push-format-* were still present too. So every AI tool in the fleet keeps its own worktree root and none of them is covered by a sweep scoped to .claude/worktrees. Most had no node_modules (the run failed them with 'Cannot find package'), so raw disk is likely below 253 x 0.89 GB, but the count is the point: any recursive tool run from the home directory now walks all of them. Re-scope this row from 'nine landed worktrees' to a fleet-wide inventory across all six roots before pruning, and keep the #XCAX01 safety preconditions — the 2026-08-21 data-loss incident is why this is not a one-line delete. PRIOR RECORD: UPDATE 2026-08-21 (measured on this machine): the figure recorded here is badly understated and moving the wrong way. git worktree list reported 69 registered worktrees under .claude/worktrees, not nine. At the ~0.89 GB / 51,735-file node_modules per worktree measured in #6SMMB4, even partial installs put this well beyond the 4.5 GB recorded, on a Dev Drive noted as 51% full. SAFETY, learned the hard way on 2026-08-21: a sweep removed an in-use worktree during this very session and destroyed its uncommitted work - see the separate row filed for that. Re-measure actual on-disk size, then prune, but confirm each worktree is landed, holds no uncommitted or unpushed work, AND is not currently checked out by a live agent session before removing it. | Accidental home-directory vitest run, 2026-08-21: 253 test-file copies across six worktree roots | 2026-08-18 | | #VKH7N1 | P3 | rec | eval-canary neuroleptic-side-effect-escalation exceeded its 20 s latency SLO once | Run 32111839806 (canary pair 32100681177 -> 32111839806, otherwise green): strong generation took 20.2 s on neuroleptic-side-effect-escalation, flagged as a non-blocking latency advisory. Answer was still grounded via the source-backed extractive fallback. Watch on subsequent canaries; escalate only if it repeats or worsens. | docs/rag-improvement/HANDOVER.md packet table row S2, canary pair 32100681177 -> 32111839806 | 2026-08-18 | | #1K6T35 | P2 | issue | Point-in-time recovery is OFF on the live Supabase project, so the remediation plan's 'restore point before any mutating phase' rule cannot be met | Measured 2026-08-19 during the Phase 4 production window (forensics section 'Phase 4 completion', step 1). `supabase backups list --project-ref sjrfecxgysukkwxsowpy` returns pitr_enabled false, walg_enabled true, and seven retained daily physical backups, most recent COMPLETED 2026-08-17T20:33:28Z -- roughly 38 hours before that window opened. CONSEQUENCE: the recovery-point objective for the live clinical corpus (2851 documents, 70120 chunks) is up to ~24 hours, and the database-remediation plan's standing rule 'PITR/backup restore point captured before any mutating phase' CANNOT be satisfied on this project as currently configured. Phase 4 proceeded anyway and said so: every statement in it was index-only with an exact one-statement inverse (CREATE INDEX CONCURRENTLY <-> DROP INDEX CONCURRENTLY) and no data-loss surface, the same reasoning the 2026-08-14 incident window recorded. That reasoning does NOT generalise. Any future window that mutates DATA rather than indexes -- #022's BMJ attestation hosted apply, #036's public_corpus marker migration, #191's ACL consolidation, #057's restore/soak drill, or any reindex or backfill -- must not proceed on this precedent while the only restore point is a day-old physical backup. DECISION REQUIRED FROM THE OWNER, and it is dashboard plus billing work no agent can do: either enable PITR on the Supabase project (Database settings -> Add-ons -> Point in Time Recovery; it is a paid add-on, so this is a cost decision as well as a safety one), or deliberately accept the ~24h RPO and amend the plan's standing rule to say so, so that future sessions stop treating an unsatisfiable checklist item as if it had been met. Whichever is chosen, record it, because the current state is that the rule reads as satisfied by default when nobody checks. Consider re-grading this row to P1 if a ~24-hour worst-case data loss on the clinical corpus is judged unacceptable; it is filed P2 because the exposure is a deliberate platform configuration rather than a regression, and no data loss has occurred. Related: #057 (restore/rollback drill -- its value is limited while PITR is off), #188 and #196-#200 (DR codification). | Phase 4 production window 2026-08-19; docs/audit/live-drift-forensics-2026-08.md 'Phase 4 completion' step 1; PR #2151 | 2026-08-18 | | #TF6TPJ | P2 | issue | Repeated main-merges on open PR branches cancel required CI, so 'PR required' reads red with zero failing jobs | UPDATE 2026-08-21 (repo read on main at 1cc0d2987): the guard that closes the shared root cause has landed. scripts/guard-push.mjs now carries an explicit Guard 2 in-flight CI push guard block naming #HSSHRG, with inFlightCiVerdict() and findInFlightCiRuns(), covering merge-main syncs made outside sync:pr-branches. #HSSHRG was closed on that evidence. This row should be re-checked against that guard and closed too if the false-red symptom is gone; it was NOT verified against a live PR from here, which needs GitHub access. | PR #2143, runs 32170524256 and 32178668323, 2026-08-18 | 2026-08-18 | | #P5542X | P2 | issue | pr-policy classifies the switch controlling whether unreviewed clinical content reaches production as clinicalRisk false, so no governance preflight is enforced | Found 2026-08-18 on PRs #2145 and #2150, both of which removed the Therapy production gate. classifyPullRequestFiles in scripts/pr-policy.mjs returned clinicalRisk false for a diff touching src/lib/app-modes.ts and src/lib/therapies.ts - the exact two modules deciding whether 205 clinically-unreviewed therapy records are reachable by users in production. Its clinicalRiskPatterns match src/lib/ only when the filename contains auth, permission, privacy, security, rag, retriev, rank, search, answer, clinical, citation, source, document, upload or download; app-modes and therapies match none. The data patterns (src/data, data, public/therapy-compass-data) match the records themselves but not the code gating their reachability. Both PRs completed a governance preflight voluntarily, which is exactly the fragility: the next such change may not. Consider matching on reachability/exposure surfaces, or treating any diff that changes an app-mode devOnly flag or a review-status filter as clinical-risk. Stop rule: do not widen the patterns so far that ordinary UI work trips the preflight - the classifier comment already warns that presentation files are not clinical-risk merely for living under a clinically-named directory, and that judgement is correct. | session 2026-08-18 | 2026-08-18 | -| #VTEW3W | P3 | rec | therapyBtn still dresses 30 raw controls across 8 therapy files with no shared equivalent | UPDATE 2026-08-21 (repo read on main at 1cc0d2987): the count has fallen. therapyBtn now appears 21 times across 8 files under src/components/therapy-compass/, against the 30 call sites measured 2026-08-18 at adf93a75. The design question is unchanged - nothing shared covers list rows, disclosure headers, section toggles and chips - and the stop rule still stands: do not resolve this by converting the remaining sites to Button variants. | session 2026-08-18 | 2026-08-18 | +| #VTEW3W | P3 | rec | therapyBtn still dresses 13 raw controls across 7 therapy files with no shared equivalent | CORRECTION 2026-08-21, superseding the update applied earlier the same day: the count of 21 across 8 files recorded by that update was WRONG, and the 13 across 7 files measured by the request cancelled as c6a9756d is RIGHT. The discrepancy flagged in that cancellation is now resolved by direct re-measurement on main rather than by choosing between the two numbers. Cause of the error: the earlier update counted raw textual occurrences of therapyBtn, which includes one import statement per consuming file plus the export in controls.ts, and then compared that total against a baseline expressed in CALL SITES. That is an apples-to-oranges comparison and it overstated the remaining work. Measured per file, excluding the import line in each and excluding the definition: brief-screen 1, compare-screen 1, detail-screen 1, pathways-screen 1, recommend-screen 1, sheets-screen 7, therapy-card 1 = 13 call sites across 7 .tsx files, with the export at controls.ts:26. Against the 30 call sites recorded 2026-08-18 at adf93a75, that is a real reduction of 17, not the 9 the bad arithmetic implied. The design question and the stop rule are unchanged: nothing shared covers list rows, disclosure headers, section toggles and chips, and this must not be resolved by converting the remaining sites to Button variants. | session 2026-08-18 | 2026-08-18 | | #GBBYTA | P2 | task | Hoist the filtered-zero empty state out of the documents results grid so it can sit flush under the results band | SearchResultsEmptyState renders the filtered-to-zero case nested two divs inside the results grid in document-search-results.tsx (grid gap-3 wrapper, with a conditional 'N results after filters' pill above it), not adjacent to SearchResultsHeaderBand. That nesting blocks the inline treatment evaluated for PR #2147: recovery cannot share the band's bottom edge, the band's data-tone lead is not adjacent so the panel has no state mark, and the filter chips are not near enough for the panel to point at them instead of duplicating them. PR #2147 therefore shipped the self-contained rail panel, which does not depend on adjacency. Hoisting the state to a sibling of the band would let the panel drop its own rail, its named-removal row and its eyebrow — roughly a third less height on phones. Only the documents nesting was verified; the other five consumers (favourites, calculators, forms, services, therapy-compass) were not checked and may nest the same way. | PR #2147 design review; document-search-results.tsx:1558 | 2026-08-18 | | #0HFDWD | P2 | issue | CI change-scope reports UI_CHANGED false for changes that alter which modes render, so Production UI is skipped on user-facing work | Found 2026-08-18 on PR #2145. The CI run recorded UI_CHANGED false, UI_RESULT skipped and UI_FAST_RESULT skipped for a diff that removed devOnly from the therapy-compass mode and switched off the production record filter - a change that alters which modes appear in the shell for every user. Production UI therefore never ran. The uiPatterns in scripts/pr-policy.mjs and the equivalent scope detection in scripts/ci-change-scope.mjs match src/app/ (non-api), src/components/, src/styles/, public/, tests/ui-*.spec.ts and playwright config; the diff touched only src/lib/app-modes.ts, src/lib/therapies.ts and unit tests, so nothing matched. PR #2150 supersedes that change and adds a visible component, and would still not trip the classifier for its src/lib half. Browser coverage for both was supplied only by a local verify:ui run (447 passed), which no policy required. Consider treating src/lib/app-modes.ts as UI scope, since it is the mode registry the shell renders from, and auditing which other src/lib modules feed rendering. Stop rule: do not make all of src/lib UI scope - that would run a 20-minute Chromium gate on every library change and reintroduce the cancellation waste documented in docs/testing.md. | session 2026-08-18 | 2026-08-18 | | #EP1BQS | P3 | rec | The RAG improvement programme carries its own status table with no session-start link back to the ledger | NARROWED 2026-08-18 before filing: an earlier read of this found zero ledger references to docs/rag-improvement/. That is no longer true — #231 now cites it (5 mentions), so the ledger-to-programme direction exists. What remains is the reverse direction and ownership. docs/rag-improvement/HANDOVER.md instructs every implementing session to read its packet, then README.md, then docs/rag-behaviour/, and to update a per-session status table (section 2) — it does not tell that session to read docs/outstanding-issues.md or to check open PRs for the surface its packet touches. So a session entering through HANDOVER.md never sees the canonical queue, and no row owns the programme itself. AGENTS.md designates docs/outstanding-issues.md as the single universal cross-session ledger and warns that detailed runbooks must not become a second status ledger; a per-session status table is close to that line. This is the documented precondition for #292 (two assistants shipped the same queued conversion four hours apart, one PR closed as a duplicate) and #301 (two sessions built #262 part 3 in parallel), and it is not hypothetical for this programme: the same check-before-filing discipline is what stopped this very row from being filed with a stale premise. Next (cheap, docs-only, no behaviour change): add to HANDOVER.md section 4's session-start checklist a step to read the recommended queue and check open PRs for the packet's surface, and decide whether the programme warrants one owning ledger row so its state is visible from the canonical side. Stop: do not duplicate the programme's tracks as ledger rows — that would create the second queue this row exists to prevent, in the other direction. Design authority stays with docs/rag-improvement/README.md and protected-surface rules with docs/rag-behaviour/. | session 2026-08-12/08-18 cross-session review; verified against origin/main 622f1fb | 2026-08-18 | @@ -151,6 +148,14 @@ removed after current-main verification; it is not missing recommended work. | #61TZJA | P3 | task | Re-adopt the document-viewer Linux visual baseline after PR #2199 lands | PR #2199 makes document search on demand, which moves the document-viewer golden two ways: the overview action reads 'Search document' instead of 'Add to scope', and the closed composer releases the desktop sm:pb-40 clearance that was previously always reserved. The committed tests/__screenshots__/linux/document-viewer.png therefore drifts the moment that PR merges. This is ordinary pixel drift, which scripts/classify-visual-baseline-outcome.mjs scores advisory rather than red, and the visual-baseline job runs only on pushes to main — so the refresh point is post-land, from that run's artifact, via npm run design-system:baselines:adopt. Blocked until #2199 merges: adopting earlier would commit a golden for a state main does not have. Related: the same PR removed .document-viewer-composer from that target's mask (it is no longer rendered in the default state, and assertMaskSelectors fails loudly on a mask matching zero nodes), so the closed composer's resting layout is now inside the compared region rather than painted over. Stop rule: adopt from the CI artifact only, never from a developer machine or this container — font hinting alone would make every later run red, which is what the suite's own header warns about. | PR #2199 (tests/ui-visual-baseline.spec.ts, commit e6d52b8); ci.yml visual-baseline job | 2026-08-21 | | #800E5M | P2 | rec | Reachability scans must not treat in-flight programme scaffolding as dead code (Ward Flow, Caring Contacts) | The 2026-08-20 cleanup sweep initially removed symbols from src/components/ward-management/ and src/components/caring-contacts/ because no file imported them. That test is wrong for a programme still under construction. wallClockNow() is a specified export of ward-clock.ts in docs/superpowers/plans/2026-08-18-ward-flow-phase-1-model.md, and movementsByStage(stage) is a specified export of ward-movements.ts in the Phase 2 coordinator plan, whose 55 tasks are all still unchecked -- the consumers (Tasks 5, 7, 8) have not been built yet. Ward Flow itself landed only on 2026-08-19 in PR #2140, and Caring Contacts is an active design programme with no production route. All of those removals were reverted on the owner's instruction and the areas are byte-identical to their pre-sweep state. Recommendation for any future dead-code sweep: before removing a symbol, check whether it is named as a module contract in docs/superpowers/plans/ or docs/superpowers/specs/, and treat any plan with unchecked tasks as in-flight and out of scope. A second trap in the same sweep: this container clones shallow (105 commits spanning only 2026-08-19..2026-08-20), so git cannot date file creation and 'is this recent?' is unanswerable locally -- deepen the clone before relying on file age. | docs/superpowers/plans/2026-08-18-ward-flow-phase-1-model.md, docs/superpowers/plans/2026-08-18-ward-flow-phase-2-coordinator-screen.md, src/components/ward-management/, src/components/caring-contacts/ | 2026-08-20 | | #4XBMMR | P2 | issue | public/mockups/** is publicly served and indexable in production; mockups/README.md claims otherwise | src/proxy.ts 404s /mockups/* routes when NODE_ENV=production, but its matcher explicitly excludes .svg/.png/.jpg/.jpeg/.gif/.webp/.ico, so the 19 MB of design comps under public/mockups/ are served unauthenticated at psychiatry.tools/mockups/... . src/lib/crawler-policy.ts serves robots.txt as allow:/ by design so crawlers can read per-page noindex metadata, and a raw PNG carries no such metadata; the X-Robots-Tag: noindex header in next.config.ts is scoped to /offline.html alone. mockups/README.md 'Production behavior' asserts that robots.txt disallows indexing, which is false. Content is UI design comps, not clinical or patient data, so this is weight and a broken documented guarantee rather than a privacy incident. Next step: add an X-Robots-Tag: noindex header for /mockups/:path* in next.config.ts, decide whether the comps should ship in the deploy image at all, and correct the README either way. Found by the 2026-08-20 repo-cleanup audit. | src/proxy.ts, src/lib/crawler-policy.ts, next.config.ts, mockups/README.md, public/mockups/ | 2026-08-20 | +| #KFRC3H | P2 | issue | mobile-/ Lighthouse CLS bistable flake: PR #2234 fixes 8 more racy double-:has() install-card selectors PR #2219 missed; unconfirmed pending CI | PR #2219 (fix/pwa-notice-cls-shift) fixed ONE of nine identical-shaped selectors in the phone-hero install-card @media block in src/app/globals.css: each chained a redundant second body:has(.pwa-install-native-sheet) on top of the hero-composer-ownership :has(), and PR #2219 removed that second :has() only from .pwa-notice-stack's own bottom-gap rule. The other 8 rules (hiding tagline/copy/support/benefits, compacting header/body/actions/compact-copy) kept the identical two-:has() shape, predating PR #2219 entirely (present on main before that branch existed), with zero test coverage. Confirmed via CI job log that mobile-root CLS was STILL exactly 0.223 on a run (32477570217, head 851f0d693b656aba8fd492cd627f726917c24410) after BOTH of PR #2219's fixes had landed on that branch -- proving a mechanism survived both. PR #2234 (fix/lighthouse-cls-flake-mobile-root, based on main, does NOT touch PR #2219's branch) replaces the second :has() in all 8 remaining rules with a plain descendant combinator off .pwa-install-native-sheet, adds a static-contract test guarding all 9 selectors, and passes npm run verify:pr-local in full (lint/typecheck/696 test files/build/RAG fixtures all green). NOT YET CONFIRMED: could not download the CI Lighthouse artifact (Azure Blob Storage egress blocked by this environment's network policy) to see the exact layout-shifts debugdata/node for the post-both-fixes failing run, so this fix is static-analysis-based, not trace-confirmed. A 20-run local repro loop (real Lighthouse 12.8.2, offline/demo build, Chromium rev 1194 vs CI's pinned chromium-1234) produced 0/20 breaches before and after -- consistent with this ledger's own prior finding that local repro never catches this regardless of harness or Chromium revision, so non-repro is not disconfirming. Confirming evidence must come from N consecutive green CI Lighthouse budget runs on PR #2234 itself. Do not close this row or the original bistable entry until that CI evidence lands; if PR #2234 lands and CI is STILL bistable afterward, a fourth mechanism remains and the original bistable entry should stay open with this PR noted as ruled out. | Investigation continuing docs/outstanding-issues-inbox/5f472de7-797f-49ba-8ba5-b5b6d4a7ad7a.json; PR https://github.com/BigSimmo/Database/pull/2234; CI run https://github.com/BigSimmo/Database/actions/runs/32477570217 | 2026-08-21 | +| #8VAY97 | P2 | task | The document_index_units retrieval path has no EXPLAIN baseline, and Phase 5 has no query-specific plan-flip evidence | Two Phase 5.1 deliverables are explicitly OPEN, not discharged. Re-graded P3 -> P2 versus the withdrawn request 2040d1fb, because that request understated the gap by claiming substitute coverage that does not exist. (A) NO EXPLAIN BASELINE FOR THE INDEX-UNITS PATH. public.explain_retrieval_rpc accepts exactly four names -- match_documents_for_query, match_document_chunks_text, match_document_lookup_chunks_text, match_document_table_facts_text -- and raises 22023 Unsupported retrieval RPC for anything else, proven against production for both match_document_chunks_text_v2 and match_document_index_units_hybrid_v2. For the first of those the v1 sibling match_document_chunks_text shares the owning table document_chunks and is a usable stand-in. For the second there is none: match_document_index_units_hybrid_v2 delegates to match_document_index_units_hybrid_scoped over document_index_units (supabase/schema.sql:8033-8054), and no supported RPC touches that table. document_index_units is one of the two section 1.2 outliers, so the outlier that most needed a baseline is the one that has none. (B) NO QUERY-SPECIFIC PLAN-FLIP EVIDENCE. explain_retrieval_rpc EXPLAINs `select * from public.(...)`, so a PL/pgSQL body's inner plan is never exposed and every sample reports a single Function Scan with no index names. Plan section 5.1's 'record plan flips (seq scan -> index scan)' is therefore unanswerable through this instrument. The pg_stat_user_indexes read captured in Phase 5.1(c) is a WEAKER and DIFFERENT signal, not a substitute: idx_scan is cumulative across every workload touching the table and no before/after delta was captured around the samples, so it can prove an index is never chosen by anything but cannot prove that a given query changed plan. NEXT: one migration extending the explain_retrieval_rpc p_rpc branch list to the _v2 family (at minimum match_document_index_units_hybrid_v2 and match_document_chunks_text_v2), shipped in an approved window -- with D4 ON, merging it to main deploys it, so it needs the window and a green post-merge live-drift run. Then re-run npm run profile:retrieval --analyze to capture the missing baseline. For (B), consider whether an auto_explain-style capture is a better fit than widening the RPC. STOP: do not record the cumulative index-usage read as plan-flip evidence; that conflation is exactly what this row exists to prevent. | Codex review of PR #2250 (P2, comment 3833062803 and 3833062807); docs/audit/live-drift-forensics-2026-08.md Phase 5 close-out 5.1(b); supabase/schema.sql:8033-8054 | 2026-08-21 | +| #47M1XD | P2 | issue | Restored trigram indexes have never been scanned, so the 2026-08-14 incident fix is probably mis-attributed to them rather than to ANALYZE | Measured on production 2026-08-22 Perth (2026-08-21 UTC), read-only. pg_stat_database.stats_reset is NULL, so no database-wide reset has been recorded -- note this does NOT prove the counters were never reset, because pg_stat_reset_single_table_counters(oid) resets one table or index without touching that database-level timestamp; 163 of 210 public indexes show scans, max(idx_scan) 262,335,345, total 344,747,815 -- the counters are demonstrably live. Against that, ALL 22 indexes restored or repaired by the incident response report idx_scan = 0: the 20 Phase 4 rebuilds of 2026-08-19, and both trigram indexes restored 2026-08-14 -- document_chunks_content_trgm_idx (68 MB, OID 1491258) and documents_title_trgm_idx (648 kB, OID 1491257). The OID matters: 1491258 is the same value Phase 4 Step 4 recorded as UNCHANGED across the 2026-08-19 push, so the index was never dropped and recreated and its counter has accumulated for the full seven days since restoration. What actually serves retrieval on those tables is document_chunks_search_idx (GIN tsvector, 37,717 scans), document_chunks_embedding_hnsw_idx (HNSW, 4,906) and documents_title_search_idx (37,299). Note that a DIFFERENT trigram index on a sibling table, document_table_facts_title_row_param_trgm_idx, is used 2,372 times, so this is not a blanket property of the planner or of pg_trgm. CONSEQUENCE: forensics Phase 5 attributes the 31,610 -> 1,535 ms recovery to 'restore + ANALYZE', treating the trigram restore as the fix. Zero scans mean those indexes are very unlikely to be carrying that recovery -- unlikely rather than impossible, because a per-relation counter reset would be invisible to the read above; the OID continuity across the 2026-08-19 push is what makes the zero credible, and ANALYZE was an unseparated co-intervention in the same operation -- 20260626020000 itself ends by running analyze over documents, document_chunks, document_table_facts, document_embedding_fields and document_index_units. Stale planner statistics is the better-supported explanation for both the 31-second regression and its recovery -- better-supported, not established. THIS DOES NOT RETRACT THE REPAIR: the two indexes are repo-defined, the migration chain commands them, and drift is correctly closed by their presence. It retracts the ATTRIBUTION, and it changes triage order -- the next 30-second retrieval incident should check planner statistics BEFORE hunting missing indexes. Secondary and non-urgent: roughly 69 MB of currently unscanned index. NEXT: (a) in an approved window, first rule out a per-index counter reset -- on PostgreSQL 18+ read pg_stat_all_indexes.stats_reset for these two OIDs, and on earlier versions fall back to whatever reset or audit record exists (the production server version was not read in this window); (b) separate the two interventions by measuring retrieval latency before and after a fresh ANALYZE; and (c) only then decide whether the two trigram indexes earn their storage. STOP: do NOT drop them -- they are repo-defined and dropping them reopens live drift. | production read-only window 2026-08-22 Perth (2026-08-21 UTC); docs/audit/live-drift-forensics-2026-08.md Phase 5 close-out 5.1(c) | 2026-08-21 | +| #K9XD5N | P3 | issue | DegradedNotice banner shifts the hero section by ~0.16 CLS on / when it appears/disappears (separate from the .pwa-notice-stack fix in PR #2219) | scripts/measure-cls-attribution.mjs (offline-only trigger, no install prompt) shows main#main-content > ... > section (the answer-mode hero, sourced from ClinicalDashboard's DegradedNotice) shifting from y=88,h=623 to y=165,h=623 — 0.159 CLS, 2 entries — purely from the in-flow DegradedNotice banner mounting/unmounting above it when isOnline flips. This is distinct from the .pwa-notice-stack root cause fixed in PR #2219 (fix/pwa-notice-cls-shift): that fix collapses .pwa-notice-stack's contribution to 0 under the same harness, but this hero-section shift is untouched by it and remained present in the fixed-code re-run (0.159 total, single source). The real Lighthouse CI trace that motivated #2219 (mobile-root, PRs #2199/#2204, 2026-08-21) named only .pwa-notice-stack as the shift source at score 0.223, so this hero-section mechanism apparently did not fire (or was below threshold) in that specific CI run — but it is a real, reproducible shift on the same route and could surface as a future budget flake. Likely fix direction: reserve the DegradedNotice banner's height (or use the same unmounted-frame-swap pattern) so its mount/unmount does not resize the hero section while already visible. | Investigation for PR #2219 (fix/pwa-notice-cls-shift), 2026-08-21 | 2026-08-21 | +| #99KVDF | P3 | rec | Do not re-attempt folding AnswerCard's support label inline into VerificationNotice — measured, it saves 4.5px, not a row | REFUTED 2026-08-21 by direct measurement; recorded so it is not re-attempted. Context: the full-frontend design review made `support` a required prop on AnswerCard (PR #2210), rendering "Evidence support: Strong support" as its own row above the answer prose. That added real height and tripped two tests/ui-smoke.spec.ts phone-geometry budgets in Production UI; d095f96 fixed them properly, by measuring the label's real rendered height via [data-testid="answer-card-support"] and adding it to permittedOverflow and to the post-collapse ceiling, rather than by fudging a constant. The standing follow-up idea was to fold the label INLINE into the end of the VerificationNotice sentence, on the theory that it would then cost nothing and both budgets could return to their original strict constants (+8 / < 72 / < 200). MEASURED, both variants on the same page at 390x900 in demo mode, same Chromium: LANDED standalone row = 11px text on a 16.5px line, and removing it shrinks the answer surface by 24.5px (16.5 line + 8px flex gap) and document scrollHeight by 24px. INLINE variant = the compact notice paragraph is 294px wide at 12px/20px line-height; the `ready` compact wording is 82 chars and wraps to 2 lines (40px), and appending " Evidence: Strong support." (26 chars) tips it to 3 lines (60px) - a 20px cost. So the inline form saves 4.5px, not ~24px. The two budgets overran by only 4px (maxScrollTop 12 vs 8) and 2px (postCollapseMaxOffset 74 vs 72), so 4.5px is a coin-flip rather than a fix, and it is NOT stable across states: the `ungrounded` compact wording is 140 chars against `ready`'s 82, so whether the appended clause tips a line varies by verification state, making the saving unpredictable exactly where the budget is tightest. It also buries a clinical trust signal mid-sentence instead of giving it a scannable row. CONCLUSION: the landed standalone-row design plus d095f96's measured budgets is correct; leave both alone. If the phone answer header ever does need height back, take it from somewhere with a stable cost, not from this label. | session 2026-08-21 | 2026-08-21 | +| #BJ80DB | P2 | issue | Windows-only test-budget failures: 3 tests fixed (2 of the original 5, plus 1 newly found in the same file), 2 unreproducible, 1 (hosted-migration-role-guard) still unexplained | Supersedes cancelled request 67bf71cf-25cb-40d9-a8a2-bbf993bf6b29, whose diagnosis was partly wrong. ORIGINAL REPORT: a full npm run test on a clean Windows workstation (D:\Repos\Database, main at cdfcbaccd, empty tree) exited 1 with 4 files / 5 tests failed, 680 files / 7423 passed, 601.68s. CORRECTED FINDING: main was never broken. A full GATE_RECEIPTS=off npm run test on Linux at the content-identical HEAD is green (696 files, 7770 passed, 4 skipped, exit 0, 196s), and git diff cdfcbaccd..HEAD shows none of the four test files nor their subjects changed. THE ROOT CAUSE FOR THE TWO NOW FIXED IS A TIME BUDGET, NOT A DEFECT IN BEHAVIOUR. (1) codex-cloud-setup 'writes managed shell policy behaviorally and preserves unrelated Codex config' measured 24.96s on that workstation running its file ALONE, against the 30s testTimeout in vitest.config.mts - 83% of budget with nothing competing; a full run puts maxWorkers:4 on the machine and it tips over. It spawns bash scripts/setup-codex-cloud.sh twice, cheap on Linux and expensive on Windows where every spawn goes through Git Bash. Its immediate sibling already carried an explicit 120_000 budget for the same reason (measured 112.9s); this one had been missed. FIXED in PR #2255 by giving it the same budget. (2) http-readiness 'honours the overall deadline when every response remains open' and its neighbour 'destroys stalled requests and resumes polling' both work to millisecond budgets (requestTimeoutMs 40, timeoutMs 180/1000) that Windows cannot hold. The neighbour fails IN ISOLATION ON AN IDLE MACHINE ('expected 4 to be 3'), which is stronger than a load flake: the 40ms request budget bounds not only the two deliberately-stalled responses but also the healthy third one, so a merely-late good response is destroyed as though stalled and the loop polls a fourth time. FIXED in PR #2256 (requestTimeoutMs 40->250 with the deadline 1s->5s; the other case's deadline 180ms->600ms), with a negative proof that breaking the stall-destroy path still fails both. (3) The two document-viewer page-virtualization cases PASS on re-run on that workstation (whole file 3566ms). PR #2252 made their shared failure point legible: flushIdle() could only report 'expected 0 to be greater than 0', which reads as a slow machine; it now names the canvas-budget cause and prints slot/rendered/observer counts. STILL OPEN AND THE REASON THIS ROW EXISTS: hosted-migration-role-guard 'accepts the current repository state' passed on re-run at 1550ms, nowhere near its 30s budget, so the timeout explanation that resolved the other two does NOT fit it and nothing has been changed for it. Its original cause is unexplained. Leading hypothesis, untested: validateRepository() calls repositoryEntries(), which runs git ls-files --cached --others --exclude-standard, so it grades UNTRACKED non-ignored files too - any stray file under scripts/, supabase/migrations/, .github/workflows/ or the guarded exact paths whose name or content matches the reserved role turns it red while git status still looks clean enough to call the tree empty, as would a nested git worktree directory (readFileSync on a directory entry throws EISDIR). It also SHA-256s the on-disk bytes of the pinned immutable migration, so CRLF would break it, though .gitattributes '* text=auto eol=lf' should prevent that and the bytes hash correctly on Linux. NEXT: if it recurs, capture git status --porcelain --untracked-files=all and git ls-files --others --exclude-standard at the moment of failure - the assertion alone will not identify which entry did it. FLAKE POLICY DOES NOT APPLY TO ANY OF THESE: tests/flake-ledger.json is explicitly Playwright-only (exact spec+title, @quarantine tag); all five are Vitest and none are eligible for quarantine. Also note the previously known local-Windows failures (tests/session-start-hook.test.ts, worker-observability) PASSED in the reported run, so any note calling those the known environmental set is stale. STANDING LESSON: on this workstation, a test's assertions being deterministic does NOT make its runtime deterministic. Subprocess-spawning and wall-clock-bounded tests need budgets sized for Windows, and 83%-of-budget in isolation is a latent failure, not a pass. | PRs #2252, #2255, #2256 (2026-08-21); Windows workstation runs at cdfcbaccd and after | 2026-08-21 | +| #HDYCQP | P2 | issue | PR mergeability re-fires on merged/closed PRs and always fails: the mergeability job has no PR-state filter, and a merged PR's mergeable_state is permanently 'unknown' | MECHANISM (confirmed end to end on PR #2229, 2026-08-21). .github/workflows/pr-mergeability.yml listens on pull_request_target with types [opened, synchronize, reopened, ready_for_review, edited]. GitHub fires 'edited' on CLOSED and MERGED pull requests, and this repo has a bot that reliably edits PR descriptions (the PR #2229 body carries a '## Summary by CodeRabbit' section). The 'mergeability' job is gated only by `if: github.event_name == 'pull_request_target'` — there is NO filter on pull_request.state, pull_request.merged, or head-ref existence. Its 'Signal real merge conflicts' step calls github.rest.pulls.get and feeds the result to classifyMergeability() in scripts/pr-mergeability.mjs. For a merged PR the API returns mergeable: null and mergeable_state: 'unknown' PERMANENTLY, which is exactly the classifier's 'retry' branch, so all 5 attempts retry and the step ends in core.setFailed('GitHub did not finish computing mergeability for PR # after 5 attempts.'). The failure is therefore deterministic, not flaky: any pull_request_target event on a merged or closed PR fails this required check. EVIDENCE. PR #2229 merged 2026-08-21T13:52:54Z (merge commit 68bcb38d031cb9c355d81d809c535a2ea3e2f9c6), head branch claude/ledger-reconcile-0821b deleted by the merge. At 13:54:31Z — 97 seconds after the merge — workflow run 32489311892 (.github/workflows/pr-mergeability.yml, event pull_request_target, triggering_actor coderabbitai[bot]) started; job 96792973908 'Refresh PR mergeability after base push' correctly skipped, and job 96792972554 'PR mergeability' failed at 13:54:51.99Z with exactly that setFailed message. A live pulls.get on #2229 today still returns state 'closed', merged true, mergeable_state 'unknown' — so the check would fail identically on every future edit event. MISSING FILTER, AND THE PROOF IT WAS AN OVERSIGHT. The sibling job in the same file, 'refresh-after-base-push', already scopes its work with github.rest.pulls.list({ state: 'open' }). The state filter was applied to the push path and omitted from the pull_request_target path. SMALLEST FIX (not applied; .github/workflows/** is operational-risk scope). Add a closed/merged branch to classifyMergeability() in scripts/pr-mergeability.mjs, ahead of the existing draft branch, returning { ok: true, action: 'skip', reason: 'merged' } when merged === true or state === 'closed', and pass state: latestPr.state / merged: latestPr.merged from both call sites in pr-mergeability.yml. This mirrors the existing draft skip path exactly, keeps the check reporting rather than silently skipping the job, and is provable offline with 'node scripts/pr-mergeability.mjs --self-test' plus a new assertion there. Do NOT fix this by dropping the 'edited' trigger type: 'edited' is what catches a base-branch change on an OPEN PR, which genuinely alters mergeability. Any change to this file must respect the deliberate cancel-in-progress asymmetry pinned by tests/ci-cache-safety.test.ts, which this fix does not touch. CORRECTION TO THE ORIGINAL REPORT — the co-reported symptoms were NOT part of this defect. The clarifying comment on #2229 (issuecomment-5371138259) attributed failing 'PR required' and 'Static PR checks' to the merge as well. That is wrong. ci.yml's pull_request types do not include 'edited', and the run list confirms it: every ci.yml run on claude/ledger-reconcile-0821b is pre-merge, and the last one (32489042816, 13:51:34-13:52:52Z, head 754cbfcb) was SUCCESS three seconds before the merge. The six earlier failures were genuine, diff-attributable failures on earlier heads — e.g. run 32488292727 at 13:44Z, where 'Static PR checks' exited 1 on its own step and 'PR required' logged 'static-pr result was failure' — and were fixed before merge. What made them look post-merge is that ci-triage.yml edits ONE comment in place: comment 5369760686 was created 12:23:46Z and last updated 13:44:36Z, both pre-merge, but still sat on the page after the merge naming those two jobs. So the ci-triage comment is stale-by-design, not re-fired; only 'PR mergeability' actually re-fired post-merge. Worth knowing before diagnosing the next one. RELATED, NOT DUPLICATE. #TF6TPJ is the cancellation-driven false red on OPEN PR branches ('PR required' red with zero failing jobs after repeated main-merges); different trigger, different job, different failure text. #HSSHRG (closed 2026-08-21) is the in-flight CI push guard in scripts/guard-push.mjs. Neither covers a required check re-firing against an already-merged PR. pr-policy.yml carries the same pull_request_target 'edited' exposure but is not defective — its post-merge run 32489311920 at 13:54:33Z passed. SCOPE NOT MEASURED. GitHub reads for this investigation were authorised only for PR #2229, so how often this fires repo-wide is unquantified. It should recur on any PR whose description a bot edits after merge, which is the normal CodeRabbit pattern here. | PR #2229; run 32489311892 job 96792972554 (2026-08-21T13:54:51Z); .github/workflows/pr-mergeability.yml; scripts/pr-mergeability.mjs; https://github.com/BigSimmo/Database/pull/2229#issuecomment-5371138259 | 2026-08-21 | +| #9X40BT | P2 | rec | Supabase preview-branch compute is an uncapped cost sitting outside the organisation Spend Cap | Dashboard read 2026-08-21 (the same read that settled D4) shows Automatic branching ON with limit 3 and "Supabase changes only" enabled, and the same screen warns that Branching Compute is NOT covered by the organisation's Spend Cap. Preview databases are therefore an uncapped cost that scales with the number of open PRs touching supabase/**, on a project that already runs auto-deploy to production. CONTEXT FOR ANY DECISION TO REDUCE OR DISABLE THEM: CI's Migration replay job (db-reset-verify, which runs `supabase migration up --local`) independently replays the entire migration chain on every database-touching PR, so preview branches are a SECOND net rather than the only one -- turning them down would not leave the chain unproven. Preview branches did earn their keep once (the 20260819100200 guard failure on PR #2151 was caught by a preview branch building from the chain alone), so this is a cost/benefit decision, not a cleanup. NEXT: decide whether to keep branching at limit 3, lower the limit, or disable it, and record the decision with its date. STOP: do not change Supabase project settings without explicit owner approval; this row is a decision request, not a licence to reconfigure the project. | Supabase dashboard read 2026-08-21; docs/audit/live-drift-forensics-2026-08.md D4 section; AGENTS.md Supabase project safety | 2026-08-21 | ## Resolved / archive @@ -521,3 +526,6 @@ Move resolved rows here with the resolution date and a one-line outcome. Keep th | #90Y0FD | rec | Mode home suggestion data is duplicated across three unrelated sources | Resolved 2026-08-20: verified on origin/main a341832af. searchCommandSurfaceByMode entries now spread sharedHomePresentation..suggestions into examples, and therapy-compass home-screen.tsx takes its pill row from the same source, so the Try this ticket and the pill row can no longer advertise different sets. Residual not re-queued: the typed chip suggestions arrays and tools-catalog remain separate lists serving different surfaces. | 2026-08-20 | | #339 | task | Favourites Continue and Recent are driven by hard-coded demo timestamps; real saved items have no last-opened data | Resolved 2026-08-20: verified on origin/main a341832af. favourites-command-library-page.tsx now derives lastUsed from a real lastOpenedMap plus formatLastOpened, with recordFavouriteOpened(item.id) wired to every open path (ten call sites), and the hard-coded lastUsedByItemId literals are gated behind demoMode. Real saved items now carry real last-opened data; 'Saved' is only the never-opened fallback. | 2026-08-20 | | #YJ3R7Y | issue | Tools and Favourites bespoke home composer slots skip the SSR height reservation chrome invariant 15 requires | Resolved 2026-08-20: verified on origin/main a341832af. All three bespoke composer slots now pass data-composer-reserve={modeHomeComposerReservePendingValue} with the matching min-h reserve classes: favourites-command-library-page.tsx:1445, favourites-hub.tsx:191 and tools-search-results-page.tsx:354, so chrome invariant 15's SSR height reservation holds on all three. | 2026-08-20 | +| #SZGPAH | issue | tests/ui-tools-search-mode-mockup.spec.ts has two assertions stale on main, so the advisory lane is red for every UI PR | Resolved 2026-08-21. Re-measured first-hand on 2026-08-21 at HEAD e4df772e3712620a8d64dc28843048e32bde88ee: node scripts/run-playwright.mjs --project=chromium-mockups tests/ui-tools-search-mode-mockup.spec.ts reported '16 passed (1.5m)' with exit code 0. Both previously-failing tests are green by name: test 1, 'desktop uses universal search and keeps results beside the selected-tool panel' (spec line 24, 10.9s), and test 9, 'phone filter sheet follows the shared local-filter behavior' (spec line 194, 4.5s). This independently reproduces the run at a341832af cited by the request cancelled as 3eb84c6a-97fa-4b1c-9167-190ba928c200, whose author explicitly recommended that a fresh done request be queued so the evidence would not be lost; that recommendation is what this request carries out. The rows are therefore closed on a reproduced measurement, not on a third-party claim. The advisory lane is no longer red for every UI PR from this spec. Note for the record: the 2026-08-21 update on this row said 'NOT VERIFIED: whether the spec now passes ... Re-measure before closing' - that re-measurement has now been done and is the basis for this closure. | 2026-08-21 | +| #316 | issue | Live DB has 20 currently missing repo-defined indexes and 10 retrieval RPC bodies diverge; weekly live-drift has been red since 2026-07-26 with no routing | CLOSED 2026-08-22 Perth (2026-08-21 UTC) -- Phase 5, this row's last remaining follow-on, is complete and the alarm is OBSERVED clear rather than merely believed clear. (1) MEASUREMENT, like-for-like with the section 1.3 probe style: text fast path 31,610 -> 955 ms (33x better than the incident, 1.6x better than the 2026-08-14 post-restore reading); hybrid 21,757 -> 6,720 ms. Nothing was worse than the 2026-08-17 healthy baseline, so nothing was escalated. A new EXPLAIN forward baseline was captured on the healthy system for all four RPCs that explain_retrieval_rpc supports, zero errors across twelve samples; the new slowest path is match_document_table_facts_text (1.72 s unprimed, 1,070 unprimed shared_read). Section 1.3's two pending items are now closed: missing-index sizing is moot (0 missing) and the rag_retrieval_logs miss-scan baseline is recorded (47 seq scans, 6,620 tuples read, 640 live rows, 1.4 MB -- cheap at this scale; the row to watch as it grows is rag_aliases at 5,829 seq scans over 68 rows). (2) 5.2 confirmed ALREADY SATISFIED via #231 and not reopened: retrieval now consumes 4-27% of the 25 s fast-route budget, so it cannot bind it. (3) 5.3 needed NO eval canary -- Phase 3 deployed zero behaviour change -- so it reduced to check:production-readiness: READY, 9 PASS, 0 blocking failures. (4) PRODUCTION RE-VERIFIED UNCHANGED, 8/8 against the 2026-08-21 baseline: 210 public indexes, 0 invalid, 211 history rows, 20 no-statement rows, migration_history_versions() probe ok with 211 versions, search_schema_health() ok true. (5) STAGING PARITY CLOSED: 20260820120000 applied to ikoiolksxqxfxgiyqpnu by real db push (never migration repair); staging now reads 211 rows with the function present and stmt_count 3, matching production exactly. (6) THE ALARM IS OBSERVED CLEAR: live-drift run 32514326022, dispatched on main, is GREEN -- 'No unexpected schema drift between live and supabase/schema.sql', 'Remote migration versions: 211 (read via rpc)', 'Remote-only (Preview blockers): 0', every step success. That is the FIRST green live-drift since 2026-07-19T19:37:29Z (of the last 60 runs only four succeeded), ending a 33-day red streak, and pinned issue #1963 auto-closed at 2026-08-21T18:38:42Z. (7) D4 DOCUMENTATION CORRECTED: this row's 2026-08-19 'auto-deploy is OFF' sentence was already superseded by the 2026-08-21 correction; the coordination board and the forensics dossier are now aligned to the dashboard fact (Deploy to production ENABLED, production branch main, automatic branching ON limit 3), with the superseded safe-either-way reasoning retained and marked rather than deleted. THREE FINDINGS QUEUED SEPARATELY rather than absorbed here: the uncapped Branching Compute cost; the explain_retrieval_rpc gap on the _v2 RPC family (needs production DDL, deliberately not written in a read-only phase); and the discovery that all 22 restored indexes report idx_scan = 0 with no database-wide statistics reset recorded, which makes ANALYZE rather than the trigram restore the better-supported explanation for the incident recovery (a per-relation pg_stat_reset_single_table_counters() call would not show in that read, so this is well-supported, not proven). RESIDUAL WORK LIVES ON ITS OWN ROWS, not here: PITR is still OFF on production, and the fifteen no-statements history rows remain #Q5JHBJ. | 2026-08-21 | +| #4TBHS8 | issue | Advisory UI mockup spec 'phone filter sheet follows the shared local-filter behavior' fails on main | Resolved 2026-08-21. Re-measured first-hand on 2026-08-21 at HEAD e4df772e3712620a8d64dc28843048e32bde88ee: node scripts/run-playwright.mjs --project=chromium-mockups tests/ui-tools-search-mode-mockup.spec.ts reported '16 passed (1.5m)' with exit code 0. Both previously-failing tests are green by name: test 1, 'desktop uses universal search and keeps results beside the selected-tool panel' (spec line 24, 10.9s), and test 9, 'phone filter sheet follows the shared local-filter behavior' (spec line 194, 4.5s). This independently reproduces the run at a341832af cited by the request cancelled as 1a175782-d9cf-4de6-a67b-d3b2da632c84, whose author explicitly recommended that a fresh done request be queued so the evidence would not be lost; that recommendation is what this request carries out. The rows are therefore closed on a reproduced measurement, not on a third-party claim. The specific failure recorded here - waiting for the exact text '2 showing' inside the tools-search-filter-sheet testid - is gone with the rewritten assertion, and the rewritten test passes. Tracked with #SZGPAH, which named the same spec file and closed on the same run. | 2026-08-21 | From b6e17ff53d1d84ac45b449ad2ab66ddd762ce28b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 20:52:03 +0000 Subject: [PATCH 2/2] docs(issues): queue the recommended-queue re-grade gap found in review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #2260's review raised that queue row 1 still presents `#231` as A1 "Immediate approved live investigation" into retrieval binding the fast route, while the #231 Open-items row this PR updates records the P1 -> P2 re-grade and the measurement that closed that cause. The finding is correct, and the row itself asks for the queue entry to be re-graded "AT RECONCILE". It cannot be honoured here, for structural reasons rather than oversight: - `updateIssue` edits only Open-items columns; the sole queue-touching function is `pruneResolvedIdFromQueue`, which runs on `done` and only deletes the row. Nothing can re-grade one. - A hand edit of the canonical ledger is refused by `check:ledger-write-discipline` — its self-test asserts that accepting a manual canonical edit is a failure. - Creating a request on this branch and applying it in the same transaction is refused: the applied batch must equal the base inbox exactly. So this files the gap as a pending inbox request for the next serialized reconcile, which is the one shape the guard accepts, rather than editing the canonical ledger. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01ApB8NBygQn9cosxCQ8omk9 --- .../6895c60a-309d-4ecc-ae2e-5d34163761b2.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs/outstanding-issues-inbox/6895c60a-309d-4ecc-ae2e-5d34163761b2.json diff --git a/docs/outstanding-issues-inbox/6895c60a-309d-4ecc-ae2e-5d34163761b2.json b/docs/outstanding-issues-inbox/6895c60a-309d-4ecc-ae2e-5d34163761b2.json new file mode 100644 index 000000000..060599b7d --- /dev/null +++ b/docs/outstanding-issues-inbox/6895c60a-309d-4ecc-ae2e-5d34163761b2.json @@ -0,0 +1,14 @@ +{ + "version": 2, + "id": "6895c60a-309d-4ecc-ae2e-5d34163761b2", + "createdOn": "2026-08-21", + "action": "add", + "payload": { + "pri": "P2", + "type": "issue", + "summary": "Recommended-execution-queue rows cannot be re-graded by any ledger writer operation", + "detail": "FILED 2026-08-21 from PR #2260 review (Codex P2, verified against the repo). The queue row for an issue and its Open-items row can disagree indefinitely, because no writer can change the queue row's text. Concrete instance: queue row 1 still presents `#231` as A1 / 'Immediate approved live investigation' into retrieval binding `answerRouteBudgetMs.fast`, while the #231 Open-items row -- updated by PR #2260 -- records the P1 -> P2 re-grade and the measurement that closed that cause (retrieval now consumes 4-27% of the 25 s fast budget). The row itself asks for the queue entry to be re-graded 'AT RECONCILE'. That could not be honoured, and the reason is structural, not an oversight: (1) scripts/outstanding-issues.mjs updateIssue edits only Open-items columns (editable = { pri: 1, summary: 3, detail: 4, source: 5 }) and the only queue-touching function is pruneResolvedIdFromQueue, which runs on 'done' and merely deletes the row; (2) a hand edit of docs/outstanding-issues.md is refused by check:ledger-write-discipline, whose own self-test asserts 'manual canonical edit accepted' is a failure; (3) creating a request on the reconcile branch and applying it in the same transaction is refused -- verifyIssueReconciliation returns 'was introduced without moving the identical pending request from the base', since the applied batch must equal the base inbox exactly. So the queue can only be pruned, never corrected. RISK: the queue owns recommended order, acuity, timing, and approvals, so a stale A1 entry can send an operator into provider-backed live work on a cause the ledger elsewhere declares closed. NEXT (choose one, owner's call): add a queue-row edit action to scripts/outstanding-issues.mjs plus an inbox request action that carries it, so re-grades travel through the serial transaction like every other mutation; or accept a narrow, explicitly-audited hand-edit path for the queue section only. STOP: do not hand-edit docs/outstanding-issues.md to clear the #231 instance -- that is the exact write the guard exists to refuse.", + "source": "PR #2260 review thread discussion_r3833600137; docs/outstanding-issues.md queue row 1 and row #231; scripts/outstanding-issues.mjs:255-279; scripts/check-ledger-write-discipline.mjs:130-175", + "issueUlid": "01M0K1EDKAM6JNR80RPQNVE930" + } +}