Skip to content

fix(warm-ups): a barbell warm-up is never lighter than the bar - #409

Open
kurktchiev wants to merge 1 commit into
DuarteSantos8:mainfrom
kurktchiev:gh/warmup-bar-floor
Open

kurktchiev wants to merge 1 commit into
DuarteSantos8:mainfrom
kurktchiev:gh/warmup-bar-floor

Conversation

@kurktchiev

@kurktchiev kurktchiev commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

A 55 lb barbell press planned with two warm-up sets opens at 25 and 40 lb, and neither fits on a 45 lb bar. Each warm-up row halves the gap left to the work weight, starting from 0: insertWarmupRow builds each planned row, then rerampWarmups runs again once the prescription has moved the work weight. Nothing in that ramp knows the lift is done with a bar.

barFloor(S, exId) in history.js returns bar.js barWeightFor, or 0 for a lift without a bar. Both ramp computations, in insertWarmupRow and rerampWarmups, now keep a rung at or above that floor and at or below the work weight. buildSets reads the floor from S. applyPrescription takes it as a new last argument (default 0), and buildPlannedEntry passes it. The in-session "Add warm-up set" button passes it to insertWarmupRow. Session start, logging a past workout, editing, adding or swapping an exercise mid-session, combined routines and "Repeat today" all build through buildSets or buildPlannedEntry, so they get the floor with no change of their own. So does the MCP preview_session, but only for built-in exercises until #412 lands. The MCP server doesn't register custom exercises, so a custom barbell lift at 30 kg with two warm-ups still previews 15 / 22.5.

The floor follows the athlete's own bar setting for that exercise:

  • a bar weight they set wins, so a 35 lb bar gives the 55 lb press a 35 lb warm-up;
  • "No bar" (a stored 0, Being able to set Smith bar to 0 kg/lb. #138) sets no floor, and the ramp starts at 25 as before;
  • with nothing set, it is the default for the bar type in the profile's unit: 45 lb / 20 kg for a barbell, 25 lb / 10 kg for an EZ bar, 20 lb / 9 kg for a Smith machine, 55 lb / 25 kg for a trap bar;
  • a bar heavier than the work weight gives a warm-up at the work weight, never above it.

Dumbbell, cable, machine and bodyweight lifts have no bar and ramp as before.

I ran the old and the new code on the barbell bench press (0025), lb profile with a 5 lb step unless noted:

work weight warm-ups before after
55 lb 1 25 45
55 lb 2 25, 40 45, 50
135 lb 3 65, 100, 115 65, 100, 115
30 kg (kg profile, 2.5 kg step) 2 15, 22.5 20, 25
55 lb, after linear progression from 50 1 25 45
50 lb dumbbell bench (0289) 1 25 25

The routine sheet's warm-up help now reads "Each one closes half the gap to the work weight, never below the bar on a barbell lift", in all 17 packs. The new lines were translated with Claude, and no native speaker has checked them in any pack. German and Hungarian say "never lighter than the empty bar" («nie leichter als die leere Stange», «soha nem könnyebb az üres rúdnál»), because the earlier «nie unter der leeren Stange» and «soha nem az üres rúd alatt» read as physically under the bar. I wrote the zh-TW line during the rebase. @nauish, since you added the pack in #368, could you check it?

Tests:

  • One new test each in history.test.js (buildSets and insertWarmupRow against the default bar, the athlete's own bar, "no bar", a bar heavier than the work weight, and a dumbbell), progression.test.js (applyPrescription re-ramping an open warm-up), session-start.test.js (a linear session that moves 50 to 55 lb) and Workout.test.jsx (the "Add warm-up set" button on a 55 lb bench). All 4 fail on the old code. The four files pass.
  • The full frontend suite passes on 39bc71e. The mcp suite passes, and check-node-loadable still loads the whole import graph under plain Node.
  • check-locales.mjs: 17 locales, 1,979 keys each. check-source-strings.mjs --strict: 1,555 strings. pt-br-locale.test.js passes with the fingerprint unchanged.

#312 replaces buildSets, rerampWarmups and applyPrescription with its engine. Beyond the conflicts it already has with main, it conflicts with this branch in lib/session-start.js and lib/session-start.test.js. Its warm-up planner (planWarmupRows in api/engine/warmup.js) works in percentages of the work weight and does not read the bar. One more open PR conflicts with this branch: #443 in views/Workout.test.jsx. No other open PR gains a conflict from this branch.

🤖 Generated with Claude Code

Warm-up rows halve the gap from 0 toward the work weight, so a 55 lb
barbell press planned with two warm-ups opened at 25 and 40 lb. Neither
fits on a 45 lb bar.

history.js barFloor reads the bar from bar.js barWeightFor: the
athlete's own bar weight for that exercise, 0 when they set "no bar",
else the default for the bar type in their unit. buildSets,
insertWarmupRow, rerampWarmups and applyPrescription take it as the
lightest rung they will build, and never go past the work weight when
the bar is heavier. The session builder (session-start.js) and the
in-session "Add warm-up set" button pass it in. Dumbbell, machine,
cable and bodyweight lifts have no bar and ramp as before.

The routine sheet's warm-up help says so, in all 17 packs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@kurktchiev
kurktchiev force-pushed the gh/warmup-bar-floor branch from d136c51 to ce69b83 Compare October 7, 2026 17:25

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.

1 participant