Files
HealthLog/src/lib/insights/briefing-payload.ts
T
Marc-André Bombeck a4feabec81 chore(release): v1.28.30 — the daily briefing stops silently skipping days
The recurring no-briefing day had a chain of causes, closed end to end:

Every failure path in the nightly pregenerate + the comprehensive generator
now annotates a queryable cause (several classes — features-error,
payload-too-large, aborted, generator-failed — previously bumped a counter
with zero trace). A failed nightly warm enqueues one bounded retry ~45
minutes later (singleton per user, existing budgets apply), so a transient
provider hiccup heals before morning. A cached payload that carries NO
briefing no longer satisfies the 24h POST short-circuit nor the
unchanged-content hash gate — a once-stripped briefing could previously
block its own regeneration indefinitely. The card surfaces the omission
reason persistently (grounding strip, generation failure, not attempted)
with a forcing retry.

Documentation corrected against code truth: Withings credentials are
per-user (the documented env path never existed; the dead example entries
and manifest rows are gone, and WITHINGS_WEBHOOK_SECRET is now actually
whitelisted in compose — stock deploys could never deliver it); the classic
Fitbit portal no longer accepts new registrations; the backup-restore
example no longer mints a fresh encryption key and uses pnpm dlx tsx; the
TLS guide describes the real client model (two CA-level SPKI pins,
any-match, leaf renewals need no build); scaling/admin references fixed;
the operator-shared subscription provider is documented.
2026-07-12 11:08:59 +02:00

27 lines
980 B
TypeScript

/**
* v1.28.30 — does a cached comprehensive payload actually carry a daily
* briefing?
*
* Shared by the generator's content-hash gate and the POST route's 24 h
* short-circuit: a fresh-but-briefingless cache must not satisfy a
* briefing-expecting caller for the rest of the day (the "one silent
* nightly failure + 24 h cache = a full day without a briefing" chain).
* Unparseable text counts as briefingless — regeneration repairs it.
*
* Lives in its own leaf module (no provider-tree imports) so the route
* can consume it without pulling the whole generation pipeline into its
* bundle, and tests that mock `comprehensive-generate` keep the real
* implementation.
*/
export function cachedPayloadCarriesBriefing(
cachedText: string | null | undefined,
): boolean {
if (!cachedText) return false;
try {
const parsed = JSON.parse(cachedText) as Record<string, unknown>;
return parsed.dailyBriefing != null;
} catch {
return false;
}
}