Require the `insights` module (in addition to the existing assistant-surface
gate and any per-metric data-module gate) on all 14 narrative insights
routes: blood-pressure / bmi / pulse / weight / medication-compliance /
mood / metric / derived / derived-batch status, cards, correlations,
narrative, pregenerate, and rhythm-events. A 403 module.disabled envelope
now precedes any provider or cache work when the account has insights off.
The per-metric sleep/glucose/recovery/mood gates and the
requireAssistantSurface("insightStatus"|"correlations") checks are kept;
this adds the module layer on top of them.
Route tests that now resolve the gate mock @/lib/modules/gate
default-enabled so their existing data-shape and assistant-flag assertions
ride through unchanged.
When no AI provider is configured (or before the first AI summary is written),
the period-in-review card stayed empty. Compose a concise, factual, strictly
non-causal summary from the same structured digest the AI prompt is built from
— ranked metric changes vs the prior period, vitals that moved outside their
typical range, and an honest count of statistical associations — and persist it
with a `deterministic` provider marker so a later AI warm replaces it in place.
The read route now warms regardless of provider; the read-never-blocks posture
is unchanged. Fills the no-key demo's retrospective too.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a calm "your week / month in review" summary to the Insights
overview, generated from the period-narrative context (deltas, personal
bands, FDR-controlled associations, coincident days).
- New insight_narratives table (migration 0113): one durable row per
(user, period, locale); generated prose AES-256-GCM at rest following
the coach-message precedent; labels-only provenance stays plaintext.
- generatePeriodNarrative feeds the context into the provider chain with
a tight, descriptive-never-causal prompt; an insufficient context
yields no narrative, a missing provider no-ops, neither fabricates.
- Nightly warm cron on week (Mon) / month (1st) boundaries, budget-gated
per user; the read-only GET enqueues a single-user warm on a cold read.
- Read route is stale-while-revalidate and never blocks on the provider;
the card renders plain text (no markdown), a single provenance
disclosure, and a fixed footprint (no CLS). i18n in all six locales.