Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions docs/branch-review-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -793,9 +793,14 @@ This file is append-only. Never rewrite or delete an existing review record; app
| 2026-07-24 | open-PR conflict sync (20 PRs) | multi-head | Conflict resolution pass | Before: 8 PRs behind/dirty (#1124 #1131 #1162 #1169 #1174-1177). After: merged origin/main into all; all 20 open PRs MERGEABLE behind=0 (BLOCKED only by CI/reviews). | merge origin/main per branch; no provider-backed checks run |
| 2026-07-24 | open-PR conflict sync (22 PRs) | multi-head | Conflict resolution pass | Before: all 22 open PRs behind/dirty vs main (several CONFLICTING/DIRTY). After: merged origin/main into every open head; all pushes OK; merge-tree classified 22/22 clean. | merge origin/main per branch; check:branch-review-ledger on #1172; no provider-backed checks run |
| 2026-07-24 | cursor/pr-queue-hygiene-72ec | pending-push | PR queue hygiene | Add pr-branch-sync workflow + sync:pr-branches helper; bump postcss to clear npm audit high; document anti-churn guidance in AGENTS/process-hardening/pr-babysit/run-pr. | check:github-actions PASS; docs:check-scripts/index PASS; vitest sync-open-pr-branches 3/3; npm audit high clean; no provider-backed checks run |
| 2026-07-25 | cursor/fix-mode-switch-lag-22f6 | 54d45f687e3723f51fa3d7e9940692c9a6e3b52c | Same-class bug hunt: mode-switch/layout thrash after reserve-flip fix | No P0. Branch fix mitigates pathname∧searchMode gate, shell changeMode optimistic setSearchMode, selectSearchMode leaving dashboard, and always-on padding-bottom transitions. Still open P2s: (1) ClinicalDashboard.crossModeSearch still setSearchMode before router.push without isDashboardModeHref guard; (2) dashboard-internal Answer↔/?mode=* still eager setSearchMode → overlay/collapse + heroBreakpoint + portal rebind; (3) standalone shell persists #main-content scrollTop + phoneScrollHide across mode homes; (4) ClinicalDashboard↔GlobalStandaloneSearchShellClient remount + grid-template-columns transition; (5) hero portal null gap while slot/MutationObserver rebinds; (6) ModeHomeRouteLoading phone min-h 13.5rem vs idle-reserve mode homes; (7) /tools vs /?mode=tools dual shell (#007). P3: services/forms contentAlign center→startOnPhone after registry load. | Static source audit of shell/dashboard/header/reserve/CSS/app-modes/skeletons; no browser/provider checks. |
| 2026-07-25 | `cursor/fix-mode-switch-lag-22f6` | `b9484396347defaaa934571604b9d165ae6d8b98` | Same-class mode-switch thrash review + fixes | FIXED prior open P2s from 54d45f68 hunt: crossModeSearch now mirrors selectSearchMode (navigate-only when leaving dashboard); shared shell resets phone scrollTop + scroll-hide on pathname; hero portal keeps default composer until host attaches; ModeHomeRouteLoading uses --shell-header-h; services/forms contentAlign stays startOnPhone while loading. No P0/P1. Residual P2: ClinicalDashboard↔standalone shell remount + sidebar grid-template-columns transition; dashboard-internal Answer↔Documents still eager setSearchMode (overlay/hero flip by design, scroll now reset). Residual P3/#007: /tools vs /?mode=tools dual entry. | Focused Vitest ownership/align/hide-on-scroll/merge-artifacts/overlay 46/46; typecheck; static contracts for portal/scroll reset/crossModeSearch. No verify:ui / provider-backed checks. |
| 2026-07-25 | `cursor/fix-mode-switch-lag-22f6` / PR #1187 | `775d15adef8155aba68e43f0e9354adf60f1ea8d` | Same-class thrash fixes lint closeout | Supersedes b9484396 row for lint follow-up: pathname bottomComposerHidden reset moved to render-time; removed unused desktopHomeComposerFallback. verify:cheap green. Residual unchanged (dashboard↔standalone remount; #007 Tools dual entry). | verify:cheap 3345 passed / 3 skipped; focused ownership tests; eslint clean on touched shell/header. No provider checks. |
| 2026-07-25 | `cursor/fix-mode-switch-lag-22f6` | `0ef62ff521fb9f0457f685e9d2f50a24d640e663` | Frontend-architecture review: loading/navigation performance for modes/pages | No P0. P1: (1) GlobalSearchShell statically imports ClinicalDashboard into shared (search-app) layout client graph — every namespaced mode pays dashboard module weight; (2) ClientHydrationBoundary blanks standalone mode children until hydrate — defeats RSC paint for DSM/factsheets/etc. P2: ClinicalDashboard↔standalone remount + grid-template-columns transition; dashboard URL sync still useEffect+rAF (shell already render-time); ToolsHub ssr:false on /?mode=tools; MutationObserver portal rebind cost on mode-home slot changes; SearchCommandProvider value tied to query in shell. P3/#007: /tools vs /?mode=tools dual entry (PT-11 vs nav). Quick wins: dynamic() ClinicalDashboard; remove/narrow ClientHydrationBoundary; point tools href to /tools. Larger: unify shells / extract shared chrome. | Static architecture review of SharedSearchAppShell/GlobalSearchShell/ClinicalDashboard/MasterSearchHeader/app-modes/search-route-ownership/mode homes/tools routes; prior mode-switch ledger rows at b9484396/775d15ad noted. No browser, verify:ui, bundle measure, or provider-backed checks. |
| 2026-07-24 | codex/apply-phone-layout-to-all-home-pages (PR #1124) | pending | Babysit: ledger dedupe + merge readiness | Before: Static PR failed on exact duplicate ledger rows after main sync. After: removed duplicate rows; squash auto-merge armed. | check:branch-review-ledger PASS; no provider-backed checks run |
| 2026-07-25 | cursor/pdf-crop-malformed-repro-9b3e (PR #1176) | c31543f5b5862dbe6911079029f28500a6af2a59 | Run PR sweep: CI fix + threads + drift | Before: GitHub reported DIRTY and Static PR checks failed formatting `docs/outstanding-issues.md` and `tests/pdf-extractor.test.ts`; 0 unresolved threads. After: merged current `origin/main` cleanly and formatted both failing files. | Prettier check pass; `git diff --check` pass; no provider-backed checks run. |
| 2026-07-25 | codex/search-results-filters-20260725 | 88131e7267efd33059766dec80355a9246fbb2bf | Search result filters and document Sources merge-readiness review | APPROVE. No P0-P2 finding after current-main sync. Documents open Sources as an on-screen filtering surface with source-type controls; the shared results ribbon is applied across search pages. Highest residual risk: unusual real-content combinations may alter perceived density, while responsive, forced-colors, focus, and overflow paths are browser-covered. RAG impact: no retrieval behaviour change - UI controls and source browsing only. | `npm run verify:ui` pass 268/268; `npm run verify:cheap` pass (377 files, 3340 passed, 1 skipped); post-sync `npm run verify:pr-local` pass (378 files, 3349 passed, 1 skipped, production build, bundle-secret scan, offline RAG fixtures); `npm run check:production-readiness` pass with OPENAI_SAFETY_IDENTIFIER_SECRET warning; no live/provider-backed app checks run. |
| 2026-07-25 | `codex/therapy-page-polish-ad78b4` | `157559aa0678f02de09c14f66d544b62a5138c4a` | Targeted release review: Therapy naming, centred navigation, and white canvas | APPROVE. No P0-P3 findings. The production Therapy route consistently uses the title Therapy, the shared page background token, and a centred overflow-safe section navigation. The latest `origin/main` merge was clean and retained both upstream responsive/home-composer assertions. Highest residual risk is visual drift at an untested browser engine; exact desktop and phone Chromium measurements were stable. | Focused Vitest 40/40; pre-sync `verify:cheap` 378 files / 3342 passed / 1 skipped; pre-sync `verify:ui` passed; integrated runtime, Prettier, lint, and typecheck passed; integrated Vitest was interrupted by the shared heavyweight-test queue after an independent 378-file / 3342-pass run. Required hosted checks must pass on the published exact head before merge. No clinical/provider workflow ran. |
| 2026-07-25 | codex/search-results-filters-20260725 (PR #1184) | 8f74d8bd40810ede34ad4b155973b598c1be0101 | Superseding merge-readiness review after Sources focus repair | APPROVE. Supersedes the 88131e72 row: the automated P2 showed a transient Daily Actions menu item could disconnect before Sources restored focus. Closing Sources now falls back after unmount to the currently rendered action trigger, and the regression requires the visible Documents trigger to own focus. No P0-P2 finding remains. RAG impact: no retrieval behaviour change - UI focus restoration only. | Post-fix isolated production Chromium 1/1; post-current-main local Chromium 1/1; `npm run verify:cheap` pass (378 files, 3350 passed, 1 skipped); targeted Prettier and ESLint pass; required hosted checks must rerun on the published exact head; no live clinical/provider workflow ran. |
| 2026-07-25 | `codex/mobile-search-filter-dropdowns-dcbb32` | `d9f0051ef8335817e7fa29aeb02ee6324331df39` | Release review: responsive search-result filter dropdowns across production modes | APPROVE with verification note. No P0-P2 finding. Phone result-type rails are replaced by page-specific native selects while desktop controls remain intact; shared controls own a real 44px interactive target and retain forced-colors/focus behavior. Highest residual risk is browser-specific native-select rendering outside Chromium. RAG impact: no retrieval behaviour change - result filtering and sort presentation only. | `npm run verify:cheap` pass twice (378 files, 3351 passed, 1 skipped); focused production Chromium routes and accessibility/stress guards pass; production `npm run build` and client-bundle secret scan pass; offline RAG fixtures 36/36 pass. `verify:pr-local` reached unit tests but local infrastructure tests timed out under heavy worktree contention; two remained timeout-only on focused retry. Required hosted checks must pass on the exact published head before merge. No live clinical/provider workflow ran. |
| 2026-07-25 | `cursor/fix-mode-switch-lag-22f6` / PR #1187 | `876d7ecfa1ae8ec79fc0f0bdf1198c6640ad89b8` | Parallel loading UX + frontend-architecture review + quick-win fixes | No P0. Confirmed live: H1 dashboard↔standalone remount dominant (~0.6–1.2s settle); H4 hero portal rebind; H3 registry post-paint. FIXED quick wins: remove ClientHydrationBoundary blanking; ModeHomeRouteLoading startOnPhone; mode-home loading.tsx alignment/additions; forms server defaultFormSlug + client-boundary test; dynamic ClinicalDashboard; sidebar grid transition mount-gate; forms drop key=query; DocumentViewer key=id; therapy Suspense ModeHomeRouteLoading; redirect /?mode=services|forms. Residual P2: unify shells (H1), stable hero slot, registry abort+LRU/summary fields, Tools dual entry #007, prescribing full-catalogue cliff. | Parallel explore×3 + debug measurement; focused Vitest loading/forms/ownership/align contracts; typecheck; eslint touched shell. No verify:ui / provider-backed checks. |
8 changes: 8 additions & 0 deletions docs/search-chrome-behaviour.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ This repo uses one shared search experience across the global shell, dashboard r
6. Header and footer chrome that share the same scroll signal should hide/reveal symmetrically: when hidden, underlying content must be visible to the viewport edge.
7. Do not add page-local dock-sized `pb-[calc(...safe-area...)]` under a shell-owned dock. Put clearance in the shared reserve or the page-owned composer, never both.
8. `GlobalSearchShell` uses an inner `mobile-composer-reserve-pad` so phone padding contributes to scroll height; do not move phone shell clearance back to scrollport padding without a browser proof.
9. Standalone mode-home detection (`isStandaloneModeHomePath`) is pathname-only. Do not gate hero vs dock on a React `searchMode` that can update before the router pathname lands — that one-frame mismatch animates reserve padding and reads as a choppy screen resize.
10. Phone `#main-content` / reserve-pad `padding-bottom` transitions apply only while `data-bottom-composer-hidden="true"` (scroll-hide). Mode and route reserve flips must snap.
11. Shared shell must reset phone scroll offset and scroll-hide state on `pathname` change so mode homes do not inherit a mid-page offset or collapsed header.
12. Hero composer portal: keep the default composer mounted until the portal host is actually attached; do not hide on `slotId` alone (mode-home remounts otherwise flash a null gap).
13. Leaving the dashboard shell for a namespaced mode (`selectSearchMode` / `crossModeSearch`) must navigate without rewriting dashboard chrome first.
14. Do not wrap mode-home `{children}` in `ClientHydrationBoundary` — that blanks RSC HTML until JS mounts. Keep hydration guards on the specific leaf that mismatches.
15. Standalone mode-home `loading.tsx` files must render `ModeHomeRouteLoading` (phone top-aligned). Do not reuse unrelated results/medication skeletons.
16. `ClinicalDashboard` must stay out of the shared shell’s static import graph (dynamic import) so namespaced mode routes do not parse the dashboard module.

## Change checklist

Expand Down
4 changes: 3 additions & 1 deletion scripts/check-maintainability-budgets.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import { readFileSync } from "node:fs";

const budgets = new Map([
["src/components/ClinicalDashboard.tsx", 4140],
// Raised with the mode-loading pass: leave-dashboard nav guards + scroll reset.
// Net client cost still fell — GlobalSearchShell now dynamic-imports this file.
["src/components/ClinicalDashboard.tsx", 4160],
["src/lib/rag/rag.ts", 5030],
["src/components/DocumentViewer.tsx", 1734],
["supabase/functions/indexing-v3-agent/index.ts", 2191],
Expand Down
25 changes: 2 additions & 23 deletions src/app/(search-app)/differentials/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
import { Skeleton, searchPageShell, searchPageContainer } from "@/components/ui-primitives";
import { ModeHomeRouteLoading } from "@/components/mode-home-page-skeleton";

export default function Loading() {
return (
<div className={searchPageShell} role="status" aria-label="Loading library">
<div className={searchPageContainer}>
<div className="mb-6 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<Skeleton className="h-10 w-full max-w-sm" />
<div className="flex gap-2">
<Skeleton className="h-9 w-20 rounded-full" />
<Skeleton className="h-9 w-20 rounded-full" />
<Skeleton className="h-9 w-20 rounded-full" />
</div>
</div>

<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<Skeleton className="h-40 w-full rounded-xl" animationDelay="50ms" />
<Skeleton className="h-40 w-full rounded-xl" animationDelay="100ms" />
<Skeleton className="h-40 w-full rounded-xl" animationDelay="150ms" />
<Skeleton className="h-40 w-full rounded-xl" animationDelay="200ms" />
</div>
</div>
<span className="sr-only">Loading library</span>
</div>
);
return <ModeHomeRouteLoading />;
}
4 changes: 3 additions & 1 deletion src/app/(search-app)/documents/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export default async function DocumentPage({

return (
<DocumentViewer
key={`${id}:${initialPage}:${query.chunk ?? ""}`}
// Key on document identity only — page/chunk updates are handled inside
// DocumentViewer via URL sync. Remounting on every page flip reloaded the PDF.
key={id}
documentId={id}
initialPage={initialPage}
chunkId={query.chunk}
Expand Down
17 changes: 2 additions & 15 deletions src/app/(search-app)/dsm/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
import { Skeleton, searchPageShell, searchPageContainer } from "@/components/ui-primitives";
import { ModeHomeRouteLoading } from "@/components/mode-home-page-skeleton";

export default function Loading() {
return (
<div className={searchPageShell} role="status" aria-label="Loading DSM criteria">
<div className={searchPageContainer}>
<Skeleton className="mb-6 h-10 w-1/3 max-w-sm" />
<div className="grid gap-4">
<Skeleton className="h-32 w-full rounded-xl" animationDelay="50ms" />
<Skeleton className="h-32 w-full rounded-xl" animationDelay="100ms" />
<Skeleton className="h-32 w-full rounded-xl" animationDelay="150ms" />
<Skeleton className="h-32 w-full rounded-xl" animationDelay="200ms" />
</div>
</div>
<span className="sr-only">Loading DSM criteria</span>
</div>
);
return <ModeHomeRouteLoading />;
}
5 changes: 5 additions & 0 deletions src/app/(search-app)/factsheets/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ModeHomeRouteLoading } from "@/components/mode-home-page-skeleton";

export default function Loading() {
return <ModeHomeRouteLoading />;
}
24 changes: 2 additions & 22 deletions src/app/(search-app)/favourites/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,5 @@
import { Skeleton } from "@/components/ui-primitives";
import { ModeHomeRouteLoading } from "@/components/mode-home-page-skeleton";

export default function Loading() {
return (
<div className="mx-auto w-full max-w-7xl px-3 py-4 sm:px-5 lg:px-6" role="status" aria-label="Loading medication">
<Skeleton className="mb-2 h-10 w-2/3 max-w-sm" />
<Skeleton className="mb-6 h-6 w-1/3 max-w-xs" />

{/* Tabs */}
<div className="mb-6 flex gap-2">
<Skeleton className="h-10 w-24 rounded-lg" />
<Skeleton className="h-10 w-24 rounded-lg" />
<Skeleton className="h-10 w-24 rounded-lg" />
</div>

{/* Grid */}
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
<Skeleton className="h-48 w-full rounded-xl" animationDelay="50ms" />
<Skeleton className="h-48 w-full rounded-xl" animationDelay="100ms" />
<Skeleton className="h-48 w-full rounded-xl" animationDelay="150ms" />
</div>
<span className="sr-only">Loading medication</span>
</div>
);
return <ModeHomeRouteLoading />;
}
20 changes: 2 additions & 18 deletions src/app/(search-app)/forms/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,5 @@
import { Skeleton, searchPageShell, searchPageContainer } from "@/components/ui-primitives";
import { ModeHomeRouteLoading } from "@/components/mode-home-page-skeleton";

export default function Loading() {
return (
<div className={searchPageShell} role="status" aria-label="Loading services">
<div className={searchPageContainer}>
<div className="mb-6 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<Skeleton className="h-10 w-full max-w-sm" />
<Skeleton className="h-10 w-32 rounded-lg" />
</div>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
<Skeleton className="h-32 w-full rounded-xl" animationDelay="50ms" />
<Skeleton className="h-32 w-full rounded-xl" animationDelay="100ms" />
<Skeleton className="h-32 w-full rounded-xl" animationDelay="150ms" />
<Skeleton className="h-32 w-full rounded-xl" animationDelay="200ms" />
</div>
</div>
<span className="sr-only">Loading services</span>
</div>
);
return <ModeHomeRouteLoading />;
}
4 changes: 3 additions & 1 deletion src/app/(search-app)/forms/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FormsHomePage } from "@/components/forms/forms-home-page";
import { FormsSearchResultsPage } from "@/components/forms/forms-search-results-page";
import { defaultFormSlug } from "@/lib/forms";

type FormsSearchParams = Promise<{ [key: string]: string | string[] | undefined }>;

Expand All @@ -17,7 +18,8 @@ export default async function FormsPage({ searchParams }: { searchParams: FormsS
const hasSubmittedSearch = readFirstSearchParam(resolvedSearchParams.run) === "1" && query.length > 0;

if (!hasSubmittedSearch) {
return <FormsHomePage />;
// Computed server-side so the client route chunk never bundles the forms catalog.
return <FormsHomePage defaultFormSlug={defaultFormSlug() ?? null} />;
}

return <FormsSearchResultsPage query={query} />;
Expand Down
5 changes: 5 additions & 0 deletions src/app/(search-app)/formulation/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ModeHomeRouteLoading } from "@/components/mode-home-page-skeleton";

export default function Loading() {
return <ModeHomeRouteLoading />;
}
12 changes: 12 additions & 0 deletions src/app/(search-app)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,17 @@ export default async function Home({ searchParams }: HomeProps) {
redirect(suffix ? `/formulation?${suffix}` : "/formulation");
}

// Services/forms are namespaced mode homes; keep /?mode=* from mounting the
// full ClinicalDashboard + registry path for those surfaces.
if (initialSearchMode === "services" || initialSearchMode === "forms") {
redirect(
appModeHomeHref(initialSearchMode, {
query: firstSearchParam(params.q)?.trim(),
focus: firstSearchParam(params.focus) === "1",
run: firstSearchParam(params.run) === "1",
}),
Comment on lines +81 to +87

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve the supported query alias.

GlobalStandaloneSearchShellClient reads q ?? query, but this redirect forwards only q. /?mode=services&query=mania&run=1 therefore lands without a query or submitted search.

Proposed fix
-        query: firstSearchParam(params.q)?.trim(),
+        query: firstSearchParam(params.q ?? params.query)?.trim(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (initialSearchMode === "services" || initialSearchMode === "forms") {
redirect(
appModeHomeHref(initialSearchMode, {
query: firstSearchParam(params.q)?.trim(),
focus: firstSearchParam(params.focus) === "1",
run: firstSearchParam(params.run) === "1",
}),
if (initialSearchMode === "services" || initialSearchMode === "forms") {
redirect(
appModeHomeHref(initialSearchMode, {
query: firstSearchParam(params.q ?? params.query)?.trim(),
focus: firstSearchParam(params.focus) === "1",
run: firstSearchParam(params.run) === "1",
}),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/`(search-app)/page.tsx around lines 81 - 87, Update the redirect
built by appModeHomeHref in the initialSearchMode services/forms branch to
preserve the supported query alias by reading and forwarding the query parameter
alongside q. Ensure requests using query, such as query=mania with run=1, retain
the search text and submitted-search state when redirected.

);
}

return <HomePageClient initialMode={initialSearchMode} />;
}
5 changes: 5 additions & 0 deletions src/app/(search-app)/specifiers/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ModeHomeRouteLoading } from "@/components/mode-home-page-skeleton";

export default function Loading() {
return <ModeHomeRouteLoading />;
}
Loading
Loading