Skip to content

Stop a working 4.0 battery read logging as a failure (#900) - #923

Merged
ryanbr merged 1 commit into
mainfrom
fix/battery-failure-log-noise-900
Jul 28, 2026
Merged

Stop a working 4.0 battery read logging as a failure (#900)#923
ryanbr merged 1 commit into
mainfrom
fix/battery-failure-log-noise-900

Conversation

@ryanbr

@ryanbr ryanbr commented Jul 28, 2026

Copy link
Copy Markdown
Owner

A landable piece of #900. It does not resolve that issue — which still needs one real 4.0 GET_BATTERY_LEVEL capture of known provenance — but it stops the log asserting an answer while we wait.

The line

WhoopBleClient logs every non-SUCCESS command response, which is how the MG haptics rejection (#48) would surface in-app. Every WHOOP 4.0 battery reply on record carries a zeroed [seq][result] prefix, so a battery read that worked logs:

Command response: GET_BATTERY_LEVEL(26) → FAILURE(0)

…next to a battery gauge reading 42%. On every battery read a 4.0 owner makes.

That is the artefact #900 exists to warn about. That issue began when a FAILURE(0) was read as evidence about firmware — and this line manufactures the same misreading, in the app, in a log people paste into issues.

The fix, and what it deliberately does not do

The line still prints. Suppressing it would hide the anomaly, and the anomaly is what #900 wants captured. It is annotated instead, only when the same frame also decoded a value:

Command response: GET_BATTERY_LEVEL(26) → FAILURE(0) (the reply still carried a
value: battery 42.5% — see #900, the 4.0 result byte is not established)

A genuine failure carrying no value — the #791 empty extended-battery reply, the UNSUPPORTED rejections — is untouched, because the annotation is gated on a decoded value being present. Verified by rendering both cases.

It also does not claim the result byte means anything. Same discipline as #913, #914 and #918: say what was observed, name what is unestablished.

Notes

  • Android-only, for a sharper reason than first stated. Swift'''s FrameRouter does log command-response results — but only for opcodes it deliberately handles (REBOOT_STRAP, POWER_CYCLE_STRAP, 4.0 alarm and advertising-name), reading the byte through its own commandResultByte(in:) rather than the decoded field. There is no blanket non-SUCCESS logger on that side, so a battery reply never reaches a log line and there is nothing to mirror. (My first check searched only Strand/ for parsed["result"], which Swift does not use — right conclusion, wrong evidence.)
  • Wording is family-agnostic, because the branch is: the 5/MG decoder also sets battery_pct, so a 5/MG battery reply that ever returned FAILURE would hit this too. An earlier revision said "the 4.0 result byte", which would have been wrong there.
  • No test. The string lives in a class that needs the Android framework, and this is a log line rather than behaviour. The rendered output was checked against both real 4.0 battery fixtures and against a valueless failure. Flagging the omission rather than quietly skipping it.

WhoopBleClient logs every non-SUCCESS command response, which is how the MG
haptics rejection (#48) would surface in-app. But every WHOOP 4.0
GET_BATTERY_LEVEL reply on record carries a zeroed [seq][result] prefix, so a
battery read that returned a perfectly good percentage logs as:

    Command response: GET_BATTERY_LEVEL(26) → FAILURE(0)

next to a battery gauge showing 42%. A log line asserting a failure that did not
happen is exactly the artefact #900 exists to warn about — that issue began when
a FAILURE(0) was read as evidence about firmware, and this line manufactures the
same misreading on every battery read a 4.0 owner makes.

The line still prints. Suppressing it would hide the anomaly, and the anomaly is
the thing #900 wants a capture of. It is annotated instead, when the same frame
also decoded a value:

    Command response: GET_BATTERY_LEVEL(26) → FAILURE(0) (the reply still
    carried a value: battery 42.5% — see #900, the 4.0 result byte is not
    established)

A genuine failure that carried no value — the extended-battery case from #791,
the UNSUPPORTED rejections — is untouched, because the annotation is gated on a
decoded value being present.

This does not decide what the 4.0 result byte means; #900 still wants one real
capture of known provenance. It stops the log asserting an answer in the
meantime, the same discipline as #913, #914 and #918.

Android-only: the Swift side has no command-response result consumer, so there
is no parity twin to change. No test — the string is inside a class that needs
the Android framework, and the annotation is a log line rather than behaviour;
the rendered output was checked against both real 4.0 battery fixtures instead.
@ryanbr
ryanbr force-pushed the fix/battery-failure-log-noise-900 branch from 6e62a6d to 8b58971 Compare July 28, 2026 05:07
@ryanbr
ryanbr merged commit e932600 into main Jul 28, 2026
3 checks passed
@ryanbr
ryanbr deleted the fix/battery-failure-log-noise-900 branch July 28, 2026 05:14
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