Stop a working 4.0 battery read logging as a failure (#900) - #923
Merged
Conversation
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
force-pushed
the
fix/battery-failure-log-noise-900
branch
from
July 28, 2026 05:07
6e62a6d to
8b58971
Compare
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.
A landable piece of #900. It does not resolve that issue — which still needs one real 4.0
GET_BATTERY_LEVELcapture of known provenance — but it stops the log asserting an answer while we wait.The line
WhoopBleClientlogs 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:…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:
A genuine failure carrying no value — the #791 empty extended-battery reply, the
UNSUPPORTEDrejections — 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
FrameRouterdoes 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 owncommandResultByte(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 onlyStrand/forparsed["result"], which Swift does not use — right conclusion, wrong evidence.)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.