diff --git a/src/components/insights/__tests__/recommendation-card-integration.test.tsx b/src/components/insights/__tests__/recommendation-card-integration.test.tsx
new file mode 100644
index 000000000..d574d5e5b
--- /dev/null
+++ b/src/components/insights/__tests__/recommendation-card-integration.test.tsx
@@ -0,0 +1,178 @@
+import { describe, it, expect, vi } from "vitest";
+import { renderToStaticMarkup } from "react-dom/server";
+
+vi.mock("@/components/charts/health-chart", () => ({
+ HealthChart: ({
+ types,
+ title,
+ mini,
+ windowOverride,
+ }: {
+ types: string[];
+ title: string;
+ mini?: boolean;
+ windowOverride?: string;
+ }) => (
+
+ chart:{title}
+
+ ),
+}));
+
+vi.mock("@/components/charts/mood-chart", () => ({
+ MoodChart: ({ mini }: { mini?: boolean }) => (
+
+ ),
+}));
+
+vi.mock("@tanstack/react-query", () => ({
+ useQuery: () => ({ data: null, isLoading: false }),
+ useQueryClient: () => ({ invalidateQueries: vi.fn() }),
+}));
+
+import { I18nProvider } from "@/lib/i18n/context";
+import { InsightAdvisorCard } from "../insight-advisor-card";
+import type { InsightResult } from "@/lib/ai/types";
+import { generateInsight } from "@/lib/ai/generate-insight";
+import { MockAIProvider } from "@/lib/ai/mock-client";
+import { MEDICAL_REFERENCES } from "@/lib/ai/medical-references";
+
+/**
+ * v1.4.16 phase B5c — full-flow integration.
+ *
+ * Mocks an AIProvider that returns a structured payload with
+ * rationale on every rec, runs `generateInsight()` to validate +
+ * parse, then feeds the parsed payload through InsightAdvisorCard.
+ * Asserts the advisor card surfaces the rec text + rationale rows
+ * via the RecommendationCard subcomponent.
+ *
+ * The advisor card consumes the legacy `InsightResult` shape, not
+ * the strict `AIInsightResponse` — but the new field schema is
+ * optional on the UI type, so a recommendation flowing in as a
+ * structured object with rationale renders the expand-card.
+ */
+
+const knownRefId = MEDICAL_REFERENCES[0].id;
+
+const strictPayload = {
+ summary: "Your blood pressure is elevated against your own baseline.",
+ recommendations: [
+ {
+ id: "rec-1",
+ text: "Discuss home BP log with your physician.",
+ severity: "important",
+ metricSource: {
+ type: "bloodPressure",
+ timeRange: "last7days",
+ summary: "avg 138/86 across 9 readings",
+ n: 9,
+ },
+ rationale: {
+ dataWindow: "last7days",
+ comparedTo: "your 90-day median (122/78)",
+ deviation: "+16/+8 mmHg above baseline over 9 of 9 readings",
+ },
+ referenceId: knownRefId,
+ },
+ ],
+ citations: [
+ {
+ type: "bloodPressure",
+ timeRange: "last7days",
+ summary: "avg 138/86 across 9 readings",
+ },
+ ],
+ warnings: [],
+};
+
+describe("end-to-end — generateInsight() + RecommendationCard render", () => {
+ it("strict payload from MockAIProvider passes parse + flows through to RecommendationCard rationale rows", async () => {
+ const provider = new MockAIProvider({
+ responses: JSON.stringify(strictPayload),
+ });
+
+ const outcome = await generateInsight(provider, {
+ systemPrompt: "system",
+ userPrompt: "user",
+ });
+
+ expect(outcome.parsed.recommendations).toHaveLength(1);
+ const rec = outcome.parsed.recommendations[0];
+ expect(rec.rationale).toEqual({
+ dataWindow: "last7days",
+ comparedTo: "your 90-day median (122/78)",
+ deviation: "+16/+8 mmHg above baseline over 9 of 9 readings",
+ });
+
+ // Wrap as an InsightResult (legacy UI-shape) — only the
+ // recommendations need to carry the new fields for the rec card
+ // to render the expand panel.
+ const insight: InsightResult = {
+ insightType: "general",
+ summary: outcome.parsed.summary,
+ classification: "grenzwertig",
+ classificationLabel: "Borderline",
+ findings: [],
+ correlations: [],
+ recommendations: outcome.parsed.recommendations.map((r) => ({
+ text: r.text,
+ referenceId: r.referenceId,
+ rationale: r.rationale,
+ metricSource: r.metricSource,
+ severity: r.severity,
+ id: r.id,
+ })),
+ dataQuality: { coverage: "good", gaps: [], confidence: "hoch" },
+ disclaimer: "Not a substitute for medical advice.",
+ };
+
+ const html = renderToStaticMarkup(
+
+
+ ,
+ );
+
+ // The rec card is collapsed by default — assert chevron present.
+ expect(html).toContain("Discuss home BP log");
+ expect(html).toMatch(/aria-expanded="false"/);
+ // Severity badge
+ expect(html).toContain("important");
+ });
+
+ it("legacyPayload flag surfaces the regenerate CTA", () => {
+ const insight: InsightResult = {
+ insightType: "general",
+ summary: "x",
+ classification: "gut",
+ classificationLabel: "Good",
+ findings: [],
+ correlations: [],
+ recommendations: ["Plain string rec"],
+ dataQuality: { coverage: "good", gaps: [], confidence: "hoch" },
+ disclaimer: "Disclaimer",
+ };
+
+ const html = renderToStaticMarkup(
+
+ {}}
+ />
+ ,
+ );
+
+ expect(html).toContain('data-slot="insight-legacy-payload-cta"');
+ expect(html).toContain("Insights updated");
+ });
+});