Skip to content

iOS/macOS: log 5/MG GET_DATA_RANGE diagnostics (sync gated until validated) (#695) - #696

Merged
ryanbr merged 2 commits into
mainfrom
fix/swift-5mg-datarange-695
Jul 21, 2026
Merged

ryanbr merged 2 commits into
mainfrom
fix/swift-5mg-datarange-695

Conversation

@ryanbr

@ryanbr ryanbr commented Jul 21, 2026 •

Copy link
Copy Markdown
Owner

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_RANGE handler keyed on frame[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 — no strapNewestTs, no #547 backfill window, and none of the #451/#364/#928 diagnostics or the #689 pagesBehind line 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:

  • the WHOOP4 case: cmdOff: 6, feedsSync: true (byte-identical to before), and
  • the 5/MG case: cmdOff: 10, feedsSync: false, detected via the puffin type-0x24@8 / cmd@10 shape.

Why it's safe to merge now

feedsSync gates 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.

ryanbr added 2 commits July 21, 2026 18:42
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>
@ryanbr ryanbr changed the title iOS/macOS: handle 5/MG GET_DATA_RANGE replies (#695) iOS/macOS: log 5/MG GET_DATA_RANGE diagnostics (sync gated until validated) (#695) Jul 21, 2026
@ryanbr
ryanbr merged commit 7f50153 into main Jul 21, 2026
7 checks passed
@ryanbr
ryanbr deleted the fix/swift-5mg-datarange-695 branch July 21, 2026 07:00
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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

iOS/macOS misses 5/MG GET_DATA_RANGE diagnostics (newest/oldest/backlog) — handler is 4.0-only

1 participant