chore(release): v1.12.12 — deterministic fallback so the period retrospective is never empty

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>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.8 committed 2026-06-05 19:10:08 +02:00
1 parent f0fe834283
commit f25b6aa2dc
9 files changed
+457 -49

No files matched your search

+7 -5
View File
@@ -18,7 +18,6 @@ import { apiHandler, requireAuth } from "@/lib/api-handler";
import { annotate } from "@/lib/logging/context";
import { resolveServerLocale } from "@/lib/i18n/server-locale";
import { requireAssistantSurface } from "@/lib/feature-flags";
import { hasUsableStatusProvider } from "@/lib/insights/status-provider";
import { readPeriodNarrative } from "@/lib/insights/narrative/period-narrative-generate";
import { PERIOD_DAYS, type NarrativePeriod } from "@/lib/insights/narrative/period-narrative";
import { enqueueNarrativeWarm } from "@/lib/jobs/period-narrative-shared";
@@ -66,11 +65,14 @@ export const GET = apiHandler(async (request: NextRequest) => {
existing !== null &&
Date.now() - new Date(existing.updatedAt).getTime() < NARRATIVE_FRESH_MS;
// Read-only: never block on the provider. Warm out of band only when stale
// / missing AND a provider is configured (a provider-less account costs one
// cheap chain-resolve and shows the no-key state instead).
// Read-only: never block on the provider. Warm out of band whenever the row
// is stale / missing. The generator produces AI prose when a provider is
// configured and a deterministic, non-causal fallback otherwise, so even a
// provider-less account (incl. the no-key demo) gets a non-empty
// retrospective on the next read. The enqueue's singletonKey + the 20 h
// freshness window bound this to at most one warm per period per ~day.
let revalidating = false;
if (!isFresh && (await hasUsableStatusProvider(user.id))) {
if (!isFresh) {
void enqueueNarrativeWarm({ userId: user.id, period, locale });
revalidating = true;
}