mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
feat(insights): wire CorrelationRow + TrendsRow into /insights
Compute the three pre-defined correlation hypotheses (BP × compliance, mood × pulse, weight × weekday) on the trailing 30-day window in `/api/analytics` and surface the typed result shapes on the response payload. Each runner is gated on n >= 14 + p < 0.05; below the bar the result.status === "insufficient" and the per-card EmptyState paints in place of a misleading near-zero scatter. The insights page now mounts: - `<CorrelationRow>` between the Daily Briefing and the Advisor card — the layout slot the artboard reserves for the patterns surface. - `<TrendsRow>` immediately below it, fed from `advisor.payload.trendAnnotations` (lifted client-side via `trendAnnotationsSchema.safeParse`). Legacy cached payloads predating PROMPT_VERSION 4.20.1 surface the per-metric empty-state hint instead of a half-rendered annotation. The wide-event annotation captures per-hypothesis status so admin observability can attribute coverage gaps without re-querying the DB. 10 source-scan tests pin the load-bearing imports, the JSX mounts, the analytics-route surfacing, and the malformed-payload null fallback in the advisor hook. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
42591c6cec
commit
c83cb2311d
4 files changed
+359
No files matched your search
@@ -4,7 +4,9 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import type { InsightResult } from "@/lib/ai/types";
|
||||
import {
|
||||
dailyBriefingSchema,
|
||||
trendAnnotationsSchema,
|
||||
type DailyBriefing as DailyBriefingPayload,
|
||||
type TrendAnnotations,
|
||||
} from "@/lib/ai/schema";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
|
||||
@@ -39,6 +41,12 @@ export interface InsightAdvisorPayload {
|
||||
* malformed payload from poisoning the briefing card.
|
||||
*/
|
||||
dailyBriefing?: DailyBriefingPayload | null;
|
||||
/**
|
||||
* v1.4.20 phase B3 — optional trend annotations for the Trends row.
|
||||
* Same lift-pattern as `dailyBriefing` — validated client-side and
|
||||
* left null when the cached payload predates PROMPT_VERSION 4.20.1.
|
||||
*/
|
||||
trendAnnotations?: TrendAnnotations | null;
|
||||
}
|
||||
|
||||
async function fetchAdvisor(
|
||||
@@ -77,6 +85,19 @@ async function fetchAdvisor(
|
||||
} else {
|
||||
payload.dailyBriefing = null;
|
||||
}
|
||||
|
||||
// v1.4.20 phase B3 — same lift for `trendAnnotations`. Cached payloads
|
||||
// from the 4.20.0 line predate the field, so null is the expected
|
||||
// default. A malformed candidate also resolves to null so the UI
|
||||
// surfaces the per-metric empty hint instead of a half-rendered card.
|
||||
const annotationsCandidate = (payload?.insights as Record<string, unknown>)
|
||||
?.trendAnnotations;
|
||||
if (annotationsCandidate != null) {
|
||||
const parsed = trendAnnotationsSchema.safeParse(annotationsCandidate);
|
||||
payload.trendAnnotations = parsed.success ? parsed.data : null;
|
||||
} else {
|
||||
payload.trendAnnotations = null;
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user