Repository navigation
Conversation
|
Thanks @kavemang. The bug is real and your mechanism claim checks out: Holding it, because removing the gate entirely reintroduces the regression the gate was added for, and I can put numbers on it. The six-hour afternoon nap now winsThe comment this patch deletes states the hazard outright:
That is still true.
360 beats 300, so the unclassified afternoon block becomes MAIN and the real night loses. Because the bonus is capped at 90, the general rule after this change is that any unclassified daytime sleep more than 90 minutes longer than the night becomes the main sleep. That moves the day-cycle boundary into the afternoon and spreads steps, Effort and calories across the wrong days, which is the same class of error this patch sets out to correct for early bedtimes. The test change hid it rather than caught it
A much smaller fix for the reported bug
If shift schedules need covering too, two options that do not give up the protection:
Either way I would want Refs #2626 |
What this PR does
Main sleep starting at 19:00 or 19:45 can create its physiological-day boundary instead of being classified as a nap and extending the preceding cycle across another day. Both platforms retain the onset eligibility gate before ranking groups and lower the shared selection-band start from 20:00 to 19:00.
The original unclassified 13:00–19:00 nap fixture is restored on Android and covered by the same fixture on Swift: the 01:00–04:30 night remains MAIN and the six-hour afternoon block remains NAP. Explicit main/nap overrides remain authoritative. Learned timing ranks eligible groups; an unclassified daytime group still needs an explicit main override. Raw detector thresholds are unchanged. The selection band's cold-start center consequently moves from 03:30 to 03:00.
Verification
All 17 expected CI checks passed at
daf0430a3d133c5d688c8cb732ff3c4775fa6281, including native macOS/iOS app builds, macOS StrandTests, Android APK/full unit suite, Swift packages/tools, Tools Python, i18n and source hygiene. The final exact-head check API reports the same 17-check roster with zero non-success results; the PR head was re-read to confirm it matches. A normal merge of current main completed without conflicts, and normal parity regeneration passed with 289 known findings and no generated diff. Local verification of the review fix before the main merge passed:Oracle reproduction: compile production
SleepStageTotals.swift, a copy ofPhysiologicalSteps.swiftwith its unusedimport WhoopProtocolremoved, and amain.swiftcontaining the test'sclassificationOracle()andprint(classificationOracle()), usingswiftc -O. The committed tests compare the same output. Run the Swift package withswift test --jobs 1; Android CI runs its complete APK build/unit suite.No wearer database or held-out reference is available. No physiological accuracy improvement is claimed.
Validation protocol
The original ungated proposal was rejected by the maintainer's unclassified long-nap counterexample. The revised prediction was stated in the maintainer review before these reruns: retaining eligibility and moving its early edge to 19:00 admits the reported bedtimes while preserving the shorter-night/long-nap protection. Expected threshold: zero twin-oracle mismatches; the original unclassified afternoon fixture must remain NAP. Synthetic domain: UTC offsets −5h/0/+13h, 15-minute onset sweep, duration floor, explicit overrides, edited onset and bridged fragments. No synthetic exclusions.
Related issues
Refs #2626