feat(mood): add the prediction table, with one writer and no writer yet

`MoodPrediction` holds the expected value of a day beside the day's own
rating: one row per account per local day, with a band and the number of
days the fit used. Two tables rather than four columns on the entry,
because the point of the second value is that the person cannot correct
it into agreement with the first — the distance between them is the
finding, and a value the edit form can write is not a second reading.

The table stays out of the disaster-recovery backup and the reason is
written where the completeness guard reads it: every row is recomputable
from the entries, the contexts and the linked modules, and carrying one
would restore a forecast made by a model version that may no longer
exist against data the restore has just moved. It is in the wipe plan,
because a derived row is still a day-by-day statement about somebody.

The write-surface guard lands red on purpose and names what is missing:
`lib/jobs/mood-prognosis-refresh.ts` does not exist yet, so the writer
set is empty where it should hold exactly that one file. The job closes
it. The rest of the guard is green now — no route, page or component
writes the table, and the matcher proves itself against a call broken
across lines, an aliased client, a read and a different model.
This commit is contained in:
Marc-André Bombeck committed 2026-08-08 11:10:25 +02:00
1 parent 779b7bcaf1
commit a118d4810d
5 files changed
+274

No files matched your search

+6
View File
@@ -75,6 +75,12 @@ export const WIPE_MODELS = [
// but a parent deleted first leaves the child's own count reporting zero for
// rows that existed, and the confirmation screen quotes those counts.
"MoodContext",
// Derived, and wiped anyway. The forecast rows are recomputable from the
// entries above — which is why they stay out of the backup — but they are
// still a day-by-day statement about somebody's mood, and leaving them
// behind after a screen that promised to delete all health data would leave
// the shape of the record standing where the record used to be.
"MoodPrediction",
"MoodEntry",
"MoodEntryRollup",
"MoodReminderDispatch",
+2
View File
@@ -342,6 +342,8 @@ export const DERIVED_MODELS: Readonly<Record<string, string>> = {
"Recomputed from `MedicationIntakeEvent` against the schedule by the compliance analytics tier.",
MoodEntryRollup:
"A per-day reconstruction of `MoodEntry`, rebuilt by the same rollup tier that rebuilds the measurement one.",
MoodPrediction:
"What the account's own past days imply about a day, fitted from `MoodEntry` + `MoodContext` and the linked modules. The nightly `mood-prognosis-refresh` job rebuilds it after a restore, and rebuilding it is better than carrying it: a restored row would state a forecast made by a model version that may no longer exist, against data the restore has just moved.",
CyclePrediction:
"A forecast derived from `MenstrualCycle` history; regenerated on the next cycle read.",
StrainTrimpCache: