fix(illness): gate the recovery-gap floor on adverse-direction days

The cross-episode typical-gap median counts an episode toward its
qualifying-days floor via the per-episode coverage `historyDays`, which
counts a day if ANY banded vital has a reading. A WEIGHT-only episode (no
illness-adverse direction) could therefore clear the floor and feed the
median despite carrying no illness-relevant signal, weakening the honest-
sample claim.

Compute a distinct-adverse-day count in the engine — days with at least
one notable reading in the metric's adverse direction — and feed that as
the qualifying-days floor instead. Reuses the engine's single adverse-
direction predicate (now exported as `isAdverseDeviation`); a neutral-
direction vital never counts a day. The insufficient arm contributes 0,
which is correct since its gap is null and never reaches the median.
This commit is contained in:
Marc-André Bombeck committed 2026-06-21 14:07:44 +02:00
1 parent 62a4dfdf7e
commit 36affd5daf
6 files changed
+151 -7

No files matched your search

+11 -3
View File
@@ -119,9 +119,17 @@ export const GET = apiHandler(async (request: NextRequest) => {
derived.status === "ok"
? derived.value.recoveryGapDays
: null,
// `historyDays` = distinct episode days with a banded vital,
// present on both the `ok` and `insufficient` arms.
gapMeasurementDays: derived.coverage.historyDays,
// Qualifying-days floor: distinct episode days carrying an
// ADVERSE-direction banded reading — NOT raw coverage
// (`historyDays` counts ANY banded vital, so a WEIGHT-only
// episode with no illness-adverse signal could otherwise clear
// the floor and tip the typical-gap median). Only the `ok` arm
// ever contributes a gap; the `insufficient` arm's gap is null,
// so 0 here is correct (it never reaches the median anyway).
gapMeasurementDays:
derived.status === "ok"
? derived.value.adverseCoverageDays
: 0,
},
];
},