Skip to content

Alarm: name the "no alarm stored" readback plainly + log SET_ALARM_TIME's result byte (#34) - #392

Merged
ryanbr merged 1 commit into
ryanbr:mainfrom
digitalerdude:fix/34-alarm-clock
Jul 14, 2026
Merged

ryanbr merged 1 commit into
ryanbr:mainfrom
digitalerdude:fix/34-alarm-clock

Conversation

@digitalerdude

Copy link
Copy Markdown

Summary

  • A GET_ALARM_TIME readback of epoch 0 was logged as "unrecognised payload — layout undocumented," which hid the most diagnostic signal in a "didn't buzz" report on [master] Alarm not buzzing #34: the strap explicitly telling us it has no alarm stored (i.e. a SET_ALARM_TIME that silently failed to persist). That case is now named plainly instead.
  • SET_ALARM_TIME's own COMMAND_RESPONSE result byte (WHOOP 4.0) is now logged — previously thrown away on both platforms. Log-only, no verdict claimed: the 4.0 result-code meaning is unverified (the 5/MG puffin table is 0=FAILURE 1=SUCCESS 2=PENDING 3=UNSUPPORTED, but the existing 4.0 reboot-probe code assumes 0=accepted — the two contradict, so this just surfaces the raw byte).
  • Both changes are log-only diagnostics; no BLE arm/disarm behavior changes. Mirrored in Swift (Strand/BLE/FrameRouter.swift) and Kotlin (android/.../ble/WhoopBleClient.kt) per the cross-platform parity contract.

Context: issue #34 comment from a WHOOP 4.0 owner on v8.7.0 — the strap ACKs the arm and the alarm logs "armed," but every readback comes back as epoch 0, and the alarm never buzzes. This surfaces exactly why.

Test plan

  • swift test equivalent: xcodebuild -scheme Strand -destination 'platform=macOS' -only-testing:StrandTests/AlarmReadbackDecodeTests test — 17/17 passed (also validates the app-target FrameRouter compiles, since swift-packages.yml doesn't cover Strand/)
  • Android: ./gradlew testFullDebugUnitTest --tests "com.noop.ble.AlarmReadbackDecodeTest" — all green
  • Not tested on hardware (no strap available in this environment) — this is a log-only change with no BLE write path affected, so on-device verification is limited to confirming the new log lines appear on a real 4.0 strap

…ME's result byte (ryanbr#34)

A GET_ALARM_TIME readback of epoch 0 was logged as "unrecognised payload —
layout undocumented", hiding the single most diagnostic signal in a
"didn't buzz" report: the strap telling us it has no alarm armed, i.e. a
SET that silently failed to persist. Reframe that case plainly, and start
logging the strap's own accept/reject byte for SET_ALARM_TIME (WHOOP 4.0),
which was previously thrown away — log-only, no verdict claimed since the
4.0 result-code meaning is unverified. Mirrored in Swift and Kotlin with
matching tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@digitalerdude digitalerdude mentioned this pull request Jul 13, 2026
5 tasks done
@ryanbr
ryanbr merged commit 17e5b09 into ryanbr:main Jul 14, 2026
2 checks passed
ryanbr pushed a commit that referenced this pull request Jul 22, 2026
…34)

Log-only, no behaviour change. #34's remaining open question: since
v9.0.0, morning wake-up and morning short-horizon alarm tests fire
reliably, but an identical evening short-horizon test does not - same
code path, same commands, no day/night branch anywhere in
armStrapAlarm. One firmware-side explanation that would fit every
reported case: the physical alarm haptic might only fire while the
strap's own sleep/rest detection considers the wearer sleep-adjacent,
independent of anything NOOP sends.

This doesn't prove or fix that - it's a free read of HR already
tracked live, persisted alongside the existing Alarm-block fields
(sent epoch, connected, clock skew) and surfaced in the debug export,
so the next reported failure (ideally a captured evening one) can be
compared against the resting HR of the successful arms already on
file. Mirrors the #392 precedent of both-platform log-only alarm
diagnostics.

No stored analytics/formula changed; both platforms touched for
parity per usual.
DX23876 pushed a commit to DX23876/noop that referenced this pull request Jul 22, 2026
…ME's result byte (#34) (ryanbr#392)

A GET_ALARM_TIME readback of epoch 0 was logged as "unrecognised payload —
layout undocumented", hiding the single most diagnostic signal in a
"didn't buzz" report: the strap telling us it has no alarm armed, i.e. a
SET that silently failed to persist. Reframe that case plainly, and start
logging the strap's own accept/reject byte for SET_ALARM_TIME (WHOOP 4.0),
which was previously thrown away — log-only, no verdict claimed since the
4.0 result-code meaning is unverified. Mirrored in Swift and Kotlin with
matching tests.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
DX23876 pushed a commit to DX23876/noop that referenced this pull request Jul 22, 2026
…34)

Log-only, no behaviour change. #34's remaining open question: since
v9.0.0, morning wake-up and morning short-horizon alarm tests fire
reliably, but an identical evening short-horizon test does not - same
code path, same commands, no day/night branch anywhere in
armStrapAlarm. One firmware-side explanation that would fit every
reported case: the physical alarm haptic might only fire while the
strap's own sleep/rest detection considers the wearer sleep-adjacent,
independent of anything NOOP sends.

This doesn't prove or fix that - it's a free read of HR already
tracked live, persisted alongside the existing Alarm-block fields
(sent epoch, connected, clock skew) and surfaced in the debug export,
so the next reported failure (ideally a captured evening one) can be
compared against the resting HR of the successful arms already on
file. Mirrors the ryanbr#392 precedent of both-platform log-only alarm
diagnostics.

No stored analytics/formula changed; both platforms touched for
parity per usual.
simoncad7 pushed a commit to simoncad7/noop that referenced this pull request Aug 17, 2026
…ME's result byte (ryanbr#34) (ryanbr#392)

A GET_ALARM_TIME readback of epoch 0 was logged as "unrecognised payload —
layout undocumented", hiding the single most diagnostic signal in a
"didn't buzz" report: the strap telling us it has no alarm armed, i.e. a
SET that silently failed to persist. Reframe that case plainly, and start
logging the strap's own accept/reject byte for SET_ALARM_TIME (WHOOP 4.0),
which was previously thrown away — log-only, no verdict claimed since the
4.0 result-code meaning is unverified. Mirrored in Swift and Kotlin with
matching tests.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
simoncad7 pushed a commit to simoncad7/noop that referenced this pull request Aug 17, 2026
…yanbr#34)

Log-only, no behaviour change. ryanbr#34's remaining open question: since
v9.0.0, morning wake-up and morning short-horizon alarm tests fire
reliably, but an identical evening short-horizon test does not - same
code path, same commands, no day/night branch anywhere in
armStrapAlarm. One firmware-side explanation that would fit every
reported case: the physical alarm haptic might only fire while the
strap's own sleep/rest detection considers the wearer sleep-adjacent,
independent of anything NOOP sends.

This doesn't prove or fix that - it's a free read of HR already
tracked live, persisted alongside the existing Alarm-block fields
(sent epoch, connected, clock skew) and surfaced in the debug export,
so the next reported failure (ideally a captured evening one) can be
compared against the resting HR of the successful arms already on
file. Mirrors the ryanbr#392 precedent of both-platform log-only alarm
diagnostics.

No stored analytics/formula changed; both platforms touched for
parity per usual.
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.

2 participants