mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 22:26:13 +00:00
test: describe analytics fixtures without tying them to a real profile
Several test titles and comments said whose readings a fixture came from, with a host name beside them: a blood pressure average, a month of paired readings with dates, a cached insight about weight, cycle history and dose timing. They now describe the fixture itself (a profile averaging 134/87, a ten-pair month, a long history); the values and what each test proves are unchanged.
This commit is contained in:
1 parent
c9264c047e
commit
7dd251184f
11 files changed
+37
-41
No files matched your search
@@ -163,7 +163,7 @@ describe("POST /api/ingest/medication — 422 multi-issue (v1.4.43 W6)", () => {
|
||||
});
|
||||
|
||||
describe("POST /api/ingest/medication — slot attribution + convergence (v1.16.9)", () => {
|
||||
// The maintainer's live bug: a daily 09:00 med, the worker pre-minted the
|
||||
// The bug as it was seen: a daily 09:00 med, the worker pre-minted the
|
||||
// pending REMINDER row at 09:00 Berlin, the user ingested the take at
|
||||
// 08:42 Berlin via the external API. The bare create anchored a SECOND
|
||||
// row at 08:42 and left the 09:00 pending row open — reminder kept
|
||||
|
||||
@@ -290,7 +290,7 @@ export function RestoreSkipReport({
|
||||
/**
|
||||
* Says out loud whether the SCHEDULE is still alive.
|
||||
*
|
||||
* The weekly pass on the maintainer's own instance stopped producing copies
|
||||
* The weekly pass on one instance stopped producing copies
|
||||
* and nothing surfaced it for a month and a half: the table listed the rows it
|
||||
* had, each with an ordinary timestamp, and a copy from six weeks ago reads
|
||||
* exactly like one made on Sunday until somebody does the subtraction. Two
|
||||
|
||||
@@ -128,9 +128,9 @@ describe("isLegacyInsightPayload()", () => {
|
||||
expect(isLegacyInsightPayload({ summary: "x" })).toBe(false);
|
||||
});
|
||||
|
||||
it("returns true for the v1.4.14 pre-strict-schema shape (the maintainer's prod blob)", () => {
|
||||
// The actual cached blob that crashed /insights for the live tenant on
|
||||
// 2026-05-10. No `summary`, no `recommendations[]` — just the
|
||||
it("returns true for the v1.4.14 pre-strict-schema shape", () => {
|
||||
// A cached blob of this shape crashed /insights after the schema
|
||||
// change. No `summary`, no `recommendations[]` — just the
|
||||
// pre-v1.4.16 `{changed, stable, drivers, nextSteps, confidence,
|
||||
// limitations}` shape. The route's `safeParse` failed and fell
|
||||
// through to the raw blob, so the rich card got `summary ===
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* v1.15.12 — unit pins for the graded BP pillar score.
|
||||
*
|
||||
* The maintainer's apps01 profile (under-65 ceiling 129/79, avg 134/87)
|
||||
* is the canonical regression: the binary all-time in-target rate read
|
||||
* A profile averaging 134/87 against the under-65 ceiling of 129/79 is the
|
||||
* canonical regression: the binary all-time in-target rate read
|
||||
* ~10-16/100; the graded score must land in the borderline-stage-1 band
|
||||
* (low-to-mid 50s), not in the catastrophic band.
|
||||
*/
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from "../bp-grade";
|
||||
import type { BpTargets } from "../bp-targets";
|
||||
|
||||
// Under-65 ESH band — the maintainer's age band.
|
||||
// Under-65 ESH band.
|
||||
const UNDER65: BpTargets = {
|
||||
sysLow: 120,
|
||||
sysHigh: 129,
|
||||
@@ -34,7 +34,7 @@ function bpScore(input: { sys: number; dia: number; target: BpTargets }) {
|
||||
}
|
||||
|
||||
describe("gradeBpScore", () => {
|
||||
it("grades the maintainer's 134/87 into the borderline band [45,60]", () => {
|
||||
it("grades 134/87 into the borderline band [45,60]", () => {
|
||||
const score = bpScore({ sys: 134, dia: 87, target: UNDER65 });
|
||||
expect(score).toBeGreaterThanOrEqual(45);
|
||||
expect(score).toBeLessThanOrEqual(60);
|
||||
@@ -145,7 +145,7 @@ describe("gradeBpScore", () => {
|
||||
).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
it("preserves the audit fairness anchors (134/87 → 57, 165/105 → 22)", () => {
|
||||
it("preserves the fairness anchors (134/87 → 57, 165/105 → 22)", () => {
|
||||
expect(bpScore({ sys: 134, dia: 87, target: UNDER65 })).toBe(57);
|
||||
expect(bpScore({ sys: 165, dia: 105, target: UNDER65 })).toBe(22);
|
||||
});
|
||||
|
||||
@@ -21,8 +21,8 @@ describe("isBpReadingInTarget()", () => {
|
||||
* v1.4.16 A2 regression: 117/79 is textbook normotensive
|
||||
* (well-controlled, below the goal ceiling, above hypotension). The
|
||||
* v1.4.15 implementation rejected this because sys < sysLow (120),
|
||||
* which collapsed the live tenant's BD-Zielbereich tile to 0 %. The fix uses a
|
||||
* one-sided ceiling check with a clinical floor.
|
||||
* which collapsed the in-target tile of a well-controlled profile to
|
||||
* 0 %. The fix uses a one-sided ceiling check with a clinical floor.
|
||||
*/
|
||||
it("counts a normotensive reading below the goal band as in-target", () => {
|
||||
expect(isBpReadingInTarget(117, 79, TARGETS_UNDER_65)).toBe(true);
|
||||
@@ -197,11 +197,8 @@ describe("computeBpInTargetPct", () => {
|
||||
});
|
||||
|
||||
/**
|
||||
* v1.4.16 A2 regression — the live tenant's actual production data.
|
||||
*
|
||||
* The maintainer reported BD-Zielbereich = 0 % despite multiple BP readings
|
||||
* that "are clearly in target". A query against production showed
|
||||
* their last 30 days of paired readings include 117/79, 122/76, 108/76,
|
||||
* v1.4.16 A2 regression: a month of ten paired readings, most of them
|
||||
* clearly in target, that the tile read as 0 %: 117/79, 122/76, 108/76,
|
||||
* 106/73, 127/86, 115/78, 108/75, 124/82, 126/80, 133/95.
|
||||
*
|
||||
* Under v1.4.15 narrow-band semantics (sys >= 120 AND sys <= 129 AND
|
||||
@@ -216,9 +213,9 @@ describe("computeBpInTargetPct", () => {
|
||||
* Result: 5/10 = 50 %.
|
||||
*
|
||||
* Compare with the v1.4.15 narrow-band result (0/10 = 0 %) — that's
|
||||
* the regression the maintainer reported.
|
||||
* the regression.
|
||||
*/
|
||||
it("regression: the maintainer's production data produces non-zero % under the ceiling semantics", () => {
|
||||
it("regression: the ten-pair month produces non-zero % under the ceiling semantics", () => {
|
||||
const sys = [
|
||||
reading("2026-05-08T07:38:22Z", 117),
|
||||
reading("2026-05-03T21:22:02Z", 122),
|
||||
@@ -267,12 +264,12 @@ describe("computeBpInTargetPct", () => {
|
||||
|
||||
describe("computeBpInTargetWindows — all-time headline (v1.4.19 A1)", () => {
|
||||
/**
|
||||
* v1.4.19 A1 regression — the maintainer reported the BD-Zielbereich tile shows
|
||||
* **EXACTLY 50 % on 7T, 30T, AND the headline ("total")** for their
|
||||
* production data. Hand-counted hypothesis-1 from the brief (the
|
||||
* three-way coincidence cannot be data — it's a calculation pin):
|
||||
* v1.4.19 A1 regression — the in-target tile showed
|
||||
* **EXACTLY 50 % on 7T, 30T, AND the headline ("total")** for a long
|
||||
* history. Hand-counted (the three-way coincidence cannot be data, it is
|
||||
* a calculation pin):
|
||||
*
|
||||
* - The live tenant has 572 paired BP readings going back to 2022-01.
|
||||
* - A history of 572 paired BP readings over four years.
|
||||
* - Last 7 days: 1 / 2 in target = 50 %.
|
||||
* - Last 30 days: 5 / 10 in target = 50 %.
|
||||
* - All time: 62 / 572 in target ≈ 11 %.
|
||||
@@ -389,8 +386,8 @@ describe("computeBpInTargetWindows — all-time headline (v1.4.19 A1)", () => {
|
||||
expect(result.last90Days).toBeNull();
|
||||
});
|
||||
|
||||
it("regression: the live tenant's 30-day fixture mirrors the live tenant's prod headline bug", () => {
|
||||
// Reuse the maintainer's production fixture (10 pairs, 5 in target = 50 %).
|
||||
it("regression: the ten-pair month alone hides the headline bug", () => {
|
||||
// Reuse the ten-pair fixture (5 in target = 50 %).
|
||||
// When the input is JUST those 10 pairs, allTime equals 30d == 50 %
|
||||
// (this is the legitimate coincidence — it only hides the bug when
|
||||
// the user has no older history). The bug surfaces the moment older
|
||||
@@ -431,7 +428,7 @@ describe("computeBpInTargetWindows — all-time headline (v1.4.19 A1)", () => {
|
||||
|
||||
describe("computeBpInTargetWindows", () => {
|
||||
/**
|
||||
* v1.4.18 A1 regression — the maintainer reported the BD-Zielbereich tile shows
|
||||
* v1.4.18 A1 regression — the in-target tile showed
|
||||
* the 30-day headline (50 %) but `7T: —` and `30T: —` placeholders
|
||||
* even though the user has paired BP readings in both windows. Root
|
||||
* cause: the analytics route only returned `bpInTargetPct` once over
|
||||
@@ -439,7 +436,7 @@ describe("computeBpInTargetWindows", () => {
|
||||
* renders the "—" fallback. The fix is a windowed helper that returns
|
||||
* both 7-day and 30-day shares so the tile can show all three.
|
||||
*
|
||||
* Pinning the live tenant's actual production fixture (10 paired readings over
|
||||
* Pinning a fixture of 10 paired readings over
|
||||
* the last 30 days, 2 of them within the last 7 days) so a future
|
||||
* reviewer can re-derive the expected counts by hand.
|
||||
*/
|
||||
@@ -520,11 +517,11 @@ describe("computeBpInTargetWindows", () => {
|
||||
});
|
||||
|
||||
/**
|
||||
* the live tenant's real fixture: 10 paired readings over the last 30 days (5 in
|
||||
* The fixture: 10 paired readings over the last 30 days (5 in
|
||||
* target, 5 out → 50 %), of which 2 are inside the last 7 days
|
||||
* (1 in target, 1 out → 50 %).
|
||||
*/
|
||||
it("regression: the maintainer's production fixture renders 7d=50% and 30d=50%", () => {
|
||||
it("regression: the ten-pair fixture renders 7d=50% and 30d=50%", () => {
|
||||
const fixtureNow = new Date("2026-05-09T12:00:00Z");
|
||||
const sys = [
|
||||
reading("2026-05-08T07:38:22Z", 117), // 7d IN
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* v1.15.12 — unit pins for resting-pulse estimation.
|
||||
*
|
||||
* The canonical regression (the maintainer's apps01 profile): a day with
|
||||
* The canonical regression: a day with
|
||||
* ~500 high workout PULSE samples + ~10 resting reads must NOT classify
|
||||
* the day as a resting-HR excursion. A user with clean
|
||||
* RESTING_HEART_RATE (~72) reads healthy.
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* `sys >= sysLow && sys <= sysHigh && dia >= diaLow && dia <= diaHigh`.
|
||||
* With ESH 2023 narrow targets (Sys 120-129, Dia 70-79 for under-65)
|
||||
* this collapses to 0 % for healthy normotensive users whose
|
||||
* readings sit BELOW the goal band — the live tenant's actual data has many
|
||||
* readings sit BELOW the goal band — a well-controlled profile has many
|
||||
* readings like 117/79 (textbook normotensive, well-controlled) that
|
||||
* were marked OUT of target because sys < 120. Users intuitively
|
||||
* consider those readings *in target* — and so does clinical
|
||||
@@ -222,8 +222,8 @@ export function collectBpPairs(
|
||||
* - v1.4.18 A1 wired `avg7` + `avg30` from `computeBpInTargetWindows`,
|
||||
* BUT the analytics route also routed the **headline**
|
||||
* (`bpInTargetPct`) through `windows.last30Days?.pct` — i.e. the
|
||||
* headline was a literal copy of `bpInTargetPct30d`. For the live tenant's prod
|
||||
* data (572 paired readings since 2022, recent 30 days = 50 %, all-time
|
||||
* headline was a literal copy of `bpInTargetPct30d`. For a long history
|
||||
* (572 paired readings over four years, recent 30 days = 50 %, all-time
|
||||
* ≈ 11 %) the tile rendered `50 %` headline, `7T: 50, 30T: 50` and
|
||||
* looked algorithmically pinned to 50/50/50. That was hypothesis-1
|
||||
* from the v1.4.19 A1 brief: "the 7T/30T branches reuse the all-time
|
||||
|
||||
@@ -2933,7 +2933,7 @@ describe("tallyComplianceFromLedger — the unified % keystone", () => {
|
||||
});
|
||||
|
||||
it("an off-schedule (ad-hoc) take is EXCLUDED + leaves its slot missed", () => {
|
||||
// The maintainer's case: 07:00 dose logged at 11:29 → outside the band → ad-hoc;
|
||||
// The reported case: 07:00 dose logged at 11:29 → outside the band → ad-hoc;
|
||||
// the 07:00 slot is missed; the 19:00 slot is also missed (untouched).
|
||||
const events = [
|
||||
{ scheduledFor: at(7, 0), takenAt: at(11, 29), skipped: false },
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
* v1.4.16: fall back to slope30 (projected onto 7 days) when
|
||||
* slope7 is unavailable. Some metrics (mood, sleep) have <2 entries
|
||||
* within the trailing 7-day window for users who don't log daily,
|
||||
* which used to surface as a missing delta on the dashboard tile —
|
||||
* the maintainer's complaint: "Bei Stimmung wird zum Beispiel kein Trend in
|
||||
* Zahlen dargestellt." A 30-day slope still answers the question
|
||||
* which used to surface as a missing delta on the dashboard tile: mood
|
||||
* showed no trend figure at all. A 30-day slope still answers the question
|
||||
* "is this metric drifting up or down?" — we just project it onto
|
||||
* a 7-day window for label consistency. Returning `null` is reserved
|
||||
* for the truly insufficient case where neither slope is available.
|
||||
|
||||
@@ -834,8 +834,8 @@ export interface AggregatedFeatures {
|
||||
*
|
||||
* Replaces v1.4.35.x `rawMeasurements` (which appended every
|
||||
* measurement row and blew the 10 MB Codex prompt ceiling on power
|
||||
* users with multi-year imports — 25.9 MB observed on the maintainer's account
|
||||
* with 311 775 rows). Reading from `measurement_rollups` instead caps
|
||||
* users with multi-year imports, about 26 MB for an account of some 300 000
|
||||
* rows). Reading from `measurement_rollups` instead caps
|
||||
* the payload at O(types × buckets) regardless of underlying row
|
||||
* count.
|
||||
*/
|
||||
|
||||
@@ -127,7 +127,7 @@ async function startPeriod(date: string): Promise<Response> {
|
||||
);
|
||||
}
|
||||
|
||||
/** The three months of history the maintainer's record carried. */
|
||||
/** Three months of history, the shape the bug needed. */
|
||||
async function seedHistory(): Promise<void> {
|
||||
await startPeriod("2026-05-04");
|
||||
await startPeriod("2026-06-01");
|
||||
|
||||
Reference in new issue
Block a user