diff --git a/docs/README.md b/docs/README.md index f8a8422b4a..395309d2a3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -35,6 +35,7 @@ npm run docs:check-links - [pwa.md](pwa.md) — PWA install assets, privacy-first service worker, offline shell - [webhooks.md](webhooks.md) — the two inbound webhook receivers and the outbound Actions notifier - [api-jobs-ops-surface.md](api-jobs-ops-surface.md) — standing decision to keep `GET /api/jobs` as an ops/admin surface +- [verified-answer-incremental-delivery-design.md](verified-answer-incremental-delivery-design.md) — staged, clinical-safety-preserving design for delivering verified evidence and answer sections before the canonical final SSE frame ## Operations runbooks diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index e27947b9ba..bb6c15dd33 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -144,11 +144,19 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-30 | PR #1396 / claude/latency-findings-impl-s8g01v | 70e810b66881e17aa9f58126fdad970986bda911 | User ask: resolve comments + Production UI phone-scroll + main sync | FIXED: synced main (DIRTY was staleness); removed union ledger dup; adapted phone-scroll asserts for Answer strategy-overlay + overlay/reserve-only calculator budget + focus pre-scroll inside 8px reveal band. Codex P1s already on tip; 0 unresolved threads. Focused Chromium phone-scroll 9/9 green (system Chrome). | phone-scroll focused 9/9; check:branch-review-ledger PASS; merge-tree clean; prior Codex P1s retained | | 2026-07-30 | HEAD | 13c16cf07c854b50daa35a2ef2a2ea76d5e059e1 | ci-testing-approach | findings: UI-load flake #093 dominates PR reds; schedule full-sentinel blocks release-browser via audit; UI scope overfires on src/app/api; ~40% PR runs cancelled wasting ~12 UI-hrs; CI_TRIAGE inert; eval:rag:offline claimed-in-CI but only fixtures run | gh-ci-500-runs,ci.yml,ci-change-scope,testing.md,process-hardening,outstanding-issues-093-095-097-023,flake-ledger-empty | | 2026-07-30 | cursor/ci-testing-review-1bf5 | 13c16cf07c854b50daa35a2ef2a2ea76d5e059e1 | ci-testing-approach | Corrects the ref cell from the unresolved placeholder "HEAD" to the actual branch name, so ledger:lookup can match this review by branch (Codex P2 finding on PR #1406). | node scripts/branch-review-ledger.mjs lookup cursor/ci-testing-review-1bf5 --scope ci-testing-approach | +| 2026-07-30 | PR #1427 / claude/ci-testing-review-2l8klp | db8209be707b79142d1d228d8c4e04120f9cdeaa | ci-testing-review | Measured PR CI from the Actions API: Production UI is 15m26-16m31 of a 16.8-18.6min run (83-89% of wall clock; Playwright itself 339 passed (13.5m)), every other job done by minute 4; 25/60 completed runs in an 83min window were cancelled (42%). FIXED: sharded ui-critical across 3 runners (count measured - N=4 gives the same 121-test critical path, N=5/N=8 give empty shards which would go red without --pass-with-no-tests); root-caused the real red (ui-phone-scroll dragScrollBy clamped silently and returned nothing, so a 720px request could deliver a fraction and the correct assertion failed 10s later) and made the drag prove its delivery with assertions byte-identical; browser-cache restore-keys; codex-autofix job timeouts; visual config serialised; gate-count guard added and mutation-proven. DEFERRED as #125-#129: ui_changed over-firing on src/app/api, cold Next cache in the Playwright build, advisory-UI cost vs zero quarantine tests, inert CI_TRIAGE, dead changes outputs. | verify:cheap PASS (431 files / 4493 passed, 4 skipped); verify:pr-local PASS (same); prettier --check . PASS; check-gate-manifest PASS + mutation-proven red at stale count; shard balance measured via playwright --list; verify:ui NOT RUN - container cannot launch Chromium (issue #121, build 1234 vs 1194) so the phone-scroll fix and the sharded job are unexecuted, PR CI is first execution | | 2026-07-30 | cursor/ci-hygiene-gates-1bf5 | ad9da6a6f8ba3884b389fa78e678bb88ee72d9d1 | ci-hygiene-gates | implemented matrix unblock, scope narrow, cancelled≠failure, pinned gitleaks, critical-first UI, eval:rag:offline; skipped #093; verify:cheap 4471 pass | verify:cheap,check:ci-scope,check:gitleaks-pinned,check:gate-manifest,eval:rag:offline | | 2026-07-30 | cursor/ci-hygiene-gates-1bf5 | b660dbc5a10d7ca3da03541028017f0abc6b5bd3 | ci-hygiene-gates merge-readiness | findings | check:ci-scope;check:gitleaks-pinned;scope-classify PR files ui_changed=false;sim cancelled-as-neutral | | 2026-07-30 | cursor/ci-hygiene-gates-1bf5 | 8f3283d00da274dee507a1b8e9b611321d1f35be | pr-1413-merge-readiness | READY after main sync + cancel-to-green fix; draft until tip CI green; deferred #093 + CI_TRIAGE_ENABLED confirm | verify:cheap:4481-pass;format:outstanding-issues;merge-tree:clean;cancelled:!cancelled();hosted:awaiting-tip | | 2026-07-30 | cursor/ci-hygiene-gates-1bf5 | 0d70de480f370fec3e7f3774f13d906318a09b3c | pr-1413-merge-readiness | READY: synced with main/#1409; tip CI success incl PR required; draft; deferred #093 + CI_TRIAGE_ENABLED | merge-tree:clean;ci-cache-safety:13/13;hosted:30520195863:success;PR-required:pass | -| 2026-07-30 | claude/organize-local-worktree-d22bc3 | 2f26a53b5aeb3df451cf7b1d04f80b07edf0d6fe | docs organisation: dated-record filing, docs index gaps, orientation maps | PR #1436 opened — 5 dated docs filed into docs/audit and docs/archive, root codex-cloud-review moved under docs/prompts, 17 docs README index gaps closed, root data/ documented in CLAUDE.md + codebase-index; no product code, schema or RAG surface touched | docs:check-links 1368 refs pass; docs:check-scripts 378 pass; docs:check-index OK; format:check whole-tree clean; verify:cheap 26 static gates + lint + typecheck pass, unit 4562 pass / 1 pre-existing Windows path-separator failure in tests/repo-hygiene.test.ts | +| 2026-07-30 | origin/main | 3569e7888bba5d11f143f27c11eb9bfa58800e4f | dependency installation and CI reproducibility | no P0-P2 findings; corrected stale setup-ui-e2e cache description | manifest-lock parity; Actions pins; merge-marker scan; merged PR 1360 diff | +| 2026-07-30 | cursor/process-anti-conflict-speed-1edf / PR #1416 | 2a31fcee0ef2e330a4901481c0810103d89c96cf | process anti-conflict merge readiness | NOT READY. CI green on stale head, but merge-tree vs current main is CONFLICTING in ci.yml, package.json, and add/add on check-outstanding-issues.mjs after #1410 landed a stronger #112 gate. Keep unique value: AGENTS anti-conflict procedure, #116 PR mergeability workflow, merge=union on outstanding-issues (explicitly still open after #1410). Drop duplicate weaker outstanding-issues checker; re-verify after sync. | ledger:lookup NOT REVIEWED; merge-tree dirty vs origin/main; ManagePullRequest CI SUCCESS (15 ok / 0 fail, Production UI skipped as non-UI); local verify:pr-local earlier on pre-conflict head 4467 passed | +| 2026-07-30 | cursor/process-anti-conflict-speed-1edf / PR #1416 | 387ffd07887f1160fca8fe98c1c4809e852531ae | process anti-conflict merge readiness | READY after sync with main. Kept #1410 structural outstanding-issues gate; added merge=union + runtime attr check; retained #116 PR mergeability workflow and AGENTS anti-conflict playbook; dropped duplicate weaker checker/test. merge-tree clean vs origin/main. | merge-tree clean; check:outstanding-issues pass; check:pr-mergeability pass; check:gate-manifest pass; verify:pr-local pass | +| 2026-07-30 | cursor/process-anti-conflict-speed-1edf / PR #1416 | 38ae07b989e6414026235debad0e429ba64cf462 | process anti-conflict merge readiness | READY at final tip. Same as prior READY plus this ledger append only; merge-tree still clean vs origin/main. | merge-tree clean; verify:pr-local on 387ffd07 parent (4480 passed); tip is ledger-only follow-up | +| 2026-07-30 | codex/chat-dependency-pr-review-dependency-pr-review-20260730 | 2aee8c74e64bd09954fe1b474c73b25805063de0 | open PR changed-scope review | APPROVE: setup action description now matches clean npm install with npm-download caching; no behavior change. | check:github-actions PASS; diff review; no unresolved threads | +| 2026-07-30 | PR #1427 / claude/ci-testing-review-2l8klp | b9de34d40d2dc5ab164bb1eb582db1cfcd1009c3 | ci-testing-review | SUPERSEDES the 2026-07-30 db8209be record, which asserted a root cause now REFUTED. That record claimed dragScrollBy clamping made the ui-phone-scroll red; main's #127 carries trace evidence (PR #1404 run 30521269873) that the drag delivered in full (scrollTop 1272 = 552+720) with ~1300px runway spare and a 10s non-flip is a latched state. The change is a diagnostic and guard, NOT a fix, and is now labelled so in the docstring, commit, PR body and #127. Remaining candidates: scrollHidden false vs sharedChromePinned latched; they are indistinguishable from the DOM because only the composite data-scroll-hidden is exposed. Prime suspect in source: composerFocusPinsChrome has a still-the-active-owner guard, headerFocusPinsChrome has none (master-search-header.tsx:397-398). ALSO: this PR ran zero pull_request workflows for ~2h (no CI/Gitleaks/Semgrep, only pull_request_target) because a real conflict blocked refs/pull/1427/merge - issue #116, caught by main's new PR mergeability check. Merging main fixed it and CI ran green first try. | CI run 30530618838 SUCCESS (13m39). MEASURED shard result, correcting the ~7min prediction: Production UI (1) 121 tests 9m36, (2) 111 tests 6m54, (3) 110 tests 6m20 - per-test cost is NOT uniform, shard 1 holds the slow specs, so the largest shard is 9m36 not the predicted 6.8min. ui-critical-fast 3m14. PR required SUCCESS. verify:cheap on merged tree PASS (434 files / 4563 passed, 4 skipped); prettier --check . PASS; ui-phone-scroll ran locally 1x via PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH: 56 passed (5.3m) - three-run protocol NOT completed and not applicable, since this is not a flake fix. | +| 2026-07-30 | PR #1400 | e869cb9d7ab20939361b277d1c6fcc07bbb6ca45 | pr-1400-guard-push-band-adoption | MERGED — 17 review findings across guard-push.mjs and the band-adoption gate, all fixed and thread-resolved; each fix confirmed by reverting it and watching the guard fail. Guard now checks the pushed SHA in a git worktree (config, dynamic config, policy escalation incl. removal, lockfile Prettier parity); adoption gate replaced presence-matching with per-module reachability, closing six false greens of one root cause plus type-position edges found in self-review. Merge verified: all 8 commits ancestors of main, 4 changed files byte-identical. | verify:cheap 432 files / 4470 passed 4 skipped; format:check clean; PR required success; services+tools page gutting reports orphans; 6 push-guard scratch-repo cases with real exit codes; every fixture mutation-verified | +| 2026-07-30 | claude/top-search-design-mockups-w53znc | 939d5799b9999f3f63928e1b2c95d097f07eff90 | open PR changed-scope review | APPROVE: PR 1400 closeout and issue IDs 131-134 are unique, internally consistent, and preserve the append-only ledgers. | check:branch-review-ledger PASS; check:outstanding-issues PASS; diff review; no unresolved threads | | 2026-07-30 | origin/circleci-project-setup | 9a55990053e26c02703b1ec9f2523a7c85e21e14 | branch-cleanup | REJECTED and deleted remote. Unique tip only changed trailing newline on obsolete .circleci hello-world config; CircleCI removed from main in PR #1412. No open PR. | fetch --prune; three-dot + tip inspect; gh pr list open=0; main has no .circleci; GitHub reads explicitly authorized; no non-GitHub provider checks. | | 2026-07-30 | origin/execute-audit-code-remediation | 3470279fba23ad442d59d34552eb576e87f24141 | branch-cleanup | REJECTED and deleted remote. PR #1162 already merged; sole unique commit was a ledger CI-green row already present on main (edcd17a1…). No open PR; no unique product content. | fetch --prune; cherry-pick log; tip-to-tip/three-dot; grep ledger for edcd17a1; gh pr 1162 MERGED; open=0; GitHub reads explicitly authorized; no non-GitHub provider checks. | | 2026-07-30 | origin/apply-audit-remediation-protocol | 046cb38ad45411c5f539636d4c976b25195f7bbd | branch-cleanup | RETAIN. Closed PR #1338; tip still has unique files main lacks (motion-tokens.ts, use-overlay-presence.ts) plus stale sheet/globals diffs. Not empty vs main; do not delete. | ledger lookup; cherry-pick+three-dot; blob existence on main; gh PR #1338 CLOSED; GitHub reads explicitly authorized; no non-GitHub provider checks. | @@ -159,24 +167,28 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-30 | origin/execute-audit-remediation-tasks | bdcf8d5c1f14c927bf5b71aaacd34d006856da4f | branch-cleanup | RETAIN. Closed PR #1347; tip adds check-answer-quality-thresholds.ts and check-cost-cap-preflight.ts that main lacks, plus other diffs. Keep. | ledger lookup; cherry-pick; MAIN_LACKS path check; gh #1347 CLOSED; GitHub reads explicitly authorized; no non-GitHub provider checks. | | 2026-07-30 | origin/execute-typography-audit-fixes | dd641579f4cf54f82de89ef268ac8aa6acb439b5 | branch-cleanup | RETAIN. Closed PR #1185 (clean successor #1294 merged); tip blobs still differ from main on globals.css and mockup typography tweaks. Not empty; keep. | ledger lookup; cherry-pick; blob equality; gh #1185 CLOSED #1294 MERGED; GitHub reads explicitly authorized; no non-GitHub provider checks. | | 2026-07-30 | origin/implement-audit-design-fixes | dda4a42baa34e28f12d1e676fcabdbdfaef820c8 | branch-cleanup | RETAIN. Closed PR #1263; tip still carries unique not-found/error route files and a large three-dot diff vs main. Keep. | ledger lookup; cherry-pick; path existence; gh #1263 CLOSED; GitHub reads explicitly authorized; no non-GitHub provider checks. | -| 2026-07-30 | PR #1400 | e869cb9d7ab20939361b277d1c6fcc07bbb6ca45 | pr-1400-guard-push-band-adoption | MERGED — 17 review findings across guard-push.mjs and the band-adoption gate, all fixed and thread-resolved; each fix confirmed by reverting it and watching the guard fail. Guard now checks the pushed SHA in a git worktree (config, dynamic config, policy escalation incl. removal, lockfile Prettier parity); adoption gate replaced presence-matching with per-module reachability, closing six false greens of one root cause plus type-position edges found in self-review. Merge verified: all 8 commits ancestors of main, 4 changed files byte-identical. | verify:cheap 432 files / 4470 passed 4 skipped; format:check clean; PR required success; services+tools page gutting reports orphans; 6 push-guard scratch-repo cases with real exit codes; every fixture mutation-verified | -| 2026-07-30 | cursor/process-anti-conflict-speed-1edf / PR #1416 | 2a31fcee0ef2e330a4901481c0810103d89c96cf | process anti-conflict merge readiness | NOT READY. CI green on stale head, but merge-tree vs current main is CONFLICTING in ci.yml, package.json, and add/add on check-outstanding-issues.mjs after #1410 landed a stronger #112 gate. Keep unique value: AGENTS anti-conflict procedure, #116 PR mergeability workflow, merge=union on outstanding-issues (explicitly still open after #1410). Drop duplicate weaker outstanding-issues checker; re-verify after sync. | ledger:lookup NOT REVIEWED; merge-tree dirty vs origin/main; ManagePullRequest CI SUCCESS (15 ok / 0 fail, Production UI skipped as non-UI); local verify:pr-local earlier on pre-conflict head 4467 passed | -| 2026-07-30 | cursor/process-anti-conflict-speed-1edf / PR #1416 | 387ffd07887f1160fca8fe98c1c4809e852531ae | process anti-conflict merge readiness | READY after sync with main. Kept #1410 structural outstanding-issues gate; added merge=union + runtime attr check; retained #116 PR mergeability workflow and AGENTS anti-conflict playbook; dropped duplicate weaker checker/test. merge-tree clean vs origin/main. | merge-tree clean; check:outstanding-issues pass; check:pr-mergeability pass; check:gate-manifest pass; verify:pr-local pass | -| 2026-07-30 | cursor/process-anti-conflict-speed-1edf / PR #1416 | 38ae07b989e6414026235debad0e429ba64cf462 | process anti-conflict merge readiness | READY at final tip. Same as prior READY plus this ledger append only; merge-tree still clean vs origin/main. | merge-tree clean; verify:pr-local on 387ffd07 parent (4480 passed); tip is ledger-only follow-up | -| 2026-07-30 | origin/main | 3569e7888bba5d11f143f27c11eb9bfa58800e4f | dependency installation and CI reproducibility | no P0-P2 findings; corrected stale setup-ui-e2e cache description | manifest-lock parity; Actions pins; merge-marker scan; merged PR 1360 diff | -| 2026-07-30 | codex/chat-dependency-pr-review-dependency-pr-review-20260730 | 2aee8c74e64bd09954fe1b474c73b25805063de0 | open PR changed-scope review | APPROVE: setup action description now matches clean npm install with npm-download caching; no behavior change. | check:github-actions PASS; diff review; no unresolved threads | -| 2026-07-30 | claude/top-search-design-mockups-w53znc | 939d5799b9999f3f63928e1b2c95d097f07eff90 | open PR changed-scope review | APPROVE: PR 1400 closeout and issue IDs 131-134 are unique, internally consistent, and preserve the append-only ledgers. | check:branch-review-ledger PASS; check:outstanding-issues PASS; diff review; no unresolved threads | | 2026-07-30 | cursor/safe-branch-cleanup-78a8 | c5190f38834ef2e928edc4876d971aa9d5d69fe7 | open PR changed-scope review | APPROVE after fixes: cleanup refs are discoverable, provider evidence is accurate, and issue 108 closure is preserved against current main. | check:branch-review-ledger PASS; check:outstanding-issues PASS; two review threads resolved | | 2026-07-30 | claude/outstanding-issues-triage-24c8ow | 8d2710fd6cbdc84e8c50a6c9bc0a1e1a0cd612c8 | open PR changed-scope review | APPROVE: completed items 095, 096, 104, 109, and 115 move to archive with no deletion, duplicate ID, or stale next-id. | check:outstanding-issues PASS; check:branch-review-ledger PASS; diff review; no unresolved threads | | 2026-07-30 | claude/latency-findings-impl-s8g01v | e7ff5e933ba1f34d5adbd46dd77c38aced11ed44 | open PR changed-scope review | APPROVE: ordering-risk documentation is accurate and the near-bottom refusal guard now proves its geometry is non-vacuous before asserting no hide. | diff check PASS; focused test review; no unresolved threads; exact-head Production UI required | -| 2026-07-30 | PR #1427 / claude/ci-testing-review-2l8klp | db8209be707b79142d1d228d8c4e04120f9cdeaa | ci-testing-review | Measured PR CI from the Actions API: Production UI is 15m26-16m31 of a 16.8-18.6min run (83-89% of wall clock; Playwright itself 339 passed (13.5m)), every other job done by minute 4; 25/60 completed runs in an 83min window were cancelled (42%). FIXED: sharded ui-critical across 3 runners (count measured - N=4 gives the same 121-test critical path, N=5/N=8 give empty shards which would go red without --pass-with-no-tests); root-caused the real red (ui-phone-scroll dragScrollBy clamped silently and returned nothing, so a 720px request could deliver a fraction and the correct assertion failed 10s later) and made the drag prove its delivery with assertions byte-identical; browser-cache restore-keys; codex-autofix job timeouts; visual config serialised; gate-count guard added and mutation-proven. DEFERRED as #125-#129: ui_changed over-firing on src/app/api, cold Next cache in the Playwright build, advisory-UI cost vs zero quarantine tests, inert CI_TRIAGE, dead changes outputs. | verify:cheap PASS (431 files / 4493 passed, 4 skipped); verify:pr-local PASS (same); prettier --check . PASS; check-gate-manifest PASS + mutation-proven red at stale count; shard balance measured via playwright --list; verify:ui NOT RUN - container cannot launch Chromium (issue #121, build 1234 vs 1194) so the phone-scroll fix and the sharded job are unexecuted, PR CI is first execution | -| 2026-07-30 | PR #1427 / claude/ci-testing-review-2l8klp | b9de34d40d2dc5ab164bb1eb582db1cfcd1009c3 | ci-testing-review | SUPERSEDES the 2026-07-30 db8209be record, which asserted a root cause now REFUTED. That record claimed dragScrollBy clamping made the ui-phone-scroll red; main's #127 carries trace evidence (PR #1404 run 30521269873) that the drag delivered in full (scrollTop 1272 = 552+720) with ~1300px runway spare and a 10s non-flip is a latched state. The change is a diagnostic and guard, NOT a fix, and is now labelled so in the docstring, commit, PR body and #127. Remaining candidates: scrollHidden false vs sharedChromePinned latched; they are indistinguishable from the DOM because only the composite data-scroll-hidden is exposed. Prime suspect in source: composerFocusPinsChrome has a still-the-active-owner guard, headerFocusPinsChrome has none (master-search-header.tsx:397-398). ALSO: this PR ran zero pull_request workflows for ~2h (no CI/Gitleaks/Semgrep, only pull_request_target) because a real conflict blocked refs/pull/1427/merge - issue #116, caught by main's new PR mergeability check. Merging main fixed it and CI ran green first try. | CI run 30530618838 SUCCESS (13m39). MEASURED shard result, correcting the ~7min prediction: Production UI (1) 121 tests 9m36, (2) 111 tests 6m54, (3) 110 tests 6m20 - per-test cost is NOT uniform, shard 1 holds the slow specs, so the largest shard is 9m36 not the predicted 6.8min. ui-critical-fast 3m14. PR required SUCCESS. verify:cheap on merged tree PASS (434 files / 4563 passed, 4 skipped); prettier --check . PASS; ui-phone-scroll ran locally 1x via PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH: 56 passed (5.3m) - three-run protocol NOT completed and not applicable, since this is not a flake fix. | | 2026-07-30 | claude/ci-testing-review-2l8klp | 2e2160bc8b9d2d824209c217c67cb9cac1be3a8d | open PR changed-scope review | APPROVE: three-way UI sharding, critical-first gating, measured drag travel, and gate-manifest updates preserve required-check aggregation and deterministic Playwright settings. | check:github-actions PASS; check:ci-scope PASS; check:gate-manifest PASS; ledger guards PASS; exact-head sharded Production UI required | +| 2026-07-30 | PR #1432 | a2b53c815b3c060dec2619af2855a63f9f496858 | Playwright browser preflight review and repair | fixed; focused tests pending coordinator | Prettier PASS; issues guard PASS; focused Vitest blocked by active Playwright lease | +| 2026-07-30 | PR #1432 | f85995ade3a19513a531713724813adc742c360d | Playwright browser preflight verification | focused tests pass; typecheck lease-blocked | 16 focused tests PASS; Prettier PASS; typecheck admission blocked | | 2026-07-30 | PR #1430 | a9ae22ac4915e86d51ee05787059382a39bd8ba8 | phone chrome diagnostics and merge repair | fixed and ready for CI | issues guard; ledger guard; 37 focused tests; phone-chrome dry-run | -| 2026-07-30 | PR-1436 | 9d8e081f3e7003d4f2210b00a7b7e54bf7ca2f0b | PR #1436 documentation organization and link repair | fixed stale no-driver wording and renumbered three union-collided issue records; no remaining findings | docs index, links, scripts, outstanding-issues, and ledger guards pass | -| 2026-07-30 | cursor/ci-hygiene-gates-1bf5 | b660dbc5a10d7ca3da03541028017f0abc6b5bd3 | ci-hygiene-gates-merge-readiness | NOT READY: cancel-to-green behavior still allowed required PR CI to pass incorrectly; fixed at subsequent head 8f3283d00da274dee507a1b8e9b611321d1f35be | check:ci-scope; check:gitleaks-pinned; scope-classify PR files ui_changed=false; cancelled-as-neutral simulation exposed #095 | +| 2026-07-30 | PR-1432 | 7c7b63cf40d59652954e539ce1b3027005916bf1 | PR #1432 Playwright browser preflight final exact-head review | fixed existing project-isolation contract after preflight refactor; no remaining findings | preflight and isolation Vitest 9/9; typecheck pass; Prettier and diff checks pass | | 2026-07-30 | PR-1440 | f7260cc6a0da87cb4df1ac95ef962967e667c3f0 | PR #1440 issue #102 ordering correction | accurately restores the two canary-gated retrieval ordering constraints; no findings | outstanding-issues and ledger guards pass; documentation-only diff | +| 2026-07-30 | PR-1432 | a5d234302b57be6f7ce5d1957c9ec00bc7f191f0 | PR #1432 Playwright preflight and phone-scroll reliability | cross-platform preflight fails closed and production focus-restore race is removed from the phone-scroll proof; no remaining findings | preflight tests 9 passed; focused Chromium journey 2 passed; formatting and ledger guards pass | +| 2026-07-30 | PR-1432 | 330086eff76f704ce6b9cf5405aeecfdd375027c | PR #1432 visual-config preflight follow-up | visual runs now preflight chromium-artifacts instead of the unrelated main browser matrix; unknown configs fail closed | config-selection tests added; formatting passes; exact-head CI pending | | 2026-07-30 | PR-1445 | 07933e08cff6c7d81345e02c03727032ccf522b6 | PR #1445 close duplicate issue | correctly archives duplicate #140 while preserving #133 as the surviving open conflict-frequency record; no findings | outstanding-issues and docs-link guards pass; docs-only diff | +| 2026-07-30 | claude/organize-local-worktree-d22bc3 | 2f26a53b5aeb3df451cf7b1d04f80b07edf0d6fe | docs organisation: dated-record filing, docs index gaps, orientation maps | PR #1436 opened — 5 dated docs filed into docs/audit and docs/archive, root codex-cloud-review moved under docs/prompts, 17 docs README index gaps closed, root data/ documented in CLAUDE.md + codebase-index; no product code, schema or RAG surface touched | docs:check-links 1368 refs pass; docs:check-scripts 378 pass; docs:check-index OK; format:check whole-tree clean; verify:cheap 26 static gates + lint + typecheck pass, unit 4562 pass / 1 pre-existing Windows path-separator failure in tests/repo-hygiene.test.ts | +| 2026-07-30 | PR-1436 | 9d8e081f3e7003d4f2210b00a7b7e54bf7ca2f0b | PR #1436 documentation organization and link repair | fixed stale no-driver wording and renumbered three union-collided issue records; no remaining findings | docs index, links, scripts, outstanding-issues, and ledger guards pass | +| 2026-07-30 | cursor/ci-hygiene-gates-1bf5 | b660dbc5a10d7ca3da03541028017f0abc6b5bd3 | ci-hygiene-gates-merge-readiness | NOT READY: cancel-to-green behavior still allowed required PR CI to pass incorrectly; fixed at subsequent head 8f3283d00da274dee507a1b8e9b611321d1f35be | check:ci-scope; check:gitleaks-pinned; scope-classify PR files ui_changed=false; cancelled-as-neutral simulation exposed #095 | +| 2026-07-30 | PR #1446 / claude/ci-testing-review-2l8klp | 11e7e8653c4742108feee4e9164ba066a92fc18a | ci-testing-review-capture | Captures #141, the one finding from the PR #1427 session that was never recorded: ui-phone-scroll.spec.ts:973 Services result anchor jumped on viewport shrink (run 30534158395 shard 1, :1133, 120 passed). Distinct from #127 and not fixed by #1427 - that head already carried #1427's runway poll and travel assertion, the journey is the Services result canvas not the document route, and the assertion is anchor stability across a resize not a chrome hide. Narrowing recorded: the sibling documentScrollTop assertion at :1137 did NOT fail, so the scroll position held while the element moved, ruling out the scroll-restoration class. Branch restarted from origin/main because #1427 merged as 040ce97 (verified by content not ancestry: shard matrix, dragScrollUntilHidden and the gate-count guard all present on main). NOTE for #127: its updated row shows the trace-based refutation of the short-drag hypothesis was itself misread (maxOffset 2753 read at a different trace moment than the failing drag; pre-runway value was 1153), so the root cause withdrawn during the #1427 session was in fact correct - a third-party refutation needs the same verification as a third-party fix claim. | verify:cheap PASS (Test Files 435 passed; Tests 4569 passed, 4 skipped, exit 0); check:outstanding-issues PASS (139 rows, unique ids, next-id=142 above highest); prettier --check . PASS. Docs-only: ui_changed should be false and the Chromium shards should skip. | +| 2026-07-30 | PR #1446 / claude/ci-testing-review-2l8klp | e6c704c6c8cd989825adf30ecbffeb57344bfa56 | ci-testing-review-capture | SUPERSEDES the 11e7e865 capture row: the Services viewport-anchor flake is now #142, not #141. Main's #141 (design-sync --clinical-accent-strong token gap from PR #1443) landed while this branch was open, colliding on the same id. Merge conflict in docs/outstanding-issues.md resolved by rebuilding from origin/main and re-applying the Services capture as #142 with next-id=143. Content of the capture is unchanged. | check:outstanding-issues PASS (140 rows, 68 open, 72 archived, next-id=143); merge-tree was CONFLICTING on outstanding-issues only; conflict markers removed | +| 2026-07-30 | PR #1446 / claude/ci-testing-review-2l8klp | 8be4f703d5729b4aa10e73ee8fbc77e03f400b8b | ci-testing-review-capture | Withdraws an invalid inference from the earlier records for this PR, on a correct Codex finding. Those rows argued that because the sibling documentScrollTop assertion did not fail, the scroll position held and scroll-restoration causes were ruled out. Playwright aborts a test at the first failing expect, so once anchorTop threw, documentScrollTop NEVER EXECUTED - its absence from the output shows nothing. The #142 row now says so and the class is not ruled out. The capture itself stands: the Services viewport-anchor failure is real, intermittent on byte-identical code (pass/pass/fail/pass-on-rerun), and distinct from #127. Separately CodeRabbit flagged :973 vs :1133 as inconsistent and then withdrew it: :973 is the test declaration and :1133 the thrown assertion, both reported by Playwright, and declaration lines drift (898 / 973 / 1041 across three tree states) which is why the exact title is the durable identity. | check:outstanding-issues PASS (140 rows, unique ids, next-id=143). Lesson: reasoning from an assertion that never ran is the same verified-vs-assumed error this session already hit twice in the other direction. | +| 2026-07-30 | claude/x3-rag-coverage-gate-qx9j7d (PR #1454, squashed as 102bb1f) | 102bb1f5edf09e666d1be5934ff5dfb2aa5abcf0 | X3/#086 evidence coverage gate extraction from rag.ts into rag-coverage-gate.ts | clean and landed — byte-identical move verified against pre-merge main, rag.ts 5030->4780, budget ratcheted to 4780, no back-edge, public re-export preserved; squash captured 100% of branch content, nothing orphaned | workflow:rag-lab, focused vitest 81/81, check:maintainability-budgets 4780/4780, check:rag:fixtures 36 golden, eval:rag:offline 567/567, typecheck, lint, check:knip, format:check, verify:cheap 4569 passed, npm test 4569 passed, verify:pr-local build+bundle-scan, post-merge npm test on main 4574 passed | +| 2026-07-30 | PR #1432 | 74adc5aa3f8a4dad659c7a40490288ef8efcb82e | Playwright browser preflight and phone-sheet focus repair | APPROVE after current-main sync: browser-project resolution fails closed, phone-sheet focus is stable, and no stale issue-ledger state remains. | 3 focused files 45 passed; phone-chrome dry-run; installed-lock parity; docs and ledger guards; formatting | +| 2026-07-30 | PR-1470 | 1932e81ece9361c08607d2ef01ad653a7df0ac8d | PR #1470 full diff vs origin/main | PASS after repair: #013 remains open and measurement-gated | check:outstanding-issues passed; docs:check-links 1408 passed; Prettier passed; git diff --check | +| 2026-07-30 | PR-1473 | a2b2820c13a47425cfc0ea751e57ee35e9bd1105 | PR #1473 full diff vs origin/main | PASS after review repair: governance refusal and error-state contracts are consistent | outstanding-issues guard passed; docs links 1412 passed; docs index passed; Prettier passed; git diff --check | | 2026-07-30 | 0b01c56fe539598279b9393db5e207bc78fa41c9 | 0b01c56fe539598279b9393db5e207bc78fa41c9 | branch-cleanup-deletion-pending | redundant clean detached head already on origin/main; removal deferred by primary-dirty lease | clean status; merge-base ancestor of origin/main; no open PR | | 2026-07-30 | 018673ff5cadadbd799815cea8d742de28922754 | 018673ff5cadadbd799815cea8d742de28922754 | branch-cleanup-deletion-pending | redundant clean detached review base already on origin/main; removal deferred by primary-dirty lease | clean status; merge-base ancestor of origin/main; no open PR | | 2026-07-30 | codex/review-pr1438 | f13c261ee96405dc338db184ec74009bcd3699a3 | branch-cleanup-deletion-pending | redundant exact head merged in PR 1438; removal deferred by primary-dirty lease | clean status; GitHub merged exact head; zero cherry-pick-unique commits | @@ -198,17 +210,6 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-30 | codex/review-pr1444 | 5d88a6547e5785db0929df5d51a1eaea12ad5ac6 | branch-cleanup-deletion-pending | redundant exact head merged in PR 1444; removal deferred by primary-dirty lease | clean status; GitHub merged exact head; no active process | | 2026-07-30 | codex/review-pr1445 | 483a1c6190dfbd1a5895ef2c419a73f0f2162f05 | branch-cleanup-deletion-pending | redundant exact head merged in PR 1445; removal deferred by primary-dirty lease | clean status; GitHub merged exact head; no active process | | 2026-07-30 | PR #1462 | 5146ae94e226a6e55968d80ecefa53c7cd5df9c3 | bounded inactive-work cleanup documentation | APPROVE after fix: both cleanup batches remain deferred behind the primary-checkout lease, and the resume instruction now names the executable repository command. | outstanding-issues guard; ledger guard; diff review; one review finding fixed | -| 2026-07-30 | PR #1432 | a2b53c815b3c060dec2619af2855a63f9f496858 | Playwright browser preflight review and repair | fixed; focused tests pending coordinator | Prettier PASS; issues guard PASS; focused Vitest blocked by active Playwright lease | -| 2026-07-30 | PR #1432 | f85995ade3a19513a531713724813adc742c360d | Playwright browser preflight verification | focused tests pass; typecheck lease-blocked | 16 focused tests PASS; Prettier PASS; typecheck admission blocked | -| 2026-07-30 | PR-1432 | 7c7b63cf40d59652954e539ce1b3027005916bf1 | PR #1432 Playwright browser preflight final exact-head review | fixed existing project-isolation contract after preflight refactor; no remaining findings | preflight and isolation Vitest 9/9; typecheck pass; Prettier and diff checks pass | -| 2026-07-30 | PR-1432 | a5d234302b57be6f7ce5d1957c9ec00bc7f191f0 | PR #1432 Playwright preflight and phone-scroll reliability | cross-platform preflight fails closed and production focus-restore race is removed from the phone-scroll proof; no remaining findings | preflight tests 9 passed; focused Chromium journey 2 passed; formatting and ledger guards pass | -| 2026-07-30 | PR-1432 | 330086eff76f704ce6b9cf5405aeecfdd375027c | PR #1432 visual-config preflight follow-up | visual runs now preflight chromium-artifacts instead of the unrelated main browser matrix; unknown configs fail closed | config-selection tests added; formatting passes; exact-head CI pending | -| 2026-07-30 | PR #1446 / claude/ci-testing-review-2l8klp | 11e7e8653c4742108feee4e9164ba066a92fc18a | ci-testing-review-capture | Captures #141, the one finding from the PR #1427 session that was never recorded: ui-phone-scroll.spec.ts:973 Services result anchor jumped on viewport shrink (run 30534158395 shard 1, :1133, 120 passed). Distinct from #127 and not fixed by #1427 - that head already carried #1427's runway poll and travel assertion, the journey is the Services result canvas not the document route, and the assertion is anchor stability across a resize not a chrome hide. Narrowing recorded: the sibling documentScrollTop assertion at :1137 did NOT fail, so the scroll position held while the element moved, ruling out the scroll-restoration class. Branch restarted from origin/main because #1427 merged as 040ce97 (verified by content not ancestry: shard matrix, dragScrollUntilHidden and the gate-count guard all present on main). NOTE for #127: its updated row shows the trace-based refutation of the short-drag hypothesis was itself misread (maxOffset 2753 read at a different trace moment than the failing drag; pre-runway value was 1153), so the root cause withdrawn during the #1427 session was in fact correct - a third-party refutation needs the same verification as a third-party fix claim. | verify:cheap PASS (Test Files 435 passed; Tests 4569 passed, 4 skipped, exit 0); check:outstanding-issues PASS (139 rows, unique ids, next-id=142 above highest); prettier --check . PASS. Docs-only: ui_changed should be false and the Chromium shards should skip. | -| 2026-07-30 | PR #1446 / claude/ci-testing-review-2l8klp | e6c704c6c8cd989825adf30ecbffeb57344bfa56 | ci-testing-review-capture | SUPERSEDES the 11e7e865 capture row: the Services viewport-anchor flake is now #142, not #141. Main's #141 (design-sync --clinical-accent-strong token gap from PR #1443) landed while this branch was open, colliding on the same id. Merge conflict in docs/outstanding-issues.md resolved by rebuilding from origin/main and re-applying the Services capture as #142 with next-id=143. Content of the capture is unchanged. | check:outstanding-issues PASS (140 rows, 68 open, 72 archived, next-id=143); merge-tree was CONFLICTING on outstanding-issues only; conflict markers removed | -| 2026-07-30 | PR #1446 / claude/ci-testing-review-2l8klp | 8be4f703d5729b4aa10e73ee8fbc77e03f400b8b | ci-testing-review-capture | Withdraws an invalid inference from the earlier records for this PR, on a correct Codex finding. Those rows argued that because the sibling documentScrollTop assertion did not fail, the scroll position held and scroll-restoration causes were ruled out. Playwright aborts a test at the first failing expect, so once anchorTop threw, documentScrollTop NEVER EXECUTED - its absence from the output shows nothing. The #142 row now says so and the class is not ruled out. The capture itself stands: the Services viewport-anchor failure is real, intermittent on byte-identical code (pass/pass/fail/pass-on-rerun), and distinct from #127. Separately CodeRabbit flagged :973 vs :1133 as inconsistent and then withdrew it: :973 is the test declaration and :1133 the thrown assertion, both reported by Playwright, and declaration lines drift (898 / 973 / 1041 across three tree states) which is why the exact title is the durable identity. | check:outstanding-issues PASS (140 rows, unique ids, next-id=143). Lesson: reasoning from an assertion that never ran is the same verified-vs-assumed error this session already hit twice in the other direction. | -| 2026-07-30 | claude/x3-rag-coverage-gate-qx9j7d (PR #1454, squashed as 102bb1f) | 102bb1f5edf09e666d1be5934ff5dfb2aa5abcf0 | X3/#086 evidence coverage gate extraction from rag.ts into rag-coverage-gate.ts | clean and landed — byte-identical move verified against pre-merge main, rag.ts 5030->4780, budget ratcheted to 4780, no back-edge, public re-export preserved; squash captured 100% of branch content, nothing orphaned | workflow:rag-lab, focused vitest 81/81, check:maintainability-budgets 4780/4780, check:rag:fixtures 36 golden, eval:rag:offline 567/567, typecheck, lint, check:knip, format:check, verify:cheap 4569 passed, npm test 4569 passed, verify:pr-local build+bundle-scan, post-merge npm test on main 4574 passed | -| 2026-07-30 | PR #1432 | 74adc5aa3f8a4dad659c7a40490288ef8efcb82e | Playwright browser preflight and phone-sheet focus repair | APPROVE after current-main sync: browser-project resolution fails closed, phone-sheet focus is stable, and no stale issue-ledger state remains. | 3 focused files 45 passed; phone-chrome dry-run; installed-lock parity; docs and ledger guards; formatting | -| 2026-07-30 | PR-1470 | 1932e81ece9361c08607d2ef01ad653a7df0ac8d | PR #1470 full diff vs origin/main | PASS after repair: #013 remains open and measurement-gated | check:outstanding-issues passed; docs:check-links 1408 passed; Prettier passed; git diff --check | | 2026-07-30 | PR-1441 | c298432cffd2a1aee1b96edda9d32deb31be7f00 | PR #1441 upload-limit parity and issue-ledger closures | upload limit guard is fail-closed and safely wired; archived rows retain their dispositions; no findings | upload parity self-test/runtime pass; issue, ledger, gate-manifest, and docs-script guards pass | | 2026-07-30 | PR #1441 | d8bd22192ce974d4d2340ff26959ee41480218e9 | PR readiness: issue ledger, upload parity, CircleCI cleanup | FIXED: review found the Docker build lacked MAX_UPLOAD_MB input and open issue #119 still requested obsolete CircleCI investigation; both are repaired, with no remaining P0-P2 findings in scope. | upload parity default and 50/50 pass; 50/40 mismatch fails; outstanding-issues, branch-review-ledger, and gate-manifest guards pass | | 2026-07-30 | PR #1441 | 0b17e849406a03b87af20e627da6500a7cd03c2e | PR readiness: issue ledger, upload parity, CircleCI cleanup | FIXED: review repaired Docker build-time server parity, archived stale CircleCI row #119, and made the #095 aggregate harness portable; no remaining P0-P2 findings in scope. | verify:pr-local PASS on parent code tree 727ed55a7: 435 files, 4570 passed, build 1694 pages, client scan pass, RAG 36 cases/21 suites; latest-main docs, issue, review-ledger, and upload guards pass | diff --git a/docs/outstanding-issues.md b/docs/outstanding-issues.md index ca225ed696..dcc574f8fb 100644 --- a/docs/outstanding-issues.md +++ b/docs/outstanding-issues.md @@ -135,7 +135,7 @@ removed after current-main verification; it is not missing recommended work. | #094 | P2 | rec | Design-system gates assert structure, not rendered effect | **Outcome:** a style contract cannot pass while the style is inert. **Detail:** PR #1316's accent rail shipped inert because `.search-band` sat in `@layer components`, which loses to Tailwind's utilities layer regardless of specificity — and the test asserted `toHaveClass("search-band")`, i.e. class presence, not effect. Computed style showed `1px rgb(229,231,235)` where `2px rgb(11,111,134)` was intended. The same shape of gap let a rail-colour assertion compare a colour against a width and pass unconditionally. **Next:** for contracts where the visual IS the requirement (rails, forced-colors thickness, tap targets), assert `getComputedStyle` in a Playwright case rather than class names in a DOM test, and add the unlayered-component convention to the design-system contract check. **Stop:** do not convert existing passing DOM tests wholesale; add computed-style proof only where the effect carries the meaning. | PR #1316 Codex P2 finding; session 2026-07-28 | 2026-07-28 | | #098 | P2 | task | Offline round-trip budget harness for the hot routes | **Outcome:** per-scenario Supabase round-trip counts are pinned by a test, so an extra round trip on a hot path is a red gate rather than an inference. **Done 2026-07-29:** the measurement gap is closed — `Server-Timing` now covers `auth`/`ratelimit`/`scope` on `/api/answer`, `auth`/`ratelimit`/`search`/`total` on `/api/search`, and `auth`/`ratelimit` on `/api/answer/stream` (previously the route the UI actually calls emitted no header at all). Headers flush before the first SSE frame, so in-stream stages cannot reach a header and must NOT be routed through the governed `progress`/`final` contract. `tests/answer-route-preamble.test.ts` pins admission-before-scope (no scope call while the limiter is pending or after a deny) and the client-disconnect abort signal. **Done 2026-07-30 (PR #1450, `1bff4c78`):** the counting proxy exists and the answer path is budgeted. `tests/helpers/supabase-round-trip-counter.ts` counts on **execution, not construction** — a builder that is never awaited costs zero, one awaited twice costs two — which is the distinction that makes the count mean "requests issued". `tests/rag-round-trip-budget.test.ts` pins two offline answer-path scenarios (a single-source source-only answer, and that trips do not scale with the number of retrieved sources) plus three self-tests of the counter, and is registered in `scripts/fixtures/rag-offline-contract-tests.json` so it runs inside the offline contract rather than only on demand. Verified locally, provider-free: `Test Files 1 passed (1)`, `Tests 5 passed (5)`. Its documented blind spot is worth repeating before anyone cites a budget as total cost: it sees only traffic through the wrapped client, so a trip issued via another client instance, a direct `fetch`, or a provider SDK is invisible to it. **Next:** two gaps remain from the original scope. (a) `/api/search` has no budget — this row named the hot routes plural and only the answer path is pinned, so an added round trip on search is still an inference. (b) `scripts/eval-rag-offline.mjs` and `scripts/test-rag-offline.mjs` were not wired; decide whether the offline contract runner is the single right home for budgets or whether those suites need their own, and record the decision here rather than leaving both plausible. | `docs/audit/latency-audit-2026-07-28.md` measurement plan; `src/lib/server-timing.ts`; `src/lib/answer-stream-contract.ts:18-21` | 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 | **Outcome:** a clinician sees verified answer content before the whole generation completes. Highest-leverage latency finding in the 2026-07-28 audit: generation is buffered (`openai.ts:465`) and delivered in ONE `final` SSE frame, so time-to-first-content equals total latency — a strong answer inside its 25 s SLO still shows a blank panel for 25 s. The 15 s `sse-heartbeat` exists because that silence routinely exceeds 15 s; it instruments the defect rather than fixing it. **Naive token streaming is REFUTED, not merely unbuilt:** `answer-stream-contract.ts:18-21` removed `token`/`revising` deliberately because a rolling deployment would "re-expose unvalidated clinical prose", and raw tokens bypass the numeric-faithfulness gate the 2026-07-01 audit filed as H1. **Only admissible shape:** progressive disclosure of already-verified units (evidence/sources at retrieval-complete, then per-section after that section clears verification) over the existing whitelisted `progress` event. Needs a clinical-governance decision plus a canary pair. Also add the refutation to `docs/rag-behaviour/refuted-approaches.md`. Cross-references #021. **Stop:** do not re-land `token` streaming. | `docs/audit/latency-audit-2026-07-28.md` L0-1; `src/lib/answer-stream-contract.ts:18-21`; `src/lib/sse-heartbeat.ts` | 2026-07-29 | +| #100 | P2 | rec | Buffered answer generation has no incremental verified delivery | **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 | **Outcome:** independent retrieval stages stop running serially, proven by a live canary pair. Candidates: metadata/memory/visual hydration triples repeated on four branches (`rag.ts:2460,2493,2521` and three more) while `rag.ts:2751-2804` already parallelises three RPCs in one `Promise.all`, so the omission is inconsistency rather than intent; the nested `await`-in-loop scope enumeration (`search-scope.ts:202,328`); typeahead results never cached (`rag.ts:2698-2711`); 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 needs 36/36 retrieval plus recall 1.0 and zero per-case rr regressions. Distinct from #001 (semantic rerank). Resolved #075 and #083 are the precedents for why these are gated rather than free. **Stop:** needs the #098 harness and explicit canary approval first. | `docs/audit/latency-audit-2026-07-28.md` L2-1/L2-2/L2-8/L1-5 | 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 | | #103 | P2 | issue | Wide table-facts trigram index missing from `schema.sql` | **Outcome:** the migration chain and `schema.sql` agree on `document_table_facts` trigram indexes. `supabase/migrations/20260714190000_document_table_facts_trgm_idx.sql` creates a wide 5-column trigram index that is **absent from `supabase/schema.sql`**, so local replay and the live database can diverge. Distinct from #102: different owner and verification path. **Next:** confirm whether the wide index exists live, then take one of exactly two routes — **retained:** mirror `document_table_facts_text_trgm_idx` into `supabase/schema.sql` beside the narrow one and regenerate `drift-manifest.json`; **redundant:** drop it through a new forward migration, never by deleting `20260714190000`. **`drift-allowlist.json` is NOT a third option** (PR #1377 review): its own header scopes it to _"Known live-vs-`schema.sql` divergence"_, so it can silence a live drift finding but cannot reconcile the migration chain with the mirror — a fresh `supabase db reset` still runs `20260714190000` and creates the index while `schema.sql` still omits it, leaving this row's stated outcome unmet. **No offline gate catches this today:** the migration↔`schema.sql` parity test (`tests/drift-detection.test.ts:59-68`) only asserts one migration's `schema_drift_snapshot` function definition, not an index inventory — which is why this sits open rather than red in CI, and why a replay-to-schema inventory comparison is the check that would have caught it. Note the narrow `document_table_facts_title_row_param_trgm_idx` (`schema.sql:6425`) is the one the effective RPC expression (`:6726`) actually matches, so the wide index may be genuinely redundant — do not drop it without live scan evidence, per the monitored-not-auto-fixed index policy. | `docs/audit/latency-audit-2026-07-28.md` limitations; `npm run check:drift` | 2026-07-29 | diff --git a/docs/verified-answer-incremental-delivery-design.md b/docs/verified-answer-incremental-delivery-design.md new file mode 100644 index 0000000000..2250a1f3de --- /dev/null +++ b/docs/verified-answer-incremental-delivery-design.md @@ -0,0 +1,214 @@ +# Incremental delivery of verified answer content + +Status: **design accepted for staged implementation; no runtime behaviour changed**
+Tracks: [`#100`](outstanding-issues.md), [`#021`](outstanding-issues.md)
+Origin: [`latency-audit-2026-07-28.md`](audit/latency-audit-2026-07-28.md#l0--structural-1) + +## Decision + +Improve time to first useful content without reviving token streaming. The answer stream may +progressively disclose only immutable, independently verified units: + +1. a bounded evidence preview after retrieval, ranking, owner-scope enforcement, the canonical + danger-level source-governance decision, and client-payload trimming; then +2. answer sections after each complete section has passed the same citation, text, numeric, source, + and claim-support checks required for the final answer. + +The canonical `final` event remains mandatory and authoritative. Incremental units are an +append-only preview of content that is byte-identical to a subset of that final payload. A client +must discard previews if the stream errors, is cancelled, or the final payload does not reconcile. + +This design explicitly rejects raw model-token delivery, provisional prose, in-place revision, and +any widening of `answerStreamEventNames`. Those shapes can expose a dose, threshold, or unsupported +claim before the existing post-generation safety gates can remove it. + +## Current constraint + +The provider call is buffered and returns one parsed structured object. Consequently, splitting the +existing fully generated object into frames would improve only post-processing paint time, not the +dominant generation wait. Meaningful per-section delivery requires a later provider-backed generation +experiment; retrieval-complete evidence can be delivered earlier without changing model behaviour. + +## Stream contract + +Keep the existing `progress`, `final`, and `error` event-name allowlist. Extend the public `progress` +DTO with an optional, discriminated `verifiedUnit` field. Existing clients ignore the field; new +clients render only recognized schema versions and unit kinds. + +```ts +type VerifiedUnit = + | { + schemaVersion: 1; + kind: "evidence_preview"; + sequence: 0; + sources: ClientSourcePreview[]; + selectedContextCount: number; + } + | { + schemaVersion: 1; + kind: "answer_section"; + sequence: number; + section: AnswerSection; + citations: Citation[]; + supportLevel: Exclude; + }; +``` + +Contract rules: + +- `sequence` is strictly increasing and unique within one response. Retries start a new HTTP stream; + units never carry across attempts. +- Evidence previews use the existing route-boundary source field policy and snippet limit. They never + include full chunk context, table facts, document summaries, memory cards, images, service-role + data, or another owner's document identifiers. +- A section is emitted only after all of its cited chunk IDs resolve to the already selected, + owner-scoped evidence and its support level is not `unsupported`. +- The final response contains the same section body, citation identities, and source identities for + every emitted unit. Reconciliation failure is a server fault, not permission to revise the preview. +- `complete` remains buffered until immediately before `final`. It never means that preview delivery + alone succeeded. +- Cache hits may emit the same units from the already governed cached answer, but the final cache + payload remains authoritative. + +## Verification boundary + +Create one pure server-only function for section finalization. It accepts a complete section plus the +selected evidence and returns either a governed immutable unit or a rejection. It must reuse, rather +than approximate, the current production gates: + +1. the canonical danger-level source-governance refusal used by `buildGovernedAnswerClientResponse`; +2. citation sanitization and source membership; +3. answer and structured-text sanitization; +4. numeric verification and unbolding of unverified numbers; +5. quote-card sanitization where applicable; +6. claim-support assessment and labelled numeric-band coherence; and +7. the canonical answer render policy. + +The governance refusal is evaluated before any evidence preview or answer section crosses the route +boundary. If it refuses the authoritative response, the stream emits zero verified units and continues +through the existing refusal/fallback contract; a preview must never disclose source content that the +final governed response withholds. + +Do not implement a second, weaker “stream-safe” verifier. If the current gates cannot operate on an +independent section, that section stays buffered until the final answer. Cross-section comparisons, +conflicts, and conclusions that depend on later sections are not independently emit-able in v1. + +## Delivery phases + +### Phase 0 — offline contract proof + +- Add schema validation for `verifiedUnit`, sequence monotonicity, bounded payload size, and rejection + of `token` / `revising`. +- Add reconciliation tests proving every preview is an exact subset of `final` and is discarded on + error, cancellation, retry, unknown schema version, or mismatch. +- Add a source-governance refusal fixture proving an outdated or poorly extracted danger-level source + emits zero evidence previews and zero answer-section units. +- Add owner-boundary fixtures proving private source fields and cross-owner identifiers cannot cross + the route boundary. + +This phase is provider-free and must land before either visible phase. + +### Phase 1 — retrieval-complete evidence preview + +- After answer evidence is ranked and the final context pack is selected, run the same danger-level + source-governance refusal used by the authoritative final response. Only when it permits disclosure, + build a preview through the existing client-source trimming policy and emit it as + `progress.verifiedUnit`. +- Render it in a clearly labelled “Selected evidence — answer still being verified” region. Do not + render it as answer prose or mark the answer complete. +- Preserve the current final source list, source governance warnings, feedback token, telemetry, and + persistence behaviour. + +This is the smallest useful increment: it brings owner-scoped, source-backed content forward while +leaving generation, retrieval ordering, and ranking byte-identical. + +### Phase 2 — verified answer sections + +- Experiment with generation in complete independently verifiable section units. A unit must be fully + parsed before verification; model token deltas remain private to the server. +- Prefer a bounded lead section followed by supporting sections. Do not create one provider request per + display paragraph without evidence that cost, latency, cancellation, and rate-limit behaviour remain + acceptable. +- Run independent section finalization, emit accepted sections, then assemble and globally verify the + canonical final answer. If global verification would change an emitted unit, fail closed, terminate + that stream, and let the existing client retry start a fresh request; never patch already displayed + prose or label the partial response complete. + +Phase 2 changes answer generation and cannot begin without the provider-backed gate below. + +## Failure, retry, and rollout behaviour + +- **Disconnect or Stop:** abort provider and retrieval work as today; the client removes all previews. +- **Retry:** clear prior previews before opening the new stream. A sequence number has meaning only + inside one response. +- **Verifier rejection:** emit no unit. Continue toward the governed final or existing conservative + source-only fallback. +- **Stream error after preview:** discard every preview and display the existing error state. Evidence + links from the failed stream do not remain visible; a retry starts with empty preview state. +- **Rolling deploy:** old clients safely ignore the optional field; new clients accept an absent field. + No new SSE event name is introduced. +- **Feature flag:** gate rendering and emission separately. Deploy client parsing first, then server + emission, then enable rendering for internal users. Rollback disables emission; no schema or stored + data rollback is needed. + +## Telemetry and acceptance + +Record no clinical text in telemetry. Record timestamps and counts only: + +- `retrieval_verified_unit_ms`, `first_verified_content_ms`, `first_verified_section_ms`; +- emitted/rejected unit counts and rejection-reason enums; +- final reconciliation success/failure; +- disconnect-before-final rate; and +- route, cache, fallback, and model class already recorded by the answer pipeline. + +Acceptance requires: + +- no change to retrieval results, ranking order, owner scope, final payload, source governance, or + conservative fallback behaviour; +- zero preview/final reconciliation failures in deterministic tests; +- a lower median `first_verified_content_ms` than final-answer latency for Phase 1; +- for Phase 2, no regression in grounded-supported answers, citation failures, numeric verification, + p95 final latency, provider cost, or disconnect-before-final rate; and +- accessibility proof that incremental additions do not repeatedly announce entire prior content or + move focus. + +## Required gates before runtime implementation + +Local/offline: + +1. focused stream-contract, parser, owner-scope, verification, and reconciliation tests; +2. `npm run eval:rag:offline`; +3. `npm run verify:cheap`; +4. `npm run check:production-readiness`; +5. `npm run ensure` followed by `npm run verify:ui` for the visible client phase; and +6. `npm run verify:pr-local` before handoff. + +Provider-backed and therefore separately approval-gated: + +1. `npm run eval:rag -- --limit 15` plus `npm run eval:quality -- --rag-only` for answer-generation + and post-processing changes; +2. a baseline/post live canary pair with document/content recall pinned at `1.0`, zero per-case + reciprocal-rank regressions, and no answer-quality regression; and +3. a staged observation window for final reconciliation, abort, latency, and cost metrics. + +## Governance disposition + +- **Clinical safety:** safer than token streaming because no provisional prose crosses the boundary; + rejected units remain invisible and the existing source-only fallback remains intact. +- **Privacy and access:** no new data source or owner scope; the route emits only the bounded fields + already permitted in final client payloads. +- **Source governance:** evidence remains linked to the same source identities and warnings; a preview + is explicitly not a completed clinical answer. +- **SaMD:** this changes presentation timing, not intended purpose or recommendation logic. Reassess + before Phase 2 because multiple generated units could change synthesis behaviour. +- **Rollback:** disable the server emission flag, then the client rendering flag. The canonical final + contract and stored answer format remain unchanged. + +## Explicit non-goals + +- Reintroducing `token` or `revising` events. +- Streaming partial JSON or prose before a complete unit verifies. +- Changing retrieval, ranking, evidence selection, prompts, or final-answer quality thresholds in + Phase 1. +- Persisting previews as completed answers or accepting feedback against preview-only content. +- Calling OpenAI, Supabase, hosted CI, or production services as part of this design-only change.