From 880fa0e9bdfafa61f95137b61b9f3bd52452ecd1 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 9 Aug 2026 16:05:27 +0000 Subject: [PATCH 1/3] fix: honor restoreFocusUnlessMoved on same-mode reselect PR #1790 landed with a force-focus fallback that could override deliberate focus moves after the mode menu closed. Keep only restoreFocusUnlessMoved and cover the no-steal path with a DOM test. Records the #1790 babysit ledger row. Co-authored-by: BigSimmo --- docs/branch-review-ledger.md | 1 + .../master-search-header.tsx | 4 +-- tests/mode-menu-prefetch.dom.test.tsx | 29 +++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index 171e63bcdb..2a59976b1c 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -855,3 +855,4 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-08-09 | PR #1782 / cursor/fix-document-open-scroll-e5bf | 5709f2cc7a954197e02107c96d7896d8d13445c3 | document-viewer open-at-top | ship: remove chunk mount scrollIntoView so document opens stay at overview top | document-viewer-shell.dom 7 pass; document-section-summary.dom 8 pass; verify:pr-local dry-run | | 2026-08-09 | cursor/fix-document-open-scroll-e5bf (PR #1782) | 98029875db7d640d3e699829249bb33892296bff | PR #1782 unblock | before: static-pr+coverage failed on stale adoption-manifest (document-viewer-shell testFiles drift), merge-tree clean 0 behind, auto-merge armed, 1 advisory CodeRabbit waitFor thread; after: regenerated adoption-manifest, hardened scroll negative assertion, pre-commit+handoff adoption sync to prevent recurrence; CodeRabbit dispositioned as fixed by sync assert | check:design-system-adoption PASS; vitest design-system-adoption+document-viewer-shell+docs-inventory 63/63 PASS; format; no provider-backed checks | | 2026-08-09 | cursor/fix-document-open-scroll-e5bf (PR #1782) | 86698228533ebe10452c10c1bd7a3e1610d891ae | PR #1782 unblock | merged origin/main (behind-but-clean); fixed static-pr TS2322 on document-viewer-shell chunk fixture; fixed Production UI DSM compare remove stall via location.assign + DOM proof; prior adoption-manifest drift already fixed | tsc clean for changed files; vitest document-viewer-shell+dsm-compare-remove+design-system-adoption 59/59 PASS; check:design-system-adoption PASS; format; no provider-backed checks | +| 2026-08-09 | codex/chat-mode-home-copy-9d76 | 1d32ce6f0a9f580eef55363de17e15723ae8d898 | PR #1790 babysit | MERGED via squash auto-merge as d812c769; same-mode focus fixed; Copilot aria dispositioned (drawer still Clinical Guide); CodeRabbit focus-steal follow-up in cursor/same-mode-focus-no-steal-6df8; reply API unavailable | PR required PASS; Production UI shards PASS; unit mode-menu-prefetch PASS | diff --git a/src/components/clinical-dashboard/master-search-header.tsx b/src/components/clinical-dashboard/master-search-header.tsx index d76266e2d2..4921bf8ab8 100644 --- a/src/components/clinical-dashboard/master-search-header.tsx +++ b/src/components/clinical-dashboard/master-search-header.tsx @@ -866,9 +866,7 @@ export function MasterSearchHeader({ window.setTimeout(restoreSameModeFocus, 50); return; } - if (!restoreFocusUnlessMoved(modeButtonRef.current)) { - modeButtonRef.current?.focus({ preventScroll: true }); - } + restoreFocusUnlessMoved(modeButtonRef.current); pendingModeSelectionFocusRef.current = null; }; window.requestAnimationFrame(() => { diff --git a/tests/mode-menu-prefetch.dom.test.tsx b/tests/mode-menu-prefetch.dom.test.tsx index 242b243347..44cd923e53 100644 --- a/tests/mode-menu-prefetch.dom.test.tsx +++ b/tests/mode-menu-prefetch.dom.test.tsx @@ -167,4 +167,33 @@ describe("mode menu destination prefetch", () => { expect(trigger).toHaveFocus(); }); }); + + it("does not steal focus when the user moves elsewhere during same-mode restore", async () => { + const user = userEvent.setup(); + render( + <> + + + , + ); + + const trigger = screen.getByRole("button", { name: /Mode Answer/i }); + await user.click(trigger); + const answerOption = within(await screen.findByRole("menu", { name: "Choose app mode" })).getByRole( + "menuitemradio", + { name: /Answer/i }, + ); + await user.click(answerOption); + + const outside = screen.getByRole("button", { name: "Outside control" }); + outside.focus(); + await vi.waitFor(() => { + expect(outside).toHaveFocus(); + }); + // Deferred same-mode restore must honor restoreFocusUnlessMoved and leave + // deliberately moved focus alone. + await new Promise((resolve) => setTimeout(resolve, 120)); + expect(outside).toHaveFocus(); + expect(trigger).not.toHaveFocus(); + }); }); From 817f3c2f79aedccb39f91013e48e681dfbd607e1 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 10 Aug 2026 10:41:24 +0000 Subject: [PATCH 2/3] fix(ci): drop deprecated baseUrl from isolated Playwright tsconfigs Next 16.3 surfaces TS5101 when the Playwright/Lighthouse run-root tsconfig still injects baseUrl. Resolve @/* with root-relative paths instead so Production UI critical can typecheck again after the main sync. --- docs/branch-review-ledger.md | 1 + scripts/run-lighthouse-budget.mjs | 3 ++- scripts/run-playwright.mjs | 4 ++-- tests/check-lighthouse-budget.test.ts | 8 ++++++++ tests/test-runner-safety.test.ts | 4 ++++ 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index 2a59976b1c..615daf101c 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -856,3 +856,4 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-08-09 | cursor/fix-document-open-scroll-e5bf (PR #1782) | 98029875db7d640d3e699829249bb33892296bff | PR #1782 unblock | before: static-pr+coverage failed on stale adoption-manifest (document-viewer-shell testFiles drift), merge-tree clean 0 behind, auto-merge armed, 1 advisory CodeRabbit waitFor thread; after: regenerated adoption-manifest, hardened scroll negative assertion, pre-commit+handoff adoption sync to prevent recurrence; CodeRabbit dispositioned as fixed by sync assert | check:design-system-adoption PASS; vitest design-system-adoption+document-viewer-shell+docs-inventory 63/63 PASS; format; no provider-backed checks | | 2026-08-09 | cursor/fix-document-open-scroll-e5bf (PR #1782) | 86698228533ebe10452c10c1bd7a3e1610d891ae | PR #1782 unblock | merged origin/main (behind-but-clean); fixed static-pr TS2322 on document-viewer-shell chunk fixture; fixed Production UI DSM compare remove stall via location.assign + DOM proof; prior adoption-manifest drift already fixed | tsc clean for changed files; vitest document-viewer-shell+dsm-compare-remove+design-system-adoption 59/59 PASS; check:design-system-adoption PASS; format; no provider-backed checks | | 2026-08-09 | codex/chat-mode-home-copy-9d76 | 1d32ce6f0a9f580eef55363de17e15723ae8d898 | PR #1790 babysit | MERGED via squash auto-merge as d812c769; same-mode focus fixed; Copilot aria dispositioned (drawer still Clinical Guide); CodeRabbit focus-steal follow-up in cursor/same-mode-focus-no-steal-6df8; reply API unavailable | PR required PASS; Production UI shards PASS; unit mode-menu-prefetch PASS | +| 2026-08-10 | cursor/same-mode-focus-no-steal-6df8 (PR #1792) | 905caf2d8eeb5d74af4d8d90fef7e50f4cb78f13 | PR #1792 babysit | before: Production UI critical FAILED (TS5101 baseUrl in isolated Playwright tsconfig after Next 16.3 main sync); Lighthouse advisory ignored; merge-tree clean 0 behind. after: removed deprecated baseUrl from run-playwright + run-lighthouse-budget; root-relative @/* paths; regression guards in unit tests; no threads acted on | tsc isolated tsconfig: old baseUrl TS5101 exit 2, fixed exit 0; vitest test-runner-safety+check-lighthouse-budget 84/84 PASS; format; no provider-backed checks | diff --git a/scripts/run-lighthouse-budget.mjs b/scripts/run-lighthouse-budget.mjs index 6bc98da207..a92dbf675e 100644 --- a/scripts/run-lighthouse-budget.mjs +++ b/scripts/run-lighthouse-budget.mjs @@ -315,7 +315,8 @@ try { `${JSON.stringify( { extends: "../../tsconfig.json", - compilerOptions: { baseUrl: "../..", paths: { "@/*": ["src/*"] } }, + // Resolve `@/*` from the repo root without deprecated `baseUrl` (TS 6 / Next 16.3). + compilerOptions: { paths: { "@/*": ["../../src/*"] } }, }, null, 2, diff --git a/scripts/run-playwright.mjs b/scripts/run-playwright.mjs index 91c4a9c5f4..ebb72ae52b 100644 --- a/scripts/run-playwright.mjs +++ b/scripts/run-playwright.mjs @@ -253,9 +253,9 @@ try { `${JSON.stringify( { extends: "../../tsconfig.json", + // Resolve `@/*` from the repo root without deprecated `baseUrl` (TS 6 / Next 16.3). compilerOptions: { - baseUrl: "../..", - paths: { "@/*": ["src/*"] }, + paths: { "@/*": ["../../src/*"] }, }, }, null, diff --git a/tests/check-lighthouse-budget.test.ts b/tests/check-lighthouse-budget.test.ts index e8c99ba2d8..2d73284f90 100644 --- a/tests/check-lighthouse-budget.test.ts +++ b/tests/check-lighthouse-budget.test.ts @@ -415,6 +415,14 @@ describe("committed lighthouse-budget.json", () => { expect(committed.routes.filter((route) => route.includes("?"))).toEqual([]); }); + it("writes an isolated tsconfig without deprecated baseUrl", () => { + const runner = readFileSync(path.join(process.cwd(), "scripts", "run-lighthouse-budget.mjs"), "utf8"); + + // Same Next 16.3 + TS 6 TS5101 trap as the Playwright runner. + expect(runner).toContain('paths: { "@/*": ["../../src/*"] }'); + expect(runner).not.toContain('baseUrl: "../.."'); + }); + it("invokes npm's JavaScript npx CLI through Node when available", () => { const runner = readFileSync(path.join(process.cwd(), "scripts", "run-lighthouse-budget.mjs"), "utf8"); diff --git a/tests/test-runner-safety.test.ts b/tests/test-runner-safety.test.ts index 6f9f163184..11e8636b94 100644 --- a/tests/test-runner-safety.test.ts +++ b/tests/test-runner-safety.test.ts @@ -733,6 +733,10 @@ describe("provider-safe test environment", () => { expect(runner).toContain('["--max-old-space-size=8192", nextBin, "build", "--webpack"]'); expect(runner).toContain('[nextBin, "start", "--hostname"'); expect(runner).not.toContain('[nextBin, "dev", "--hostname"'); + // Next 16.3 + TS 6 fail isolated Playwright builds when the run-root tsconfig + // still injects deprecated `baseUrl` (TS5101). Keep root-relative `@/*` paths. + expect(runner).toContain('paths: { "@/*": ["../../src/*"] }'); + expect(runner).not.toContain('baseUrl: "../.."'); expect(runner).toContain('NODE_ENV: "production"'); expect(runner).toContain('PLAYWRIGHT_OFFLINE_MODE: "true"'); expect(runner).toContain('NEXT_PUBLIC_MOCKUPS_ENABLED: mockupProjectRequested ? "true" : "false"'); From 8b92a0241b678e8b2aaeb254d8878d59a9bb2ef3 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 10 Aug 2026 11:24:11 +0000 Subject: [PATCH 3/3] fix(ci): align Playwright tsconfig contracts with #1798 Unit coverage failed after merging #1798: runners keep baseUrl + ignoreDeprecations, but this branch still asserted root-relative paths. Update the two contract tests to match the kept runner shape. --- docs/branch-review-ledger.md | 5 +++++ tests/check-lighthouse-budget.test.ts | 9 +++++---- tests/test-runner-safety.test.ts | 9 +++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index ba83d1d94b..c1f711a029 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -859,3 +859,8 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-08-10 | cursor/same-mode-focus-no-steal-6df8 (PR #1792) | 905caf2d8eeb5d74af4d8d90fef7e50f4cb78f13 | PR #1792 babysit | before: Production UI critical FAILED (TS5101 baseUrl in isolated Playwright tsconfig after Next 16.3 main sync); Lighthouse advisory ignored; merge-tree clean 0 behind. after: removed deprecated baseUrl from run-playwright + run-lighthouse-budget; root-relative @/* paths; regression guards in unit tests; no threads acted on | tsc isolated tsconfig: old baseUrl TS5101 exit 2, fixed exit 0; vitest test-runner-safety+check-lighthouse-budget 84/84 PASS; format; no provider-backed checks | | 2026-08-10 | PR #1797 / claude/codex-m4a-retire-dead-type-8wq9ta | 6bf3c7b2a0600021290e165302fd07d721af6592 | retire the dead --text-2xl-compact type step (ledger #297): globals.css @theme, twMerge config, two test lists, the design-system-contract exemption, TOKENS.md/GATES.md | Executed the recorded next action on outstanding-issues #297. The step had zero class-utility and zero var(--text-*) consumers, so the deletion renders identically; UNUSED_TYPE_STEP_EXEMPTIONS is now empty and the declared-but-unconsumed gate holds the line with no carve-out. One test fixture using the token as a synthetic var() consumer was repointed at --text-2xl-minus. GATES.md corrected to eight non-standard steps; the 705-consumer total is unchanged because this step contributed 0. No clinical, RAG-ranking or operational risk paths touched (classifyPullRequestFiles: all false). | check:design-system-contract PASS (705 production files); check:type-scale --strict PASS; lint exit 0; typecheck exit 0; npm run build after rm -rf .next exit 0 (Compiled successfully in 63s); check:outstanding-issues PASS; verify:pr-local completed through typecheck then failed at test on a PRE-EXISTING root-permission failure in tests/pr-handoff-stop.test.ts that reproduces on clean d812c76 (5993 passed, 1 failed); build and check:rag:fixtures run/assessed separately. No UI gate: no rendered output can change. No provider-backed check run. | | 2026-08-10 | codex/visual-baseline-advisory-pr | 6bc57714c36bc6d027561bb8f5f8b00bb92524b2 | PR #1791 babysit unblock | fixed Production UI formulation Clear→Draft flake settle; classified visual drift vs non-drift failures | test:ci-workflows 263; classify-visual-baseline-outcome+ci-cache-safety 40 | +| 2026-08-10 | cursor/same-mode-focus-no-steal-6df8 | b82ae6fe80cfc5e4dac139383230d5a8fcb62b68 | Run PR sweep | fix: Unit coverage tsconfig contract aligned to #1798 ignoreDeprecations; merged origin/main | vitest test-runner-safety+check-lighthouse-budget 84 passed; Unit coverage was FAIL on 3f2aae3a | +| 2026-08-10 | cursor/same-mode-focus-no-steal-6df8 | f0dc8e922d0cf05ff3d9f7c2c5f4d203c8449794 | Run PR sweep | fix: Unit coverage tsconfig contract aligned to #1798 ignoreDeprecations; merged origin/main | vitest test-runner-safety+check-lighthouse-budget 84 passed; Unit coverage was FAIL on 3f2aae3a | +| 2026-08-10 | cursor/same-mode-focus-no-steal-6df8 | a6a5e4cd59352244163a5d6d5439c2bc40a7ff95 | Run PR sweep | fix: Unit coverage tsconfig contract aligned to #1798 ignoreDeprecations; merged origin/main | vitest test-runner-safety+check-lighthouse-budget 84 passed; Unit coverage was FAIL on 3f2aae3a | +| 2026-08-10 | cursor/same-mode-focus-no-steal-6df8 | f8d7ef3faa397de7c9aecc61a66ec5428a3eeed3 | Run PR sweep | fix: Unit coverage tsconfig contract aligned to #1798 ignoreDeprecations; merged origin/main | vitest test-runner-safety+check-lighthouse-budget 84 passed; Unit coverage was FAIL on 3f2aae3a | +| 2026-08-10 | cursor/same-mode-focus-no-steal-6df8 | e6eea4d9b677de6919165753b9ceae059bac1190 | Run PR sweep | fix: Unit coverage tsconfig contract aligned to #1798 ignoreDeprecations; merged origin/main | vitest test-runner-safety+check-lighthouse-budget 84 passed; Unit coverage was FAIL on 3f2aae3a | diff --git a/tests/check-lighthouse-budget.test.ts b/tests/check-lighthouse-budget.test.ts index 2d73284f90..00d58d3f06 100644 --- a/tests/check-lighthouse-budget.test.ts +++ b/tests/check-lighthouse-budget.test.ts @@ -415,12 +415,13 @@ describe("committed lighthouse-budget.json", () => { expect(committed.routes.filter((route) => route.includes("?"))).toEqual([]); }); - it("writes an isolated tsconfig without deprecated baseUrl", () => { + it("writes an isolated tsconfig that silences TS5101 baseUrl deprecation", () => { const runner = readFileSync(path.join(process.cwd(), "scripts", "run-lighthouse-budget.mjs"), "utf8"); - // Same Next 16.3 + TS 6 TS5101 trap as the Playwright runner. - expect(runner).toContain('paths: { "@/*": ["../../src/*"] }'); - expect(runner).not.toContain('baseUrl: "../.."'); + // Same Next 16.3 + TS 6 TS5101 trap as the Playwright runner (#1798). + expect(runner).toContain('ignoreDeprecations: "6.0"'); + expect(runner).toContain('baseUrl: "../.."'); + expect(runner).toContain('paths: { "@/*": ["src/*"] }'); }); it("invokes npm's JavaScript npx CLI through Node when available", () => { diff --git a/tests/test-runner-safety.test.ts b/tests/test-runner-safety.test.ts index 11e8636b94..cb0c7f0097 100644 --- a/tests/test-runner-safety.test.ts +++ b/tests/test-runner-safety.test.ts @@ -733,10 +733,11 @@ describe("provider-safe test environment", () => { expect(runner).toContain('["--max-old-space-size=8192", nextBin, "build", "--webpack"]'); expect(runner).toContain('[nextBin, "start", "--hostname"'); expect(runner).not.toContain('[nextBin, "dev", "--hostname"'); - // Next 16.3 + TS 6 fail isolated Playwright builds when the run-root tsconfig - // still injects deprecated `baseUrl` (TS5101). Keep root-relative `@/*` paths. - expect(runner).toContain('paths: { "@/*": ["../../src/*"] }'); - expect(runner).not.toContain('baseUrl: "../.."'); + // Next 16.3 typechecks the run-root tsconfig; TS 6 deprecates baseUrl (TS5101). + // Keep baseUrl + src-relative paths and silence via ignoreDeprecations (#1798). + expect(runner).toContain('ignoreDeprecations: "6.0"'); + expect(runner).toContain('baseUrl: "../.."'); + expect(runner).toContain('paths: { "@/*": ["src/*"] }'); expect(runner).toContain('NODE_ENV: "production"'); expect(runner).toContain('PLAYWRIGHT_OFFLINE_MODE: "true"'); expect(runner).toContain('NEXT_PUBLIC_MOCKUPS_ENABLED: mockupProjectRequested ? "true" : "false"');