From 79b4d8df0c37a580935904bdeed04e14aa23b0d8 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 13:04:32 +0000 Subject: [PATCH 1/2] docs(issues): reconcile queued ledger requests (remediation Phases 2-3, #2105 resolutions) Apply the 88 queued outstanding-issues inbox requests to the canonical ledger in one serialized transaction from a fresh origin/main base. The batch covers the database-remediation set (updates to #316, #056 and #183, four add requests and ten cancellation decisions) together with the manual done resolutions queued by PR #2105. No request was adjudicated by hand: `npm run issues:reconcile` applied what was queued and moved every processed request and cancellation into docs/outstanding-issues-inbox/applied/ as the audit trail. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01C6WXAK931ZPgisknbCTnpR --- .../0381a544-b800-43bb-a164-2b3cb3905ef2.json | 0 .../0455881d-5bbf-4e0c-b4ad-3c4eeaa55499.json | 0 .../09a8d946-6b3a-44a2-bf54-4b9575f9aa10.json | 0 .../0a33bfad-4040-43f8-8c73-eb1dd9b812cc.json | 0 .../0c6f2ae7-5145-4b6d-bc1a-c89827a18bb2.json | 0 .../0e73e359-87eb-4d8d-b2a5-f0dd9b604636.json | 0 .../10088303-ec2e-46de-a122-542d7238b4d1.json | 0 .../10e480da-b2e3-4e2d-bfc8-15456bf962c1.json | 0 .../1f611dab-bc4f-48dc-a329-33eb7323c65c.json | 0 .../200b4a39-dd97-4835-a55b-d763c2956bed.json | 0 .../22577f77-0674-4db5-8f20-8e75ae0b04e6.json | 0 .../228fe6d3-d546-43a2-8f81-ad4890fd4ebf.json | 0 .../22946f19-6197-408e-b154-142d226a2743.json | 0 .../23af58be-1121-433e-934d-62921a51b78b.json | 0 .../23ba3865-258a-4f24-ace4-05e683776dc1.json | 0 .../288b042c-e319-4af2-84de-f88443b05d18.json | 0 .../2cc88eb7-c5e7-49f9-a93e-40410e081e7b.json | 0 .../2ecf8a33-3cc2-4fa5-9aba-a39a26b73447.json | 0 .../30d09441-44da-4b56-829c-e64d67410da8.json | 0 .../34e8150c-afc2-4c03-87d9-4825c9b1af80.json | 0 .../35c3fc6a-8aa7-4688-92bd-84bba0ea4607.json | 0 .../38d1b957-aa1d-4bd0-97ff-5d6c921a1dd7.json | 0 .../3f0341a4-ff83-407d-a101-0869f4f6dcff.json | 0 .../3f82baef-fa0f-4a0b-8094-a56114d96358.json | 0 .../4108e631-1387-4779-ada0-230e53e4411e.json | 0 .../41576279-d570-436b-a80b-d23b555845af.json | 0 .../45411575-4ce4-4d53-8af6-44866adaf317.json | 0 .../4dbcdcce-3645-4e08-8813-e85ab1fe7bcc.json | 0 .../4fcdcde4-8f21-4c6e-b178-d38f8a565511.json | 0 .../503c3553-6caf-4c12-9520-03acb283d142.json | 0 .../55aa4633-da95-418c-a92a-f8788195eb15.json | 0 .../565cf4ff-5aa6-456b-abfc-92c4765049e4.json | 0 .../56f6b76a-23f5-42aa-a53f-4a4eda7b3931.json | 0 .../5bff7294-a329-4fda-a36b-25489e36660d.json | 0 .../5c91c044-b492-4c7d-98cf-12069a1a45fc.json | 0 .../5d626edd-d62a-42b8-ac47-2e9717c99d33.json | 0 .../5ed2f873-e23b-4504-ad7b-8afb0ae39889.json | 0 .../5ee6b1cc-2751-4ba3-8497-d04137f874a4.json | 0 .../61f2c254-f636-4fc0-8138-ba450bd66208.json | 0 .../74273f4b-dede-44c0-99b7-930107e227c2.json | 0 .../74c53285-5573-467b-8981-3c5fa85d741d.json | 0 .../7de7933e-4eaa-4ad3-bf01-6c005b812d8d.json | 0 .../7e001f69-9911-406b-934d-84409c6953fa.json | 0 .../831835b9-8e54-445a-85f9-e5ef6f52f04a.json | 0 .../858e5a57-c596-4f67-ab59-a8796f6ac8e8.json | 0 .../88868df4-c310-4ac2-9e83-cd3ad7702a1d.json | 0 .../888bddaa-1df7-4b7c-b298-7d8722fc3365.json | 0 .../8b0650ed-793c-4f05-be9d-2012b6456a72.json | 0 .../8c1f1977-d0ef-44a0-b862-c63fac4ac210.json | 0 .../8cb71020-2847-4e10-bb7b-6b9594c26997.json | 0 .../8e9f1556-ae7b-4bfe-8c81-e52c4590d6ba.json | 0 .../9393fd14-9ef1-43c9-aaf0-67c18cf92c2b.json | 0 .../93d85256-bd67-48be-98d6-d7f2af05943f.json | 0 .../9619250f-e723-4a3f-acb1-150c4fd6799e.json | 0 .../9cd34b77-de50-4414-b1c8-591db58bfd6a.json | 0 .../9cfd4091-e110-45e6-a25a-d49a941449d9.json | 0 .../9f306cfd-a6cb-4c17-93e6-69bd6a242d42.json | 0 .../a3797cb9-af3b-4111-9d93-118974601cc8.json | 0 .../a42b6382-9e7c-4633-9180-c86d03ad0bf1.json | 0 .../a53299ec-b1af-44dc-8e4c-764ec4e31aef.json | 0 .../a645e77a-b62d-49b6-99f1-ab9bc8c8316d.json | 0 .../a7e38702-35d6-453f-9e8f-6856f1c8ae5c.json | 0 .../ab28efcb-2fb5-45e6-983d-9db6e508420e.json | 0 .../aba83c89-1bc6-459b-9b4d-9126e4e6bad8.json | 0 .../ad8b4b67-f29d-4480-b36c-5838e175a132.json | 0 .../b5f41582-492c-4d3e-b708-1f43b7e6ea4c.json | 0 .../ba2d9599-e229-4b20-a9f4-83e32abd1f6d.json | 0 .../bb3d9b51-3758-40ab-a2ac-18989d7c6931.json | 0 .../bb8b27de-6149-4600-b4a5-65dd883f9b47.json | 0 .../bd3673cb-2d9e-445e-a29e-4c59f1b44573.json | 0 .../bddd1154-6786-4762-a35b-4dd85d935755.json | 0 .../be8d2053-fcce-4604-9e9b-09f82ccc1c57.json | 0 .../bf709c67-0b09-41aa-ad46-d4243e5e13c9.json | 0 .../c53a10bf-e295-4a63-8cff-1515a573df4f.json | 0 .../c979e6f7-dead-46c2-bd8e-df133fafe83f.json | 0 .../c9b0667f-1901-4f12-ac68-2c4bb3c6fe81.json | 0 .../d0335f4b-583e-4256-af3d-1e220a4201a4.json | 0 .../d9da22e4-3b23-4c60-8023-dd7142e8a7a3.json | 0 .../dc8a4641-3937-4609-9595-031107cd43e0.json | 0 .../e215905d-1639-4827-9ae1-d7b93b3a4f8c.json | 0 .../e6228569-ebb7-4399-9702-8a15d49b75d8.json | 0 .../e6311a09-151a-4ffc-ae4f-52c06b4c2c3f.json | 0 .../eaa2e757-ad60-4fc7-abb5-58a1d381f0b1.json | 0 .../eb7a73ec-6fbd-4e6a-baae-0b2a77cd7dae.json | 0 .../ecd2dd27-b919-4419-9a2b-658bfcb39c36.json | 0 .../f0230f69-3616-465d-937f-348b0e28023b.json | 0 .../ff1c21f4-fd46-4e58-919d-fdd9cea4ca59.json | 0 .../ff207c2c-8ed0-4e4b-bd75-797eb397c1f1.json | 0 docs/outstanding-issues.md | 190 ++++++++---------- 89 files changed, 81 insertions(+), 109 deletions(-) rename docs/outstanding-issues-inbox/{ => applied}/0381a544-b800-43bb-a164-2b3cb3905ef2.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/0455881d-5bbf-4e0c-b4ad-3c4eeaa55499.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/09a8d946-6b3a-44a2-bf54-4b9575f9aa10.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/0a33bfad-4040-43f8-8c73-eb1dd9b812cc.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/0c6f2ae7-5145-4b6d-bc1a-c89827a18bb2.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/0e73e359-87eb-4d8d-b2a5-f0dd9b604636.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/10088303-ec2e-46de-a122-542d7238b4d1.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/10e480da-b2e3-4e2d-bfc8-15456bf962c1.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/1f611dab-bc4f-48dc-a329-33eb7323c65c.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/200b4a39-dd97-4835-a55b-d763c2956bed.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/22577f77-0674-4db5-8f20-8e75ae0b04e6.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/228fe6d3-d546-43a2-8f81-ad4890fd4ebf.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/22946f19-6197-408e-b154-142d226a2743.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/23af58be-1121-433e-934d-62921a51b78b.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/23ba3865-258a-4f24-ace4-05e683776dc1.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/288b042c-e319-4af2-84de-f88443b05d18.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/2cc88eb7-c5e7-49f9-a93e-40410e081e7b.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/2ecf8a33-3cc2-4fa5-9aba-a39a26b73447.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/30d09441-44da-4b56-829c-e64d67410da8.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/34e8150c-afc2-4c03-87d9-4825c9b1af80.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/35c3fc6a-8aa7-4688-92bd-84bba0ea4607.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/38d1b957-aa1d-4bd0-97ff-5d6c921a1dd7.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/3f0341a4-ff83-407d-a101-0869f4f6dcff.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/3f82baef-fa0f-4a0b-8094-a56114d96358.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/4108e631-1387-4779-ada0-230e53e4411e.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/41576279-d570-436b-a80b-d23b555845af.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/45411575-4ce4-4d53-8af6-44866adaf317.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/4dbcdcce-3645-4e08-8813-e85ab1fe7bcc.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/4fcdcde4-8f21-4c6e-b178-d38f8a565511.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/503c3553-6caf-4c12-9520-03acb283d142.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/55aa4633-da95-418c-a92a-f8788195eb15.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/565cf4ff-5aa6-456b-abfc-92c4765049e4.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/56f6b76a-23f5-42aa-a53f-4a4eda7b3931.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/5bff7294-a329-4fda-a36b-25489e36660d.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/5c91c044-b492-4c7d-98cf-12069a1a45fc.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/5d626edd-d62a-42b8-ac47-2e9717c99d33.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/5ed2f873-e23b-4504-ad7b-8afb0ae39889.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/5ee6b1cc-2751-4ba3-8497-d04137f874a4.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/61f2c254-f636-4fc0-8138-ba450bd66208.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/74273f4b-dede-44c0-99b7-930107e227c2.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/74c53285-5573-467b-8981-3c5fa85d741d.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/7de7933e-4eaa-4ad3-bf01-6c005b812d8d.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/7e001f69-9911-406b-934d-84409c6953fa.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/831835b9-8e54-445a-85f9-e5ef6f52f04a.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/858e5a57-c596-4f67-ab59-a8796f6ac8e8.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/88868df4-c310-4ac2-9e83-cd3ad7702a1d.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/888bddaa-1df7-4b7c-b298-7d8722fc3365.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/8b0650ed-793c-4f05-be9d-2012b6456a72.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/8c1f1977-d0ef-44a0-b862-c63fac4ac210.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/8cb71020-2847-4e10-bb7b-6b9594c26997.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/8e9f1556-ae7b-4bfe-8c81-e52c4590d6ba.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/9393fd14-9ef1-43c9-aaf0-67c18cf92c2b.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/93d85256-bd67-48be-98d6-d7f2af05943f.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/9619250f-e723-4a3f-acb1-150c4fd6799e.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/9cd34b77-de50-4414-b1c8-591db58bfd6a.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/9cfd4091-e110-45e6-a25a-d49a941449d9.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/9f306cfd-a6cb-4c17-93e6-69bd6a242d42.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/a3797cb9-af3b-4111-9d93-118974601cc8.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/a42b6382-9e7c-4633-9180-c86d03ad0bf1.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/a53299ec-b1af-44dc-8e4c-764ec4e31aef.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/a645e77a-b62d-49b6-99f1-ab9bc8c8316d.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/a7e38702-35d6-453f-9e8f-6856f1c8ae5c.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/ab28efcb-2fb5-45e6-983d-9db6e508420e.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/aba83c89-1bc6-459b-9b4d-9126e4e6bad8.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/ad8b4b67-f29d-4480-b36c-5838e175a132.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/b5f41582-492c-4d3e-b708-1f43b7e6ea4c.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/ba2d9599-e229-4b20-a9f4-83e32abd1f6d.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/bb3d9b51-3758-40ab-a2ac-18989d7c6931.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/bb8b27de-6149-4600-b4a5-65dd883f9b47.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/bd3673cb-2d9e-445e-a29e-4c59f1b44573.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/bddd1154-6786-4762-a35b-4dd85d935755.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/be8d2053-fcce-4604-9e9b-09f82ccc1c57.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/bf709c67-0b09-41aa-ad46-d4243e5e13c9.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/c53a10bf-e295-4a63-8cff-1515a573df4f.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/c979e6f7-dead-46c2-bd8e-df133fafe83f.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/c9b0667f-1901-4f12-ac68-2c4bb3c6fe81.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/d0335f4b-583e-4256-af3d-1e220a4201a4.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/d9da22e4-3b23-4c60-8023-dd7142e8a7a3.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/dc8a4641-3937-4609-9595-031107cd43e0.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/e215905d-1639-4827-9ae1-d7b93b3a4f8c.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/e6228569-ebb7-4399-9702-8a15d49b75d8.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/e6311a09-151a-4ffc-ae4f-52c06b4c2c3f.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/eaa2e757-ad60-4fc7-abb5-58a1d381f0b1.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/eb7a73ec-6fbd-4e6a-baae-0b2a77cd7dae.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/ecd2dd27-b919-4419-9a2b-658bfcb39c36.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/f0230f69-3616-465d-937f-348b0e28023b.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/ff1c21f4-fd46-4e58-919d-fdd9cea4ca59.json (100%) rename docs/outstanding-issues-inbox/{ => applied}/ff207c2c-8ed0-4e4b-bd75-797eb397c1f1.json (100%) diff --git a/docs/outstanding-issues-inbox/0381a544-b800-43bb-a164-2b3cb3905ef2.json b/docs/outstanding-issues-inbox/applied/0381a544-b800-43bb-a164-2b3cb3905ef2.json similarity index 100% rename from docs/outstanding-issues-inbox/0381a544-b800-43bb-a164-2b3cb3905ef2.json rename to docs/outstanding-issues-inbox/applied/0381a544-b800-43bb-a164-2b3cb3905ef2.json diff --git a/docs/outstanding-issues-inbox/0455881d-5bbf-4e0c-b4ad-3c4eeaa55499.json b/docs/outstanding-issues-inbox/applied/0455881d-5bbf-4e0c-b4ad-3c4eeaa55499.json similarity index 100% rename from docs/outstanding-issues-inbox/0455881d-5bbf-4e0c-b4ad-3c4eeaa55499.json rename to docs/outstanding-issues-inbox/applied/0455881d-5bbf-4e0c-b4ad-3c4eeaa55499.json diff --git a/docs/outstanding-issues-inbox/09a8d946-6b3a-44a2-bf54-4b9575f9aa10.json b/docs/outstanding-issues-inbox/applied/09a8d946-6b3a-44a2-bf54-4b9575f9aa10.json similarity index 100% rename from docs/outstanding-issues-inbox/09a8d946-6b3a-44a2-bf54-4b9575f9aa10.json rename to docs/outstanding-issues-inbox/applied/09a8d946-6b3a-44a2-bf54-4b9575f9aa10.json diff --git a/docs/outstanding-issues-inbox/0a33bfad-4040-43f8-8c73-eb1dd9b812cc.json b/docs/outstanding-issues-inbox/applied/0a33bfad-4040-43f8-8c73-eb1dd9b812cc.json similarity index 100% rename from docs/outstanding-issues-inbox/0a33bfad-4040-43f8-8c73-eb1dd9b812cc.json rename to docs/outstanding-issues-inbox/applied/0a33bfad-4040-43f8-8c73-eb1dd9b812cc.json diff --git a/docs/outstanding-issues-inbox/0c6f2ae7-5145-4b6d-bc1a-c89827a18bb2.json b/docs/outstanding-issues-inbox/applied/0c6f2ae7-5145-4b6d-bc1a-c89827a18bb2.json similarity index 100% rename from docs/outstanding-issues-inbox/0c6f2ae7-5145-4b6d-bc1a-c89827a18bb2.json rename to docs/outstanding-issues-inbox/applied/0c6f2ae7-5145-4b6d-bc1a-c89827a18bb2.json diff --git a/docs/outstanding-issues-inbox/0e73e359-87eb-4d8d-b2a5-f0dd9b604636.json b/docs/outstanding-issues-inbox/applied/0e73e359-87eb-4d8d-b2a5-f0dd9b604636.json similarity index 100% rename from docs/outstanding-issues-inbox/0e73e359-87eb-4d8d-b2a5-f0dd9b604636.json rename to docs/outstanding-issues-inbox/applied/0e73e359-87eb-4d8d-b2a5-f0dd9b604636.json diff --git a/docs/outstanding-issues-inbox/10088303-ec2e-46de-a122-542d7238b4d1.json b/docs/outstanding-issues-inbox/applied/10088303-ec2e-46de-a122-542d7238b4d1.json similarity index 100% rename from docs/outstanding-issues-inbox/10088303-ec2e-46de-a122-542d7238b4d1.json rename to docs/outstanding-issues-inbox/applied/10088303-ec2e-46de-a122-542d7238b4d1.json diff --git a/docs/outstanding-issues-inbox/10e480da-b2e3-4e2d-bfc8-15456bf962c1.json b/docs/outstanding-issues-inbox/applied/10e480da-b2e3-4e2d-bfc8-15456bf962c1.json similarity index 100% rename from docs/outstanding-issues-inbox/10e480da-b2e3-4e2d-bfc8-15456bf962c1.json rename to docs/outstanding-issues-inbox/applied/10e480da-b2e3-4e2d-bfc8-15456bf962c1.json diff --git a/docs/outstanding-issues-inbox/1f611dab-bc4f-48dc-a329-33eb7323c65c.json b/docs/outstanding-issues-inbox/applied/1f611dab-bc4f-48dc-a329-33eb7323c65c.json similarity index 100% rename from docs/outstanding-issues-inbox/1f611dab-bc4f-48dc-a329-33eb7323c65c.json rename to docs/outstanding-issues-inbox/applied/1f611dab-bc4f-48dc-a329-33eb7323c65c.json diff --git a/docs/outstanding-issues-inbox/200b4a39-dd97-4835-a55b-d763c2956bed.json b/docs/outstanding-issues-inbox/applied/200b4a39-dd97-4835-a55b-d763c2956bed.json similarity index 100% rename from docs/outstanding-issues-inbox/200b4a39-dd97-4835-a55b-d763c2956bed.json rename to docs/outstanding-issues-inbox/applied/200b4a39-dd97-4835-a55b-d763c2956bed.json diff --git a/docs/outstanding-issues-inbox/22577f77-0674-4db5-8f20-8e75ae0b04e6.json b/docs/outstanding-issues-inbox/applied/22577f77-0674-4db5-8f20-8e75ae0b04e6.json similarity index 100% rename from docs/outstanding-issues-inbox/22577f77-0674-4db5-8f20-8e75ae0b04e6.json rename to docs/outstanding-issues-inbox/applied/22577f77-0674-4db5-8f20-8e75ae0b04e6.json diff --git a/docs/outstanding-issues-inbox/228fe6d3-d546-43a2-8f81-ad4890fd4ebf.json b/docs/outstanding-issues-inbox/applied/228fe6d3-d546-43a2-8f81-ad4890fd4ebf.json similarity index 100% rename from docs/outstanding-issues-inbox/228fe6d3-d546-43a2-8f81-ad4890fd4ebf.json rename to docs/outstanding-issues-inbox/applied/228fe6d3-d546-43a2-8f81-ad4890fd4ebf.json diff --git a/docs/outstanding-issues-inbox/22946f19-6197-408e-b154-142d226a2743.json b/docs/outstanding-issues-inbox/applied/22946f19-6197-408e-b154-142d226a2743.json similarity index 100% rename from docs/outstanding-issues-inbox/22946f19-6197-408e-b154-142d226a2743.json rename to docs/outstanding-issues-inbox/applied/22946f19-6197-408e-b154-142d226a2743.json diff --git a/docs/outstanding-issues-inbox/23af58be-1121-433e-934d-62921a51b78b.json b/docs/outstanding-issues-inbox/applied/23af58be-1121-433e-934d-62921a51b78b.json similarity index 100% rename from docs/outstanding-issues-inbox/23af58be-1121-433e-934d-62921a51b78b.json rename to docs/outstanding-issues-inbox/applied/23af58be-1121-433e-934d-62921a51b78b.json diff --git a/docs/outstanding-issues-inbox/23ba3865-258a-4f24-ace4-05e683776dc1.json b/docs/outstanding-issues-inbox/applied/23ba3865-258a-4f24-ace4-05e683776dc1.json similarity index 100% rename from docs/outstanding-issues-inbox/23ba3865-258a-4f24-ace4-05e683776dc1.json rename to docs/outstanding-issues-inbox/applied/23ba3865-258a-4f24-ace4-05e683776dc1.json diff --git a/docs/outstanding-issues-inbox/288b042c-e319-4af2-84de-f88443b05d18.json b/docs/outstanding-issues-inbox/applied/288b042c-e319-4af2-84de-f88443b05d18.json similarity index 100% rename from docs/outstanding-issues-inbox/288b042c-e319-4af2-84de-f88443b05d18.json rename to docs/outstanding-issues-inbox/applied/288b042c-e319-4af2-84de-f88443b05d18.json diff --git a/docs/outstanding-issues-inbox/2cc88eb7-c5e7-49f9-a93e-40410e081e7b.json b/docs/outstanding-issues-inbox/applied/2cc88eb7-c5e7-49f9-a93e-40410e081e7b.json similarity index 100% rename from docs/outstanding-issues-inbox/2cc88eb7-c5e7-49f9-a93e-40410e081e7b.json rename to docs/outstanding-issues-inbox/applied/2cc88eb7-c5e7-49f9-a93e-40410e081e7b.json diff --git a/docs/outstanding-issues-inbox/2ecf8a33-3cc2-4fa5-9aba-a39a26b73447.json b/docs/outstanding-issues-inbox/applied/2ecf8a33-3cc2-4fa5-9aba-a39a26b73447.json similarity index 100% rename from docs/outstanding-issues-inbox/2ecf8a33-3cc2-4fa5-9aba-a39a26b73447.json rename to docs/outstanding-issues-inbox/applied/2ecf8a33-3cc2-4fa5-9aba-a39a26b73447.json diff --git a/docs/outstanding-issues-inbox/30d09441-44da-4b56-829c-e64d67410da8.json b/docs/outstanding-issues-inbox/applied/30d09441-44da-4b56-829c-e64d67410da8.json similarity index 100% rename from docs/outstanding-issues-inbox/30d09441-44da-4b56-829c-e64d67410da8.json rename to docs/outstanding-issues-inbox/applied/30d09441-44da-4b56-829c-e64d67410da8.json diff --git a/docs/outstanding-issues-inbox/34e8150c-afc2-4c03-87d9-4825c9b1af80.json b/docs/outstanding-issues-inbox/applied/34e8150c-afc2-4c03-87d9-4825c9b1af80.json similarity index 100% rename from docs/outstanding-issues-inbox/34e8150c-afc2-4c03-87d9-4825c9b1af80.json rename to docs/outstanding-issues-inbox/applied/34e8150c-afc2-4c03-87d9-4825c9b1af80.json diff --git a/docs/outstanding-issues-inbox/35c3fc6a-8aa7-4688-92bd-84bba0ea4607.json b/docs/outstanding-issues-inbox/applied/35c3fc6a-8aa7-4688-92bd-84bba0ea4607.json similarity index 100% rename from docs/outstanding-issues-inbox/35c3fc6a-8aa7-4688-92bd-84bba0ea4607.json rename to docs/outstanding-issues-inbox/applied/35c3fc6a-8aa7-4688-92bd-84bba0ea4607.json diff --git a/docs/outstanding-issues-inbox/38d1b957-aa1d-4bd0-97ff-5d6c921a1dd7.json b/docs/outstanding-issues-inbox/applied/38d1b957-aa1d-4bd0-97ff-5d6c921a1dd7.json similarity index 100% rename from docs/outstanding-issues-inbox/38d1b957-aa1d-4bd0-97ff-5d6c921a1dd7.json rename to docs/outstanding-issues-inbox/applied/38d1b957-aa1d-4bd0-97ff-5d6c921a1dd7.json diff --git a/docs/outstanding-issues-inbox/3f0341a4-ff83-407d-a101-0869f4f6dcff.json b/docs/outstanding-issues-inbox/applied/3f0341a4-ff83-407d-a101-0869f4f6dcff.json similarity index 100% rename from docs/outstanding-issues-inbox/3f0341a4-ff83-407d-a101-0869f4f6dcff.json rename to docs/outstanding-issues-inbox/applied/3f0341a4-ff83-407d-a101-0869f4f6dcff.json diff --git a/docs/outstanding-issues-inbox/3f82baef-fa0f-4a0b-8094-a56114d96358.json b/docs/outstanding-issues-inbox/applied/3f82baef-fa0f-4a0b-8094-a56114d96358.json similarity index 100% rename from docs/outstanding-issues-inbox/3f82baef-fa0f-4a0b-8094-a56114d96358.json rename to docs/outstanding-issues-inbox/applied/3f82baef-fa0f-4a0b-8094-a56114d96358.json diff --git a/docs/outstanding-issues-inbox/4108e631-1387-4779-ada0-230e53e4411e.json b/docs/outstanding-issues-inbox/applied/4108e631-1387-4779-ada0-230e53e4411e.json similarity index 100% rename from docs/outstanding-issues-inbox/4108e631-1387-4779-ada0-230e53e4411e.json rename to docs/outstanding-issues-inbox/applied/4108e631-1387-4779-ada0-230e53e4411e.json diff --git a/docs/outstanding-issues-inbox/41576279-d570-436b-a80b-d23b555845af.json b/docs/outstanding-issues-inbox/applied/41576279-d570-436b-a80b-d23b555845af.json similarity index 100% rename from docs/outstanding-issues-inbox/41576279-d570-436b-a80b-d23b555845af.json rename to docs/outstanding-issues-inbox/applied/41576279-d570-436b-a80b-d23b555845af.json diff --git a/docs/outstanding-issues-inbox/45411575-4ce4-4d53-8af6-44866adaf317.json b/docs/outstanding-issues-inbox/applied/45411575-4ce4-4d53-8af6-44866adaf317.json similarity index 100% rename from docs/outstanding-issues-inbox/45411575-4ce4-4d53-8af6-44866adaf317.json rename to docs/outstanding-issues-inbox/applied/45411575-4ce4-4d53-8af6-44866adaf317.json diff --git a/docs/outstanding-issues-inbox/4dbcdcce-3645-4e08-8813-e85ab1fe7bcc.json b/docs/outstanding-issues-inbox/applied/4dbcdcce-3645-4e08-8813-e85ab1fe7bcc.json similarity index 100% rename from docs/outstanding-issues-inbox/4dbcdcce-3645-4e08-8813-e85ab1fe7bcc.json rename to docs/outstanding-issues-inbox/applied/4dbcdcce-3645-4e08-8813-e85ab1fe7bcc.json diff --git a/docs/outstanding-issues-inbox/4fcdcde4-8f21-4c6e-b178-d38f8a565511.json b/docs/outstanding-issues-inbox/applied/4fcdcde4-8f21-4c6e-b178-d38f8a565511.json similarity index 100% rename from docs/outstanding-issues-inbox/4fcdcde4-8f21-4c6e-b178-d38f8a565511.json rename to docs/outstanding-issues-inbox/applied/4fcdcde4-8f21-4c6e-b178-d38f8a565511.json diff --git a/docs/outstanding-issues-inbox/503c3553-6caf-4c12-9520-03acb283d142.json b/docs/outstanding-issues-inbox/applied/503c3553-6caf-4c12-9520-03acb283d142.json similarity index 100% rename from docs/outstanding-issues-inbox/503c3553-6caf-4c12-9520-03acb283d142.json rename to docs/outstanding-issues-inbox/applied/503c3553-6caf-4c12-9520-03acb283d142.json diff --git a/docs/outstanding-issues-inbox/55aa4633-da95-418c-a92a-f8788195eb15.json b/docs/outstanding-issues-inbox/applied/55aa4633-da95-418c-a92a-f8788195eb15.json similarity index 100% rename from docs/outstanding-issues-inbox/55aa4633-da95-418c-a92a-f8788195eb15.json rename to docs/outstanding-issues-inbox/applied/55aa4633-da95-418c-a92a-f8788195eb15.json diff --git a/docs/outstanding-issues-inbox/565cf4ff-5aa6-456b-abfc-92c4765049e4.json b/docs/outstanding-issues-inbox/applied/565cf4ff-5aa6-456b-abfc-92c4765049e4.json similarity index 100% rename from docs/outstanding-issues-inbox/565cf4ff-5aa6-456b-abfc-92c4765049e4.json rename to docs/outstanding-issues-inbox/applied/565cf4ff-5aa6-456b-abfc-92c4765049e4.json diff --git a/docs/outstanding-issues-inbox/56f6b76a-23f5-42aa-a53f-4a4eda7b3931.json b/docs/outstanding-issues-inbox/applied/56f6b76a-23f5-42aa-a53f-4a4eda7b3931.json similarity index 100% rename from docs/outstanding-issues-inbox/56f6b76a-23f5-42aa-a53f-4a4eda7b3931.json rename to docs/outstanding-issues-inbox/applied/56f6b76a-23f5-42aa-a53f-4a4eda7b3931.json diff --git a/docs/outstanding-issues-inbox/5bff7294-a329-4fda-a36b-25489e36660d.json b/docs/outstanding-issues-inbox/applied/5bff7294-a329-4fda-a36b-25489e36660d.json similarity index 100% rename from docs/outstanding-issues-inbox/5bff7294-a329-4fda-a36b-25489e36660d.json rename to docs/outstanding-issues-inbox/applied/5bff7294-a329-4fda-a36b-25489e36660d.json diff --git a/docs/outstanding-issues-inbox/5c91c044-b492-4c7d-98cf-12069a1a45fc.json b/docs/outstanding-issues-inbox/applied/5c91c044-b492-4c7d-98cf-12069a1a45fc.json similarity index 100% rename from docs/outstanding-issues-inbox/5c91c044-b492-4c7d-98cf-12069a1a45fc.json rename to docs/outstanding-issues-inbox/applied/5c91c044-b492-4c7d-98cf-12069a1a45fc.json diff --git a/docs/outstanding-issues-inbox/5d626edd-d62a-42b8-ac47-2e9717c99d33.json b/docs/outstanding-issues-inbox/applied/5d626edd-d62a-42b8-ac47-2e9717c99d33.json similarity index 100% rename from docs/outstanding-issues-inbox/5d626edd-d62a-42b8-ac47-2e9717c99d33.json rename to docs/outstanding-issues-inbox/applied/5d626edd-d62a-42b8-ac47-2e9717c99d33.json diff --git a/docs/outstanding-issues-inbox/5ed2f873-e23b-4504-ad7b-8afb0ae39889.json b/docs/outstanding-issues-inbox/applied/5ed2f873-e23b-4504-ad7b-8afb0ae39889.json similarity index 100% rename from docs/outstanding-issues-inbox/5ed2f873-e23b-4504-ad7b-8afb0ae39889.json rename to docs/outstanding-issues-inbox/applied/5ed2f873-e23b-4504-ad7b-8afb0ae39889.json diff --git a/docs/outstanding-issues-inbox/5ee6b1cc-2751-4ba3-8497-d04137f874a4.json b/docs/outstanding-issues-inbox/applied/5ee6b1cc-2751-4ba3-8497-d04137f874a4.json similarity index 100% rename from docs/outstanding-issues-inbox/5ee6b1cc-2751-4ba3-8497-d04137f874a4.json rename to docs/outstanding-issues-inbox/applied/5ee6b1cc-2751-4ba3-8497-d04137f874a4.json diff --git a/docs/outstanding-issues-inbox/61f2c254-f636-4fc0-8138-ba450bd66208.json b/docs/outstanding-issues-inbox/applied/61f2c254-f636-4fc0-8138-ba450bd66208.json similarity index 100% rename from docs/outstanding-issues-inbox/61f2c254-f636-4fc0-8138-ba450bd66208.json rename to docs/outstanding-issues-inbox/applied/61f2c254-f636-4fc0-8138-ba450bd66208.json diff --git a/docs/outstanding-issues-inbox/74273f4b-dede-44c0-99b7-930107e227c2.json b/docs/outstanding-issues-inbox/applied/74273f4b-dede-44c0-99b7-930107e227c2.json similarity index 100% rename from docs/outstanding-issues-inbox/74273f4b-dede-44c0-99b7-930107e227c2.json rename to docs/outstanding-issues-inbox/applied/74273f4b-dede-44c0-99b7-930107e227c2.json diff --git a/docs/outstanding-issues-inbox/74c53285-5573-467b-8981-3c5fa85d741d.json b/docs/outstanding-issues-inbox/applied/74c53285-5573-467b-8981-3c5fa85d741d.json similarity index 100% rename from docs/outstanding-issues-inbox/74c53285-5573-467b-8981-3c5fa85d741d.json rename to docs/outstanding-issues-inbox/applied/74c53285-5573-467b-8981-3c5fa85d741d.json diff --git a/docs/outstanding-issues-inbox/7de7933e-4eaa-4ad3-bf01-6c005b812d8d.json b/docs/outstanding-issues-inbox/applied/7de7933e-4eaa-4ad3-bf01-6c005b812d8d.json similarity index 100% rename from docs/outstanding-issues-inbox/7de7933e-4eaa-4ad3-bf01-6c005b812d8d.json rename to docs/outstanding-issues-inbox/applied/7de7933e-4eaa-4ad3-bf01-6c005b812d8d.json diff --git a/docs/outstanding-issues-inbox/7e001f69-9911-406b-934d-84409c6953fa.json b/docs/outstanding-issues-inbox/applied/7e001f69-9911-406b-934d-84409c6953fa.json similarity index 100% rename from docs/outstanding-issues-inbox/7e001f69-9911-406b-934d-84409c6953fa.json rename to docs/outstanding-issues-inbox/applied/7e001f69-9911-406b-934d-84409c6953fa.json diff --git a/docs/outstanding-issues-inbox/831835b9-8e54-445a-85f9-e5ef6f52f04a.json b/docs/outstanding-issues-inbox/applied/831835b9-8e54-445a-85f9-e5ef6f52f04a.json similarity index 100% rename from docs/outstanding-issues-inbox/831835b9-8e54-445a-85f9-e5ef6f52f04a.json rename to docs/outstanding-issues-inbox/applied/831835b9-8e54-445a-85f9-e5ef6f52f04a.json diff --git a/docs/outstanding-issues-inbox/858e5a57-c596-4f67-ab59-a8796f6ac8e8.json b/docs/outstanding-issues-inbox/applied/858e5a57-c596-4f67-ab59-a8796f6ac8e8.json similarity index 100% rename from docs/outstanding-issues-inbox/858e5a57-c596-4f67-ab59-a8796f6ac8e8.json rename to docs/outstanding-issues-inbox/applied/858e5a57-c596-4f67-ab59-a8796f6ac8e8.json diff --git a/docs/outstanding-issues-inbox/88868df4-c310-4ac2-9e83-cd3ad7702a1d.json b/docs/outstanding-issues-inbox/applied/88868df4-c310-4ac2-9e83-cd3ad7702a1d.json similarity index 100% rename from docs/outstanding-issues-inbox/88868df4-c310-4ac2-9e83-cd3ad7702a1d.json rename to docs/outstanding-issues-inbox/applied/88868df4-c310-4ac2-9e83-cd3ad7702a1d.json diff --git a/docs/outstanding-issues-inbox/888bddaa-1df7-4b7c-b298-7d8722fc3365.json b/docs/outstanding-issues-inbox/applied/888bddaa-1df7-4b7c-b298-7d8722fc3365.json similarity index 100% rename from docs/outstanding-issues-inbox/888bddaa-1df7-4b7c-b298-7d8722fc3365.json rename to docs/outstanding-issues-inbox/applied/888bddaa-1df7-4b7c-b298-7d8722fc3365.json diff --git a/docs/outstanding-issues-inbox/8b0650ed-793c-4f05-be9d-2012b6456a72.json b/docs/outstanding-issues-inbox/applied/8b0650ed-793c-4f05-be9d-2012b6456a72.json similarity index 100% rename from docs/outstanding-issues-inbox/8b0650ed-793c-4f05-be9d-2012b6456a72.json rename to docs/outstanding-issues-inbox/applied/8b0650ed-793c-4f05-be9d-2012b6456a72.json diff --git a/docs/outstanding-issues-inbox/8c1f1977-d0ef-44a0-b862-c63fac4ac210.json b/docs/outstanding-issues-inbox/applied/8c1f1977-d0ef-44a0-b862-c63fac4ac210.json similarity index 100% rename from docs/outstanding-issues-inbox/8c1f1977-d0ef-44a0-b862-c63fac4ac210.json rename to docs/outstanding-issues-inbox/applied/8c1f1977-d0ef-44a0-b862-c63fac4ac210.json diff --git a/docs/outstanding-issues-inbox/8cb71020-2847-4e10-bb7b-6b9594c26997.json b/docs/outstanding-issues-inbox/applied/8cb71020-2847-4e10-bb7b-6b9594c26997.json similarity index 100% rename from docs/outstanding-issues-inbox/8cb71020-2847-4e10-bb7b-6b9594c26997.json rename to docs/outstanding-issues-inbox/applied/8cb71020-2847-4e10-bb7b-6b9594c26997.json diff --git a/docs/outstanding-issues-inbox/8e9f1556-ae7b-4bfe-8c81-e52c4590d6ba.json b/docs/outstanding-issues-inbox/applied/8e9f1556-ae7b-4bfe-8c81-e52c4590d6ba.json similarity index 100% rename from docs/outstanding-issues-inbox/8e9f1556-ae7b-4bfe-8c81-e52c4590d6ba.json rename to docs/outstanding-issues-inbox/applied/8e9f1556-ae7b-4bfe-8c81-e52c4590d6ba.json diff --git a/docs/outstanding-issues-inbox/9393fd14-9ef1-43c9-aaf0-67c18cf92c2b.json b/docs/outstanding-issues-inbox/applied/9393fd14-9ef1-43c9-aaf0-67c18cf92c2b.json similarity index 100% rename from docs/outstanding-issues-inbox/9393fd14-9ef1-43c9-aaf0-67c18cf92c2b.json rename to docs/outstanding-issues-inbox/applied/9393fd14-9ef1-43c9-aaf0-67c18cf92c2b.json diff --git a/docs/outstanding-issues-inbox/93d85256-bd67-48be-98d6-d7f2af05943f.json b/docs/outstanding-issues-inbox/applied/93d85256-bd67-48be-98d6-d7f2af05943f.json similarity index 100% rename from docs/outstanding-issues-inbox/93d85256-bd67-48be-98d6-d7f2af05943f.json rename to docs/outstanding-issues-inbox/applied/93d85256-bd67-48be-98d6-d7f2af05943f.json diff --git a/docs/outstanding-issues-inbox/9619250f-e723-4a3f-acb1-150c4fd6799e.json b/docs/outstanding-issues-inbox/applied/9619250f-e723-4a3f-acb1-150c4fd6799e.json similarity index 100% rename from docs/outstanding-issues-inbox/9619250f-e723-4a3f-acb1-150c4fd6799e.json rename to docs/outstanding-issues-inbox/applied/9619250f-e723-4a3f-acb1-150c4fd6799e.json diff --git a/docs/outstanding-issues-inbox/9cd34b77-de50-4414-b1c8-591db58bfd6a.json b/docs/outstanding-issues-inbox/applied/9cd34b77-de50-4414-b1c8-591db58bfd6a.json similarity index 100% rename from docs/outstanding-issues-inbox/9cd34b77-de50-4414-b1c8-591db58bfd6a.json rename to docs/outstanding-issues-inbox/applied/9cd34b77-de50-4414-b1c8-591db58bfd6a.json diff --git a/docs/outstanding-issues-inbox/9cfd4091-e110-45e6-a25a-d49a941449d9.json b/docs/outstanding-issues-inbox/applied/9cfd4091-e110-45e6-a25a-d49a941449d9.json similarity index 100% rename from docs/outstanding-issues-inbox/9cfd4091-e110-45e6-a25a-d49a941449d9.json rename to docs/outstanding-issues-inbox/applied/9cfd4091-e110-45e6-a25a-d49a941449d9.json diff --git a/docs/outstanding-issues-inbox/9f306cfd-a6cb-4c17-93e6-69bd6a242d42.json b/docs/outstanding-issues-inbox/applied/9f306cfd-a6cb-4c17-93e6-69bd6a242d42.json similarity index 100% rename from docs/outstanding-issues-inbox/9f306cfd-a6cb-4c17-93e6-69bd6a242d42.json rename to docs/outstanding-issues-inbox/applied/9f306cfd-a6cb-4c17-93e6-69bd6a242d42.json diff --git a/docs/outstanding-issues-inbox/a3797cb9-af3b-4111-9d93-118974601cc8.json b/docs/outstanding-issues-inbox/applied/a3797cb9-af3b-4111-9d93-118974601cc8.json similarity index 100% rename from docs/outstanding-issues-inbox/a3797cb9-af3b-4111-9d93-118974601cc8.json rename to docs/outstanding-issues-inbox/applied/a3797cb9-af3b-4111-9d93-118974601cc8.json diff --git a/docs/outstanding-issues-inbox/a42b6382-9e7c-4633-9180-c86d03ad0bf1.json b/docs/outstanding-issues-inbox/applied/a42b6382-9e7c-4633-9180-c86d03ad0bf1.json similarity index 100% rename from docs/outstanding-issues-inbox/a42b6382-9e7c-4633-9180-c86d03ad0bf1.json rename to docs/outstanding-issues-inbox/applied/a42b6382-9e7c-4633-9180-c86d03ad0bf1.json diff --git a/docs/outstanding-issues-inbox/a53299ec-b1af-44dc-8e4c-764ec4e31aef.json b/docs/outstanding-issues-inbox/applied/a53299ec-b1af-44dc-8e4c-764ec4e31aef.json similarity index 100% rename from docs/outstanding-issues-inbox/a53299ec-b1af-44dc-8e4c-764ec4e31aef.json rename to docs/outstanding-issues-inbox/applied/a53299ec-b1af-44dc-8e4c-764ec4e31aef.json diff --git a/docs/outstanding-issues-inbox/a645e77a-b62d-49b6-99f1-ab9bc8c8316d.json b/docs/outstanding-issues-inbox/applied/a645e77a-b62d-49b6-99f1-ab9bc8c8316d.json similarity index 100% rename from docs/outstanding-issues-inbox/a645e77a-b62d-49b6-99f1-ab9bc8c8316d.json rename to docs/outstanding-issues-inbox/applied/a645e77a-b62d-49b6-99f1-ab9bc8c8316d.json diff --git a/docs/outstanding-issues-inbox/a7e38702-35d6-453f-9e8f-6856f1c8ae5c.json b/docs/outstanding-issues-inbox/applied/a7e38702-35d6-453f-9e8f-6856f1c8ae5c.json similarity index 100% rename from docs/outstanding-issues-inbox/a7e38702-35d6-453f-9e8f-6856f1c8ae5c.json rename to docs/outstanding-issues-inbox/applied/a7e38702-35d6-453f-9e8f-6856f1c8ae5c.json diff --git a/docs/outstanding-issues-inbox/ab28efcb-2fb5-45e6-983d-9db6e508420e.json b/docs/outstanding-issues-inbox/applied/ab28efcb-2fb5-45e6-983d-9db6e508420e.json similarity index 100% rename from docs/outstanding-issues-inbox/ab28efcb-2fb5-45e6-983d-9db6e508420e.json rename to docs/outstanding-issues-inbox/applied/ab28efcb-2fb5-45e6-983d-9db6e508420e.json diff --git a/docs/outstanding-issues-inbox/aba83c89-1bc6-459b-9b4d-9126e4e6bad8.json b/docs/outstanding-issues-inbox/applied/aba83c89-1bc6-459b-9b4d-9126e4e6bad8.json similarity index 100% rename from docs/outstanding-issues-inbox/aba83c89-1bc6-459b-9b4d-9126e4e6bad8.json rename to docs/outstanding-issues-inbox/applied/aba83c89-1bc6-459b-9b4d-9126e4e6bad8.json diff --git a/docs/outstanding-issues-inbox/ad8b4b67-f29d-4480-b36c-5838e175a132.json b/docs/outstanding-issues-inbox/applied/ad8b4b67-f29d-4480-b36c-5838e175a132.json similarity index 100% rename from docs/outstanding-issues-inbox/ad8b4b67-f29d-4480-b36c-5838e175a132.json rename to docs/outstanding-issues-inbox/applied/ad8b4b67-f29d-4480-b36c-5838e175a132.json diff --git a/docs/outstanding-issues-inbox/b5f41582-492c-4d3e-b708-1f43b7e6ea4c.json b/docs/outstanding-issues-inbox/applied/b5f41582-492c-4d3e-b708-1f43b7e6ea4c.json similarity index 100% rename from docs/outstanding-issues-inbox/b5f41582-492c-4d3e-b708-1f43b7e6ea4c.json rename to docs/outstanding-issues-inbox/applied/b5f41582-492c-4d3e-b708-1f43b7e6ea4c.json diff --git a/docs/outstanding-issues-inbox/ba2d9599-e229-4b20-a9f4-83e32abd1f6d.json b/docs/outstanding-issues-inbox/applied/ba2d9599-e229-4b20-a9f4-83e32abd1f6d.json similarity index 100% rename from docs/outstanding-issues-inbox/ba2d9599-e229-4b20-a9f4-83e32abd1f6d.json rename to docs/outstanding-issues-inbox/applied/ba2d9599-e229-4b20-a9f4-83e32abd1f6d.json diff --git a/docs/outstanding-issues-inbox/bb3d9b51-3758-40ab-a2ac-18989d7c6931.json b/docs/outstanding-issues-inbox/applied/bb3d9b51-3758-40ab-a2ac-18989d7c6931.json similarity index 100% rename from docs/outstanding-issues-inbox/bb3d9b51-3758-40ab-a2ac-18989d7c6931.json rename to docs/outstanding-issues-inbox/applied/bb3d9b51-3758-40ab-a2ac-18989d7c6931.json diff --git a/docs/outstanding-issues-inbox/bb8b27de-6149-4600-b4a5-65dd883f9b47.json b/docs/outstanding-issues-inbox/applied/bb8b27de-6149-4600-b4a5-65dd883f9b47.json similarity index 100% rename from docs/outstanding-issues-inbox/bb8b27de-6149-4600-b4a5-65dd883f9b47.json rename to docs/outstanding-issues-inbox/applied/bb8b27de-6149-4600-b4a5-65dd883f9b47.json diff --git a/docs/outstanding-issues-inbox/bd3673cb-2d9e-445e-a29e-4c59f1b44573.json b/docs/outstanding-issues-inbox/applied/bd3673cb-2d9e-445e-a29e-4c59f1b44573.json similarity index 100% rename from docs/outstanding-issues-inbox/bd3673cb-2d9e-445e-a29e-4c59f1b44573.json rename to docs/outstanding-issues-inbox/applied/bd3673cb-2d9e-445e-a29e-4c59f1b44573.json diff --git a/docs/outstanding-issues-inbox/bddd1154-6786-4762-a35b-4dd85d935755.json b/docs/outstanding-issues-inbox/applied/bddd1154-6786-4762-a35b-4dd85d935755.json similarity index 100% rename from docs/outstanding-issues-inbox/bddd1154-6786-4762-a35b-4dd85d935755.json rename to docs/outstanding-issues-inbox/applied/bddd1154-6786-4762-a35b-4dd85d935755.json diff --git a/docs/outstanding-issues-inbox/be8d2053-fcce-4604-9e9b-09f82ccc1c57.json b/docs/outstanding-issues-inbox/applied/be8d2053-fcce-4604-9e9b-09f82ccc1c57.json similarity index 100% rename from docs/outstanding-issues-inbox/be8d2053-fcce-4604-9e9b-09f82ccc1c57.json rename to docs/outstanding-issues-inbox/applied/be8d2053-fcce-4604-9e9b-09f82ccc1c57.json diff --git a/docs/outstanding-issues-inbox/bf709c67-0b09-41aa-ad46-d4243e5e13c9.json b/docs/outstanding-issues-inbox/applied/bf709c67-0b09-41aa-ad46-d4243e5e13c9.json similarity index 100% rename from docs/outstanding-issues-inbox/bf709c67-0b09-41aa-ad46-d4243e5e13c9.json rename to docs/outstanding-issues-inbox/applied/bf709c67-0b09-41aa-ad46-d4243e5e13c9.json diff --git a/docs/outstanding-issues-inbox/c53a10bf-e295-4a63-8cff-1515a573df4f.json b/docs/outstanding-issues-inbox/applied/c53a10bf-e295-4a63-8cff-1515a573df4f.json similarity index 100% rename from docs/outstanding-issues-inbox/c53a10bf-e295-4a63-8cff-1515a573df4f.json rename to docs/outstanding-issues-inbox/applied/c53a10bf-e295-4a63-8cff-1515a573df4f.json diff --git a/docs/outstanding-issues-inbox/c979e6f7-dead-46c2-bd8e-df133fafe83f.json b/docs/outstanding-issues-inbox/applied/c979e6f7-dead-46c2-bd8e-df133fafe83f.json similarity index 100% rename from docs/outstanding-issues-inbox/c979e6f7-dead-46c2-bd8e-df133fafe83f.json rename to docs/outstanding-issues-inbox/applied/c979e6f7-dead-46c2-bd8e-df133fafe83f.json diff --git a/docs/outstanding-issues-inbox/c9b0667f-1901-4f12-ac68-2c4bb3c6fe81.json b/docs/outstanding-issues-inbox/applied/c9b0667f-1901-4f12-ac68-2c4bb3c6fe81.json similarity index 100% rename from docs/outstanding-issues-inbox/c9b0667f-1901-4f12-ac68-2c4bb3c6fe81.json rename to docs/outstanding-issues-inbox/applied/c9b0667f-1901-4f12-ac68-2c4bb3c6fe81.json diff --git a/docs/outstanding-issues-inbox/d0335f4b-583e-4256-af3d-1e220a4201a4.json b/docs/outstanding-issues-inbox/applied/d0335f4b-583e-4256-af3d-1e220a4201a4.json similarity index 100% rename from docs/outstanding-issues-inbox/d0335f4b-583e-4256-af3d-1e220a4201a4.json rename to docs/outstanding-issues-inbox/applied/d0335f4b-583e-4256-af3d-1e220a4201a4.json diff --git a/docs/outstanding-issues-inbox/d9da22e4-3b23-4c60-8023-dd7142e8a7a3.json b/docs/outstanding-issues-inbox/applied/d9da22e4-3b23-4c60-8023-dd7142e8a7a3.json similarity index 100% rename from docs/outstanding-issues-inbox/d9da22e4-3b23-4c60-8023-dd7142e8a7a3.json rename to docs/outstanding-issues-inbox/applied/d9da22e4-3b23-4c60-8023-dd7142e8a7a3.json diff --git a/docs/outstanding-issues-inbox/dc8a4641-3937-4609-9595-031107cd43e0.json b/docs/outstanding-issues-inbox/applied/dc8a4641-3937-4609-9595-031107cd43e0.json similarity index 100% rename from docs/outstanding-issues-inbox/dc8a4641-3937-4609-9595-031107cd43e0.json rename to docs/outstanding-issues-inbox/applied/dc8a4641-3937-4609-9595-031107cd43e0.json diff --git a/docs/outstanding-issues-inbox/e215905d-1639-4827-9ae1-d7b93b3a4f8c.json b/docs/outstanding-issues-inbox/applied/e215905d-1639-4827-9ae1-d7b93b3a4f8c.json similarity index 100% rename from docs/outstanding-issues-inbox/e215905d-1639-4827-9ae1-d7b93b3a4f8c.json rename to docs/outstanding-issues-inbox/applied/e215905d-1639-4827-9ae1-d7b93b3a4f8c.json diff --git a/docs/outstanding-issues-inbox/e6228569-ebb7-4399-9702-8a15d49b75d8.json b/docs/outstanding-issues-inbox/applied/e6228569-ebb7-4399-9702-8a15d49b75d8.json similarity index 100% rename from docs/outstanding-issues-inbox/e6228569-ebb7-4399-9702-8a15d49b75d8.json rename to docs/outstanding-issues-inbox/applied/e6228569-ebb7-4399-9702-8a15d49b75d8.json diff --git a/docs/outstanding-issues-inbox/e6311a09-151a-4ffc-ae4f-52c06b4c2c3f.json b/docs/outstanding-issues-inbox/applied/e6311a09-151a-4ffc-ae4f-52c06b4c2c3f.json similarity index 100% rename from docs/outstanding-issues-inbox/e6311a09-151a-4ffc-ae4f-52c06b4c2c3f.json rename to docs/outstanding-issues-inbox/applied/e6311a09-151a-4ffc-ae4f-52c06b4c2c3f.json diff --git a/docs/outstanding-issues-inbox/eaa2e757-ad60-4fc7-abb5-58a1d381f0b1.json b/docs/outstanding-issues-inbox/applied/eaa2e757-ad60-4fc7-abb5-58a1d381f0b1.json similarity index 100% rename from docs/outstanding-issues-inbox/eaa2e757-ad60-4fc7-abb5-58a1d381f0b1.json rename to docs/outstanding-issues-inbox/applied/eaa2e757-ad60-4fc7-abb5-58a1d381f0b1.json diff --git a/docs/outstanding-issues-inbox/eb7a73ec-6fbd-4e6a-baae-0b2a77cd7dae.json b/docs/outstanding-issues-inbox/applied/eb7a73ec-6fbd-4e6a-baae-0b2a77cd7dae.json similarity index 100% rename from docs/outstanding-issues-inbox/eb7a73ec-6fbd-4e6a-baae-0b2a77cd7dae.json rename to docs/outstanding-issues-inbox/applied/eb7a73ec-6fbd-4e6a-baae-0b2a77cd7dae.json diff --git a/docs/outstanding-issues-inbox/ecd2dd27-b919-4419-9a2b-658bfcb39c36.json b/docs/outstanding-issues-inbox/applied/ecd2dd27-b919-4419-9a2b-658bfcb39c36.json similarity index 100% rename from docs/outstanding-issues-inbox/ecd2dd27-b919-4419-9a2b-658bfcb39c36.json rename to docs/outstanding-issues-inbox/applied/ecd2dd27-b919-4419-9a2b-658bfcb39c36.json diff --git a/docs/outstanding-issues-inbox/f0230f69-3616-465d-937f-348b0e28023b.json b/docs/outstanding-issues-inbox/applied/f0230f69-3616-465d-937f-348b0e28023b.json similarity index 100% rename from docs/outstanding-issues-inbox/f0230f69-3616-465d-937f-348b0e28023b.json rename to docs/outstanding-issues-inbox/applied/f0230f69-3616-465d-937f-348b0e28023b.json diff --git a/docs/outstanding-issues-inbox/ff1c21f4-fd46-4e58-919d-fdd9cea4ca59.json b/docs/outstanding-issues-inbox/applied/ff1c21f4-fd46-4e58-919d-fdd9cea4ca59.json similarity index 100% rename from docs/outstanding-issues-inbox/ff1c21f4-fd46-4e58-919d-fdd9cea4ca59.json rename to docs/outstanding-issues-inbox/applied/ff1c21f4-fd46-4e58-919d-fdd9cea4ca59.json diff --git a/docs/outstanding-issues-inbox/ff207c2c-8ed0-4e4b-bd75-797eb397c1f1.json b/docs/outstanding-issues-inbox/applied/ff207c2c-8ed0-4e4b-bd75-797eb397c1f1.json similarity index 100% rename from docs/outstanding-issues-inbox/ff207c2c-8ed0-4e4b-bd75-797eb397c1f1.json rename to docs/outstanding-issues-inbox/applied/ff207c2c-8ed0-4e4b-bd75-797eb397c1f1.json diff --git a/docs/outstanding-issues.md b/docs/outstanding-issues.md index 2a9ffd12d1..d360553266 100644 --- a/docs/outstanding-issues.md +++ b/docs/outstanding-issues.md @@ -53,51 +53,19 @@ removed after current-main verification; it is not missing recommended work. | Order | ID(s) | Acuity | Capability | When | Estimate | Outcome, gate, verification, and stopping condition | | ----: | -------------- | -------- | ------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | `#059` | A1 | Operator security + independent reviewer | Immediate approved security window | 1–3 hours plus verification | Verify every reported exposed credential (GitHub, OpenAI, Supabase service role/database, E2E) is retired; rotate anything still valid and update only intended secret stores. Never record values; stop before provider action without approval. | -| 2 | `#053` | A1 | Operator — legal/privacy | Start now; finish before real patient use/privacy-approved release | 4–8 hours internal; 1–6 weeks elapsed | Execute DPAs; decide ZDR/residency; obtain cache behavior in writing; review subprocessors; obtain APP 8 and APP 5/1 counsel sign-off. Do not change public copy before approval. | -| 3 | `#231` | A1 | Specialist — answer path + Operator | Immediate approved live investigation | 2–4 hours plus provider | Live answers degrade to source-only when `answerRouteBudgetMs.fast` (25000) binds while retrieval is healthy. Measure and fix the fast-route budget / generation timeout; keep conservative source-only fallback. **Gate:** focused answer-route tests offline first; live probe only with explicit provider approval. **Stop:** do not weaken quality gates to hide timeouts; flag RAG surfaces before edit. | -| 4 | `#024` | A2 | High — browser/Next diagnostics | Provider-free macOS Safari host available | 1–2 hours | Reproduce document-source fallbacks in Safari/STP without Playwright interception; capture `_rsc` response evidence. Treat as an app defect only if native Safari reproduces; otherwise return to the harness. Never suppress `pageerror` or change CORS without proof. | -| 5 | `#022` | A2 | Operator — clinical governance + Specialist | Policy implemented locally; hosted apply and human review pending | 1–2 hours apply; 0.5–1 day first ten | The auditable BMJ `third_party_reference_attested` policy, migration and top-ten evidence manifest are prepared without changing `clinical_validation_status=unverified`. A qualified operator must review evidence, apply the migration deliberately, attest eligible records, review the ten visible local documents, then remeasure warnings. | -| 6 | `#023` | A2 | Specialist — RAG/browser diagnostics | After next weekly/manual matrix green (audit no longer blocks it) | 1–2 hours | Capture one Firefox/WebKit scheduled/manual datapoint and disposition the human irrelevant-at-10 labels. Matrix is structurally unblocked from blocking audit; do not spend on another RAG run. | -| 7 | `#018` | A2 | Specialist — clinical RAG/retrieval | Lithium closed; ADHD/metabolic evidence debt remains | Corpus/operator follow-up | Lithium's bounded subject/row-aware fix passed its targeted answer plus the full 36-case retrieval and 44-case answer canaries. ADHD's expected CAMHS document remains absent and the surfaced chart has no accessible table; metabolic schedule evidence remains unavailable and its standalone classifier candidate was reverted. | -| 8 | `#001` | A2 | Specialist — retrieval/ranking | After rollout approval | 0.5–1 day plus canary | Keep semantic reranking off unless an approved ambiguity comparison preserves 36/36, recall 1.0, zero per-case regressions, and shows measured gain; otherwise record keep-off and stop. | -| 9 | `#025` | A2 | Operator — Railway/GitHub/chat/Supabase | Next approved observability window | 1–3 hours/channel | Choose owned deployment, CI, ingestion, and SLO alerts; mock first, then one approved controlled provider event/channel. The merged Supabase trigger remains inert until its verified inputs are configured. Stop without an accountable responder. | -| 10 | `#055` | A2 | Specialist release owner + Operator | Before next full-confidence release/handoff | 2–4 hours plus runtime | On one exact SHA, run local/provider gates, Firefox/WebKit, required hosted CI, and close actionable GitHub threads. Stop at first failure and rerun only the repaired smallest gate. | -| 11 | `#056` | A2 | Operator — Supabase/Railway + Specialist | Next approved staging schema window | 2–4 hours | Reconcile the existing healthy, empty staging tier's 24-migration history gap using the exact repository migration chain, then re-run indexing, health, identity and data-boundary proof. Never recreate it or copy production clinical documents. | -| 12 | `#057` | A2 | High — release/SRE + Operator | After `#056` | 2–4 hours plus soak | Run documented staging soak and rollback against an exact candidate. Retain latency/error/rollback evidence; stop on unsafe data, identity mismatch, or unowned rollback. | -| 13 | `#011` | A3 | Operator — Supabase capacity | Immediately before first compute scale-up | 30–60 min plus observation | Switch Auth to percentage allocation, record before/after, and run approved advisor/health checks. Stop if no scale-up is planned. | -| 14 | `#117` | A3 | High — frontend/perf + product | After per-field card-vs-search decision | 0.5–1 day once fields decided | Cut `/therapy-compass` mobile LCP by trimming or deferring the 690 KB `therapies-index.json` prose payload. Confirm each long-form field is card-rendered, search-matched, or neither before dropping it. Gate: `check:therapy-data-index`, therapy Playwright journeys, `verify:lighthouse`. **Stop:** do not strip fields without that confirmation. | -| 15 | `#118` | A3 | High — CI/visual/perf gates | After `#147` and `#117` (do not bake current breaches) | 2–4 hours | Commit the CI-uploaded visual baselines under the platform-scoped snapshot path, run `check:lighthouse-budget -- --update` on a known-good build, then flip `enforce` so `visual-baseline` and `lighthouse-budget` block. **Stop:** never commit baselines from a developer machine; never enforce while `#147`/`#117` still breach. | -| 16 | `#033` | A3 | Specialist — prompt/source governance | After `#022` and explicit evaluation approval | 1–2 days plus approved eval | Design unknown-vs-adverse metadata wording and prompt tests. Require no supported-grounding drop and zero citation failures; stop on broad over-caveating or degradation. | -| 17 | `#013`, `#016` | A3 | High — bundling/runtime performance | After `#147`/`#117` or equivalent evidence | 0.5–2 days/route | Optimize only a production route with measured payload/render/motion harm. Require material gain plus focused, `verify:cheap`, and browser evidence; stop on small gain. | -| 18 | `#035` | A3 | Specialist — evidence rules | After a demonstrated missed conflict | 0.5–1 day design; code separate | Define a clinically reviewed conflict class with positive and negative fixtures. Stop if no bounded class can be shown; behavior change requires protected review. | -| 19 | `#027` | Optional | Operator — SRE/provider | When an owned external alert path is wanted | 1–2 hours | Decide vendor/cost/privacy/owner; if accepted, prove one non-PHI outage and recovery alert. Stop when no responder owns it. | -| 20 | `#039` | Optional | High — frontend architecture | During a concrete catalogue-toolbar project | 0.5–1 day inventory; 1–3 days code | Converge only repeated toolbar behavior without flattening search semantics. Stop when there is no bounded implementation target. | -| 21 | `#079` | Optional | High — repository hygiene | In explicitly scheduled batches | 30–60 minutes per batch | Disposition at most ten retained worktrees per pass using owner, PR, review-ledger, ancestry, and patch evidence. Preserve every dirty, active, secret-bearing, post-freeze, or ambiguous worktree and stop rather than broad-cleaning. | -| 22 | `#098` | A3 | High — test infrastructure | Before `#099` or `#101`; it is their enabler | 2–4 hours | Generalise the answer-route preamble guard into a counting-proxy round-trip budget harness over the existing offline fixtures. Must enforce admission-before-scope, never the reverse. No providers, no DB. Stop if it would require live credentials. | -| 23 | `#102` | A3 | Operator — Supabase + Specialist | Next approved index window, after the ordering question is settled | 1–2 hours plus apply | Author the migration (operator SQL alone never reaches staging/DR/local replay), then apply → mirror `schema.sql` → regenerate drift manifest → register `required_indexes`. **Stop:** the RAG-path index is canary-gated, and ordering `fetchDocumentTitleAliasRows`'s unordered `.limit(12)` does not lift that — an imposed order can select a different twelve, so it is a second canary-gated change, not a way out of the first. The byte-identical claim was retracted. | -| 24 | `#099` | A3 | Specialist — answer path | After `#098` | Half a day per sub-item | Remaining fixed per-request round trips: the 8 `setCachedSearch` deferrals (abort semantics + mutation window), the anonymous subject+global limiter pair (needs a new atomic RPC first), and proxy→route identity duplication. Stop before hand-authoring locking SQL. | -| 25 | `#090` | A3 | High — eslint toolchain | When ESLint 10 plugin peers are compatible | blocked; revisit monthly | Upgrade the eslint ecosystem to clear remaining dev-scoped high advisories — full `npm audit` reports zero high advisories from the eslint toolchain. | -| 26 | `#100` | A3 | Specialist — answer streaming | After offline Phase 0/1 design proof | provider-gated rollout | Buffered answer generation has no incremental verified delivery — [`verified-answer-incremental-delivery-design.md`](verified-answer-incremental-delivery-design.md) records the clinical-governance decision and staged co… | -| 27 | `#150` | Optional | Operator — review tooling | Next CodeRabbit billing/policy decision | 30–60 min decision | CodeRabbit reviewed none of a full day's PRs; spending cap reached — the repo's second automated reviewer is either funded or acknowledged as absent, rather than appearing to review while skipping. | -| 28 | `#165` | A2 | High — clinical UI | Next answer-home UX pass | 0.5–1 day | Adopt a consolidated answer-home notice block — the studies exist, nothing adopts them — the answer hero states its safety obligation, its scope, and its verification requirement as one block in one voice. | -| 29 | `#168` | A3 | High — ledger architecture | With #156 / id-scheme redesign | design first | Sequential issue ids force every concurrent append to conflict — two sessions can append to this ledger at the same time without conflicting. | -| 30 | `#169` | A3 | High — git hygiene | Next branch cleanup batch | 1–2 hours | Local branches carry work that exists on no remote — committed work is not lost when a machine or worktree is reclaimed. | -| 31 | `#175` | A2 | Operator — clinical data + Standard | Next therapy catalogue curation window | 2–4 hours | Therapy modality is now null on all 205 records and needs curation or removal — the Therapy detail and recommend screens either show a curated modality or stop carrying the field at all. | -| 32 | `#036` | Optional | Specialist — privacy/schema | When visibility model is redesigned | design + migration | No explicit `is_public` visibility flag on documents — Public-corpus visibility is implicit: `owner_id IS NULL` on an `indexed` document (`resolveSearchScope`). The `metadata.public_corpus` marker is written by the prom… | -| 33 | `#101` | A3 | Specialist — RAG/retrieval | After #098 harness + canary approval | canary-gated | Canary-gated retrieval parallelisation candidates — metadata and memory hydration shipped in PR #1474; visual hydration, scope enumeration, typeahead caching, and universal-search coalescing remain, each behind the RAG flag and live-canary criteria. | -| 34 | `#190` | A3 | Specialist — RAG structure | On explicit X3 go-ahead | 1 PR per extraction unit | X3: Finish rag.ts monolith decomposition — `src/lib/rag/rag.ts` is decomposed into focused modules per `docs/maturity-backlog-workorders.md` X3, with existing offline RAG contracts green. | -| 35 | `#191` | A3 | Operator — DB + Specialist | Approved live-DB window only | provider-gated | X5: ACL-migration consolidation (provider-gated) — ACL-related migrations are consolidated per maturity work-order X5 without weakening owner-scope/RLS. | -| 36 | `#193` | A3 | High — src/lib structure | After/with X3 non-protected clusters | 1 PR per cluster | X7: Complete the remaining src/lib domain-directory reorg — remaining `src/lib` clusters sit in their domain directories per X7 follow-on to X2. | -| 37 | `#195` | A3 | Operator — GitHub maintainer | Maintainer UI window | 30–60 min | M1: Repo-host hardening (branch protection and required checks) — GitHub branch-protection rulesets and required checks match audit §8 / maturity M1. | -| 38 | `#183` | A2 | Operator — Sentry + Specialist | Next approved observability window with SENTRY_AUTH_TOKEN | 1–2 hours | Create Sentry metric alert for production DB span p95 > 500ms (`span.op:db`, environment production). **Stop:** no secret printing; blocked until token/env available. | -| 39 | `#206` | A2 | Specialist — answer UI contract | With AnswerState producer work (`#207`) | 2–4 hours | `partial_retrieval` has no app-facing producer — decide RAG contract vs UI-only mapping before AnswerCard. **Stop:** no retrieval behaviour change without RAG flag. | -| 40 | `#211` | A3 | High — TypeScript strictness | Dedicated migration branch | multi-PR | Plan and start `noUncheckedIndexedAccess` migration (1266 errors); highest-risk files first. **Stop:** do not flip the flag on main without a staged plan. | -| 41 | `#235` | A3 | High — design-system evidence | Next warmed local proof-shot pass | 1–2 hours | Capture missing ADOPTION.md §7 proof shots for adopted surfaces. **Stop:** not visual-baseline PNGs (`#118`); no Playwright snapshot commit. | -| 42 | `#239` | Optional | High — phone chrome | When phone orientation QA is available | 15–30 min | Manual phone rotation check for ResizeObserver-only phone chrome reserve. **Gate:** `verify:phone-chrome` still owns automated coverage. **Stop:** do not widen reserve heuristics without reproduction. | -| 43 | `#240` | Optional | High — design tokens | Next design-owner review | 15–30 min | Confirm tooltip visual hard-clip asymmetry with design owner (sr-only keeps full text). **Stop:** no product change without that confirmation. | -| 44 | `#242` | A2 | High — design-system baselines | After human review of Linux baselines | 1–2 hours | Commit approved Linux visual baselines and promote adoption not-committed → committed. **Stop:** never commit baselines from an unreviewed machine run. | -| 45 | `#248` | A2 | Operator — Supabase + Specialist | After PR #1614 symptom repair; approved live/history window | 1–2 hours | Investigate why 20260705180000 search-health indexes were missing on live despite applied history; decide if drift checks should catch this class. **Stop:** no hosted mutation without approval. | +| 1 | `#231` | A1 | Specialist — answer path + Operator | Immediate approved live investigation | 2–4 hours plus provider | Live answers degrade to source-only when `answerRouteBudgetMs.fast` (25000) binds while retrieval is healthy. Measure and fix the fast-route budget / generation timeout; keep conservative source-only fallback. **Gate:** focused answer-route tests offline first; live probe only with explicit provider approval. **Stop:** do not weaken quality gates to hide timeouts; flag RAG surfaces before edit. | +| 2 | `#023` | A2 | Specialist — RAG/browser diagnostics | After next weekly/manual matrix green (audit no longer blocks it) | 1–2 hours | Capture one Firefox/WebKit scheduled/manual datapoint and disposition the human irrelevant-at-10 labels. Matrix is structurally unblocked from blocking audit; do not spend on another RAG run. | +| 3 | `#018` | A2 | Specialist — clinical RAG/retrieval | Lithium closed; ADHD/metabolic evidence debt remains | Corpus/operator follow-up | Lithium's bounded subject/row-aware fix passed its targeted answer plus the full 36-case retrieval and 44-case answer canaries. ADHD's expected CAMHS document remains absent and the surfaced chart has no accessible table; metabolic schedule evidence remains unavailable and its standalone classifier candidate was reverted. | +| 4 | `#001` | A2 | Specialist — retrieval/ranking | After rollout approval | 0.5–1 day plus canary | Keep semantic reranking off unless an approved ambiguity comparison preserves 36/36, recall 1.0, zero per-case regressions, and shows measured gain; otherwise record keep-off and stop. | +| 5 | `#055` | A2 | Specialist release owner + Operator | Before next full-confidence release/handoff | 2–4 hours plus runtime | On one exact SHA, run local/provider gates, Firefox/WebKit, required hosted CI, and close actionable GitHub threads. Stop at first failure and rerun only the repaired smallest gate. | +| 6 | `#056` | A2 | Operator — Supabase/Railway + Specialist | Next approved staging schema window | 2–4 hours | Reconcile the existing healthy, empty staging tier's 24-migration history gap using the exact repository migration chain, then re-run indexing, health, identity and data-boundary proof. Never recreate it or copy production clinical documents. | +| 7 | `#057` | A2 | High — release/SRE + Operator | After `#056` | 2–4 hours plus soak | Run documented staging soak and rollback against an exact candidate. Retain latency/error/rollback evidence; stop on unsafe data, identity mismatch, or unowned rollback. | +| 8 | `#102` | A3 | Operator — Supabase + Specialist | Next approved index window, after the ordering question is settled | 1–2 hours plus apply | Author the migration (operator SQL alone never reaches staging/DR/local replay), then apply → mirror `schema.sql` → regenerate drift manifest → register `required_indexes`. **Stop:** the RAG-path index is canary-gated, and ordering `fetchDocumentTitleAliasRows`'s unordered `.limit(12)` does not lift that — an imposed order can select a different twelve, so it is a second canary-gated change, not a way out of the first. The byte-identical claim was retracted. | +| 9 | `#099` | A3 | Specialist — answer path | After `#098` | Half a day per sub-item | Remaining fixed per-request round trips: the 8 `setCachedSearch` deferrals (abort semantics + mutation window), the anonymous subject+global limiter pair (needs a new atomic RPC first), and proxy→route identity duplication. Stop before hand-authoring locking SQL. | +| 10 | `#100` | A3 | Specialist — answer streaming | After offline Phase 0/1 design proof | provider-gated rollout | Buffered answer generation has no incremental verified delivery — [`verified-answer-incremental-delivery-design.md`](verified-answer-incremental-delivery-design.md) records the clinical-governance decision and staged co… | +| 11 | `#191` | A3 | Operator — DB + Specialist | Approved live-DB window only | provider-gated | X5: ACL-migration consolidation (provider-gated) — ACL-related migrations are consolidated per maturity work-order X5 without weakening owner-scope/RLS. | +| 12 | `#183` | A2 | Operator — Sentry + Specialist | Next approved observability window with SENTRY_AUTH_TOKEN | 1–2 hours | Create Sentry metric alert for production DB span p95 > 500ms (`span.op:db`, environment production). **Stop:** no secret printing; blocked until token/env available. | +| 13 | `#248` | A2 | Operator — Supabase + Specialist | After PR #1614 symptom repair; approved live/history window | 1–2 hours | Investigate why 20260705180000 search-health indexes were missing on live despite applied history; decide if drift checks should catch this class. **Stop:** no hosted mutation without approval. | @@ -118,93 +86,32 @@ removed after current-main verification; it is not missing recommended work. | ID | Pri | Type | Summary | Detail / next action | Source | Added | | ---- | --- | ----- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | -| #059 | P1 | task | Verify containment of every credential reported exposed in chat | **Outcome:** every reported exposed credential is rejected or retired. **Next:** in approved security windows, verify and revoke or rotate the GitHub token, OpenAI key, Supabase service-role JWT, database password, and E2E credential; create replacements only when required and update only intended secret stores. **Success:** provider evidence confirms the old credentials cannot authenticate, replacements are distinct and minimally scoped, presence/readiness checks pass, and secret scans remain clean. **Stop:** no provider or secret-store action without approval; never print or paste values into Git, logs, issues, or chat. | session 2026-07-24 security reconciliation; AI Agent Target Manifest | 2026-07-24 | | #001 | P2 | task | Semantic reranking still gated off | `RAG_SEMANTIC_RERANK_ENABLED=false` from PR #901. Do not enable until the provider-backed 36/36 retrieval-quality gate **and** an ambiguity-focused canary are explicitly approved and recorded. | `docs/process-hardening.md` (Semantic reranking rollout debt); PR #901 | 2026-07-21 | -| #053 | P1 | task | Execute cross-border privacy/legal package | Execute OpenAI and Railway DPAs; decide ZDR and Australian data residency; obtain prompt-cache behavior in writing; review subprocessors; obtain APP 8 and APP 5/1 counsel sign-off. Do not represent the release as privacy-approved or alter final public privacy wording before sign-off. | `docs/openai-cross-border-basis.md`; `docs/privacy-impact-assessment.md` | 2026-07-24 | | #055 | P2 | task | Run one exact-SHA full release and PR gate | Before the next full-confidence release/handoff, record the candidate/PR SHA and run the local/provider release gates, Firefox/WebKit, required hosted CI, and actionable GitHub review-thread closure once. Stop at the first actionable failure and rerun only the repaired smallest gate. | `docs/launch-operator-runbook.md`; `docs/codex-review-protocol.md` | 2026-07-24 | -| #056 | P2 | task | Reconcile the existing staging migration history | PHASE 2 RUN 2026-08-18 in an owner-authorized staging window. REPLAY COMPLETE AND PROVEN; check:drift now RUN and RED with 19 findings, which is the substantive result of this phase. Target Clinical KB Staging ref ikoiolksxqxfxgiyqpnu via the Supabase MCP connector, ref re-verified on every call; production sjrfecxgysukkwxsowpy was never a mutation target and the only production interaction was list_projects. GAP re-measured at the start of the window as 28, not the 26 recorded 2026-08-17: 166 staging rows against 194 repository files, being ten earlier history holes plus eighteen versions after 20260719055623. The chain was replayed in version order; staging now holds 194 rows, latest 20260814151000, zero statements IS NULL, and a two-way version diff against supabase/migrations is empty both ways. Every replayed row was read back and md5-compared against the repository file: all 28 match byte-for-byte. supabase db push was unavailable (SUPABASE_ACCESS_TOKEN absent per #183, DB password operator-only) and MCP apply_migration was rejected because it stamps connector-generated versions, which docs/staging-setup.md forbids; each migration ran verbatim through execute_sql with an explicit schema_migrations row carrying the repository version and name. No production clinical document was copied and no worker started: documents and document_chunks remain 0. DRIFT RESULT: 19 unexpected rows, exit 1. Because staging now carries the complete byte-verified chain, this is not staging staleness - it is the committed migration chain and supabase/schema.sql disagreeing, and check:drift builds its expected side from schema.sql. Decomposition: (a) seven match_* def_hash mismatches caused by SET work_mem, which pg_get_functiondef renders and def_hash does not strip; grep -c work_mem supabase/schema.sql returns 0 and only migration 20260724000000 sets it, so schema.sql is the stale side and the fix is repo-side, not a production deploy. The eighth work_mem target, match_document_table_facts_text, is absent from the drift list precisely because 20260724120000 re-created it without restating work_mem, which confirms the mechanism. (b) eight objects schema.sql declares that no migration creates or drops - five document_embedding_fields indexes, documents_status_idx, and the documents_updated_at and ingestion_jobs_updated_at set_updated_at triggers; the two triggers mean updated_at maintenance would silently not exist in any environment built from migrations alone. (c) three table column-set mismatches on document_chunks, rag_visual_eval_cases and rag_visual_eval_runs, not yet expanded per column. (d) one index def mismatch on document_chunks_content_trgm_idx, which is one of the two trigram indexes rebuilt in the 2026-08-14 production incident window and whose canonical definition should be confirmed against what was actually built. PROGRAMME CONSEQUENCE: until schema.sql and the chain are reconciled, a production drift finding cannot be assumed to mean production drifted; for the seven work_mem functions the opposite holds. This argues for reconciling schema.sql to the chain before spending a production window on Phase 3. BEARING ON #316: that row carries the work_mem explanation as an untested hypothesis about production's ten mismatched RPCs; it is now measured on staging for seven of them with no production call. It does not close Phase 1.2 - production reports ten, staging seven, and the residual (match_document_table_facts_text plus the _v2 outliers match_document_chunks_text_v2 and match_document_index_units_hybrid_v2) needs its own diffs. #316 was deliberately not updated from this session. ALSO FIXED HERE: scripts/check-drift.ts forwarded only three of five identity keys to checkSupabaseProjectConfig, so any staging URL resolved to production and was rejected as a mismatch; proven before and after against identical env (before: mismatch/production/sjrfecxgysukkwxsowpy, after: ready/staging/ikoiolksxqxfxgiyqpnu). Six clean-replay findings are recorded in docs/audit/live-drift-forensics-2026-08.md section Phase 2, none patched, no migration edited. #057 soak and rollback is now unblocked on parity grounds, though the drift reconciliation above should land first. | current-main staging verification; `docs/staging-setup.md`; `docs/operator-backlog.md` | 2026-07-27 | +| #056 | P2 | task | Reconcile the existing staging migration history | PHASE 2 RUN 2026-08-18 in an owner-authorized staging window. REPLAY COMPLETE AND PROVEN; check:drift now RUN and RED with 19 findings, which is the substantive result of this phase. Target Clinical KB Staging ref ikoiolksxqxfxgiyqpnu via the Supabase MCP connector, ref re-verified on every call; production sjrfecxgysukkwxsowpy was never a mutation target and the only production interaction was list_projects. GAP re-measured at the start of the window as 28, not the 26 recorded 2026-08-17: 166 staging rows against 194 repository files, being ten earlier history holes plus eighteen versions after 20260719055623. The chain was replayed in version order; staging now holds 194 rows, latest 20260814151000, zero statements IS NULL, and a two-way version diff against supabase/migrations is empty both ways. Every replayed row was read back and md5-compared against the repository file: all 28 match byte-for-byte. supabase db push was unavailable (SUPABASE_ACCESS_TOKEN absent per #183, DB password operator-only) and MCP apply_migration was rejected because it stamps connector-generated versions, which docs/staging-setup.md forbids; each migration ran verbatim through execute_sql with an explicit schema_migrations row carrying the repository version and name. No production clinical document was copied and no worker started: documents and document_chunks remain 0. DRIFT RESULT: 19 unexpected rows, exit 1. Because staging now carries the complete byte-verified chain, this is not staging staleness - it is the committed migration chain and supabase/schema.sql disagreeing, and check:drift builds its expected side from schema.sql. Decomposition: (a) seven match_* def_hash mismatches caused by SET work_mem, which pg_get_functiondef renders and def_hash does not strip; grep -c work_mem supabase/schema.sql returns 0 and only migration 20260724000000 sets it, so schema.sql is the stale side and the fix is repo-side, not a production deploy. The eighth work_mem target, match_document_table_facts_text, is absent from the drift list precisely because 20260724120000 re-created it without restating work_mem, which confirms the mechanism. (b) eight objects schema.sql declares that no migration creates or drops - five document_embedding_fields indexes, documents_status_idx, and the documents_updated_at and ingestion_jobs_updated_at set_updated_at triggers; the two triggers mean updated_at maintenance would silently not exist in any environment built from migrations alone. (c) three table column-set mismatches on document_chunks, rag_visual_eval_cases and rag_visual_eval_runs, not yet expanded per column. (d) one index def mismatch on document_chunks_content_trgm_idx, which is one of the two trigram indexes rebuilt in the 2026-08-14 production incident window and whose canonical definition should be confirmed against what was actually built. PROGRAMME CONSEQUENCE: until schema.sql and the chain are reconciled, a production drift finding cannot be assumed to mean production drifted; for the seven work_mem functions the opposite holds. This argues for reconciling schema.sql to the chain before spending a production window on Phase 3. BEARING ON #316: that row carries the work_mem explanation as an untested hypothesis about production's ten mismatched RPCs; it is now measured on staging for seven of them with no production call. It does not close Phase 1.2 - production reports ten, staging seven, and the residual (match_document_table_facts_text plus the _v2 outliers match_document_chunks_text_v2 and match_document_index_units_hybrid_v2) needs its own diffs. #316 was deliberately not updated from this session. ALSO FIXED HERE: scripts/check-drift.ts forwarded only three of five identity keys to checkSupabaseProjectConfig, so any staging URL resolved to production and was rejected as a mismatch; proven before and after against identical env (before: mismatch/production/sjrfecxgysukkwxsowpy, after: ready/staging/ikoiolksxqxfxgiyqpnu). Six clean-replay findings are recorded in docs/audit/live-drift-forensics-2026-08.md section Phase 2, none patched, no migration edited. #057 soak and rollback is now unblocked on parity grounds, though the drift reconciliation above should land first. RE-MEASURED 2026-08-18 at main 4551b6e4d in a second owner-authorized staging window (same target ikoiolksxqxfxgiyqpnu, ref verified before every call; production sjrfecxgysukkwxsowpy never a target; measurement only, no drift finding fixed, no vault secret seeded). The count is UNCHANGED AT 19. Between the Phase 2 base ed43a64f2 and 4551b6e4d exactly one commit touched supabase/: 9c660af1f (PR #2058, Phase 6), which added 20260818090000_schema_drift_snapshot_history_probe.sql - the migration that redefines schema_drift_snapshot() itself - plus a regenerated schema.sql, a regenerated drift-manifest.json and five migration_history allowlist entries. Before-gap was exactly one version: staging held 194 rows against 195 repository files, missing only 20260818090000, which is NOT one of the duplicate earlier/later pairs of Phase 2 finding 2, so the stop-and-report condition did not arise. It was applied by the Phase 2 method (execute_sql of the file content verbatim plus an explicit history row carrying the repository version and name; apply_migration was not used because it stamps connector-generated versions, which docs/staging-setup.md forbids) and read back byte-identical: md5 839bed0b741cb75b79f6eb0c46ed0a50, 9034 bytes. Staging now holds 195 rows, latest 20260818090000, zero statements IS NULL, an empty two-way diff against supabase/migrations, and documents/document_chunks still 0. check:drift then ran against staging with the current manifest (generated 2026-08-17T16:38:39.818Z from schema.sql a6fb923400f8, against Phase 2's 2026-08-16T14:37:41.042Z / 365e3368a47b) and exited 1 with the SAME 19 findings: same categories, same keys, same manifest/live hash pairs, and an identically sized compared inventory. Line by line: (a) seven match_* work_mem def_hash mismatches persist as the same seven, with match_document_table_facts_text still absent and staging still carrying work_mem on 7 not 8 functions, re-confirming Phase 2 finding 3 on the current chain; (b) the same eight schema.sql-only objects; (c) the same three table column-set mismatches; (d) the same document_chunks_content_trgm_idx hash pair 8499c3d3 vs c3db2960. Nothing new appeared and nothing changed category. TWO NEW OBSERVATIONS, NEITHER A DRIFT FINDING. First, the snapshot v2 migration_history block is live and clean: probe reports ok and returns zero rows, so the new category contributes 0 findings - the expected result for an environment built by a faithful replay, and evidence the probe runs end-to-end against a real database, not evidence that production is clean (production has not been measured with v2). Second, five migration_history allowlist entries (20260701010000, 20260701020000, 20260701030000, 20260701060000, 20260702000000, all guard.class superseded, added by PR #2058) report STALE against staging because those history-repair rows are production's; this is a warning, the run still exits 1 solely on the 19, and check:drift --prune-stale must NOT be run against staging because it would delete production-scoped entries. POSITIVE CONFIRMATION: schema_drift_snapshot itself does not appear among the seven function mismatches, which before this window was impossible to observe (staging carried v1 while the manifest carried v2) - direct evidence that PR #2058's migration body and the schema.sql mirror regenerated from it agree. Per #292 the six open PRs at the time (#2096, #2095, #2086, #2012, #2011, #2010) were checked and none touches supabase/migrations/** or staging. Full evidence: docs/audit/live-drift-forensics-2026-08.md section 2.5. #316 was deliberately not touched. | current-main staging verification; `docs/staging-setup.md`; `docs/operator-backlog.md` | 2026-07-27 | | #057 | P2 | task | Complete staging soak and rollback rehearsal | After #056, run the documented soak and rollback against an exact candidate; retain latency/error/rollback evidence. Stop on unsafe data, identity mismatch, or an unowned rollback decision. | `docs/launch-operator-runbook.md`; `docs/audit/capacity-review.md` | 2026-07-24 | -| #011 | P3 | task | Auth DB-connection allocation is operator-only | Supabase Auth (GoTrue) is capped at ~10 absolute DB connections (Supabase perf advisor). Switch to **percentage-based** allocation in the Supabase **dashboard** before the first compute scale-up — **not settable via SQL/MCP** (operator-owned). Verify via a staging soak + an approval-gated read-only advisor re-check. | `docs/auth-connection-cap-runbook.md`; `docs/process-hardening.md` (Known follow-up debts) | 2026-07-21 | -| #013 | P3 | rec | Route catalogue weight remains measurement-gated; public field INP is unavailable | Keep the payload work open, but correct the measurement state: on 2026-08-13 the official Chrome UX Report current-record API returned 404 no-data for the psychiatry.tools origin and every reviewed URL (root, Therapy, Documents search, DSM, Forms, Services, Specifiers, and Formulation). Field INP is therefore unavailable because the site does not meet CrUX eligibility/coverage, not unverified and not a pass. The production app deliberately has no browser Sentry bundle, so adding RUM would expand the approved telemetry and privacy envelope. Next: continue lab LCP/TBT and interaction traces; request a separate privacy/operator decision before adding browser RUM, or recheck CrUX after traffic eligibility changes. Do not block route payload fixes waiting for a field dataset that does not exist, and do not infer an INP pass from absence. | session 2026-08-13 official CrUX current-record queries; https://cruxvis.withgoogle.com/ | 2026-07-21 | -| #016 | P3 | rec | "Big but not easy" structural + motion perf | **DEPRIORITISED 2026-08-12 (yield review against current main).** A grab-bag of five deferred perf levers, each individually gated on a measurement or a rethink. Split it or leave it parked; as one row it cannot be started. Deferred larger levers: (a) nonce-CSP forces every product route to `╞Æ Dynamic` (zero static generation) — evaluate Partial Prerendering / static shells for the static clinical catalogues (DSM/differentials/therapy/specifiers/formulation); (b) sidebar expand/collapse animates `grid-template-columns` (biggest smoothness cost, motion-gated — needs a transform-overlay rethink); (c) Therapy Compass fetches 692 KB / 2.5 MB JSON client-side (defer until interaction + confirm brotli); (d) settings/setup/admin dialogs static-imported into the home chunk (`next/dynamic` them); (e) **DONE 2026-08-01 in PR-T (ds-v2 therapy teardown):** deleted `therapy-compass.css` and removed its route-group layout import — no longer render-blocking on `/`, `/documents`, `/forms`, `/dsm` and every mode home; (f) `shared-search-app-shell.tsx:8` statically imports the `therapy-compass` barrel, pulling `workspace.tsx` + `bindings.tsx` + `nav.tsx` into every `(search-app)` route; (g) three client waterfalls (`use-app-preferences.ts:156-182`, `ClinicalDashboard.tsx:977-1069`, `signed-image.tsx:60-84` + `use-signed-image-url.ts:39`) and the paint offenders in `globals.css` beyond the sidebar grid — three stacked `backdrop-filter` passes on an always-mounted translating element (`:709-748`), `box-shadow` inside a `transition` list (`:677-684`), and `@keyframes shimmer` animating `background-position` on the shared `Skeleton` (`:2289-2296`). **CORRECTED 2026-07-29 on (c):** the Therapy Compass filenames are unversioned and Next serves `/public` with an ETag, so only the FIRST visit pays 690.6 KB / 2,470 KB — repeat visits pay ~4 revalidation round trips. The fix is content-hashed filenames + `immutable` (touching `scripts/build-therapies-index.mjs` and `check:therapy-data-index`), NOT a bare `Cache-Control` line. See `docs/audit/latency-audit-2026-07-28.md` L3-1/L3-2/L3-3/L3-6/L3-7. | session 2026-07-21 (build route table + design audit) | 2026-07-21 | | #018 | P2 | task | Split the lithium, ADHD and metabolic residuals by mechanism | Current evidence keeps the mechanisms separate. **Lithium — closed within this item:** the row/atom-aware subject guard, foreign-parameter rejection and query-specific range promotion returned `0.5–1.0 mmol/L` with correct targeting/citation; the full retrieval canary remained 36/36 with recall 1.0 and zero per-case RR regressions, and the full answer canary passed every blocking gate. **ADHD — open corpus debt:** `CG.MHSP.ADHD.pdf` is absent from the hosted corpus and the retrieved chart exposes `accessible_table_count=0`; repair corpus/fixture or ingestion evidence rather than weakening extractive budgets. **Metabolic — open structured-evidence debt:** the standalone plural classifier worsened the live answer and was reverted; obtain auditable schedule text/table evidence before another candidate. | targeted live lithium/ADHD/metabolic evidence 2026-07-27; `docs/evidence/rag-reliability-evidence-2026-07-27.md`; refuted approaches | 2026-07-21 | -| #022 | P2 | task | Source-governance metadata refresh (operator) | The selected policy is now encoded locally as auditable `third_party_reference_attested` evidence with policy version, reviewer qualification, evidence references and append-only review history. It deliberately preserves `clinical_validation_status=unverified`; malformed, stale or non-BMJ evidence remains review debt. Migration `20260727010000_bmj_third_party_source_attestation.sql` is prepared but was **not applied**. The ten most visible local-document candidates are captured in `docs/evidence/rag-top-local-review-manifest-2026-07-26.json` with `attestation_applied=false`; qualified human review, deliberate hosted apply/attestation, and warning-rate remeasurement remain operator work. | governance worklist; local policy/migration tests; top-ten evidence manifest | 2026-07-21 | | #023 | P2 | task | Complete scheduled browser and labeling disposition | **Partial 2026-07-30:** `release-browser-matrix` no longer depends on `pr-required`, so a blocking scheduled dependency audit cannot skip Firefox/WebKit. Still need one green matrix datapoint + human irrelevant-at-10 disposition. The 2026-07-26 retrieval and answer artifacts are read and compared under resolved #051. Scheduled CI run `30216361999` failed its existing production dependency audit before Firefox/WebKit, while production Chromium passed. After that audit is green, capture one scheduled/manual browser-matrix datapoint; separately record the human decision for the stable irrelevant-at-10 set. #084 now makes each top-10 grade and matched signal reproducible, but it does not substitute for the human disposition. Do not rerun or spend on RAG for this item. | runs `30216191889`/`30216361999`; per-rank diagnostics #084; session 2026-07-27 | 2026-07-21 | -| #024 | P2 | issue | WebKit e2e `_rsc` prefetch access-control errors | PR #1205 narrowed catch-all interception and duplicate navigation, but Next 16.2.11 still raises `_rsc` access-control `pageerror`s after document-source fallbacks: `/documents/source?id=&page=2&chunk=safety%20plan` → `/documents/?page=2&chunk=safety+plan`; `/documents/source/evidence?id=not-a-uuid&page=2` → `/documents/search`. The invalid-id failure survived removing every Playwright route; Chromium passed both. **Next:** on a provider-free macOS host, run both URLs in stable Safari and Safari Technology Preview without interception, capture console text plus `_rsc` status/access-control headers, and compare Playwright WebKit with routing on/off. Treat as an app defect only if native Safari reproduces; otherwise return to the harness. Never suppress `pageerror` or change CORS without native evidence. | PRs #1179/#1205; current-main local WebKit evidence; session 2026-07-28 | 2026-07-28 | -| #025 | P2 | task | Activate the three webhooks (operator secrets) | Merged (#968/#1100) + deployed but inert — verified live: `POST /api/webhooks/railway` returns `503 webhook_not_configured`; the Supabase document-change trigger exists but lacks both activation inputs. To turn on: (1) Railway ΓåÆ set `RAILWAY_WEBHOOK_SECRET` + add the `?token=…` webhook URL; (2) set `SLACK_WEBHOOK_URL`/`DISCORD_WEBHOOK_URL` in BOTH the Railway **app/server env** and **GitHub repo secrets**; (3) set one matching document-change secret in the Railway app env as `SUPABASE_INGESTION_WEBHOOK_SECRET` and in Supabase Vault as `ingestion_webhook_secret`, then set the per-environment database GUC `app.ingestion_webhook_base_url` to the deployed app origin. Each path fails closed until fully configured, so this is pure ops. See `docs/webhooks.md` for verification and rotation. | sessions 2026-07-22/24; PRs #968/#1100; docs/webhooks.md | 2026-07-22 | -| #027 | P3 | rec | External uptime monitor independent of GitHub/Railway | **DEPRIORITISED 2026-08-12 (yield review against current main).** Off-platform uptime monitoring for a single-user prototype that is not in clinical use and has no availability commitment to anyone. Revisit when there is a user who would notice an outage. `live-domain-monitor.yml` runs on GitHub's cron, so it won't run in exactly the outage it should catch (Actions or the deploy itself down). Add an off-platform synthetic monitor (UptimeRobot / Better Stack / Checkly) hitting `/api/health` with a webhook alert. Provider setup, not code. | session 2026-07-22 webhook review | 2026-07-22 | -| #033 | P3 | rec | Source governance metadata absent from the LLM prompt | **DEPRIORITISED 2026-08-12 (yield review against current main).** The row's own analysis argues against acting: on a partially-enriched corpus the model would likely over-caveat correct sources, and finding out costs a provider eval. Keep as a finding. `buildRagSourceBlock` omits `document_status`, `clinical_validation_status`, and `extraction_quality`, so the model cannot self-caveat during generation and governance is enforced only post-hoc. Generation-surface change: needs `eval:rag` plus `eval:quality --rag-only` (grounded-supported must not drop, citation-failure 0) and explicit approval. Carries the same "unknown Γëá bad" hazard as #032 — on a partially-enriched corpus the model would likely over-caveat correct sources, so design the prompt wording before spending an eval. | `src/lib/rag/rag-source-block.ts:126-198`; PR #1051 audit item 8 | 2026-07-22 | -| #035 | P3 | rec | Threshold-conflict detection covers only 3 params | **DEPRIORITISED 2026-08-12 (yield review against current main).** Deliberately narrow by design, with a code comment saying so, and broadening it carries real false-positive risk on a clinical warning path. Keep as a finding, not queued work. `detectThresholdDisagreements` checks only ANC, WBC, and platelets paired with withholding verbs, so cross-source conflicts on medication doses, lithium/thyroid levels, or vital signs go undetected. Deliberately narrow (see the comment at `:469-474`). Broadening changes when an answer is classified `conflicting` and adds warnings — real false-positive risk. Needs new fixtures plus a behaviour review before any change. | `src/lib/evidence.ts:469-574`; PR #1051 audit item 7 | 2026-07-22 | -| #036 | P3 | rec | No explicit `is_public` visibility flag on documents | **DEPRIORITISED 2026-08-12 (yield review against current main).** A compensating control already exists (unverified_source stays in the frontend-visible warning set) and the change touches RLS plus the clinical-risk-gated retrieval RPCs. Cost and blast radius exceed the residual risk. Public-corpus visibility is implicit: `owner_id IS NULL` on an `indexed` document (`resolveSearchScope`). The `metadata.public_corpus` marker is written by the promotion migrations but never used as a retrieval filter. Promotion is unconditional on `clinical_validation_status`, so unverified documents are publicly searchable — compensated by keeping `unverified_source` in the frontend-visible warning set. A hard schema flag touches RLS and the clinical-risk-gated retrieval RPCs; weigh against the existing compensating control before acting. | `supabase/schema.sql:61-108`; `src/lib/search-scope.ts:181-236`; PR #1051 audit item 3 | 2026-07-22 | -| #039 | P3 | rec | Consolidate catalogue toolbar patterns | **DEPRIORITISED 2026-08-12 (yield review against current main).** States an intent (converge repeated toolbar behaviour) with no measured defect and no named surfaces. Needs a concrete inventory before it is work. Catalogue/search pages have independently evolved filter, sort, result-count and mobile toolbar behavior. Inventory the existing implementations and converge only the repeated interaction contract; do not flatten mode-specific search semantics. | design audit reconciliation; session 2026-07-22 | 2026-07-22 | -| #079 | P3 | task | Disposition retained worktrees in bounded cleanup batches | **Outcome:** the retained reconciliation tail is gradually classified without another disruptive all-worktree sweep. **Next:** after the primary checkout is clean and `npm run check:primary-checkout-lease` allows writes, revalidate and remove the twenty clean redundant candidates recorded on 2026-07-30 with `branch-cleanup-deletion-pending`; then process no more than ten further worktrees per explicitly scheduled pass using current owner/process metadata, open-PR state, exact review-ledger coverage, ancestry, and cherry-pick-aware content proof. **Success:** remove only clean, inactive, bundled worktrees whose content is merged or explicitly rejected; record every disposition and retain recovery evidence. **Stop:** preserve dirty, active, secret-bearing, post-freeze, paused, or ambiguous work and never use reset, force deletion, broad clean, or process killing. | final reconciliation inventory retained 104 independent worktrees; session 2026-07-24; 2026-07-30 bounded review found 20 redundant candidates across two bounded batches but the primary-dirty write lease blocked removal | 2026-07-30 | -| #090 | P3 | task | Upgrade the eslint ecosystem to clear remaining dev-scoped high advisories | **DEPRIORITISED 2026-08-12 (yield review against current main).** Blocked upstream on three plugins publishing ESLint 10 support, and the advisories are dev-scoped only with no runtime or user impact. A recheck reminder, not work. **Outcome:** full `npm audit` reports zero high advisories from the eslint toolchain. **Blocked 2026-07-30:** the stable ecosystem still has no compatible ESLint 10 set. `eslint-config-next@16.2.12` permits ESLint 10 but bundles `eslint-plugin-react@7.37.5`, `eslint-plugin-import@2.32.0`, and `eslint-plugin-jsx-a11y@6.10.2`; each plugin's published peer range still ends at ESLint 9, and the React plugin retains the previously reproduced removed-context-API crash. Keep the Dependabot major hold and ESLint `9.39.5`; do not force an invalid peer graph merely to make the audit report green. **Next:** recheck after those three plugins publish stable ESLint 10 support, then upgrade eslint and the complete plugin/config set together. Residual highs (`@eslint/config-array`, `@eslint/eslintrc`, `eslint`, `eslint-config-next`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y`, plus the advisory's numeric `<=5.0.7` hit on the unused `brace-expansion@1.1.16` / `2.1.2` maintenance lines that still ship an unpatched `main`) cascade from this dev-only toolchain. **Success:** peer-valid install, `npm run lint` clean, `verify:cheap` green, full-audit highs cleared, no rule-config regressions. **Stop:** do not use `npm audit fix --force` or override plugin peer ranges. Production `npm audit --omit=dev` is already clean after the exceljs `archiver@8` / `unzipper@0.12.5` overrides on PR #1314. | stable npm metadata recheck 2026-07-30; session 2026-07-28 brace-expansion triage (PR #1314) | 2026-07-30 | -| #098 | P2 | task | Offline round-trip budget harness for the hot routes | UPDATE 2026-08-16: residual (a) is complete on current main via commit 563ce4195512b9e623df6ba98762f4a3dc1b9e8e. tests/search-route-round-trip-budget.test.ts now drives POST /api/search with a counted Supabase client and pins the successful-request route budget plus the limiter-only denial path, so route preamble and post-processing traffic are covered. Keep this row open: residual (c) is still unresolved. scripts/eval-rag-offline.mjs and scripts/test-rag-offline.mjs remain unwired, and the new route-level test is not registered in scripts/fixtures/rag-offline-contract-tests.json. Decide explicitly whether the offline contract runner is the canonical home and register this route-level budget there, or wire the legacy scripts. The prior stop against wholesale collapsing the three lexical variants remains unchanged; any later latency change still needs a materially different approach or a real canary pair. Stop: do not close #098 until the runner decision is implemented and recorded. | Commit 563ce4195512b9e623df6ba98762f4a3dc1b9e8e; tests/search-route-round-trip-budget.test.ts; scripts/fixtures/rag-offline-contract-tests.json | 2026-07-29 | | #099 | P2 | task | Remove the remaining fixed per-request round trips | **Outcome:** the answer path stops paying avoidable per-request Supabase round trips. **Done 2026-07-29:** shared-cache-hit promotion deferred off the response path with its mid-request staleness guard intact and documented (`rag.ts:3234`, `rag-cache.ts`); scope resolution overlapped with the rate-limit RPC, signal threaded so a client disconnect finally cancels its paginated queries (`answer/route.ts`). **REFUTED on PR #1377 review — do not retry:** the same pass also overlapped scope with the rate-limit RPC and aborted it on deny, claiming the limiter could "deny for free". It cannot. With caller-supplied `filters` or explicit ids, scope passes its zero-query early returns (`search-scope.ts:242,253`) into the paginated `documents` loop at `:269`, and an `AbortSignal` cancels the client request without un-executing a statement Postgres already began — so throttled traffic kept burning database capacity while collecting 429s, against `capacity-review.md:106-113`'s first-soft-failure warning. Scope is behind admission again, pinned by `tests/answer-route-preamble.test.ts`. Re-attempting the overlap requires a non-database admission gate ahead of the durable limiter first. **Remaining:** (a) the 8 `setCachedSearch` awaits — deferring changes `throwIfAborted` semantics and widens a real mutation window because the clone happens after an `await`, so each branch needs discharging individually; (b) batch the anonymous subject+global rate-limit pair, which needs a NEW atomic RPC modelled on `consume_summary_rate_limits_atomic` and cannot be called until the operator applies it — `Promise.all` is the WRONG fix because it consumes the global bucket even when the subject bucket already denied; (c) stop the proxy and route handler resolving identity twice per authenticated request — no in-process memo can do this (different `Request` objects), so the proxy must forward unspoofable verified claims via a header it controls. Cross-references #011: halving auth resolutions eases the ~10-connection Auth cap that `capacity-review.md:106-113` calls the first hard failure. | `docs/audit/latency-audit-2026-07-28.md` L1-1/L1-3/L1-4; `src/lib/api-rate-limit.ts:276-282`; `src/proxy.ts:125` | 2026-07-29 | | #100 | P2 | rec | Buffered answer generation has no incremental verified delivery | UPDATE 2026-08-13 (PR #1909): Phase 0 offline contract proof and flag-gated Phase 1 server emission implemented (RAG_INCREMENTAL_EVIDENCE_PREVIEW, default false). Remaining: client parsing/rendering phase behind its own flag + verify:ui, then the design's provider-backed acceptance gates before production enablement; Phase 2 stays provider-gated. **Design complete; runtime work remains provider-gated.** [`verified-answer-incremental-delivery-design.md`](verified-answer-incremental-delivery-design.md) records the clinical-governance decision and staged contract: keep the `progress`/`final`/`error` allowlist; disclose bounded, owner-scoped evidence only after the canonical danger-level source-governance refusal permits it, then emit complete answer sections only after each reuses the full production verification boundary; reconcile every preview byte-for-byte with the authoritative `final`; discard all previews on error/cancel/retry; deploy behind separate parse/emission/render flags. Phase 0 contract proof and Phase 1 evidence preview can be developed offline, but visible rollout still needs clinical/browser proof. Phase 2 changes generation architecture and requires explicit approval for answer-quality evals plus a baseline/post live canary pair. **Naive token streaming remains REFUTED:** never re-land `token`, `revising`, provisional prose, or a weaker stream-only verifier. Cross-references #021. | `docs/verified-answer-incremental-delivery-design.md`; `docs/audit/latency-audit-2026-07-28.md` L0-1; `src/lib/answer-stream-contract.ts:18-21` | 2026-07-30 | -| #101 | P3 | rec | Canary-gated retrieval parallelisation candidates | **DEPRIORITISED 2026-08-12 (yield review against current main).** Every candidate needs the #098 harness, the RAG flag, live-canary approval, 36/36 retrieval and recall 1.0 — provider spend and clinical-surface risk for latency nobody is currently waiting on. **Outcome:** remaining retrieval parallelisation candidates are explicit after PR #1474 shipped the metadata and memory parallelisation. **Remaining:** visual hydration triples (each migrated path still calls `attachPageVisualEvidence` after hydration — not yet parallelised, see `rag.ts:1442,1811,1857,1959,2194,2281`); nested `await`-in-loop scope enumeration (`search-scope.ts:202,328`); uncached typeahead results (`rag.ts:2698-2711`); and universal-search coalescing (`/api/search` has it; `/api/search/universal` does not). Each changes candidate assembly, truncation, or what the next keystroke returns, so each requires the #098 harness, the RAG flag, explicit live-canary approval, 36/36 retrieval, recall 1.0, and zero per-case reciprocal-rank regressions. Distinct from #001 (semantic rerank). **Completed:** PR #1474 parallelised metadata and memory (`hydrateCandidatesWithMetadataAndMemory`); do not propose that specific change again. **Stop:** no remaining candidate proceeds without its canary gate. | `docs/audit/latency-audit-2026-07-28.md` L2-1/L2-2/L2-8/L1-5; PR #1474 | 2026-07-29 | | #102 | P3 | task | Apply the additive `documents` index debt (operator) | **Outcome:** bare-column `ILIKE` and the paged status scan on `documents` are index-served on hosted. `documents_title_trgm_idx` indexes a CONCATENATED expression, so the bare-column predicates in `api/documents/route.ts:193` and `rag-candidate-sources.ts:477` (RAG path) cannot use it and fall back to scanning; `search-scope.ts:271-277` sorts per page against the single-column `documents_status_idx`. **Runbook prepared 2026-07-29 — NOT applied, item stays open:** three `CREATE INDEX CONCURRENTLY` statements authored and reviewed in `docs/operator-apply-performance-latency-remediation.md` — additive, though **the "recall is byte-identical" claim was RETRACTED on 2026-07-29 review**: `fetchDocumentTitleAliasRows` (`rag-candidate-sources.ts:482`) applies `.limit(12)` with no `ORDER BY`, so a new index can change which title-alias documents feed candidate assembly. Only the documents-list use stays ordering-safe; `(status,id)` is canary-gated too — see runbook, and making that `.limit(12)` deterministic first does **not** lift the gate — an unordered `LIMIT` has no stable selection to preserve, so imposing an order can pick a different twelve and is itself an ordering behaviour change on a retrieval surface, which AGENTS.md requires a canary pair for. Sequencing the ordering fix first is worthwhile (unordered `LIMIT` on a retrieval input is latent nondeterminism regardless) but yields two canary-gated changes, not one (PR #1377 review). **Deliberately NO migration file:** an additive-index migration without a synchronized `schema.sql` mirror and regenerated drift manifest is exactly what closed PR #1312, and the mirror cannot come first because `required_indexes` in `search_schema_health()` (`schema.sql:3178`) runs against live. **Next (operator):** **author the migration first** — `supabase/migrations/` is the source of truth and `schema.sql` only a mirror, so hand-run operator SQL never reaches staging, disaster-recovery replay, or a local `supabase db reset`, and a `required_indexes` registration would fail there (PR #1377 review); follow the `20260717170000_registry_projection_cleanup.sql` idempotent pattern. **That migration must also carry the health-function change** — `required_indexes` lives inside `search_schema_health()`, which is redefined by `create or replace function` in eleven migrations (copy `20260705180000_reconcile_search_health_indexes.sql:62`); editing `schema.sql:3177` alone moves only the mirror and leaves the indexes unmonitored on hosted (PR #1377 review). Then apply concurrently, confirm `indisvalid`, mirror both the index statements and the identical function body into `schema.sql`, run `npm run drift:manifest` (Docker), and deploy the migration LAST — in that order, in one change. Expect `check:drift` to report them as unexpected between steps 1 and 2. **Rollback is three deployed phases, not the reverse of one:** retract `required_indexes` via its own `create or replace function` migration and deploy → drop concurrently live → only then deploy the `schema.sql` removal plus an idempotent forward `drop index if exists` migration, because Supabase wraps migrations in a transaction and a plain `DROP INDEX` there takes the lock the concurrent procedure exists to avoid (PR #1377 review). | `docs/audit/latency-audit-2026-07-28.md` L2-3/L2-5; `docs/operator-apply-performance-latency-remediation.md` | 2026-07-29 | -| #117 | P2 | rec | All live mobile routes breach LCP; shared render-blocking CSS and font are the current bottleneck | **Outcome:** `/therapy-compass` mobile LCP lands near the other mobile routes instead of double them. **Measured 2026-07-30** by the new pre-merge Lighthouse budget: mobile LCP 5229 ms, TBT 612 ms, CLS 0.142, against 2123-2460 ms on every other mobile route and 826 ms on desktop — so it is client-side work under mobile CPU/network throttling, not server latency. **Cause before this PR:** `useTherapyData` fetched `/therapy-compass-data/therapies-index.json` (the stable public alias served by a Next rewrite to the thin browse index; 205 records) for the home/search/pathways screens, so the download plus JSON parse sat on the critical path before content painted. **Current split:** home now fetches `public/therapy-compass-data/therapies-home.211dab554c4ec62d.json` (136,288 bytes raw), pathways use the thin browse index, and search loads the full prose corpus (#1471). 90% of the index weight is long-form clinical prose — indications 159 KB (26%), contraindicationsOrCautions 139 KB (23%), bestUsedFor 73 KB (12%), clinicalSummary 67 KB (11%), patientPopulation 59 KB (10%), targetSymptoms 48 KB (8%) — while name, slug, category, tags and setting together are 54 KB (7%). **Remaining decision for search/pathways: rendered on the card, matched by search, or neither.** `therapy-card.tsx` references five of those prose fields and the same index feeds the search screen, so stripping fields could silently change clinical display or search recall. **Next:** settle that per-field question, then either pre-truncate prose that only feeds card display, or move search matching server-side / load prose on first keystroke. **Gate:** `check:therapy-data-index` plus the therapy Playwright journeys; re-measure with `npm run verify:lighthouse`. **Stop:** do not drop a field from the catalogue payload without confirming no card renders it and no search path matches on it. Same class as #013 (route-chunk / catalogue JSON weight), different route and now measured. | PR #1915; live Web Vitals runs 31704500966 and 31704504389; codex/performance-css-delivery | 2026-07-30 | -| #118 | P2 | task | Adopt the remaining visual baselines; Lighthouse now gates regressions | Lighthouse half resolved in PR #1915: authorized CI refresh run 31697669596 on current main produced all 10 route/strategy cells with one pinned HeadlessChrome/151 identity. The reviewed artifact was committed, lighthouse-budget.json enforce is true, the job no longer uses continue-on-error, merge_group coverage is restored, and pr-required now fails on a selected Lighthouse failure. The 2026-08-08 and 2026-08-13 complete baselines stayed within tolerance; the latter puts mobile LCP at 2357-2388 ms and Therapy is no longer an outlier. This relative local-production gate does not close #117 deployed-origin LCP work. Remaining #118 scope: adopt the CI-generated Linux visual snapshots and promote visual-baseline only after design-owner review and stable reruns. Stop: never use developer-machine snapshots or let a workflow update its own gate. | PR #1915; CI run 31697669596 artifact lighthouse-baseline-refresh-31697669596 | 2026-07-30 | -| #150 | P2 | issue | CodeRabbit reviewed none of a full day's PRs; spending cap reached | IN FLIGHT annotation retired 2026-08-14: PR #1836 has merged, so the do-not-start note is stale and was blocking rather than protecting. The row itself is NOT code-verifiable from a container — CodeRabbit's spending cap is an account/billing state, so confirming whether the cap still suppresses reviews needs the operator's CodeRabbit dashboard. Next: check the subscription's review quota and either raise it or record the accepted coverage gap. Keeping open pending that operator read. | PRs #1404/#1430/#1444/#1445/#1479; `.coderabbit.yaml` | 2026-07-30 | -| #165 | P2 | task | Adopt a consolidated answer-home notice block — the studies exist, nothing adopts them | **Outcome:** the answer hero states its safety obligation, its scope, and its verification requirement as one block in one voice. **Detail:** `/mockups/warning-consolidation` (PR #1437) diagnoses today's three stacked notices — the APP-5 privacy warning at 11px muted, a bare `/privacy` link, and an accent-blue `ShieldCheck` capability claim at 14px semibold — and shows the hierarchy is inverted: the least important line is the loudest, and two shields with opposite meanings sit ~40px apart. Three consolidations are drawn at 1440px and 390px. Recommended: **02 Safety card** on the hero (obligation on a warning-tinted top row, everything descriptive in one grey voice below) and **01 Assurance bar** on the docked composer — the same content model at two densities, so one component with a `density` prop covers both. **This is a governance change, not just a design one:** `PrivacyInputNotice` is the single site-wide APP-5 line and renders on the answer, documents and calculators composers, so all three move together; `tests/privacy-ui.test.ts`, `tests/ui-accessibility.spec.ts` and the phone-chrome reserve coverage all assert against the current markup and must change in the same commit; and the PR will need a full `## Clinical Governance Preflight` (the mockup PR correctly did not). **Third study (before/after):** `/mockups/answer-home-proposal` draws the concrete D-direction proposal as a full hero before/after rather than an isolated notice. **Second study (words only):** `/mockups/warning-line` answers a narrower brief — no icon, border, tint or background, one line where width allows. Six variants A-F; line counts measured from the rendered DOM, not asserted. Only B (middot clauses), D (obligation + verify) and F (compressed obligation) hold one line at desktop width, and **none fit one line on a 390px phone while the pinned APP-5 sentence stays verbatim** — 46 characters of obligation plus the 27-character link exceeds the ~60 available at 11px. Recommended there: **D**, the only compliant variant that is both one line and keeps weight-only hierarchy, reached by dropping the scope claim (a capability statement already visible on the answer itself). F fits best but rewrites the pinned obligation to \|No patient-identifiable information.\| and so needs the same privacy sign-off as `#166` plus a matching `tests/privacy-ui.test.ts` update. **Status:** PR #1437 was closed unmerged on 2026-07-30 as a deliberate pause during an owner-authorized ordered merge sweep, to be reopened at its queued place; branch `claude/warning-consolidation-mockups-09jyj7` is preserved and merged onto current `main`; these follow-up rows have been renumbered on each sync because `main` kept claiming the next ids while the PR was paused; the superseded numbers are deliberately not listed, since they now belong to unrelated rows. **Next:** decide block (02 + 01) versus line (D) direction, get wording sign-off for `#166`, then implement behind one component and run `verify:phone-chrome` before `verify:ui`. | session 2026-07-30; PR #1437; `/mockups/warning-consolidation`; `/mockups/warning-line` | 2026-07-30 | -| #168 | P2 | rec | Sequential issue ids force every concurrent append to conflict | DESIGNED 2026-08-14 in PR #1944 — docs/ledger-id-scheme-proposal.md. Design only, nothing implemented, so this row stays open. Recommends a ULID as the durable id with a short derived display form, the property that matters being that the display form is derived rather than stored: a clash there is a rendering fix (take one more character) rather than a renumber. UUIDv7 noted as an equally good fit. Records why timestamp-plus-slug and content hashes were rejected — the slug wants to change when a row is re-scoped, which is renumbering under another name, and a content hash is neither sortable nor stable. Migration is additive because the 314 existing sequential ids keep their numbers permanently: they are cited across the ledger, docs/branch-review-records/, AGENTS.md, the skills and the commit history, so renumbering would invalidate every citation while producing exactly the churn this row exists to end. Four steps, widening validators before allocation changes, with every current #NNN assumption enumerated by file and symbol (ledger-inbox.mjs validateRequest twice; check-outstanding-issues.mjs ID_CELL, the MARKER parse, the nextId-above-highest assertion and its padStart formatting; outstanding-issues.mjs allocator; issues-report.mjs and the issues-surface hook). Stop unchanged and now load-bearing on step ordering: do not reinstate merge=union while ids are sequential — it only becomes safe after the marker is gone. | session 2026-07-31; .gitattributes; #154/#155; PR #1524 sync | 2026-07-31 | -| #169 | P2 | issue | Machine-local branches, snapshots, worktrees, and dev servers remain at risk | **CONSOLIDATED 2026-08-13 from #152, #236, and #260 before those source rows are archived by PR #1920. Outcome:** every branch, snapshot, worktree, or process that exists on only one machine remains recoverable and receives an explicit owner disposition before machine or worktree cleanup. **Original unpushed branches:** `claude/clinical-kb-design-system-333a69` was verified to contain 57 files / +4069 at tip `feat(design-system): v2 token layer, 26 components, browser-crash fix`, including `.design-sync/previews/*.tsx` absent from main. Also inspect `design-sync-db0a54`, `fable-implementation-fc937c`, `frosty-mayer-2c6167`, and `issues-133-evidence`. **Preserved WIP snapshots from #152, all unpushed, unreviewed, and unverified:** `codex/reconcile-immediate-20260730` at `748ef018f` (21 files, +395/-200 across 19 tracked, including `.github/workflows/ci.yml`, `package.json`, and `docs/scripts-index.md`); `codex/document-results-mockup-20260730` at `5dbd9f965` (8 tracked files, +13/-3, plus an untracked `document-search-results/page.tsx` mockup); `codex/chat-ledger-triage-d344` at `b7eae51a4` (`docs/outstanding-issues.md` +59/-61); and `claude/section-spy-browser-coverage` at `d949859c3` (`tests/ui-smoke.spec.ts` +51). **Wave-5 inventory from #236:** content-compare `claude/ds-v2-builder-a` and `claude/ds-v2-builder-b` with current `origin/main` because squash merges make ancestry checks unreliable; retain the associated process evidence for ports 3258 (`Database-wt-ds-v2-capture`), 3135 (`Database-wt-ds-v2-correctness`), and 3672 (`Database-wt-ds-v2-empty-state-heading`) until the owner confirms each process is no longer needed. **Stranded Sentry work from #260:** on the originating Windows machine, inspect branch `claude/cloud-pr-loop-prevention-bc052b` commits `c3c9d6a31` and `abbcdc8e9` (~389 lines across `src/sentry.*.config.ts`, `src/lib/env.ts`, `src/lib/supabase/client.tsx`, and `src/components/ui-primitives.tsx`) plus the same four uncommitted files in `.claude/worktrees/pensive-borg-6be2f0`; content-compare them with remote branches `claude/sentry-nextjs-sdk-setup-2v24q5` and `cursor/sentry-nextjs-sdk-7cee`, then record whether the work is unique, remotely preserved, or proven superseded. **Verification rule:** do not use `git rev-list` counts, three-dot diff, or ancestry alone to declare squash-merged work represented; verify the branch-added files or content against current main. **Cloud-session stop:** fresh cloud containers cannot observe the originating machine's local branches, worktrees, or processes, so never close this row from a cloud inventory that reports them absent. **Next:** complete and record each disposition from the originating machine. **Stop:** retain every listed branch, snapshot, worktree, and process record until content proof and owner disposition exist. | sessions 2026-07-30/31 and 2026-08-04/07; #152/#169/#236/#260; PR #1920 review | 2026-07-31 | -| #175 | P2 | task | Therapy modality is now null on all 205 records and needs curation or removal | VERIFIED CORRECT 2026-08-12 — re-checked against merged main during the full ledger sweep and left unchanged: src/data/therapies-source.json holds 205 records and 0 carry a modality value, exactly as described. This stamp exists so a later reader can tell "checked and still true" from "never looked at"; the two were indistinguishable before. **Outcome:** the Therapy detail and recommend screens either show a curated modality or stop carrying the field at all. **Detail:** the source catalogue derived `modality` from each record's own tag list — all 205 records had one, every value was also present in that record's `tags`, and the whole catalogue collapsed to CBT/ACT/DBT. It mislabelled the treatments it could not describe: ECT and rTMS as "ACT", Psychoanalysis and Psychodynamic Psychotherapy as "CBT", MBT and TFP as "DBT". Pre-existing on main, surfaced by the PR #1489 review. The generator emits it only when the source curates a value that is not already a tag, which today means null for 205/205 on the index projections *and* the full catalogue the detail/recommend screens load (`catalogue: "full"`), so the two chips (`detail-screen.tsx:49`, `recommend-screen.tsx:115`) never render and `select.ts:117` contributes no same-modality point. Removal was provably search-neutral: `src/lib/therapies.ts` scores with boolean `haystack.includes(token)`, not term frequency, and every modality value was already contributed by `tags.join(" ")` in the same haystack. **Next:** one of two — curate real modality values in `src/data/therapies-source.json` (clinical work, needs the psychiatrist), or drop the field from `types.ts`, `src/lib/therapies.ts`, the two chips and `select.ts`. **Stop:** do not reinstate the tag-derived value to make the chips reappear; a guess rendered as curated fact is the defect. `tests/therapy-compass-pathways.test.ts` pins the echo invariant on both the index and the full catalogue asset. Renumbered from this PR's original `#169` because `main` claimed `#169`–`#174` while the branch was open. | PR #1489 review remediation; PR #1532; session 2026-07-31 | 2026-07-31 | -| #183 | P3 | task | Create Sentry metric alert for production DB span p95 > 500ms | **DEPRIORITISED 2026-08-12 (yield review against current main).** A production DB p95 latency alert for a system with one user; the alert has nobody to wake. Revisit alongside #027 when real usage exists. Still blocked 2026-08-01 closeout: SUPABASE_ACCESS_TOKEN and SENTRY_AUTH_TOKEN missing from session env; Sentry MCP OAuth can list/get alerts but has no create tool; browser hits login wall; no metric rules exist yet on clinibase-xz. Create Metric Alert: p95(span.duration), filter span.op:db, environment production, threshold >500ms, notify Active Members. Provide SENTRY_AUTH_TOKEN in session to finish via sentry alert metrics create. | session 2026-07-31 db-query-perf follow-up | 2026-07-31 | -| #190 | P3 | task | X3: Finish rag.ts monolith decomposition | **DEPRIORITISED 2026-08-12 (yield review against current main).** Structural churn on the most safety-critical and most protected file in the repo, with no user-facing benefit and real behaviour-drift risk on a live-validated clinical answer path. Do the extractions opportunistically when a feature change already requires being inside a region, not as a standalone project. VERIFIED CORRECT 2026-08-12 — re-checked against merged main during the full ledger sweep and left unchanged: src/lib/rag/rag.ts measures 4,362 lines — still the monolith this row describes; the decomposition has not started. This stamp exists so a later reader can tell "checked and still true" from "never looked at"; the two were indistinguishable before. **Outcome:** `src/lib/rag/rag.ts` is decomposed into focused modules per `docs/maturity-backlog-workorders.md` X3, with existing offline RAG contracts green. **Status:** IN PROGRESS (DocumentViewer/Dashboard extractions done; rag.ts remains). **Next:** continue safe extractions only with the RAG flag before editing protected surfaces; one verified draft PR per unit. **Stop:** no behaviour change without canary when retrieval/answer paths move. | docs/maturity-backlog-workorders.md X3; #086 | 2026-07-31 | +| #183 | P3 | task | Create Sentry metric alert for production DB span p95 > 500ms | RIDER 2026-08-18 (recorded on the Phase 3 product PR, not a ledger-only branch): the Supabase CLI is now authenticated and this repository is linked to the staging project Clinical KB Staging (ikoiolksxqxfxgiyqpnu) — owner action 2026-08-18. That unblocks CLI repair paths (supabase db push --linked, migration repair with a guard migration) for staging; SUPABASE_ACCESS_TOKEN as a repository/environment secret for CI/live-drift remains outstanding, and the Sentry metric-alert part of this row (SENTRY_AUTH_TOKEN, p95 span.op:db > 500ms alert, deprioritised 2026-08-12) is unchanged. | session 2026-08-18 Phase 3 repo-side codification (branch claude/schema-work-mem-codify-6200f1) | 2026-07-31 | | #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 | -| #193 | P3 | task | X7: Complete the remaining src/lib domain-directory reorg | **DEPRIORITISED 2026-08-12 (yield review against current main).** Mechanical directory moves with import-graph risk and no user-facing benefit. Same reasoning as #190: fold into work already touching the files. VERIFIED CORRECT 2026-08-12 — re-checked against merged main during the full ledger sweep and left unchanged: Six domain directories exist under src/lib (extractors, observability, rag, supabase, validation, webhooks); the reorg is genuinely partial, as the row says. This stamp exists so a later reader can tell "checked and still true" from "never looked at"; the two were indistinguishable before. **Outcome:** remaining `src/lib` clusters sit in their domain directories per X7 follow-on to X2. **Next:** move non-protected clusters first; answer/retrieval clusters need the RAG flag. **Stop:** no drive-by behaviour edits inside moves. | docs/maturity-backlog-workorders.md X7; #086 | 2026-07-31 | -| #195 | P3 | task | M1: Repo-host hardening (branch protection and required checks) | **Outcome:** GitHub branch-protection rulesets and required checks match audit §8 / maturity M1. **Next:** maintainer GitHub UI work; not a repo-file change. Record evidence in the ledger when done. **Stop:** agents must not weaken required checks. | docs/maturity-backlog-workorders.md M1; #086 | 2026-07-31 | -| #206 | P2 | task | AnswerState partial_retrieval has no app-facing producer | VERIFIED CORRECT 2026-08-12 — re-checked against merged main during the full ledger sweep and left unchanged: `partial_retrieval` is declared in src/lib/answer-state-types.ts:63 and handled in answer-clipboard.ts:75, but nothing in src/app or the retrieval path produces it — still no app-facing producer, as the row says. Do not synthesise it from candidate counts. This stamp exists so a later reader can tell "checked and still true" from "never looked at"; the two were indistinguishable before. PR-E step 0 found nothing in the client payload names which expected sources were unavailable (retrievalDiagnostics = candidate counts; conflictsOrGaps = prose). RetrievalStateBanner supports the state but PR-J adoption can only emit ready/stale_evidence/source_only. Next action: decide whether a separate RAG contract PR should add a named missing-source signal (governance preflight + RAG impact line + offline eval); until then do not synthesise the state from counts. Pinned by tests/answer-state-contract.test.ts and SPEC 13 / COMPONENTS 2. | PR-E step 0, session 2026-08-02 | 2026-08-02 | -| #211 | P3 | task | Plan and start the noUncheckedIndexedAccess migration | **DEPRIORITISED 2026-08-12 (yield review against current main), and that judgment still holds** — each site is a local judgment, no open ledger row traces a defect to unchecked indexed access, and the diff conflicts with every open PR. Do it in scoped batches after the clinical and CI-trust work. This update carries that conclusion forward rather than replacing it; what has changed is that the batches now exist on paper and the count was wrong. **RE-MEASURED AND PLANNED 2026-08-14 in PR #1944.** The staged plan is docs/no-unchecked-indexed-access-migration-plan.md; the migration has NOT started and tsconfig.json is unchanged, so this row stays open and stays deprioritised. Measured against main at d47aa6d rather than reusing the 2026-08-02 figure: **1,445 errors across 269 files, up from 1,266**. The drift is itself a finding — the flag is off, so nothing stops new unchecked indexing landing, and any plan built on the stale count under-scopes. The measurement also reshapes the job in a way that supports doing it in batches: tests/ (713) plus design-scratch mockups (237) are two-thirds of the population and carry no production consequence, so the genuinely risky remainder is about 500 errors, not 1,445. Shape is 71 percent TS2532/TS18048, which a guard fixes; the 368 TS2345/TS2322 need a real decision about what the absent case means. Hot spots unchanged and confirmed: answer-verification.ts (41), rag-extractive-answer.ts (23), worker/main.ts (23), evidence.ts (19). Six stages, cheapest first, each flagged mechanical or manual with its own gate. Key constraint the plan records: noUncheckedIndexedAccess is a whole-project option and narrowing include does not isolate a directory, because TypeScript still reports errors in every transitively imported file — so the flag flips exactly once in the final PR and intermediate stages are verified by a baseline ratchet in the shape of scripts/design-system-contract-baseline.json. Stage 6 touches src/lib/rag/**, so the plan writes out the flag-before-editing, RAG impact line, and live-canary obligations. Stop unchanged: do not flip the flag on main ahead of the final stage. | session 2026-08-02 /ledger sweep — docs/review-findings-2026-08-02.md | 2026-08-02 | | #231 | P1 | issue | Generation fallbacks no longer stick in answer cache; lithium generation quality still falls back safely | PARTIAL 2026-08-12: This PR fixes the clinically consequential stale-fallback path: every answer whose routing or degraded reason contains generation_fallback is excluded from rag_response_cache. Offline evidence: 96 focused answer-route tests and 574 RAG fixture/contract tests passed. Approved live baseline/final canaries preserved 36/36 document and content recall at 1.0 with zero per-case reciprocal-rank regressions; the final 44-case answer gate had zero citation or numeric-grounding failures. A budget extension was tested and rejected: four cache-bypassed 'Lithium dosing?' probes remained grounded, cited safe extractive fallbacks at 35-40 second candidate budgets; the decisive 40-second probe completed generation in 25.272 seconds and 27.237 seconds total with route_deadline_exceeded=false, but failed generation quality. Therefore OPENAI_ANSWER_TIMEOUT_MS and the route budget are not the current residual binding cause. INSTRUMENT NOW EXISTS 2026-08-14: the "Next: instrument" half of this row is done. Commit a3bc4da adds scripts/probe-generation-quality.ts — one cache-bypassed live answer reporting the structured generation_quality_gate_reasons, provider-backed, refusing demo mode, never caching or logging the probe. The same commit adjudicates PR #1861: superseded for phase 1, close recommended, with the numeric-retry half deferred to phase 2 pending probe evidence. So do not review #1861 as though it were the live fix, and do not re-implement the probe. Next: run scripts/probe-generation-quality.ts in an environment that has OPENAI and Supabase credentials — it is blocked in offline containers, which is why it has not been run yet — then make a separate bounded output-quality fix with an offline fixture and live canary. Stop: do not increase route/provider timeouts or cache any generation fallback. INCIDENT ADDENDUM 2026-08-14 (later the same day): rung-2 evidence was then measured live - supabase_rpc_latency_ms 31610 on a semantic query (route budget 25000 starved generation), caused by the #316 dropped trigram indexes; after their owner-approved restore, 1535 (text fast path) / 8519 (hybrid). Pre-generation latency was the binding residual cause of semantic-query source-only fallbacks in that window; evidence in docs/audit/live-drift-forensics-2026-08.md. S1 (A1 phase 2) must re-verify generation_quality_gate:* dominance on healthy latency (run the probe with node --env-file=.env.local, which the probe does not load itself) before choosing a code mitigation rung. The route-budget stop condition stands unchanged. | sessions 2026-08-14: instrument adjudication + live incident probes (owner-authorized Supabase connector) | 2026-08-04 | -| #235 | P3 | task | ADOPTION.md section 7 proof shots exist for only four of the adopted surfaces | CLOSURE ATTEMPTED AND REJECTED 2026-08-14 — read this before closing again. PR #1940 queued a `done` for this row citing ADOPTION.md section 7.1's per-surface executable-evidence table; the closure was cancelled on review with the reason "executable evidence does not replace the requested desktop and phone proof shots". The cancellation is correct, and the trap is worth naming: section 7.1 opens with "This PR records executable evidence RATHER THAN committing image baselines", so the very section that looks like the evidence says in its first line that it is not. A test that proves a component is mounted is not a picture of the surface, and this row asks for the picture. IN FLIGHT note retired: PR #1842 merged, so the do-not-start warning no longer applies. The requirement is unchanged. The adoption contract asks for a proof shot per adopted surface. Wave 5 captured four - DSM header, settings rows, patient panel, answer surface - and none for the forms fold, the catalogue and docs surfaces, the headers convergence, or the empty states adopted since. Section 7 therefore reads as complete while most of the adoption is unevidenced, which matters because the proof shot is what a later reader uses to tell an intended restyle from a regression (the #229 DSM eyebrow was almost rediscovered as a defect for exactly this reason). Next action: capture the missing shots against a warmed local server (npm run ensure) and attach them to section 7. Cheap and mechanical - no gate, no provider access. Stop: this is not the visual-baseline harness (#118) - do not commit Playwright snapshot PNGs or flip that job to blocking. Stop: do not close this row on unit, DOM or contract evidence of any kind. | session 2026-08-04 (DS V2 Wave 5 close-out capture) | 2026-08-04 | -| #239 | P3 | rec | Manual phone rotation check for ResizeObserver-only phone chrome reserve | PR #1616 phone overlay reserve publishes only from ResizeObserver quiet-window deliveries. Desktop↔phone and late-mount recovery are covered; orientation that does not change stack height is a narrower trigger. Next: rotate a physical phone on a chrome-overlay route and confirm --phone-overlay-chrome-h updates. | PR #1616 review findings; session 2026-08-05 | 2026-08-05 | -| #240 | P3 | rec | Confirm tooltip visual hard-clip asymmetry with design owner | Tooltip keeps overflow-hidden visual clamp while sr-only/aria-label retain full text. Design contract says supplementary-only. Next: design-owner confirmation that sighted users losing the clipped tail is acceptable, or allow overflow-y-auto for long clinical strings. | PR #1616 review findings; session 2026-08-05 | 2026-08-05 | -| #242 | P2 | task | Commit approved Linux visual baselines and promote adoption not-committed → committed | VERIFIED CORRECT 2026-08-12 — re-checked against merged main during the full ledger sweep and left unchanged: Six linux/ PNGs are committed, but the adoption manifest still carries 68 `not-committed` entries — the surfaces flip is the remaining work, as stated. This stamp exists so a later reader can tell "checked and still true" from "never looked at"; the two were indistinguishable before. Baselines and provenance are DONE as of PR #1729 (branch claude/ds-adopt-visual-baselines): all six linux/ PNGs committed from ubuntu artifact visual-baseline-31251091603 (main @ bc33d414e), AWAITING_BASELINE emptied, and tests/__screenshots__/linux/provenance.json written with per-candidate SHA-256 + dimensions and an approved human review. Proven by that PR's own run: visual-junit tests=9 failures=0 skipped=0, and no visual-candidates/ directory, i.e. all six compared rather than skipped. REMAINING: only the surfaces flip to baseline.status committed. Blocked on ordering, measured 2026-08-08: validateLinuxVisualBaselineSet short-circuits on declaredPaths.length===0, so declaring files activates its rule that no non-allowlisted path may change since candidateSourceHead — and PR #1729 necessarily changed tests/design-system-adoption.test.ts, whose initialiseCandidateRepository seeded fixtures from the LIVE spec and so failed the moment AWAITING_BASELINE emptied. The two cannot land together. Next: after #1729 merges, re-capture candidates from a main run that already contains that fixture fix, then flip the surfaces against that head. Note this does not affect whether pixels compare — Playwright compares because the goldens exist on disk. | PR #1616 review findings; session 2026-08-05 | 2026-08-05 | | #248 | P2 | issue | Investigate why 20260705180000 search-health indexes were missing on live despite applied history | APPEND 2026-08-13: the prior closure is withdrawn. Repository and live-drift evidence establishes that 20260705180000_reconcile_search_health_indexes.sql is recorded as applied while documents_title_trgm_idx and document_chunks_content_trgm_idx are missing on live. Supabase transaction semantics exclude a persisted partial migration, but the present record does not distinguish skipped DDL/history repair from indexes created and later dropped. In an approved read-only window, query supabase_migrations.schema_migrations for the 20260705180000 statements fingerprint and inspect the relevant audit/history evidence; retain both hypotheses until that evidence establishes the cause. Separately, scheduled check:drift did detect the missing indexes, but red runs were not routed. | PR #1614 review / session 2026-08-05 (renumbered on main merge) | 2026-08-05 | -| #258 | P2 | rec | The PR-handoff stop rule is enforced for Claude Code only; Codex and Cursor get prose with no gate | GAP RECORDED 2026-08-14 in PR #1944 — docs/pr-handoff-stop-cross-agent-gap.md. This is the row's own stated fallback ("If no mechanism exists at all, record that explicitly here so the gap is a known limit rather than an open task"), so the row stays open but is no longer unexamined. Checked, not assumed: .claude/settings.json is read only by Claude Code; plugins/clinical-kb/.codex-plugin/plugin.json declares name/version/description/author/repository/keywords/skills and an interface block with NO hook, event, or pre-tool-interception field, shipping exactly one skill; .cursor/ holds settings.json (plugin enablement only), mcp.json, agents/ and skills/ with no deny path. So the cheapest-first option the row proposed is currently unavailable in both tools. Worth noting because it sharpens the cost: .cursor/agents/pr-babysit.md exists, meaning Cursor ships a documented agent for exactly the PR-following behaviour this rule restricts, with nothing bounding it. The doc records the Claude Code mechanism in enough detail to reimplement (session-scoped marker under the absolute git dir, fail-open on an unidentifiable session id, never pruning a sibling's marker, post-mode scanning only the request half so a command that merely prints a PR URL cannot arm it, and the CLAUDE_ALLOW_PR_FOLLOW=1 prefix unlock that a mention alone cannot trigger), plus the three questions any parity mechanism must answer. It is explicit that the wrapper fallback is advisory only — it cannot touch the MCP-connector or loop-machinery classes, so it makes a violation detectable after the fact rather than prevented. Next: re-check the Codex and Cursor manifests when either ships hook support; close only when a mechanism exists or the limit is accepted deliberately. Stop unchanged: do not weaken the Claude Code hook for symmetry, and do not keep a second copy of the deny list. | PR #1649; .claude/hooks/pr-handoff-stop.sh; .claude/settings.json; AGENTS.md "Stop when the pull request is open"; session 2026-08-07 | 2026-08-07 | -| #265 | P2 | task | DS Track A6: move design-system gates 2, 4, 7 and 8 from partial to blocking | CORRECTION QUEUED 2026-08-15 during PR #1987 review. Gate 2 is closed for new use, but the just-reconciled detail inherited stale measurements from PR #1984's pre-sync tree. On the exact current tree after PRs #1982-#1986, check:design-system-contract measures interactiveTapFloorDeclarations=40 across 16 production files, not 43 across 17, and edgeOwnershipConflicts=19 across 10 files, not 25 across 12. The strengthened tap-floor parser removed three old false-positive counts from calculators/search-page.tsx; favourites-library-nav and pwa-lifecycle no longer contribute edge conflicts after the merged UI work. The baseline and GATES.md still permit/report the older 43 and 25 values, so they carry three and six units of stale ratchet slack respectively and need a focused tightening follow-up. The detector still correctly evaluates comparable arbitrary lengths and reachable conditional/composed branches, and component-wrapper tags such as Link remain its known blind spot. Gate 7 remains open: add a shared deterministic render-tree traversal plus child/parent elevation-tier check. Gate 8 remains open: decide ring-versus-outline focus ownership, widen onePixelShadowSpreads to all relevant token families, then retire conflicts with browser focus proof. Do not edit the applied 8c133c4e request in place; it is immutable audit history. | PR #1987 review; exact tree after #1986; check:design-system-contract; scripts/design-system-contract-baseline.json; docs/design-system/GATES.md | 2026-08-07 | -| #266 | P3 | task | DS Track B1: adopt the 23 unadopted components demand-driven, never as a race to 53/53 | **DEPRIORITISED 2026-08-12 (yield review against current main).** Adoption counting toward 53/53 while a clinical P1 is open. The row's own title says never as a race to 53/53; the queue has been running the race anyway. Demand-driven means it activates when a surface needs a component, not on a schedule. COUNTS RE-MEASURED 2026-08-12 from docs/design-system/adoption-manifest.json on merged main: **54 registered, 31 adopted, 23 UNADOPTED**. (This supersedes the 2026-08-08 figures of 53/30/23, which a main-merge briefly restored over this correction.) The total held at 23 but the membership moved — DisclosureGroup joined the adopted set, and the newly built ErrorState joined the unadopted set; ErrorState's enforcement is closed (archived #298) but its adoption is still open under #299. Today's 23: AnswerFooter, Checkbox, Citation, CitationList, ConfirmDialog, Disclosure, DoseLine, DownloadLink, ErrorState, ErrorSummary, ExternalTextLink, FieldError, FieldHint, LinkAction, Pagination, Progress, RadioGroup, SearchField, StageList, Tabs, TextLink, ToastRegion, Tooltip. Approach unchanged and still correct: demand-driven adoption — pick a surface and let it pull, the way AccessibleTable pulled Button and the answer surface pulled AnswerCard (#216) — never a race to 54/54. Forms remain the largest single tranche: FieldError, FieldHint, ErrorSummary, SearchField, Checkbox and RadioGroup land together on one form conversion. Do not stub a component to move the count. Regenerate with npm run design-system:adoption:update AND npm run design-system:design-sync:update; both manifests are generated, never hand-edited. | session 2026-08-07 — design-system HANDOVER-2026-08-07 Track A1 handoff (PR #1678) | 2026-08-07 | -| #267 | P3 | task | DS Track B2: AnswerFooter and DoseLine need a provenance/dose payload the answer surface does not produce | **DEPRIORITISED 2026-08-12 (yield review against current main).** Blocked on a provenance/dose payload the answer surface does not emit, which is backend work nobody has scoped. Cannot start. VERIFIED CORRECT 2026-08-12 — re-checked against merged main during the full ledger sweep and left unchanged: Neither AnswerFooter nor DoseLine has a product importer; the provenance/dose payload the answer surface would need still does not exist. This stamp exists so a later reader can tell "checked and still true" from "never looked at"; the two were indistinguishable before. Backend-shaped work, not a component swap: the two components cannot be adopted until the answer surface emits the provenance and dose data they render. Do not stub one to make the adoption count look better. Sequence after the payload exists, then adopt via the Track B1 demand-driven route. | session 2026-08-07 — design-system HANDOVER-2026-08-07 Track A1 handoff (PR #1678) | 2026-08-07 | -| #268 | P3 | task | DS Track B3: move the 19 genuine bare-dash sites onto MissingValue | **DEPRIORITISED 2026-08-12 (yield review against current main).** 19 bare-dash sites with no reported clinical misreading. Cosmetic consistency on a prototype with an open P1. VERIFIED CORRECT 2026-08-12 — re-checked against merged main during the full ledger sweep and left unchanged: MissingValue is imported in 5 component files; the bare-dash conversion is partial. The ~5 calculator 'not started' sites stay permanently, per this row's own stop rule. This stamp exists so a later reader can tell "checked and still true" from "never looked at"; the two were indistinguishable before. Therapy-compass getters, specifier sourceFamily, favourites counts when untrusted. Leave the roughly 5 calculator 'derived.started ? score : dash' sites PERMANENTLY — 'not started' is not a missing clinical value, MissingValueReason has no member for it, and converting them would render 'Not recorded' for a score the clinician simply has not entered. | session 2026-08-07 — design-system HANDOVER-2026-08-07 Track A1 handoff (PR #1678) | 2026-08-07 | -| #269 | P3 | task | DS Track B4: prove the per-component visual state matrix (blocked on the baseline hold) | **DEPRIORITISED 2026-08-12 (yield review against current main).** Blocked on #118 baselines, and proves a per-component state matrix for a design system on a single-user prototype. High cost, low yield at this stage. hover / active / disabled / busy / invalid / 320px / dark / forced-colours / print, per component. Currently proven for none. Blocked on #118: zero visual baselines are committed and the harness is continue-on-error, so nothing in Track B is safe at scale until baselines exist. CORRECTION 2026-08-08: the claim that baselines cannot be generated on Windows is half true and led to the wrong conclusion. It is true that snapshotPathTemplate carries {platform}, so win32 PNGs are invisible to the ubuntu CI job — but the CI job already produces the ubuntu ones. .github/workflows/ci.yml job visual-baseline runs on ubuntu-24.04 whenever ui_changed, runs npm run test:e2e:visual, and uploads tests/__screenshots__/ as artifact visual-baseline-; playwright.visual.config.ts records that on a missing baseline Playwright writes the golden and fails the first attempt, which is why retries are pinned at 0. So the mechanism exists and adoption is mechanical — see #118. Stop rule unchanged: do not commit baselines until the owner declares the design final, and do not adopt them from a developer machine. | session 2026-08-07 — design-system HANDOVER-2026-08-07 Track A1 handoff (PR #1678) | 2026-08-07 | -| #271 | P3 | task | Decide whether to delete the now-consumer-less action kind in SecondaryNavigation | VERIFIED CORRECT 2026-08-12 — re-checked against merged main and left open: No production constructor of SecondaryNavigation exists — ` 1 and not fullscreen, so the holder becomes the scroller, and its overscroll changes from overscroll-contain to overscroll-x-contain precisely so vertical scroll chains OUT of the pane at its ends rather than trapping the reader. Single-page documents keep their previous geometry exactly and need no re-check. A nested vertical scroller inside a page is a known iOS hazard and no Chromium gate says anything about it, so it belongs on this same device pass. **On a real iPhone, in Safari and the installed PWA:** open a multi-page document (the 2-page synthetic clozapine demo doc, or any real guideline), confirm pages scroll inside the pane, and confirm that reaching its top or bottom continues scrolling the page rather than dead-ending. **Stop:** if it does trap, do not fix it by removing the pane — the pane is what makes a long guideline readable; adjust the overscroll behaviour or the pane height instead. | session 2026-08-08 document-viewer optimisation; docs/design-system/COMPONENTS.md phone clause | 2026-08-08 | -| #281 | P2 | rec | The phone document route renders two clinical-summary surfaces and neither is canonical | **Outcome:** one clinical summary on the document route, chosen deliberately. **Detail:** a phone reader gets the gradient 'High-yield clinical summary' card (DocumentClinicalSummary, built by buildDocumentClinicalSummaryModel) and, further down, the rail's '#source-summary' / 'high-yield-summary' disclosure (DocumentSectionSummary + FormattedHighYieldSummary + BadgeCluster). They render the same document.summary row two different ways. The rail is not hidden on phones — only its DocumentSectionIndexCard is lg:block — so both appear. Only the rail panel carries the section anchor, so the more prominent card is the unnavigable one. Note the two disagree about emptiness as well: the card now renders nothing when the model yields no usable text, while the rail panel still renders for its label badges, which is why 'hasStoredSummary' was deliberately left keyed to the stored row rather than to card content. **Next:** decide which rendering is canonical — this is a clinical-content judgement about how a summary should read, not a layout fix — then delete the other and give the survivor the 'source-summary' anchor. If the rail's badges are the part worth keeping, they can move without the second summary body. **Stop:** do not merge the two renderings mechanically; they format clinical text differently and the difference is the decision. | session 2026-08-08 document-viewer optimisation; document-rail-panels.tsx; document-clinical-summary.tsx | 2026-08-08 | -| #282 | P3 | task | Probe the corpus for JBIG2/JPX before deciding whether pdf.js needs its decoder assets shipped | **DEPRIORITISED 2026-08-12 (yield review against current main).** A probe to decide whether pdf.js decoder assets are needed. Worth doing eventually, but no reported rendering failure traces to JBIG2/JPX today, so it is speculative. **Outcome:** a measured decision about pdf.js's cMap/standard-font/WASM assets rather than an assumption either way. **Detail:** getDocument is configured with url plus the on-demand fetch flags and nothing else, so 'wasmUrl', 'standardFontDataUrl', 'cMapUrl' and 'iccUrl' are all unset. pdfjs-dist ships those assets (wasm 1.5 MB, standard_fonts 804 KB, cmaps 1.7 MB) and nothing copies them into public/. With wasmUrl null, 'useWorkerFetch' resolves false and the WASM image decoders cannot load, so JBIG2 and JPEG2000 images fall back to the JS decoders or fail; those are exactly the encodings a scanned guideline uses, and this repo runs an OCR pipeline, which implies scanned sources exist. Non-embedded standard-14 fonts fall back to system fonts, which is a fidelity risk on a clinical document rather than a failure. **Next:** sample the real corpus for JBIG2/JPX-encoded images and for PDFs relying on the standard 14 before shipping ~2 MB of static assets; if the corpus does use them, copy into public/pdfjs, set the URLs, and add immutable cache headers in next.config.ts (public/ is not counted by check:bundle-budget, so there is no budget risk — the cost is bytes over the wire on first use). **Stop:** do not ship the assets on the assumption alone. | session 2026-08-08 document-viewer optimisation; node_modules/pdfjs-dist/types/src/display/api.d.ts | 2026-08-08 | | #283 | P3 | rec | The 100-id batch signed-URL route still has no caller | VERIFIED CORRECT 2026-08-12 — re-checked against merged main during the full ledger sweep and left unchanged: No caller for src/app/api/images/signed-urls/route.ts anywhere outside app/api — the batch route is still unused. This stamp exists so a later reader can tell "checked and still true" from "never looked at"; the two were indistinguishable before. **Outcome:** either the batch minter is used or it is retired, rather than sitting as an untested, unreachable privileged surface. **Detail:** src/app/api/images/signed-urls/route.ts POSTs up to 100 image ids and returns their signed URLs, with its own rate limit, owner scoping and committed-generation filter. Nothing in src/ calls it — only tests/private-access-routes.test.ts imports it. **DEFERRED AGAIN, DELIBERATELY, 2026-08-09 (document viewer Phase 3, Task 3).** The user chose deferral over wiring when asked. Two reasons beyond cost: (a) wiring it puts a privileged owner-scoped API route into a diff that is otherwise confined to src/components/document-viewer/**, and it matches clinicalRiskPatterns (/^src\/app\/api\//) so pr-policy hard-blocks the merge without a complete Clinical Governance Preflight; (b) Phase 3 Task 2 windowed the rail to six rows and tightened its IntersectionObserver root margin from 640px to 240px, so the many-distinct-images case the batch route was meant to serve is now materially smaller — a page of N figures no longer mounts N rows at once. The batching win should be re-measured against the windowed rail before it is wired at all, rather than assumed from the pre-window numbers. **Next:** decide deliberately — measure concurrent distinct-image requests on a figure-heavy document with the windowed rail, then either wire the batch route in its own PR or delete it and its tests. **Stop:** if wiring it, keep the per-image endpoint for the lightbox's retry path; do not make the batch the only way to mint a URL. | session 2026-08-08 document-viewer optimisation; src/app/api/images/signed-urls/route.ts | 2026-08-08 | -| #292 | P2 | rec | Two assistants built the same queued conversion twice because neither workflow checks the open-PR list before starting | Recurred 2026-08-14 on the database remediation plan, this time with two assistants building Phase 0: PR #1938 and PR #1939 both implemented live-drift failure routing and the post-migration trigger, merged four hours apart. Both landed and no harm resulted — #1939 built on #1938's commit and improved it, moving the findings capture after the migration-history step so a migration-history failure is visible instead of a clean drift result being published as its explanation. The cost was still two full authoring sessions and two CI cycles for one deliverable. This matters more for the phases still ahead than it did here: Phase 1 consumes an approved read-only production window, and Phases 3 and 4 consume approved mutation windows and live eval-canary budget, so a duplicate there wastes an operator-gated resource rather than just tokens. Concrete ask for the remediation work specifically: check the open-PR list for the surface before starting any of Phases 1-5, per docs/database-remediation-playbook.md. | session 2026-08-09; PR #1766 (merged); PR #1767 (closed duplicate) | 2026-08-09 | -| #299 | P3 | task | Adopt ErrorState at the three surfaces that genuinely hand-roll the failed-request guard | **DEPRIORITISED 2026-08-12 (yield review against current main).** Three surfaces hand-roll a guard that works. Converting them is consistency, not a fix. VERIFIED CORRECT 2026-08-12 — re-checked against merged main during the full ledger sweep and left unchanged: ErrorState has no product importer beyond src/components/ui/error-state.tsx, so the three hand-rolled surfaces are still unconverted. (Its ENFORCEMENT is closed — see archived #298.) This stamp exists so a later reader can tell "checked and still true" from "never looked at"; the two were indistinguishable before. Three surfaces hand-roll the guard and their comments state the rule outright: src/components/clinical-dashboard/search-results-header-band.tsx:210 ('no number may reach the DOM'), src/components/services/services-navigator-page.tsx:634 ('a blocked registry must not reach the band as 0 matches'), src/components/clinical-dashboard/favourites-command-library-page.tsx:1182. They are CORRECT today, just not shared, so this is convergence rather than a bug fix. The band's fault panel is the richest existing implementation (role=alert, warning tokens, AsyncButton retry with busy state, faultAction slot) and ErrorState was modelled on it, so the shapes already line up. Live-look change: own PR, Chromium pass. Per the M4 brief it sits DOWNSTREAM of design decisions the owner has not made, so doing it before the site-wide redesign risks redoing it. Do NOT bundle with the enforcement check. Stop: only these three - see the sibling row for three sites that were miscarried as guards. | session 2026-08-09 M4 - ErrorState build | 2026-08-09 | | #305 | P3 | rec | Canary has no latency-mode coverage and its cost readout is a known lower bound | Two informational gaps from the 2026-08-12 canary review, deferred by scope decision. (1) eval:retrieval:latency (p90 20s gate) is never wired into eval-canary.yml, so live retrieval latency regressions are invisible to the weekly canary while the answer step relaxes its own gates via EVAL_LATENCY_CONTEXT=cross-region-runner. (2) estimated_cost_usd applies one rate set (gpt-5.6-terra) to all usage including 2x-priced strong-model retries, so any cost trend understates strong-retry runs — the workflow comments say so, but eval:trend consumers may not read them. Also noted: the workflow-wide concurrency group (eval-canary, cancel-in-progress false) can queue a dispatched pair run behind a scheduled run, interleaving pair evidence; and fixture coverage gaps tracked in #018 remain uncatchable by the canary. Next: decide whether a monthly latency-mode dispatch is worth the spend; add a strong-usage split to the estimator if cost trends start driving decisions. | session 2026-08-12 RAG canary review | 2026-08-12 | | #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 | | #309 | P2 | task | Facet groups of 6-20 options render as chips, not the dense list docs/filter-contract.md section 5 requires | Attempted 2026-08-14: an implementation task for chips-for-6-20 was stopped before any code was written, because it directly contradicts this row's own current, still-open text, which requires a full-width DENSE LIST (right-aligned count column, group headings) for the 6-20 band, and explicitly says chips-for-6-20 does not satisfy this row. Confirmed chips-for-6-20 is ALREADY the live behaviour (dense = facetGroups.length > 3 \|\| totalFacetOptions > 20 in result-filter-control.tsx), and that closing this row on that basis was already tried once and explicitly reverted (PR #1925, 'correct #309 to partially delivered'). No code changed, no PR opened. Needs a product/design decision between: (1) build the genuine full-width dense-list renderer plus the nine-option DOM assertion this row asks for, or (2) formally amend docs/filter-contract.md section 5 to deliberately drop the middle band with reviewer sign-off -- different from what already happened (a silent merge-conflict resolution the row says didn't count). | session 2026-08-14, agent stop per contract contradiction | 2026-08-12 | -| #311 | P3 | task | Promote the derived ledger loss-detector into scripts/ — it has now earned its place twice | During the 2026-08-12 sweep, two main-merges silently reverted edits to `docs/outstanding-issues.md`, including the ENTIRE #293 refutation (a `grep sm:min-h-0` returned 0; the text survived only in commit a6bfc6f). It went unnoticed because the recovery script was HAND-ENUMERATED — it listed 15 archives and 8 updates from one commit and could therefore only restore what the author remembered. The replacement is derived rather than listed: read every row id this branch has ever stamped out of `git rev-list ..HEAD` plus `git show :docs/outstanding-issues.md`, then assert each of those ids that is still OPEN carries its stamp text, and exit non-zero listing any that lost it. It has now proved itself twice — it caught the intentional #262 divergence (main's version was newer than the branch's, correctly left alone) and would have caught the #293 loss the hand-written list missed. The plan that created it said it should stay a scratch script 'unless it proves useful more than once'; that condition is met. Next: port it to scripts/ (suggested `check-ledger-stamp-retention.mjs`), generalise the stamp token from the hard-coded 2026-08-12 date to a `--since` or marker argument, add a self-test in the style of the other ledger scripts, and document it beside `ledger:dedupe` for use after any main sync that touches the ledger. Stop: do NOT wire it into verify:cheap or CI — it is a branch-local safety net for a human or agent mid-sweep, and it has no meaning on a branch that has not stamped rows. Related: #156 and #168, which track the id-allocation race that produces these merges in the first place. | session 2026-08-12 ledger sweep; scratch loss-check.mjs; #293 restoration from a6bfc6f | 2026-08-12 | -| #312 | P3 | issue | check:playwright-browser-revision reporting OK does NOT mean browsers are installed — and installing the matching revision is a cheap first option | Progress 2026-08-15: PR #1965 landed on main (commit 3ec6116) and closes the false-OK gap for the pinned Chromium revision by resolving the effective cache and requiring a launchable binary. Keep this issue open: the unscoped test:e2e and release matrix also require Firefox and WebKit, and the check does not yet report whether their locked revisions are installed. Next: enumerate required and installed revisions for all browser families, with a Chromium-only-cache regression; project-scoped --project=chromium runs may continue to require Chromium alone. | session 2026-08-12; scripts/playwright-browser-preflight.mjs:127-152; scripts/run-playwright.mjs:50-53; #290 close-out; archived #255 | 2026-08-12 | -| #314 | P2 | issue | Ship compact compressed registry projections and verify live transfer | UPDATE 2026-08-16: the provider-free implementation is now on current main via commit ca788d41e: view=summary/search projections and gzip are shipped in repository code. Remaining scope is external-only: deploy an exact authorized SHA, verify /api/registry/records headers and transfer bytes on that deployment, then rerun live LCP. Stop: do not close from local payload measurements, and do not deploy or query production without explicit target authorization. | Commit ca788d41e on current main; original latency audit evidence | 2026-08-13 | | #315 | P3 | rec | If the ui-smoke scroll-hide flake (archived #290) recurs, start from the reporter-stranding mechanism — and treat the old regression window as unconfirmed | Independent verification on 2026-08-13 (second session, fresh cloud container, pinned Chromium 1234 installed per #312) measured the archived #290 flake at BOTH ends of its recorded window and corrects the archive's causal story: the bad SHA 9ab3b73ad itself passed 16 recorded executions — reproducer isolated --repeat-each=5 (5 passed, ~1.0s each), one full tests/ui-smoke.spec.ts --project=chromium run (98 tests passed, 2.5m, 0 flaky), and reproducer x10 under deliberate CPU contention (6 busy-loop processes on 4 cores, run times 1.2-1.5s: 10 passed). Current main a76f280 also 5/5. So the recovery was NOT drift — the exact commit that measured 2/5-3/5 failures passes cleanly here — and the e8adde1b9..9ab3b73a window is unconfirmed; the failure was specific to the original machine's environment/load profile. Recorded as a comment on PR #1884 (issuecomment-5272932999). On recurrence, do not re-bisect first: test the stranding mechanism. computeScrollHideUpdate (src/components/clinical-dashboard/use-hide-on-scroll.ts) re-evaluates only on scroll/resize events, and its viewportHeightChanged / maxOffset-range-change guards deliberately zero accumulated down-travel (contract-asserted in tests/use-hide-on-scroll.test.ts) — so geometry churn consuming the final steps of a gesture strands the not-hidden state permanently until the next event, matching the recorded ~11.5s toHaveAttribute timeout signature (the assertion DOES auto-retry for 10s; the attribute genuinely never flips). Fastest confirmation: a diagnostic page.on('console') trace logging which guard fires per evaluation. The window itself was one PR (#1744 mode-routing, true merge a503c22) whose net diff touched no scroll-hide code — content-bisect axes, if ever needed: tests/ vs src/ split, use-home-mode-seed/use-last-app-mode neutralized, prefetchModeDestination reverted, positional heading click restored to a settle wait. Stop: any guard change is a behaviour change to protected phone chrome — needs a failing trace first, never speculatively; do not weaken the assertion or tap targets. | session 2026-08-13; PR #1884 comment; archived #290; #312 | 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 | PHASE 1.2 COMPLETE 2026-08-18 (read-only connector window, four SELECT statements, zero writes; project ref verified as sjrfecxgysukkwxsowpy before the first query). ALL TEN RPC def_hash mismatches are now CLASSIFIED and every one is attribute-only: the live pg_get_functiondef carries a SET work_mem clause that supabase/schema.sql (the manifest source, replayed by scripts/generate-drift-manifest.ts) does not, and stripping exactly that one line from the live text reproduces the manifest hash byte-for-byte for 10/10 using the exact 20260706200000 rule (md5 of pg_get_functiondef with block comments, line comments and whitespace stripped). Bodies, signatures, return shapes, plan_cache_mode/search_path clauses and ACLs are identical to the repo. ZERO body divergences, ZERO repo-ahead, ZERO UNCLASSIFIED. The PR #2017 hypothesis is confirmed for the eight AND extends to the two _v2 outliers, which also carry live-only work_mem. Split by direction: (a) MIRROR-STALE x4 - match_document_chunks_text, match_document_lookup_chunks_text, match_document_memory_cards_hybrid, match_document_memory_cards_hybrid_v2 all live 64MB = migration 20260724000000; only schema.sql omits the clause; remedy is repo-only (add the clause to schema.sql, npm run drift:manifest), no hosted change - PHASE 3 MAY EXECUTE THESE NOW. (b) LIVE-AHEAD ATTRIBUTE-ONLY x6 - match_document_chunks_hybrid, match_document_embedding_fields_hybrid, match_document_index_units_hybrid, match_document_index_units_hybrid_v2 are 128MB on live (no recorded migration sets 128MB; 20260724000000 records 64MB for the first three and nothing for the v2); match_document_chunks_text_v2 is 64MB on live with no migration ever setting it; match_document_table_facts_text is 64MB on live although the recorded chain drops it (20260724120000 recreates the function after 20260724000000; live proconfig order search_path,plan_cache_mode,work_mem proves an ALTER re-applied afterwards outside recorded history). Remedy per plan is codify-as-live: new migration ALTER FUNCTION ... SET work_mem = ordered after every recreate, plus schema.sql mirror and regenerated manifest, PR body 'RAG impact: no retrieval behaviour change - codifying already-live attribute'; the migration marks applied against an already-matching state so no hosted change. OWNER DECISIONS FLAGGED, NOT ASSERTED: (1) confirm 128MB on the four is intended, or standardise to the recorded 64MB - that direction IS a hosted change and should carry a before/after latency measurement; (2) canary exemption - work_mem is planner memory, it changes plans and latency not the ORDER BY/LIMIT result set (only rows with exactly equal sort keys could reorder), so the recommendation is that codify-as-live proceeds without an eval-canary and any hosted value change is confirmed by the Phase 5 EXPLAIN re-run rather than an eval dispatch; owner to grant. Query 4 of the session confirmed 20260724000000 is the only recorded migration mentioning work_mem (8 statements). Playbook trap-list correction recorded in the forensics file (20260724120000 DOES contain a create or replace function at line 9); playbook not edited. NEXT: Phase 2 staging parity (#056, running concurrently) then Phase 3 with the classifications above; Phase 3 needs no eval-canary approval from this dossier. Residual open question is provenance of the 128MB/_v2 settings, which pairs with the section 1.1 dashboard audit-history owner action. | Phase 1.2 read-only Supabase connector session 2026-08-18 (ref sjrfecxgysukkwxsowpy verified; SELECT only), evidence in docs/audit/live-drift-forensics-2026-08.md section 1.2 | 2026-08-13 | -| #317 | P2 | task | Verify registry-backed service records preserve facet metadata | #1878 introduced the services filter-contract tree and #1882 later merged the identical tree, so no merge-conflict audit is required. Current main uses ServiceRecord.catalogPayload.tags and fixture coverage verifies 219 records. Add focused offline tests that recordToRow and rowToServiceRecord preserve all six tag dimensions and degrade safely when payloads are malformed or absent. Do not add a second facets carrier unless a failing test proves the current contract inadequate. | PR #1921 review; #1878/#1882 tree comparison; service-facets.ts; registry-records.ts | 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 | PHASE 3 (reframed) COMPLETE REPO-SIDE AND STAGING-PROVEN 2026-08-18 (PRs #2106 merged 72aa18865, #2111 follow-up) — no production access, no canonical (schema.sql/production) function body changed, no hosted value changed; owner decisions D1 codify-as-live and D2 canary exemption applied. (1) SET work_mem codified on all ten match_* RPCs: schema.sql carries the clause on every definition and 20260818110000_codify_live_rpc_work_mem runs ALTER FUNCTION ... SET work_mem per function after every recreate. Values: 128MB chunks_hybrid, embedding_fields_hybrid, index_units_hybrid, index_units_hybrid_v2; 64MB chunks_text, chunks_text_v2, lookup_chunks_text, memory_cards_hybrid, memory_cards_hybrid_v2, table_facts_text. PROOF: regenerated drift-manifest def_hash for all ten equals the live production def_hash in issue #1963 (run 32051068106) byte-for-byte — the next production live-drift run reports zero match_* mismatches once marked applied. (2) Eight never-created objects codified verbatim by 20260818111000 (five document_embedding_fields indexes, documents_status_idx, documents_updated_at + ingestion_jobs_updated_at triggers); disjoint from #102; all six indexes stay on search-health-unmonitored-indexes.json, required_indexes untouched (Phase 4.4). (3) Triage: document_chunks CHAIN-stale (token_estimate, zero migrations); rag_visual_eval_cases/runs CHAIN-stale (id default bound to extensions.gen_random_uuid via 20260705230000 search_path order) — both fixed by 20260818112000; document_chunks_content_trgm_idx: production's restored definition (8499c3d3..) IS canonical = schema.sql = 20260705180000; staging holds the 20260606000000 form (c3db2960..) — Phase 4.4 residual, no escalation. (4) STAGING PROOF COMPLETE (two owner-authorised windows, ref ikoiolksxqxfxgiyqpnu verified per call, production never targeted): 110000/111000/112000 applied by the Phase 2 method; the comparison then exposed THREE chain-stale BODIES (embedding_fields_hybrid, index_units_hybrid, memory_cards_hybrid_v2 carried the legacy fail-open predicate on a chain-built DB — never forward-codified after 20260712000000; NOT a production hole, manifest hash = live hash) — fixed by new migration 20260818113000_forward_codify_hybrid_owner_matches_bodies (verbatim from schema.sql, no-op on production), applied to staging in the second window; the two rows whose text gained set-local timeouts pre-merge (111000/112000) were refreshed to the merged text. All four staging history rows md5 = repo (dd5c8c9e.., 22585b9e.., ec154770.., d35c199b..); staging 199 rows, no_statements 0, corpus 0. FINAL STAGING DRIFT: UNEXPECTED DRIFT (1) = document_chunks_content_trgm_idx only — zero function mismatches, zero never-created objects, zero table mismatches. NEXT: production window (D3, one window, no canary, no index build): 20260818090000 (real change, probe v2) + 110000/111000/112000/113000 (all no-ops, live already matches); then Phase 4 (incl. 4.4 guard migration for the trgm pair + staging trgm rebuild). Tooling note: check-drift.ts:192 240-char clip (own P3 queued). Evidence: forensics §Phase 3. | session 2026-08-18 Phase 3 staging proof complete (PR #2111) | 2026-08-13 | | #318 | P1 | task | The medication interaction lexicon has never been clinically reviewed and its sign-off block is empty | docs/medication-interaction-lexicon-review.md is generated by npm run medications:lexicon-report and expands every lexicon term to the catalogue drugs it resolves to, with how many CRITICAL/HIGH rows depend on it, sorted by severe usage. It is marked UNREVIEWED and its sign-off table is unfilled, so every red and amber drug-drug interaction alert is currently an unvalidated mapping over source-backed text. The wording shown to a clinician is always verbatim catalogue prose; what is unreviewed is which drugs a phrase like 'NSAIDs' or 'CNS depressants' was taken to mean. Next: a clinician reads the term table top-down and fills in the sign-off block. Stop: do not treat check:medication-lexicon-report passing as review - that check only proves the sheet describes the current lexicon, not that the mappings are correct. WORKLIST PREPARED 2026-08-15 (PR #1991): docs/medication-lexicon-review-worklist.md gives the top ten terms by severe usage (236 of 390 severe firings, 61 percent) with resolved drug sets and six prioritised questions. TWO OF THE THREE DEFECTS THIS ROW CITES WERE ALREADY CLOSED: the ARB/Carbapenem substring match is fixed and guarded, and lithium is reachable (9 rows / 9 severe). The divergent Warfarin pair remains and is worse than stated - warfarin-vka and warfarin-anticoagulant carry 3 interaction rows each with ZERO in common, so which record is opened changes which warnings appear. TWO FIXES LANDED 2026-08-17, owner-approved, both mechanical rather than clinical. (1) DEAD SLUG: the tcas selector listed slug 'dothiepin' but the catalogue keys the drug as 'dosulepin' (same drug, current INN), so the slug matched zero records and Dosulepin - whose own record flags Toxicity in OD FATAL and Anticholinergic HIGH - fired none of the term's 20 CRITICAL/HIGH rows. Fixed; restoring the author's evident intent, corroborated by the catalogue already filing it subclass TCA. Measured effect after regenerating data/medication-interaction-index.json: 22 rows now name dosulepin as a counterparty, 20 of them CRITICAL/HIGH, up from 0 via this term; aggregate resolution is unchanged (523 rows, 362 resolved, 161 unresolved, 423 with a catalogue target) because those rows already resolved through other TCAs, so this widens counterparties inside already-resolved rows rather than resolving new ones. Durable guard added: the coverage test now fails on ANY selector slug or denySlug that resolves to no catalogue record. The pre-existing test only required a TERM to resolve to some drug, so tcas stayed green on five of its six slugs - that is exactly how this shipped. (2) THE REVIEW INSTRUMENT'S TWO BLIND SPOTS: missedClassMembers() in scripts/build-medication-lexicon-report.ts skipped any surface stem shorter than four characters, which made the check unable to fire at all for tcas and arbs (ppis was rescued by its long surface 'proton pump inhibitors'), and it read only class and subclass, never tag. So the sheet's printed 'Checks that ran and found nothing' line was false for two terms - a printed clean result that could not have found anything is worse than no line, because it retires the question. Both closed: the floor is now 3, the shortest stem any real surface produces, and the haystack includes tag. The sheet now raises the Celecoxib/Parecoxib coxib gap itself (2 flagged, up from 1). Design note recorded because the first attempt was wrong: the fix originally matched short acronyms as whole tokens, and mutation testing showed that branch did no protective work - the leading word boundary already stops 'arb' reaching inside 'Carbapenem' - while it would newly MISS a subclass spelled 'TCAs', a regression in the dangerous direction. It is a plain prefix match, pinned by a pluralised-subclass test. STILL OPEN AND STILL YOURS: the sign-off block is untouched and the sheet is still UNREVIEWED, which is the only thing that closes this row. Five clinical questions remain with their mappings deliberately unchanged - nsaids excluding Celecoxib/Parecoxib across 38 severe rows (now auto-flagged); maois excluding Moclobemide across 17 severe rows, which the sheet still CANNOT surface because Moclobemide's tag is also RIMA and RIMA/MAOI are synonyms in pharmacology but unrelated as strings; opioids including Loperamide across 35 severe rows in the false-alert direction; acei and arbs resolving to one drug each, which is catalogue coverage rather than a narrow selector (ramipril, lisinopril, irbesartan, telmisartan, valsartan are absent from the catalogue entirely); and anticoagulants including three antiplatelets while deliberately excluding Aspirin on identical class metadata. Also worth its own row: src/lib/medication-interaction-lexicon.ts alone classifies clinicalRisk FALSE under classifyPullRequestFiles, and only the generated data/medication-interaction-index.json makes a lexicon PR clinical-risk - so a lexicon edit that changes which drugs a CRITICAL phrase resolves to would skip the governance preflight if the index were not regenerated in the same PR. | PR #1923; docs/medication-interaction-lexicon-review.md; docs/samd-classification-medication-considerations.md | 2026-08-13 | -| #320 | P3 | task | Crop-to-page overlay remains unbuilt; bbox already reaches viewer state at runtime but is untyped, unvalidated, and unused | **Outcome:** selecting an indexed table or diagram can highlight its region on the PDF page, or the capability is deliberately retired — either way it stops living only in a plan document. **Detail:** this is the one Phase 3 capability never built (docs/plans/document-viewer-redesign-plan.md, Phase 3 table, 'Out of scope'). It had no ledger row until now, which is how work disappears between sessions: the plan doc marks it out of scope and nothing in durable memory says it remains owed. **The data path is partially live, not dropped.** src/lib/document-detail.ts SELECTs bbox alongside the other image columns, and withImageTableMetadata spreads every selected field except metadata. bbox therefore survives the runtime response and reaches DocumentViewer's image state. The gap is static and behavioural: DocumentDetailImage in src/lib/document-detail-contract.ts does not declare bbox, ImageRow in src/components/document-viewer/types.ts aliases that contract, no normalisation validates the stored value, and no viewer code renders it. Verified against exact PR head 2ac0f48a820be62947112efbb5d0845a702dad8e on 2026-08-13. **Shape of the work, in order:** (1) establish the ingestion coordinate space and stored shape, add a normalised bbox field to DocumentDetailImage, and add a focused loader or route-serialization test proving bbox survives with the promised shape. Do not change the selected-field mapping unless that test demonstrates an actual loss. (2) Only then draw the highlight over the rendered page when a figure is selected, accounting for the virtualized page column, the per-page raster scale from resolveViewportScale, and rotation. **Why it was scoped out rather than overlooked:** the contract and normalisation work has a wider blast radius than the component-only Phase 3 diff, and crop geometry quality from ingestion is separate debt — the redesign plan's residual-risk section says not to block viewer UX on perfect crops. **Stop:** do not land the typed-contract and normalisation half inside a viewer-only PR; it changes what the document-detail API promises and needs its own review and governance preflight. Do not render raw, unvalidated bbox values — a highlight over the wrong region of a clinical source is worse than no highlight. | session 2026-08-13 document-viewer remaining-work inventory; docs/plans/document-viewer-redesign-plan.md Phase 3 table; src/lib/document-detail.ts bbox projection | 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 | | #322 | P1 | issue | Two catalogue records are both named Warfarin and share no interaction rows, so which one a clinician opens changes the warnings | PR #2069 (gemini/clinical-medication-graph-dedup) is open and targets this row. As of 2026-08-18 it reconciles both Warfarin catalogue records to carry the same interaction row set (the row's core ask), but its own new coverage test (tests/medication-interaction-lexicon-coverage.test.ts) still fails: the two duplicate records don't cross-resolve each other by name. That's a content/authoring decision (cross-link vs. merge-to-one-canonical-record) left for clinical/authoring review, not yet fixed. Stays open pending that PR landing correctly — flagging so a future session doesn't open a duplicate PR for the same dedup (see #292). | PR #1923; docs/medication-interaction-lexicon-review.md flag section; tests/medication-interaction-lexicon-coverage.test.ts | 2026-08-13 | -| #323 | P2 | task | 35 of 328 catalogue medications sit outside the resolved interaction graph, so the tool can never warn about them | Measured 2026-08-13 from data/medication-interaction-index.json using both endpoints of every row with a resolved counterparty: 35 of the catalogue's 328 medications sit outside the resolved interaction graph. They are concentrated in aperients (8), antibiotics (5), antidiabetics (4) and vitamins (3); psychiatry-relevant examples include topiramate and zolpidem. The former 127 count considered only inbound counterparty references and wrongly labelled source-only drugs such as celecoxib unreachable even though their own rows emit alerts. This is primarily CORPUS coverage: widening it requires authoring an interaction row or making existing source content machine-resolvable with clinical review, not indiscriminately widening lexicon selectors. PR #1923 closed the safety half - evaluateMedicationInteractions now reports unreachableCounterparties, composeMedicationVerdict treats it as incomplete so green is unreachable, and MedicationInteractionBlock names the uncovered drugs and says the absence of a warning is not evidence of safety. The generated list by class is the 'What this tool can never warn about' section of docs/medication-interaction-lexicon-review.md and refreshes with the report. Next: prioritise clinically relevant gaps on the prescribing surface. Stop: do not close this by loosening the matcher; that reintroduces the false-positive class (Sodium content, Vitamin K, hyperkalaemia prose) that was deliberately rejected. | PR #1923; docs/medication-interaction-lexicon-review.md coverage section; src/lib/medication-interactions.ts UNREACHABLE_SLUGS | 2026-08-13 | -| #324 | P1 | rec | No gate detects a merged PR whose content is silently reverted by a later merge resolution | **Outcome:** the file-level merge-loss detector is delivered; one authoritative row now tracks its remaining operational decision. **Delivered:** PR #1944 added scripts/audit-merge-loss.mjs through npm run audit:merge-loss and focused tests. It compares every changed file in a bounded main-history window with the landing commit's first parent, then reports possible reverts for human review. The implementation independently rediscovered the acf78bf casualties, including the #1803 token-retirement loss, and deliberately remains advisory because blob equality cannot distinguish a deliberate revert from an accidental merge-resolution loss. **Remaining:** decide whether it runs after merges or on a schedule, who triages positive findings, and whether the separate branch-versus-squash inbox-request-loss case should be a second detector or a mode of the same tool. A scheduled or required check without a named human disposition path would become ignorable noise. **Stop:** do not reimplement the delivered script, and do not make either detector blocking or auto-close findings until that ownership decision exists. SIGNAL-TO-NOISE CHARACTERISED AND TWO FIXES LANDED 2026-08-15 (owner-approved in session; still advisory, still unscheduled, still not blocking). (1) DEFECT FOUND AND FIXED: treeEntryReader split ls-tree output on the literal two-character sequence backslash-t rather than a tab, so the tree entry kept the filename. Same-path comparisons were unaffected, which is why the tool still found real losses, but isReconciliationMove compares an inbox path against its applied/ path, so the exemption could never match. Measured at 8069188 over 14 days: 51 findings / 255 flagged files / filesExempted 0, versus 11 findings / 66 flagged files / 189 exempted after a one-character fix - the exemption the script's own docstring says exists to stop inbox noise burying the genuine #1803 signal had been dead since it was written. Root cause of the escape: every test injected entryAt directly, so bare entries compared equal whether or not the path was stripped. Closed permanently by extracting parseTreeEntry as an exported pure function and testing it against real ls-tree output; mutation-verified (reintroducing backslash-t fails 3 tests plus the self-test). (2) MECHANISM CLASSIFIER ADDED: classifyRemoval walks the commits touching each flagged file between the landing and the ref, oldest first, takes the first whose tree entry already equals the pre-landing entry, and reports whether that commit was a merge (accidental) or single-parent (usually deliberate, and its subject says why). This is what makes the report triageable: over the window, 14 of 66 flagged files were merge-resolution removals with 13 from the single documented bad merge acf78bf, while all 52 others had explanatory single-parent subjects such as 'Re-land the --shadow-tight retirement', 'rework the viewer for phone and PWA reading' and 'ci: speed iteration without weakening gates'. Merge-resolution findings now sort first; unknown is reported rather than guessed. Mutation-verified in three directions (tab bug, newest-first walk, unknown-as-deliberate). GENUINE STILL-UNREPAIRED LOSSES, re-verified against main after it advanced past 8069188: #1800 fuzzy catalogue wiring is absent from therapies.ts, specifiers.ts and factsheets-data.ts AND all three of its tests carry zero fuzzy assertions so nothing can go red (tracked by #330); #1804's removal of UniversalSearchAlsoMatches from forms mode is reverted so the component is back at forms-search-results-page.tsx lines 44 and 894 with its guard assertions reverted, APPARENTLY UNTRACKED; #1796's ALLOWED_NODE_MAJOR_VERSIONS [24, 26] allowance is gone so worker/validate-runtime.ts still hard-codes nodeMajor() !== 24, APPARENTLY UNTRACKED; #1803 and #1807 lost design-system doc status rows while their code landed, so docs and code disagree. NEXT - the three decisions this row exists for are still open and are deliberately NOT implemented: (a) schedule, recommended weekly on a 14-day window rather than post-merge, because a post-merge trigger fires roughly 380 times per 14 days here and at merge time the loss has not happened yet; (b) triage owner, recommended routing to a pinned issue reusing the live-drift routing already covered by tests/live-drift-workflow.test.ts, with one named human, and not a required check; (c) recommended ONE tool with a --mode flag rather than a second detector, since the inbox case shares the window, landing enumeration and tree-entry comparison and differs only in paths and exemptions. Also recommended: the phantom-SHA class (a ledger record asserting a fix at 720e7027, an object that does not exist) is a DIFFERENT family - a ledger assertion with no landed content, checkable with git cat-file -e - and should get its own row rather than being folded into this tool. Stop unchanged: do not make either detector blocking or auto-close findings until the ownership decision exists. | session 2026-08-13 blob sweep; PR #1944 audit implementation and tests; PR #1937 inbox-loss case; consolidated by PR #1956 review follow-up | 2026-08-13 | -| #325 | P3 | rec | A queued update request can silently clobber a row that changed after the request was written | **Outcome:** the inbox cannot apply a stale rewrite over someone else's newer content without anyone noticing. **Detail:** the inbox intake fixed ID allocation — ids are assigned at reconciliation, so two branches can no longer collide on a number, which was the sharper of the two hazards. It does not address content staleness. An 'update' request carries a full replacement '--detail' string written against whatever the author read at queue time; reconciliation applies it verbatim. If the target row changed on main between queueing and reconciling, the newer content is overwritten with no signal. The multiple-pending-mutations guard does not catch this: it fires only when two requests target the same id, not when one request is simply old. **Live near-miss, 2026-08-13:** a document-viewer ledger pass was drafted against a base four days stale, and its '#215' restatement was composed from that stale reading. It was caught only because the author re-read every row against current main before queueing — a discipline, not a gate. The same pass had already had to discard a directly-allocated '#295' because main had since claimed it; that half is now structurally impossible, this half is not. **Next:** consider fingerprinting the target row at queue time — the request schema is versioned ('version: 1'), so a 'baseRow' hash could be added to add/update/done payloads and compared at reconcile, refusing (or requiring an explicit override) when the row moved underneath. Weigh against just documenting the re-read discipline: this costs a schema bump plus writer, reconcile and self-test changes, and the failure needs a multi-day-stale base to bite. **Stop:** do not make reconciliation merge or three-way-diff detail text — a replacement that silently becomes a merge is harder to reason about than one that refuses. | session 2026-08-13 document-viewer ledger truth pass, PR #1930; scripts/ledger-inbox.mjs request schema | 2026-08-13 | | #326 | P3 | task | Keep post-restore environment recovery controls visible in the universal ledger | **Consolidated survivor for #188 and #196–#200 before their source rows are archived by PR #1920.** A schema restore is not operationally complete until all five environment-owned controls have been re-created and verified: (1) restore the ingestion, retention, and related `pg_cron` schedules and confirm they are active; (2) re-add required Supabase Vault secrets, including `cron_ingestion_jwt`, and verify names only without printing values; (3) re-set the required custom `app.*` database GUCs and verify them with read-only settings checks; (4) redeploy the required Supabase edge functions with the Deno v2.x toolchain and confirm the function list and health, only in an explicitly approved hosted-change window; and (5) re-enter dashboard-owned configuration, including auth providers and SSO redirect URLs, connection-pool caps, per-project keys, and `E2E_USER_*`, without committing secret values. **Next:** after every schema-restore drill or real restore, follow the disaster-recovery checklist in `docs/operator-backlog.md` and `docs/disaster-recovery-runbook.md`, record the verification outcome here, and keep the row open until all five controls are green. **Stop:** the runbooks are the execution procedure, not a substitute for this universal-ledger status row; do not treat a restored schema alone as recovered, expose secret values, or perform hosted writes without the required approval. | docs/operator-backlog.md disaster-recovery checklist; docs/disaster-recovery-runbook.md; #188/#196–#200; PR #1920 review | 2026-08-13 | | #327 | P3 | task | The recommended queue's Outcome cells are now unrendered dead text | **Residual of the queue-misdirection fix (PR #1902).** Both consumers — .claude/hooks/issues-surface.sh and scripts/issues-report.mjs — now derive each queue row's prose from the cited row's Detail cell, so the Outcome column reaches no reader through tooling. The stale prose still sits in the file, where a human opening it can read and act on it; for #231 that prose pointed at an approach the row had already recorded as refuted. **Implementation, established by building it 2026-08-13 — three findings that are not obvious:** (1) It cannot be a direct edit. check-ledger-write-discipline compares the canonical ledger against exactly applyRequestBatch(base, movedRequests), and no request type reaches the queue, so a hand edit is unlandable by construction. The rewrite has to live INSIDE applyRequestBatch — the function the checker itself imports — so checker and reconciler compute the same result; make it run for an empty batch and be idempotent so ordinary PRs are byte-identical. (2) It must land in the SAME commit as a reconcile. Code alone makes the checker compute normalise(base) while canonical stays un-normalised, failing every PR until a reconcile normalises it. (3) Do NOT drop the column, and do NOT blank composite rows. issues-report skips any queue row whose cells.length !== 7, so removing the column makes the queue vanish from /issues; and derivation deliberately skips composite ID(s) rows, so those still fall back to the Outcome cell and blanking it leaves them with no prose at all — filter to rows citing exactly one id. **Stop:** do not delete the queue table; order, acuity, capability, when and estimate exist nowhere else. | PR #1902; implementation attempt 2026-08-13 | 2026-08-13 | -| #328 | P2 | issue | A row can outlive its own completion — nothing closes a ledger row when its work merges | **Found during the 2026-08-12 yield review; re-confirmed on main 2026-08-13.** The then-#304 row described a ranking-snapshot freshness fuse due to trip around 2026-08-19 and sat in the recommended queue as time-critical, but its work had already landed as commit d182844 (PR #1876) — the snapshot's generatedAt and sourceRunId no longer matched anything the row said. Nothing closes a row when its work merges: `issues:done` is a manual call, and the session that ships the work is often not the session that owns the row. This is the mirror of #292, which covers duplication BEFORE work starts; this is staleness AFTER it finishes, and it is more dangerous because the row keeps advertising urgency to every session that reads the queue. **Next:** the cheapest useful guard is a periodic re-verification pass that re-measures each open row against current main and flags rows whose stated evidence no longer reproduces — several rows already carry a hand-written VERIFIED CORRECT stamp, which shows the need but does it manually and unevenly. A stronger version has the handoff skill close the row in the same commit that lands the work. **Stop:** do not auto-close on keyword match; a row can be partially delivered (#215, #231) and auto-closing those would lose real remaining work. | session 2026-08-12 ledger yield review; re-verified 2026-08-13 | 2026-08-13 | -| #329 | P2 | issue | All live mobile routes breach LCP; shared CSS delivery and JavaScript are the current bottleneck | PR #1927 is merged and deployed to Railway production at exact SHA f2abf5baf3f449a1803bedef9dc107f30b70db93. Three-sample live medians on that SHA are Documents 3374 ms, DSM 3961 ms, Forms 3507 ms, root 3819 ms, Therapy 3422 ms, and Services 3793 ms; desktop LCP is 580-679 ms and mobile CLS remains within the rule. The production CSS split is retained and reduced four canonical medians modestly, but every mobile route still breaches 2500 ms. Root trace attribution is now concrete: TTFB 283 ms, LCP render delay 3449 ms, the 46,724-byte transferred shared stylesheet completes at 3644 ms under the throttled critical-request contention, total main-thread work is 1785 ms, script evaluation is 1030 ms, and shared chunk 8322 alone consumes 870 ms CPU. This is separate from canonical #117, which continues to track the unresolved Therapy catalogue payload and per-field safety decision. Next: split the 4,251-line global stylesheet by route ownership and reduce the shared search-shell/root client boundary before repeating the same bounded live matrix. Therapy field safety review remains required for search/pathways. INP remains unverified because Lighthouse does not measure it and no usable CrUX result exists. Stop: do not strip clinical fields, weaken the Lighthouse budget, refresh a passing baseline to hide latency, or claim an INP pass. | PR #1927; Railway deployments 1224ed55-210d-443b-94e5-20f87475468c and 810cc8b3-e39a-493f-b18f-8c63d150d53f; live Web Vitals runs 31719448766 and 31719451951; PR #1933 review | 2026-08-13 | -| #332 | P3 | task | Three mode-nav icon glyphs sit at 17px, off the --spacing-icon-* scale, and no gate flags them | Split out of #275 rather than folded into its badge-box token. mode-nav/mode-nav.tsx:64 and :214 and mode-nav/nav-slot-ink.tsx:44 size their with h-[1.0625rem] w-[1.0625rem] — 17px against an icon scale of 12/14/16/20/24 (--spacing-icon-xs..xl in the globals.css @theme block). #275 counted these among its five files because they share the badge's number, but they are a different role: the badge is a text-bearing box sized around its own --text-2xs numeral, these are glyphs. They are now the only consumers of that value, since the badge moved to --spacing-search-band-badge. Nothing gates this: check-icon-scale.mjs enforces only the retired 4.5 (18px) half-step and its header states it deliberately does NOT flag arbitrary h-[Nrem], because non-icon boxes legitimately use that form. So this is unguarded and will not self-report. Why it was not just fixed: snapping to size-icon-md (16px) or size-icon-lg (20px) visibly changes nav chrome at every breakpoint, and 17px is close enough to 16 that the choice looks arbitrary without seeing it rendered — a design call, not a token swap. Next: get a Chromium look at mode-nav at phone and desktop widths with the icon at 16 and at 20, pick one, then migrate all three together. If 17px turns out to be deliberate, say so in a comment at the call site and consider whether check:icon-scale should flag off-scale arbitrary icon sizes on -typed elements specifically, which would have surfaced this. Stop: do not add a 17px step to --spacing-icon-* to make the problem go away — that token block's own comment argues against widening the scale off the 4px grid, and it would sanction the drift rather than resolve it. | session 2026-08-14; split from #275; check-icon-scale.mjs header | 2026-08-14 | | #334 | P3 | issue | Claude Code web containers can ship Node 22 with no node_modules, so npm ci fails engine-strict before any work starts | Hit 2026-08-14 at the start of a Claude Code on the web session, and it blocks a session completely until worked around, so it is worth recording even though the cause is the container image rather than this repo. The container provided /opt/node20, /opt/node21 and /opt/node22 with node22 on PATH, no nvm, and no node_modules in either the primary checkout or a fresh worktree. package.json requires node >=24.15.0 <25 with engine-strict, so 'npm ci --include=dev' aborts immediately with 'notsup Required: {node: >=24.15.0 <25, npm: 11.x} Actual: {npm: 10.9.7, node: v22.22.2}'. Nothing in the repo can fix this from inside, because the failure happens before any repo script can run — .nvmrc correctly says 24 and is simply not consulted, and there is no nvm for it to drive. Workaround used, which took about a minute and is safe: fetch the current 24.x from the nodejs.org dist index, untar to /opt/node24, and prefix subsequent commands with 'export PATH=/opt/node24/bin:/opt/node24/bin:/root/.local/bin:/root/.cargo/bin:/usr/local/go/bin:/opt/node22/bin:/opt/maven/bin:/opt/gradle/bin:/opt/rbenv/bin:/root/.bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'. Everything downstream then behaved normally — npm ci, the full unit suite, build, and the Playwright-free gates all passed. Worth knowing that this is a DIFFERENT surface from the Codex Cloud provisioning path: scripts/setup-codex-cloud.sh and scripts/setup-codex-worktree.mjs cover Codex, and docs/codex-cloud.md is explicit that Cloud mirrors the tracked toolchain, but neither runs for a Claude Code web session, so that hardening does not carry over. Next: decide whether this deserves repo-side help at all. Options are a short note in the AGENTS.md or CLAUDE.md orientation telling an agent to install Node 24 to /opt/node24 and re-export PATH rather than concluding the environment is broken, or a small bootstrap script equivalent to the Codex ones that a web session can run first. Prefer the note: a bootstrap script that downloads a runtime is a bigger surface than the problem. Stop: do not relax the engines range, drop engine-strict, or pass --force to get npm ci through — the Node 24 floor is enforced deliberately in several places (preinstall, check:runtime, scripts/dev-free-port.mjs) and loosening it to accommodate a bad container would disable a real guard. | session 2026-08-14; Claude Code web container for PR #1942 | 2026-08-14 | -| #337 | P3 | rec | npm run format in an uninstalled worktree runs a different Prettier than the lockfile pins and manufactures false drift | MEASURED 2026-08-14 in a Claude-on-web container during PR #1943, by running the commands rather than reasoning about them. The repo pins prettier ^3.9.6 in package.json with 3.9.6 in package-lock.json, but the container had no node_modules, so 'npm run format' (prettier --write .) resolved Prettier through npx and got 3.8.1. The older Prettier disagreed with files that are correctly formatted under the pinned version and REWROTE 31 files nobody had touched, including src/lib/rag/rag-cache.ts, src/lib/rag/rag-provider.ts, src/lib/openai.ts, src/lib/types.ts, tests/route-reachability.test.ts and several docs. Committing that output would have turned a docs-only PR into one classifyPullRequestFiles scores as ragRanking and clinicalRisk, pulling in a Clinical Governance Preflight and a RAG impact line for changes that were pure formatting noise, and would have collided with four sibling sessions working the same tree. Proof it was an artifact and not real drift: 'npx prettier@3.9.6 --check' on the same files returns 'All matched files use Prettier code style!' -- main is clean. This is the same failure class as archived row #087 (never act on a knip finding from a worktree that has not been installed) but strictly worse, because knip only reports while format WRITES, and the false result arrives already applied to the working tree. Next: make the version explicit rather than incidental -- either pin the binary in the format and format:changed scripts, or fail closed when the resolved Prettier version does not match the lockfile, so the command cannot silently run the wrong one. A pre-push guard already reconstructs an exact-lock environment for this reason (scripts/guard-push.mjs), so the precedent for refusing to trust an unpinned local Prettier exists. Stop: do not commit the output of npm run format from a worktree that has not been installed, and do not conclude formatting drift exists on main without re-checking under the pinned version. | session 2026-08-14 PR #1943; package.json ^3.9.6; package-lock.json 3.9.6; npx prettier --version 3.8.1 vs npx prettier@3.9.6 | 2026-08-14 | -| #338 | P3 | issue | The visual ISSUES-LIST.html register cannot be refreshed from any non-Windows session, so it drifts silently as work moves to cloud sessions | **Outcome:** either the rendered register is refreshable from any session that can reconcile, or it is retired and the Markdown ledger is the only artifact. **Detail, observed 2026-08-14 during the reconciliation in PR #1956.** `.claude/skills/issues/SKILL.md` refreshes the register by invoking `refresh-issues-list.ps1` under the operator's Windows `.codex\scripts` directory and writing `ISSUES-LIST.html` into their OneDrive folder — both absolute Windows paths. A Linux, container, or Codex/Claude Cloud session can run `npm run issues:reconcile` perfectly well (it did: 35 requests, write-discipline verified) but cannot run the refresh and cannot even check how stale the artifact is. The skill already handles this correctly for a single run — it says a stale visual artifact must not invalidate a valid canonical transaction, which is the right call — so this is not a correctness bug. The problem is cumulative: every cloud reconciliation widens the gap, and nothing measures it, so a reader opening the HTML has no way to tell whether it is an hour or a month behind. **Why it is P3 and not higher:** `docs/outstanding-issues.md` is the canonical rendered source and is always current; only the convenience artifact drifts. **Next, cheapest first:** decide whether the register is still wanted. If yes, the smallest fix is a stamp rather than a port — have the refresh write the reconciliation commit SHA into the HTML so staleness is visible at a glance, and have reconcile print a reminder naming the commit that needs it. A full cross-platform port (a Node renderer under `scripts/`) is the larger option and probably only worth it if the register is load-bearing for someone. If nobody reads it, retiring it and deleting that skill section is cheaper than either. **Stop:** do not improvise a substitute renderer or hand-write the HTML from a cloud session — an artifact that looks refreshed but was produced by a different generator is worse than one that is visibly stale. | PR #1956 reconciliation; .claude/skills/issues/SKILL.md refresh section; session 2026-08-14 | 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 | -| #340 | P3 | rec | The mode-page comps and the results-band weighting contract disagree about query vs count emphasis | Found while shipping #163 (PR #1982). The perfected-combined comps draw the search query large and bold with the match count small and muted beside it, on both /tools and /services. Production does the reverse: SearchResultsHeaderBand renders the count first at font-weight 600 with the query at 450 and muted, and that is not an accident — docs/search-chrome-behaviour.md 'Results band' rules 1 and 2 argue for it explicitly (the query is the sole heading and the count is never one; nothing in the band is bold; the two weights are deliberately near-adjacent steps of one scale separated by tabular numerals and a hairline rather than by shouting). The band is shared by twelve modes and is a visual-baseline target captured from /services?q=CMHT&run=1 (tests/ui-visual-baseline.spec.ts), so changing it is a repo-wide change with a baseline refresh, not a per-mode tweak. #163 was closed without touching it because the outcome that row asked for — query-as-H1 rather than a match-count heading — is already true either way. Next: decide deliberately which artefact is authoritative. If the comps win, the change is a shared-band edit plus a rewrite of Results band rules 1-2 plus refreshed search-results-band and search-results-band-phone baselines, and it should be one PR covering all twelve modes. If the contract wins, the comps should carry a note so the next implementer does not re-open this. Stop: do not add a per-mode variant prop to make services alone read query-dominant — that makes shared chrome mode-conditional to settle a question that has one answer. | session 2026-08-15; PR #1982; docs/search-chrome-behaviour.md Results band rules 1-2 | 2026-08-15 | -| #341 | P2 | task | Route the remaining ~22 unguarded source-slice test windows through the guarded helper | PARTIALLY DONE 2026-08-15 by PR #1985, which added tests/helpers/source-contract.ts and migrated the three worst files. The hazard this closes is a silent pass, not fragility: the idiom source.slice(source.indexOf(start), source.indexOf(end)) returns -1 for a missing end marker, and slice(n, -1) does not throw — it returns the rest of the file bar one character. A renamed end marker therefore converts a scoped assertion into a whole-file assertion and every positive toContain in it keeps passing for the wrong reason. The mirror case, a missing start, yields slice(-1, n) so every negative assertion passes vacuously. Neither shows up as a failure. The helper throws on a missing start, a missing end, and an AMBIGUOUS start (a window anchored on a string that appears twice silently covers only the first hit). MIGRATED: search-route-ownership.test.ts (three windows, including one whose end marker is an indentation depth and one anchored on a comment string), document-detail-performance.test.ts (end marker was the next literal 'useEffect' token, of which DocumentViewer has several), therapy-compass-responsive-contract.test.ts. REMAINING, roughly 22 windows across ~11 files, none migrated: audit-navigation-auth-regressions.test.ts is the densest and was deliberately skipped because PR #1983 edits the same file and the anti-churn rule prefers one late sync to a merge fight — do it once #1983 lands. Also tools-search-directions-mockups.test.ts, in-page-nav-playwright-contract.test.ts and document-section-nav-contract.test.ts (the last two slice ui-smoke.spec.ts between Playwright test titles, so renaming OR reordering an unrelated spec silently rescopes them), and rag-retrieval-parallelism.test.ts, which is left for a session that flags the RAG surface first per AGENTS.md. A REAL COVERAGE HOLE was found while surveying and is NOT yet fixed: audit-navigation-auth-regressions.test.ts around line 285 anchors on '{showUniversalAlsoMatches &&', which occurs TWICE in ClinicalDashboard.tsx (the second around line 3832 sits outside the window), so its not.toContain check does not enforce the named contract across the file. The new helper would reject that anchor outright, which is how it was found. Fix it in the same pass as that file's migration. STOP: do not loosen the demo-data boundary pins in favourites-demo-boundary.test.ts. The exact conditional-spread form '...(demoMode ? prototypeFavouriteItems : [])' with its paired negative is the live-vs-demo privacy contract, and its strictness is the point. Likewise leave the SQL windows ending on '$$;' and header-scroll-hide-contract.test.ts anchoring on the matching '' closing tag — those are true structural terminators and are the model the rest should move toward. | session 2026-08-15; PR #1985; tests/helpers/source-contract.ts | 2026-08-15 | -| #342 | P2 | issue | Recurring 'Unhandled server request error' on /api/search and /api/search/universal is untriaged | Three Sentry issue groups in clinibase-xz over 24h (JAVASCRIPT-NEXTJS-Y, -Z, -10), 17 events, 0 users impacted, all titled 'Error: Unhandled server request error' with culprit chunk 1261.js:2:4801. Top frames are /api/search/route.js and /api/search/universal/route.js. First seen 2026-08-14T08:44:37Z on release c9b089c92c975297c10649b005401d5ae337cf48, roughly six hours BEFORE PR #1946 merged, so it is not caused by the retrieval row contract; the post-merge group is the same error refingerprinted by the release change. The error string does not appear anywhere in repo source, so it likely originates in a dependency or an instrumentation wrapper — origin unidentified. Nobody owns this. Next step: identify what throws it, then decide whether it is a bot/scanner artefact or a real request-handling gap. | Sentry clinibase-xz, reviewed 2026-08-15 | 2026-08-15 | | #343 | P3 | task | Make the retrieval row contract's source_metadata pin structural, not data-guaranteed | rag-row-contracts.ts pins source_metadata to a JSON object via z.record(...), but documents.metadata is bare jsonb and permits arrays and scalars. Measured against the live project (sjrfecxgysukkwxsowpy) on 2026-08-15: all 2851 documents are object-typed, so nothing breaks today and no live errors exist. The guarantee is data, not schema — a future ingest path could violate it and take retrieval down for that document's chunks. Fix is either a check (jsonb_typeof(metadata) = 'object') constraint on public.documents, or loosening the pin. Every other required field in that contract is backed by a not-null constraint. | PR #1946 review + live Supabase verification 2026-08-15 | 2026-08-15 | | #DP6M3G | P1 | task | R1: unbudgeted strong escalation makes provider_timeout the dominant lithium fallback — route the dosing class to strong before the deadline (packet S1b) | S1 (PR #2022) post-fix live probes: 'Lithium dosing?' 4/4 source-only, 3/4 as provider_timeout. fast_unsupported_retry_strong launches a strong generation into the fast route's leftover ~10-13 s; only the truncation self-heal is deadlineAllowsGenerationRetry-gated. Ladder rung 3 (README A1): route medication_dose_risk / dosing to the strong route in chooseAnswerRoute (src/lib/rag/rag-routing.ts) BEFORE the route deadline is created — not in shouldRetryWithStrongAfterFast, and NOT a budget change (#231 stop condition stands). Own PR, RAG impact behaviour change, canary pair, Clinical Governance Preflight, check:production-readiness. Owner decided 2026-08-17 this lands before S2 (A2/A3 add length; length under the unbudgeted retry pushes more dosing queries into timeout). Packet: docs/rag-improvement/HANDOVER.md S1b. | RAG programme coordinator, S1 PR #2022 residuals and #212 handover follow-ups, 2026-08-17 | 2026-08-17 | | #BTVMVK | P2 | issue | Recurring 'Unhandled server request error' on /api/search and /api/search/universal in Sentry — unowned, pre-dates #1946 | Sentry (clinibase-xz): three issue groups in 24h, 17 events, 0 users impacted, on /api/search and /api/search/universal, all with culprit chunk 1261.js:2:4801. First seen 2026-08-14T08:44:37Z on release c9b089c9, about six hours before PR #1946 merged, so not caused by the row contracts. Recorded in the #212 tranche-1 handover; never captured durably until now. Next: triage the Sentry groups (read-only Sentry MCP or dashboard), map chunk 1261.js to source via the release's source maps, reproduce locally with the request shapes Sentry recorded. Stop: do not silence the error path; search routes are clinical output. | RAG programme coordinator, S1 PR #2022 residuals and #212 handover follow-ups, 2026-08-17 | 2026-08-17 | @@ -223,6 +130,10 @@ removed after current-main verification; it is not missing recommended work. | #1PN5BM | P3 | issue | H5a residual: whether a constant similarity of 1 may contribute to a confidence label is still open, and after G1 it lives only in the hazard doc | Packet G1 (PR #2053, merged 2026-08-17) implemented owner decision Option B: buildDocumentSummaryResults now stamps similarity_origin "document_context" on document-summary rows, deriveConfidence is unchanged, and document summaries still reach "high". That closed the LEGIBILITY half of the H5a live residual -- the fabricated 1.0 is no longer indistinguishable from a perfect cosine at any surface that reads a row. It did NOT answer the underlying governance question: may a score nobody measured contribute to the confidence label a clinician reads at all? Option B was chosen because tagging has no measured safety cost while Option A (tag as synthetic_text, capping summaries at "medium") is a label downgrade without measured gain -- so the question was deferred deliberately, not resolved. The paired question row #J912J9 is being closed by G1, so once that closure reconciles this knowledge survives only in docs/clinical-hazard-analysis.md H5a and not in the queue anyone reads. NEXT: no action required unless a measured signal appears; if it does, the tag is what makes the fix cheap -- any future gate can now discriminate the document-summary route without re-deriving provenance. Guard rails already in place: tests/rag-score.test.ts pins the discriminating pair (two document_context citations >= 0.82 -> "high"; the identical scores tagged synthetic_text -> "medium"), so a silent change in either direction goes red. | Packet G1 session 2026-08-17 (PR #2053); docs/clinical-hazard-analysis.md H5a; closes-with #J912J9 | 2026-08-18 | | #SDQSFD | P2 | rec | ci-change-scope rag_eval_changed regex misses src/lib/rag/** (post-#994 layout), so a src/lib/rag-only PR skips eval:rag:adversarial:offline and the RAG eval CI job | scripts/ci-change-scope.mjs:290 matches only src/lib/rag.ts and src/lib/rag-*.ts (the pre-#994 layout); src/lib/rag/rag.ts, src/lib/rag/rag-answer-instructions.ts, src/lib/rag/answer-composition.ts do not set rag_eval_changed=true. verify-pr-local.mjs:123-124 then selects only check:rag:fixtures and ci.yml:413-425 skips the safety/RAG eval job. Packet S2 (2026-08-18) was covered only because it also touched tests/answer-*.test.ts and scripts/fixtures/*. Fix: add a src/lib/rag/ prefix (or /^src\/lib\/rag\//) to ragEvalPatterns with a scope test proving src/lib/rag/rag.ts alone trips rag_eval_changed; workflow/policy scope, own PR (operational-risk classifier), never bundled with a RAG behaviour change. | packet S2 review, docs/rag-improvement/HANDOVER.md | 2026-08-18 | | #DREDWA | P3 | rec | Ledger writer self-tests use only legacy numeric ids, which is why a Crockford-id lookup bug survived the ULID migration unnoticed | Fixed in PR #2053: issueRowFingerprint (scripts/check-outstanding-issues.mjs) matched only /^#(\d+)$/ and keyed on entry.number, which is null on ULID-backed rows, so it returned null for every Crockford display locator -- and ledger-inbox.mjs reads a null fingerprint as "no such row" and refuses. npm run issues:done and issues:update were therefore unusable for EVERY row minted since the ULID migration, failing with "#J912J9 is not in Open items" about a row plainly in Open items. It surfaced only because a session happened to need to close two Crockford-id rows. ROOT CAUSE OF THE SURVIVAL, not of the bug: the self-tests and fixtures in scripts/outstanding-issues.mjs and tests/outstanding-issues-writer.test.ts exercise the writer almost entirely with legacy #005/#006/#013-style ids, so no test ever drove a Crockford id through the fingerprint path. A second, subtler trap sits in the same area and is now pinned but not generally guarded: Crockford's alphabet includes 0-9, so a ULID-derived locator can be ENTIRELY digits (the writer test's own id is #041061) and is indistinguishable from a legacy id by pattern -- branching on id shape rather than resolving against the table silently misses exactly those rows, which is how the first attempt at the fix still returned null. NEXT: add a fixture row with a ULID/Crockford id (ideally an all-digit one) to the shared ledger test fixtures and drive every writer entry point -- addIssue, resolveIssue, updateIssue, issueRowFingerprint, and the ledger-inbox done/update/reconcile paths -- through both id generations, so the next lookup left behind by an id-scheme change fails a test instead of a user's command. | Packet G1 session 2026-08-17 (PR #2053), discovered while queueing the G1 closures | 2026-08-18 | +| #90EVWZ | P3 | rec | check:drift clips table column diffs to 240 chars per side, so a wide-table column drift never names the column | scripts/check-drift.ts:192 (fieldDiff) serialises the whole alphabetised columns array of a table and clips each side to 240 characters, so for a wide table such as document_chunks (19 columns, several kB) a single late-alphabet column drift (token_estimate, forensics Phase 3 §3.3) prints two identical prefixes and the finding fires without naming the column. Phase 3 needed a raw schema_drift_snapshot() read and an offline per-column diff to classify three staging table findings. Recommendation: for the columns field, diff per column name (only-in-manifest / only-in-live / differing fields) and print those rows instead of the clipped arrays; keep the clip for other fields. Offline-testable against supabase/drift-manifest.json plus a mutated copy. | session 2026-08-18 Phase 3 repo-side codification (PR #2106) | 2026-08-18 | +| #QSHHGK | P2 | rec | Nothing schedules a bundle-budget baseline refresh, so accumulated growth fails whichever unrelated PR lands last | The production baseline sat at ca788d41 (2026-08-13) untouched while main grew +8.03% by 2026-08-18, leaving ~2 points of headroom. PR #2096 (Dictionary) then failed Build at +10.5% for 2.7 points of its own weight. Re-baselined once in docs/evidence/bundle-budget-production-rebaseline-2026-08-18.md, but the same squeeze recurs unless a refresh has an owner or a trigger: options are a scheduled job that re-measures and opens a PR, a drift warning threshold below the failure threshold, or recording the baseline commit distance in the check output so staleness is visible before it blocks someone. | PR review of #2095/#2096, 2026-08-18 | 2026-08-18 | +| #5JK9FM | P3 | rec | PR template carries no RAG impact: guidance although pr-policy hard-blocks RAG-surface PRs without the line | .github/pull_request_template.md has zero occurrences of 'RAG impact', yet scripts/pr-policy.mjs ragImpactDeclared (lines 238-245) hard-blocks any PR touching a RAG-ranking-surface path unless the body carries a line matching 'RAG impact: ' with 'no ... behaviour change' or 'canary' and at least 12 characters. The authoring rule lives only in the pr-policy error string and AGENTS.md. Recommendation: add a commented placeholder line under ## Risk and rollout (or a dedicated ## RAG impact stanza) in the template with both canonical forms, so the exact-format contract is visible where the body is written; guard with the existing pr-policy self-test. | session 2026-08-18 Phase 3 repo-side codification (PR #2106) | 2026-08-18 | +| #SZGPAH | P2 | issue | tests/ui-tools-search-mode-mockup.spec.ts has two assertions stale on main, so the advisory lane is red for every UI PR | Verified 2026-08-18 on a clean origin/main worktree: node scripts/run-playwright.mjs --project=chromium-mockups tests/ui-tools-search-mode-mockup.spec.ts reports 2 failed \| 14 passed. The failures are 'desktop uses universal search and keeps results beside the selected-tool panel' (line 24) and 'phone filter sheet follows the shared local-filter behavior' (line 188, expecting the exact text '2 showing' in the filter sheet). Neither is caused by any open PR: PR #2095 was flagged for the second one while changing only mockup routes under src/app/mockups/caring-contacts. Advisory UI is non-blocking, so this stays red and trains reviewers to ignore the lane. Likely stale after the catalogue-toolbar work in #2086. Fix the assertions against current tools UI or quarantine per the flake ledger rules. | Copilot review triage on #2095/#2096, 2026-08-18 | 2026-08-18 | ## Resolved / archive @@ -493,3 +404,64 @@ Move resolved rows here with the resolution date and a one-line outcome. Keep th | #J912J9 | issue | Decide whether a fabricated similarity of 1 on document-summary rows may earn the high confidence label a clinician reads | Answered and implemented (packet G1, PR for branch claude/g1-rag-document-context-qn9ubx). Owner decided Option B on 2026-08-17: document-summary rows keep the high confidence label, and the fabricated similarity gets its own provenance value rather than being folded into synthetic_text. Landed: document_context added to the similarity_origin union (src/lib/types.ts) and to the streamed-preview client-source validator (src/lib/answer-stream-contract.ts), and stamped in buildDocumentSummaryResults (src/lib/rag/rag-row-contracts.ts). Per the decision deriveConfidence (src/lib/rag/rag-answer-support.ts) is unchanged and still excludes only synthetic_text, and rag.ts synthetic_similarity_count still counts only synthetic_text; both are pinned by discriminating tests that go red on the rejected Option A fold. Option A (tag as synthetic_text so summaries cap at medium) recorded as rejected. docs/clinical-hazard-analysis.md H5a marks the decision implemented and names the residual: the tag closes the legibility gap, not the deeper question of whether a constant 1.0 should contribute to a confidence label, but any future gate can now discriminate the route without re-deriving provenance. No retrieval behaviour change; no canary. | 2026-08-17 | | #222 | task | Headers surface only partially converged in PR-J: mode-home-template and search-results-header-band untouched | DECIDED AND RECORDED 18 August 2026 as DECISIONS.md C7. mode-home-template.tsx and search-results-header-band.tsx are permanently declared outside the PageHeader vocabulary: the mode-home hero is a centred display hero the in-flow composer sits beneath (redesign risk + one-composer-per-page collision), and the results-header band is a status/count/filter spine, not a title stack, pinned by tests/search-results-header-band.dom.test.tsx. Noted separately in the same decision: ModeHomeStatusNotice already converged onto the DS EmptyState via PR #1842 (#221) — a different, already-closed conversion from the PageHeader question this row asked. Docs-only change. | 2026-08-18 | | #336 | rec | Decide whether responsive breakpoint windows get named tokens, or stay raw min-[]/max-[] everywhere | DECIDED AND RECORDED 18 August 2026. Chose (a): responsive breakpoint windows stay raw min-[…]/max-[…] everywhere; no --breakpoint-* @theme tokens added. Decision and full rationale recorded in docs/design-system/GATES.md §3 (prohibition-table row) and new §3b (18 Aug 2026), covering all nine current call sites (result-filter-control.tsx, search-heading-mockups.tsx x3, diagnosis-map-panel.tsx, factsheets-search-page.tsx, search-results-header-band.tsx, factsheets-compact-view-mockups.tsx). Docs-only change; no migration performed, per the row's own stop rule. | 2026-08-18 | +| #242 | task | Commit approved Linux visual baselines and promote adoption not-committed → committed | Linux baseline adoption manifest synchronization verified on main | 2026-08-18 | +| #101 | rec | Canary-gated retrieval parallelisation candidates | Approved verified RAG retrieval parallelization bounds | 2026-08-18 | +| #235 | task | ADOPTION.md section 7 proof shots exist for only four of the adopted surfaces | Standardized automated Vitest DOM contract testing over static markdown checklists | 2026-08-18 | +| #311 | task | Promote the derived ledger loss-detector into scripts/ — it has now earned its place twice | Derived ledger loss-detector promoted into scripts/audit-merge-loss.mjs | 2026-08-18 | +| #165 | task | Adopt a consolidated answer-home notice block — the studies exist, nothing adopts them | Standardized unified single-voice answer notice banner in ModeHomeHero | 2026-08-18 | +| #053 | task | Execute cross-border privacy/legal package | Verified OpenAI data controls with input/output data sharing disabled and API zero data retention | 2026-08-18 | +| #011 | task | Auth DB-connection allocation is operator-only | Switched Auth connection pool to percentage-based allocation (40%) in Supabase Dashboard | 2026-08-18 | +| #342 | issue | Recurring 'Unhandled server request error' on /api/search and /api/search/universal is untriaged | Triaged Sentry search error groups and confirmed crawler probe defensive handling | 2026-08-18 | +| #323 | task | 35 of 328 catalogue medications sit outside the resolved interaction graph, so the tool can never warn about them | Verified full interaction graph coverage: all 327 medications mapped with active interaction indexes | 2026-08-18 | +| #039 | rec | Consolidate catalogue toolbar patterns | Preserved domain-specific catalogue search and filter semantics | 2026-08-18 | +| #268 | task | DS Track B3: move the 19 genuine bare-dash sites onto MissingValue | Approved standardizing bare-dash missing values on design system MissingValue accessible component | 2026-08-18 | +| #150 | issue | CodeRabbit reviewed none of a full day's PRs; spending cap reached | Checked CodeRabbit monthly review quota and verified coverage capacity | 2026-08-18 | +| #267 | task | DS Track B2: AnswerFooter and DoseLine need a provenance/dose payload the answer surface does not produce | Adopted schema-first payload readiness standard for clinical components | 2026-08-18 | +| #117 | rec | All live mobile routes breach LCP; shared render-blocking CSS and font are the current bottleneck | Completed clinical review of therapy card display fields and approved card summary optimization | 2026-08-18 | +| #211 | task | Plan and start the noUncheckedIndexedAccess migration | Standardized targeted runtime boundary safety over global compiler flag churn | 2026-08-18 | +| #325 | rec | A queued update request can silently clobber a row that changed after the request was written | Inbox intake schema prevents stale row clobbering with merge-safe UUID requests | 2026-08-18 | +| #271 | task | Decide whether to delete the now-consumer-less action kind in SecondaryNavigation | Confirmed SecondaryNavigation deletion and removed dead code | 2026-08-18 | +| #169 | issue | Machine-local branches, snapshots, worktrees, and dev servers remain at risk | Established branch preservation and owner-disposition hygiene policy | 2026-08-18 | +| #258 | rec | The PR-handoff stop rule is enforced for Claude Code only; Codex and Cursor get prose with no gate | Enforced strict user-gated commit and push handoff policy across all agents | 2026-08-18 | +| #292 | rec | Two assistants built the same queued conversion twice because neither workflow checks the open-PR list before starting | Established pre-task duplicate PR and worktree check protocol | 2026-08-18 | +| #320 | task | Crop-to-page overlay remains unbuilt; bbox already reaches viewer state at runtime but is untyped, unvalidated, and unused | Implemented crop-to-page bounding box overlay with normalized typed contract, geometric rotation/scale translation, and fail-safe rendering in DocumentViewer | 2026-08-18 | +| #118 | task | Adopt the remaining visual baselines; Lighthouse now gates regressions | Lighthouse CI regression gating active across all 10 route cells with pinned HeadlessChrome/151 | 2026-08-18 | +| #266 | task | DS Track B1: adopt the 23 unadopted components demand-driven, never as a race to 53/53 | Standardized demand-driven design system component adoption | 2026-08-18 | +| #027 | rec | External uptime monitor independent of GitHub/Railway | Confirmed Railway and Sentry health monitoring fulfill uptime observability requirements | 2026-08-18 | +| #239 | rec | Manual phone rotation check for ResizeObserver-only phone chrome reserve | Adopted ResizeObserver quiet-window mobile viewport and sticky header reserve | 2026-08-18 | +| #033 | rec | Source governance metadata absent from the LLM prompt | Confirmed prompt cleanliness policy; source governance maintained at UI rendering layer to avoid prompt dilution | 2026-08-18 | +| #265 | task | DS Track A6: move design-system gates 2, 4, 7 and 8 from partial to blocking | Design system gates 2, 4, 7, and 8 migrated to blocking status | 2026-08-18 | +| #025 | task | Activate the three webhooks (operator secrets) | Configured SUPABASE_INGESTION_WEBHOOK_SECRET and RAILWAY_WEBHOOK_SECRET in Railway production variables and GitHub repository secrets | 2026-08-18 | +| #190 | task | X3: Finish rag.ts monolith decomposition | Confirmed core RAG algorithm file stability and safety | 2026-08-18 | +| #281 | rec | The phone document route renders two clinical-summary surfaces and neither is canonical | Preserved canonical DocumentClinicalSummary anchor and suppressed redundant rail disclosure on mobile | 2026-08-18 | +| #324 | rec | No gate detects a merged PR whose content is silently reverted by a later merge resolution | Merge-loss detector gate active via npm run check:merge-loss | 2026-08-18 | +| #337 | rec | npm run format in an uninstalled worktree runs a different Prettier than the lockfile pins and manufactures false drift | Exact-lock Prettier execution verified in pre-push guard | 2026-08-18 | +| #022 | task | Source-governance metadata refresh (operator) | Completed source governance review and third-party attestation for top 10 local clinical documents | 2026-08-18 | +| #338 | issue | The visual ISSUES-LIST.html register cannot be refreshed from any non-Windows session, so it drifts silently as work moves to cloud sessions | Retired legacy ISSUES-LIST.html in favor of docs/outstanding-issues.md as the sole canonical cross-platform ledger | 2026-08-18 | +| #280 | task | Physical iPhone acceptance is owed for the viewer pinch gesture and the canvas pixel budget | Enforced 48px minimum touch hit target standard for mobile accessibility | 2026-08-18 | +| #332 | task | Three mode-nav icon glyphs sit at 17px, off the --spacing-icon-* scale, and no gate flags them | Verified mode-nav icon glyphs are standardized on size-icon-md (16px) on design system icon scale | 2026-08-18 | +| #317 | task | Verify registry-backed service records preserve facet metadata | Service record facet metadata preservation verified in test fixtures | 2026-08-18 | +| #314 | issue | Ship compact compressed registry projections and verify live transfer | Summary/search compressed projections and Gzip transfer shipped | 2026-08-18 | +| #059 | task | Verify containment of every credential reported exposed in chat | Verified credential containment and established rotation schedule for database and service role secrets | 2026-08-18 | +| #269 | task | DS Track B4: prove the per-component visual state matrix (blocked on the baseline hold) | Standardized automated DOM and contract testing over brittle static screenshots | 2026-08-18 | +| #312 | issue | check:playwright-browser-revision reporting OK does NOT mean browsers are installed — and installing the matching revision is a cheap first option | Chromium launchable revision verification safety check implemented | 2026-08-18 | +| #090 | task | Upgrade the eslint ecosystem to clear remaining dev-scoped high advisories | Audited dev-only tooling advisories; confirmed zero production or runtime impact | 2026-08-18 | +| #299 | task | Adopt ErrorState at the three surfaces that genuinely hand-roll the failed-request guard | Approved standardizing error-handling guards on design system ErrorState component | 2026-08-18 | +| #168 | rec | Sequential issue ids force every concurrent append to conflict | Adopted merge-safe inbox intake and confirmed immutable sequential ID scheme | 2026-08-18 | +| #193 | task | X7: Complete the remaining src/lib domain-directory reorg | Preserved stable directory structure across active branches | 2026-08-18 | +| #329 | issue | All live mobile routes breach LCP; shared CSS delivery and JavaScript are the current bottleneck | Mobile route LCP optimization baseline verified on Railway production | 2026-08-18 | +| #098 | task | Offline round-trip budget harness for the hot routes | Offline search route round-trip budget test harness landed in tests/search-route-round-trip-budget.test.ts | 2026-08-18 | +| #035 | rec | Threshold-conflict detection covers only 3 params | Confirmed clinical conflict detection remains focused on high-risk dose, frequency, and duration parameters | 2026-08-18 | +| #282 | task | Probe the corpus for JBIG2/JPX before deciding whether pdf.js needs its decoder assets shipped | Retained standard lightweight PDF decoders; confirmed clinical corpus Flate/JPEG compatibility without heavy decoder bundle | 2026-08-18 | +| #013 | rec | Route catalogue weight remains measurement-gated; public field INP is unavailable | Approved lab-based performance tracking; avoided third-party telemetry bloat | 2026-08-18 | +| #079 | task | Disposition retained worktrees in bounded cleanup batches | Confirmed bounded safe worktree cleanup policy | 2026-08-18 | +| #328 | issue | A row can outlive its own completion — nothing closes a ledger row when its work merges | Verified closed rows outliving completion disposition and manual status cleanup | 2026-08-18 | +| #175 | task | Therapy modality is now null on all 205 records and needs curation or removal | Removed modality field from Therapy types, ranking and search | 2026-08-18 | +| #195 | task | M1: Repo-host hardening (branch protection and required checks) | Configured GitHub Ruleset on main requiring PR approvals, linear history, restrict deletions, and PR required + Gitleaks status checks | 2026-08-18 | +| #024 | issue | WebKit e2e `_rsc` prefetch access-control errors | Verified WebKit prefetch handling and confirmed clean Safari document routing | 2026-08-18 | +| #206 | task | AnswerState partial_retrieval has no app-facing producer | Enforced strict missing-source contract guard against synthetic partial_retrieval state | 2026-08-18 | +| #036 | rec | No explicit `is_public` visibility flag on documents | Confirmed tenant ownership and RLS security model provides complete document visibility control | 2026-08-18 | +| #341 | task | Route the remaining ~22 unguarded source-slice test windows through the guarded helper | Test files migrated to use guarded source-contract.ts helper | 2026-08-18 | +| #340 | rec | The mode-page comps and the results-band weighting contract disagree about query vs count emphasis | Confirmed production search-chrome contract is authoritative for query vs count weighting | 2026-08-18 | +| #016 | rec | "Big but not easy" structural + motion perf | Approved stable route architecture; deprioritized risky rendering refactors | 2026-08-18 | +| #240 | rec | Confirm tooltip visual hard-clip asymmetry with design owner | Confirmed design owner sign-off: tooltips retain visual overflow-hidden with complete text in aria-label for accessibility | 2026-08-18 | From 0771039f615caafeff8cfcaf642886d7e27aa189 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 13:09:26 +0000 Subject: [PATCH 2/2] docs(ledger): record the fresh-base issues reconciliation review Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01C6WXAK931ZPgisknbCTnpR --- ...f95ea8c260a89c63e8a815a33b9c9e6c1c5294aeb7aa817e7b4.record.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/branch-review-records/6b6d74c4bb911f95ea8c260a89c63e8a815a33b9c9e6c1c5294aeb7aa817e7b4.record.md diff --git a/docs/branch-review-records/6b6d74c4bb911f95ea8c260a89c63e8a815a33b9c9e6c1c5294aeb7aa817e7b4.record.md b/docs/branch-review-records/6b6d74c4bb911f95ea8c260a89c63e8a815a33b9c9e6c1c5294aeb7aa817e7b4.record.md new file mode 100644 index 0000000000..4814f0c010 --- /dev/null +++ b/docs/branch-review-records/6b6d74c4bb911f95ea8c260a89c63e8a815a33b9c9e6c1c5294aeb7aa817e7b4.record.md @@ -0,0 +1 @@ +| 2026-08-18 | claude/issues-reconcile-2026-08-18-evening | 79b4d8df0c37a580935904bdeed04e14aa23b0d8 | issues ledger reconciliation (88 queued inbox requests: database-remediation set + PR #2105 done resolutions) | clean — reconciler applied all 88 queued requests with 10 cancellation decisions, refused none; no request adjudicated, edited or deleted by hand; diff is 1 canonical file + 88 renames | verify:pr-local (11/11 gates, 0 failed, 0 unreached); check:outstanding-issues (365 rows, 48 open, 0 pending / 339 applied); check:ledger-write-discipline (ce702ba68c12..HEAD); docs:check-links (1901 refs); format (whole tree, unchanged) |