Repository navigation
Review follow-ups for 1.0.0b2: lap-press steps open in the execution analysis, health note window, event last day, display rounding - #40
Merged
Conversation
…ow, event last day, display rounding - analyze_workout_execution / get_activity_report / get_activity_intervals plan matching: lap-press steps (until_lap_press) are open. "ended by lap after <actual> (planning estimate <estimate>)", no length deviation, no cap or split, target adherence kept, plan clock restarts at the actual lap. Alignment: soft estimate cost, a lap-press step ends on the lap closed by the press (not on a full device auto-lap), its end is never moved or extended, its estimate is no lap length for the auto-lap detection (R36-11). - Health markers: the description note (max 120 characters) only while the entry covers the tool's day or ended at most 2 days before (R39-10). - get_event_by_id: last day of multi-day events in text and JSON last_day; single-day unchanged (R39-13). - Text outputs round stored floats for display (4 significant digits, known metrics with their usual decimals; a stored non-zero is never shown as 0); JSON unchanged (R39-14). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…w R40 follow-ups - R40-1: a lap-press step is its closing lap preceded only by full device auto-laps (auto_lap_evidence: layout length at most 0.5 % short of the setting, else a usual auto-lap distance); it never reaches across a press, a step lap or the workout start, so riding before the workout and after the last press stays outside the plan. With lap-press steps the edge blocks pay their fixed cost once, the first step takes all full auto-laps back to the workout start, a lap off target at the plan edges costs what it costs outside. - R40-2: ending on a full auto-lap costs 0.4 (below GAP_COST), 1.0 only when a shorter lap that fits the target follows (the press came later); "ended at a full device auto-lap". - R40-3: long warm-ups whose auto-laps are too few for a layout are matched as a whole. - Coarsening never merges across a lap that may close a lap-press step. - R40-6/7/8/9: non-zero never shown as 0 (also below 1e-6), form/ramp never -0.0, snapshot baselines 1 decimal only for known metrics, "Work: 872 kJ", elapsed + moving time with a pause, distance estimates in the plan total, report wording, JSON note_withheld. - Known limitations (no press, double press, start on an exact auto-lap, >600 laps) in the guide. - Plans without lap-press steps are analysed exactly as before (2,307 r26 analyses identical). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
futureweb
added a commit
that referenced
this pull request
Oct 15, 2026
Prepares tag `v1.0.0b2` (RELEASING.md steps 2–3; owner approved the release). - Version `1.0.0b2` everywhere it is stored (`scripts/check_release_metadata.py`: consistent); jq only re-laid out the JSON files, the semantic diff is the version fields. - README and docs/DOCKERHUB.md install examples and badge on `1.0.0b2`; status line updated, release item removed from "Next". - CHANGELOG: Unreleased → `[1.0.0b2] - 2026-10-15` with a short summary and **Known limitations** of the lap-press execution analysis (from the PR #40 re-check). - Execution guide: the claim that devices whose auto-laps do not restart at a press are handled is corrected — fixed auto-lap markers are a known limitation; very short laps named as the cause of the many-laps limitation. Main changes since 1.0.0b1: lap-press steps (#36, confirmed on a Garmin Edge 1040, #38), coaching answer rules, health markers, date anchors and n/a fixes (#39), lap-press steps in the execution analysis, health note window, event last day, display rounding (#40), serverInfo version (#34), docs (#35, #37). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.
Open follow-ups from the reviews of #36 and #39, wanted before release 1.0.0b2. No new tools, no
parameter or catalogue changes, no extra API requests.
1. Lap-press steps in the execution analysis (R36-11)
The duration or distance of an
until_lap_pressstep is only a planning estimate, butanalyze_workout_executiontreated it as the planned length. Lap-press steps are now open:"shorter than planned" or a cap at the estimate with "extra time inside the plan";
"ended with the recording" when the last step runs to the end of the activity.
"started 5:00 earlier than the plan timeline" after a short warm-up).
auto-laps the step ends on the lap closed by the press (a partial lap), never on a full auto-lap.
Its end boundary is never moved, split or extended by trailing laps. Its estimate no longer makes
auto-laps of the same length look like lap presses. Carving a lap-less step uses the plan bounds,
so it is skipped for a lap-press step.
lap_press(ended_by,elapsed_s,moving_time_s,estimate_s/estimate_m,actual_m),planned.lap_press, summarylap_press_steps/lap_press_estimate_s. The plan totalis marked "≈" with the estimate share.
get_activity_reportkey finding names the lap-press steps.get_activity_intervals(include_planned_types=true)shows "until lap press, ended by lap after …" and never
beyond_plan_sfor them.Code paths checked with synthetic tests (
tests/test_execution_lap_press.py):timed step stays exact, has no start shift and has no length or timeline note.
The warm-up and auto-lap cases also fail on
main, so the tests cover the change.Live, read-only: activity i196751426, paired with event 144186380 (lap-press warm-up with a 17:00
estimate, 4×(3+3 min), 3 min, 10 min).
Before (
main):After:
The one remaining clear deviation is rep 1 at +5.6 % above the target range, which is correct.
Offline, same plan, warm-up ended by lap after 12:00 (compact):
Offline, warm-up ended by lap after 25:00:
2. Health markers: note only while current (R39-10)
The note from a SICK/INJURED entry's description is shown only while the entry covers the tool's
day, or ended at most 2 days before it. Later in the 14-day window the line has only category,
name and dates (JSON
notenull). The note limit stays at 120 characters (NOTE_CHARS, confirmedand tested). Live, read-only,
get_recovery_snapshot(date_str=…)for the entry of 2024-12-22 to2024-12-27:
3.
get_event_by_id: last day of multi-day events (R39-13)This reuses
event_day_spanfrom #39. Live, read-only, SICK event 49921901:Single-day events (e.g. the workout 144186380,
End: 2026-10-14T00:00:00 (local)) are unchanged intext and JSON, and so are events without an end. An end after midnight (22:00 → 02:00) names the
next day.
4. Float noise in text outputs (R39-14)
format_value(the "as stored" helper behind_stored/_val) now shows floats with 4 significantdigits instead of up to 6 decimals. Whole numbers are never rounded. Known metrics get their usual
precision through a new
digitsargument:Also covered: training-summary form and ramp,
get_event_by_idother fields, report device values.A stored non-zero is never shown as 0; it keeps one significant digit, e.g. a gradient of 0.001984 % is
shown as
0.002%. JSON values are unchanged: a structural comparison of the live JSON outputs beforeand after shows only the new lap-press keys and the corrected
start_offset_s.Live before → after (i196751426 and today's snapshot):
Floats with 4 or more decimals across about 67 live text outputs (44 read tools): 727 before, 11
after. The remaining ones are intended:
Stride 0.9177,ss_p_max=0.4769,Elapsed Time 0.9775 hr);get_sport_settings;-0.00002%).Review of this PR (R40) — second commit
device auto-laps: laps of the auto-lap length, at most 0.5 % short of the setting (a press lap
usually is shorter).
A long ride home in many auto-laps is therefore not moved into the plan.
the plan edges counts as outside the plan.
correct: "Additional training after the plan: 15:00 / 60:00", "Riding before the plan: 20:00".
GAP_COST.have no such field. The original FIT has
lap_trigger(manual/time/session_end) andwkt_step_index(verified read-only for i196751426). Using them would need an extra file downloadper analysis and a FIT decoder, so this is left as a possible follow-up. The rule above uses the
lap lengths instead.
-0.0.note_withheldis added.lap-press step.
consecutive lap-press steps or at the plan edges, workout start exactly on an auto-lap at the
warm-up's intensity, more than about 600 laps).
Measurements (offline, the reviewer's scripts):
r40/lp_fuzz3.py)analyzecalls)The 2 worse cases in the original fuzz (seeds 77 and 226) share one cause. The synthetic riding
before the workout covers an exact multiple of the auto-lap at the warm-up's intensity, so no lap
marks the workout start.
Live, read-only, i196751426: unchanged.
The report finding now ends "…; lap-press steps (length set by the lap press, not judged; targets
judged): plan 1 warmup ended by lap after 16:01 (planning estimate 17:00)".
Checks
ruff check .: all checks passed.mypy src tests: no issues in 130 files.pytest: 1154 passed (main 1129), including the catalogue budgets.--disable=C0301 --fail-under=0 --fail-on=E,F): exit 0, and no new messages comparedwith
main.async), and all requests were GET. Request counts per tool are unchanged.
🤖 Generated with Claude Code