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",