feat(energy): price walking into Active energy from measured cadence (v77) - #283
Merged
abdulsaheel merged 2 commits intoAug 26, 2026
Merged
Conversation
Contributor
|
Warning Review limit reachedNext included review available in 24 minutes. View limit detailsLimit details: You’ve used all 2 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (4)
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. Comment |
…(v77)
The reported bug ("Walking calories are not counted"): a Walking workout
records fine, its steps count fine, and the day's Active energy never moves.
Root cause is not a wiring or sync failure — MOT-02's HR-flex gate
deliberately bills nothing below the ACSM moderate floor, and a walk lives
entirely below it. The session's own bout number (which bills sub-gate
samples at the resting rate) made the gap read like a sync bug.
The analytics half (OpenStrap/analytics#52) prices sub-gate minutes from
MEASURED cadence — CADENCE-Adults' published 100/110/120/130 spm ↔ 3/4/5/6
METs line, the one gait signal this platform actually has after MT-05 ruled
the 1 Hz accel out. This is the edge half:
- lib/compute/step_cadence.dart: the ONE windows→minutes cadence mapping,
from the day's RESOLVED live_coverage spans (credited, never raw rows, so
band/phone overlap cannot double-price a step). Partial coverage pro-rates
DOWN — a walk's boundary minute under-bills rather than half a minute of
walking pricing a full MET-minute; untouched minutes are null, unmeasured.
- Both energy passes feed it through that one mapping: the coordinator's
canonical wakeDayEnergy AND the pipeline's early-read mirror
(DayBundleInput carries the spans across the isolate), so the early read
and the derived day bill a walk identically instead of the number growing
when the coordinator's pass lands.
- wakeDayEnergy filters the cadence series in the SAME pass as the off-skin
HR filter — dropping an HR entry without its cadence would price every
later cadence against the wrong minute (pinned by test).
- The TDEE block discloses the term (live_coverage_pedometer in inputs_used,
walking kcal in the note) only on days it actually priced something.
- kAlgoVersion 76 → 77. A day with no pedometer coverage derives
byte-identical to v76.
PIN GATE: the pubspec analytics pin is NOT flipped yet — it must move to the
OpenStrap/analytics#52 merge SHA (together with kAnalyticsPin) before this
can merge, per invariant OpenStrap#5. Draft until then.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015TxisrChNFxtVMXFFNRGtV
… exists to consume All three pin locations move together to analytics main @ a077a4a, the OpenStrap/analytics#52 merge commit: the cadence→MET walking term in Calories.dailyEnergy (CADENCE-Adults). Unlike the usual repin this one exists to move a number — that number IS this branch's change, priced in by the kAlgoVersion 77 bump and the v77 migration. The hop is exactly OpenStrap#52 and nothing else (calories.dart + its tests).
DropTabl
force-pushed
the
feat/walking-cadence-active-energy
branch
from
August 26, 2026 13:34
940808e to
916a54b
Compare
DropTabl
marked this pull request as ready for review
August 26, 2026 13:34
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.
The bug (user report: "Walking calories are not counted")
A Walking workout records fine, its steps count fine, and the day's Active energy never moves. Not a wiring or sync failure: MOT-02's HR-flex gate deliberately bills nothing below the ACSM moderate floor (its own changelog: billed wake minutes → 4.9%, median daily active → 48 kcal), and a walk at ~95 bpm lives entirely below it. The session's bout number — which bills sub-gate samples at the resting rate — made the gap read like a sync bug.
The fix (edge half)
The analytics half (OpenStrap/analytics#52) prices sub-gate minutes from measured cadence — CADENCE-Adults' published 100/110/120/130 spm ↔ 3/4/5/6 METs line, the one gait signal this platform actually has after MT-05 ruled the 1 Hz accel out. This PR wires it:
lib/compute/step_cadence.dart— the ONE windows→minutes cadence mapping, fed by the day's resolvedlive_coveragespans (credited, never raw rows, so band/phone overlap can't double-price a step). Partial coverage pro-rates down: a walk's boundary minute under-bills rather than half a minute of walking pricing a full MET-minute. Untouched minutes are null — unmeasured, not zero.wakeDayEnergyand the pure pipeline's early-read mirror (DayBundleInputcarries the spans across the isolate) — so Today's early number and the derived day bill a walk identically instead of the figure growing when the coordinator's pass lands.wakeDayEnergyfilters the cadence series in the same pass as its off-skin HR filter; a dropped HR entry without its cadence would price every later cadence against the wrong minute (pinned by test).live_coverage_pedometerininputs_used, walking kcal in the note) only on days it actually priced something.kAlgoVersion76 → 77, changelog above the constant. A day with no pedometer coverage derives byte-identical to v76. No settings, no UI changes — Home's "Active energy" card and the Health export pick the figure up through the existing seam.What it means for the reported walk
Tracked Walking workout, phone present (so the 100 Hz pedometer covered it), HR below the gate: the walk's minutes now bill
(MET − 1)basal-minutes each — e.g. an hour at 110 spm ≈ 220 kcal for an 80 kg profile, previously 0. Walks with no live link stay unpriced (gen4 has no durable 24/7 cadence) — honest abstention, unchanged.Tests
step_cadence_test.dart— the mapping: whole/partial minutes, overlap summing, measured-zero vs null, degenerate spans.daily_energy_consistency_test.dart— the reported walk bills;total − active == basal(the Health-export invariant) survives the walking term; cadence stays aligned across the off-skin filter.flutter analyzeclean; full suite green — 3,037 passed / 0 failed against the flippeda077a4apin, rebased on current main.Companion: OpenStrap/analytics#52 (the model + citations). Fixes the "Walking calories are not counted" report.