mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 15:02:04 +00:00
fix(sleep): count a re-exported sleep period once
A device can write the same period twice: an original envelope and a corrected one, same start, later end, distinct external ids. Both rows belong to the same writer, so the writer collapse keeps both, and the per-stage totals added them. One night served a 10 h 13 min in-bed headline next to a 20 h 17 min in-bed legend on the same screen, and the hypnogram drew the night twice over. Every per-stage total is now the measure of the union of that stage's spans rather than the sum of the rows, and the same merged spans feed the hypnogram segments and the time-asleep headline. Stages merge independently: two stages describing one minute is a contest, and the writer collapse is this file's mechanism for that - arbitrating again would collapse the summary-shaped writers, which stamp every stage total on the sleep end instant and nest by design. stages.IN_BED is now the in-bed envelope itself, the same union inBedMinutes reports, so the legend cannot contradict the headline and a night whose envelope only a losing writer recorded still reports it.
This commit is contained in:
1 parent
81ba711946
commit
a3b0af577f
3 files changed
+554
-27
No files matched your search
@@ -201,4 +201,31 @@ describe("GET /api/sleep/night", () => {
|
||||
const res = await GET(req("date=2026-06-04"));
|
||||
expect(res.status).toBe(200); // never 500 on the reconstruction edge
|
||||
});
|
||||
it("cannot serve an in-bed headline that contradicts its stage legend", async () => {
|
||||
// A device wrote the same night twice: an envelope 16:06 -> 02:09:59 and
|
||||
// a corrected one 16:06 -> 02:18:59. Raw-summing them served a 613-minute
|
||||
// headline next to a 1217-minute legend on the same screen.
|
||||
vi.mocked(getSession).mockResolvedValue(SESSION_OK as never);
|
||||
vi.mocked(prisma.measurement.findMany).mockResolvedValue([
|
||||
stage("2026-07-25T02:09:59.000Z", "IN_BED", 603 + 59 / 60),
|
||||
stage("2026-07-25T02:18:59.000Z", "IN_BED", 612 + 59 / 60),
|
||||
stage("2026-07-24T21:55:42.000Z", "CORE", 319.7),
|
||||
stage("2026-07-24T23:30:36.000Z", "DEEP", 94.9),
|
||||
stage("2026-07-24T23:37:31.200Z", "AWAKE", 6.92),
|
||||
stage("2026-07-25T01:53:25.200Z", "REM", 135.9),
|
||||
] as never);
|
||||
const res = await GET(req("date=2026-07-25"));
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json();
|
||||
expect(body.data.main.inBedMinutes).toBe(613);
|
||||
expect(body.data.main.stages.IN_BED).toBe(613);
|
||||
// One in-bed bar on the hypnogram, not the night drawn twice over.
|
||||
expect(
|
||||
body.data.main.segments.filter(
|
||||
(seg: { stage: string }) => seg.stage === "IN_BED",
|
||||
),
|
||||
).toHaveLength(1);
|
||||
expect(body.data.main.stages.CORE).toBe(320);
|
||||
expect(body.data.main.asleepMinutes).toBe(551);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user