Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d9aba57
Unify information-page chrome across catalogue modes.
cursoragent Jul 24, 2026
f0071e2
Update dock min-height guard for shared information-page shell.
cursoragent Jul 24, 2026
edb6a65
Merge remote-tracking branch 'origin/main' into HEAD
cursoragent Jul 24, 2026
a7a3b6b
test: align information page navigation assertions
cursoragent Jul 24, 2026
1beea8e
Merge remote-tracking branch 'origin/main' into HEAD
cursoragent Jul 24, 2026
3b89b02
Merge branch 'main' into cursor/information-page-structure-2a5d
BigSimmo Jul 24, 2026
97511d6
Merge remote-tracking branch 'origin/main' into cursor/information-pa…
BigSimmo Jul 24, 2026
5666be0
docs: record Run PR behind-main sweep for #1148
BigSimmo Jul 24, 2026
230770a
Merge remote-tracking branch 'origin/main' into cursor/information-pa…
BigSimmo Jul 24, 2026
c938266
docs: ledger re-sync sweep for PR #1148
BigSimmo Jul 24, 2026
14d6cd5
Merge branch 'main' into cursor/information-page-structure-2a5d
cursoragent Jul 24, 2026
6b00023
Merge branch 'main' into cursor/information-page-structure-2a5d
cursoragent Jul 24, 2026
5d56d16
Merge branch 'main' into cursor/information-page-structure-2a5d
cursoragent Jul 24, 2026
26cc662
Merge remote-tracking branch 'origin/main' into cursor/information-pa…
cursoragent Jul 24, 2026
cbff685
style(docs): format codebase-index.md for Prettier CI
cursoragent Jul 24, 2026
c9682a9
Merge remote-tracking branch 'origin/main' into cursor/information-pa…
cursoragent Jul 24, 2026
b843258
Merge cursor/pr-queue-hygiene-72ec for postcss audit + PR branch sync
cursoragent Jul 24, 2026
bfa7bec
Merge branch 'main' into cursor/information-page-structure-2a5d
github-actions[bot] Jul 24, 2026
0134f8f
Merge branch 'main' into cursor/information-page-structure-2a5d
github-actions[bot] Jul 24, 2026
e5e8f09
merge origin/main into cursor/information-page-structure-2a5d
BigSimmo Jul 25, 2026
2ced88c
Merge branch 'main' into cursor/information-page-structure-2a5d
github-actions[bot] Jul 25, 2026
51c47e6
Merge branch 'main' into cursor/information-page-structure-2a5d
github-actions[bot] Jul 25, 2026
8295038
merge origin/main into cursor/information-page-structure-2a5d
BigSimmo Jul 25, 2026
41add33
merge origin/main into cursor/information-page-structure-2a5d
BigSimmo Jul 25, 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
2 changes: 2 additions & 0 deletions docs/branch-review-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,7 @@ This file is append-only. Never rewrite or delete an existing review record; app
| 2026-07-24 | cursor/search-performance-review-4ee9 (PR #1134) | 9311d01212fe42bd41ffb22a83bfa51f1a4d19f2 | Run PR re-sync sweep | Re-check: CONFLICTING on use-differential-catalog.ts (+ related). Not cheap; merge aborted, no push. | merge origin/main and/or conflict re-check only; no provider-backed checks run |
| 2026-07-24 | cursor/comprehensive-repo-review-ledger-d9a1 (PR #1150) | 60a3c3a83a31e65ec2759540629687e7113e2489 | Run PR sweep: CI fix + threads + drift | Before: CONFLICTING, CI green, 0 threads. After: merged origin/main cleanly (ledger auto-merge); pushed 60a3c3a83. Threads: none. Residual: CI re-running. | merge origin/main only; no provider-backed checks run |
| 2026-07-24 | cursor/search-interactive-perf-af54 (PR #1138) | ff4b293d95f922e70ebf5ee9b0c156c41a8bff3b | Run PR sweep: CI fix + threads + drift | Before: CONFLICTING, CI green, 0 threads. RAG impact: no retrieval behaviour change — PR is client deferred-search/UI only (no src/lib/rag/**). After: merged origin/main; conflict resolved in src/components/ui/sheet.tsx by keeping main restoreTimersRef/unmountingRef focus-restore fix; pushed ff4b293d9. Threads: none. | merge origin/main only; no provider-backed checks run |
| 2026-07-24 | cursor/information-page-structure-2a5d (PR #1148) | 97511d69256b97de4f4e654ff6c12f3742f795f4 | Run PR sweep: CI fix + threads + drift | Before: behind main. After: merged origin/main cleanly (no conflicts). Unresolved review threads left as non-P0/P1. CI not waited. | merge origin/main only; thread scan read-only; no provider-backed checks run |
| 2026-07-24 | codex/audit-remediation-final (PR #1158) | 4bfaf2a77a5c8cc0e6c48ee27a72a2faad203dd3 | Run PR sweep: CI fix + threads + drift | Before: behind main by 64. After: merged origin/main cleanly (no conflicts). Threads: non-P0/P1 left open. CI not waited. | merge origin/main only; thread scan read-only; no provider-backed checks run |
| 2026-07-24 | implement-audit-viewport-fixes (PR #1140) | 47ebd3d20184875d80bf192144b614ec58d48e08 | Run PR sweep: CI fix + threads + drift | Before: already contained origin/main. After: ledger-only record. Threads: non-P0/P1 left open. CI not waited. | merge origin/main only; thread scan read-only; no provider-backed checks run |
| 2026-07-24 | codex/hydration-fixes (PR #1131) | 6c093e927d7b4f7261fb78160d85bdc407853001 | Run PR sweep: CI fix + threads + drift | Before: already contained origin/main. After: ledger-only record. Threads: non-P0/P1 left open. CI not waited. | merge origin/main only; thread scan read-only; no provider-backed checks run |
Expand All @@ -753,6 +754,7 @@ This file is append-only. Never rewrite or delete an existing review record; app
| 2026-07-24 | codex/query-ribbon-search-headings (PR #1166) | 37cfa5553ccb784ee5e9f47ded1ad69914c053ed | Run PR babysit: CI/threads/drift | Final HEAD after merge origin/main + ledger bookkeeping. 0 unresolved threads; no Bugbot actionable findings; required CI re-running on this SHA. | merge origin/main; no provider-backed checks run. |
| 2026-07-24 | codex/query-ribbon-search-headings (PR #1166) | 9eac2e252bcc5c548aa919b69faeb79b9ff7d2cf | Run PR babysit: CI/threads/drift | Merged origin/main; Codex ledger-SHA P2 dispositioned+resolved (append-only supersede already in 9eac2e252). 0 unresolved threads. | merge origin/main; thread resolve only; no provider-backed checks run. |
| 2026-07-24 | remediate-audit-system-issues (PR #1160) | bdf530fc8c6faaa4491c510396b47872fc39bf25 | Run PR sweep: CI fix + threads + drift | second re-merge after main moved to 2e68888f3 during first push; clean ort merge (ledger + layout.tsx); taskkill /T retained; sitemap prettier retained | merge only; no provider-backed checks run |
| 2026-07-24 | cursor/information-page-structure-2a5d (PR #1148) | 230770a53f9bfb53ba69abc81d6e8491e021f8a9 | Run PR re-sync sweep | Before: CONFLICTING. After: merged origin/main clean. | merge origin/main and/or conflict re-check only; no provider-backed checks run |
| 2026-07-24 | codex/audit-remediation-final (PR #1158) | 78fab6be0c43cf5e92361315399d393ee7742f2e | Run PR re-sync sweep | Before: CONFLICTING. After: merged origin/main clean (no RAG conflict markers). NOTE: PR still intentionally adds deterministic broad_summary queryClass shortcut in src/lib/rag/rag.ts (+17) — RAG impact behaviour change, not dropped during merge. | merge origin/main and/or conflict re-check only; no provider-backed checks run |
| 2026-07-24 | implement-audit-viewport-fixes (PR #1140) | a541b75c0e49f84125fc7e5d114cd9fc32d1a694 | Run PR re-sync sweep | Before: CONFLICTING. After: merged origin/main clean. | merge origin/main and/or conflict re-check only; no provider-backed checks run |
| 2026-07-24 | codex/hydration-fixes (PR #1131) | a29b0d778b542932972aa6035ee115b91e49025a | Run PR re-sync sweep | Before: CONFLICTING + Static PR FAIL (suppressHydrationWarning on skip link). After: merged origin/main; removed illegal suppressHydrationWarning from skip-to-content anchor; theme fix already on PR head b4b5f21b9. CI re-running. | merge origin/main and/or conflict re-check only; no provider-backed checks run |
Expand Down
8 changes: 8 additions & 0 deletions docs/codebase-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,15 @@ sequenceDiagram

One shared composer (`master-search-header.tsx`) serves every mode. Placement:

<<<<<<< HEAD

- **Mode homes** (`/services`, `/forms`, `/favourites`, `/differentials`, `/formulation`, `/tools`, and dashboard homes): inline in the hero via the `mode-home-composer-slot` portal, on phone and tablet+ alike. (`/applications` is a redirect to `/tools`, not a composer surface.)
- **Information (detail) pages**: catalogue/record routes under each mode (`/services/[slug]`, `/forms/[slug]`, `/medications/[slug]`, `/specifiers/[slug]`, `/formulation/[slug]`, `/factsheets/[slug]`, `/dsm/diagnoses/[slug]`, …). Route detection: `src/lib/information-pages.ts` (`isInformationPage`). Shared outer chrome: `src/components/information-page-shell.tsx` (`InformationPageShell`, breadcrumbs, optional footer). Specifier/formulation mode shells re-export that primitive. Intentional opt-outs: document viewer, therapy-compass CSS workspace, differentials presentation workflow.
\=======
- **Mode homes** (`/services`, `/forms`, `/favourites`, `/differentials`, `/dsm`, `/specifiers`, `/formulation`, `/factsheets`, `/therapy-compass`, `/tools`, and dashboard homes): inline in the hero via the `mode-home-composer-slot` portal, on phone and tablet+ alike. (`/applications` is a redirect to `/tools`, not a composer surface.)

> > > > > > > origin/main

- **Result and detail views**: fixed bottom dock on phone (compact variant on submitted searches), sticky top from `sm` up.
- **Results routing**: standalone routes own their submitted searches via `?q=…&run=1` (`/services` → `ServicesNavigatorPage`, `/forms` → `FormsSearchResultsPage`, `/differentials` → `DifferentialsHome` results view, `/formulation` → local mechanism results, `/favourites` filters the command library in place). Answer, Documents, and Prescribing submitted searches render inside `ClinicalDashboard` — intentional, since they need retrieval/answer state. `/?mode=favourites` redirects to `/favourites`; `/?mode=differentials` redirects to `/differentials`; `/?mode=dsm` redirects to `/dsm`; `/?mode=specifiers` redirects to `/specifiers`; `/?mode=formulation` redirects to `/formulation`.
- **Intentionally composer-free routes**: `/differentials/presentations/*` (comparison workflow owns its chrome), `/documents/[id]` viewer (has its own in-document ask composer), `/documents/source/*` (document flow owns mobile chrome). Do not re-flag these in search-consistency audits.
Expand Down
60 changes: 1 addition & 59 deletions src/components/clinical-dashboard/global-search-shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
} from "@/lib/app-modes";
import { isLocalNoAuthMode, resolveClientDemoMode } from "@/lib/client-env";
import { documentsSearchHref } from "@/lib/document-flow-routes";
import { isInformationPage } from "@/lib/information-pages";
import { differentialsMobileCompareAddonSlotId, modeHomeDesktopComposerSlotId } from "@/lib/mode-home-composer";
import { readSearchNavigationContext, type SearchNavigationOptions } from "@/lib/search-navigation-context";
import { shouldRenderClinicalDashboard, shouldRenderDashboardSearch } from "@/lib/search-route-ownership";
Expand Down Expand Up @@ -164,65 +165,6 @@ function GlobalSearchShellClient(props: GlobalSearchShellProps) {
);
}

function isInformationPage(pathname: string): boolean {
// Services detail: /services/[slug]
if (pathname.startsWith("/services/") && pathname !== "/services") return true;

// Forms detail: /forms/[slug]
if (pathname.startsWith("/forms/") && pathname !== "/forms") return true;

// Medications detail: /medications/[slug]
if (pathname.startsWith("/medications/") && pathname !== "/medications") return true;

// Psychiatric specifier detail: /specifiers/[slug]
if (
pathname.startsWith("/specifiers/") &&
pathname !== "/specifiers" &&
pathname !== "/specifiers/builder" &&
pathname !== "/specifiers/compare" &&
pathname !== "/specifiers/map"
)
return true;

// Clinical formulation detail: /formulation/[slug]
if (
pathname.startsWith("/formulation/") &&
pathname !== "/formulation" &&
pathname !== "/formulation/builder" &&
pathname !== "/formulation/compare" &&
pathname !== "/formulation/map"
)
return true;

// Factsheets detail: /factsheets/[slug]
if (pathname.startsWith("/factsheets/") && pathname !== "/factsheets" && pathname !== "/factsheets/search")
return true;

// Therapy compass detail: /therapy-compass/[slug]/brief or /therapy-compass/[slug]/sheet
if (
pathname.startsWith("/therapy-compass/") &&
pathname !== "/therapy-compass" &&
pathname !== "/therapy-compass/compare" &&
pathname !== "/therapy-compass/pathways" &&
pathname !== "/therapy-compass/recommend" &&
pathname !== "/therapy-compass/review" &&
pathname !== "/therapy-compass/search"
)
return true;

// Differential diagnosis detail: /differentials/diagnoses/[slug] or /differentials/presentations/[slug]
if (pathname.startsWith("/differentials/diagnoses/") || pathname.startsWith("/differentials/presentations/"))
return true;

// DSM-5 Diagnosis detail: /dsm/diagnoses/[slug] or /dsm/diagnoses/[slug]/differentials or /dsm/compare
if (pathname.startsWith("/dsm/diagnoses/")) return true;

// Document detail: /documents/[id] (excluding /documents/search)
if (pathname.startsWith("/documents/") && pathname !== "/documents/search") return true;

return false;
}

function isToolDetailWithFooterSearch(pathname: string): boolean {
return (
(pathname.startsWith("/services/") && pathname !== "/services") ||
Expand Down
45 changes: 20 additions & 25 deletions src/components/clinical-dashboard/medication-record-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
Activity,
Ban,
TriangleAlert,
ArrowLeft,
BadgeCheck,
BookOpen,
CalendarDays,
Expand All @@ -19,7 +18,6 @@ import {
Timer,
type LucideIcon,
} from "lucide-react";
import Link from "next/link";
import { useMemo, useRef, useState, type CSSProperties, type KeyboardEvent as ReactKeyboardEvent } from "react";

import { BadgeCluster } from "@/components/clinical-dashboard/clinical-badge";
Expand All @@ -46,12 +44,17 @@ import {
cn,
EmptyState,
LoadingPanel,
pageContainer,
toneDanger,
toneInfo,
toneSuccess,
toneWarning,
} from "@/components/ui-primitives";
import {
InformationPageBreadcrumbs,
InformationPageFooter,
InformationPageShell,
} from "@/components/information-page-shell";
import { appModeHomeHref } from "@/lib/app-modes";

const sectionIcons: Record<string, LucideIcon> = {
dose: CalendarDays,
Expand Down Expand Up @@ -387,7 +390,7 @@ function MedicationRecordDetail({
const activeSections = sectionsByTab[activeTab];

return (
<div className={cn(pageContainer, "space-y-3 py-1 sm:py-2")} style={medicationAccentStyle(record.accent)}>
<div className="space-y-3 py-1 sm:py-2" style={medicationAccentStyle(record.accent)}>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_21rem]">
<div className="space-y-3.5">
<section className="scroll-mt-16 overflow-hidden rounded-xl border border-[color:var(--border)] border-l-4 border-l-[color:var(--med-accent)] bg-[color:var(--surface-raised)] p-3.5 shadow-[var(--shadow-soft)] sm:p-5">
Expand Down Expand Up @@ -496,27 +499,19 @@ export function MedicationRecordPage({
const governance = data?.governance ?? (error ? undefined : fallbackGovernance);

return (
<main
className="min-h-[calc(100dvh-var(--shell-header-h))] text-[color:var(--text)]"
data-testid={`medication-page-${slug}`}
>
<div className="mx-auto max-w-7xl px-3 pt-3 sm:px-6 lg:px-8">
<Link
href={`/?mode=prescribing&q=${encodeURIComponent(slug)}`}
className="inline-flex min-h-tap w-fit items-center gap-2 rounded-lg border border-[color:var(--clinical-accent-border)] bg-[color:var(--clinical-accent-soft)] px-3 text-sm font-semibold text-[color:var(--clinical-accent)] shadow-[var(--shadow-inset)] transition hover:border-[color:var(--clinical-accent)] hover:bg-[color:var(--surface-raised)] hover:text-[color:var(--text-heading)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--focus)]"
>
<ArrowLeft className="h-4 w-4" aria-hidden="true" />
<span className="hidden sm:inline">Back to medication search</span>
<span className="sm:hidden">Back</span>
</Link>
</div>
<div className="px-3 py-3 sm:px-6 lg:px-8">
<InformationPageShell testId={`medication-page-${slug}`} gap={false}>
<InformationPageBreadcrumbs
home={{
label: "Medications",
href: appModeHomeHref("prescribing", { query: slug, focus: true }),
}}
current={record?.name ?? slug}
/>
<div className="mt-3">
{record ? (
<MedicationRecordDetail record={record} governance={governance} />
) : loading ? (
<div className="mx-auto max-w-7xl">
<LoadingPanel label="Loading medication reference…" variant="skeleton" lines={6} />
</div>
<LoadingPanel label="Loading medication reference…" variant="skeleton" lines={6} />
) : (
<div className="rounded-lg border border-[color:var(--danger-border)] bg-[color:var(--danger-bg)] p-4 text-sm text-[color:var(--danger-text)]">
<div className="flex items-start gap-2">
Expand All @@ -526,9 +521,9 @@ export function MedicationRecordPage({
</div>
)}
</div>
<footer className="mx-auto max-w-7xl px-4 pb-4 text-center text-2xs font-medium text-[color:var(--text-muted)]">
<InformationPageFooter className="mt-4 pb-1">
Clinical KB provides evidence summaries, not medical advice. Verify clinical decisions.
</footer>
</main>
</InformationPageFooter>
</InformationPageShell>
);
}
5 changes: 3 additions & 2 deletions src/components/dsm/dsm-diagnosis-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from "lucide-react";

import { DsmHeaderActions, DsmPageHeader } from "@/components/dsm/dsm-page-header";
import { InformationPageShell } from "@/components/information-page-shell";
import { cn, codeText, metadataPill, pageContainer } from "@/components/ui-primitives";
import { dsmCriteria, resolveDsmDifferential, type DsmDiagnosis, type DsmLabeledText } from "@/lib/dsm";

Expand All @@ -36,7 +37,7 @@ export function DsmDiagnosisPage({ diagnosis }: { diagnosis: DsmDiagnosis }) {
const compareHref = `/dsm/compare?ids=${encodeURIComponent(diagnosis.slug)}`;

return (
<article data-testid="dsm-diagnosis-page" className="min-h-full bg-[color:var(--background)] pb-8">
<InformationPageShell testId="dsm-diagnosis-page" width="bleed" className="pb-8">
<DsmPageHeader
eyebrow="Diagnosis information"
title={diagnosis.title}
Expand Down Expand Up @@ -270,6 +271,6 @@ export function DsmDiagnosisPage({ diagnosis }: { diagnosis: DsmDiagnosis }) {
<span className={metadataPill}>Supplied local catalogue</span>
</div>
</div>
</article>
</InformationPageShell>
);
}
17 changes: 6 additions & 11 deletions src/components/dsm/dsm-page-header.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Link from "next/link";
import { ArrowLeft, BookOpenCheck, GitCompareArrows, Search } from "lucide-react";
import { BookOpenCheck, GitCompareArrows, Search } from "lucide-react";
import type { ReactNode } from "react";

import { InformationPageBreadcrumbs } from "@/components/information-page-shell";
import { cn, codeText, metadataPill, pageContainer } from "@/components/ui-primitives";

export function DsmPageHeader({
Expand All @@ -26,26 +27,20 @@ export function DsmPageHeader({
<div className={cn(pageContainer, "px-4 py-4 sm:px-6 sm:py-5 lg:px-8")}>
<div className="flex flex-wrap items-start justify-between gap-4">
<div className="min-w-0 max-w-4xl">
<Link
href="/dsm"
className="mb-3 inline-flex min-h-tap items-center gap-2 rounded-lg text-xs font-bold text-[color:var(--clinical-accent)] transition hover:text-[color:var(--clinical-accent-hover)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--focus)]"
>
<ArrowLeft className="h-4 w-4" aria-hidden />
DSM-5 Diagnosis home
</Link>
<p className="text-2xs font-extrabold uppercase tracking-[0.09em] text-[color:var(--clinical-accent)]">
<InformationPageBreadcrumbs home={{ label: "DSM-5 Diagnosis home", href: "/dsm" }} className="mb-3" />
<p className="text-2xs font-extrabold uppercase tracking-[0.06em] text-[color:var(--clinical-accent)]">
{eyebrow}
</p>
<div className="mt-1.5 flex min-w-0 items-start gap-3">
<span className="mt-0.5 hidden h-tap w-tap shrink-0 place-items-center rounded-xl border border-[color:var(--clinical-accent-border)] bg-[color:var(--clinical-accent-soft)] text-[color:var(--clinical-accent)] shadow-[var(--shadow-inset)] sm:grid">
<BookOpenCheck className="h-5 w-5" aria-hidden />
</span>
<div className="min-w-0">
<h1 className="text-balance text-2xl font-extrabold leading-tight text-[color:var(--text-heading)] sm:text-3xl">
<h1 className="text-balance text-2xl font-extrabold leading-tight tracking-tight text-[color:var(--text-heading)] sm:text-3xl">
{title}
</h1>
{description ? (
<p className="mt-1.5 max-w-3xl text-sm font-medium leading-6 text-[color:var(--text-muted)]">
<p className="mt-1.5 max-w-3xl text-pretty text-sm font-medium leading-6 text-[color:var(--text-muted)]">
{description}
</p>
) : null}
Expand Down
Loading
Loading