Repository navigation
NOOP 11.7.0
NOOP v11.7.0
A release about the app keeping up with you, and about readings meaning what they say.
A stress screen that keeps up
Scoring a day of stress reads hundreds of thousands of samples. That work was happening on the same
thread that draws the screen, so Today and Stress could sit unresponsive while they loaded. It now
runs off that thread on both platforms, the baseline is reduced a day at a time rather than held a
month at once, and the unprompted rescore yields to whatever you are doing instead of competing with
it for the machine.
The home-screen widget fills on its own schedule without the app being opened. A rescore that produces
nothing is retried rather than being allowed to spend the whole refresh interval, and the Today curve
is kept as fresh as the screen it links to.
The readings themselves now agree with each other. The 0 to 3 level has one spelling across the widget
and the card, and is no longer rounded a second time on its way to the widget. The screen draws its
line from the same sliding read the number is taken from. Movement is drawn as the stretches it
actually covers rather than as dots on the axis. An early morning says the day has not started rather
than reporting Calibrating, which reads like something is wrong.
WHOOP 5 readings in the units the strap sends
Thanks to @Trillient, two decoding faults are corrected.
R-R intervals arriving on the standard heart-rate profile were converted as though they were in the
Bluetooth spec's units. A WHOOP 5 sends milliseconds directly, so every interval taken from that
profile came out 2.3% low, and HRV computed from it inherited the error. What settled it was a paired
capture: the same beats arriving on both the strap's own channel and the standard one carry
byte-identical values, so only one of the two conversions could be right.
The console log's record header was read as a 16-bit counter spanning two bytes. Only the first is a
counter, and it wraps at 255. Across 2,978 records from a single night the second byte never moved
through nine of those wraps, which a real counter could not do. Both platforms now decode the two
fields separately.
An Oura ring that stops repeating itself
Thanks to @pipiche38 for a sustained run of corrections to the ring's history path.
A replayed burst that the ring's own clock disproves as a reboot no longer resets the history resume
cursor, and no longer announces a reboot that did not happen. A night that has just been offloaded is
scored immediately rather than waiting for the next periodic tick. History is fetched every five
minutes rather than every fifteen, the anchor check judges a ten second gap rather than only a thirty
second one, and an onset rekey is refused when the assembler's own clip never bound.
There is also a feature-mode control and a consolidated set of Oura diagnostics in the Test Centre,
the raw night sidecar stays in the export, and the SpO2 sample keeps only the channel that carries a
reading.
Scores that survive a re-score
Thanks to @bhelm. WHOOP 5 HRV and Recovery, and the vitals derived from R-R, were being dropped by a
re-score pass that could not recompute them, so a value you already had could disappear on a pass that
had nothing better to put in its place. Both are now preserved.
Readings that say when they are at a limit
A Fitness Age resting at the end of its scale now says so, rather than presenting a bound as though it
were a measurement, and points at the number that still moves when the age stops. On Sleep, a night
already detected and staged no longer sits under a banner claiming it is still being calculated, and
browsing back to a night with no stage data no longer shows the most recent night's date beneath it.
Diagnostics that name the cause
A device reporting no R-R now says whether the beats were never banked or were refused by the unit
policy, which are different problems with different answers. The nightly HRV summary says why it
reported nothing. A retired probe tells whoever reads its output which switch to turn on, and stops
under-reporting its own retirement. A re-arm clears a refusal latch that previously could not be
reached once set. The sync chip surfaces the strap's backlog.
Thanks
Thanks to @pipiche38 (Oura history, replay judgement, diagnostics and export), @Trillient (WHOOP 5
R-R units and console sequence decoding), @bhelm (preserving legacy HRV, Recovery and R-R vitals),
@kavemang (tile values that shrink rather than truncate, per-signal illness baselines, Android
guards), and @digitalerdude (parity tooling on macOS, sync chip backlog, and documentation that
describes what the code returns).
What's Changed
- fix(android): skip stress scoring without a widget by @kavemang in #2111
- fix(android): guard sleep session cache upserts by @kavemang in #2112
- feat(oura): add a SetFeatureMode enable control, consolidate Oura Test Centre diagnostics by @pipiche38 in #2105
- today(android): move Customize into the header cluster, where it stops covering the wordmark in #2113
- today(android): shape a hosted card clip from what it actually renders in #2114
- stress: reduce each baseline day as it is read, instead of holding thirty at once in #2116
- diag: say whether a device R-R beats were never banked or were refused by the unit policy in #2118
- Preserve legacy WHOOP 5 HRV and Recovery across re-score by @bhelm in #2115
- widget: retry a stress rescore that produced nothing, instead of spending the interval on it in #2121
- fix(oura): don't reset the history resume cursor to 0 on a stale replay the ring's own clock disproves as a reboot by @pipiche38 in #2100
- sleep: a night already in hand silences the calculating banner in #2122
- stress: draw the movement marks as the stretches they are, not as dots on the axis in #2124
- hrv: say why the nightly summary reported nothing in #2129
- illness: a handful of stored nights is not a baseline in #2132
- Describe what DayOwnerSource.candidatePriorities actually returns (#2026) by @digitalerdude in #2133
- probe: let a re-arm clear the refusal latch it could never reach in #2136
- Preserve legacy RR-derived vitals and remove accidental scaffolding by @bhelm in #2141
- ci: let the parity gate see main, so drift stops ambushing other PRs in #2142
- Sync chip: surface the strap backlog, with both counts inflected (#833) by @digitalerdude in #2138
- Say that the day-owner path uses archived candidates, not just inherits them (#2026) by @digitalerdude in #2134
- ble: tell a retired probe reader to turn the switch ON, and stop under-reporting retirement in #2160
- parity tests: pass on macOS, and resolve expand_twin_map's root (#2143 follow-up) by @digitalerdude in #2159
- parity_ledger: resolve the temp checkout root before deriving from it (#2143) by @digitalerdude in #2158
- fix(diagnostics): keep the night's raw Oura sidecar in the export — session-scoped, ring-buffered, fairly capped, generations merged by @pipiche38 in #2154
- doc(oura): correct the macOS pairing limitation - a factory-reset ring works fine by @pipiche38 in #2149
- docs(oura): fix the §7.5 heading left stale by 450256a by @pipiche38 in #2150
- fix(oura): score the ring's freshly-offloaded night now, not at the next periodic tick by @pipiche38 in #2147
- fix(oura): refuse the #1284 onset rekey when the assembler's own clip never bound by @pipiche38 in #2146
- fix(oura): only persist the SpO2 raw channel, drop dc_raw from spo2Sample by @pipiche38 in #2152
- fix(oura): fetch ring history every 5 min, not 15 — the periodic fetch is the real data cadence by @pipiche38 in #2153
- fix(oura): let the #2097 anchor check judge a 10 s gap, not only 30 s by @pipiche38 in #2155
- health: trust Android baselines per signal by @kavemang in #2157
- stress: one spelling for the 0-3 level, on the widget and the card in #2165
- stress: stop the widget snapshot rounding the level a second time in #2168
- stress: give the marker tile's reading the width the chip was holding in #2172
- ci: do not let a failed release delete look like a tag that already exists in #2175
- health: say when a Fitness Age is sitting on the end of its scale in #2176
- stress: keep the Today curve as fresh as the screen it links to in #2177
- today: put scan and connect on the Today header in #2178
- today: show the scan control only while the strap is away, and make it look like a scan in #2180
- stress: do not say Calibrating when the day has simply not started yet in #2182
- widget: refresh the stress curve without waiting for the app to be opened in #2186
- fix(oura): stop announcing a ring reboot the #2097 judge has just rejected by @pipiche38 in #2170
- health: point at the number that still moves when the age stops in #2189
- stress: draw the screen's line from the sliding read, not the bare hours in #2190
- stress: get the screen's work off the main thread and the chart out from behind it in #2191
- today: stop scoring a day of heart rate on the UI thread in #2194
- fix: decode WHOOP 5 console sequence as a wrapping u8 by @Trillient in #2192
- fix: WHOOP 5 R-R words are milliseconds, not 1/1024-second ticks by @Trillient in #2195
- whoop5: decode the Kotlin console sequence as a wrapping u8 in #2196
- whoop5: pin the Kotlin console sequence wrap, matching Swift in #2197
- test(ios): make the reject-archive protection skip visible on macOS in #2198
- test(import): assert the Inbox purge no-op off iOS instead of skipping it in #2200
- sleep: date the browsed night, not the newest one, in the nav header in #2201
- perf: let the unprompted analysis work actually yield to the UI in #2202
- ui: shrink ellipsized stat values by @kavemang in #2203
- ui: test the stat-value shrink rule, and guard the line index in #2204
- docs: release notes for 11.7.0 in #2205
Full Changelog: v11.6.0...v11.7.0
Downloads — NOOP Staging identity, installs beside the official app (separate data):
- Android —
NOOP-android-v11.7.0.apk(com.noop.whoop.staging) - macOS —
NOOP-macos-v11.7.0.zip(unzip, then right-click → Open) - iOS —
NOOP-ios-unsigned-v11.7.0.ipa(AltStore / Sideloadly)