diff --git a/docs/outstanding-issues-inbox/02a39fa5-f889-4098-96a7-d5b9e5352b8f.json b/docs/outstanding-issues-inbox/applied/02a39fa5-f889-4098-96a7-d5b9e5352b8f.json similarity index 100% rename from docs/outstanding-issues-inbox/02a39fa5-f889-4098-96a7-d5b9e5352b8f.json rename to docs/outstanding-issues-inbox/applied/02a39fa5-f889-4098-96a7-d5b9e5352b8f.json diff --git a/docs/outstanding-issues-inbox/04d7b548-a676-4f13-beb1-4215e7d9277c.json b/docs/outstanding-issues-inbox/applied/04d7b548-a676-4f13-beb1-4215e7d9277c.json similarity index 100% rename from docs/outstanding-issues-inbox/04d7b548-a676-4f13-beb1-4215e7d9277c.json rename to docs/outstanding-issues-inbox/applied/04d7b548-a676-4f13-beb1-4215e7d9277c.json diff --git a/docs/outstanding-issues-inbox/068c5a72-0f52-4dcf-bd1b-a9acc7783962.json b/docs/outstanding-issues-inbox/applied/068c5a72-0f52-4dcf-bd1b-a9acc7783962.json similarity index 100% rename from docs/outstanding-issues-inbox/068c5a72-0f52-4dcf-bd1b-a9acc7783962.json rename to docs/outstanding-issues-inbox/applied/068c5a72-0f52-4dcf-bd1b-a9acc7783962.json diff --git a/docs/outstanding-issues-inbox/090820f0-6389-4cf2-8a19-4ede897364bb.json b/docs/outstanding-issues-inbox/applied/090820f0-6389-4cf2-8a19-4ede897364bb.json similarity index 100% rename from docs/outstanding-issues-inbox/090820f0-6389-4cf2-8a19-4ede897364bb.json rename to docs/outstanding-issues-inbox/applied/090820f0-6389-4cf2-8a19-4ede897364bb.json diff --git a/docs/outstanding-issues-inbox/0de7c846-b53f-42e5-ab1d-fe43135c1eef.json b/docs/outstanding-issues-inbox/applied/0de7c846-b53f-42e5-ab1d-fe43135c1eef.json similarity index 100% rename from docs/outstanding-issues-inbox/0de7c846-b53f-42e5-ab1d-fe43135c1eef.json rename to docs/outstanding-issues-inbox/applied/0de7c846-b53f-42e5-ab1d-fe43135c1eef.json diff --git a/docs/outstanding-issues-inbox/17e75361-d767-4c72-96ea-7d1bf34959c6.json b/docs/outstanding-issues-inbox/applied/17e75361-d767-4c72-96ea-7d1bf34959c6.json similarity index 100% rename from docs/outstanding-issues-inbox/17e75361-d767-4c72-96ea-7d1bf34959c6.json rename to docs/outstanding-issues-inbox/applied/17e75361-d767-4c72-96ea-7d1bf34959c6.json diff --git a/docs/outstanding-issues-inbox/1a175782-d9cf-4de6-a67b-d3b2da632c84.json b/docs/outstanding-issues-inbox/applied/1a175782-d9cf-4de6-a67b-d3b2da632c84.json similarity index 100% rename from docs/outstanding-issues-inbox/1a175782-d9cf-4de6-a67b-d3b2da632c84.json rename to docs/outstanding-issues-inbox/applied/1a175782-d9cf-4de6-a67b-d3b2da632c84.json diff --git a/docs/outstanding-issues-inbox/1c104a63-698b-49d6-8b95-d933b7ee59d8.json b/docs/outstanding-issues-inbox/applied/1c104a63-698b-49d6-8b95-d933b7ee59d8.json similarity index 100% rename from docs/outstanding-issues-inbox/1c104a63-698b-49d6-8b95-d933b7ee59d8.json rename to docs/outstanding-issues-inbox/applied/1c104a63-698b-49d6-8b95-d933b7ee59d8.json diff --git a/docs/outstanding-issues-inbox/1c280ab2-7c3d-4985-b6b2-ed1b5466b853.json b/docs/outstanding-issues-inbox/applied/1c280ab2-7c3d-4985-b6b2-ed1b5466b853.json similarity index 100% rename from docs/outstanding-issues-inbox/1c280ab2-7c3d-4985-b6b2-ed1b5466b853.json rename to docs/outstanding-issues-inbox/applied/1c280ab2-7c3d-4985-b6b2-ed1b5466b853.json diff --git a/docs/outstanding-issues-inbox/249bbac7-839b-43c6-85c4-cf93b0f02383.json b/docs/outstanding-issues-inbox/applied/249bbac7-839b-43c6-85c4-cf93b0f02383.json similarity index 100% rename from docs/outstanding-issues-inbox/249bbac7-839b-43c6-85c4-cf93b0f02383.json rename to docs/outstanding-issues-inbox/applied/249bbac7-839b-43c6-85c4-cf93b0f02383.json diff --git a/docs/outstanding-issues-inbox/29bf4571-4bc3-42cf-8a4a-7edab14ee031.json b/docs/outstanding-issues-inbox/applied/29bf4571-4bc3-42cf-8a4a-7edab14ee031.json similarity index 100% rename from docs/outstanding-issues-inbox/29bf4571-4bc3-42cf-8a4a-7edab14ee031.json rename to docs/outstanding-issues-inbox/applied/29bf4571-4bc3-42cf-8a4a-7edab14ee031.json diff --git a/docs/outstanding-issues-inbox/29d09ba7-2ee1-4801-98a1-4e7f94644ecd.json b/docs/outstanding-issues-inbox/applied/29d09ba7-2ee1-4801-98a1-4e7f94644ecd.json similarity index 100% rename from docs/outstanding-issues-inbox/29d09ba7-2ee1-4801-98a1-4e7f94644ecd.json rename to docs/outstanding-issues-inbox/applied/29d09ba7-2ee1-4801-98a1-4e7f94644ecd.json diff --git a/docs/outstanding-issues-inbox/30225672-82e8-4eac-9fb1-79f2448fdb8c.json b/docs/outstanding-issues-inbox/applied/30225672-82e8-4eac-9fb1-79f2448fdb8c.json similarity index 100% rename from docs/outstanding-issues-inbox/30225672-82e8-4eac-9fb1-79f2448fdb8c.json rename to docs/outstanding-issues-inbox/applied/30225672-82e8-4eac-9fb1-79f2448fdb8c.json diff --git a/docs/outstanding-issues-inbox/32d107af-ded9-49b1-9fa1-80be3715a5e0.json b/docs/outstanding-issues-inbox/applied/32d107af-ded9-49b1-9fa1-80be3715a5e0.json similarity index 100% rename from docs/outstanding-issues-inbox/32d107af-ded9-49b1-9fa1-80be3715a5e0.json rename to docs/outstanding-issues-inbox/applied/32d107af-ded9-49b1-9fa1-80be3715a5e0.json diff --git a/docs/outstanding-issues-inbox/3399642f-f5c4-46ac-89cd-473c0e0823fe.json b/docs/outstanding-issues-inbox/applied/3399642f-f5c4-46ac-89cd-473c0e0823fe.json similarity index 100% rename from docs/outstanding-issues-inbox/3399642f-f5c4-46ac-89cd-473c0e0823fe.json rename to docs/outstanding-issues-inbox/applied/3399642f-f5c4-46ac-89cd-473c0e0823fe.json diff --git a/docs/outstanding-issues-inbox/34cfce6f-71a8-4ad3-8e95-e5fac0e90c40.json b/docs/outstanding-issues-inbox/applied/34cfce6f-71a8-4ad3-8e95-e5fac0e90c40.json similarity index 100% rename from docs/outstanding-issues-inbox/34cfce6f-71a8-4ad3-8e95-e5fac0e90c40.json rename to docs/outstanding-issues-inbox/applied/34cfce6f-71a8-4ad3-8e95-e5fac0e90c40.json diff --git a/docs/outstanding-issues-inbox/3622b3f9-ef00-494e-8207-f80536eb2c4e.json b/docs/outstanding-issues-inbox/applied/3622b3f9-ef00-494e-8207-f80536eb2c4e.json similarity index 100% rename from docs/outstanding-issues-inbox/3622b3f9-ef00-494e-8207-f80536eb2c4e.json rename to docs/outstanding-issues-inbox/applied/3622b3f9-ef00-494e-8207-f80536eb2c4e.json diff --git a/docs/outstanding-issues-inbox/3b9a4858-2665-4fe7-9ff4-ada3e650c644.json b/docs/outstanding-issues-inbox/applied/3b9a4858-2665-4fe7-9ff4-ada3e650c644.json similarity index 100% rename from docs/outstanding-issues-inbox/3b9a4858-2665-4fe7-9ff4-ada3e650c644.json rename to docs/outstanding-issues-inbox/applied/3b9a4858-2665-4fe7-9ff4-ada3e650c644.json diff --git a/docs/outstanding-issues-inbox/3eb66718-997b-4db9-8970-cc7a4d6cbe63.json b/docs/outstanding-issues-inbox/applied/3eb66718-997b-4db9-8970-cc7a4d6cbe63.json similarity index 100% rename from docs/outstanding-issues-inbox/3eb66718-997b-4db9-8970-cc7a4d6cbe63.json rename to docs/outstanding-issues-inbox/applied/3eb66718-997b-4db9-8970-cc7a4d6cbe63.json diff --git a/docs/outstanding-issues-inbox/3eb84c6a-97fa-4b1c-9167-190ba928c200.json b/docs/outstanding-issues-inbox/applied/3eb84c6a-97fa-4b1c-9167-190ba928c200.json similarity index 100% rename from docs/outstanding-issues-inbox/3eb84c6a-97fa-4b1c-9167-190ba928c200.json rename to docs/outstanding-issues-inbox/applied/3eb84c6a-97fa-4b1c-9167-190ba928c200.json diff --git a/docs/outstanding-issues-inbox/46755148-9e76-4cc7-9eae-3faa32d9c8b7.json b/docs/outstanding-issues-inbox/applied/46755148-9e76-4cc7-9eae-3faa32d9c8b7.json similarity index 100% rename from docs/outstanding-issues-inbox/46755148-9e76-4cc7-9eae-3faa32d9c8b7.json rename to docs/outstanding-issues-inbox/applied/46755148-9e76-4cc7-9eae-3faa32d9c8b7.json diff --git a/docs/outstanding-issues-inbox/48bd82db-0f97-49e5-b0ef-d19e9f901c86.json b/docs/outstanding-issues-inbox/applied/48bd82db-0f97-49e5-b0ef-d19e9f901c86.json similarity index 100% rename from docs/outstanding-issues-inbox/48bd82db-0f97-49e5-b0ef-d19e9f901c86.json rename to docs/outstanding-issues-inbox/applied/48bd82db-0f97-49e5-b0ef-d19e9f901c86.json diff --git a/docs/outstanding-issues-inbox/4a9488a8-ed77-4784-894f-85a98b1599e5.json b/docs/outstanding-issues-inbox/applied/4a9488a8-ed77-4784-894f-85a98b1599e5.json similarity index 100% rename from docs/outstanding-issues-inbox/4a9488a8-ed77-4784-894f-85a98b1599e5.json rename to docs/outstanding-issues-inbox/applied/4a9488a8-ed77-4784-894f-85a98b1599e5.json diff --git a/docs/outstanding-issues-inbox/4ac63981-491c-4ab5-afa5-9ce319a5a10f.json b/docs/outstanding-issues-inbox/applied/4ac63981-491c-4ab5-afa5-9ce319a5a10f.json similarity index 100% rename from docs/outstanding-issues-inbox/4ac63981-491c-4ab5-afa5-9ce319a5a10f.json rename to docs/outstanding-issues-inbox/applied/4ac63981-491c-4ab5-afa5-9ce319a5a10f.json diff --git a/docs/outstanding-issues-inbox/58351996-e4d4-46b3-bbf0-29a51df5081e.json b/docs/outstanding-issues-inbox/applied/58351996-e4d4-46b3-bbf0-29a51df5081e.json similarity index 100% rename from docs/outstanding-issues-inbox/58351996-e4d4-46b3-bbf0-29a51df5081e.json rename to docs/outstanding-issues-inbox/applied/58351996-e4d4-46b3-bbf0-29a51df5081e.json diff --git a/docs/outstanding-issues-inbox/5b31b1a6-6ac7-4cf6-983e-1520a40d570e.json b/docs/outstanding-issues-inbox/applied/5b31b1a6-6ac7-4cf6-983e-1520a40d570e.json similarity index 100% rename from docs/outstanding-issues-inbox/5b31b1a6-6ac7-4cf6-983e-1520a40d570e.json rename to docs/outstanding-issues-inbox/applied/5b31b1a6-6ac7-4cf6-983e-1520a40d570e.json diff --git a/docs/outstanding-issues-inbox/5ce31276-9d07-4e4b-a486-b7f41decaa87.json b/docs/outstanding-issues-inbox/applied/5ce31276-9d07-4e4b-a486-b7f41decaa87.json similarity index 100% rename from docs/outstanding-issues-inbox/5ce31276-9d07-4e4b-a486-b7f41decaa87.json rename to docs/outstanding-issues-inbox/applied/5ce31276-9d07-4e4b-a486-b7f41decaa87.json diff --git a/docs/outstanding-issues-inbox/5f472de7-797f-49ba-8ba5-b5b6d4a7ad7a.json b/docs/outstanding-issues-inbox/applied/5f472de7-797f-49ba-8ba5-b5b6d4a7ad7a.json similarity index 100% rename from docs/outstanding-issues-inbox/5f472de7-797f-49ba-8ba5-b5b6d4a7ad7a.json rename to docs/outstanding-issues-inbox/applied/5f472de7-797f-49ba-8ba5-b5b6d4a7ad7a.json diff --git a/docs/outstanding-issues-inbox/6c8bdf87-7983-448b-81d9-65f5a735077e.json b/docs/outstanding-issues-inbox/applied/6c8bdf87-7983-448b-81d9-65f5a735077e.json similarity index 100% rename from docs/outstanding-issues-inbox/6c8bdf87-7983-448b-81d9-65f5a735077e.json rename to docs/outstanding-issues-inbox/applied/6c8bdf87-7983-448b-81d9-65f5a735077e.json diff --git a/docs/outstanding-issues-inbox/6d7c79b5-06cf-4076-a736-9fee535ccce3.json b/docs/outstanding-issues-inbox/applied/6d7c79b5-06cf-4076-a736-9fee535ccce3.json similarity index 100% rename from docs/outstanding-issues-inbox/6d7c79b5-06cf-4076-a736-9fee535ccce3.json rename to docs/outstanding-issues-inbox/applied/6d7c79b5-06cf-4076-a736-9fee535ccce3.json diff --git a/docs/outstanding-issues-inbox/74d9f4c7-96d0-4d98-862f-3fc4184f813c.json b/docs/outstanding-issues-inbox/applied/74d9f4c7-96d0-4d98-862f-3fc4184f813c.json similarity index 100% rename from docs/outstanding-issues-inbox/74d9f4c7-96d0-4d98-862f-3fc4184f813c.json rename to docs/outstanding-issues-inbox/applied/74d9f4c7-96d0-4d98-862f-3fc4184f813c.json diff --git a/docs/outstanding-issues-inbox/966143f8-5f2b-411d-9121-56360b5c3f54.json b/docs/outstanding-issues-inbox/applied/966143f8-5f2b-411d-9121-56360b5c3f54.json similarity index 100% rename from docs/outstanding-issues-inbox/966143f8-5f2b-411d-9121-56360b5c3f54.json rename to docs/outstanding-issues-inbox/applied/966143f8-5f2b-411d-9121-56360b5c3f54.json diff --git a/docs/outstanding-issues-inbox/9a01f033-b9b1-46a3-ab57-f4e24b4f1140.json b/docs/outstanding-issues-inbox/applied/9a01f033-b9b1-46a3-ab57-f4e24b4f1140.json similarity index 100% rename from docs/outstanding-issues-inbox/9a01f033-b9b1-46a3-ab57-f4e24b4f1140.json rename to docs/outstanding-issues-inbox/applied/9a01f033-b9b1-46a3-ab57-f4e24b4f1140.json diff --git a/docs/outstanding-issues-inbox/a2c34077-7eec-4023-aef7-af2a5b21ca42.json b/docs/outstanding-issues-inbox/applied/a2c34077-7eec-4023-aef7-af2a5b21ca42.json similarity index 100% rename from docs/outstanding-issues-inbox/a2c34077-7eec-4023-aef7-af2a5b21ca42.json rename to docs/outstanding-issues-inbox/applied/a2c34077-7eec-4023-aef7-af2a5b21ca42.json diff --git a/docs/outstanding-issues-inbox/a58cedb0-f8fd-4244-bf19-978699e2fda7.json b/docs/outstanding-issues-inbox/applied/a58cedb0-f8fd-4244-bf19-978699e2fda7.json similarity index 100% rename from docs/outstanding-issues-inbox/a58cedb0-f8fd-4244-bf19-978699e2fda7.json rename to docs/outstanding-issues-inbox/applied/a58cedb0-f8fd-4244-bf19-978699e2fda7.json diff --git a/docs/outstanding-issues-inbox/b39c23df-a7eb-4a6a-aae5-a43943377d2d.json b/docs/outstanding-issues-inbox/applied/b39c23df-a7eb-4a6a-aae5-a43943377d2d.json similarity index 100% rename from docs/outstanding-issues-inbox/b39c23df-a7eb-4a6a-aae5-a43943377d2d.json rename to docs/outstanding-issues-inbox/applied/b39c23df-a7eb-4a6a-aae5-a43943377d2d.json diff --git a/docs/outstanding-issues-inbox/b76b0daf-2463-4895-825a-5ce4632f49ac.json b/docs/outstanding-issues-inbox/applied/b76b0daf-2463-4895-825a-5ce4632f49ac.json similarity index 100% rename from docs/outstanding-issues-inbox/b76b0daf-2463-4895-825a-5ce4632f49ac.json rename to docs/outstanding-issues-inbox/applied/b76b0daf-2463-4895-825a-5ce4632f49ac.json diff --git a/docs/outstanding-issues-inbox/bc68f2d7-fb20-42da-800d-b4507b4a067f.json b/docs/outstanding-issues-inbox/applied/bc68f2d7-fb20-42da-800d-b4507b4a067f.json similarity index 100% rename from docs/outstanding-issues-inbox/bc68f2d7-fb20-42da-800d-b4507b4a067f.json rename to docs/outstanding-issues-inbox/applied/bc68f2d7-fb20-42da-800d-b4507b4a067f.json diff --git a/docs/outstanding-issues-inbox/bd4997ba-068d-480a-bc47-8b0a216b4451.json b/docs/outstanding-issues-inbox/applied/bd4997ba-068d-480a-bc47-8b0a216b4451.json similarity index 100% rename from docs/outstanding-issues-inbox/bd4997ba-068d-480a-bc47-8b0a216b4451.json rename to docs/outstanding-issues-inbox/applied/bd4997ba-068d-480a-bc47-8b0a216b4451.json diff --git a/docs/outstanding-issues-inbox/c48838cd-2c96-4257-9297-116553746c5d.json b/docs/outstanding-issues-inbox/applied/c48838cd-2c96-4257-9297-116553746c5d.json similarity index 100% rename from docs/outstanding-issues-inbox/c48838cd-2c96-4257-9297-116553746c5d.json rename to docs/outstanding-issues-inbox/applied/c48838cd-2c96-4257-9297-116553746c5d.json diff --git a/docs/outstanding-issues-inbox/c68684ed-c16f-46ae-8238-c3d40be7342f.json b/docs/outstanding-issues-inbox/applied/c68684ed-c16f-46ae-8238-c3d40be7342f.json similarity index 100% rename from docs/outstanding-issues-inbox/c68684ed-c16f-46ae-8238-c3d40be7342f.json rename to docs/outstanding-issues-inbox/applied/c68684ed-c16f-46ae-8238-c3d40be7342f.json diff --git a/docs/outstanding-issues-inbox/c6a9756d-f417-4be0-a846-124200672554.json b/docs/outstanding-issues-inbox/applied/c6a9756d-f417-4be0-a846-124200672554.json similarity index 100% rename from docs/outstanding-issues-inbox/c6a9756d-f417-4be0-a846-124200672554.json rename to docs/outstanding-issues-inbox/applied/c6a9756d-f417-4be0-a846-124200672554.json diff --git a/docs/outstanding-issues-inbox/d3addb93-9550-4ecf-a8d2-c363caed4f49.json b/docs/outstanding-issues-inbox/applied/d3addb93-9550-4ecf-a8d2-c363caed4f49.json similarity index 100% rename from docs/outstanding-issues-inbox/d3addb93-9550-4ecf-a8d2-c363caed4f49.json rename to docs/outstanding-issues-inbox/applied/d3addb93-9550-4ecf-a8d2-c363caed4f49.json diff --git a/docs/outstanding-issues-inbox/dceb6940-445e-4dc4-93b1-3fd9aa51f3fe.json b/docs/outstanding-issues-inbox/applied/dceb6940-445e-4dc4-93b1-3fd9aa51f3fe.json similarity index 100% rename from docs/outstanding-issues-inbox/dceb6940-445e-4dc4-93b1-3fd9aa51f3fe.json rename to docs/outstanding-issues-inbox/applied/dceb6940-445e-4dc4-93b1-3fd9aa51f3fe.json diff --git a/docs/outstanding-issues-inbox/e4723e4a-1543-4884-bce4-d3c77705c25e.json b/docs/outstanding-issues-inbox/applied/e4723e4a-1543-4884-bce4-d3c77705c25e.json similarity index 100% rename from docs/outstanding-issues-inbox/e4723e4a-1543-4884-bce4-d3c77705c25e.json rename to docs/outstanding-issues-inbox/applied/e4723e4a-1543-4884-bce4-d3c77705c25e.json diff --git a/docs/outstanding-issues-inbox/eb0ceb9c-0af5-4ba8-9a66-80d30eb6c174.json b/docs/outstanding-issues-inbox/applied/eb0ceb9c-0af5-4ba8-9a66-80d30eb6c174.json similarity index 100% rename from docs/outstanding-issues-inbox/eb0ceb9c-0af5-4ba8-9a66-80d30eb6c174.json rename to docs/outstanding-issues-inbox/applied/eb0ceb9c-0af5-4ba8-9a66-80d30eb6c174.json diff --git a/docs/outstanding-issues-inbox/ef24bd2e-9cdc-4e4b-8032-12cc7d71dd25.json b/docs/outstanding-issues-inbox/applied/ef24bd2e-9cdc-4e4b-8032-12cc7d71dd25.json similarity index 100% rename from docs/outstanding-issues-inbox/ef24bd2e-9cdc-4e4b-8032-12cc7d71dd25.json rename to docs/outstanding-issues-inbox/applied/ef24bd2e-9cdc-4e4b-8032-12cc7d71dd25.json diff --git a/docs/outstanding-issues.md b/docs/outstanding-issues.md index 6defda7b1d..f88ee85315 100644 --- a/docs/outstanding-issues.md +++ b/docs/outstanding-issues.md @@ -96,9 +96,8 @@ removed after current-main verification; it is not missing recommended work. | #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 | | #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 | 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 | +| #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 | -| #339 | P2 | task | Favourites Continue and Recent are driven by hard-coded demo timestamps; real saved items have no last-opened data | Surfaced while shipping #164 (PR #1983), which made both surfaces prominent. src/components/clinical-dashboard/favourites-command-library-page.tsx derives 'most recently used' from lastUsedScore(item.lastUsed), and item.lastUsed comes from lastUsedByItemId — a hard-coded five-entry literal keyed to demo slugs ('Today 08:44', 'Yesterday 16:12', ...). Anything else, including every real registry favourite, falls back to the literal string 'Saved', which lastUsedScore buckets at 1000. pinnedItemIds is likewise a hard-coded two-item Set. The consequence after #164: for a signed-in user with real favourites, the Continue card and the Recent panel are effectively arbitrary — every item ties at the same score and the order is whatever the source array happened to be. Note that recentQueries in the shell is search-query history, not viewed-item history, so it cannot back this. Next: add a per-favourite last-opened timestamp. Cheapest is a client-side recents store keyed by favourite id written on open; the durable version is a column on the account favourites record so it survives a device change, which is a schema plus /api/account/favourites change and needs the usual migration review. Either way, pinning should stop being a hard-coded id set. Stop: do not fabricate a timestamp at render time from anything other than a recorded open event — an invented 'last used' on a clinical reference list is worse than an honest absence. | session 2026-08-15; PR #1983; favourites-command-library-page.tsx lastUsedByItemId/pinnedItemIds | 2026-08-15 | | #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 | @@ -125,26 +124,33 @@ removed after current-main verification; it is not missing recommended work. | #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 | | #XPY409 | P3 | task | Phone screenshots and DOM measurements taken before the phone chrome stack settles misreport every offset below it | The phone header stack (.phone-sticky-header-stack) is position:fixed and mounts collapsed, and the page reserve max-sm:pt-[var(--phone-overlay-chrome-h)] resolves to the settled height only after mount. A Playwright screenshot or evaluate() run at networkidle can therefore read main at y=72 with the mode-nav rail overlapping it, when the settled layout has main at y=121 with no overlap at all. Measured on /dictionary/browse 2026-08-18: unsettled h1 y=88 (appears hidden behind the rail), settled y=161, and the same page before and after a header redesign both settled to y=161 — i.e. the apparent overlap was pure measurement artefact. This cost a wrong diagnosis and a reverted 'fix' that padded the header to clear a rail that was never covering it. Fix is a documented settle wait (waitForTimeout ~1200ms, or better a wait on the stack's settled height) in the phone verification recipe in docs/testing.md, so the next person measuring phone chrome does not repeat it. Cheap, docs-only. | Dictionary browse header rebuild, PR #2143, 2026-08-18 | 2026-08-18 | -| #WJDQ0X | P3 | issue | Shared search chrome fails axe landmark rules on every mode: composer content sits outside any landmark and the universal header renders a second banner | An axe sweep of the six Dictionary routes at 1440px (2026-08-18, PR #2114) found two violations that are not Dictionary's: `region` (3 nodes — the composer label, the `#answer-composer-privacy-warning` span, and the privacy link, all outside any landmark) and `landmark-no-duplicate-banner` + `landmark-unique` on detail routes, where the global `#search` universal header renders a second banner landmark beside the app header. Both are moderate impact, both reproduce on routes that branch never touched (/dictionary/browse, /dictionary/compare), and both live in shared chrome — master-search-header / global-search-shell — so they affect all 13 modes, not one. Repo axe gates only fail on critical/serious, which is why this has never gone red. Next: wrap the composer privacy row in the composer's own landmark (or give it `role="group"` with a label) and decide which of the two headers keeps `banner`; then widen tests/ui-accessibility.spec.ts to assert the landmark rules, not just critical/serious. Deliberately out of scope for PR #2114 — a shared-chrome change under a Dictionary PR is the wrong blast radius. | Session 2026-08-18, PR #2114 axe sweep; @axe-core/playwright wcag2a+wcag2aa+wcag21a+wcag21aa+best-practice at 1440x900 | 2026-08-18 | | #G4M3DV | P3 | issue | Two documented workflow steps conflict: npm run ensure guarantees verify:pr-local fails its build stage with BUILD_REFUSED_DEV_SERVER | Reproduced 2026-08-18 on branch claude/therapy-mode-consistency-a466b0. AGENTS.md requires npm run ensure before any browser/UI work, and docs/testing.md requires npm run verify:pr-local at PR handoff. Doing both in one session always fails, because the production build refuses to run while the project dev server holds its port: verify:pr-local exits with 'failed: build (exit 76)' and the note 'production build was refused while the Clinical KB dev server is running (BUILD_REFUSED_DEV_SERVER). This is a failed gate, not a skip.' The refusal itself is correct and should stay - a build sharing a port with a dev server is not trustworthy - but nothing in either doc warns that the two required steps are ordered, so the gate reads as a real failure. Workaround used: stop the dev server, rm -rf .next, re-run npm run build standalone (exit 0), then check:bundle-budget against the fresh output. Options: have verify-pr-local.mjs name the remedy in its own failure note, or document the ordering in the testing speed playbook. Stop rule: do not make the build stage soft-skip when a dev server is up; the existing fail-closed behaviour is the correct half of this. | session 2026-08-18 | 2026-08-18 | -| #NEBJAM | P2 | rec | Therapy keeps a private eight-component UI kit whose shared equivalents it imports zero times, including the badge that carries review status | Measured 2026-08-18 on main at adf93a75, after PRs #2122 and #2150. src/components/therapy-compass/ui.tsx exports Tag, TagRow, StatusBadge, IconTile, LoadingState, EmptyState, Eyebrow and Meter. Shared equivalents exist and Therapy imports them zero times: ui/chip.tsx for Tag/TagRow (Chip is imported in exactly one therapy file), ui/status-mark.tsx for StatusBadge, ui/error-state.tsx for EmptyState, ui/progress.tsx for Meter, the eyebrowText primitive for Eyebrow, and category-icon-tile.tsx for IconTile. This is the same class of duplication card-recipes.ts was written to end for cards, one layer down, and it survived the #2122 convergence because that work targeted Button, card surfaces and page headers only. Highest-consequence piece: StatusBadge renders the Needs source review label, which since #2150 is the per-record half of the only protection standing between an unreviewed therapy record and a clinical decision - and it is a module-private implementation no shared contract governs. Two migration hazards to respect. (1) StatusBadge pairs its warning tone with a TriangleAlert glyph via reviewStatusMeta in data/select.ts; any swap must preserve that shape channel or the warning becomes colour-only and trips the status-colour boundary ratchet. (2) Meter's colour-only status was deliberately fixed in commit 8c791a1ad by naming the completeness band in text; a naive swap to shared Progress would regress it. Suggested order: Eyebrow and Tag/TagRow first (lowest risk, no status semantics), then EmptyState and IconTile, then Meter and StatusBadge last with the colour-only contract tests extended first. Stop rule: do not fold any of these into ui-primitives.tsx; COMPONENTS.md section 0.4 lists that module as over-budget and slated to split. Related: #ZF006G tracks the parallel SectionHeading duplication across four modes. | session 2026-08-18 | 2026-08-18 | +| #NEBJAM | P2 | rec | Therapy keeps a private eight-component UI kit whose shared equivalents it imports zero times, including the badge that carries review status | PARTIAL 2026-08-21, verified on origin/main a341832af. PR #2159 began the adoption: therapy-compass/ui.tsx now imports the shared Chip. Eight components remain local to that file - Tag, TagRow, StatusBadge, IconTile, LoadingState, EmptyState, Eyebrow and Meter - including StatusBadge, the badge carrying review status, which is the one that matters for the clinical sign-off work in the therapy review-status row. Next: adopt shared equivalents for the remaining eight, StatusBadge first. | session 2026-08-18 | 2026-08-18 | | #SBKXZ7 | P2 | task | Therapy sign-off has no tooling: nothing stops reviewStatus reviewed being set with an empty checklist, and there is no reviewer attribution | Re-queued 2026-08-18 after PR #2145 was closed in favour of #2150, which supersedes the exposure change but does not carry this follow-up. Therapy now ships in production with its review state disclosed rather than hidden, so sign-off is the remaining clinical work. Three gaps. (1) reviewStatus is a bare string in src/data/therapies-source.json; a record can be flipped to reviewed with all seven reviewChecklist booleans still false and nothing detects it. Needs a script that refuses the flip unless the checklist is complete, plus a contract test pinning reviewed implies full checklist. (2) No attribution: none of the 44 record fields carries reviewedBy or reviewedAt, so a sign-off cannot record who signed or when - the same defect #318 flags against the medication interaction lexicon. (3) No review workflow: 205 records x 7 checks is 1435 clinical judgements by hand; a CLI that walks records, shows the fields each check covers, and writes the decision with attribution would make it tractable. State at re-queue: 205 records, all reviewStatus needs_review, all seven checklist booleans false, reviewCompleteness 57-71 with zero records complete. The catalogue notice #2150 adds reads from THERAPY_CATALOGUE_SUMMARY.needsReviewCount and disappears when that reaches zero, so completing sign-off is what retires it. Stop rule: an assistant must never tick clinicalAccuracyReviewed, sourceChecked, evidenceAppraised, safetyCautionsChecked or patientExplanationChecked - those are qualified-clinician attestations. proofread and australianEnglishChecked are non-clinical and may be done with attribution. | session 2026-08-18 | 2026-08-18 | | #BSBE9B | P3 | task | Docling lab fixtures.v2 table-hardness corpus: add unruled, merged-cell, and rotated-header tables so the Gate B table-heavy improvement leg has measurable headroom | The v1 corpus's table strata are cleanly ruled grids on which the legacy extractor already scores cell F1 1.0 (S6 smoke run and the S6b Gate B run), so the pre-agreed table-heavy improvement target was set to 0 pp (parity at ceiling) by owner decision on 2026-08-18. Before any table-heavy delta is treated as decisive for a Docling promotion beyond B4 shadow design, add a docling-lab-fixtures.v2 stratum set where the legacy find_tables path is expected to degrade: unruled tables, merged cells, rotated headers. Fixture-hardness change only — eval/docling/ manifest + generator, no worker or extractor edit. See eval/docling/README.md 'Known limitation (v1 corpus)' and docs/rag-improvement/gate-b-decision-record-2026-08-18.md. | packet S6b (Gate B run), owner threshold decision 2026-08-18 | 2026-08-18 | | #5DYBQQ | P2 | issue | tests/ui-forms-section-nav.spec.ts 'expands information previews into one continuous answer' failed on PR #2149 and was never reproduced — CI's path-scoped UI jobs can hide a forms regression on main | On PR #2149 (a DSM-only, two-file change) Production UI shard 3 failed 166 passed / 1 failed on tests/ui-forms-section-nav.spec.ts:53 'expands information previews into one continuous answer'. The assertion is 'await expect(trigger.getByText(preview)).toHaveCount(0)' at line 65: after clicking the 'Does not authorise' trigger on the form detail route, the preview text 'Psychiatric treatment or detention beyond the linked authority.' must leave the trigger and appear in the panel. It stayed in the trigger. NOT a timing race: the locator polled 24 times over the full 10s timeout and resolved to 1 element every time, so it was a stable wrong state, not a slow transition. NOT attributable to #2149: that PR changed exactly src/components/dsm/dsm-diagnosis-page.tsx and one ledger record, zero forms files; the behaviour lives in src/components/forms/form-detail-page.tsx which shares nothing with the DSM page. NOT a known flake: the identity is absent from tests/flake-ledger.json. NOT explained by recent forms history: the only recent main commit touching forms is 495e097 (#2139), which edited forms-home-page.tsx only (caveat-footer removal), a different component from the form detail page under test. Reproduction was never obtained: the job was re-run once and that re-run was cancelled, and the following full cycle was cancelled too, both by the merge-main sync loop described in the sibling record. #2149 then merged with the question open. The reason this can hide: CI UI jobs are path-scoped, so a docs-only push to main SKIPS Production UI entirely — verified in main run 32183858120 where 'Production UI', 'Production UI critical', 'Build' and 'Lighthouse budget' all report conclusion 'skipped'. The repo's own CI-triage bot nevertheless cited that run as 'Compared with main CI run #12334 (success)', which is an aggregate-level comparison that never exercised this test and must not be read as a green baseline. Given main's docs-heavy traffic, a genuine forms regression could sit on main unexercised. Next: run the single spec against current main to settle it — 'npx playwright test tests/ui-forms-section-nav.spec.ts --project=chromium' after 'npm run ensure' — then either fix form-detail-page.tsx so the preview moves out of the trigger on expand, or, if it passes repeatedly, add the identity to tests/flake-ledger.json under the documented three-reproductions-on-one-SHA rule. Stop rule: do not quarantine on a single observation, and do not weaken the assertion to green it. Note this could not be reproduced locally in the Claude web container because Playwright pins chromium revision 1234 while the image ships 1194 (see #255); forcing a mismatched browser path is disallowed. | PR #2149 run 32185492075 job 95868823944 (Production UI (3)); main comparison run 32183858120; session 2026-08-18 | 2026-08-18 | -| #D8JBCV | P2 | issue | /tools on a phone is the only mode home with no visible patient-identifiable-information warning | Tools is the sole route setting mobileHomeComposerPlacement: 'footer' (src/lib/search-shell-props.ts). showsComposerPrivacyNotice in master-search-header.tsx:1813 is 'usesPhoneSearchLayout ? isDesktopHomeComposer : true', so the phone footer dock suppresses both the 'Do not enter patient-identifiable information.' line and the Privacy and data processing link. The composer placement matches the documented exception in docs/search-chrome-behaviour.md row 2, but the docs do not record that the exception costs the governance copy. Needs an owner decision for a clinical product. Found during the PR #2160 cross-mode audit. | PR #2160 cross-mode home audit | 2026-08-18 | | #97VQK5 | P3 | rec | Mode home copy drift: three placeholder-punctuation conventions, inconsistent heading levels, and a stale docs/site-map.md mode index | UPDATE 2026-08-21 (repo read on main at 1cc0d2987): the documentation half is DONE. CLAUDE.md now reads 15 app modes, and the mode index in docs/site-map.md now carries rows for Calculators, Therapy, Factsheets and Dictionary, so the four missing modes and the stale count are both corrected. REMAINING SCOPE, and the only reason this row stays open: the placeholder-punctuation split (ASCII three dots vs Unicode ellipsis vs no terminator on differentials) and the heading-level inconsistency (h2 on answer/documents/prescribing, h1 elsewhere, so the Documents home has no h1). Both are decisions, and the heading change moves visual baselines. | PR #2160 cross-mode home audit | 2026-08-18 | -| #YJ3R7Y | P3 | issue | Tools and Favourites bespoke home composer slots skip the SSR height reservation chrome invariant 15 requires | ModeHomeTemplate renders its composer slot with data-composer-reserve='pending' plus min-h tokens (mode-home-template.tsx:316-320) so the hero does not shift when the portal attaches. The two bespoke homes hand-roll the slot without either: favourites-command-library-page.tsx:1426 and tools-search-results-page.tsx:353, plus favourites-hub.tsx:187. Those three get no SSR height reservation, which is the CLS that invariant 15 exists to prevent. Found during the PR #2160 cross-mode audit. | PR #2160 cross-mode home audit | 2026-08-18 | -| #TWKWE4 | P2 | issue | Mode homes: two competing title systems disagree for 8 of 13 modes (sharedHomePresentation vs hard-coded standalone titles) | src/lib/ui-copy.ts sharedHomePresentation drives the shared home /, while each standalone *-home-page.tsx hard-codes its own title. Its doc comment claims each entry mirrors the standalone home 'so a clinician sees the same words whichever door they came through' — untrue today: Documents/Clinical Documents, Services/Clinical Services, Forms/Clinical Forms, Differentials/Differential Diagnosis, Specifiers/Diagnostic Specifiers, Formulation/Clinical Formulation, Medication/Medication Guidance, Therapy/Therapy Compass. Either derive one list from the other or correct the comment. Found during the PR #2160 cross-mode audit. | PR #2160 cross-mode home audit | 2026-08-18 | -| #V0EDR4 | P3 | issue | /favourites and /?mode=favourites render visibly different homes for the same mode | The standalone hero lockup was deliberately deleted from favourites-command-library-page.tsx (ledger #164), but the dashboard variant FavouritesHub (src/components/clinical-dashboard/favourites-hub.tsx:179) still renders ModeHomeHero with 'Favourites / Saved notes, sources, and sets.' So the same mode looks different depending on the door. Decide which treatment is canonical and apply it to both. Found during the PR #2160 cross-mode audit. | PR #2160 cross-mode home audit | 2026-08-18 | -| #90Y0FD | P3 | rec | Mode home suggestion data is duplicated across three unrelated sources | searchCommandSurfaceByMode examples/suggestions (src/lib/search-command-surface.ts) drive the Try this ticket, rotating hint and prompt chips; per-page pills arrays (e.g. therapy-compass/screens/home-screen.tsx:14, services-home-page.tsx) drive the mode-home pill row; src/lib/tools-catalog.ts:348 is a third. Only the first drives the ticket, so after PR #2160 the Therapy home advertises two different suggestion sets — its five pills and the three ticket examples. Reconcile to one source per mode. Found during the PR #2160 cross-mode audit. | PR #2160 cross-mode home audit | 2026-08-18 | -| #JVYQEM | P2 | issue | Mode-home composer reserve does not account for the suggestion ticket, so every ticket-bearing home carries a ~0.035 CLS shift | ModeHomeTemplate reserves the composer slot with --spacing-mode-home-composer-phone (6.625rem) / --spacing-mode-home-composer-wide (5.5rem), but the portal content is UniversalSearchCommandSurface, which renders SmartRotatingHint (phone ticket) and the sm+ rotating line/prompt-chip row ABOVE the composer inside that same slot. The reserve therefore under-accounts, and the portal attaching post-hydration shifts content — the defect class chrome invariant 15 exists to prevent. Evidence from the PR #2160 Lighthouse run: mobile-dsm baseline CLS 0.0353, mobile-forms 0.088, mobile-root 0.016, while mobile-therapy-compass was 0.000 purely because Therapy had no command-surface entry and so rendered no ticket. Restoring the ticket moved Therapy to 0.032, matching its peers. Fix: raise the reserve tokens to include the hint row height (or reserve it separately), which should take every mode home toward ~0. Touches all 15 mode homes, so it needs verify:phone-chrome plus Lighthouse and visual baseline re-adoption — deliberately not bundled into PR #2160. | PR #2160 Lighthouse budget failure | 2026-08-18 | +| #V0EDR4 | P3 | issue | /favourites and /?mode=favourites render visibly different homes for the same mode | NARROWED 2026-08-21, verified on origin/main a341832af. The copy divergence is gone: favourites-hub.tsx:182 now takes title and subtitle from sharedHomePresentation.favourites and its glyph from appModeIcons.favourites. The structural divergence stands: the dashboard hub still renders a ModeHomeHero lockup while the standalone favourites-command-library-page.tsx renders none, its hero having been deliberately deleted under #164, so the same mode still looks different depending on the door. What is left is the owner decision about which treatment is canonical, then applying it to both. | PR #2160 cross-mode home audit | 2026-08-18 | +| #JVYQEM | P2 | issue | Mode-home composer reserve does not account for the suggestion ticket, so every ticket-bearing home carries a ~0.035 CLS shift | PARTIALLY STALE as of 2026-08-21 — verify before acting. The phone remedy this row proposes has already landed: --spacing-mode-home-composer-phone in src/app/globals.css now reads 10.125rem, not the 6.625rem recorded here, and the surrounding comment states the raise was made to cover the hint row. What remains open is the WIDE case, which that same comment calls out explicitly: --spacing-mode-home-composer-wide is still 5.5rem (88px) against a settled 160px at 1280 and 199px at 800, and it is deliberately NOT raised to match, because the sm+ surface swaps the phone ticket for a prompt-chip row that rewraps with viewport width, so no single static value is correct at every width. That needs a different mechanism (measure-and-publish, or a container-query reserve), not a bigger constant. Also: do NOT treat this row as the cause of the mobile-/ CLS 0.223 breach seen on PR #2199 — that value is bistable, an order of magnitude larger than the ~0.035 recorded here, and did not reproduce under either local harness; it has its own row. Next: confirm the phone case is closed by measuring a ticket-bearing mode home, then scope the wide-reserve mechanism separately. | PR #2160 Lighthouse budget failure | 2026-08-18 | | #HVTYAT | P2 | issue | OpenAI zero-data-retention status contradicts itself: cross-border doc says no, ledger #053 says verified | docs/openai-cross-border-basis.md §8 (dated 2026-07-14) records ZDR 'no', DPA executed 'no', Australia data residency 'not enabled'. Completed ledger row #053 (2026-08-18) states the cross-border package was executed and 'verified OpenAI data controls with input/output data sharing disabled and API zero data retention'. One of the two is wrong. This blocks the /privacy page from telling clinicians what actually happens to question text at the provider: the page currently states only code-verifiable request controls (store:false, no raw owner identifier, requested prompt-cache lifetime) and deliberately makes no ZDR or no-training claim, which is correct under either reading but weaker than it could be. Next step: an operator confirms the live OpenAI project's data controls, then either §8's status table is filled in and the page's External provider processing section is strengthened, or #053 is corrected. | src/lib/privacy-page-content.tsx, docs/openai-cross-border-basis.md §8, docs/privacy-impact-assessment.md PIA-1/PIA-6 | 2026-08-19 | -| #1VFSYF | P3 | task | Close the four operator unknowns the B4 shadow-extraction runbook could not answer from the repository: Railway variable-change behaviour, the shadow-record read path, the timeout rollback threshold, and the worker memory limit/peak | docs/worker-deploy-runbook.md section 3 (added 2026-08-20) is the Gate F runbook for packet B4 docling shadow extraction. Three values in it could not be verified from the repository and are flagged as such in the text. (1) ROLLBACK TIME TO EFFECT: the one-step rollback is WORKER_DOCUMENT_EXTRACTOR_MODE=legacy on the Railway worker service, but whether Railway restarts or fully rebuilds the service on a variable change is not recorded anywhere in this repo, so the runbook can only bound the worker-side cost (SIGTERM batch drain plus at most one 120 s docling window). One dashboard observation settles it; record the answer in section 3.7. (2) NO READ PATH: no npm script reads, exports, or clears documents.metadata.shadow_extraction, so the first-24-hours watch in section 3.6 is a hand-run SQL query in the Supabase editor. A small read-only aggregation script (outcome counts, wall_ms and peak_rss_bytes percentiles, delta ratios) would make the watch repeatable and reviewable instead of ad hoc. (3) TIMEOUT ROLLBACK THRESHOLD: section 3.7 trigger 5 proposes rolling back when more than 10 percent of cohort runs time out. That number is a proposed operating rule, not a measured value, and needs owner ratification or replacement once real-corpus wall_ms data exists. Also unverified: the memory headroom precondition in section 3.2 asks the operator to confirm the Railway worker memory limit and observed peak, neither of which is in-repo. Stop: no code, worker, or provider change is implied by this row; it is documentation completion plus one small offline read-only script. | docs/worker-deploy-runbook.md section 3 (Gate F runbook PR, 2026-08-21); PR #2170 squash 5437c309f | 2026-08-20 | +| #1VFSYF | P3 | task | Close the four operator unknowns the B4 shadow-extraction runbook could not answer from the repository: Railway variable-change behaviour, the shadow-record read path, the timeout rollback threshold, and the worker memory limit/peak | TWO OF FOUR ANSWERED 2026-08-21 and folded into docs/worker-deploy-runbook.md section 3. (1) RAILWAY VARIABLE-CHANGE BEHAVIOUR - ANSWERED, and it was a latent safety trap: Railway's docs state that containers read environment variables only at startup, so a variable change never restarts a running container by itself and the new value exists only inside the new deployment. The worker parses WORKER_DOCUMENT_EXTRACTOR_MODE once at process start, so setting the variable is NOT by itself the rollback. Sections 3.5 and 3.7 now state the rollback as two steps (set the variable, then deploy) and warn that stopping after the first leaves docling running. (2) MEMORY LIMIT AND PEAK - ANSWERED by a read-only Railway metrics query on the production worker service over a 7-day window, 10081 samples: memory limit 24 GB, peak 0.566 GB, average 0.139 GB, so roughly 23.4 GB of headroom against the ~1.5 GiB docling needs. The precondition is met with about a fifteenfold margin; section 3.2 now records the numbers as a baseline and requires a busy-window memory-headroom re-check immediately before every shadow enablement and again after any worker image, workload, WORKER_CONCURRENCY, service-plan, or resource-limit change. It also flags that the service reports a 24 vCPU limit while Gate B measured 9-19 s/doc on 2 CPUs, and that the section 3.4 cost model should NOT be assumed to scale down, because docling runs eager and single-process. STILL OPEN, both needing an owner decision rather than investigation: (3) the proposed rollback trigger of more than 10 percent of cohort runs timing out is an unratified operating rule, not a measurement, and nothing in the repository fixes the number; it needs ratifying or replacing, ideally once real wall_ms values exist. (4) there is still no script that reads or aggregates documents.metadata.shadow_extraction, so the first-24-hours watch remains the hand-run SQL query in section 3.6. Recommendation recorded against (4): build the reader when shadow mode is first enabled rather than now, because shadow mode has never run so the table holds zero rows and the tooling cannot be exercised end to end against real data. | docs/worker-deploy-runbook.md sections 3.2, 3.5 and 3.7; read-only Railway metrics on service worker (project Database 5deaad0b) 2026-08-21 | 2026-08-20 | | #M54C4N | P2 | issue | live-drift's Align migration history step fails on PGRST106 (supabase_migrations not exposed to PostgREST), so the job stays red and pinned issue #1963 cannot self-close even with zero drift | Exposed 2026-08-19 by Phase 6.2: live-drift run 32251326536 reported No unexpected schema drift (all 20 history rows allowed) but concluded failure because the next step, Align migration history for Supabase Preview (npm run check:migration-history, scripts/check-migration-history-alignment.ts, added in Phase 0 PR #1939), ran for the first time ever -- it was skipped on every earlier run because the compare step failed first, and the last green run (29700973962, 2026-07-19) predates it. It reads supabase_migrations.schema_migrations through PostgREST with Accept-Profile, which this project has never exposed (406 PGRST106: only public, graphql_public). The routing job therefore keeps #1963 open on job result even with an empty findings block. OPTIONS (owner decision): (a) expose supabase_migrations read-only to the service role in the dashboard; (b) rewrite the read onto the management API / supabase migration list using the SUPABASE_ACCESS_TOKEN secret (#183); (c) add a service-role RPC listing versions (new migration, own window). Until fixed, weekly live-drift stays red on that step alone; drift itself is green. Evidence: forensics section 6.2 completion step 6. | Phase 6.2 session 2026-08-19; live-drift run 32251326536 | 2026-08-19 | | #1YPV51 | P1 | task | Reopen #318: the medication interaction lexicon clinical review and sign-off has not actually happened; the lexicon remains clinically unreviewed | #318 was closed 2026-08-18 with outcome 'Completed Clinical Lead medication interaction lexicon review and sign-off'. The repo owner confirmed in chat on 2026-08-21 that this review and sign-off was not performed by the Clinical Lead. The medication interaction lexicon therefore remains clinically unreviewed and its sign-off block is empty, exactly as the original #318 described before its (inaccurate) closure. This must be reopened and tracked through to a genuine Clinical Lead review and sign-off; do not close again without explicit owner confirmation that the review was actually carried out. Related: #SBKXZ7 flags the same missing-attribution gap (no reviewedBy/reviewedAt) for therapy sign-off. | session 2026-08-21 ledger reconciliation and docs-truth pass; owner confirmed in chat the 2026-08-18 closure was inaccurate | 2026-08-20 | | #XCAX01 | P2 | issue | A worktree sweep deleted an in-use worktree mid-session on 2026-08-21 and destroyed its uncommitted work; nothing checks whether a worktree is live before removal | Reproduced by loss, not by test. On 2026-08-21 an agent session was working in .claude/worktrees/task-ledger-review-bee095 with 25 staged-but-uncommitted files. Mid-task the directory was emptied, its .git/worktrees admin directory (and therefore its index) was deleted, and the worktree was deregistered, while the session was still running. The staged blobs became unreachable and the work was lost; only the branch ref survived, still at its unchanged base 1cc0d298774e. Every other worktree on disk carried a modification timestamp inside the same twenty-minute span, so this was a sweep across the whole directory rather than a one-off. TWO CONSEQUENCES WORTH SEPARATING. (1) Data loss: removal considered neither uncommitted/untracked content nor whether a process was live in the directory. (2) Silent corruption of the surviving session: after the removal, git commands issued from the deleted path resolved upward to the main checkout D:/Repos/Database, which was on another agent's feature branch with uncommitted modifications - so an unlucky commit would have landed in a different session's branch and working tree. NEXT: before any automated worktree removal, require all three of (a) the branch is merged or its tip is pushed, (b) git status --porcelain --untracked-files=all is empty, and (c) no live process holds the directory; and skip rather than force when any check cannot be evaluated. Prefer a report-only default with an explicit apply flag, matching how sync:pr-branches already separates dry-run from apply. RELATED: #6GW95D records the disk pressure that motivates sweeping, and now carries the same safety caveat. | Session 2026-08-21; worktree task-ledger-review-bee095 removed while in use | 2026-08-20 | | #S19JRT | P2 | task | Add the DB-side structural constraint backing the source_metadata pin, or document why the data-backed pin is sufficient | Re-files #343, closed 2026-08-18 with outcome 'Made retrieval row contract source_metadata schema structural and nullish' -- that outcome is false. Verified 2026-08-21: PR #2107 loosened the source_metadata pin in src/lib/rag/rag-row-contracts.ts to .nullish(); PR #2121 restored the strict .nullable()-required-key pin (git log: ce702ba68 then 4575cf57a). The comment at rag-row-contracts.ts:44-49 explicitly reads 'PR #2107 loosened it to .nullish() and this PR restores it. See docs/outstanding-issues.md #343 for the constraint-backing follow-up.' The DB-side structural constraint (check (jsonb_typeof(metadata) = 'object')) was never added: grep of supabase/schema.sql and supabase/migrations/ finds only 'metadata jsonb not null default {}::jsonb' with no jsonb_typeof check anywhere. The cancelled duplicate #ND10QT record itself states '#343, which is still open', confirming the two closures landed inconsistently. Actionable follow-up: add the check (jsonb_typeof(metadata) = 'object') constraint on documents.metadata with a fail-fast validation guard migration per AGENTS.md's guard-migration contract, or record in this row why the Zod-level pin in rag-row-contracts.ts is sufficient without a DB constraint. | session 2026-08-21 ledger reconciliation and docs-truth pass | 2026-08-20 | | #3514B7 | P2 | issue | Live production carries migration 20260820120000_migration_history_versions_rpc, which exists nowhere in the repository | Found 2026-08-21 by a read-only Supabase MCP list_migrations against production ref sjrfecxgysukkwxsowpy (Clinical KB Database), compared against main at 1cc0d2987. Production's newest recorded version is 20260820120000 migration_history_versions_rpc. supabase/migrations/ holds 210 files and its newest is 20260819110500_validate_history_function_bodies.sql; there is no 20260820 file, and the string migration_history_versions has zero occurrences anywhere under supabase/, scripts/ or src/. The live database is therefore one migration ahead of the repository, and that migration's SQL is not under version control here. LIKELY RELATED, and the reason this matters rather than being cosmetic: pending request cc60253d (2026-08-19) records that live-drift's Align migration history step fails on PGRST106 because supabase_migrations is not exposed to PostgREST. An RPC named migration_history_versions is exactly the shape of a fix for that, applied live on 2026-08-20 with the repo side still unmerged. NOT VERIFIED from this session: whether an open PR carries the file, which needs GitHub access. NEXT: identify the PR or session that applied it; if none exists, capture the live function definition and land it as a forward migration so schema.sql, the drift manifest and the migration chain agree. STOP: do not re-apply, repair, or mark-apply anything on production to resolve this - it is a repo-side reconciliation, and any live mutation needs its own approved window under the guard-migration contract. | Read-only Supabase MCP list_migrations on sjrfecxgysukkwxsowpy, 2026-08-21; compared to supabase/migrations on main 1cc0d2987; relates to pending request cc60253d | 2026-08-20 | +| #3SG2H9 | P3 | task | Ledger inbox update path is never driven with a modern Crockford display id, and ledger-inbox.mjs --self-test uses only legacy #001 | Residual of #DREDWA, surfaced by a Codex review finding on PR #2217 and then measured rather than accepted. WHAT IS ALREADY COVERED, so this is a narrow gap and not a reopening: tests/repo-hygiene.test.ts 'fingerprints and closes ULID-display-id rows minted by reconcile' drives applyRequest with action done against the ULID display id #6BG9X2, asserts the row is archived, and asserts the stale-fingerprint path throws; scripts/outstanding-issues.mjs self-tests drive addIssue, resolveIssue and updateIssue against the all-digit Crockford id #041061 ('done archives all-digit Crockford #041061'); and scripts/check-outstanding-issues.mjs self-tests resolve issueRowFingerprint for #041061 with an explicit failure message. The original bug and its stated failure mode are therefore guarded. WHAT IS STILL UNCOVERED: (1) the inbox update action is only ever applied against legacy #001 - the ULID test covers done alone; (2) scripts/ledger-inbox.mjs --self-test builds its done, update, cancel and reconcile fixtures entirely from #001, so the self-test that ships with the writer would not catch an id-scheme regression on its own. NEXT: add a ULID-display-id update case beside the existing done case in tests/repo-hygiene.test.ts, and give ledger-inbox.mjs --self-test one modern-id row (ideally the all-digit #041061 shape) driven through done, update and reconcile. Small and offline-testable; npm run test:focused -- --files tests/repo-hygiene.test.ts plus npm run check:outstanding-issues covers it. | Codex review comment 3829158494 on PR #2217, verified against tests/repo-hygiene.test.ts, scripts/outstanding-issues.mjs, scripts/check-outstanding-issues.mjs and scripts/ledger-inbox.mjs on 2026-08-21 | 2026-08-21 | +| #50QRCF | P2 | issue | Lighthouse budget mobile-root CLS is intermittent: 0.223 vs 0.016 baseline on one run, ~0.000 on the next, same code | MEASURED ON CI, NOT INFERRED. PR #2204 ran the same Lighthouse budget job on two consecutive heads whose only difference was deleting one JSON file under docs/outstanding-issues-inbox/ -- no source, asset, route or style change, nothing that can affect layout. Head c8b7bcdd PASSED. Head 09ff450c FAILED with exactly one metric out of tolerance: 'mobile-root cls +0.207 vs baseline (max +0.02)', measuring 0.223 against a 0.016 baseline (job 96780922258, run 32485431566). Every other cell was comfortably inside tolerance on the failing run: mobile-root LCP 2261 vs 2253, TBT 312 vs 296; mobile-documents-search LCP 2274 vs 2272, TBT 394 vs 348; desktop-documents-search LCP 804 vs 866; desktop-root LCP 815 vs 822. TWO SEPARATE PROBLEMS. (1) GATE RELIABILITY: a required check in pr-required flips pass/fail on a diff that cannot influence it, so it can block any PR at random. Note the grader already re-confirms an out-of-budget cell twice and takes the majority, so this survived that mechanism -- the instability is wider than a single spike. (2) PROBABLE REAL DEFECT ON THE MOBILE HOME ROUTE: 0.223 is not a marginal overshoot of a 0.02 tolerance, it is a large layout shift that sometimes occurs during load on '/' at mobile viewport and sometimes does not. Likely candidates are a webfont swap, an image or media element without reserved dimensions, or late-hydrating chrome (the phone composer/header reserve is a known-sensitive area per docs/search-chrome-behaviour.md). A user on a phone would feel this when it happens. Worth reproducing directly rather than only through the budget gate. DO NOT respond by widening the CLS tolerance or refreshing the baseline to absorb 0.223 -- that would encode an intermittent user-visible shift as acceptable. Diagnose which element shifts first. The Lighthouse artifact for the failing run is retained (artifact 9447841108) and contains the per-run reports, which identify the shifting elements. RELATED CAUTION FOR TRIAGE: main's CI runs do not exercise this job (path-scoped, perf scope only), so a green main run is not evidence the gate passes there -- the ci-triage bot correctly classified it 'not baselined'. | job 96780922258 (run 32485431566) vs the passing run on head c8b7bcdd; lighthouse-budget.json; scripts/check-lighthouse-budget.mjs | 2026-08-21 | +| #45V4Y7 | P3 | task | Dead exports on protected surfaces: answerQuestion (rag.ts), embedText (openai.ts), clinicalRankScore (clinical-search.ts) | The 2026-08-20 repo-cleanup sweep removed 60+ verified-dead exported symbols but deliberately left three untouched because they sit on RAG-protected surfaces that AGENTS.md requires flagging before any edit, deletion included. All three are exported, imported by nothing, and referenced nowhere else in the tree: src/lib/rag/rag.ts answerQuestion (a thin wrapper superseded by answerQuestionWithScope, which is what /api/answer actually calls), src/lib/openai.ts embedText, and src/lib/clinical-search.ts clinicalRankScore. Removing them cannot change retrieval behaviour because nothing calls them, but the removal still travels through docs/rag-behaviour and the RAG impact declaration on the PR. Next step: confirm with the owner, then delete in a single RAG-scoped PR carrying 'RAG impact: no retrieval behaviour change -- dead exports with zero callers'. | src/lib/rag/rag.ts, src/lib/openai.ts, src/lib/clinical-search.ts | 2026-08-20 | +| #72G3XZ | P3 | task | Watch runner usage now that every main push gets its own CI concurrency group | PR #2209 (merged af2075a) changed ci.yml so base-branch pushes key concurrency on github.run_id. The defect it fixed was real: cancel-in-progress: false only prevents supersession, while GitHub separately keeps at most ONE pending run per concurrency group, so during a merge burst each newly queued main run cancelled the one already waiting. Observed 2026-08-20: a1c2ced, d745d15, 97f6142 and 1cc0d29 all cancelled while a ~70-minute release-browser-matrix held CI-refs/heads/main, and a mobile-/ CLS regression rode through that gap. The accepted cost is a real one and nobody has measured it yet: a burst of N merges now produces N concurrent runs instead of one plus a survivor, each carrying release-browser-matrix. The in-file comment already accepts this ('concurrent main runs, one per merge, each already scoped by the changes job'), but that was written as a prediction, not an observation. Next: after a few days of normal traffic, compare Actions minutes on main-branch pushes against the week before af2075a, and confirm no queueing/limit pressure appeared. If the cost is worse than the defect, the alternative is a bounded group (for example keyed on run_id only while a long job is in the workflow) rather than reverting to the shared group, which would restore the eviction hole. Pinned by the 'never cancels an in-flight run for a base-branch push' case in tests/ci-cache-safety.test.ts, which now also asserts the per-run key. | PR #2209, merged af2075a; ci.yml concurrency block | 2026-08-21 | +| #V15EAS | P3 | issue | therapies-home and therapies-index generated assets are byte-identical, so the home projection saves nothing | public/therapy-compass-data/therapies-home.211dab554c4ec62d.json and therapies-index.211dab554c4ec62d.json have identical content hashes. The home asset exists so the Therapy landing page can paint the catalogue count and default artifact destinations without downloading and parsing a full record projection first, but it is currently a byte-for-byte copy of the index, so the landing page pays the full 136 KB it was meant to avoid. This is a projection bug in scripts/build-therapies-index.mjs rather than stray duplication. Next step: either narrow the home projection to the fields THERAPY_CATALOGUE_SUMMARY actually needs, or drop the asset and point the home path at the index. Note the immutable Cache-Control in next.config.ts is keyed on the content hash, so a narrowed projection lands under a new URL and needs the one-generation retention already implemented in generated-assets.ts. Found by the 2026-08-20 repo-cleanup audit. | scripts/build-therapies-index.mjs, src/components/therapy-compass/data/generated-assets.ts, public/therapy-compass-data/ | 2026-08-20 | +| #TYZK23 | P2 | issue | mobile-/ Lighthouse CLS is bistable at 0.016 or 0.223 and reproduces only in CI, so the budget gate randomly reddens UI PRs and each looks like its own regression | BISTABLE, NOT A REGRESSION. Five CI measurements across PR #2199 heads: 175c641 FAIL (2/3 samples, cls 0.223), 74f39f0 FAIL (3/3, 0.223), 8506db3 PASS (no breach detected at all — 4 artifact files, no confirmation samples collected), c56d12d FAIL (2/3, 0.223), 4eabf0b FAIL. The decisive pair is 8506db3 -> c56d12d: the ONLY delta between those heads is 26 ledger JSON files under docs/outstanding-issues-inbox/, zero source code. The value recurring to three decimals is one discrete layout shift firing or not, rather than accumulating noise. NOT PR #2199's: it changes only DocumentViewer.tsx and document-viewer/document-overview-landing.tsx, and DocumentViewer is imported solely by src/app/(search-app)/documents/[id]/{page,loading}.tsx, so neither module is in the client bundle for /. TWO NEGATIVE LOCAL RESULTS, 2026-08-21, both in the Claude web container on Chromium 141: (1) scripts/measure-cls-attribution.mjs against / reported 'CLS=0.000 shifts=0' with the reserve timeline showing a single unset write at 436ms; (2) a full local npm run verify:lighthouse -- --keep, which applies Lighthouse's own mobile emulation and throttling, reported mobile-root cls 0.000 against the 0.016 baseline (ungraded: 'evidence incomplete — browser drift', HeadlessChrome/141 vs the baseline's /151). So the shift does not fire under either local harness and depends on something CI-specific — runner CPU contention, or Chromium 151 behaviour. NOT #JVYQEM, or at least not confidently: that row's phone remedy has already landed (--spacing-mode-home-composer-phone is 10.125rem, not the 6.625rem it records) and its scale (~0.035) is an order of magnitude below 0.223. NEXT STEP THAT DOES NOT NEED A REPRO: every failing run uploads a lighthouse-budget- artifact containing the full Lighthouse report; download lighthouse-budget-32463920997 (or any failing run) and read the mobile-root cumulative-layout-shift audit's debugdata, which names the shifting node directly. Only if that is empty is a CI-side attribution dispatch needed. Stop rules: do not raise the cls tolerance in lighthouse-budget.json to clear it; do not re-adopt the Lighthouse baseline while the metric is bistable, because the refresh would bake in whichever state that run happened to land on; and do not attribute it to a component without evidence from a run where it actually fired. | CI runs 32412788947, 32415624534, 32459391430, 32460303619, 32463920997 on PR #2199; local attribution + Lighthouse runs 2026-08-21 | 2026-08-21 | +| #8A00R7 | P2 | issue | AGENTS.md loads ~6k tokens/turn of Codex/Cursor-only sections, but three gates pin them in place | AGENTS.md is 1213 lines (~19.6k tokens) loaded every turn, plus CLAUDE.md (~2.4k). 372 of those lines (30 percent, ~6k tokens/turn) are Codex-only or Cursor-only and can never fire in a Claude Code session: Dependency shortcut, Codex review throttling, Codex Desktop worktree setup, Codex productivity defaults, Codex GitHub review behavior, Codex Cloud environment, Cursor Cloud instructions. The obvious fix (move them to docs/ and leave pointers) is BLOCKED: scripts/check-codex-cloud-setup.mjs line 1122 requires exactly one '## Codex Cloud environment' heading in AGENTS.md; scripts/check-codex-autofix-workflow.mjs requires the scoped resolve command, the 'one automatic repair pass per pull request lifetime' phrase and the disposition marker in AGENTS.md; tests/setup-codex-worktree.test.ts line 106 requires 'Never configure Windows Desktop worktrees' and the dry-run command in AGENTS.md. Any restructure must move the gate assertions to the new file paths in the same change. Measured 2026-08-21 on main a341832af. | Session applying the writing-for-agents skill to AGENTS.md, 2026-08-21 | 2026-08-20 | +| #2DQXD8 | P3 | issue | Two contract tests pin unreachable components: VerificationWorkspace and TherapyListItem | The 2026-08-20 cleanup sweep found VerificationWorkspace (with its only caller RenderModelSourceList) in src/components/clinical-dashboard/evidence-panels.tsx and TherapyListItem in src/components/therapy-compass/therapy-card.tsx are exported, imported by nothing, and rendered by no route. Removing them was reverted because two committed contract tests assert on the source text of those files: tests/rendered-text-formatting.test.ts requires the literal compactSourceSnippet(source.snippet ?? "", { dropTitle: source.title }) to appear in the dashboard surfaces, and that string exists only inside RenderModelSourceList; tests/therapy-review-regressions.test.ts requires therapy-card.tsx to surface reviewStatus, which only TherapyListItem does. Both guards are therefore currently satisfied by code no user can reach, so they are not protecting the live render path they name. Next step: identify the live source-card and therapy-record render paths, repoint both assertions at them, then delete the unreachable components. Do not simply delete the assertions -- they guard clinical output formatting and the per-record review badge. | tests/rendered-text-formatting.test.ts, tests/therapy-review-regressions.test.ts, src/components/clinical-dashboard/evidence-panels.tsx, src/components/therapy-compass/therapy-card.tsx | 2026-08-20 | +| #CHW9N3 | P3 | rec | mode-home loading contract enumerates its thirteen routes by hand, so the next standalone home can ship with no loading coverage | MODE_HOME_LOADING_ROUTES in tests/mode-home-loading-contract.test.ts is a hand-written thirteen-entry array. It currently matches standaloneModeHomePaths (src/lib/search-route-ownership.ts) exactly - the mismatch that let medications, calculators and dictionary ship without loading.tsx was ledger #6K9YGQ and is now fixed - but nothing keeps the two lists in step, so the next standalone mode home added will silently have no loading coverage and CI will not notice. Fix: derive the test's route list from standaloneModeHomePaths instead of hand-writing it. | session 2026-08-21, raised while closing #6K9YGQ | 2026-08-20 | +| #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 | ## Resolved / archive @@ -509,3 +515,9 @@ Move resolved rows here with the resolution date and a one-line outcome. Keep th | #90EVWZ | rec | check:drift clips table column diffs to 240 chars per side, so a wide-table column drift never names the column | Resolved 2026-08-21. Verified on main at 1cc0d2987: scripts/check-drift.ts now exports diffColumns, which builds name-keyed maps of the manifest and live column arrays and diffs per column rather than serialising and clipping each side to 240 characters. A late-alphabet column drift such as token_estimate on document_chunks can now be named. Verification: read of the diffColumns implementation in check-drift.ts. | 2026-08-20 | | #5JK9FM | rec | PR template carries no RAG impact: guidance although pr-policy hard-blocks RAG-surface PRs without the line | Resolved 2026-08-21. Verified on main at 1cc0d2987: .github/pull_request_template.md now contains 4 occurrences of 'RAG impact', so the exact-format contract enforced by scripts/pr-policy.mjs ragImpactDeclared is visible where the body is authored. Verification: grep -c 'RAG impact' on the template. | 2026-08-20 | | #HSSHRG | issue | The in-flight-CI guard closed as #145 does not cover merge-main syncs made outside sync:pr-branches — PR #2149 lost 8 of 9 CI cycles to self-inflicted cancellation | Resolved 2026-08-21. Verified on main at 1cc0d2987: scripts/guard-push.mjs now carries an explicit 'Guard 2: in-flight CI push guard (#HSSHRG)' block with inFlightCiVerdict() and findInFlightCiRuns(), and its header documents the cancel-in-progress waste this closes. Coverage therefore no longer depends on going through sync:pr-branches. Not verified from here: behaviour against a live PR with runs in flight, which needs GitHub access. Related row #TF6TPJ shares this root cause and should be re-checked against the same guard before it is closed separately. | 2026-08-20 | +| #WJDQ0X | issue | Shared search chrome fails axe landmark rules on every mode: composer content sits outside any landmark and the universal header renders a second banner | Resolved 2026-08-20: does not reproduce on current main (a341832af). Re-scanned the two routes this row names as reproducing, /dictionary/browse and /dictionary/compare, at 1440x900 with @axe-core/playwright 4.12 under tags wcag2a+wcag2aa+wcag21a+wcag21aa+best-practice: zero violations on both, and none of region, landmark-no-duplicate-banner, landmark-unique or landmark-one-main present. The scan is proven to have run rather than no-opped - axe reported 38 and 39 rule passes, the pages rendered 17820 and 2265 characters of text with the composer present. A first pass at a 3s settle did report transient landmark-one-main and page-has-heading-one on /dictionary/compare; both cleared at a 9s settle, which is the hydration double-render the ui-accessibility spec already documents. Caveats: dev server, not a production build, and only the two named routes were re-swept. If a production-build sweep of all six Dictionary routes reproduces it, raise a fresh row rather than reopening this one. | 2026-08-20 | +| #D8JBCV | issue | /tools on a phone is the only mode home with no visible patient-identifiable-information warning | Resolved 2026-08-20: verified on origin/main a341832af. showsComposerPrivacyNotice (master-search-header.tsx:1824) now reads isDesktopHomeComposer \|\| (mobileHomeComposerPlacement === 'footer' && Boolean(desktopHomeComposerSlotId)), so the Tools phone footer dock renders the patient-identifiable-information line and the privacy link instead of suppressing them. | 2026-08-20 | +| #TWKWE4 | issue | Mode homes: two competing title systems disagree for 8 of 13 modes (sharedHomePresentation vs hard-coded standalone titles) | Resolved 2026-08-20: verified on origin/main a341832af. Every standalone *-home-page.tsx now takes title and subtitle from sharedHomePresentation. (services:137, forms:127, dsm:19, plus dictionary, calculators, differentials, factsheets, formulation, specifiers and therapy-compass). One title system remains, and the ui-copy.ts doc comment about a clinician seeing the same words whichever door they came through is now true. | 2026-08-20 | +| #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 |