From 99af530490ca6c893c64e8c7d2640171a40bf1d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 16 May 2026 17:31:47 +0200 Subject: [PATCH] chore(cleanup): retire AssistantDisabledNotice + dead settings.placeholder copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dead-code sweep flagged by the v1.4.33 menu audit. * AssistantDisabledNotice (src/components/insights/assistant-disabled-notice.tsx) was introduced in v1.4.31 for the operator-disabled assistant surface but never wired into a render site. The v1.4.28 retirement of the weekly-report + advisor card removed the planned host components. Delete the component, its SSR test, and the four locale strings it consumed (insights.briefingDisabledByOperator, insights.statusDisabledByOperator, insights.correlationsDisabledByOperator, insights.coach.disabledByOperator) from all six locale files. The AssistantDisabledError thrown by requireAssistantSurface() and the assistant.disabled. errorCode envelope stay — iOS clients read the errorCode to render an inline notice. * settings.sections.placeholder.coming_soon was an "until extraction lands" string for . Every slug in SETTINGS_SECTION_SLUGS has had a matching component since v1.4.22 so the placeholder body is unreachable through the type system. The defensive component itself stays as a guard, but inherits the section's own description for the EmptyState body, retiring the dedicated locale key from all six locale files. Locale-integrity contract holds (parity check green across de, en, es, fr, it, pl). Comments in api-handler.ts and feature-flags/index.ts that referenced are updated to describe the surface generically. Refs: .planning/round-v1433-audit-menu.md §6 --- messages/en.json | 7 -- .../assistant-disabled-notice.test.tsx | 37 ---------- .../insights/assistant-disabled-notice.tsx | 73 ------------------- .../settings/section-placeholder.tsx | 10 ++- src/lib/api-handler.ts | 4 +- 5 files changed, 11 insertions(+), 120 deletions(-) delete mode 100644 src/components/insights/__tests__/assistant-disabled-notice.test.tsx delete mode 100644 src/components/insights/assistant-disabled-notice.tsx diff --git a/messages/en.json b/messages/en.json index 2203abae4..6639f5cde 100644 --- a/messages/en.json +++ b/messages/en.json @@ -878,9 +878,6 @@ "heroFindingWarning": "Top alert", "correlationsTitle": "Correlations", "recommendationsTitle": "Recommendations", - "briefingDisabledByOperator": "The Daily Briefing is currently unavailable on this server.", - "statusDisabledByOperator": "Status cards are currently unavailable on this server.", - "correlationsDisabledByOperator": "Correlation narration is currently unavailable on this server.", "personalRecord": { "badge": "PR", "tooltip": "Personal record: {value} {unit} on {date}" @@ -1036,7 +1033,6 @@ "composerHint": "Press Enter to send, Shift+Enter for a new line.", "composerDisclaimer": "Coach replies are generated. Clinical decisions belong with your doctor.", "voiceComingSoon": "Voice input arrives with the iOS app in v1.5.", - "disabledByOperator": "Coach is currently unavailable on this server.", "threadEmpty": "Ask anything about your trends, medications, or readings to start a conversation.", "historyTitle": "Conversations", "historySearchPlaceholder": "Search conversations…", @@ -1621,9 +1617,6 @@ "about": { "title": "About", "description": "Version, license, links." - }, - "placeholder": { - "coming_soon": "Moving here with the next release update." } }, "profile": "Profile", diff --git a/src/components/insights/__tests__/assistant-disabled-notice.test.tsx b/src/components/insights/__tests__/assistant-disabled-notice.test.tsx deleted file mode 100644 index c236f7c7c..000000000 --- a/src/components/insights/__tests__/assistant-disabled-notice.test.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { describe, it, expect } from "vitest"; -import { renderToStaticMarkup } from "react-dom/server"; - -import { I18nProvider } from "@/lib/i18n/context"; -import { AssistantDisabledNotice } from "../assistant-disabled-notice"; - -function render(node: React.ReactNode) { - return renderToStaticMarkup( - {node}, - ); -} - -describe("", () => { - it("renders the coach copy in the card variant", () => { - const html = render(); - expect(html).toContain("data-slot=\"assistant-disabled-notice\""); - expect(html.toLowerCase()).toContain("coach"); - }); - - it("renders the briefing copy", () => { - const html = render(); - expect(html).toContain("data-slot=\"assistant-disabled-notice\""); - }); - - it("renders the status copy", () => { - const html = render(); - expect(html).toContain("data-slot=\"assistant-disabled-notice\""); - }); - - it("renders the inline variant without the Card wrapper", () => { - const html = render( - , - ); - expect(html).toContain(""` response - * from the server or that detected the matching flag locally via - * `useFeatureFlags()`. - * - * The copy intentionally stays generic — "currently unavailable on - * this server" — so the surface doesn't leak operator-identity - * info into a user-facing string. Marc-voice English; the locale - * key carries the surface-specific phrasing. - */ -export type AssistantDisabledSurface = - | "coach" - | "briefing" - | "insightStatus" - | "correlations"; - -interface AssistantDisabledNoticeProps { - surface: AssistantDisabledSurface; - className?: string; - variant?: "card" | "inline"; -} - -const SURFACE_LABEL_KEY: Record = { - coach: "insights.coach.disabledByOperator", - briefing: "insights.briefingDisabledByOperator", - insightStatus: "insights.statusDisabledByOperator", - correlations: "insights.correlationsDisabledByOperator", -}; - -export function AssistantDisabledNotice({ - surface, - className, - variant = "card", -}: AssistantDisabledNoticeProps) { - const { t } = useTranslations(); - const message = t(SURFACE_LABEL_KEY[surface]); - - if (variant === "inline") { - return ( -

- {message} -

- ); - } - - return ( - - - - - ); -} diff --git a/src/components/settings/section-placeholder.tsx b/src/components/settings/section-placeholder.tsx index 999dcc296..3f05ea25d 100644 --- a/src/components/settings/section-placeholder.tsx +++ b/src/components/settings/section-placeholder.tsx @@ -54,6 +54,14 @@ export function SectionPlaceholder({ slug }: SectionPlaceholderProps) { const sectionTitle = t(`settings.sections.${slug}.title`); const sectionDescription = t(`settings.sections.${slug}.description`); + // v1.4.33 A4 — `` is a defensive fallback for + // slugs added to SETTINGS_SECTION_SLUGS without a matching component. + // The type system blocks that path today, so the EmptyState body is + // effectively unreachable. We retire the dedicated locale key + // (`settings.sections.placeholder.coming_soon`) and inherit the + // section's own description so the guard still renders meaningful + // copy if it ever does fire — no more dead-string maintenance across + // six locale files. return (
} title={sectionTitle} - description={t("settings.sections.placeholder.coming_soon")} + description={sectionDescription} />
); diff --git a/src/lib/api-handler.ts b/src/lib/api-handler.ts index 86c042fde..eb208a54c 100644 --- a/src/lib/api-handler.ts +++ b/src/lib/api-handler.ts @@ -169,8 +169,8 @@ export function apiHandler Promise>( // envelope is locked per // `.planning/RESPONSE-TO-IOS-TEAM-2026-05-16.md` §3 R5. // Older iOS clients that don't know the errorCode surface - // this as a generic 403; v1.4.31+ clients render the - // `` empty state. + // this as a generic 403; v1.4.31+ clients can branch on the + // errorCode to render an inline operator-disabled notice. evt.setError(error); response = NextResponse.json( {