Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
24605b5
docs: record mode-switch performance review
BigSimmo Jul 27, 2026
e5a668b
merge origin/main into mode-switch prefetch branch
cursoragent Jul 27, 2026
2f11b6a
docs(ledger): restore historical rows after main sync
cursoragent Jul 27, 2026
82c17f7
docs(ledger): pin PR #1275 sync closeout to pushed head
cursoragent Jul 27, 2026
6c544c1
test(nav): require prefetch in both mode-menu open helpers
cursoragent Jul 27, 2026
c0f2bc9
Merge branch 'main' into codex/identify-and-fix-performance-issues-du…
BigSimmo Jul 27, 2026
a5100d0
fix: apply CodeRabbit auto-fixes
coderabbitai[bot] Jul 27, 2026
bc5b51c
docs(ledger): revert CodeRabbit autofix history rewrite
cursoragent Jul 27, 2026
6126edf
docs(ledger): pin CodeRabbit disposition closeout SHA
cursoragent Jul 27, 2026
d5f9b74
docs(ledger): fill CodeRabbit disposition SHA cell
cursoragent Jul 27, 2026
d7455f1
merge origin/main to clear PR #1275 staleness
cursoragent Jul 27, 2026
3952ec0
docs(ledger): re-append PR #1275 rows after main merge
cursoragent Jul 27, 2026
191707e
docs(ledger): disposition CodeRabbit malformed-row finding
cursoragent Jul 27, 2026
b69c454
docs(ledger): pin malformed-row disposition SHA
cursoragent Jul 27, 2026
0efcbde
docs(ledger): fill malformed-row disposition SHA
cursoragent Jul 27, 2026
f4b5575
test(ui): exercise mode-home prefetch on both menu-open paths
cursoragent Jul 27, 2026
5e8d963
docs(ledger): record CodeRabbit prefetch-test disposition
cursoragent Jul 27, 2026
81005d1
docs(ledger): disposition Codex mojibake-ledger finding
cursoragent Jul 27, 2026
0146984
merge origin/main; adopt per-option mode-home prefetch
cursoragent Jul 28, 2026
db17807
docs(ledger): record PR #1275 main-merge prefetch reconciliation
cursoragent Jul 28, 2026
4df7b6c
merge origin/main to clear PR #1275 staleness
cursoragent Jul 28, 2026
9a9e416
docs(ledger): restore append-only prefix after main sync
cursoragent Jul 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/branch-review-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -1175,3 +1175,9 @@ This file is append-only. Never rewrite or delete an existing review record; app
| 2026-07-28 | PR #1289 / `codex/rag-reliability-final` | `a1ca6a016490e4d4b564edd3d553d87fed3071df` | Protected-main RAG reliability, clinical-governance and release review | APPROVE. Independent retrieval, governance and fallback reviews found and fixed three merge blockers: global chunk-query alias overreach was narrowed to the measured clozapine blood-count action shape; legacy private source reviews remain on the deployed v1 RPC while unapplied-v2 paths fail explicitly; and source-backed review fallback is now a zero-tolerance blocking metric with reconciled evidence. Final rereviews found no P0-P2. PR #1288 was superseded without force-push after GitGuardian correctly rejected a token-shaped fake fixture; the clean replacement tree is byte-identical to the reviewed tree and both secret scanners pass. The additive BMJ attestation migration remains unapplied and BMJ stays unverified pending qualified human action. | Exact application tree `verify:pr-local` PASS: format, zero-warning lint, typecheck, 403 files and 4,101 tests passed with 2 skipped, production build/client-secret scan, and 36 offline RAG fixtures. Live 36-case canary PASS with document/content recall 1.0, zero failed cases and zero per-case document/content RR regressions; three cache-bypassed affected-path answer probes PASS with zero provider requests and zero generation cost. Earlier coverage PASS: 399 files, 4,062 passed and 2 skipped, RAG 86.83% statements and 90.79% lines. Hosted build, static, unit coverage, migration replay, Supabase Preview, Production UI, policy, Semgrep, Gitleaks and GitGuardian passed on the implementation tree; final evidence-only head requires the normal hosted rerun. |
| 2026-07-28 | PR #1289 / `codex/rag-reliability-final` | `d49af8acb42ccedbfe6c8b3f03d30769ba906ec7` | Bugbot review (exact head) | APPROVE. No high-confidence P0–P2. Application `src/`/`supabase/`/`tests/`/`scripts/` trees are unchanged vs prior APPROVE tip `a1ca6a01`; tip delta is docs evidence + clean merge from `main`. No unresolved `cursor[bot]` Bugbot threads. Residual risk: unapplied BMJ attestation migration (`#022`) correctly fails closed with `503 source_review_v2_unavailable` until qualified hosted apply. | Focused high-risk Vitest 358 + 1502 passed; merge-tree CLEAN vs `origin/main`; no provider-backed checks; no PR comment mutations. |
| 2026-07-28 | PR #1289 / `codex/rag-reliability-final` | `ab6ca036937bff1acaefbda8a5581d6d75f489b3` | Final current-main sync review | APPROVE pending fresh exact-head required checks. Merged current `origin/main` without conflict after its already-reviewed document-search and focus-path changes; no protected RAG, evaluation, migration, or RAG fixture surface changed from the live-canary application tree, and no P0-P2 finding remains. | `git merge-tree --write-tree` CLEAN before sync; branch-ledger guard and `git diff --check` PASS; prior exact application-tree `verify:pr-local` and live 36-case canary remain applicable; fresh hosted checks required. |
| 2026-07-27 | PR #1275 / `codex/identify-and-fix-performance-issues-during-mode-switch` | `82c17f76` | Mode-switch prefetch review + merge restore | Prefetch mode homes on menu open; later reconciled with main per-option prefetch. Ledger restored append-only from main after mojibake rewrite. | Focused nav tests; check:branch-review-ledger; no provider checks. |
| 2026-07-27 | PR #1275 / `codex/identify-and-fix-performance-issues-during-mode-switch` | `bc5b51c2` | CodeRabbit duplicate-ledger disposition | DISPOSITIONED / not actionable as a PR product delete. Near-duplicates already exist on origin/main as non-identical historical records; check:branch-review-ledger passes on main. Removing main-owned history from a feature PR would violate append-only. | substring counts on origin/main; ledger guard PASS; no provider checks. |
| 2026-07-27 | PR #1275 / `codex/identify-and-fix-performance-issues-during-mode-switch` | `191707ee` | CodeRabbit malformed-ledger-row disposition | DISPOSITIONED / not actionable on this PR. MD056 cell-count warnings on ~700-722 are identical on origin/main. Fix belongs in dedicated main ledger hygiene if desired. | cell-count scan main vs tip; check:branch-review-ledger PASS; no provider checks. |
| 2026-07-27 | PR #1275 / `codex/identify-and-fix-performance-issues-during-mode-switch` | `f4b55751` | CodeRabbit behavioral prefetch-test disposition | RESOLVED. Behavioral DOM coverage for menu-open prefetch paths (later adapted to per-option model). | focused vitest PASS; no provider checks. |
| 2026-07-27 | PR #1275 / `codex/identify-and-fix-performance-issues-during-mode-switch` | `81005d18` | Codex mojibake-ledger disposition | RESOLVED. Historical rows restored byte-for-byte from origin/main; append-only thereafter. | exact prefix check; check:branch-review-ledger PASS; no provider checks. |
| 2026-07-28 | PR #1275 / `codex/identify-and-fix-performance-issues-during-mode-switch` | `01469840` | CI/merge conflict closeout + Bugbot triage | RESOLVED merge conflict with origin/main (7ae4eb49 per-option prefetchModeHome). Dropped superseded bulk prefetchModeHomes; menu-open warms only highlighted option; focus/pointer scanning retained. CodeRabbit duplicate/malformed ledger threads dispositioned (main-owned). No open cursor[bot] Bugbot product defects. | merge-tree clean; focused vitest 12/12; ledger restored from main + appends; no provider checks. |
23 changes: 15 additions & 8 deletions src/components/clinical-dashboard/master-search-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -852,9 +852,22 @@ export function MasterSearchHeader({
setScopeSheetOpen(false);
}

// Mode options are buttons (not Links), so Next cannot discover destinations.
// Prefetch only the mode the user is about to choose — the highlighted option
// on open, then whichever option receives focus/pointer while scanning.
function prefetchModeHome(modeId: AppModeId) {
if (modeId === searchMode) return;
const href = appModeHomeHref(modeId);
if (prefetchedModeHrefsRef.current.has(href)) return;
prefetchedModeHrefsRef.current.add(href);
router.prefetch(href);
}

function openModeMenuWithFocus(index: number) {
closeModeSurfaces();
const nextIndex = (index + visibleAppModeOptions.length) % visibleAppModeOptions.length;
const highlighted = visibleAppModeOptions[nextIndex];
if (highlighted) prefetchModeHome(highlighted.id);
const phoneLayout = currentUsesPhoneSearchLayout();
setUsesPhoneSearchLayout(phoneLayout);
setModeMenuFocusIndex(nextIndex);
Expand All @@ -872,6 +885,8 @@ export function MasterSearchHeader({
setModeMenuOpen(false);
return;
}
const highlighted = visibleAppModeOptions[selectedModeIndex];
if (highlighted) prefetchModeHome(highlighted.id);
setUsesPhoneSearchLayout(currentUsesPhoneSearchLayout());
setModeMenuFocusIndex(selectedModeIndex);
setModeMenuOpen(true);
Expand Down Expand Up @@ -923,14 +938,6 @@ export function MasterSearchHeader({
}
}

function prefetchModeHome(modeId: AppModeId) {
if (modeId === searchMode) return;
const href = appModeHomeHref(modeId);
if (prefetchedModeHrefsRef.current.has(href)) return;
prefetchedModeHrefsRef.current.add(href);
router.prefetch(href);
}

function renderModeMenuOptions() {
return visibleAppModeOptions.map((mode, index) => {
const Icon = appModeIcons[mode.id];
Expand Down
17 changes: 17 additions & 0 deletions tests/audit-navigation-auth-regressions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,29 @@ describe("audit navigation and auth regressions", () => {
"function renderModeMenuOptions()",
"const restoreActionMenuFocusRef",
);
const openModeMenuWithFocus = sourceSegment(
masterSearchHeaderSource,
"function openModeMenuWithFocus(",
"function toggleModeMenu(",
);
const toggleModeMenu = sourceSegment(
masterSearchHeaderSource,
"function toggleModeMenu(",
"function handleModeTriggerKeyDown(",
);

expect(masterSearchHeaderSource).toContain("function prefetchModeHome(modeId: AppModeId)");
expect(masterSearchHeaderSource).toContain("router.prefetch(href)");
expect(modeOptions).toContain("onFocus={() => prefetchModeHome(mode.id)}");
expect(modeOptions).toContain("onPointerEnter={() => prefetchModeHome(mode.id)}");
// Menu-open paths warm only the highlighted option — never every visible home.
expect(openModeMenuWithFocus).toContain("prefetchModeHome(highlighted.id)");
expect(toggleModeMenu).toContain("prefetchModeHome(highlighted.id)");
expect(masterSearchHeaderSource).not.toContain("function prefetchModeHomes(");
expect(masterSearchHeaderSource).not.toContain("visibleAppModeOptions.forEach((mode) => router.prefetch");
expect(masterSearchHeaderSource).not.toContain(
"new Set(visibleAppModeOptions.map((mode) => appModeHomeHref(mode.id)))",
);
});

it("defers cross-mode search on narrow screens until expansion except for completed answers", () => {
Expand Down
115 changes: 115 additions & 0 deletions tests/mode-menu-prefetch.dom.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/** @vitest-environment jsdom */

import { render, screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { beforeEach, describe, expect, it, vi } from "vitest";

import { MasterSearchHeader } from "@/components/clinical-dashboard/master-search-header";
import { appModeHomeHref, visibleAppModeDefinitionsForSession } from "@/lib/app-modes";

const router = vi.hoisted(() => ({
push: vi.fn(),
replace: vi.fn(),
prefetch: vi.fn(),
}));

vi.mock("next/navigation", () => ({
useRouter: () => router,
}));

vi.mock("@/lib/supabase/client", () => ({
useAuthSession: () => ({
status: "signed_out",
session: null,
isConfigured: true,
error: null,
signInWithEmail: vi.fn(),
signOut: vi.fn(),
}),
}));

vi.mock("@/components/clinical-dashboard/use-saved-registry-favourites", () => ({
useSavedRegistryFavourites: () => [],
}));

vi.mock("@/components/clinical-dashboard/search-command-context", () => ({
useSearchCommand: () => null,
}));

vi.mock("@/components/clinical-dashboard/universal-search-also-matches", () => ({
UniversalSearchAlsoMatches: () => null,
}));

function headerProps() {
return {
demoMode: false,
documents: [],
query: "",
searchMode: "answer" as const,
loading: false,
selectedDocumentIds: [] as string[],
queryMode: "auto" as const,
scopeFilters: {},
realDataReady: true,
canAccessFavourites: false,
onQueryChange: () => undefined,
onSearchModeChange: vi.fn(),
onAsk: () => undefined,
onClearQuery: () => undefined,
onClearScope: () => undefined,
onQueryModeChange: () => undefined,
onScopeFiltersChange: () => undefined,
onToggleScope: () => undefined,
queryModeOptions: [{ value: "auto" as const, label: "Auto" }],
};
}

function guestModeHomes() {
return visibleAppModeDefinitionsForSession({ authenticated: false, demoMode: false });
}

describe("mode menu home prefetch", () => {
beforeEach(() => {
router.push.mockReset();
router.replace.mockReset();
router.prefetch.mockReset();
});

it("prefetches a mode home when the user points at that option", async () => {
const user = userEvent.setup();
const documents = guestModeHomes().find((mode) => mode.id === "documents");
expect(documents).toBeTruthy();
const documentsHref = appModeHomeHref("documents");

render(<MasterSearchHeader {...headerProps()} />);
await user.click(screen.getByRole("button", { name: /Mode Answer/i }));
const menu = await screen.findByRole("menu", { name: "Choose app mode" });

// Opening on the current mode is a no-op; scanning another option warms it.
expect(router.prefetch).not.toHaveBeenCalledWith(documentsHref);
await user.hover(within(menu).getByRole("menuitemradio", { name: /Documents/i }));
expect(router.prefetch).toHaveBeenCalledWith(documentsHref);
const prefetched = new Set(router.prefetch.mock.calls.map(([href]) => href as string));
expect(prefetched.has(documentsHref)).toBe(true);
expect(prefetched.size).toBeLessThan(guestModeHomes().length);
});

it("prefetches the highlighted mode when openModeMenuWithFocus targets another home", async () => {
const user = userEvent.setup();
const modes = guestModeHomes();
const answerIndex = modes.findIndex((mode) => mode.id === "answer");
expect(answerIndex).toBeGreaterThanOrEqual(0);
const previous = modes[(answerIndex - 1 + modes.length) % modes.length];
expect(previous.id).not.toBe("answer");
const previousHref = appModeHomeHref(previous.id);

render(<MasterSearchHeader {...headerProps()} />);
const trigger = screen.getByRole("button", { name: /Mode Answer/i });
trigger.focus();
await user.keyboard("{ArrowUp}");
await screen.findByRole("menu", { name: "Choose app mode" });

expect(router.prefetch).toHaveBeenCalledWith(previousHref);
expect(new Set(router.prefetch.mock.calls.map(([href]) => href)).size).toBe(1);
});
});
Loading