diff --git a/docs/branch-review-records/80cbe21a397bb239bbc43ceca3bf117412cf732bc2ad6e0bfc360a7a759102ed.record.md b/docs/branch-review-records/80cbe21a397bb239bbc43ceca3bf117412cf732bc2ad6e0bfc360a7a759102ed.record.md new file mode 100644 index 0000000000..1a41f08087 --- /dev/null +++ b/docs/branch-review-records/80cbe21a397bb239bbc43ceca3bf117412cf732bc2ad6e0bfc360a7a759102ed.record.md @@ -0,0 +1 @@ +| 2026-08-14 | claude/issues-reconcile-lnhvja | cabdd290b00ff81569955cdd4a1b6b6b9f8999de | serialized outstanding-issues reconciliation (9 requests, 2 cancels) | PR #1967 open | issues:reconcile applied 9; check:outstanding-issues pass; verify:pr-local failed:(none) | diff --git a/docs/outstanding-issues-inbox/19fb70c0-1fd4-43a8-a4f4-efa9c31d16b1.json b/docs/outstanding-issues-inbox/applied/19fb70c0-1fd4-43a8-a4f4-efa9c31d16b1.json similarity index 100% rename from docs/outstanding-issues-inbox/19fb70c0-1fd4-43a8-a4f4-efa9c31d16b1.json rename to docs/outstanding-issues-inbox/applied/19fb70c0-1fd4-43a8-a4f4-efa9c31d16b1.json diff --git a/docs/outstanding-issues-inbox/38c6095f-41f5-4925-b1ea-f5af5187885d.json b/docs/outstanding-issues-inbox/applied/38c6095f-41f5-4925-b1ea-f5af5187885d.json similarity index 100% rename from docs/outstanding-issues-inbox/38c6095f-41f5-4925-b1ea-f5af5187885d.json rename to docs/outstanding-issues-inbox/applied/38c6095f-41f5-4925-b1ea-f5af5187885d.json diff --git a/docs/outstanding-issues-inbox/606b1573-6217-457a-9183-7f8e550d3094.json b/docs/outstanding-issues-inbox/applied/606b1573-6217-457a-9183-7f8e550d3094.json similarity index 100% rename from docs/outstanding-issues-inbox/606b1573-6217-457a-9183-7f8e550d3094.json rename to docs/outstanding-issues-inbox/applied/606b1573-6217-457a-9183-7f8e550d3094.json diff --git a/docs/outstanding-issues-inbox/7f5e6922-8d0b-424a-b359-12bed3a4e315.json b/docs/outstanding-issues-inbox/applied/7f5e6922-8d0b-424a-b359-12bed3a4e315.json similarity index 100% rename from docs/outstanding-issues-inbox/7f5e6922-8d0b-424a-b359-12bed3a4e315.json rename to docs/outstanding-issues-inbox/applied/7f5e6922-8d0b-424a-b359-12bed3a4e315.json diff --git a/docs/outstanding-issues-inbox/81845ded-27a8-43d8-9a56-d85a5515935b.json b/docs/outstanding-issues-inbox/applied/81845ded-27a8-43d8-9a56-d85a5515935b.json similarity index 100% rename from docs/outstanding-issues-inbox/81845ded-27a8-43d8-9a56-d85a5515935b.json rename to docs/outstanding-issues-inbox/applied/81845ded-27a8-43d8-9a56-d85a5515935b.json diff --git a/docs/outstanding-issues-inbox/bbf21714-0ef9-4c2f-942f-1b8d7e328ac8.json b/docs/outstanding-issues-inbox/applied/bbf21714-0ef9-4c2f-942f-1b8d7e328ac8.json similarity index 100% rename from docs/outstanding-issues-inbox/bbf21714-0ef9-4c2f-942f-1b8d7e328ac8.json rename to docs/outstanding-issues-inbox/applied/bbf21714-0ef9-4c2f-942f-1b8d7e328ac8.json diff --git a/docs/outstanding-issues-inbox/bd11cfe9-1627-425f-a8f7-e0e202b980a4.json b/docs/outstanding-issues-inbox/applied/bd11cfe9-1627-425f-a8f7-e0e202b980a4.json similarity index 100% rename from docs/outstanding-issues-inbox/bd11cfe9-1627-425f-a8f7-e0e202b980a4.json rename to docs/outstanding-issues-inbox/applied/bd11cfe9-1627-425f-a8f7-e0e202b980a4.json diff --git a/docs/outstanding-issues-inbox/d52dbc3d-6759-4f6e-9089-24059830ed5a.json b/docs/outstanding-issues-inbox/applied/d52dbc3d-6759-4f6e-9089-24059830ed5a.json similarity index 100% rename from docs/outstanding-issues-inbox/d52dbc3d-6759-4f6e-9089-24059830ed5a.json rename to docs/outstanding-issues-inbox/applied/d52dbc3d-6759-4f6e-9089-24059830ed5a.json diff --git a/docs/outstanding-issues-inbox/ec6d0c23-2f19-4159-9c73-49bdc103b61e.json b/docs/outstanding-issues-inbox/applied/ec6d0c23-2f19-4159-9c73-49bdc103b61e.json similarity index 100% rename from docs/outstanding-issues-inbox/ec6d0c23-2f19-4159-9c73-49bdc103b61e.json rename to docs/outstanding-issues-inbox/applied/ec6d0c23-2f19-4159-9c73-49bdc103b61e.json diff --git a/docs/outstanding-issues.md b/docs/outstanding-issues.md index 0ed58896bd..bf12e68b71 100644 --- a/docs/outstanding-issues.md +++ b/docs/outstanding-issues.md @@ -179,10 +179,10 @@ removed after current-main verification; it is not missing recommended work. | #212 | P3 | task | Replace as unknown as casts and unvalidated JSON.parse with Zod or runtime guards | **DEPRIORITISED 2026-08-12 (yield review against current main).** 40 casts at trust boundaries. Same reasoning as #211: worth doing, no measured defect traces to it, and it competes with clinical work for review attention. VERIFIED CORRECT 2026-08-12 — re-checked against merged main during the full ledger sweep and left unchanged: 40 `as unknown as` casts remain under src/ — the row's population is intact. This stamp exists so a later reader can tell "checked and still true" from "never looked at"; the two were indistinguishable before. 48 as unknown as casts and ~24 unvalidated JSON.parse calls across src/ trust Supabase, OpenAI, localStorage, file metadata and extraction boundaries. Start with src/lib/rag/rag.ts and src/app/api/* routes, mirroring existing Zod use in src/lib/validation/body.ts and src/lib/extractors/document.ts. See docs/review-findings-2026-08-02.md sections 2.2, 2.3 and 8. | session 2026-08-02 /ledger sweep — docs/review-findings-2026-08-02.md | 2026-08-02 | | #215 | P3 | task | Add image-optimization basics for lightbox, PWA lifecycle and demo PNGs | **Outcome:** two of the four image-only findings from the 2026-08-02 audit are shipped; two remain open for an explicit implementation-or-drop decision. **RESTATED 2026-08-13 after inspection against main 2d270392 — two of the four items already shipped and the row no longer describes them as open.** DONE: src/components/clinical-dashboard/image-lightbox.tsx carries decoding="async" (Phase 0, PR #1660), asserted by tests/signed-image.dom.test.tsx. DONE: SignedImage has the priority prop for above-fold evidence — it also skips the IntersectionObserver deferral entirely — and document viewer Phase 3 (PR #1772) added the other half of that pair: an explicit fetchPriority of high when priority is set and low otherwise, so a deferred rail figure does not contend with the page's own above-the-fold work. The document rail additionally passes a 240px observer root margin against the shared 640px default. REMAINING, both confirmed by inspection rather than inferred: (a) src/components/pwa-lifecycle.tsx still has no decoding attribute; (b) public/demo-documents/ still contains no .webp — the PNGs are ~80 KB each and served as-is, so the conversion with a PNG fallback has not been done. **Next:** apply decoding=async in pwa-lifecycle.tsx, and either convert the demo PNGs to WebP with a PNG fallback or record that an ~80 KB synthetic demo asset is not worth the build step. **Stop:** do not treat this row as covering the broader performance findings — those live under #016, #013, #117 and #147. | session 2026-08-02 /ledger sweep — docs/audit/performance-image-cwv-audit-2026-08-02.md | 2026-08-02 | | #222 | P3 | task | Headers surface only partially converged in PR-J: mode-home-template and search-results-header-band untouched | VERIFIED CORRECT 2026-08-12 — re-checked against merged main and left open: Still unconverged: src/components/mode-home-template.tsx defines ModeHomeStatusNotice locally (:232) and imports neither PageHeader nor the DS EmptyState; search-results-header-band.tsx is likewise untouched. Note the adjacency — in-flight PR #1842 delegates ModeHomeStatusNotice to the DS EmptyState under #221, which is a different conversion from the PageHeader question this row asks. Re-check after #1842 merges. Builder A converged DsmPageHeader, InformationPageHeader and InformationPageBreadcrumbs onto PageHeader plus Breadcrumb, and declined two files with reasons. mode-home-template.tsx ModeHomeHero is a centred display hero on the fluid text-hero token and is the slot the in-flow phone composer sits in, so converging it onto a left-aligned PageHeader is a redesign of 13 mode homes that collides with the one-composer-per-page contract. search-results-header-band.tsx is a results spine carrying status, counts and filters, not a page-title stack, so its pin tests/search-results-header-band.dom.test.tsx remains unflipped. Both are defensible; both leave the headers surface partially adopted. Next action: decide whether either is in scope at all, or record them as permanently out of the PageHeader vocabulary. Found during PR-J adoption, 2026-08-03. | session 2026-08-03 (PR-J Wave 5, Builder A) | 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. Next: instrument and reproduce the structured generation-quality failure using provider-safe metadata, 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. | session 2026-08-04 (production triage, live /api/search + /api/answer) | 2026-08-04 | -| #235 | P3 | task | ADOPTION.md section 7 proof shots exist for only four of the adopted surfaces | IN FLIGHT 2026-08-12 in PR #1842 (records adoption evidence). Checked against the open-PR list during the full ledger sweep. Do NOT start this row while that PR is open — duplicating a queued conversion is the exact failure #292 records, and it has happened twice. Re-verify this row against main after that PR merges, and close it there rather than here. The adoption contract asks for a proof shot per adopted surface. The Wave 5 adoption 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 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. | session 2026-08-04 (DS V2 Wave 5 close-out capture) | 2026-08-04 | -| #237 | P2 | rec | Eyeball low-confidence AccessibleTable densities at 320px before freezing Linux visual baselines | IN FLIGHT 2026-08-12 in PR #1841 (renders empty dense cells wrapping rather than truncated, with a 320px jsdom assertion). Checked against the open-PR list during the full ledger sweep. Do NOT start this row while that PR is open — duplicating a queued conversion is the exact failure #292 records, and it has happened twice. Re-verify this row against main after that PR merges, and close it there rather than here. PR #1616 clinical MissingValue phrases increase text volume in sparse OCR grids. Contract forbids abbreviating to a dash. Next: open one real lowConfidence extraction at 320px phone width and accept or adjust dense preview column widths before committing Linux screenshots (#118). | PR #1616 review findings; session 2026-08-05 | 2026-08-05 | -| #238 | P2 | rec | Visual pass for Sheet portal default on settings, sidebar, and answer overlays | IN FLIGHT 2026-08-12 in PR #1842 (exercises the Sheet portal default and adds tests/sheet.dom.test.tsx). Checked against the open-PR list during the full ledger sweep. Do NOT start this row while that PR is open — duplicating a queued conversion is the exact failure #292 records, and it has happened twice. Re-verify this row against main after that PR merges, and close it there rather than here. PR #1616 flips Sheet portal default to true, moving ~10 product overlays into OverlayRoot. Token inheritance is safe; residual risk is ancestor-scoped CSS / contain / transform. Next: one visual pass of settings-dialog, ClinicalSidebar, answer-result sheets, launcher sheet, section-nav. | PR #1616 review findings; session 2026-08-05 | 2026-08-05 | +| #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 | +| #237 | P2 | rec | Eyeball low-confidence AccessibleTable densities at 320px before freezing Linux visual baselines | CLOSURE ATTEMPTED AND REJECTED 2026-08-14 — read this before closing again. PR #1940 queued a `done` for this row citing tests/accessible-table.dom.test.tsx:110 ("keeps the full missing-value phrase readable in the dense 320px preview"); the closure was cancelled on review with the reason "the jsdom assertion does not verify the requested real 320px browser visual pass". The cancellation is correct. jsdom does not lay out text, so a 320px assertion there proves the string is present, not that it fits, wraps or stays legible at that width — which is the whole question for a low-confidence extraction in a sparse grid. IN FLIGHT note retired: PR #1841 merged, so the do-not-start warning no longer applies. The requirement is unchanged. PR #1616 clinical MissingValue phrases increase text volume in sparse OCR grids; the contract forbids abbreviating to a dash. Next: open one real lowConfidence extraction at 320px phone width in an actual browser (npm run ensure, then a phone viewport) and accept or adjust dense preview column widths before committing Linux screenshots (#118). Stop: do not close this row on a jsdom, DOM-testing-library or snapshot-string assertion — only a real browser at 320px settles it. | PR #1616 review findings; session 2026-08-05 | 2026-08-05 | +| #238 | P2 | rec | Visual pass for Sheet portal default on settings, sidebar, and answer overlays | CLOSURE ATTEMPTED AND REJECTED 2026-08-14 — read this before closing again. PR #1940 queued a `done` for this row citing tests/sheet.dom.test.tsx and the `portal = true` default; the closure was cancelled on review with the reason "generic Sheet coverage does not verify the requested product-overlay browser journeys". The cancellation is correct. The residual risk this row exists for is ancestor-scoped CSS, `contain` and `transform` on the specific product overlays — a property of where each overlay sits in the real page, which a component-level unit test cannot see no matter how thorough it is. IN FLIGHT note retired: PR #1842 merged, so the do-not-start warning no longer applies. The requirement is unchanged. PR #1616 flips the Sheet portal default to true, moving ~10 product overlays into OverlayRoot; token inheritance is safe. Next: one visual pass in a real browser over settings-dialog, ClinicalSidebar, answer-result sheets, launcher sheet and section-nav. Stop: do not close this row on Sheet component coverage — the question is about the five host surfaces, not about Sheet. | PR #1616 review findings; session 2026-08-05 | 2026-08-05 | | #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 | @@ -208,7 +208,7 @@ removed after current-main verification; it is not missing recommended work. | #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 | Two corrections learned the expensive way on 2026-08-12, both about browser proof in a cloud container. (1) **The check is easy to misread.** `npm run check:playwright-browser-revision` returned 'Playwright browser revision check OK (managed-or-unconstrained): No designated container browser root is forced; use the Playwright-managed cache or install matching browsers.' That reports that no browser root is FORCED — it does not assert any browser exists. It was read as a green light for `verify:ui`, and two subsequent Playwright runs died at preflight instead: the container carried chromium-1194 while Playwright 1.62.1 requires chromium_headless_shell-1234, with firefox-1538 and webkit-2336 absent entirely. Suggested fix: have the check say plainly which browsers are present and which the locked Playwright version requires, so 'OK' cannot be mistaken for 'ready'. (2) **Installing the matching revision works and is fast**, which archived #255's 'delegate browser proof to CI Production UI' guidance does not mention. `npx playwright install chromium` fetched 114.7 MiB in about a minute and made local Chromium proof possible — three full ui-smoke runs then completed at 2.8-3.0m each (this is how #290 was settled). It is a cheaper first option than deferring to CI. Two things that matter alongside it: `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` was EMPTY in this container, so the download was never blocked despite the environment note implying otherwise; and only Chromium is needed, because `scripts/playwright-browser-preflight.mjs:127-152` honours `--project`, so `--project=chromium` skips the firefox/webkit requirement rather than forcing two unused ~100MB downloads. Stop: do NOT set PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH at the stale 1194 binary to get past the preflight — archived #255 warns against forcing a mismatched path, and the preflight's own message warns that a later 'N failed' summary must not then be read as a product regression. | 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 | Next: land the existing view=summary/search and gzip implementation, deploy it, then verify /api/registry/records on the exact deployment SHA returns counts-only home responses and compressed compact search responses. Why: the live full payloads measured on 2026-08-13 were 482786 bytes for Forms and 1096689 bytes for Services and were downloaded by count/search-only consumers without Content-Encoding. The local projections reduce raw search data by about 91.3% and 82.0%, with gzip responses about 4.9 KB and 27.3 KB. Context: latency and Sentry review. Owner: assistant. Confidence: high. Depends on: #013 and #016. Gate: focused registry/consumer tests, production build and bundle budget, then post-deploy headers/bytes and live LCP rerun. Stop: do not close from local-only payload measurements or deploy without explicit authorization. | session 2026-08-13 latency review; src/app/api/registry/records/route.ts | 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 is missing 21 repo-defined indexes and 10 retrieval RPC bodies diverge; weekly live-drift has been red since 2026-07-26 with no routing | Phase 0 delivered — drift routing + post-migration trigger + evidence scaffold, PR #1938. live-drift.yml now creates/updates one pinned issue 'Live drift check failing' (label live-drift-failure) with the captured finding lines and run URL on failure, and comments+closes it on the next green run; issues: write is scoped to a separate drift-routing job so the job running npm ci keeps contents: read. The workflow also runs on pushes to main touching supabase/migrations/** or supabase/schema.sql. docs/audit/live-drift-forensics-2026-08.md now carries dated empty Phase 1-5 evidence sections anchored here. Still outstanding: a forced workflow_dispatch failure to observe the pinned issue end-to-end (provider-backed, operator to run), SUPABASE_ACCESS_TOKEN per #183, and Phases 1-5, which all need approved hosted windows. Note: the Phase 0 task prompt named #312 as the anchor; that is the unrelated Playwright-browser P3, and the anchor was resolved to #316 by exact title per the playbook. | session 2026-08-13 / Actions runs 30763871562 + 31330856982 / open #248 | 2026-08-13 | +| #316 | P1 | issue | Live DB is missing 21 repo-defined indexes and 10 retrieval RPC bodies diverge; weekly live-drift has been red since 2026-07-26 with no routing | 2026-08-14 incident session: two of the 21 missing indexes (documents_title_trgm_idx, document_chunks_content_trgm_idx) were the retrieval-critical pair; restored live via owner-approved CREATE INDEX CONCURRENTLY + ANALYZE. Before/after supabase_rpc_latency_ms 31610 -> 1535 (text) / 8519 (hybrid). Forensics: indexes existed 2026-08-04 (guard 20260804110240 passed) and were dropped by 2026-08-09; no app code drops indexes - owner to check dashboard audit for manual/advisor DROP INDEX. Evidence: docs/audit/live-drift-forensics-2026-08.md. Remaining drift findings + 10 diverged match_* RPC bodies stay with docs/database-remediation-plan.md. Drift routing: PR #1939. | session 2026-08-14 live incident (owner-authorized Supabase connector) | 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 | | #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. The sheet has already produced three defects on generation alone (ARB matching Carbapenem across 16 CRITICAL/HIGH rows; two divergent Warfarin records; lithium unreachable from eight HIGH rows), which is a fair indication of what reading it would still find. Next: a clinician reads the term table top-down (it is sorted so the top ten terms carry most of the severe usage) 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. | 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 |