diff --git a/src/lib/insights/derived/__tests__/dispatch.test.ts b/src/lib/insights/derived/__tests__/dispatch.test.ts index 6babe8d0a..2f595b115 100644 --- a/src/lib/insights/derived/__tests__/dispatch.test.ts +++ b/src/lib/insights/derived/__tests__/dispatch.test.ts @@ -27,22 +27,15 @@ const NOW = new Date("2026-06-02T07:00:00Z"); beforeEach(() => vi.clearAllMocks()); describe("registry", () => { - it("exposes the implemented vitals-tier metrics and the composite stubs", () => { + it("exposes every derived metric as implemented", () => { expect(getDerivedMetricMeta("VITALS_BASELINE")?.implemented).toBe(true); expect(getDerivedMetricMeta("FITNESS_AGE")?.implemented).toBe(true); expect(getDerivedMetricMeta("VASCULAR_AGE_DELTA")?.implemented).toBe(true); expect(getDerivedMetricMeta("HRV_BALANCE")?.implemented).toBe(true); expect(getDerivedMetricMeta("BMI")?.implemented).toBe(true); - // Composites still land in W3. - expect(getDerivedMetricMeta("READINESS")?.implemented).toBe(false); - expect(getDerivedMetricMeta("COINCIDENT_DEVIATION")?.implemented).toBe(false); - it("exposes the flagship + W3 composites as implemented; the passthroughs stay stubs", () => { - expect(getDerivedMetricMeta("VITALS_BASELINE")?.implemented).toBe(true); expect(getDerivedMetricMeta("SLEEP_SCORE")?.implemented).toBe(true); expect(getDerivedMetricMeta("READINESS")?.implemented).toBe(true); expect(getDerivedMetricMeta("COINCIDENT_DEVIATION")?.implemented).toBe(true); - // FITNESS_AGE + VASCULAR_AGE_DELTA land in a sibling wave. - expect(getDerivedMetricMeta("FITNESS_AGE")?.implemented).toBe(false); }); it("isDerivedMetricId rejects unknown ids", () => { @@ -76,7 +69,7 @@ describe("computeDerivedMetric dispatch", () => { expect(result.status).toBe("insufficient"); }); - it("returns not_implemented for a stubbed metric (never a 500)", async () => { + it("routes FITNESS_AGE to its engine (no data → insufficient, not not_implemented)", async () => { const result = await computeDerivedMetric({ metric: "FITNESS_AGE", userId: "u1", @@ -85,7 +78,7 @@ describe("computeDerivedMetric dispatch", () => { }); expect(result.status).toBe("insufficient"); if (result.status === "insufficient") { - expect(result.reason).toBe("not_implemented"); + expect(result.reason).not.toBe("not_implemented"); } }); diff --git a/src/lib/insights/derived/dispatch.ts b/src/lib/insights/derived/dispatch.ts index c393f7535..d09346df2 100644 --- a/src/lib/insights/derived/dispatch.ts +++ b/src/lib/insights/derived/dispatch.ts @@ -124,6 +124,9 @@ export async function computeDerivedMetric( }) as Promise>; case "BMI": return computeBmi(args.userId, args.profile, { + windowDays: args.windowDays, + now, + }) as Promise>; case "SLEEP_SCORE": return computeSleepScore(args.userId, args.profile, { windowDays: args.windowDays, diff --git a/src/lib/query-keys.ts b/src/lib/query-keys.ts index 2f3e9652a..f9101c8c7 100644 --- a/src/lib/query-keys.ts +++ b/src/lib/query-keys.ts @@ -143,6 +143,7 @@ export const queryKeys = { */ insightsDerived: (metric: string, type?: string | null) => ["insights", "derived", metric, type ?? null] as const, + /** * v1.10.0 — a derived wellness metric (`/api/insights/derived?metric=…`). * One generic route backs every derived composite (sleep score, * readiness, coincident-deviation, vitals baseline, …) so the key is