Repository navigation
iOS/macOS: log 5/MG GET_DATA_RANGE diagnostics (sync gated until validated) (#695) - #696
Merged
Merged
Conversation
The Swift GET_DATA_RANGE handler keyed on frame[6] (the WHOOP4 cmd offset), so a 5/MG reply — whose puffin envelope puts the cmd byte at 10 — was never processed: no strapNewestTs (liveness watchdog), no #547 backfill session window, and none of the #451/#364/#928 diagnostics or the #689 pagesBehind line, on 5/MG. Android already handled both via a computed cmdOff (#78 fork). Extract the handler into handleDataRangeResponse(frame, cmdOff:) — a behavior- preserving move of the existing WHOOP4 body — and call it from the WHOOP4 case (cmdOff 6, byte-identical) AND the 5/MG case (cmdOff 10, detected via the puffin type-0x24@8 / cmd@10 shape the probe dispatches already use). newest/oldest SCAN the frame (offset-agnostic); only pagesBehind uses cmdOff. The 5/MG path is NOT yet hardware-confirmed: the #451 raw dump + logs let a 5/MG strap log verify it (NOOP's unconfirmed-5/MG pattern), and the #547 window gate ignores a malformed range, so a mis-scan can't pollute ingest. Needs on-device 5.0/MG validation before it's trusted for sync. Author: ryanbr <mp3geek@gmail.com>
Gate the sync-affecting side-effects (strapNewestTs, #547 backfill window, LiveState range) behind a feedsSync flag. WHOOP4 passes feedsSync=true (byte-identical). The 5/MG path passes false: it LOGS the raw dump / pagesBehind / newest / oldest / clock-drift (so a strap log can validate the decode) but leaves sync UNCHANGED — so 5/MG behaviour is byte-identical to before plus the new diagnostic lines, with zero unvalidated sync change. Flip the 5/MG call to feedsSync=true once a real 5.0/MG strap confirms the newest/oldest decode. This makes #696 safe to merge now; enabling 5/MG sync becomes a one-line validated follow-up. Author: ryanbr <mp3geek@gmail.com>
DX23876
pushed a commit
to DX23876/noop
that referenced
this pull request
Jul 22, 2026
…dated (ryanbr#695) (ryanbr#696) Extract the GET_DATA_RANGE handler into handleDataRangeResponse(frame,cmdOff,feedsSync); call from the WHOOP4 case (cmdOff 6, feedsSync true — byte-identical) and the 5/MG case (cmdOff 10, feedsSync false). Previously keyed on frame[6] so 5/MG replies were skipped. feedsSync gates the sync-affecting side-effects (strapNewestTs, ryanbr#547 backfill window, LiveState range), so 5/MG only LOGS the dump/pagesBehind/newest/oldest/clock-drift for validation — behaviour byte-identical to before + diagnostic lines. Flip to true once a 5.0/MG strap log confirms the decode.
simoncad7
pushed a commit
to simoncad7/noop
that referenced
this pull request
Aug 17, 2026
…dated (ryanbr#695) (ryanbr#696) Extract the GET_DATA_RANGE handler into handleDataRangeResponse(frame,cmdOff,feedsSync); call from the WHOOP4 case (cmdOff 6, feedsSync true — byte-identical) and the 5/MG case (cmdOff 10, feedsSync false). Previously keyed on frame[6] so 5/MG replies were skipped. feedsSync gates the sync-affecting side-effects (strapNewestTs, ryanbr#547 backfill window, LiveState range), so 5/MG only LOGS the dump/pagesBehind/newest/oldest/clock-drift for validation — behaviour byte-identical to before + diagnostic lines. Flip to true once a 5.0/MG strap log confirms the decode.
DX23876
added a commit
to DX23876/noop
that referenced
this pull request
Oct 20, 2026
…e card The Momentum card averaged every loaded day's HRV for its "HRV x% under baseline" headline, its detail line, the HRV delta chip and the "above or below baseline for N days" trend. That mean kept the nights before a manual "Recalibrate baseline" and the imported history Charge had already dropped, so a week after a reset the card still compared against the old level while the "What shaped it" breakdown below it read HRV as above baseline. All four readouts now take Repository.chargeBaselines.hrv, the baseline Charge scored against, on both Today screens and both dashboards. The ryanbr#696 ratio guard moves with the pure delta core into MomentumCopy, and the percentage stays hidden until that baseline is usable. Analysis migration required: no (screen readout only; no stored value or scoring input changes).
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.
Fixes #695. Ports Android's both-families GET_DATA_RANGE handling to Swift — safely: the 5/MG path is diagnostic-only until validated on hardware.
The gap
Swift's
GET_DATA_RANGEhandler keyed onframe[6](the WHOOP 4.0 command offset). On 5.0/MG the puffin envelope puts the command byte at 10, so the reply was silently skipped — nostrapNewestTs, no #547 backfill window, and none of the #451/#364/#928 diagnostics or the #689pagesBehindline on 5/MG.The change
Extract the handler into
handleDataRangeResponse(_ frame:cmdOff:feedsSync:)— a behavior-preserving move of the WHOOP4 body — and call it from:cmdOff: 6, feedsSync: true(byte-identical to before), andcmdOff: 10, feedsSync: false, detected via the puffintype-0x24@8 / cmd@10shape.Why it's safe to merge now
feedsSyncgates the sync-affecting side-effects (strapNewestTs, the #547 backfill window,LiveState.setStrapRange). The 5/MG call passes false, so on 5/MG it only logs the raw dump / pagesBehind / newest / oldest / clock-drift — enough for a strap log to validate the decode — while leaving sync unchanged. So 5/MG behavior is byte-identical to before + the new diagnostic lines; zero unvalidated sync change. WHOOP4 is unchanged.Follow-up
Once a real 5.0/MG strap log confirms the newest/oldest decode is correct, flip the 5/MG call to
feedsSync: true(one line) to give 5/MG the full watchdog/backfill benefit.Verification
Swift-only (BLEManager). WHOOP4 path is a byte-identical extraction (verified via code-diff). macOS + iOS app-build — re-running on the gated version.