Repository navigation
steps: stop the calibration card asking for the half the user already has - #1815
Merged
Merged
Conversation
… has A WHOOP 4.0 user with no synced motion asked whether entering their Apple Health steps by hand would start NOOP counting and calibrating. It would not, and the sheet is why they thought it might. With no banked motion the card still showed "Need 1 more day where your phone also counted steps", which names phone-step days as the blocker. They are not. A step estimate is motion * coefficient (StepsEstimateEngine.estimate returns nil below minMotionForFit), and a calibration point is the ratio steps / motion - so both halves are required, and with the motion half missing neither the estimate nor the fit moves however many days the phone counts. Manually setting the coefficient does not help either: it sets the multiplier, and the thing being multiplied is what is absent. So the countdown was pointing at the one input the user could supply, while the input they actually needed went unmentioned in that card. The no-motion banner at the top of the same sheet explains the real blocker already, and the two were competing. The countdown and its explanatory line are now shown only when motion exists. Deliberately no new copy: the banner says the right thing, and the fix is to stop contradicting it rather than to add a third message. Same reason the comparison card is untouched - "no days yet where both counted" is true in this state. Not a fix for the underlying no-motion case, which for a 4.0 is a history sync that has not completed (#1149 covers the harder version). NOT COMPILED AND NOT SEEN: app-target Swift, no local build, no default CI job. swiftc -parse is syntax only, and this changes what a card renders. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RupifTqaTTytpPjfpMvJuj
…own cannot drift Re-review. The guard tested sampleMotion == nil, which is also true DURING the load - so in that window the countdown disappeared while the banner had not appeared yet, and the card explained nothing at all. The banner's own condition is didLoad && sampleMotion == nil; the two must be exactly complementary, and written as separate expressions they drifted on the first attempt. Both now read strapHasNoMotion, and the property carries why it exists. Also found while checking what else depends on this: TodayView.stepsCalibrationCaption has the SAME defect - it returns "Need N more days where your phone also counted steps" whenever the coefficient is zero, motion or not - and so does its Kotlin twin, TodayScreen.stepsCalibrationPrompt. That is the surface where a user actually notices steps missing, so it matters more than this sheet does. Not folded in here. Neither Today screen has a motion signal to gate on, so fixing it means threading one through both platforms and choosing between a persisted flag and a per-render query - a different change from a two-line guard, and filed rather than smuggled into this one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RupifTqaTTytpPjfpMvJuj
ryanbr
added a commit
that referenced
this pull request
Sep 2, 2026
Build numbers only: versionCode 414 -> 415, CURRENT_PROJECT_VERSION 295 -> 296. MARKETING_VERSION and versionName stay 11.1.0, which has only ever been cut as a testing build. Carries two Apple-only UI fixes that no default CI job compiles - the live-workout capsule timer no longer sitting under the pause button (#1814) and the steps calibration card no longer asking for phone-step days when the missing half is strap motion (#1815). This build's iOS and macOS legs are their first compile, and a screenshot is what confirms either of them actually looks right. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RupifTqaTTytpPjfpMvJuj
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 WHOOP 4.0 user with no synced motion asked whether entering their Apple Health steps by hand would
start NOOP counting and calibrating. It wouldn't — and the sheet is why they thought it might.
The misdirection
With no banked motion, the card still showed:
That names phone-step days as the blocker. They aren't:
A step estimate is
motion * coefficient, and a calibration point is the ratiosteps / motion. Bothhalves are required, so with the motion half missing neither the estimate nor the fit moves however
many days the phone counts. Setting the coefficient by hand doesn't help either — that sets the
multiplier, and the thing being multiplied is what's absent.
So the countdown pointed at the one input the user could supply, while the input they actually
needed went unmentioned in that card. The no-motion banner at the top of the same sheet explains the
real blocker, and the two were competing — the user believed the countdown.
The fix
The countdown and its explanatory line now render only when motion exists.
Deliberately no new copy. The banner already says the right thing; the fix is to stop
contradicting it rather than add a third message. The comparison card is untouched for the same
reason — "no days yet where both counted" is simply true in this state.
Net diff is two lines of code and a comment explaining why.
Scope
Not a fix for the underlying no-motion case, which on a 4.0 is a history sync that hasn't completed —
#1149 covers the harder version. This only stops the UI sending someone down a road that cannot work.
Verification
swiftc -parseclean;doc_comment_lintandi18n_audit --ciclean; no strings added or changed.-parseis syntax, not type-checking, and this changes what a card renders. The testing build's iOS leg
compiles it; the state is reachable on any strap that hasn't synced motion.
🤖 Generated with Claude Code