Repository navigation
v11.6.0 regression: restored HRV/Recovery data disappears after re-score — RR rows stop being served #2101
Description
NOOP version
11.6.0
Platform
iOS
OS version
iOS27
WHOOP strap model
WHOOP 5.0
Where the data is coming from
NOOP export import
Test Centre profile
Not a test-mode bug
What happens
After updating from NOOP 11.5.0 to 11.6.0, my historical HRV and Recovery/Charge data disappears.
Restoring a known-good backup initially works correctly. NOOP asks me to close and reopen the app, and after reopening all historical data is present again. For example, Today shows Recovery/Charge 59% and HRV 77 ms.
However, within seconds or a few minutes, after NOOP performs another sync/backfill/re-score, the restored HRV and Recovery data disappears again. HRV becomes “-”, Recovery/Charge disappears, and NOOP returns to “Calibrating — 0 of 4 nights”.
The same backup works normally on v11.5.0. I downgraded to 11.5.0, restored it, and the data remained available. Updating again to 11.6.0 reproduced the issue.
The diagnostic log captures the transition. Before the failure:
rr[read=493509 served=562898]
hrv day=2026-09-11 window=whole avgHrv=77.2
After the subsequent re-score:
rr[read=215 served=0 reuseOff=1]
hrv day=2026-09-11 window=whole avgHrv=nil
Recovery then reports:
nilScore reason=missingInput (hrv/rhr/hrvBaseline required)
HR, RHR, sleep and other historical data are still present. The failure specifically affects the historical RR/HRV path and consequently Recovery/Charge.
noop-strap-log-260911-1248.txt
What you expected instead
After successfully restoring a backup, the restored historical HRV and Recovery/Charge data should remain available after subsequent sync, backfill and re-scoring.
The same backup remains stable on v11.5.0, so updating to v11.6.0 should not cause the restored RR/HRV data to stop being used by the scorer.
Steps to reproduce
- Start with working historical HRV/Recovery data on NOOP v11.5.0.
- Update NOOP in-place to v11.6.0 without deleting the app.
- Observe that historical HRV/Recovery disappears.
- Restore a known-good .noopbak backup.
- NOOP reports that the restore succeeded and asks to close/reopen the app.
- Fully close NOOP and reopen it.
- Observe that historical HRV/Recovery initially appears correctly again (for example HRV 77 ms and Recovery 59%).
- Wait for NOOP to perform the next sync/backfill/re-score.
- Within seconds/minutes, HRV becomes unavailable and Recovery/Charge disappears.
- NOOP returns to “Calibrating — 0 of 4 nights”.
- Downgrade in-place to v11.5.0 and restore the same backup: the historical HRV/Recovery remains working.
- Update again to v11.6.0: the problem reproduces.
Strap log
Diagnostic bundles and full strap log attached.
Key transition captured in the log:
Before failure:
rr[read=493509 served=562898]
avgHrv=77.2
After re-score:
rr[read=215 served=0 reuseOff=1]
avgHrv=nil
Recovery subsequently reports:
nilScore reason=missingInput (hrv/rhr/hrvBaseline required)
Before you submit
- I attached my exported NOOP .zip (not a screenshot of the Live screen). If my bug is a clearly reproducible UI issue I described exactly how to see it instead.
- I attached or pasted a strap log above — or my bug is a clearly reproducible UI issue that doesn't need one (e.g. a typo, a button that does nothing) and I've described exactly how to see it.
- I checked the Troubleshooting guide — especially "history syncs but no data" (most often the strap isn't banking history to flash; charge it to 100% and reconnect).
- I checked the FAQ and — if I'm on a WHOOP 5.0 / MG — the 5.0/MG status page, and this isn't an already-known limit (e.g. SpO₂, or recovery/sleep on the 5/MG).
- I've left out anything personal (strap serial, account email, raw export).
Activity
ItsMeDrath commentedon Sep 11, 2026
yes 11.6 is causing hrv and breathing rate disapparing issue but if we downgrade to 11.5 both data comes back
bhelm commentedon Sep 11, 2026
I traced this regression across the v11.5.0..v11.6.0 history. The most likely introducing commit is 98975f9 (
Correct WHOOP 5 R-R interval units).That change intentionally introduced a strict WHOOP 5 R-R read policy: legacy rows remain stored, but unlabelled rows are excluded from scoring because old databases can mix correctly converted standard-BLE milliseconds with incorrectly scaled native interval words. This is a reasonable safety feature in isolation.
The restore/re-score lifecycle makes its current behavior a regression, however:
This matches the diagnostic transition in the report (
rr[read=493509 served=562898]torr[read=215 served=0 reuseOff=1).reuseOff=1appears to describe the sliding-window bypass, not the root cause; the decisive behavior is that the underlying strict WHOOP 5 query no longer serves the restored unlabelled rows.So I would classify this as: the legacy-row exclusion is an intentional feature, but losing previously working HRV/Recovery after a supported backup restore is an unintended v11.6.0 regression. Confidence is high (roughly 90–95%); a focused test or bisect using a real v11.5 backup immediately before and after that commit would provide the final proof.
bhelm commentedon Sep 11, 2026
A candidate fix is available in #2115.
@rafaelphh, would you be willing to test it, ideally while you still have the working v11.5 state or by restoring your known-good v11.5 backup? The intended flow is: restore/open the working data, install a build containing the PR, then let the normal sync/backfill/re-score complete and confirm that the existing HRV and Recovery remain visible.
Important test boundary: the PR has targeted Android regression coverage and a cross-platform source contract, but it has not yet been tested with a real user
.noopbak, on physical WHOOP 5 hardware, or compiled on Apple in this Linux environment. Please do not post personal or raw health data publicly; a simple pass/fail plus the redactedrr[read=... served=... reuseOff=...]and HRV/recovery transition is enough.The fix does not reinterpret or convert ambiguous legacy R-R rows. It preserves the previously computed HRV/Recovery pair until a labelled scoring transport arrives. If 11.6.0 has already cleared the values, an older backup or a new labelled strap offload is still required.
ryanbr commentedon Sep 12, 2026
The fix is merged and now in a build you can install: the
testing-lateststaging release, build 492, base 11.6.0, built from0b0d206.Thanks @bhelm for the trace and the fix, @rafaelphh for a report that carried its own proof, and @ItsMeDrath for confirming it independently. Three separate people landing on the same signature is what made this quick to place.
What the fix does
11.6.0 correctly stops scoring ambiguous unlabelled WHOOP 5 R-R rows, but the re-score then replaced the previously computed values with null. An existing HRV and Recovery pair is now preserved as an opaque snapshot, and only when the exact scoring window holds valid unlabelled legacy rows and no scorable labelled transport. Every other daily field is still freshly computed, and a labelled transport ends the protection, including when it is too sparse to produce HRV, because that is a real answer rather than an absence.
Nothing reinterprets or relabels the old rows. That was deliberate rather than conservative for its own sake: legacy rows mix units and origins, the discriminator is exactly the label that is missing, and HRV is built from successive differences, so splicing two scales fabricates a difference that never happened and feeds it to Recovery. A wrong number would be worse than a blank.
Two things to know before testing
Breathing rate is NOT covered, and that is now tracked in #2123. It dies from the same cause, since a WHOOP night derives respiratory rate from R-R through the RSA path with no vendor-measured alternative, but the preserved snapshot carries only HRV and Recovery. So on this build expect HRV and Recovery back and respiratory rate still blank. @ItsMeDrath and one other reporter both named breathing rate, so I would rather say that plainly than have it read as the fix half-working.
Values already cleared by an 11.6.0 re-score do not come back. The fix preserves what is there; it cannot reconstruct what is gone. If your values were already lost, you need an older backup or a fresh labelled strap offload. "Update and it returns" is the natural assumption and it is not what happens.
What would help
@rafaelphh, you are best placed since you still have a working 11.5 state: restore your known-good backup on this build, let a normal sync, backfill and re-score complete, and confirm HRV and Recovery survive it. The redacted
rr[read=... served=... reuseOff=...]line plus the HRV and recovery transition is enough, and please keep raw health data off a public issue.This has not been tested against a real
.noopbakon physical WHOOP 5 hardware by anyone yet, which is the one gap between "the tests pass" and "this works". Leaving the issue open until someone confirms it on a real device.rafaelphh commentedon Sep 12, 2026
@ryanbr Tested on physical WHOOP 5 / iOS using the requested 11.6.0 staging build.
I restored the known-good v11.5 backup, then allowed normal sync, historical backfill and multiple re-scores to complete.
Immediately after restore:
After sync/backfill/re-score completed:
R-R diagnostic after re-score:
rr[read=895 served=0 truncated=0 ownerFlips=0 reuseOff=1]
So HRV and Recovery no longer disappear to null/blank, but the restored HRV/Recovery pair was not preserved unchanged after re-score.
I can provide additional redacted diagnostics privately if needed.


ryanbr commentedon Sep 12, 2026
Thank you @rafaelphh, that is the exact gap I named and you closed it: a real
.noopbakon physical WHOOP 5 hardware. It also produced a more useful result than a pass would have.The reported regression is resolved
HRV no longer goes to "-", Recovery no longer disappears, and Charge no longer drops to "Calibrating, 0 of 4". The destructive nil overwrite is gone.
What you saw instead is a different problem
The pair changed rather than survived, and the preserved snapshot was meant to be exact.
First, one clarification about the line you posted, because it is easy to read as the smoking gun and is not quite:
That is the
analyzeRecentsliding-window plan, not the per-night scoring read.served=0there means no R-R reached the rolling re-score at all, which is exactly the condition the preservation requires, so on that evidence the pair should have come back untouched. It did not, so one of two things happened:Both end in the same place: the 59 ms you are seeing is most likely a real, freshly computed number, not a corrupted one.
Which makes the Recovery figure the more interesting half
Recovery moving from 59% to 9% is a much larger swing than HRV moving from 77 to 59 accounts for on its own, and that gap points somewhere the preservation work never reached.
Charge scores a night against a baseline folded over your stored HRV history. After the 11.6.0 unit correction that history can hold values computed under two different unit interpretations: older nights from rows of uncertain scale, newer nights from labelled rows of known scale. A correctly scaled HRV judged against a baseline built mostly from the other scale reads as a collapse. @bhelm's own trace describes the mixture ("correctly converted standard-BLE milliseconds with incorrectly scaled native interval words"), and #459 already documented this exact shape for a different cause, where a straddling window "reads the first nights as suppressed against an inflated mean, a device artifact, not physiology".
If that is what is happening, the individual numbers are each defensible and the comparison between them is not, which produces a wrong score rather than a blank one. That is the outcome the strict read policy exists to avoid, so it is worth getting right rather than tuning away.
I have opened #2126 for it with a proposed approach, since it is structural, it outlives the preservation work, and it affects any WHOOP 5 user whose history straddles the upgrade, with no backup involved at all.
Two things that would settle it
Both are cheap and neither needs health data:
rrTransportline from Test Centre, added in diag: say whether a device R-R beats were never banked or were refused by the unit policy #2118 for this exact question:rrTransport recorded=... scorable=... unscorableHistory=... gapDays=...It says whether a labelled transport has arrived and when the first scorable beat was banked, which is the boundary the whole thing turns on.
Please keep raw health data and full exports off the issue; those two lines plus a pass or fail is enough. If something genuinely needs more detail, say so here and we will find a better channel for it than a public thread.
Leaving this open. The original symptom is handled, the follow-up belongs to #2126, and I would rather this stayed open until you can confirm which of the two mechanisms you hit.
rafaelphh commentedon Sep 12, 2026
@ryanbr Confirmed the displayed post-rescore values are for 2026-09-11:
New rrTransport diagnostic from the current staging build:
rrTransport recorded=2026-08-31 15:07:08 scorable=2026-09-11 14:27:58 unscorableHistory=yes gapDays=11
The export was taken after a completed re-score of 13 nights.
I’m keeping the full diagnostic bundle off the public issue as requested.
ItsMeDrath commentedon Sep 15, 2026
@bhelm @rafaelphh @ryanbr$R\text{-}R$ data in the local database is intact. The snapshot preservation logic in 11.7.0 still appears to be triggering a re-score pass that overwrites these fields for my dataset.
Tested this on 11.7.0 upgrading directly from a working 11.5 state, but the issue is still present.Upon opening 11.7.0, HRV and Breathing Rate briefly display on startup, but vanish to null after a few seconds when the background re-score runs (even when tested offline / with Bluetooth off).Downgrading back to 11.5 immediately restores all historical HRV and BR metrics without needing to restore from a backup, confirming the underlying raw