Repository navigation
v18 @82: decode the SpO2 candidate as instrumentation (#103) - #709
Merged
ryanbr merged 1 commit intoJul 22, 2026
Merged
Conversation
The ryanbr#103 thread produced a decompile-sourced decode of v18 byte @82 (= inner 74): a strap-computed SpO2 % scalar, tri-mode - 70-100 a real %, bit-7 values saturation sentinels, other sub-70 diagnostic codes, populated only during sleep. An 8-night independent validation with real spread (corr +0.99, ~0.4%/night, tracks a 92% desat) meets the cross-night bar the thread had set - but the two nights checked on the original capture device moved OPPOSITE to the app value, so the cross-device evidence is split and unresolved. Per the project's derived-biosignal rule this therefore ships as INSTRUMENTATION ONLY: both decoders surface the in-band (70-100) value as a new `spo2_candidate_82` field beside the existing raw `aux_byte_82`, so more devices can correlate it against the WHOOP app's own nightly SpO2. It does not populate spo2Pct, any card, or any score - the existing never-invent-physiology guard test (spo2_red/spo2_ir absent on v18) still passes untouched. Both platforms in lockstep (Interpreter.swift / HistoricalStreams.kt), tri-mode gating pinned by new twin tests on each side; the shared decoder-oracle fixtures are unaffected (@82 = 0 on every fixture). docs/WHOOP5_DEEP_DATA.md updated from "no blood-oxygen value on the wire" to the current split-evidence state and what would flip it.
digitalerdude
marked this pull request as ready for review
July 21, 2026 16:05
DX23876
pushed a commit
to DX23876/noop
that referenced
this pull request
Jul 22, 2026
…trumentation v18 @82: decode the SpO2 candidate as instrumentation (ryanbr#103)
This was referenced Jul 22, 2026
simoncad7
pushed a commit
to simoncad7/noop
that referenced
this pull request
Aug 17, 2026
…trumentation v18 @82: decode the SpO2 candidate as instrumentation (ryanbr#103)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows up on the latest #103 developments (2026-07-17). Instrumentation only — this does not ship an SpO2 metric.
Where #103 stands
Three things happened in the thread, in order:
@82(= inner 74) as a strap-computed SpO2 % scalar: tri-mode — 70–100 a real %, bit-7 values (0x80/0xA0…) saturation sentinels, other sub-70 nonzero diagnostic codes; populated only during sleep.So the evidence is currently split across devices — the strongest yes so far, against an unexplained no on one device. Per the derived-biosignal rule (never a shipped metric on contested evidence; instrumentation first), the honest next step is to decode the candidate raw on every install so multiple devices can correlate it against the WHOOP app's own nightly SpO2 — which is what this PR does, and nothing more.
What changes
Packages/WhoopProtocol/Sources/WhoopProtocol/Interpreter.swift/android/.../protocol/HistoricalStreams.kt, byte-parity): alongside the existing rawaux_byte_82, an in-band (70–100) value now also surfaces asspo2_candidate_82with an explicit instrumentation-only note. Sentinels, diagnostic codes and the awake 0 produce no candidate key.spo2Pctstays null on every WHOOP 5.0, no card, no score, no persistence-schema change. The existing never-invent-physiology guard (testHistoricalV18OpticalFieldsAreNotNamedPhysiologically,spo2_red/spo2_irabsent on v18) passes untouched.@82= 0 on every fixture frame, verified by the byte-identical-copies drift guard).docs/WHOOP5_DEEP_DATA.md: the SpO2 section no longer claims "the v18 layout carries no blood-oxygen value" — it now describes the candidate, the split evidence, and what would flip it (multi-device cross-night tracking, including on the device where the two checked nights move opposite).Testing
swift test(Packages/WhoopProtocol): 308 tests, 0 failures — includes the newtestHistoricalV18Spo2Candidate82TriMode./gradlew compileFullDebugKotlin testFullDebugUnitTest --tests "com.noop.protocol.*"✓ — includes the newspo2Candidate82SurfacesOnlyInBandValuesand theDecoderOracleTestdrift guard