mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 13:01:00 +00:00
fix(insights): read a same-hours day by its day mean
The same-hours standing averaged each day as sum / n. Pulse already folds its day as the mean of its local hours' means, and the day-aggregate reader returns that as dayMean; a type moved onto that reader would have been compared raw. The standing now reads dayMean where the reader carries one.
This commit is contained in:
1 parent
abb1c9f8a9
commit
22cb792379
2 files changed
+45
-5
No files matched your search
@@ -33,6 +33,7 @@ import {
|
||||
computeCoincidentDeviation,
|
||||
classifyDeviation,
|
||||
COINCIDENT_FIRE_THRESHOLD,
|
||||
sameHoursStanding,
|
||||
} from "../coincident-deviation";
|
||||
|
||||
const PROFILE = { ageYears: 40, sex: "MALE" as const };
|
||||
@@ -351,3 +352,40 @@ describe("glucose — a day in progress is compared with the same hours", () =>
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("sameHoursStanding", () => {
|
||||
it("reads an hourly-mean day by its day mean, not by sum / n", () => {
|
||||
// Twelve dense readings in one hour and one in another: the mean of the
|
||||
// hours' means is 100, the raw mean is 140. A type on the hourly-mean
|
||||
// reader carries `dayMean`, and that is the day's value.
|
||||
const day = (d: string, dayMean: number) => ({
|
||||
day: d,
|
||||
n: 13,
|
||||
sum: 140 * 13,
|
||||
dayMean,
|
||||
});
|
||||
const days = [
|
||||
...Array.from({ length: 8 }, (_, i) =>
|
||||
day(`2026-05-${String(20 + i).padStart(2, "0")}`, 100),
|
||||
),
|
||||
day("2026-06-02", 101),
|
||||
];
|
||||
const standing = sameHoursStanding(days, "2026-06-02", "BLOOD_GLUCOSE");
|
||||
expect(standing?.value).toBe(101);
|
||||
expect(standing?.center).toBe(100);
|
||||
});
|
||||
|
||||
it("falls back to sum / n where the reader has no day mean", () => {
|
||||
const days = [
|
||||
...Array.from({ length: 8 }, (_, i) => ({
|
||||
day: `2026-05-${String(20 + i).padStart(2, "0")}`,
|
||||
n: 2,
|
||||
sum: 180,
|
||||
})),
|
||||
{ day: "2026-06-02", n: 1, sum: 88 },
|
||||
];
|
||||
const standing = sameHoursStanding(days, "2026-06-02", "BLOOD_GLUCOSE");
|
||||
expect(standing?.value).toBe(88);
|
||||
expect(standing?.center).toBe(90);
|
||||
});
|
||||
});
|
||||
@@ -94,20 +94,22 @@ export const SAME_HOURS_MIN_DAYS = 7;
|
||||
* there is nothing like-for-like to compare today with, and no verdict.
|
||||
*/
|
||||
export function sameHoursStanding(
|
||||
days: readonly { day: string; n: number; sum: number }[],
|
||||
days: readonly { day: string; n: number; sum: number; dayMean?: number }[],
|
||||
todayKey: string,
|
||||
type: MeasurementType,
|
||||
): { value: number; low: number; high: number; center: number } | null {
|
||||
// A type on the hourly-mean reader carries `dayMean` (the mean of its
|
||||
// hours' means); every other type's day is the mean of its readings.
|
||||
const value = (d: { n: number; sum: number; dayMean?: number }) =>
|
||||
d.dayMean ?? d.sum / d.n;
|
||||
const today = days.find((d) => d.day === todayKey && d.n > 0);
|
||||
if (!today) return null;
|
||||
const earlier = days
|
||||
.filter((d) => d.day < todayKey && d.n > 0)
|
||||
.map((d) => d.sum / d.n);
|
||||
const earlier = days.filter((d) => d.day < todayKey && d.n > 0).map(value);
|
||||
if (earlier.length < SAME_HOURS_MIN_DAYS) return null;
|
||||
const band = buildBaselineBand(earlier, type);
|
||||
if (!band) return null;
|
||||
return {
|
||||
value: today.sum / today.n,
|
||||
value: value(today),
|
||||
low: band.low,
|
||||
high: band.high,
|
||||
center: band.center,
|
||||
|
||||
Reference in new issue
Block a user