Skip to content

ble: extract GET_DATA_RANGE newest-parse into WhoopProtocol so both platforms CI-test the parity (#286 follow-up) - #307

Merged
ryanbr merged 1 commit into
mainfrom
extract-datarange-whoopprotocol
Jul 12, 2026
Merged

ryanbr merged 1 commit into
mainfrom
extract-datarange-whoopprotocol

Conversation

@ryanbr

@ryanbr ryanbr commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Follow-up to #286. Closes the same byte-parity CI gap the Oura #306 follow-up did.

Why

dataRangeNewestUnix decodes strapNewestTs, which gates automatic sync (isFutureDatedNewest → BackfillPolicy), so it must stay byte-identical Swift/Kotlin. #286 left it inline in app-target BLEManager/WhoopBleClient with a Kotlin test only — a Swift-side edit could silently drift the parity.

What

Move the pure scan into:

  • WhoopProtocol.DataRange (Swift — builds + tests on Linux)
  • com.noop.protocol.DataRange (Kotlin)

Byte-identical twins. BLEManager and WhoopBleClient keep their signatures as thin wrappers passing their own future-skew constant, so all call sites + the existing DataRangeScanTest are unchanged. Adds DataRangeTests (Swift) mirroring the Kotlin fixtures — the real WHOOP 4.0 offset-8 frames + the future/skew cases.

Verification

  • WhoopProtocol swift test: 259/259 incl. 4 new DataRangeTests — run locally on Linux (WhoopProtocol is pure).
  • Android compileFullDebugKotlin + DataRangeScanTest green (wrapper → pure).
  • BLEManager compile: app-build.
  • Now the parity is pinned by CI on both platforms (swift-packages + JVM), not the Kotlin side only.

…latforms CI-test the parity (#286 follow-up)

dataRangeNewestUnix decodes strapNewestTs, which gates automatic sync
(isFutureDatedNewest -> BackfillPolicy), so it must stay byte-identical Swift/
Kotlin. #286 left it inline in app-target BLEManager/WhoopBleClient with a Kotlin
test only — a Swift-side edit could silently drift the parity (the same gap the
Oura #306 follow-up closed).

Move the pure scan into WhoopProtocol.DataRange (Swift, builds+tests on Linux) and
com.noop.protocol.DataRange (Kotlin), byte-identical twins. BLEManager and
WhoopBleClient keep their signatures as thin wrappers that pass their own
futureSkew constant, so all call sites + the existing DataRangeScanTest are
unchanged. Adds DataRangeTests (Swift) mirroring the Kotlin fixtures — the real
WHOOP 4.0 offset-8 frames + the future/skew cases.

WhoopProtocol swift test 259/259 incl. 4 new DataRangeTests (run on Linux);
Android compileFullDebugKotlin + DataRangeScanTest green. BLEManager compile: app-build.
@ryanbr
ryanbr merged commit b6cfb04 into main Jul 12, 2026
10 checks passed
@ryanbr
ryanbr deleted the extract-datarange-whoopprotocol branch July 12, 2026 04:01
ryanbr added a commit that referenced this pull request Jul 12, 2026
…he aligned-scan protection (#286 follow-up) (#308)

Second sibling in the GET_DATA_RANGE parser. Like dataRangeNewestUnix (extracted
in #307), dataRangeOldestUnix was inline in app-target BLEManager/WhoopBleClient
with NO test on either platform — a parity-critical decoder (it reports the banked
span = backlog DEPTH a deep oldest-first drain must cover, #364).

Re-review of #307 surfaced that the oldest read must NOT be "made consistent" with
the newest by scanning every offset. The minimum is fragile where the maximum is
not: a real WHOOP 4.0 frame (aa10..2263) carries a spurious plausible straddle at
byte offset 6 (1754857506, ~11 months BEFORE the true newest at offset 8). An
any-offset MIN would grab it and report a bogus ~11-month backlog; the aligned-
from-7 grid skips it. So this extracts the aligned scan VERBATIM (no behaviour
change) into WhoopProtocol.DataRange.oldestUnix + com.noop.protocol twin, keeps the
app-target methods as thin wrappers, and adds Swift+Kotlin tests that PIN the
protection (real frame -> nil; grid-aligned words -> min) so a future refactor
can't quietly reintroduce the false-backlog bug.

WhoopProtocol swift test 262/262 (+3 oldest); Android compileFullDebugKotlin +
DataRangeScanTest green. BLEManager compile: app-build.
DX23876 pushed a commit to DX23876/noop that referenced this pull request Jul 22, 2026
…latforms CI-test the parity (ryanbr#286 follow-up) (ryanbr#307)

dataRangeNewestUnix decodes strapNewestTs, which gates automatic sync
(isFutureDatedNewest -> BackfillPolicy), so it must stay byte-identical Swift/
Kotlin. ryanbr#286 left it inline in app-target BLEManager/WhoopBleClient with a Kotlin
test only — a Swift-side edit could silently drift the parity (the same gap the
Oura ryanbr#306 follow-up closed).

Move the pure scan into WhoopProtocol.DataRange (Swift, builds+tests on Linux) and
com.noop.protocol.DataRange (Kotlin), byte-identical twins. BLEManager and
WhoopBleClient keep their signatures as thin wrappers that pass their own
futureSkew constant, so all call sites + the existing DataRangeScanTest are
unchanged. Adds DataRangeTests (Swift) mirroring the Kotlin fixtures — the real
WHOOP 4.0 offset-8 frames + the future/skew cases.

WhoopProtocol swift test 259/259 incl. 4 new DataRangeTests (run on Linux);
Android compileFullDebugKotlin + DataRangeScanTest green. BLEManager compile: app-build.
DX23876 pushed a commit to DX23876/noop that referenced this pull request Jul 22, 2026
…he aligned-scan protection (ryanbr#286 follow-up) (ryanbr#308)

Second sibling in the GET_DATA_RANGE parser. Like dataRangeNewestUnix (extracted
in ryanbr#307), dataRangeOldestUnix was inline in app-target BLEManager/WhoopBleClient
with NO test on either platform — a parity-critical decoder (it reports the banked
span = backlog DEPTH a deep oldest-first drain must cover, ryanbr#364).

Re-review of ryanbr#307 surfaced that the oldest read must NOT be "made consistent" with
the newest by scanning every offset. The minimum is fragile where the maximum is
not: a real WHOOP 4.0 frame (aa10..2263) carries a spurious plausible straddle at
byte offset 6 (1754857506, ~11 months BEFORE the true newest at offset 8). An
any-offset MIN would grab it and report a bogus ~11-month backlog; the aligned-
from-7 grid skips it. So this extracts the aligned scan VERBATIM (no behaviour
change) into WhoopProtocol.DataRange.oldestUnix + com.noop.protocol twin, keeps the
app-target methods as thin wrappers, and adds Swift+Kotlin tests that PIN the
protection (real frame -> nil; grid-aligned words -> min) so a future refactor
can't quietly reintroduce the false-backlog bug.

WhoopProtocol swift test 262/262 (+3 oldest); Android compileFullDebugKotlin +
DataRangeScanTest green. BLEManager compile: app-build.
simoncad7 pushed a commit to simoncad7/noop that referenced this pull request Aug 17, 2026
…latforms CI-test the parity (ryanbr#286 follow-up) (ryanbr#307)

dataRangeNewestUnix decodes strapNewestTs, which gates automatic sync
(isFutureDatedNewest -> BackfillPolicy), so it must stay byte-identical Swift/
Kotlin. ryanbr#286 left it inline in app-target BLEManager/WhoopBleClient with a Kotlin
test only — a Swift-side edit could silently drift the parity (the same gap the
Oura ryanbr#306 follow-up closed).

Move the pure scan into WhoopProtocol.DataRange (Swift, builds+tests on Linux) and
com.noop.protocol.DataRange (Kotlin), byte-identical twins. BLEManager and
WhoopBleClient keep their signatures as thin wrappers that pass their own
futureSkew constant, so all call sites + the existing DataRangeScanTest are
unchanged. Adds DataRangeTests (Swift) mirroring the Kotlin fixtures — the real
WHOOP 4.0 offset-8 frames + the future/skew cases.

WhoopProtocol swift test 259/259 incl. 4 new DataRangeTests (run on Linux);
Android compileFullDebugKotlin + DataRangeScanTest green. BLEManager compile: app-build.
simoncad7 pushed a commit to simoncad7/noop that referenced this pull request Aug 17, 2026
…he aligned-scan protection (ryanbr#286 follow-up) (ryanbr#308)

Second sibling in the GET_DATA_RANGE parser. Like dataRangeNewestUnix (extracted
in ryanbr#307), dataRangeOldestUnix was inline in app-target BLEManager/WhoopBleClient
with NO test on either platform — a parity-critical decoder (it reports the banked
span = backlog DEPTH a deep oldest-first drain must cover, ryanbr#364).

Re-review of ryanbr#307 surfaced that the oldest read must NOT be "made consistent" with
the newest by scanning every offset. The minimum is fragile where the maximum is
not: a real WHOOP 4.0 frame (aa10..2263) carries a spurious plausible straddle at
byte offset 6 (1754857506, ~11 months BEFORE the true newest at offset 8). An
any-offset MIN would grab it and report a bogus ~11-month backlog; the aligned-
from-7 grid skips it. So this extracts the aligned scan VERBATIM (no behaviour
change) into WhoopProtocol.DataRange.oldestUnix + com.noop.protocol twin, keeps the
app-target methods as thin wrappers, and adds Swift+Kotlin tests that PIN the
protection (real frame -> nil; grid-aligned words -> min) so a future refactor
can't quietly reintroduce the false-backlog bug.

WhoopProtocol swift test 262/262 (+3 oldest); Android compileFullDebugKotlin +
DataRangeScanTest green. BLEManager compile: app-build.
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.

1 participant