§ Forge — hypertrophy tracker
Smart coaching
Forge logs, progresses, and shows fatigue/volume — smart coaching turns that data into advice. The design principle is ambient and non-prescriptive: advice appears inline as small chips/banners, and nothing auto-changes your program — you always choose.
The module
coach.js is a pure module (mirrors engine.js):
no DB, no clock reads (the caller passes now/pre-shaped data), so it's
unit-tested in isolation (coach.test.js). It consumes the engine's existing
outputs — computeFatigue, weeklyVolume, epley1RM — plus the live program
and session history, and returns plain advice objects the server renders.
Thresholds are named constants: hypertrophy band 10–20 effective sets/week, frequency target 2×, fatigue-warn at tier ≥3 (~≥70%), plateau window 3 sessions.
The four modules
1. Recovery warnings (Today)
For the day's program, any target muscle still fatigued (tier ≥3) is flagged with its % and days-since-trained — "Quads 96% (0d)". A banner lists them; each affected exercise card gets an amber warn chip. You're told it's still cooked; whether you train it is up to you. Uses the same fatigue decay the heatmap uses.
2. Volume & balance audit (Body)
Runs an automatic version of a hand audit over the live program design:
per-muscle effective sets/cycle (Σ contribution × sets) and frequency, compared
to the band. Flags under (below MEV), over (above MRV), or low_freq (<2×),
each with a concrete fix ("add ~4 sets", "split across 2 days"), plus an
"N/16 in range" summary. Equipment-capped groups (forearms, lower back — no
direct tool with a bar + dumbbells) are tagged capped and not nagged.
3. Plateau detection (Exercise / Progress)
For a lift with ≥4 sessions of history, it walks the estimated-1RM series (best working set per session) and flags a stall when no new best appears across the last 3 trained sessions, suggesting a rep-range reset or back-off. It is the thing that won't let you tell yourself the quiet lie of "still progressing" on a plateau.
4. Deload signal (Body / Progress)
A composite, ambient flag. Fires on ≥2 stalled main lifts, ≥3 fully-fatigued (molten) muscles, ≥2 muscles over MRV, or a ≥5-week training block with any stall/fatigue. Shows "deload worth considering" with the reasons — never forces a deload week (no mesocycle state is stored in v1).
Where it's wired
server.js calls coach per route and reuses existing db reads
(setsForFatigue, getProgram, exerciseHistory, recentSessions); the only
additions are two server helpers — keyLiftStalls() and activeWeeks() (a
block-length proxy: distinct training weeks in the trailing 8). No schema
change. Advice renders in amber --warn (heat-red at high severity) as
hairline chips/banners — see the design system.
Tested
coach.test.js covers each module's logic (recovery thresholds + sorting, audit
flags/fixes, plateau detection, deload composite). The live e2e.mjs gained a
Smart Coaching pass that seeds stall + fatigue scenarios via the API and
asserts every surface shows the right advice — recovery banner + chip on Today,
audit card + deload on Body, stalled list on Progress, plateau flag on a lift —
on desktop + mobile, zero console errors. Whole suite: 77 checks green.
Not in v1 (deliberately)
No persisted mesocycle state, no one-tap auto-apply, no user-configurable thresholds, no dismiss/snooze. The next planned work (separate builds) is bulletproof in-gym UX (offline logging), growth tracking (bodyweight / measurements / photos), and a Telegram nudge integration.