From 40b92d2d6f41d0f9fadc8c4840737ffae1f34c5d Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 16:31:57 +0000 Subject: [PATCH 1/6] Clean up Factsheets, Dictionary, and Calculators home pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the verification footer strip from the three mode homes the user flagged, on both doors into each mode: the shared home at `/` (sharedHomePresentation in ui-copy.ts) and each mode's own standalone `*-home-page.tsx`. - Factsheets: "Demonstration patient information · Connect only governance-approved content before publication" - Dictionary: "Source-checked reference terminology · Not patient-specific guidance" - Calculators: "Source-cited scoring · Scores support clinical judgement and never replace a full assessment. Nothing entered here is stored." Also give Dictionary a searchCommandSurfaceByMode entry so its home shows the "TRY THIS … Tap to search" example ticket that Factsheets and Calculators already have (and, on desktop, the matching rotating hint and prompt row). Every example is a real entry in the local dictionary catalogue, and remoteSearchEnabled stays false because Dictionary owns a static catalogue rather than the remote index. The `--mode-home-verification-reserve` band is unchanged: it is sized on the slot, not the caveat, so the shared home's composer still holds position when switching between modes that do and do not carry a footer. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018kyb3c1iYZ5MGMSNRANzdE --- src/components/calculators/home-page.tsx | 8 +------- .../dictionary/dictionary-home-page.tsx | 8 +------- .../factsheets/factsheets-home-page.tsx | 8 +------- src/lib/search-command-surface.ts | 15 +++++++++++++++ src/lib/ui-copy.ts | 12 ------------ 5 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/components/calculators/home-page.tsx b/src/components/calculators/home-page.tsx index 3c06703e81..ad0ebf56fc 100644 --- a/src/components/calculators/home-page.tsx +++ b/src/components/calculators/home-page.tsx @@ -1,6 +1,6 @@ import { Calculator, CloudRain, GlassWater, Search, Zap } from "lucide-react"; -import { ModeHomeMain, ModeHomeTemplate, ModeHomeVerificationFooter } from "@/components/mode-home-template"; +import { ModeHomeMain, ModeHomeTemplate } from "@/components/mode-home-template"; import { appModeHomeHref } from "@/lib/app-modes"; import { modeHomeDesktopComposerSlotId } from "@/lib/mode-home-composer"; @@ -46,12 +46,6 @@ export function CalculatorsHomePage() { href: calculatorSearchHref(label), icon: Search, }))} - footer={ - - } /> ); diff --git a/src/components/dictionary/dictionary-home-page.tsx b/src/components/dictionary/dictionary-home-page.tsx index 6b3338c4fc..99ca5df016 100644 --- a/src/components/dictionary/dictionary-home-page.tsx +++ b/src/components/dictionary/dictionary-home-page.tsx @@ -1,6 +1,6 @@ import { BookOpen, GitCompareArrows, LibraryBig, List, Quote, Tags } from "lucide-react"; -import { ModeHomeMain, ModeHomeTemplate, ModeHomeVerificationFooter } from "@/components/mode-home-template"; +import { ModeHomeMain, ModeHomeTemplate } from "@/components/mode-home-template"; import { modeHomeDesktopComposerSlotId } from "@/lib/mode-home-composer"; import { dictionaryEntries, dictionaryTopics } from "@/lib/dictionary-data"; @@ -63,12 +63,6 @@ export function DictionaryHomePage() { }, { label: "Source governance", shortLabel: "Sources", href: "/dictionary/sources", tone: "info" }, ]} - footer={ - - } /> ); diff --git a/src/components/factsheets/factsheets-home-page.tsx b/src/components/factsheets/factsheets-home-page.tsx index 295e11f716..1c13ed67d1 100644 --- a/src/components/factsheets/factsheets-home-page.tsx +++ b/src/components/factsheets/factsheets-home-page.tsx @@ -1,6 +1,6 @@ import { BookOpenText } from "lucide-react"; -import { ModeHomeMain, ModeHomeTemplate, ModeHomeVerificationFooter } from "@/components/mode-home-template"; +import { ModeHomeMain, ModeHomeTemplate } from "@/components/mode-home-template"; import { modeHomeDesktopComposerSlotId } from "@/lib/mode-home-composer"; export function FactsheetsHomePage() { @@ -14,12 +14,6 @@ export function FactsheetsHomePage() { actions={[]} actionsLabel="Factsheets actions" desktopComposerSlotId={modeHomeDesktopComposerSlotId} - footer={ - - } /> ); diff --git a/src/lib/search-command-surface.ts b/src/lib/search-command-surface.ts index c7da653a39..d761eff350 100644 --- a/src/lib/search-command-surface.ts +++ b/src/lib/search-command-surface.ts @@ -163,6 +163,21 @@ const searchCommandSurfaceByMode: Partial; From 3e4e2e89fcc27e4294820f97a508a55babbd7249 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 16:37:40 +0000 Subject: [PATCH 2/6] Record branch review for the home-pages cleanup Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018kyb3c1iYZ5MGMSNRANzdE --- ...c798c0750476a66cfd5fe5dac55336a9339fd8986a3b1ab873b.record.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/branch-review-records/c5dc5a81e8d54c798c0750476a66cfd5fe5dac55336a9339fd8986a3b1ab873b.record.md diff --git a/docs/branch-review-records/c5dc5a81e8d54c798c0750476a66cfd5fe5dac55336a9339fd8986a3b1ab873b.record.md b/docs/branch-review-records/c5dc5a81e8d54c798c0750476a66cfd5fe5dac55336a9339fd8986a3b1ab873b.record.md new file mode 100644 index 0000000000..f8be21018e --- /dev/null +++ b/docs/branch-review-records/c5dc5a81e8d54c798c0750476a66cfd5fe5dac55336a9339fd8986a3b1ab873b.record.md @@ -0,0 +1 @@ +| 2026-08-18 | claude/home-pages-cleanup-qeh5fr | 40b92d2d6f41d0f9fadc8c4840737ffae1f34c5d | mode home footers + dictionary command surface | self-review clean; footers removed on user instruction, dictionary example ticket added | verify:pr-local pass (673 files / 7276 tests); verify:ui not run — playwright chromium 1234 vs installed 1194 (#255), delegated to CI | From 894279bc016746950916a2efca20fcb468e4445f Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 18:19:42 +0000 Subject: [PATCH 3/6] Remove the caveat footer from every mode home page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The small line under the composer's privacy link is gone from all of them, not just the three cleaned up in the previous commit. Both doors into each mode are covered: the shared home at `/` (sharedHomePresentation in ui-copy.ts, rendered by SharedHomeEmptyState) and each mode's own standalone home component. Removed: Answer, Services, Forms, Differentials, DSM, Specifiers, Formulation, Prescribing, and the Therapy Compass home screen — plus the Factsheets/Dictionary/Calculators lines already dropped earlier. Consequent cleanup, since nothing renders these any more: - `SharedHomeVerification` and the `verification` field leave `SharedHomePresentation`; the table is now exactly a title and a subtitle. - `--mode-home-verification-reserve` and the wrapper that reserved its height on phones are deleted. The band existed only to stop a varying caveat length from moving the composer between modes; with no caveat there is nothing to reserve, and the copy reserve above it still holds the title/subtitle pair. - `ModeHomeVerificationFooter` keeps its single remaining caller, the therapy-compass page footer, which workspace.tsx renders with `showFooter={!isHome}` and so never shows on a home page. Its now-unreachable `verifiedCount`/`totalCount` props and their sr-only line are removed. - `countVerifiedRegistryRecords` had no callers left after Services and Forms stopped passing counts into the footer, so it is deleted rather than left for check:knip. Services and Forms keep their registry status notice for the not-ready state; only the verified-count caveat is gone. Three source-pinning tests are updated to assert the absence rather than the presence of the footer. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018kyb3c1iYZ5MGMSNRANzdE --- src/app/globals.css | 18 ------- .../clinical-dashboard/answer-status.tsx | 22 +-------- .../clinical-dashboard/differentials-home.tsx | 3 +- .../medication-prescribing-workspace.tsx | 17 +++---- src/components/dsm/dsm-home-page.tsx | 10 +--- src/components/forms/forms-home-page.tsx | 17 +------ .../formulation/formulation-home-page.tsx | 12 +---- src/components/mode-home-template.tsx | 32 ++++-------- .../services/services-home-page.tsx | 17 +------ .../specifiers/specifiers-home-page.tsx | 12 +---- .../therapy-compass/screens/home-screen.tsx | 8 +-- src/lib/ui-copy.ts | 49 ------------------- src/lib/use-registry-records.ts | 5 -- ...audit-content-services-regressions.test.ts | 6 ++- tests/shared-home-empty-state.dom.test.tsx | 10 ++-- ...herapy-compass-responsive-contract.test.ts | 5 +- 16 files changed, 42 insertions(+), 201 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index a0644d0574..d952a66f83 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1109,24 +1109,6 @@ summary::-webkit-details-marker { } } -/* Shared-home verification reserve. - * - * The same jump the copy reserve above prevents, one block lower. On `/` the - * mode pill swaps the whole page's copy in place, and each mode's - * review-before-use caveat is a different length — measured in Chromium across - * every entry in sharedHomePresentation, the footer renders at 0, 18, 36 or - * 52px. Because the mode home is vertically centred, that difference moves the - * composer: Formulation sat 8px above Specifiers at 320px before this reserve. - * - * Flat rather than banded, unlike the copy reserve: Calculators' caveat wraps - * to three lines at every phone width, so a per-width band would resolve to the - * same value three times. 3 line boxes (leading-4) + the footer's own pt-0.5 + - * two gap-y-0.5 wrap gaps. Dead space below the shortest caveat costs nothing - * visible — it lands inside the centring gap, with no content beneath it. */ -:root { - --mode-home-verification-reserve: calc(3 * 1rem + 0.125rem + 2 * 0.125rem); -} - .mode-home-composer-slot { width: min(100%, clamp(19rem, 90vw, 52rem)); max-width: calc(100vw - 1rem - var(--safe-area-left) - var(--safe-area-right)); diff --git a/src/components/clinical-dashboard/answer-status.tsx b/src/components/clinical-dashboard/answer-status.tsx index 1f6e7c4cb3..2ef90908a3 100644 --- a/src/components/clinical-dashboard/answer-status.tsx +++ b/src/components/clinical-dashboard/answer-status.tsx @@ -12,7 +12,7 @@ import { import { useClientTime } from "@/lib/use-client-time"; import { AnswerSuggestionChips } from "@/components/clinical-dashboard/answer-suggestion-chips"; import { useAppPreferences } from "@/components/clinical-dashboard/use-app-preferences"; -import { ModeHomeTemplate, ModeHomeVerificationFooter } from "@/components/mode-home-template"; +import { ModeHomeTemplate } from "@/components/mode-home-template"; import { cn, floatingControl, sourceCard } from "@/components/ui-primitives"; import { appModeIcons } from "@/lib/app-mode-icons"; import type { AppModeId } from "@/lib/app-modes"; @@ -75,9 +75,6 @@ export function SharedHomeEmptyState({ onSelectRecent && preferences.showRecentOnHome ? recentQueries.filter((entry) => entry.trim().length > 0).slice(0, 5) : []; - // Annotated: `sharedHomePresentation` is `as const`, so indexing it with the - // AppModeId union yields a union of entry shapes and `verification` (optional) - // would not resolve on the members that omit it. const presentation: SharedHomePresentation = sharedHomePresentation[modeId]; return ( @@ -104,23 +101,6 @@ export function SharedHomeEmptyState({ icon={History} /> )} - {/* Every mode that carries a review-before-use caveat shows it here, - not just Answer: the mode pill never leaves `/`, so this page is - the only home a clinician sees for most modes. - - The reserve is on the wrapper, which renders for every mode — - including the modes with no caveat. Sized on the slot rather than - the caveat, it holds the centred column's height constant so - switching modes cannot move the composer (see - --mode-home-verification-reserve in globals.css). */} -
- {presentation.verification ? ( - - ) : null} -
} /> diff --git a/src/components/clinical-dashboard/differentials-home.tsx b/src/components/clinical-dashboard/differentials-home.tsx index 64b7b1bab4..5f58920288 100644 --- a/src/components/clinical-dashboard/differentials-home.tsx +++ b/src/components/clinical-dashboard/differentials-home.tsx @@ -21,7 +21,7 @@ import { type LucideIcon, } from "lucide-react"; -import { ModeHomeTemplate, ModeHomeVerificationFooter } from "@/components/mode-home-template"; +import { ModeHomeTemplate } from "@/components/mode-home-template"; import { SearchResultsHeaderBand, type AppliedFilterChip, @@ -1446,7 +1446,6 @@ export function DifferentialsHome({ onClick: () => handleSuggestedSearch(item.query), })) } - footer={} /> ); diff --git a/src/components/clinical-dashboard/medication-prescribing-workspace.tsx b/src/components/clinical-dashboard/medication-prescribing-workspace.tsx index daa70f2be1..0d802de435 100644 --- a/src/components/clinical-dashboard/medication-prescribing-workspace.tsx +++ b/src/components/clinical-dashboard/medication-prescribing-workspace.tsx @@ -19,7 +19,7 @@ import Link from "next/link"; import { useSearchParams } from "next/navigation"; import { useId, useMemo, useState } from "react"; -import { ModeHomeTemplate, ModeHomeVerificationFooter } from "@/components/mode-home-template"; +import { ModeHomeTemplate } from "@/components/mode-home-template"; import { SearchResultsHeaderBand } from "@/components/clinical-dashboard/search-results-header-band"; import { ResultFilterSheet, @@ -303,15 +303,12 @@ function MedicationHome({ onClick: () => onSuggestedSearch(item.query), }))} footer={ -
- - -
+ } /> ); diff --git a/src/components/dsm/dsm-home-page.tsx b/src/components/dsm/dsm-home-page.tsx index cff418c112..b5f0db3bd6 100644 --- a/src/components/dsm/dsm-home-page.tsx +++ b/src/components/dsm/dsm-home-page.tsx @@ -1,7 +1,7 @@ import { BookOpenCheck, GitCompareArrows, ListChecks, Search } from "lucide-react"; -import { ModeHomeMain, ModeHomeTemplate, ModeHomeVerificationFooter } from "@/components/mode-home-template"; -import { dsmCategories, dsmDiagnoses } from "@/lib/dsm"; +import { ModeHomeMain, ModeHomeTemplate } from "@/components/mode-home-template"; +import { dsmCategories } from "@/lib/dsm"; import { modeHomeDesktopComposerSlotId } from "@/lib/mode-home-composer"; const featuredCategories = dsmCategories @@ -64,12 +64,6 @@ export function DsmHomePage() { shortLabel: category.label, href: `/dsm/search?category=${category.key}`, }))} - footer={ - - } /> ); diff --git a/src/components/forms/forms-home-page.tsx b/src/components/forms/forms-home-page.tsx index 71a3172465..8fa85bad6a 100644 --- a/src/components/forms/forms-home-page.tsx +++ b/src/components/forms/forms-home-page.tsx @@ -17,13 +17,12 @@ import { ModeHomeMain, ModeHomeStatusNotice, ModeHomeTemplate, - ModeHomeVerificationFooter, type ModeHomeAction, type ModeHomePill, } from "@/components/mode-home-template"; import { appModeHomeHref } from "@/lib/app-modes"; import { modeHomeDesktopComposerSlotId } from "@/lib/mode-home-composer"; -import { countVerifiedRegistryRecords, useRegistryRecords } from "@/lib/use-registry-records"; +import { useRegistryRecords } from "@/lib/use-registry-records"; // The default form slug is computed server-side (app/forms/page.tsx) and passed // as a prop: a direct `@/lib/forms` value import here would compile the full @@ -84,7 +83,6 @@ const commonTasks: ModeHomePill[] = [ export function FormsHomePage({ defaultFormSlug = null }: { defaultFormSlug?: string | null }) { const taskCards = buildTaskCards(defaultFormSlug); const registry = useRegistryRecords("form", { view: "summary" }); - const verifiedCount = countVerifiedRegistryRecords(registry); const registryReady = registry.status === "ready" || registry.status === "refetching"; const hasRegistryRecords = registryReady && registry.total > 0; const registryNotice = @@ -133,18 +131,7 @@ export function FormsHomePage({ defaultFormSlug = null }: { defaultFormSlug?: st actions={hasRegistryRecords ? taskCards : []} pillsTitle="Browse by type" pills={hasRegistryRecords ? commonTasks : []} - footer={ - hasRegistryRecords ? ( - - ) : ( - registryNotice - ) - } + footer={hasRegistryRecords ? null : registryNotice} /> ); diff --git a/src/components/formulation/formulation-home-page.tsx b/src/components/formulation/formulation-home-page.tsx index 63a28f68aa..e030cac2b5 100644 --- a/src/components/formulation/formulation-home-page.tsx +++ b/src/components/formulation/formulation-home-page.tsx @@ -23,7 +23,7 @@ import { formulationCard, } from "@/components/formulation/formulation-ui"; import { ClinicalPathwayStrip } from "@/components/clinical-record-panels"; -import { ModeHomeMain, ModeHomeTemplate, ModeHomeVerificationFooter } from "@/components/mode-home-template"; +import { ModeHomeMain, ModeHomeTemplate } from "@/components/mode-home-template"; import { SearchResultsHeaderBand, type AppliedFilterChip, @@ -117,15 +117,7 @@ function FormulationHome() { } - footer={ -
- - -
- } + footer={} /> ); diff --git a/src/components/mode-home-template.tsx b/src/components/mode-home-template.tsx index 2bf9e1cb31..fa704ff00c 100644 --- a/src/components/mode-home-template.tsx +++ b/src/components/mode-home-template.tsx @@ -206,25 +206,16 @@ export function ModeHomeMain({ } // One quiet line of text. Deliberately no icon and no accent colour: a shield -// (and especially a ShieldCheck) reads as "verified", which several of these -// footers must not assert — validation status varies per document and is -// surfaced on the results themselves. Hierarchy comes from weight alone, so the -// label half (capability) carries the emphasis rather than the body half (caveat). +// (and especially a ShieldCheck) reads as "verified", which this footer must not +// assert — validation status varies per document and is surfaced on the results +// themselves. Hierarchy comes from weight alone, so the label half (capability) +// carries the emphasis rather than the body half (caveat). // -// Modes whose footer said only what the mode does, with no caveat, no longer -// render this at all; the remaining call sites are the ones whose `body` is a -// genuine review-before-use instruction. -export function ModeHomeVerificationFooter({ - label, - body, - verifiedCount, - totalCount, -}: { - label: string; - body: string; - verifiedCount?: number; - totalCount?: number; -}) { +// No mode home renders this any more: the line under the composer was removed +// from every home page. The sole remaining call site is the therapy-compass +// page footer, which sits at the bottom of the sub-routes and is explicitly not +// rendered on the therapy home (`showFooter={!isHome}` in workspace.tsx). +export function ModeHomeVerificationFooter({ label, body }: { label: string; body: string }) { return (

{/* The separator is bound to the label as one non-breaking flex item. @@ -238,11 +229,6 @@ export function ModeHomeVerificationFooter({ {body} - {typeof verifiedCount === "number" && typeof totalCount === "number" ? ( - - {verifiedCount} of {totalCount} records are locally verified. - - ) : null}

); } diff --git a/src/components/services/services-home-page.tsx b/src/components/services/services-home-page.tsx index b5decbc932..838af7fe60 100644 --- a/src/components/services/services-home-page.tsx +++ b/src/components/services/services-home-page.tsx @@ -6,13 +6,12 @@ import { ModeHomeMain, ModeHomeStatusNotice, ModeHomeTemplate, - ModeHomeVerificationFooter, type ModeHomeAction, type ModeHomePill, } from "@/components/mode-home-template"; import { appModeHomeHref } from "@/lib/app-modes"; import { modeHomeDesktopComposerSlotId } from "@/lib/mode-home-composer"; -import { countVerifiedRegistryRecords, useRegistryRecords } from "@/lib/use-registry-records"; +import { useRegistryRecords } from "@/lib/use-registry-records"; // The default service slug is computed server-side (app/services/page.tsx) and // passed as a prop: a direct `@/lib/services` value import here would compile @@ -91,7 +90,6 @@ const commonPathways: ModeHomePill[] = [ export function ServicesHomePage({ defaultServiceSlug = null }: { defaultServiceSlug?: string | null }) { const taskCards = buildTaskCards(defaultServiceSlug); const registry = useRegistryRecords("service", { view: "summary" }); - const verifiedCount = countVerifiedRegistryRecords(registry); const registryReady = registry.status === "ready" || registry.status === "refetching"; const hasRegistryRecords = registryReady && registry.total > 0; const registryNotice = @@ -142,18 +140,7 @@ export function ServicesHomePage({ defaultServiceSlug = null }: { defaultService actions={hasRegistryRecords ? taskCards : []} pillsTitle="Browse by need" pills={hasRegistryRecords ? commonPathways : []} - footer={ - hasRegistryRecords ? ( - - ) : ( - registryNotice - ) - } + footer={hasRegistryRecords ? null : registryNotice} /> ); diff --git a/src/components/specifiers/specifiers-home-page.tsx b/src/components/specifiers/specifiers-home-page.tsx index 04dd907b25..23860d6477 100644 --- a/src/components/specifiers/specifiers-home-page.tsx +++ b/src/components/specifiers/specifiers-home-page.tsx @@ -6,7 +6,7 @@ import { useId, useMemo, useState } from "react"; import { ArrowRight, ChevronRight, GitCompareArrows, ListChecks, Search, Tags } from "lucide-react"; import { ClinicalPathwayStrip } from "@/components/clinical-record-panels"; -import { ModeHomeMain, ModeHomeTemplate, ModeHomeVerificationFooter } from "@/components/mode-home-template"; +import { ModeHomeMain, ModeHomeTemplate } from "@/components/mode-home-template"; import { SearchResultsHeaderBand, type AppliedFilterChip, @@ -120,15 +120,7 @@ function SpecifiersHome() { } - footer={ -
- - -
- } + footer={} /> ); diff --git a/src/components/therapy-compass/screens/home-screen.tsx b/src/components/therapy-compass/screens/home-screen.tsx index 474ccd72ae..8cd0e33105 100644 --- a/src/components/therapy-compass/screens/home-screen.tsx +++ b/src/components/therapy-compass/screens/home-screen.tsx @@ -3,7 +3,7 @@ import { GitCompareArrows, Network, Search, Sparkles, Waypoints } from "lucide-react"; import { useRouter } from "next/navigation"; -import { ModeHomeMain, ModeHomeTemplate, ModeHomeVerificationFooter } from "@/components/mode-home-template"; +import { ModeHomeMain, ModeHomeTemplate } from "@/components/mode-home-template"; import { modeHomeDesktopComposerSlotId } from "@/lib/mode-home-composer"; import { therapyHrefWithSearchParams, therapyScreenHref } from "@/lib/therapy-compass-navigation"; @@ -67,12 +67,6 @@ export function HomeScreen() { ), icon: Network, }))} - footer={ - - } /> ); diff --git a/src/lib/ui-copy.ts b/src/lib/ui-copy.ts index 3c33032308..d8f2150432 100644 --- a/src/lib/ui-copy.ts +++ b/src/lib/ui-copy.ts @@ -14,22 +14,9 @@ import type { AppModeId } from "@/lib/app-modes"; * never hardcoded here. */ -export type SharedHomeVerification = { - label: string; - body: string; -}; - export type SharedHomePresentation = { title: string; subtitle: string; - /** - * The mode's review-before-use caveat, rendered under the composer. - * - * Optional because it is a genuine instruction, not decoration: modes whose - * footer would only restate what the mode does render nothing, matching the - * rule in `ModeHomeVerificationFooter`. - */ - verification?: SharedHomeVerification; }; /** @@ -45,10 +32,6 @@ export const sharedHomePresentation = { answer: { title: "Clinical Answers", subtitle: "Ask a clinical question or search your documents.", - verification: { - label: "Clinical decision support", - body: "Verify against cited sources before clinical use", - }, }, documents: { title: "Clinical Documents", @@ -57,18 +40,10 @@ export const sharedHomePresentation = { services: { title: "Clinical Services", subtitle: "Search by need, catchment, or route.", - verification: { - label: "Referral fit", - body: "Need, catchment, eligibility and route", - }, }, forms: { title: "Clinical Forms", subtitle: "The WA MHA 2014 forms register.", - verification: { - label: "Source catalogue reviewed", - body: "Official-source MHA 2014 forms · verify before use", - }, }, favourites: { title: "Clinical Favourites", @@ -77,42 +52,22 @@ export const sharedHomePresentation = { differentials: { title: "Differential Diagnosis", subtitle: "Match your catalogue to your library.", - verification: { - label: "Decision support", - body: "Review before use", - }, }, dsm: { title: "DSM-5 Diagnosis", subtitle: "Criteria, specifiers, and comparisons.", - verification: { - label: "Local reference content", - body: "Clinical review required", - }, }, specifiers: { title: "Diagnostic Specifiers", subtitle: "Check specifier fit and exclusions.", - verification: { - label: "Diagnostic decision support", - body: "Review criteria and exclusions before documenting", - }, }, formulation: { title: "Clinical Formulation", subtitle: "Build a formulation from the evidence.", - verification: { - label: "Hypothesis-led decision support", - body: "Check fit, alternatives, risk, and context before using a draft", - }, }, prescribing: { title: "Medication Guidance", subtitle: "Medication dosing and safety.", - verification: { - label: "Prescribing support", - body: "Confirm against source", - }, }, tools: { title: "Clinical Tools", @@ -125,10 +80,6 @@ export const sharedHomePresentation = { "therapy-compass": { title: "Therapy Compass", subtitle: "Source-grounded therapy records.", - verification: { - label: "Decision support", - body: "Source-grounded — review status before clinical use", - }, }, factsheets: { title: "Patient Factsheets", diff --git a/src/lib/use-registry-records.ts b/src/lib/use-registry-records.ts index 8531aca468..dbbb04c51f 100644 --- a/src/lib/use-registry-records.ts +++ b/src/lib/use-registry-records.ts @@ -62,11 +62,6 @@ function recordsState( return { status, records: [], total: 0, verifiedCount: 0, demoMode: false, governance: {}, kind, view, ...extra }; } -/** Count records whose authoritative validation status is reviewed/approved. */ -export function countVerifiedRegistryRecords(state: RegistryRecordsState) { - return state.verifiedCount; -} - /** Owner-scoped registry list (Services/Forms home and search surfaces). Choose * summary for counts-only homes, search for compact identity matching, and * full for result rendering. Pass enabled:false until the mode is active. */ diff --git a/tests/audit-content-services-regressions.test.ts b/tests/audit-content-services-regressions.test.ts index bb53a45971..9bb0be2442 100644 --- a/tests/audit-content-services-regressions.test.ts +++ b/tests/audit-content-services-regressions.test.ts @@ -159,7 +159,11 @@ describe("content and services audit regressions", () => { /Number, pathway, clock|Maker, clock, copies|Browse pathways|Before, current, parallel, after|starter set of MHA 2014 forms|follow a pathway/, ); expect(formsHomeSource).toContain("local confirmation"); - expect(formsHomeSource).toContain("Source catalogue reviewed"); + // The "Source catalogue reviewed · Official-source MHA 2014 forms · verify + // before use" line was removed with every other mode-home caveat footer, so + // the home must not carry it (or a replacement) under the composer. + expect(formsHomeSource).not.toContain("Source catalogue reviewed"); + expect(formsHomeSource).not.toContain("ModeHomeVerificationFooter"); }); it("does not render negative or text-only source statuses as verified", () => { diff --git a/tests/shared-home-empty-state.dom.test.tsx b/tests/shared-home-empty-state.dom.test.tsx index 3972ad886a..ad68c54ec2 100644 --- a/tests/shared-home-empty-state.dom.test.tsx +++ b/tests/shared-home-empty-state.dom.test.tsx @@ -129,13 +129,11 @@ describe("SharedHomeEmptyState", () => { expect(icon).toHaveClass(iconClass); expect(icon).toHaveAttribute("aria-hidden", "true"); - // A mode carrying a review-before-use caveat must show it here; a mode - // without one must not gain filler text. + // No mode home carries a caveat line under the composer any more, and no + // mode may reintroduce one as filler: the presentation table is exactly a + // title and a subtitle. const presentation: SharedHomePresentation = sharedHomePresentation[modeId]; - const verification = presentation.verification; - if (verification) { - expect(screen.getByText(verification.body)).toBeInTheDocument(); - } + expect(Object.keys(presentation).sort()).toEqual(["subtitle", "title"]); }, ); diff --git a/tests/therapy-compass-responsive-contract.test.ts b/tests/therapy-compass-responsive-contract.test.ts index 6155b54f61..45d3d4fc0f 100644 --- a/tests/therapy-compass-responsive-contract.test.ts +++ b/tests/therapy-compass-responsive-contract.test.ts @@ -144,7 +144,10 @@ describe("Therapy Compass responsive contract", () => { // the final row 961px, wrapped one pill, and produced desktop CLS 0.126. expect(modeHomeTemplateSource).not.toContain("sm:gap-2.5"); expect(homeSource).toContain("desktopComposerSlotId={modeHomeDesktopComposerSlotId}"); - expect(homeSource).toContain("ModeHomeVerificationFooter"); + // The caveat footer under the composer was removed from every mode home. + // Therapy keeps its own page-bottom footer, but workspace.tsx renders that + // with `showFooter={!isHome}`, so it must never reappear on the home screen. + expect(homeSource).not.toContain("ModeHomeVerificationFooter"); expect(responsiveStackCount(detailSource)).toBeGreaterThanOrEqual(1); expect(detailSource).toContain("max-sm:static"); expect(responsiveStackCount(compareSource)).toBeGreaterThanOrEqual(1); From 541e73098dfa05cfec17d31b9642df0d9f43ee37 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 18:37:34 +0000 Subject: [PATCH 4/6] Record branch review for the mode-home footer removal Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018kyb3c1iYZ5MGMSNRANzdE --- ...329db567714a1714c37fa301323219bcdaf26e142726d266a32.record.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/branch-review-records/85fbcdfb47931329db567714a1714c37fa301323219bcdaf26e142726d266a32.record.md diff --git a/docs/branch-review-records/85fbcdfb47931329db567714a1714c37fa301323219bcdaf26e142726d266a32.record.md b/docs/branch-review-records/85fbcdfb47931329db567714a1714c37fa301323219bcdaf26e142726d266a32.record.md new file mode 100644 index 0000000000..1bb5f39d28 --- /dev/null +++ b/docs/branch-review-records/85fbcdfb47931329db567714a1714c37fa301323219bcdaf26e142726d266a32.record.md @@ -0,0 +1 @@ +| 2026-08-18 | claude/home-pages-cleanup-qeh5fr | 33ec22afd7b23dfc89fdf836fc80cc4a97c7a065 | remove caveat footer from every mode home | self-review clean; all mode-home caveat footers removed, dead reserve/props/helper deleted | verify:pr-local pass on merged head (673 files / 7281 tests, build, lint, typecheck, offline RAG evals); verify:ui not run — playwright chromium 1234 vs installed 1194 (#255) | From 717472985b6a8f495071b022619f65d532ff342b Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 18:58:35 +0000 Subject: [PATCH 5/6] fix(tests): drop the stale specifiers caveat assertion in ui-tools.spec.ts Production UI (3) was failing: this test still expected the specifiers mode's "Review criteria and exclusions before documenting" caveat to be visible, but 894279bc0 removed the caveat mechanism from every mode home (SharedHomePresentation is now exactly title + subtitle). Three sibling tests were updated in that commit to match (shared-home-empty-state.dom.test.tsx, audit-content-services-regressions.test.ts, therapy-compass-responsive-contract.test.ts); this fourth file was missed. Drops the caveat assertion, keeping the subtitle/icon checks that still apply. --- tests/ui-tools.spec.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/ui-tools.spec.ts b/tests/ui-tools.spec.ts index f8385b72a0..67fa65b92f 100644 --- a/tests/ui-tools.spec.ts +++ b/tests/ui-tools.spec.ts @@ -933,12 +933,10 @@ test.describe("Clinical KB tools directory and legacy launcher", () => { const specifiersModeButton = page.getByRole("button", { name: "Mode Specifiers" }); await expect(specifiersModeButton).toBeFocused(); await expect(sharedHome.getByRole("heading", { level: 2, name: "Diagnostic Specifiers" })).toBeVisible(); - // The shared home carries the mode's own subtitle and caveat, so pin the - // copy itself rather than a paragraph count that moves with the design. + // The shared home carries the mode's own subtitle, so pin the copy itself + // rather than a paragraph count that moves with the design. No mode home + // carries a caveat line under the composer any more. await expect(sharedHome.getByText("Check specifier fit and exclusions.", { exact: true })).toBeVisible(); - await expect( - sharedHome.getByText("Review criteria and exclusions before documenting", { exact: true }), - ).toBeVisible(); await expect(sharedHome.locator(".mode-home-icon svg")).toHaveClass(/\blucide-tags\b/); await expect(visibleGlobalSearchInput(page)).toHaveAttribute( "placeholder", From 124d3a6725af35e3d5d48f84b0e723b39949e178 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 19:01:33 +0000 Subject: [PATCH 6/6] Make the no-caveat-footer rule structurally enforceable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeRabbit flagged that the guards added with the footer removal only rejected a few hand-picked strings in two files, so a renamed component or reworded copy would walk straight past them. That was a fair read of code I had just written. Adds tests/mode-home-no-caveat-footer.test.ts, which enforces the rule by structure instead of by wording: - every mode-home surface (the shared home plus each standalone home) neither imports nor renders ModeHomeVerificationFooter; - the footer has exactly ONE call site repo-wide — the therapy-compass page-bottom footer — and that survivor stays gated `showFooter={!isHome}`. Pinning the count is what catches a second footer appearing somewhere the file does not enumerate; - every sharedHomePresentation entry is exactly a title and a subtitle, which closes the copy route into the same defect. Proven to fail rather than assumed: reintroducing a footer with entirely new wording ("Totally new wording" / "Some other caveat entirely") into the DSM home turns two of these assertions red, including the repo-wide call-site count. The two ad-hoc string checks are reduced to a pointer at this contract. Also fixes the Production UI (3) failure on 541e730. tests/ui-tools.spec.ts still required the specifiers caveat to be VISIBLE on the shared home. My earlier sweep missed it because Playwright specs do not run under `npm run test`, so the unit gate stayed green. The assertion is inverted to toHaveCount(0) rather than deleted, which keeps browser-level proof of the contract that the structural test cannot provide. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018kyb3c1iYZ5MGMSNRANzdE --- ...audit-content-services-regressions.test.ts | 7 +- tests/mode-home-no-caveat-footer.test.ts | 93 +++++++++++++++++++ ...herapy-compass-responsive-contract.test.ts | 8 +- tests/ui-tools.spec.ts | 9 +- 4 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 tests/mode-home-no-caveat-footer.test.ts diff --git a/tests/audit-content-services-regressions.test.ts b/tests/audit-content-services-regressions.test.ts index 9bb0be2442..85595c90b6 100644 --- a/tests/audit-content-services-regressions.test.ts +++ b/tests/audit-content-services-regressions.test.ts @@ -160,10 +160,11 @@ describe("content and services audit regressions", () => { ); expect(formsHomeSource).toContain("local confirmation"); // The "Source catalogue reviewed · Official-source MHA 2014 forms · verify - // before use" line was removed with every other mode-home caveat footer, so - // the home must not carry it (or a replacement) under the composer. + // before use" line went with every other mode-home caveat footer. The + // enforceable version of that rule lives in tests/mode-home-no-caveat-footer.test.ts, + // which pins the footer's call sites structurally; a bare string check here + // would pass against a reworded or differently-named replacement. expect(formsHomeSource).not.toContain("Source catalogue reviewed"); - expect(formsHomeSource).not.toContain("ModeHomeVerificationFooter"); }); it("does not render negative or text-only source statuses as verified", () => { diff --git a/tests/mode-home-no-caveat-footer.test.ts b/tests/mode-home-no-caveat-footer.test.ts new file mode 100644 index 0000000000..7b000b8195 --- /dev/null +++ b/tests/mode-home-no-caveat-footer.test.ts @@ -0,0 +1,93 @@ +import { readFileSync } from "node:fs"; +import { readdirSync, statSync } from "node:fs"; +import { join, relative } from "node:path"; +import { describe, expect, it } from "vitest"; + +import { appModeIds } from "@/lib/app-modes"; +import { sharedHomePresentation } from "@/lib/ui-copy"; + +/** + * The caveat line under the composer — `ModeHomeVerificationFooter` — was removed + * from every mode home. This file is the contract that keeps it removed. + * + * It exists because the first attempt at that guard asserted the absence of a few + * hand-picked strings ("Source catalogue reviewed", …) in two files. A different + * footer component, or the same idea with reworded copy, would have walked + * straight past it. These checks are structural instead: they pin the number and + * location of call sites, and the shape of the copy table, so reintroducing the + * line anywhere on a home has to fail here rather than depending on which words + * someone chose. + */ + +const REPO_ROOT = process.cwd(); +const FOOTER = "ModeHomeVerificationFooter"; + +/** Every surface that renders a mode's home. */ +const MODE_HOME_SOURCES = [ + // The shared home at `/`, which is the only home most modes have. + "src/components/clinical-dashboard/answer-status.tsx", + // Standalone mode homes. + "src/components/calculators/home-page.tsx", + "src/components/dictionary/dictionary-home-page.tsx", + "src/components/differentials/differentials-home-page.tsx", + "src/components/dsm/dsm-home-page.tsx", + "src/components/factsheets/factsheets-home-page.tsx", + "src/components/forms/forms-home-page.tsx", + "src/components/formulation/formulation-home-page.tsx", + "src/components/services/services-home-page.tsx", + "src/components/specifiers/specifiers-home-page.tsx", + "src/components/clinical-dashboard/differentials-home.tsx", + "src/components/clinical-dashboard/medication-prescribing-workspace.tsx", + "src/components/therapy-compass/screens/home-screen.tsx", +] as const; + +/** + * The one legitimate survivor: Therapy's page-bottom footer, which sits below a + * divider at the end of its sub-routes. `workspace.tsx` renders it with + * `showFooter={!isHome}`, so it is not a home-page element. + */ +const THERAPY_PAGE_FOOTER = "src/components/therapy-compass/workspace.tsx"; + +function sourceFiles(dir: string, collected: string[] = []) { + for (const entry of readdirSync(dir)) { + const full = join(dir, entry); + if (statSync(full).isDirectory()) { + sourceFiles(full, collected); + continue; + } + if (/\.(?:ts|tsx)$/.test(entry)) collected.push(full); + } + return collected; +} + +describe("mode homes carry no caveat footer", () => { + it.each(MODE_HOME_SOURCES)("%s neither imports nor renders the footer", (path) => { + const source = readFileSync(join(REPO_ROOT, path), "utf8"); + expect(source).not.toContain(FOOTER); + }); + + it("keeps exactly one call site repo-wide, and it is not a home", () => { + // Pinning the count is what catches a *second* footer appearing somewhere + // this file does not enumerate — a new mode home, or a shared component that + // every home happens to render. + const callSites = sourceFiles(join(REPO_ROOT, "src")) + .filter((file) => readFileSync(file, "utf8").includes(FOOTER)) + .map((file) => relative(REPO_ROOT, file).split("\\").join("/")) + .filter((file) => file !== "src/components/mode-home-template.tsx") + .sort(); + + expect(callSites).toEqual([THERAPY_PAGE_FOOTER]); + + // …and that survivor stays gated off the Therapy home. + const workspace = readFileSync(join(REPO_ROOT, THERAPY_PAGE_FOOTER), "utf8"); + expect(workspace).toContain("showFooter={!isHome}"); + }); + + it("leaves no caveat copy in the shared-home presentation table", () => { + // The copy route into the same defect: a mode could carry the line as data + // rather than as a component. Every entry is exactly a title and a subtitle. + for (const modeId of appModeIds) { + expect(Object.keys(sharedHomePresentation[modeId]).sort(), modeId).toEqual(["subtitle", "title"]); + } + }); +}); diff --git a/tests/therapy-compass-responsive-contract.test.ts b/tests/therapy-compass-responsive-contract.test.ts index 45d3d4fc0f..cfd21e14f6 100644 --- a/tests/therapy-compass-responsive-contract.test.ts +++ b/tests/therapy-compass-responsive-contract.test.ts @@ -144,10 +144,10 @@ describe("Therapy Compass responsive contract", () => { // the final row 961px, wrapped one pill, and produced desktop CLS 0.126. expect(modeHomeTemplateSource).not.toContain("sm:gap-2.5"); expect(homeSource).toContain("desktopComposerSlotId={modeHomeDesktopComposerSlotId}"); - // The caveat footer under the composer was removed from every mode home. - // Therapy keeps its own page-bottom footer, but workspace.tsx renders that - // with `showFooter={!isHome}`, so it must never reappear on the home screen. - expect(homeSource).not.toContain("ModeHomeVerificationFooter"); + // The caveat footer under the composer was removed from every mode home; + // Therapy keeps only its page-bottom footer, gated `showFooter={!isHome}`. + // Both halves of that are enforced structurally in + // tests/mode-home-no-caveat-footer.test.ts rather than by name here. expect(responsiveStackCount(detailSource)).toBeGreaterThanOrEqual(1); expect(detailSource).toContain("max-sm:static"); expect(responsiveStackCount(compareSource)).toBeGreaterThanOrEqual(1); diff --git a/tests/ui-tools.spec.ts b/tests/ui-tools.spec.ts index f8385b72a0..b72367d78c 100644 --- a/tests/ui-tools.spec.ts +++ b/tests/ui-tools.spec.ts @@ -933,12 +933,15 @@ test.describe("Clinical KB tools directory and legacy launcher", () => { const specifiersModeButton = page.getByRole("button", { name: "Mode Specifiers" }); await expect(specifiersModeButton).toBeFocused(); await expect(sharedHome.getByRole("heading", { level: 2, name: "Diagnostic Specifiers" })).toBeVisible(); - // The shared home carries the mode's own subtitle and caveat, so pin the - // copy itself rather than a paragraph count that moves with the design. + // The shared home carries the mode's own subtitle, so pin the copy itself + // rather than a paragraph count that moves with the design. await expect(sharedHome.getByText("Check specifier fit and exclusions.", { exact: true })).toBeVisible(); + // The caveat line that used to sit under the composer is gone from every + // mode home. This is the browser-level half of that contract — the + // structural half is tests/mode-home-no-caveat-footer.test.ts. await expect( sharedHome.getByText("Review criteria and exclusions before documenting", { exact: true }), - ).toBeVisible(); + ).toHaveCount(0); await expect(sharedHome.locator(".mode-home-icon svg")).toHaveClass(/\blucide-tags\b/); await expect(visibleGlobalSearchInput(page)).toHaveAttribute( "placeholder",