Skip to content

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

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

kurexw wants to merge 8 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 day steps experience without changing step metrics or derivation behavior.

New Features:

  • Explain in the steps screen that WHOOP 4.0 devices only count steps while the app receives live movement data.
  • Add localized WHOOP 4.0 step-counting guidance across the supported screen languages.

Bug Fixes:

  • Prevent misleading WHOOP 4.0 guidance when steps were recorded by a capable band, a different band is paired, or no band is paired.

Enhancements:

  • Track the paired band's known generation and update the guidance when the active pairing changes.

Tests:

  • Add widget and unit coverage for WHOOP 4.0 guidance across phone-only, zero-step, band-counted, swapped-band, and unpaired scenarios.

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, when applicable.
    • 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

UI

Add the WHOOP 4.0 no-counter hint to the steps screen when the paired band is gen4 and the day has no band-counted steps, using the live pairing when available and localized text in all supported locales.

  • lib/l10n/app_de.arb L3688-3689
  • lib/l10n/app_en.arb L16806-16809
  • lib/l10n/app_es.arb L3388-3389
  • lib/l10n/app_fr.arb L3388-3389
  • lib/l10n/app_hi.arb L3389-3390
  • lib/l10n/app_ru.arb L8162-8163
  • lib/l10n/app_th.arb L16630-16631
  • lib/l10n/app_zh.arb L3388-3389
  • lib/ui2/screens/day_steps.dart L348-354, L449-473, L529-558 (+5 small edits)

Tests

Cover the hint on phone-only and no-step days, verify it follows pairing changes and is suppressed for other bands or days with strap-counter steps, and retain the existing span-merge assertion formatting change.

  • test/ui2_day_steps_test.dart L39-72, L115-220, L270-279 (+1 small edits)

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 →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • Resume reviews
  • Trigger review

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. When applicable, it adds a WHOOP 4.0 explanation to no-steps and phone-only messages. Localizations add the 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
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: Other

Suggested reviewers: abdulsaheel

Merge Risk: Minimal · up to 7c25d

The change adds an explanatory message on the steps screen for a paired WHOOP 4.0 on days when the band counted no steps. No actionable merge-blocking risk was found in the supplied context.

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 localized Steps-screen message stating that a WHOOP 4.0 only counts steps while the app receives live data. The raw summary and objectives confirm the message is sho…
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 localized Steps-screen message stating that a WHOOP 4.0 only counts steps while the app receives live data. The raw summary and objectives confirm the message is shown for a paired WHOOP 4.0 on days without band-counted steps, in the phone-only and no-steps explanations. The title is specific and matches the changeset.

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: 825486c
  • Layers: Repository YAML
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 0fd4c1a7-805b-44b7-b92f-b36422b98d3a
Commits

Reviewing files that changed from the base of the PR and between 3c0d6bc and 7c25dc1.

Files ignored due to path filters: 1

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

  • lib/l10n/app_de.arb
  • lib/l10n/app_en.arb
  • lib/l10n/app_es.arb
  • lib/l10n/app_fr.arb
  • lib/l10n/app_hi.arb
  • lib/l10n/app_ru.arb
  • lib/l10n/app_th.arb
  • lib/l10n/app_zh.arb

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 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.

abdulsaheel and others added 4 commits November 13, 2026 17:40
Pumps the screen under a real AppState and swaps the pairing (4.0, 5.0,
4.0, none), so a break in the live lookup fails a test instead of only
the flag passed in by hand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@abdulsaheel

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor
Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

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.

@abdulsaheel

Copy link
Copy Markdown
Collaborator

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor
Action not completed

Review rate limited.

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