Skip to content

Steps: say a WHOOP 4.0 only counts while the app gets its live data - #710

Open
kurexw wants to merge 5 commits into
OpenStrap:mainfrom
kurexw:fix/whoop4-steps-phone-hint
Open

kurexw wants to merge 5 commits into
OpenStrap:mainfrom
kurexw:fix/whoop4-steps-phone-hint

Conversation

@kurexw

@kurexw kurexw commented Nov 13, 2026 •

Copy link
Copy Markdown

Why

A WHOOP 4.0 has no on-chip step counter ("gen4 has no counter", derivation_engine.dart). Its steps come only from the live 100 Hz movement stream, which is counted while the app receives it and never stored. So a walk with the phone left at home leaves no steps from the band and none from the phone, and users report it as a bug. A recent support report, verbatim: "Walked but it's not tracking the steps. it did from my phone but I don't carry my phone all the time."

The steps screen already explains each sensor's limits in one footnote, but never says the band itself can't count on its own.

What it looks like

With a WHOOP 4.0 paired, on a day the band counted nothing:

  • Phone-only day. Before: "Counted by your phone, so only the steps you had it on you for are here." After: the same, followed by "A WHOOP 4.0 has no step counter of its own, so it only counts steps while this app is receiving its live data."
  • No steps at all. The "No steps counted" card gets the same sentence after its reason.

Unchanged: any day the band did count (it evidently could), any other band, or no band paired.

What changes

  • lib/ui2/screens/day_steps.dart: DayStepsData.bandHasNoCounter, set from a new pairedBandHasNoCounter() next to bandLabel(). True only for a paired band whose generation is known to be gen4; false when nothing is paired or the generation is unknown, so it never guesses. One helper appends the sentence in both places.
  • dayStepsWhoop4NoCounter in all eight locales that already translate this screen (en, de, es, fr, hi, ru, th, zh).

No metric or derivation change, so no kAlgoVersion bump.

Tests

  • test/ui2_day_steps_test.dart: three new widget tests. A phone-only day with a WHOOP 4.0 shows the hint; a no-steps day with a WHOOP 4.0 shows it; it never shows on a day the band counted or without a WHOOP 4.0.
  • flutter analyze: no issues. gen-l10n: no new untranslated messages.
  • ui2_day_steps_test, day_steps_counter_session_test, spanish_coverage_test: 14 passed. The full suite was not run locally.
  • Not checked on a real WHOOP 4.0.

🤖 Generated with Claude Code

Summary by Sourcery

Clarify WHOOP 4.0 step-counting limitations in the daily steps screen without changing metrics or derivation behavior.

New Features:

  • Explain in the steps screen that WHOOP 4.0 steps are counted only while the app receives live band data when no band steps are recorded.

Enhancements:

  • Limit the WHOOP 4.0 guidance to known gen4 bands and avoid showing it when the band or another counter recorded steps.

Tests:

  • Add widget and helper tests covering WHOOP 4.0 guidance for phone-only and empty days, along with cases where the guidance must be suppressed.

Chores:

  • Add the WHOOP 4.0 no-counter message across the supported localized step-screen translations.

Summary by CodeRabbit

  • New Features
    • The daily steps screen explains that WHOOP 4.0 has no built-in step counter and counts steps only while the app receives live data.
    • This guidance appears when no steps are recorded and alongside the phone-only step-count explanation.
    • The message is available in English, German, Spanish, French, Hindi, Russian, Thai, and Chinese.

A WHOOP 4.0 has no on-chip step counter; its steps come only from the live 100 Hz stream, so a walk with the phone left behind leaves no steps at all and users report it as "not tracking steps". On a day the band counted nothing, the steps screen now says so, after the phone footnote and on the no-steps card. Only for a known gen4 band, never on a day it counted.
@sourcery-ai

sourcery-ai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Implementation

Track whether the paired band is a known WHOOP 4.0 when loading the day, and use the current pairing state plus the day’s source to decide whether the hint is accurate.

  • lib/ui2/screens/day_steps.dart L110-115, L458-473, L529-558 (+4 small edits)

UI

Append the WHOOP 4.0 live-data explanation to the phone-only and no-steps messages, with translations for the supported locales.

  • lib/l10n/app_de.arb L3585-3586
  • lib/l10n/app_en.arb L16578-16581
  • lib/l10n/app_es.arb L3285-3286
  • lib/l10n/app_fr.arb L3285-3286
  • lib/l10n/app_hi.arb L2935-2936
  • lib/l10n/app_ru.arb L8033-8034
  • lib/l10n/app_th.arb L16405-16406
  • lib/l10n/app_zh.arb L3285-3286
  • lib/ui2/screens/day_steps.dart L348-354, L449-457

Tests

Cover the hint on phone-only and zero-step days, and verify it is suppressed for counted days and other pairing states.

  • test/ui2_day_steps_test.dart L90-162

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The day steps screen checks whether the paired band has a built-in step counter. It conditionally adds a WHOOP 4.0 explanation to no-steps and phone-only messages. Localizations add this explanation in eight languages.

Changes: WHOOP 4.0 step-counter hint

Layer / File(s) Summary
Resolve and pass counter capability
lib/ui2/screens/day_steps.dart
DayStepsData stores a counter-capability flag. The detail screen supplies the paired-band capability to the data model.
Display the conditional hint
lib/ui2/screens/day_steps.dart, lib/l10n/app_*.arb
The no-steps and phone-only messages add the WHOOP 4.0 explanation when the band lacks a counter and the day source is not strap_counter. The explanation is localized in English, German, Spanish, French, Hindi, Russian, Thai, and Chinese.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Feature

Suggested reviewers: abdulsaheel

Merge Risk: Minimal · up to 6376b

This adds a WHOOP 4.0 explanation to the steps screen. It does not change step metrics, and no merge-blocking risk remains in the supplied review evidence.

Pre-merge checks: Passed 4

Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title names the main change: a steps-screen hint that WHOOP 4.0 counts steps only while the app receives live data. The raw summary, objectives, and file changes all match this. The title is speci…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title names the main change: a steps-screen hint that WHOOP 4.0 counts steps only while the app receives live data. The raw summary, objectives, and file changes all match this. The title is specific, concise, and single-sentence, so it passes.

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: OpenStrap/edge
  • Branch: main
  • File: .coderabbit.yaml
  • Commit: e10dcaf
  • Layers: Repository YAML
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 13164a4d-01c0-4bc0-a730-b2d5c888b07a
Commits

Reviewing files that changed from the base of the PR and between 5aa0a3d and 6376bcc.

Files ignored due to path filters: 1

  • test/ui2_day_steps_test.dart is excluded by !test/**
Files selected for processing: 3

  • lib/l10n/app_fr.arb
  • lib/l10n/app_zh.arb
  • lib/ui2/screens/day_steps.dart

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.

@kurexw

kurexw commented Nov 13, 2026

Copy link
Copy Markdown
Author

@abdulsaheel could you approve the test workflow runs on my open PRs? GitHub is holding them as "approval required" for fork PRs, so none of them has a CI result yet:

Each was analyzed and tested locally (details in each description). Thanks!

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="lib/ui2/screens/day_steps.dart" line_range="449" />
<code_context>
-          : whyFromNote(d.note, unit: 'days') ??
-                (l?.dayStepsNothingCounted(when) ??
-                    'Nothing that can count steps recorded $when.'),
+          : _withNoCounterHint(
+              c,
+              d,
</code_context>
<issue_to_address>
**Hint contradicts saved band count**

When the paired band is a WHOOP 4.0 and a historical day has phone coverage spans plus a positive strap-counter day result, when a day has phone coverage spans but its published total comes from a strap counter, `_honesty` sees `d.strap == 0` and appends the WHOOP 4.0 hint. The screen then says the band added nothing even though the saved day records a band count.

Do not append the hint when the day result records a positive strap-counter total, even if resolved coverage contains only phone spans.
</issue_to_address>

### Comment 2
<location path="lib/ui2/screens/day_steps.dart" line_range="286" />
<code_context>
       final d = await DayStepsData.load(repo,
-          bandLabel: bandLabel(context), want: _day);
+          bandLabel: bandLabel(context),
+          bandHasNoCounter: pairedBandHasNoCounter(context),
+          want: _day);
       if (mounted && token == _loadToken) {
</code_context>
<issue_to_address>
**Stale band guidance remains visible**

When the paired band is unpaired or replaced while the steps detail remains mounted, `DayStepsData.load` snapshots `pairedBandHasNoCounter(context)` into `_d`, and `DayStepsDetail` does not reload when `AppState` changes, so the screen keeps showing guidance for the previous band.

Update or reload the day data when the paired band changes, or derive the hint from the current paired-band state.

Also at `lib/ui2/screens/day_steps.dart:287`.
</issue_to_address>

### Comment 3
<location path="test/ui2_day_steps_test.dart" line_range="98" />
<code_context>
+        spans: [_span(0, 60, 1200)],
+        total: 1200,
+        phone: 1200,
+        bandHasNoCounter: true,
+      ),
+    );
</code_context>
<issue_to_address>
**Paired-band wiring goes untested**

When the paired-band lookup or its wiring in `_load` is broken, if the repository-loading path stops passing `pairedBandHasNoCounter(context)` or returns the wrong value for a paired WHOOP 4.0, the new widget tests still pass: they pump `DayStepsDetail(data: d)` with the flag set directly, so `initState` skips `_load`; the “other band” case also supplies no paired-band state.

Exercise the repository-backed loading path with paired WHOOP 4.0 and non-gen4 device state rather than supplying the precomputed flag.

Also at `test/ui2_day_steps_test.dart:108`, `test/ui2_day_steps_test.dart:131`.
</issue_to_address>

Sourcery assessment

Approval pending. 3 findings to address first.

Blocking findings: lib/ui2/screens/day_steps.dart:449, lib/ui2/screens/day_steps.dart:286, test/ui2_day_steps_test.dart:98


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread lib/ui2/screens/day_steps.dart Resolved
Comment thread lib/ui2/screens/day_steps.dart Resolved
spans: [_span(0, 60, 1200)],
total: 1200,
phone: 1200,
bandHasNoCounter: true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Paired-band wiring goes untested

When the paired-band lookup or its wiring in _load is broken, if the repository-loading path stops passing pairedBandHasNoCounter(context) or returns the wrong value for a paired WHOOP 4.0, the new widget tests still pass: they pump DayStepsDetail(data: d) with the flag set directly, so initState skips _load; the “other band” case also supplies no paired-band state.

Exercise the repository-backed loading path with paired WHOOP 4.0 and non-gen4 device state rather than supplying the precomputed flag.

Also at test/ui2_day_steps_test.dart:108, test/ui2_day_steps_test.dart:131.

Prompt for AI agents
In `test/ui2_day_steps_test.dart` at line 98:

**Paired-band wiring goes untested**

When the paired-band lookup or its wiring in `_load` is broken, if the repository-loading path stops passing `pairedBandHasNoCounter(context)` or returns the wrong value for a paired WHOOP 4.0, the new widget tests still pass: they pump `DayStepsDetail(data: d)` with the flag set directly, so `initState` skips `_load`; the “other band” case also supplies no paired-band state.

Exercise the repository-backed loading path with paired WHOOP 4.0 and non-gen4 device state rather than supplying the precomputed flag.

Also at `test/ui2_day_steps_test.dart:108`, `test/ui2_day_steps_test.dart:131`.

uvtqt added 2 commits November 13, 2026 11:57
An older day whose total came off a WHOOP 5.0 / MG's own counter was counted by a band that has one, so the hint would contradict it.
@abdulsaheel

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor
Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

This branch has not been deployed

No deployments
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