Repository navigation
NOOP v12.0.0
A major release about choice and about honesty. Today can be drawn two different ways, a WHOOP 4.0 can
hand its heart rate to any app on your phone, daytime stress is measured against your own baseline
rather than a population's, and NOOP speaks a tenth language. Behind that, a long run of readouts that
had been claiming slightly more than they could attribute now say only what they know.
Today, drawn your way
- Ring gauges or liquid vessels (#2311, #2320, thanks @andigandhi). Today's gauges can be rings or
the liquid vessels, chosen per device, on Android and on Apple. Reduce Motion is honoured in both. - The hero ring, cleaned up (#2410, #2374, #2421, thanks @mailingjash). It draws flat rather than
through a bloom stand-in, its label sits centred on the ring rather than beside it, and the active
strap's own battery appears in the Liquid header. - Nothing redraws while nothing moves (#2444, thanks @UtkuDenizAltiok), so the sky and the rings
stop re-rendering between ticks. - A Today-only Key Metrics view (#2601, thanks @kavemang), and the Key Metrics header no longer
names a window it is not drawing (#2377, thanks @andremiliano). - Swipe the day the same way on both platforms (#2379, thanks @andremiliano).
Your strap's heart rate, in any app
- Direct Bluetooth heart-rate broadcast on WHOOP 4.0 (#2400, thanks @don86nl). A 4.0 can advertise
the standard heart-rate profile, so another app on your phone reads it live. The Today row says
Partly rather than Yes, because the 4.0 offers the broadcast and not the rest of what a strap does. - A link that reports its shape (#2399, #2429, #2436, #2411). The epitaph carries the signal shape
rather than only its last reading, a false start-of-frame is rejected by its own header checksum, the
peripheral is asked for again once the radio is up instead of scanning for one already bonded, and an
OS-level strap link is adopted from either WHOOP family. - A strap last seen low that has not been heard from since now says so, rather than going quiet.
Daytime stress, measured against you
- A personal daytime lens (#2125, #2430, #2431, #2432, #2452, thanks @bartmuskala). Resolved once a
day instead of once per surface and anchored to real local days. The line ramps down the chart rather
than across the day, and hours masked by activity now say why they are masked. - Today honours the same baseline the detail screen does (#2450, #2504, thanks @kavemang), and it
loads faster. It stays opt-in and off until you ask for it. - The LF/HF ratio prints through the same arithmetic on both platforms (#2369, thanks @ayiskakov).
ECG on WHOOP MG
- The R17 layout corrected, along with its wrist values and its START list.
- Android drives the turn-on probe Apple already had, an in-flight offload is cleared before a
realtime trace is requested, and the capture-may-be-running latch survives an app restart and reaches
the Devices card.
Language
- Italian (#2454). NOOP's tenth language.
- Russian that counts properly. Grammatical plurals across the app, the Watch complications and the
Apple catalogues, so counts take the right form instead of always one. Eight mistranslated Android
strings are corrected, and the copy a widened scanner surfaced is localised. - The coverage gate is diff-scoped again (#524, thanks @digitalerdude), and a push is compared
against the tip before it rather than against itself (#2329).
Sleep
- A deep base prior of 0.15, on PSG evidence (#2576, thanks @UtkuDenizAltiok), scored subject by
subject rather than in aggregate. - The hypnogram read-out matches its own rows, in order and in value, and stage rows align with
chart depth. - Two sources recording one night are collapsed (#2550, thanks @kavemang), and the dedup heal's
bank-recency witness is handed to the computed id alone (#2372).
Oura
- A ring that keeps its place (#2442, #2455, #2457, #2433, #2443, thanks @pipiche38). A sleep-window
stash survives a reconnect, an interrupted drain banks its resume cursor so the next connect does not
store again what it already holds, and a night the drain served twice is readable. - A hypnogram tail that is padding, not time (#2564, thanks @pipiche38), so a pass no longer shifts
early, and the ring's final pass no longer loses to an older one. - A read crossing wake keeps the daytime beats (#2624, thanks @pipiche38), chosen per hour so a
day-wide read does not swap channels. - Experimental all-day heart rate and HRV holds its daytime arming for the learned night rather than
for every screen-off (#2412).
Charge
- A breakdown that agrees with its headline (#2466, thanks @andremiliano). It reads the headline's
own baselines rather than resolving a second set, and there is now a written rule for which nights a
Charge baseline reads. - An old WHOOP import no longer anchors the baselines (#2666, thanks @DX23876).
A quicker Apple app
- Ten performance changes (#2633, #2634, #2635, #2636, #2637, #2639, #2640, #2641, #2642, thanks
@AlexSchmidt1999). Live Today Effort computes off the main actor, resolved Trends windows are reused
across unrelated publications, HealthKit observer deltas are bounded to the recent sync window, shared
chart styles resolve once per content update, full-resolution chart selection uses a date-ordered
lookup, and the shared panel background composites fewer layers. - Re-score passes that behave in the background (#2612, #2616, thanks @UtkuDenizAltiok and
@kavemang), spaced at least thirty minutes apart and claiming their pass before a store await.
Shortcuts, Health and the Lock Screen
- A recorded GPS route through Shortcuts (#2340, thanks @rodrigosa7), as GPX or FIT, and the picker
says what a FIT leaves out. - Apple Health export names its chart heart-rate sources and refreshes write authorization.
- Android reads your profile weight from Health Connect (thanks @paradix86).
- One Lock Screen switch per thing NOOP shows, each touching only its own.
Smaller corrections
- Android honours your selected accent in Material controls (#2627) and rejects a malformed custom
RGB value. - Vital dates carry their weekday (#2622, thanks @kavemang).
- Today explains when Start session is available, and the Sleep movement strip says its scale is
per-night. - Deep Timeline zoom and pan stop snapping back (#2368, #2382, thanks @andigandhi), with x-axis
labels and per-minute zoom ticks on both platforms. - Saved-workout overlap suppression is measured rather than guessed at (#2527, thanks @kavemang),
ahead of choosing a duration-aware threshold.
Still open
WHOOP 5/MG history remains unsolved, and the cause is now established rather than suspected: the strap
refuses the pairing handshake outright, so it is never given a clock, and an un-clocked 5/MG does not
persist sensor data to flash. Its offloads complete empty. Live heart rate works; the backfill cannot,
until the handshake does.
What's Changed
- feat(rescore): log a pass's CPU time and assertion expiries beside its elapsed time by @Iskrata in #2297
- fix(oura): watch the auth handshake — an unanswered get_nonce is retried, toggled, then dropped, never left "Connected" by @pipiche38 in #2307
- fix(live): no WHOOP strap picker or Scan / Re-scan under an active Oura ring — a ring gets its status and a Reconnect by @pipiche38 in #2306
- docs(oura): stop claiming an Apple framework property as a twin in #2316
- fix(charge): score the breakdown against the baseline the ring rides in #2317
- fix(rescore): pace a backgrounded pass in 10-second quanta so it isn't suspended after every night by @Iskrata in #2318
- Android: Change LiquidVessel gauges to GlowRing by @andigandhi in #2311
- Android: let Today choose ring gauges or the liquid vessels in #2320
- Alarm readback: refuse to judge one that answered an earlier arm in #2322
- Sleep: show "May be incomplete" only when the night actually reads short in #2324
- Parity: re-derive the twin-map authority after the scanner and source drift in #2325
- Parity: declare the OuraAuthWatchdog twin where the ledger reads it in #2326
- Changelog: say which platforms the 11.8.0 lift log actually shipped on in #2328
- i18n CI: make the coverage gate diff-scoped again, not a full-tree invariant by @digitalerdude in #524
- i18n CI: diff a push against the tip before it, not against itself in #2329
- docs: WHOOP 4 protocol parity, contract-to-implementation map and source-reference check by @bhelm in #2310
- Sleep: ask every block whether the night was staged on sparse motion in #2331
- Sleep: give Android the H9 low-confidence note it was promised in #2330
- BLE: put the link's signal strength on its epitaph in #2333
- Health: say why HRV is blank when the night over-reported R-R in #2336
- feat(apple): dynamic charge ring color based on recovery score zones by @adamstefanik in #2309
- BLE: redact the chosen strap name in the rename log in #2337
- Android: Show Effort Suggestion on Today Page by @andigandhi in #2323
- fix(rescore): retry an unfinished background pass after a cooldown instead of deferring until the app is opened by @Iskrata in #2334
- RootTabView: drop the unreachable second
case .coachby @Iskrata in #2349 - Lab Book: show custom markers at their own precision by @Iskrata in #2347
- Lab CSV import: a count row and its % row no longer overwrite each other by @Iskrata in #2348
- 5/MG strap name: a read-only probe, and an honest explainer in #2339
- 5/MG strap name: allow the rename, behind Test Centre and an in-flight gate in #2352
- Alarms screen: say which wake time actually wakes you in #2353
- Alarms: count down to the next guaranteed wake on Android too in #2354
- Body clock dial: give every element its own radius, and label the hours in #2355
- Appearance: let the gauge numerals be softer in #2357
- Backup picker: report what the sheet did, not why in #2359
- sleep-detect: stop claiming no-motion means nothing could stage a night in #2362
- feat(oura): Test Centre toggle to send the official app's SetNotification mask ff (packed-notification A/B) by @pipiche38 in #2361
- LiquidTodayView: Weight metric hardcoded to dash by @rodrigosa7 in #2343
- fix(health): hold a still-open night out of Apple Health until it closes by @Iskrata in #2294
- Add shared parity cases with independent expected-result validation by @bhelm in #2104
- docs: add a validation protocol for scoring changes by @vishk23 in #988
- fix(diagnostics): read last sleep and recovery from the strap actually being worn in #2364
- fix(diagnostics): put the R-R transport line in every export, not only after an offload in #2385
- Android: Fixed the Deep Timeline zoom/pan "snap back" issue by @andigandhi in #2382
- Strap log: keep every line on disk, across restarts, within 2 MB by @UtkuDenizAltiok in #2386
- hrv: a nightly 5-min window needs minBeats clean intervals to count by @Iskrata in #2389
- fix(health): never write RMSSD under the SDNN type in the Apple Health export by @Iskrata in #2388
- today: swipe the day the same way on both platforms by @andremiliano in #2379
- log: say whether a timed-out offload actually banked anything in #2390
- ble(android): start the keep-alive on a 5/MG that bonds by CLIENT_HELLO in #2391
- ble: give Android the HR notify line iOS has always printed in #2392
- ci: ship the macOS app built Release, like the iOS one in #2396
- macos: stop the decorative frame loops when no window can be seen in #2394
- design: parse a dynamic colour's hex once per token, not once per frame in #2395
- macos: filter the window list on .titled, so a hidden window still counts in #2401
- sleep: name the night on the HR-only funnel lines in #2398
- ble: report the link's signal shape on the epitaph, not just its last reading in #2399
- Lift Log: follow-ups from seven gym sessions by @UtkuDenizAltiok in #2403
- diagnostics: summarise the standard-HR host-received line, keep every refusal by @UtkuDenizAltiok in #2402
- ui: take the keyboard watcher's recognizer off the window in deinit too in #2404
- diagnostics: report the stall that crosses a window boundary in #2405
- diagnostics: say how long a passive reconnect waited for the OS in #2406
- Android: Missing Backend for Rhythm Screen by @andigandhi in #2381
- fix(today): draw the active ring's own battery in the Liquid header instead of nothing (#2208 second half) by @pipiche38 in #2374
- fix(sleep): hand the #899 heal's bank-recency witness to the computed id only, never to a ring's own rows by @pipiche38 in #2372
- parity(stress): the LF/HF ratio prints through the same tenths arithmetic on both platforms by @ayiskakov in #2369
- fix(live): Live-screen strap-log save carries the same extras as Settings and Test Centre by @ayiskakov in #2367
- diagnostics: REM funnel names the stager it replays vs the one that staged the screen by @ayiskakov in #2366
- fix(analytics): wire primary-session resting HR to fix nap floor dist… by @moyasserr in #2358
- today: draw the hero ring flat, without the bloom stand-in (#2407) in #2410
- ble: stamp the passive-reconnect wait after the reconnect is scheduled (#2406) in #2411
- Support direct heart-rate broadcasting on WHOOP 4.0 by @don86nl in #2400
- fix(oura): do not arm daytime HR on a connect made while live HR is suspended by @pipiche38 in #2412
- ios: push the Live HR banner only when what it shows changes by @UtkuDenizAltiok in #2415
- today: stop the Key Metrics header naming a window it is not drawing by @andremiliano in #2377
- cleanup: remove private code nothing uses by @UtkuDenizAltiok in #2417
- workouts: record one heart-rate sample a second in a manual workout by @UtkuDenizAltiok in #2416
- stress: take each live R-R packet once in the iOS check-in by @UtkuDenizAltiok in #2418
- perf(rescore): stop a post-sync pass re-scoring nights and cycles whose inputs did not change by @Iskrata in #2293
- ble: reject a false start-of-frame by its own header checksum in #2429
- fix(hrv): do not replace a refused main night's HRV with the day's naps by @pipiche38 in #2426
- log(hrv): describe the main night the gate judged in the hrv diag line by @pipiche38 in #2427
- live HR: show only a heart rate the strap is measuring, and keep the banner until its switch turns it off by @UtkuDenizAltiok in #2422
- log(oura): say WHICH SpO2 channel a first-decoded line is reporting by @pipiche38 in #2408
- stress: ramp the daytime line down the chart, not across the day in #2432
- ble: ask again for the peripheral once the radio is up, instead of scanning for one already bonded in #2436
- trends: place the date axis on named days, so a label cannot print twice over itself in #2447
- charts: put the other two date axes on named days as well, and leave the two hour axes alone in #2448
- ci: run the Tools suites that read product source on every change, and filter only the leg that does not in #2451
- fix(stress): honor the personal baseline on Today by @kavemang in #2450
- stress: give the daytime-lens memo a slot per lens, and anchor the Apple resolver to real local days in #2452
- storage: stage NOOP's temp scratch in a folder it owns, and sweep only that in #2453
- oura: bank an interrupted drain's resume cursor, so the next connect does not restore what it already stored in #2455
- oura: collapse a ring record the drain served twice, so a redrained night is readable again in #2457
- Health: Calculate effort for Apple Health workouts by @rodrigosa7 in #2440
- fix(oura): score one R-R beat channel per window, not 0x80 on top of 0x60 by @pipiche38 in #2423
- fix(diag): keep the Night line's rr= counting beats banked, on both platforms by @pipiche38 in #2435
- docs: say that an Android test run after a branch switch needs --no-build-cache --rerun-tasks in #2458
- feat(diag): name the day's HRmax source and its observed peak (#2438) in #2459
- ios: score today's Effort against the same HRmax as the day it belongs to (#2460) in #2461
- feat(i18n): add Italian localization by @paradix86 in #2454
- diag: say WHERE a NO-NIGHT's provided sessions fall, on both platforms in #2472
- android: allow bedtime edits across midnight, with the arithmetic covered and the picker cleaned up in #2474
- fix(oura): keep the 0x49 sleep-window stash across a reconnect, so a burst on the next link still anchors by @pipiche38 in #2442
- i18n: stop assembling localized Android copy in code, Italian included in #2476
- rr: label WHOOP 4 type-47 history and score one R-R stream per window in #2478
- store: order Oura raw pages by fetch time, with the contract it pins made exact in #2479
- settings: Live notifications, one switch each, and each hides only its own in #2480
- live HR banner: observe the median, and read once the change has landed in #2481
- Coach high-load threshold on the stored Effort axis, with parity and conversion corrections in #2487
- 5/MG alarm guidance points at Protocol probes, and the comments say what was captured in #2488
- parity: re-base the stored authority onto the current derivation in #2497
- Charge driver verdicts agree with the row, with parity and oracle corrections in #2500
- Apple Health workout route sync, with the point series out of the routes map in #2502
- Apple workout import: strap-HR Effort fallback, with one stream per row in #2503
- alarm diagnostics: name the switch a reader can find in #2509
- Liquid Today HR scrub, reading the renderer plot rather than a copy in #2510
- Alarms entry on Sleep, with the whole card as the tap target in #2513
- WHOOP 4 R-R source per UTC hour, with the ingress test and extractStreams pair repaired in #2515
- GPS workouts: bank the route while it is running, so a kill cannot shorten it in #2516
- test(android): make debug export scheduler tests DST-safe by @kavemang in #2483
- Clarify parity disposition and authority refresh flow by @kavemang in #2511
- docs: clarify stage vocabulary validation guidance by @kavemang in #2409
- Speed up personal stress baseline loading by @kavemang in #2504
- Surface the current Coach brief after an overnight app session by @kavemang in #2505
- Retire the stale Coach transcript on Android too in #2518
- Fix workout heart-rate time axis by @rodrigosa7 in #2494
- fix: align widget time axes with stress and heart-rate traces by @kavemang in #2490
- Register the iOS Coach brief background task, and serialise the generation attempt in #2519
- fix: update Coach key without clearing the conversation by @kavemang in #2489
- Deep Timeline x-axis labels, with the fine ticks kept off the Today card in #2520
- today: stop redrawing the sky and the rings while nothing moves by @UtkuDenizAltiok in #2444
- ios: write iOS's MetricKit reports into the strap log by @UtkuDenizAltiok in #2420
- Link the out-of-scope boundary from the contributor entry points in #2524
- Explain activity-masked stress hours in #2526
- Attribute the strap-clock verdict to the strap it is about in #2537
- ble: adopt an OS-level strap link from either WHOOP family in #2538
- i18n: check catalog keys at project-custom copy call sites in #2540
- i18n: localise the Apple copy the new gate surfaced in #2541
- i18n(android): correct eight mistranslated strings in #2542
- stress: resolve the personal daytime lens once a day, not once a surface in #2543
- diag: say when an alarm readback has no stored frame in #2545
- perf(ios): draw a tail of the strap log, not all 5,000 lines in #2546
- perf(ios): coalesce strap-log publishes instead of one per line in #2548
- fix: the stress timeline says it is loading instead of showing nothing in #2549
- sleep: one stage order across every surface (stacked on #2536) in #2551
- diag(ios): app identity in the export, and name a broken background-task registration in #2554
- feat: warn about a strap last seen low that has not been heard from since in #2559
- perf: sweep the HRV windows instead of re-filtering per window in #2560
- parity: re-derive the stored authority after the last product merges in #2568
- feat(oura): Experimental “Oura ring: all-day heart rate & HRV” — stand the daytime-HR hold down for the learned night, not for every screen-off by @pipiche38 in #2558
- refactor(data): one HR union fingerprint, not two that were free to disagree in #2570
- Preserve Apple Health steps after a failed step query by @rodrigosa7 in #2563
- doc(oura): §6.13 0x50 — the decode validated against Oura's export, record timestamp = END, Oura's active-calorie rule, confirmed-workout floor by @pipiche38 in #2565
- health: no Apple metric may be overwritten by a read that failed in #2571
- store: mark the WHOOP 5 500 ms R-R fill value as suspect by @UtkuDenizAltiok in #2569
- oura: say what the 0x50 MET decode's validation status actually is now in #2572
- store: say what tsSuspect means now that two causes set it in #2573
- sleep: lower the deep base prior to 0.15 on PSG evidence by @UtkuDenizAltiok in #2576
- sleep: compute the RSA transform's twiddle factors once per night by @UtkuDenizAltiok in #2575
- analytics: restore the primary-night resting-HR floor by @kavemang in #2557
- parity: record the two test-only call sites #2557 created in #2581
- ci: run the parity repository-acceptance suite on the unfiltered leg in #2582
- rescore: read the day fingerprint's R-R figures in one walk by @UtkuDenizAltiok in #2574
- parity: classify excluded Swift role twins by @kavemang in #2577
- oura: exclude unwritten hypnogram tail from layout by @kavemang in #2579
- today(android): remove orphan recording chip code by @kavemang in #2555
- Collapse overlapping sleep nights across device sources by @kavemang in #2550
- docs: record the parity authority workflow and its scope gaps in #2584
- fix(sleep): recover unmatched off-wrist tails from sustained HR in #2585
- fix(sleep): announce meaningful displayed result changes by @fadkeprasad in #2544
- diag(effort): report per-zone minutes on the effort score line in #2589
- ecg: clear an in-flight offload before asking for a realtime trace in #2590
- ecg: keep the capture-may-be-running latch across an app restart in #2591
- ecg: give Android the MG ECG turn-on probe Apple already drives in #2592
- fix(illness): persist the clear-to-raised edge so a restart cannot fake one in #2593
- ecg: correct the MG Labrador R17 layout, wrist values and START list in #2594
- fix(android): only count bond-watchdog bounces that reached the command channel in #2602
- fix(android): stop the unbonded probe naming a teardown cause it was never given in #2605
- perf(android): take the Test Centre log snapshot once per screen, not once per row in #2609
- fix(android): refresh workouts after captured session save by @SpurgtBror in #2596
- fix(iOS): claim re-score pass before store awaits by @kavemang in #2616
- Run legacy R-R preservation checks on every PR by @kavemang in #2597
- feat(readings): show weekdays beside vital dates by @kavemang in #2622
- liquid: keep the light-appearance night sky still; its stars cannot be seen by @UtkuDenizAltiok in #2619
- Offer a Today-only Key Metrics view by @kavemang in #2601
- cleanup: remove unreferenced declarations on both platforms by @UtkuDenizAltiok in #2617
- rescore: space backgrounded offload re-scores at least 30 minutes apart by @UtkuDenizAltiok in #2612
- breathing: make "Use my resonance pace" decide the check-in's pace by @UtkuDenizAltiok in #2618
- Preserve archived device history in Apple day ownership by @kavemang in #2600
- fix(Apple): attribute skin temperature readings to their source by @kavemang in #2620
- fix(Apple): explain legacy R-R gaps on Liquid Today by @kavemang in #2623
- fix(Android): keep illness alerts tied to evaluated nights by @kavemang in #2621
- Align Unicode numbers in Android lab marker keys (rebase of #2552) in #2628
- Keep illness alerts current after recovery (rebase of #2539) in #2629
- fix(oura): choose the R-R beat channel per hour, so a day-wide read keeps the daytime beats by @pipiche38 in #2625
- feat(android): use profile weight from Health Connect in #2632
- diag: add a sustained peak beside the raw one on the effort calib line in #2650
- fix(charge): stop an old WHOOP import from anchoring the Charge baselines by @DX23876 in #2666
- test(charge): pin the gap-longer-than-the-window display as a decision in #2670
- i18n(ru): pluralize skipped rows and chart series by @kavemang in #2669
- i18n(ru): pluralize hours across Apple catalog bundles by @kavemang in #2664
- i18n(ru): pluralize breathing and HRV counts on Apple by @kavemang in #2657
- i18n(ru): pluralize Lift Log repetitions and sets by @kavemang in #2662
- i18n(ru): pluralize Charge driver point counts by @kavemang in #2663
- i18n(ru): pluralize Lab Book marker and reading counts by @kavemang in #2665
- i18n(ru): pluralize sync progress and chunk counts by @kavemang in #2667
- i18n(ru): pluralize coverage and imported day counts by @kavemang in #2668
- i18n(ru): pluralize sleep history and calibration night counts by @kavemang in #2655
- docs: correct remaining Apple app CI coverage guidance by @kavemang in #2653
- Settings: explain which workouts auto-detection skips by @kavemang in #2658
- Settings: explain read-only Apple Health water import by @kavemang in #2656
- fix(today): explain Start session availability in customization in #2672
- fix(android): validate custom RGB accent values by @kavemang in #2630
- fix(android): honor selected accent in Material controls by @kavemang in #2631
- live-hr: remove a banner iOS has ended; it stays frozen on its last number by @UtkuDenizAltiok in #2659
- fix(apple): complete history repair before queued recent rescore by @kavemang in #2646
- Reduce layered compositing in the shared iOS panel background by @AlexSchmidt1999 in #2641
- i18n(ru): pluralize fitness and body age counts by @kavemang in #2671
- i18n(ru): pluralize imperial measurement accessibility counts by @kavemang in #2673
- i18n(ru): pluralize workout summary counts by @kavemang in #2674
- i18n(ru): pluralize battery percentage accessibility labels by @kavemang in #2675
- i18n(ru): pluralize interval countdowns on app and Watch by @kavemang in #2676
- i18n(ru): pluralize biometric accessibility quantities by @kavemang in #2677
- i18n(ru): pluralize shared reading range captions by @kavemang in #2678
- Bound HealthKit observer deltas to the existing recent sync window by @AlexSchmidt1999 in #2642
- Honor the shared motion policy in count-ups, entrances, and pip bars by @AlexSchmidt1999 in #2633
- Resolve shared chart styles once per content update by @AlexSchmidt1999 in #2636
- Use date-ordered lookup for full-resolution chart selection by @AlexSchmidt1999 in #2637
- Avoid assigning an unchanged Today pull-indicator offset by @AlexSchmidt1999 in #2634
- Keep the historical Today HR fallback trace still by @AlexSchmidt1999 in #2635
- Reuse resolved Trends windows across unrelated repository publications by @AlexSchmidt1999 in #2640
- Compute live Today Effort outside the main actor by @AlexSchmidt1999 in #2639
- fix(ios): export chart HR sources and refresh write authorization by @kavemang in #2645
- feat(ios): return a recorded GPS route through Shortcuts in #2680
- fix(ios): say what a FIT from the route Shortcut leaves out in #2683
- fix(sleep): name the movement strip and say its scale is per-night in #2686
- i18n(ru): use count forms for Journal day offsets by @kavemang in #2681
- i18n(ru): use count forms for enabled apps and HR readers by @kavemang in #2684
- i18n(ru): use count forms in Compare relationship summaries by @kavemang in #2687
- i18n(ru): use count forms for Caffeine intake summaries by @kavemang in #2688
- i18n(ru): use count forms for sleep-stage percentage labels by @kavemang in #2689
- i18n(ru): use count forms for chart reading summaries by @kavemang in #2690
- feat(android): add interactive workout HR chart and move route export by @SpurgtBror in #2595
- feat(today): start workouts through the existing recording flow by @kavemang in #2648
- diag(workouts): measure saved-session overlap suppression by @kavemang in #2692
New Contributors
- @adamstefanik made their first contribution in #2309
- @rodrigosa7 made their first contribution in #2343
- @andremiliano made their first contribution in #2379
- @ayiskakov made their first contribution in #2369
- @moyasserr made their first contribution in #2358
- @don86nl made their first contribution in #2400
- @paradix86 made their first contribution in #2454
- @DX23876 made their first contribution in #2666
- @AlexSchmidt1999 made their first contribution in #2641
Full Changelog: v11.8.0...v12.0.0
Downloads — NOOP Staging identity, installs beside the official app (separate data):
- Android —
NOOP-android-v12.0.0.apk(com.noop.whoop.staging) - macOS —
NOOP-macos-v12.0.0.zip(unzip, then right-click → Open) - iOS —
NOOP-ios-unsigned-v12.0.0.ipa(AltStore / Sideloadly)