You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
8.7.0, Android 16, Whoop 4 (Noop) vs Whoop 4 (Whoop)
Noop is showing the correct sleep time, but a short break in the night splits the sleep into two parts, the first one is shown in asleep and woke line, the split at the bottom of the screen.
Same configuration as the original report — a WHOOP 4.0 running NOOP worn alongside a second WHOOP 4.0 on the official app — but with the comparison done from the exports rather than screenshots, over nine consecutive nights. Deltas are NOOP minus the official app, in minutes; positive is later.
On builds: the export was taken on a build carrying #1188/#1211/#1349, but every night the deltas come from was recorded and detected under the previous release — the update landed at the very end of the period. No app version is stored in a backup, so I cannot rule out that a detection change landed somewhere inside the period; the only evidence against it is that the shape below is consistent across every clean night.
1. The wake end is one-signed, the onset is not
Over the four clean nights where NOOP auto-detected without a manual edit:
median
range
session start
−7.6
−16.8 … +25.5
session end
+23.3
−1.2 … +51.7
duration
+17.8
−0.5 … +68.5
The onset error is modest and two-sided — that part looks healthy. The end is the asymmetric one: NOOP keeps the session open past the official wake on essentially every night, up to about 50 minutes. Because it is one-signed it does not average out, and it inflates duration on top of an onset that is already slightly early.
The same shape shows up on the two nights I had already edited by hand: I edited exactly the nights where the automatic end had run long, which is probably the honest description of why the edit feature gets used.
Not claiming the official app is ground truth here — it is a different strap and a proprietary definition. But a one-signed 20–50 minute end delta against a device on the same wrist-pair, on nights whose onsets agree within ~15 minutes, is more consistent with a wake-detection threshold than with a reference disagreement.
2. After a data gap, the session start is pinned to the first sample — and the night is still scored as complete
Two nights in the period had a data gap in front of the session, and both produced the same failure shape:
On one night my data had a 35-hour hole. The night's session began at the exact second of the first sample after the hole — about 4.7 hours after the official onset — and was still written as an ordinary session with a full recovery score, sleep stages and a nightly HRV. Nothing in the record says the front of the night is missing.
The following night, the session start again landed exactly on the first motion sample after a ~27-minute gap, this time about 3.7 hours before the official onset, producing a 12-hour "sleep session".
The second of those two was on a night where my strap was misbehaving independently (see below), so I would not read the algorithm off it. The first is clean and, I think, the actionable one: a night that lost 4.7 hours off its front should be marked incomplete rather than scored as a full night. A gap-aware guard — if the covered fraction of the detected window is below some threshold, mark the session partial and withhold the derived nightly numbers — would be a display/scoring honesty fix in the same spirit as #1332 and #1350, and cheaper than improving detection.
To be explicit about the cause of that hole, because it is not a NOOP defect and I do not want it read as one: I was running a second app against the same strap, NOOP was not resident for that whole window, and the strap's history had most likely already been consumed and cleared by the other app before NOOP reconnected. Every table in my export stops within the same couple of minutes and resumes in the same second, with no connection or battery events in between — consistent with an absent client rather than a failing offload. So treat the gap purely as the input to the observation above: whatever the reason data is missing, the night was still scored as complete, and that part is worth fixing on its own.
3. A pre-onset fragment on WHOOP 4.0, above #1382's ratio guard
One night produced two sessions: a 1.4-hour fragment starting about 1.9 hours before the official onset, then the real night. This is the #1284 pre-onset shape, but on my-whoop rather than an Oura import — and #1382 notes WHOOP had no near-adjacent pairs at the time.
It would not be caught by the new rule as written: the fragment is about 21 % of the longer session, over the fragmentFractionOfLonger = 0.10 guard, and it is separated by a ~20 minute gap rather than grazing. Whether it should be collapsed is a genuine question — it may be real pre-sleep dozing that the official app declines to count — so this is offered as a shape the guard does not currently see, not as a bug report.
Method and caveats
One participant, nine consecutive nights, two physical WHOOP 4.0 straps worn together; the official app's own scored cycles are the comparison target, matched by the local wake day the session ends on.
Comparison is computed from both apps' exports, so it reflects stored session boundaries rather than what either UI displayed at any moment.
A second app was reading the experimental strap throughout, which is why the gap above is not attributable to either app. It does not affect the boundary deltas, which come from each app's own stored sessions.
Stored boundaries are not necessarily final: on one night I have two exports, and between them the session end moved about 74 minutes earlier with userEdited = 0. The earlier export was taken roughly 20 minutes after that session closed. So a boundary read right after wake can still change; the deltas above use the later export throughout.
The official app is a compatibility target, not verified sleep truth. Neither device was checked against PSG or an independent behavioural diary, so this measures disagreement and its sign, not accuracy.
Two of the nine nights are excluded from the boundary statistics above: one where my strap independently malfunctioned during the preceding day (implausible daytime heart rates, all LEDs lit while off-wrist), and one with no strap data at all. They are described above only as examples of gap handling.
Activity
kavemang commentedon Jul 12, 2026
was this with v1 or v2 sleep enabled on noop?
pilleuspulcher-blip commentedon Jul 12, 2026
@kavemang
V2 enabled
Continuous hrv capture enabled
ryanbr commentedon Jul 13, 2026
Re-test with noop staging 8.8.0
CLAUDE.md: add the derived-biosignal validation standard
pilleuspulcher-blip commentedon Jul 13, 2026
@ryanbr
8.7.0, Android 16, Whoop 4 (Noop) vs Whoop 4 (Whoop)
Noop is showing the correct sleep time, but a short break in the night splits the sleep into two parts, the first one is shown in asleep and woke line, the split at the bottom of the screen.
noop-strap-log-260713-0959.txt
feat(sleep): motion-aware wake refinement behind an Experimental togg…
fix(sleep): flag Rest low-confidence on sparse-motion nights (#345, #319
pilleuspulcher-blip commentedon Jul 14, 2026
@ryanbr
Another night on 8.7.0
noop-strap-log-260714-0916.txt
fix(sleep): Asleep/Woke row + hypnogram axis span the whole split nig…
fix(sleep): Asleep/Woke row + hypnogram axis span the whole split nig…
pilleuspulcher-blip commentedon Jul 15, 2026
@ryanbr
Again very similar sleep tracking (8.7.0) between Whoop app and Noop app.
noop-strap-log-260715-1022.txt
pilleuspulcher-blip commentedon Jul 16, 2026
@ryanbr
Now in 9.0.0, Android 16
RHR: Whoop 50, Noop 44
HRV: Whoop 26, Noop 46 (deep sleep window)
Sleep data in the screenshots
noop-strap-log-260716-0906.txt
CLAUDE.md: add the derived-biosignal validation standard
feat(sleep): motion-aware wake refinement behind an Experimental togg…
5 remaining items
feat(sleep): motion-aware wake refinement behind an Experimental togg…
fix(sleep): flag Rest low-confidence on sparse-motion nights (ryanbr#345
fix(sleep): Asleep/Woke row + hypnogram axis span the whole split nig…
Circadian: the input is heart rate, not motion — say so, and pin what…
feat(sleep): "sleep may be incomplete" caveat for sparse-motion nights (
artemc commentedon Aug 17, 2026
Nine nights, same setup, measured deltas
Same configuration as the original report — a WHOOP 4.0 running NOOP worn alongside a second WHOOP 4.0 on the official app — but with the comparison done from the exports rather than screenshots, over nine consecutive nights. Deltas are NOOP minus the official app, in minutes; positive is later.
On builds: the export was taken on a build carrying #1188/#1211/#1349, but every night the deltas come from was recorded and detected under the previous release — the update landed at the very end of the period. No app version is stored in a backup, so I cannot rule out that a detection change landed somewhere inside the period; the only evidence against it is that the shape below is consistent across every clean night.
1. The wake end is one-signed, the onset is not
Over the four clean nights where NOOP auto-detected without a manual edit:
The onset error is modest and two-sided — that part looks healthy. The end is the asymmetric one: NOOP keeps the session open past the official wake on essentially every night, up to about 50 minutes. Because it is one-signed it does not average out, and it inflates duration on top of an onset that is already slightly early.
The same shape shows up on the two nights I had already edited by hand: I edited exactly the nights where the automatic end had run long, which is probably the honest description of why the edit feature gets used.
Not claiming the official app is ground truth here — it is a different strap and a proprietary definition. But a one-signed 20–50 minute end delta against a device on the same wrist-pair, on nights whose onsets agree within ~15 minutes, is more consistent with a wake-detection threshold than with a reference disagreement.
2. After a data gap, the session start is pinned to the first sample — and the night is still scored as complete
Two nights in the period had a data gap in front of the session, and both produced the same failure shape:
The second of those two was on a night where my strap was misbehaving independently (see below), so I would not read the algorithm off it. The first is clean and, I think, the actionable one: a night that lost 4.7 hours off its front should be marked incomplete rather than scored as a full night. A gap-aware guard — if the covered fraction of the detected window is below some threshold, mark the session partial and withhold the derived nightly numbers — would be a display/scoring honesty fix in the same spirit as #1332 and #1350, and cheaper than improving detection.
To be explicit about the cause of that hole, because it is not a NOOP defect and I do not want it read as one: I was running a second app against the same strap, NOOP was not resident for that whole window, and the strap's history had most likely already been consumed and cleared by the other app before NOOP reconnected. Every table in my export stops within the same couple of minutes and resumes in the same second, with no connection or battery events in between — consistent with an absent client rather than a failing offload. So treat the gap purely as the input to the observation above: whatever the reason data is missing, the night was still scored as complete, and that part is worth fixing on its own.
3. A pre-onset fragment on WHOOP 4.0, above #1382's ratio guard
One night produced two sessions: a 1.4-hour fragment starting about 1.9 hours before the official onset, then the real night. This is the #1284 pre-onset shape, but on
my-whooprather than an Oura import — and #1382 notes WHOOP had no near-adjacent pairs at the time.It would not be caught by the new rule as written: the fragment is about 21 % of the longer session, over the
fragmentFractionOfLonger = 0.10guard, and it is separated by a ~20 minute gap rather than grazing. Whether it should be collapsed is a genuine question — it may be real pre-sleep dozing that the official app declines to count — so this is offered as a shape the guard does not currently see, not as a bug report.Method and caveats
userEdited = 0. The earlier export was taken roughly 20 minutes after that session closed. So a boundary read right after wake can still change; the deltas above use the later export throughout.docs: relocate the rules unique to CLAUDE.md into the reference docs
Say which gate ate the workout when a day detects none (#1574)
sleep: say when a night's hypnogram only covers part of its window
sleep: say when a night's hypnogram only covers part of its window
feat(sleep): give Android the H9 low-confidence note it was promised
feat(sleep): give Android the H9 low-confidence note it was promised
feat(sleep): give Android the H9 low-confidence note it was promised
Sleep: give Android the H9 low-confidence note it was promised (#2330)
feat(android): nightly data-trust census - one 0-100 score per night …