fix(sleep): one day total for every sleep reader, and the latest night is a night

A day's sleep is the main night plus its naps (daySleepMinutes). The
series, the sleep score and the composition already read it that way; the
sleep list, the CSV export and the correlation sleep channel read the main
night alone, so a day of naps listed as 0 h and an average over the list
counted it as a night without sleep. The list now carries the day total in
value and the main night alone in the new mainAsleepMinutes field; the nap
caption reads as included.

GET /api/sleep/night without a date answered the latest day holding any
sleep, so a nap after the last night left the hypnogram with no night to
draw. It now walks back to the latest night with a main sleep; nap days
stay reachable by date.

The SQL night page bounded a night by its asleep sessions only, so an
in-bed-only session of the same night fell outside a chunked read that the
one-night read counted. The span now covers every session of the night.
This commit is contained in:
Marc-André Bombeck committed 2026-10-20 09:28:40 +02:00
1 parent 3004f55875
commit 63bbf0931c
20 files changed
+339 -94

No files matched your search

+18
View File
@@ -1282,6 +1282,24 @@ export function separateNightsAndNaps(
return days.sort((a, b) => a.night.localeCompare(b.night));
}
/**
* A wake day's sleep total, the one definition every reader states: the main
* night plus every nap of the day. It equals `SleepNight.asleepMinutes` for
* the same rows (both sum each session's canonical-writer asleep minutes),
* which is what the series, the sleep score and the composition read; the
* main night alone stays available as `main.asleepMinutes` /
* `SleepNight.mainSession`. A day of naps alone totals its naps, not 0.
*/
export function daySleepMinutes(day: {
main: SleepSession | null;
naps: readonly SleepSession[];
}): number {
return (
(day.main?.asleepMinutes ?? 0) +
day.naps.reduce((sum, nap) => sum + nap.asleepMinutes, 0)
);
}
export interface SleepNightSummary {
/**
* A `DataSummary` whose every value is a per-night TIME-ASLEEP total