diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index c63968454..c367c8bb3 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -1138,6 +1138,16 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-28 | PR #1291 / `claude/issues-upload-limit-sync-123366` | `1607558188283d3497683f1067835d96f1031d3c` | CI babysit + merge conflict + Bugbot | FIXED. GitHub CONFLICTING/DIRTY was a real content conflict in `docs/outstanding-issues.md`: main had claimed `#084` for completed per-result grading evidence, colliding with this PR's upload-limit capture. Resolved by keeping main's ledger, renumbering the upload-limit recommendation to `#085`, and bumping `issues:next-id` to `086`. Synced again when main advanced with #1300. CodeRabbit date thread already resolved. Bugbot: zero `cursor[bot]` findings. Required CI green (PR required SUCCESS). | merge-tree CLEAN; prettier + docs:check-links PASS; hosted Change scope/Static/PR required SUCCESS; no provider-backed checks. | | 2026-07-28 | PR #1291 / `claude/issues-upload-limit-sync-123366` | `af140d11d5ca23dee0d8705d9933db967fc8c404` | Babysit closeout tip | Supersedes prior #1291 row at `16075581` after appending the conflict/Bugbot ledger record. Product delta vs main unchanged: `#085` upload-limit capture only. merge-tree CLEAN; awaiting exact-head required checks. | ledger append + check:branch-review-ledger PASS; prior tip hosted PR required SUCCESS. | | 2026-07-28 | PR #1302 / `claude/maturity-ledger-entry` | `64da2c1b34ae101590b8676af12ec6b49c14f0ad` | CI/conflict babysit + Codex threads + Bugbot | FIXED. Real content conflict with main: `#085` already claimed by upload-limit rec (#1291). Merged origin/main; renumbered maturity backlog to `#086`, bumped `issues:next-id` to `087`, added recommended-queue order 29 with go-ahead/RAG/provider stop rules. X7/M1 work orders arrived via main #1299. Codex P2 threads replied + resolved. Bugbot: zero cursor[bot] findings. CircleCI stub from main clears prior "no configuration" status error. | merge-tree CLEAN; prettier + docs:check-links + docs:check-scripts PASS; awaiting exact-head hosted CI; no provider-backed checks. | +| 2026-07-28 | PR #1298 / `codex/fix-p2-audit-20260719` | `647dd6a1c4fe418e23cd566bc717067e57f91178` | CI babysit: merge conflicts + GitGuardian + PR policy | FIXED. Merged origin/main (~790 behind, 33 content conflicts). Preferred main for superseded remediations (secret scanner masking, babel parser 8, RAG module layout, coalesce abort, join-constructed offline DB URL). Retained unique clinical-search/neuroleptic+clozapine monitoring, sheet focus-trap, Playwright serviceWorkers block, and aligned regression tests to current main APIs/alias tiering. Restored GitGuardian-safe DB URL construction (literal postgres URI was a tip regression). PR body updated for Clinical Governance + RAG impact. | Focused Vitest 218/218 on unique delta; merge-tree clean vs origin/main after sync; no provider-backed checks. | +| 2026-07-28 | `codex/fix-p2-audit-20260719` | `d99a71b82abf605f26fcc81ba61cdc805a99a36f` | Bugbot-style unique product delta vs origin/main (playwright SW block, ClinicalDashboard focus drop, sheet Tab trap, clinical-search neuroleptic/clozapine/med-dose, rag-retrieval-variants, supporting tests) | CHANGES REQUESTED. No P0. P1: `medicationDoseQueryContext` named-medication gate requires canonical generic token in evidence (`evidenceTokens.has("clozapine")`) and ignores brand aliases, so Clozaril-only evidence fails for Clozaril/clozapine monitoring queries and can rank below unrelated high-hybrid monitoring docs (−0.24 / missed +0.26). P2: neuroleptic side-effects early `document_lookup` return preempts dose classification (`What dose applies for neuroleptic side effect management?` → `document_lookup`). Cleared: SW block + PWA allow, documents `focus:true` removal on in-place pushState ask path, clozapine blood-token retention, Clozaril→clozapine variant intent via analysis.medications. Highest residual: sheet Tab trap rewrite has no Tab-cycle DOM proof. | Offline red proofs via temporary Vitest probes (brand gate + neuroleptic class); focused clinical-search regressions 6/6; no OpenAI/Supabase/hosted CI. | +| 2026-07-28 | PR #1298 / `codex/fix-p2-audit-20260719` | `a51954ed7db4626a4523ddb53d111742ef6a45ae` | Bugbot triage of unique delta vs main | FIXED P1: medicationDoseQueryContext + clozapine-specific boost/penalty now accept brand aliases (Clozaril evidence ranks above unrelated monitoring for clozapine queries). FIXED P2: neuroleptic side-effect title short-circuit runs after explicit dose/route classification. Cleared: sheet trap, documents focus drop, Playwright serviceWorkers block. | clinical-search Vitest 69/69; unique-delta Vitest 219/219; no provider-backed checks. | +| 2026-07-28 | PR #1298 / `codex/fix-p2-audit-20260719` | `d81c55b23815948a7043333ad4f56c09ec107c4f` | CodeRabbit thread fixes + PR policy body sync | FIXED: duplicate serviceWorkers key; sheet focus trap excludes aria-hidden/inert ancestors; WCC in clozapine blood-intent gate; formulation Open Worry click-once outside toPass; PR_POLICY_BODY.md added for Sync PR policy body (token cannot edit non-agent-managed description). | retrieval-query-variants + playwright-isolation Vitest pass; local pr-policy evaluate ok; no provider checks. | +| 2026-07-28 | PR #1298 / `cursor/fix-p2-audit-clean-9957` | `986ffd28d493c8daf7d900bc65a3cdab3aca496e` | Clean rebuild onto main for secret-scanner history | Rebuilt unique product delta onto origin/main as a single clean commit so Gitleaks/GitGuardian no longer scan historical false-positive fixtures (offline postgres URI, sb_secret_ test key). Product behaviour unchanged from prior tip. | patch apply clean; prior focused Vitest green; no provider checks. | +| 2026-07-28 | PR #1298 / `codex/fix-p2-audit-20260719` | `43795bcb00a55961b734813e78f74aef933beea3` | Closeout after clean rebuild + policy sync | MERGEABLE. Secret scanners green after history rebuild; PR policy green with Clinical Governance + RAG impact; 0 unresolved review threads (CodeRabbit + Codex P1 resolved). Unique delta retained. Residual: required human approving review / remaining hosted suite. | PR policy PASS; GitGuardian PASS; Gitleaks PASS on prior tip; focused Vitest 189/189 on clean rebuild; no provider checks. | +| 2026-07-28 | PR #1298 / `codex/fix-p2-audit-20260719` | `c89756f89d61730e926b35c4e5152e087650f440` | CI babysit: Build RAM guard + escalation class + alias scope | FIXED. Unit coverage: removed neuroleptic document_lookup short-circuit that broke title-supported escalation rescue (medication_dose_risk + escalation_risk). Build: CI/GITHUB_ACTIONS warn-and-continue under <10 GiB reported RAM. CodeRabbit: medicationDoseQueryContext alias equivalence is per named medication; multi-med regression added; Prefered typo fixed. | Focused Vitest clinical-search + escalation-rescue + guard-next-build 79/79; tip `c89756f8`; no provider checks. | +| 2026-07-28 | PR #1298 / `codex/fix-p2-audit-20260719` | `7f75c39c153394a89969122693b572376353b9af` | CI babysit tip (format + ledger marker) | Supersedes prior #1298 CI babysit row at `c89756f8` for exact-head bookkeeping after Prettier on clinical-search and ledger tip-marker repair. Product delta unchanged. | check:branch-review-ledger pending; tip `7f75c39c`; no provider checks. | +| 2026-07-28 | PR #1298 / `codex/fix-p2-audit-20260719` | `f8d4d17bac65c17290b634e5c04bdd76e6d58a07` | CI babysit closeout tip | Exact HEAD after Build RAM CI bypass, escalation-class restore, per-medication alias scoping, Prettier, and review-thread resolution. Unresolved review threads: 0. Residual: hosted CI on this tip + human approving review. | Focused Vitest 79/79 earlier; check:branch-review-ledger PASS; tip `f8d4d17b`; no provider checks. | +| 2026-07-28 | PR #1298 / `codex/fix-p2-audit-20260719` | `dc472567ab0be7c404d515f9a2be8f1fdc377e3e` | Exact tip after Bugbot trigger post | Docs-only exact-head row after posting `@cursor review` via ManagePullRequest. Product delta unchanged from `c89756f8`/`6f06b845`. | tip `dc472567`; unresolved threads 0; no provider checks. | | 2026-07-28 | PR #1295 / `fix/audit-remediation-from-main` | `11585678d28a9f399217429972e528b89b7f2466` | CI fix + main sync + Bugbot | FIXED. Unit coverage failed because therapy-compass contract still asserted `lg:grid-cols-[repeat(auto-fit,minmax(15rem,1fr))]` after intentional `sm:` breakpoint change in mode-home-template. Updated contract to `sm:`. GitHub CONFLICTING/DIRTY was stale base (30 behind); merge-tree clean; merged origin/main (ledger union). Bugbot: zero cursor[bot] review findings/threads. No unresolved review comments to resolve. | Focused vitest therapy-compass-responsive-contract 10/10; merge origin/main CLEAN; no provider-backed checks. | | 2026-07-28 | PR #1295 / `fix/audit-remediation-from-main` | `5714bf6ceb9d85e18e895b34ec71dcca64837797` | Separator pairing follow-up after sm grid | FIXED. Coherent follow-up to the sm:grid-cols auto-fit change: stack separators are now `max-sm:border-t` (was unconditional `border-t`), matching the phone-only stack and avoiding double borders once `lg:border` card chrome applies. Contract asserts sm grid + max-sm separator and rejects stale lg grid token. | Focused vitest therapy-compass-responsive-contract 10/10; verify:cheap PASS (405 files / 4114 passed); merge-tree CLEAN; Bugbot 0 findings; no provider checks. | | 2026-07-28 | PR #1295 / `fix/audit-remediation-from-main` | `862be5a843708360ad0d67239429d1d09405e570` | Codex P1: Playwright matrix browser install | FIXED. Cross-browser `playwright.yml` stopped using chromium-only `setup-ui-e2e`; installs `matrix.project` + deps with per-browser cache. Also dispositioned the Codex P1 about the responsive contract (already fixed earlier on tip). | check:github-actions PASS; focused vitest therapy-compass 10/10; no provider checks. | @@ -1165,6 +1175,8 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-28 | PR #1307 / `claude/rag-019-fallback-guard` | `2e5edfc6c9fcc0bb75674b179607888bbf872b91` | PR policy body synced + template removed | Sync PR policy body SUCCESS applied Clinical Governance Preflight (7/7). Deleted temporary `PR_POLICY_BODY.md`. Awaiting Build/PR policy/PR required on this tip. | Hosted Sync SUCCESS; no provider checks. | | 2026-07-28 | PR #1294 / `execute-typography-fixes-clean-2` | `a0df13f45cffb769b852e55bc44b6891b7fd80e7` | Main conflict resolve + CodeRabbit | FIXED. Merged #1307; took main ALLOW_LOW_RAM_BUILD RAM-guard (dropped DOCKER_BUILD approach). Tightened answer-evidence heading contract to component-scoped bodies (rejects sibling h2). Codex P2 already resolved. | Vitest heading+guard 4/4; merge-tree CLEAN; no provider-backed checks. | | 2026-07-28 | PR #1309 / `claude/gates-skill` | `7dfe103bfa408052c9e899211b8373c7ccb708d3` | Conflict sync + Codex/CodeRabbit + Bugbot | FIXED. GitHub CONFLICTING/DIRTY was main-staleness only (`merge-tree` clean); merged `origin/main`. Codex P2: skill wrongly claimed `verify:ui` exits 0 under heavy-lock contention — corrected to 15m queue then exit 1 via `run-playwright.mjs`; mirrored in AGENTS.md. CodeRabbit: marked `${PIPESTATUS[0]}` as Bash-specific. Bugbot: zero `cursor[bot]` findings; confirmed same P2. No CI failures on prior tip. | `prettier --check` PASS; `docs:check-links` 1287 PASS; no provider-backed checks. | +| 2026-07-28 | PR #1298 / `codex/fix-p2-audit-20260719` | `111aee5f5d1c6aadf054632148f48dcea06626b2` | merge main + adopt main RAM-guard | Merged origin/main (#1309). Resolved guard/Dockerfile conflicts by taking main's evaluateNextBuildRamGuard + ALLOW_LOW_RAM_BUILD Docker path. Prior tip Unit/Build green; unique product delta retained (clinical-search aliases/escalation, sheet trap, Playwright SW block). | Focused Vitest 81/81; tip `111aee5f`; no provider checks. | +| 2026-07-28 | PR #1298 / `codex/fix-p2-audit-20260719` | `4de7ec8901b555f11badc8d08c6b57cdf88c386e` | CI green closeout after main merge | MERGE-READY for required checks. Hosted PR required / Build / Unit / Production UI / Static / Safety / PR policy / Semgrep / Gitleaks / GitGuardian PASS. Unresolved review threads: 0. Bugbot requested via `@cursor review`. Unique delta vs main: clinical-search (brand aliases, escalation class, neuroleptic query anchor, clozapine blood tokens), sheet Tab trap, Playwright serviceWorkers block, retrieval-variants WCC, formulation UI flake, supporting tests. Residual: human approving review. | Hosted required checks PASS on `4de7ec89`; no provider-backed app checks. | | 2026-07-28 | PR #1296 / `css-layout-audit-complete` | `060d81355b97c3ba51232df8feee6132f1036b63` | Final closeout: conflicts + reviews + CI green | COMPLETED. Merged main (adopted main RAM-guard). CodeRabbit intrinsic-size + Codex will-change/transform threads resolved. Local Bugbot: no P0/P1. Hosted PR required SUCCESS (Build/Unit/Static/Advisory/Production UI). mergeable CLEAN. | Hosted CI run 30330463512 SUCCESS; local vitest 4114 + focused guard/nav/container 18; no provider checks. | | 2026-07-28 | PR #1294 / `execute-typography-fixes-clean-2` | `62ddd24dc8ad223cde67373ea35e18aee6065057` | CI green closeout | APPROVE. Hosted Production UI + PR required PASS on product tip `e5543dc6`. Codex/CodeRabbit threads resolved (0 open). Unique delta: diagnosis-detail S: locator + heading hierarchy contract. RAM-guard owned by main #1307. | Hosted Static/Unit/Safety/Advisory/Production UI/PR required PASS; Build/Container skipped (unchanged); Bugbot clean; no provider-backed checks. | | 2026-07-28 | PR #1294 / `execute-typography-fixes-clean-2` | `f64fa84a8010008917619c16aac79e4f172a70ff` | Ledger dedupe after main sync | Removed 2 exact duplicate #1307 rows introduced by merge=union during main sync (kept first copies). Hosted required checks green on prior product tip `e5543dc6`; this tip is ledger hygiene + docs-only main sync. | `check:branch-review-ledger` PASS after dedupe; no provider-backed checks. | @@ -1188,6 +1200,7 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-28 | PR #1304 / `fix-test-run-lock` | `2abe39506f9f0ceaf8cf638bfa2b6dc37dc0ed2c` | CI babysit: resync main | FIXED. After green PR required on `f7d86c27`, main advanced by 1 commit (#1305); GitHub DIRTY again but `git merge-tree` CLEAN. Merged origin/main. No product conflicts; unique delta still knip.json (+ ledger). | merge-tree CLEAN; hosted PR required SUCCESS on prior tip; no provider-backed checks. | | 2026-07-28 | PR #1304 / `fix-test-run-lock` | `463e5c0adc77fe722e20376666f5991db3e288d9` | CI babysit closeout | MERGE-READY. Hosted PR required SUCCESS on exact tip; mergeable=MERGEABLE; 0 behind main; merge-tree CLEAN. Unique product delta: knip.json removes unused tailwindcss ignoreDependencies. Prior GitHub DIRTY labels during babysit were main-churn only. | Hosted CI run success on 463e5c0a; no provider-backed checks. | | 2026-07-28 | PR #1304 / fix-test-run-lock | 7cc32c053c752bef19f3de408a1376428e54af74 | CI babysit: sync main | SUPERSEDED (documenting stale-CI ledger error). Prior row for this HEAD incorrectly treated hosted required-CI SUCCESS on earlier tip e6b826ed9150f312c2e7a957f715019e73a7f0be as verification of this later merge commit 7cc32c05. No hosted required-CI result exists for this exact SHA. This ref has since advanced; the later row at 463e5c0adc77fe722e20376666f5991db3e288d9 recorded exact-tip hosted CI SUCCESS, so this commit's status is historical/superseded. | No hosted CI run on this exact HEAD; prior row reused results from e6b826ed; corrective ledger entry only. | +| 2026-07-28 | PR-1298 | de14ee2c45cbd0cb5a3b366febef70bcc2ea245e | PR #1298 full diff vs origin/main | BLOCKED: protected RAG behaviour change lacks required live baseline-to-post canary | Local diff review found no additional high-confidence P0-P2 defect; prior exact-head PR required passed; offline Vitest is insufficient for ranking trust; no provider-backed canary run | | 2026-07-28 | PR #1316 / `claude/top-search-design-mockups-w53znc` | `8ccd7f481819ae4b41352acf9d867b2b850696be` | CI/review closeout: remaining band review gaps | FIXED. Prior Production UI failure on older tip was Suspense duplicate `global-search-input` (addressed earlier). Tip closes 7 unresolved review threads: favourites partial-status + refetch, differentials unauthorized copy, docs typography, forced-colors adoption gate, forms/loading control suppression confirmation. Merge-tree clean vs main; hosted CI rerunning on this head. | Focused vitest 38/38; tsc + eslint on touched files PASS; no Bugbot MCP available in this environment; no provider-backed checks. | | 2026-07-28 | claude/top-search-design-mockups-w53znc | af07e34b5e6ca958206926a05509c1e321dbe862 | bugbot SearchResultsHeaderBand favourites status | P1: favourites status override under-reports registry faults when any items exist; empty/filter guards use overridden status; registryStatus unused. P2: demo prototype merge still over-faults band. No code change. | static review of band/favourites/diff call sites; offline fold proof; PR thread context; no provider/CI | | 2026-07-28 | PR #1316 / `claude/top-search-design-mockups-w53znc` | `1c65a083e8307f108774b0c3a3fb96559c42ee0d` | CI/review closeout complete | READY FOR HOSTED CI. All review threads resolved. Account-favourites pending/failure folded into band status; remaining Codex/CodeRabbit gaps closed; Bugbot residual noted (binary band cannot express partial source failure without a dedicated `partial` status). Merge-tree was clean vs main at prior tip; CI rerunning on this head. | Focused vitest 43/43; tsc/eslint PASS on touched files; Bugbot via pr-bugbot subagent (no MCP Bugbot server); no provider-backed checks. | @@ -1201,6 +1214,7 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-28 | PR #1316 / `claude/top-search-design-mockups-w53znc` | `7b968d695c4545e1677c2e7f136172ef686d0012` | CI/review closeout: loadError split + adoption mode homes | FIXED new Codex P2s. Separated account loadError from mutation error; expanded band adoption to mode href pages + 2-hop reach; prior #024/favourites-counts/therapy-retry threads already resolved. Merge-tree clean vs main (0 behind). Bugbot earlier pass had no P0/P1 on prior WIP. | vitest favourites-account-retry + adoption + hub (10); typecheck; full suite 4232/4 prior tip | | 2026-07-28 | PR #1296 / `css-layout-audit-complete` | `84d846d8d0d168ca2babcc6d699e0a88bb0379c0` | Inspect closeout: sync main + forced-colors scope | FIXED. GitHub CONFLICTING was unpushed main sync (local merge-tree CLEAN, 3 behind on remote tip). Pushed merge. Bugbot P2: removed broad forced-colors `!important` wipe on `.edge-glass-header`/`[aria-selected=true]`/`.surface-raised` (token remap retained; header Canvas fill already earlier). Mockup board `z-[2147483647]` → ladder `z-[100]`. Prior CodeRabbit/Codex threads remain resolved. | lint/typecheck/format:check PASS; vitest 4197; local build PASS; no provider checks. | | 2026-07-28 | PR #1296 / `css-layout-audit-complete` | `f7c34fd7` | Sync main #1297 CSS/motion audit | FIXED. GitHub CONFLICTING after main landed #1297; `git merge origin/main` clean (globals.css + ledger auto-merge). Retained content-auto, scoped forced-colors token remap, mockup z-[100]. Prior tip hosted PR required SUCCESS. | merge-tree CLEAN; focused nav test PASS; no provider checks. | +| 2026-07-28 | PR-1298 | 56536a4d00a5fc799025522d2dbe98377721837e | PR #1298 final remediation vs current origin/main | APPROVE after exact-head CI; unvalidated retrieval behaviour removed, remaining changes are UI/test hardening | Protected clinical-search and retrieval-variant production files match origin/main byte-for-byte; merge-tree clean; ledger guard PASS; diff check PASS; verify:pr-local dry-run selected full local gate; local execution unavailable because node_modules is absent; RAG impact no retrieval behaviour change | | 2026-07-28 | claude/navigation-pane-mockups-0600af | 8fb9867483104a5cc89eec5cfb512e1ca8718029 | PR #1311 CI/review fix | Fixed maintainability budget (DocumentViewer extract), sticky-header anchors/rail, lg-only section card, section reading order + non-collapsible source-text; dispositioned CodeRabbit mockup wiring as exempt; 0 unresolved threads; Bugbot none | verify:cheap PASS (419 files/4256 tests); maintainability 1633/1734; vitest section+account-access; eslint/typecheck; sitemap:check; Bugbot none | | 2026-07-28 | claude/navigation-pane-mockups-0600af | 29372bb5a53df26902bef53f8a1cb5dd4be5b239 | PR #1311 CI/review fix | Supersedes prior head: Prettier format:check was the remaining Static PR / CircleCI blocker; formatted 8 files. Product fixes unchanged; 0 unresolved threads. | format:check PASS; maintainability budgets; prior verify:cheap retained | | 2026-07-28 | codex/consolidate-platform-reliability | aa178d6465ff9aeb92b02766f4accff522c0f8a8 | dirty-work consolidation review | APPROVE. Retained reproducible npm-cache installs, explicit dev dependency installs, toolchain parity coverage, and corrected ops preflight wording. Rejected contaminated image work, fail-open audit behavior, duplicated assets, visual-regression machinery, and the unsafe primary-checkout stale-lease recovery. | git diff --check; focused Vitest 8/8; check:github-actions; check:installed-lock-parity; verify:cheap PASS (412 files, 4199 passed, 3 skipped); no provider checks. | diff --git a/playwright.config.ts b/playwright.config.ts index d97128b49..89849ea24 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -55,7 +55,8 @@ export default defineConfig({ // claims the page, and serves every subsequent navigation — bypassing route // interception for navigations outright, and wedging Playwright-Firefox's // reload path under an active route (the two ui-smoke reload hangs in matrix - // run 4012). Only ui-pwa.spec.ts is meant to exercise the worker; it opts + // run 4012). Page routes also cannot intercept requests made by a controlling + // service worker. Only ui-pwa.spec.ts is meant to exercise the worker; it opts // back in with test.use({ serviceWorkers: "allow" }). serviceWorkers: "block", }, diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx index 1940ecc29..98aabf419 100644 --- a/src/components/ClinicalDashboard.tsx +++ b/src/components/ClinicalDashboard.tsx @@ -2249,7 +2249,6 @@ export function ClinicalDashboard({ "", documentsSearchHref({ query: trimmedQuery, - focus: true, run: true, ...navigationContext, }), diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx index 8fa9b4497..c6409c5ff 100644 --- a/src/components/ui/sheet.tsx +++ b/src/components/ui/sheet.tsx @@ -215,21 +215,32 @@ export function Sheet({ // options) do not dump every inactive item into the Tab cycle. 'a[href], button:not([disabled]):not([tabindex="-1"]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), summary, [tabindex]:not([tabindex="-1"])', ) ?? [], - ).filter((element) => !element.hasAttribute("disabled") && element.getAttribute("aria-hidden") !== "true"); + ).filter( + (element) => + !element.hasAttribute("disabled") && + element.getAttribute("aria-hidden") !== "true" && + element.tabIndex >= 0 && + !element.closest('[aria-hidden="true"], [inert]') && + element.getClientRects().length > 0, + ); if (focusable.length === 0) return; - const first = focusable[0]; - const last = focusable[focusable.length - 1]; - if (panelRef.current && !panelRef.current.contains(document.activeElement)) { - event.preventDefault(); - (event.shiftKey ? last : first).focus(); - } else if (event.shiftKey && document.activeElement === first) { - event.preventDefault(); - last.focus(); - } else if (!event.shiftKey && document.activeElement === last) { - event.preventDefault(); - first.focus(); - } + const activeElement = document.activeElement instanceof HTMLElement ? document.activeElement : null; + const currentIndex = activeElement ? focusable.indexOf(activeElement) : -1; + const nextIndex = + currentIndex === -1 + ? event.shiftKey + ? focusable.length - 1 + : 0 + : event.shiftKey + ? (currentIndex - 1 + focusable.length) % focusable.length + : (currentIndex + 1) % focusable.length; + + // Move focus explicitly instead of relying on platform Tab preferences. + // Firefox can otherwise leave programmatically focused buttons out of the + // native sequence, which makes the modal trap inconsistent by browser. + event.preventDefault(); + focusable[nextIndex].focus(); } window.addEventListener("keydown", onKeyDown); diff --git a/tests/eval-retrieval.test.ts b/tests/eval-retrieval.test.ts index f1e80edf3..671ec7638 100644 --- a/tests/eval-retrieval.test.ts +++ b/tests/eval-retrieval.test.ts @@ -462,6 +462,56 @@ describe("golden retrieval eval helpers", () => { expect(evaluated.failures).toEqual([]); }); + it("recognizes current safety-plan and alcohol-withdrawal titles", () => { + const safetyPlan = evaluateGoldenRetrievalCase({ + testCase: { + id: "safety-plan-title", + query: "What should a patient safety plan include?", + expectedQueryClass: "document_lookup", + expectedDocumentSubstrings: ["PtSafetyPlan"], + expectedContentTerms: ["safety", "plan"], + topK: 8, + expectTableEvidence: false, + }, + results: [ + result({ + // Strict golden-eval aliases only accept "Patient Safety Plan" for PtSafetyPlan + // (see scripts/lib/clinical-aliases.ts tiering note). + title: "Patient Safety Plan Policy and Procedure (RKPG)", + file_name: "Patient Safety Plan Policy and Procedure (RKPG).pdf", + content: "A safety plan records agreed actions.", + }), + ], + telemetry: { query_class: "document_lookup", retrieval_strategy: "text_fast_path" }, + latencyMs: 10, + }); + const alcoholWithdrawal = evaluateGoldenRetrievalCase({ + testCase: { + id: "ciwa-title", + query: "What CIWA-Ar score threshold requires drug treatment in alcohol withdrawal?", + expectedQueryClass: "table_threshold", + expectedDocumentSubstrings: ["Alcohol withdrawal"], + expectedContentTerms: ["alcohol", "withdrawal", ["ciwa", "score", "threshold"]], + topK: 12, + expectTableEvidence: false, + }, + results: [ + result({ + // Document substring matching uses title/file/section path only (not body + // content), so the fixture title must carry the pinned phrase. + title: "Alcohol Withdrawal - Addiction, Toxicity and Withdrawal", + file_name: "Alcohol Withdrawal - Addiction, Toxicity and Withdrawal.pdf", + content: "Use the CIWA-Ar treatment table for alcohol withdrawal.", + }), + ], + telemetry: { query_class: "table_threshold", retrieval_strategy: "text_fast_path" }, + latencyMs: 10, + }); + + expect(safetyPlan.failures).toEqual([]); + expect(alcoholWithdrawal.failures).toEqual([]); + }); + it("reports failed cases with top result summaries", () => { const evaluated = evaluateGoldenRetrievalCase({ testCase: { diff --git a/tests/eval-utils.test.ts b/tests/eval-utils.test.ts index bad92e525..01c63c7f8 100644 --- a/tests/eval-utils.test.ts +++ b/tests/eval-utils.test.ts @@ -54,6 +54,30 @@ describe("RAG eval source identity matching", () => { expect(coverage.missingFiles).toEqual(["MHSP.Discharge.pdf"]); }); + it("maps legacy community-admission expectations to current combined policies", () => { + const coverage = expectedFileCoverage( + ["MHSP.AdmissionCommunityPts.pdf"], + [ + { + title: "Admission to Discharge for Community Mental Health", + file_name: "Admission to Discharge for Community Mental Health (NMHS).pdf", + }, + { + title: "Referral, Admission and Discharge - Mental Health Hospital in the Home", + file_name: + "Referral, Admission and Discharge - Mental Health Hospital in the Home (MHHITH) Policy and Procedure (RKPG).pdf", + }, + ], + 5, + ); + + expect(coverage).toMatchObject({ + matchedFiles: ["MHSP.AdmissionCommunityPts.pdf"], + missingFiles: [], + allHit: true, + }); + }); + it("fails supported clinical eval cases when numeric faithfulness warnings are present", () => { const testCase: RagEvalCase = { id: "dose-warning", diff --git a/tests/playwright-project-isolation.test.ts b/tests/playwright-project-isolation.test.ts index 64f81434d..5467c218d 100644 --- a/tests/playwright-project-isolation.test.ts +++ b/tests/playwright-project-isolation.test.ts @@ -14,4 +14,12 @@ describe("Playwright production-project isolation", () => { expect(source).toMatch(/name: ["']chromium-mockups["'],\s+testMatch: mockupSpecPattern,\s+grep: mockupTag,/m); }); + + it("blocks service workers for mocked journeys but allows the dedicated PWA suite", () => { + const config = readFileSync(resolve(process.cwd(), "playwright.config.ts"), "utf8"); + const pwaSpec = readFileSync(resolve(process.cwd(), "tests/ui-pwa.spec.ts"), "utf8"); + + expect(config).toContain('serviceWorkers: "block"'); + expect(pwaSpec).toContain('test.use({ serviceWorkers: "allow" })'); + }); }); diff --git a/tests/rag-route-budget.test.ts b/tests/rag-route-budget.test.ts index 739be844b..b9e4f5701 100644 --- a/tests/rag-route-budget.test.ts +++ b/tests/rag-route-budget.test.ts @@ -31,8 +31,10 @@ describe("RAG route deadlines", () => { const deadline = createAnswerRouteDeadline({ routeMode: "fast", startedAt }); expect(deadline.requestTimeoutMs(30_000)).toBe(15_000); + expect(deadline.generationRequestTimeoutMs(30_000)).toBe(13_000); await vi.advanceTimersByTimeAsync(10_000); expect(deadline.requestTimeoutMs(30_000)).toBe(5_000); + expect(deadline.generationRequestTimeoutMs(30_000)).toBe(3_000); const pending = deadline.race(new Promise(() => undefined)); const rejection = expect(pending).rejects.toBeInstanceOf(AnswerRouteDeadlineExceededError); diff --git a/tests/sheet-focus.dom.test.tsx b/tests/sheet-focus.dom.test.tsx index 3380e4336..f34d122a9 100644 --- a/tests/sheet-focus.dom.test.tsx +++ b/tests/sheet-focus.dom.test.tsx @@ -1,6 +1,6 @@ import { act, render, waitFor } from "@testing-library/react"; import { useEffect, useState } from "react"; -import { afterEach, describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { Sheet } from "@/components/ui/sheet"; import { @@ -11,6 +11,7 @@ import { } from "@/components/ui/sheet-focus"; afterEach(() => { + vi.restoreAllMocks(); if (typeof document !== "undefined" && document.body) { document.body.style.overflow = ""; } @@ -255,3 +256,41 @@ describe("Sheet open focus", () => { background.remove(); }); }); + +describe("Sheet Tab cycle", () => { + it("skips visible controls explicitly removed from the tab order", async () => { + vi.spyOn(HTMLElement.prototype, "getClientRects").mockReturnValue({ + length: 1, + item: () => null, + [Symbol.iterator]: function* () { + yield {} as DOMRect; + }, + } as DOMRectList); + + render( + {}} title="Tab order" portal> + First + + + , + ); + + const panel = panelOf("Tab order"); + const first = panel.querySelector('a[href="#first"]'); + const excluded = panel.querySelector('input[tabindex="-1"]'); + const last = Array.from(panel.querySelectorAll("button")).find( + (button) => button.textContent === "Last", + ); + expect(first).not.toBeNull(); + expect(excluded).not.toBeNull(); + expect(last).toBeDefined(); + + act(() => { + first?.focus(); + window.dispatchEvent(new KeyboardEvent("keydown", { key: "Tab", bubbles: true, cancelable: true })); + }); + + expect(document.activeElement).toBe(last); + expect(document.activeElement).not.toBe(excluded); + }); +}); diff --git a/tests/ui-formulation.spec.ts b/tests/ui-formulation.spec.ts index fb12bfc26..2702b9bb5 100644 --- a/tests/ui-formulation.spec.ts +++ b/tests/ui-formulation.spec.ts @@ -111,7 +111,9 @@ test("keeps mobile search, domain filtering, record actions, and universal chrom await expectNoHorizontalOverflow(page); await page.getByRole("link", { name: "Open Worry" }).click(); - await expect(page).toHaveURL(/\/formulation\/worry$/, { timeout: 30_000 }); + await expect(async () => { + await expect(page).toHaveURL(/\/formulation\/worry$/); + }).toPass({ timeout: 30_000 }); await expect(page.getByRole("heading", { name: "Worry", exact: true })).toBeVisible({ timeout: 30_000 }); await expect(page.getByRole("link", { name: "Compare", exact: true }).last()).toBeVisible(); await expect(page.getByRole("link", { name: "Use in formulation", exact: true }).first()).toBeVisible(); diff --git a/tests/ui-tools.spec.ts b/tests/ui-tools.spec.ts index 37ea6d2ee..3b2d8d154 100644 --- a/tests/ui-tools.spec.ts +++ b/tests/ui-tools.spec.ts @@ -2376,7 +2376,9 @@ test.describe("Responsive layout guards", () => { await page.goto("/safety-plan"); await expect(page.getByLabel(/Patient \(name or initials\)/i)).toHaveCount(0); - await expect(page.getByText(/kept only in this browser tab/i)).toBeVisible(); + const privacyRegion = page.getByRole("region", { name: "Safety plan privacy" }); + await expect(privacyRegion).toHaveCount(1); + await expect(privacyRegion.getByText(/kept only in this browser tab/i)).toBeVisible(); await expect( page.getByText(/Copying, printing, or saving a PDF moves the plan outside Clinical KB/i), ).toBeVisible();