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) | 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 | 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/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/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/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/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/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/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/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; 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..85595c90b6 100644 --- a/tests/audit-content-services-regressions.test.ts +++ b/tests/audit-content-services-regressions.test.ts @@ -159,7 +159,12 @@ 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 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"); }); 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/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..cfd21e14f6 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 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..824e90be7c 100644 --- a/tests/ui-tools.spec.ts +++ b/tests/ui-tools.spec.ts @@ -933,12 +933,16 @@ 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(); + // Asserted absent rather than simply deleted: this is the browser-level half + // of the no-caveat contract, which the structural half in + // tests/mode-home-no-caveat-footer.test.ts cannot provide. 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",