", () => {
- 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 (
-
-
-
- {message}
-
-
- );
-}
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(
{