Repository navigation
history: one workoutAt(w), replacing the copies that had drifted - #407
Merged
Merged
Conversation
"When did this workout happen" was written by hand ten times in eight
files, each as w.start || new Date(w.d).getTime() or a close variant:
lib/coach-insights.js, lib/effort.js, lib/muscles.js, lib/recovery.js,
lib/strength-exercises.js (two copies), lib/coach-demo.js, views/Stats.jsx (two copies),
and the MCP server's muscle_balance in mcp/src/tools.js
new Date('2026-09-22') is UTC midnight, which any negative UTC offset drags
back into the day before. Every other date helper in the app parses local
noon precisely so no timezone or DST shift can move the day. And `||`
discards a legitimate start of 0.
lastWorkSetAt and the effort/recovery windows feed the retained-strength
and fatigue decay off this, so imported history with no start was dated
at UTC midnight instead of local noon: up to a day early west of UTC
(17 h at UTC-5), and nothing reported it. muscleBalanceWindow and the Stats volume/last-
trained numbers dated their own cutoffs the same way, moving a workout in
or out of a window at the edge.
One exported workoutAt in history.js now answers it, and every call site
routes through it, the MCP server included (it already imports
history.js), so there is one rule to get right. exercise-history.js
already had this right in its own local startOf; it now shares the same
function instead of keeping a correct copy of its own. entriesWithId in
strength-exercises.js keeps -Infinity for the undated case on purpose,
because isNewerOccurrence compares with !== then >, and a NaN pair would
answer "not equal, not greater" instead of falling through to insertion
order.
frontend 9 new tests in workout-at.test.js, including a source-tree grep
that fails if any file outside history.js, in frontend/src or mcp/src,
hand-rolls the pattern again.
7 of the 9 fail against the old code (checked by stashing the fix and
re-running); the grep test names all eight offending files.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
kurktchiev
force-pushed
the
gh/workout-at
branch
from
October 7, 2026 17:25
31d095f to
bed92bc
Compare
crstnmac
added a commit
to crstnmac/openGym
that referenced
this pull request
Oct 9, 2026
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.
"When did this workout happen" was written by hand ten times in eight files, each as
w.start || new Date(w.d).getTime()or a close variant:lib/coach-insights.js,lib/effort.js,lib/muscles.js,lib/recovery.js,lib/strength-exercises.js(two copies),
lib/coach-demo.js,views/Stats.jsx(two copies), and the MCPserver's
muscle_balanceinmcp/src/tools.js.new Date('2026-09-22')is UTC midnight, which any negative UTC offset dragsback into the day before. Every other date helper in the app parses local
noon so no timezone or DST shift can move the day. And
||discards a legitimate start of 0.
lastWorkSetAtand the effort/recovery windows feed the retained-strengthand fatigue decay off this, so imported history with no start was dated at
UTC midnight instead of local noon: up to a day early west of UTC (17 h at
UTC-5), and nothing reported it.
muscleBalanceWindowand the Stats volume/last-trainednumbers dated their own cutoffs the same way, which can move a workout in or
out of a window right at the edge.
One exported
workoutAtinhistory.jsnow answers it, and every call siteroutes through it, the MCP server included (it already imports
history.js),so there's one rule to get right.
exercise-history.jsalready had this right in its own local
startOf; it now shares the samefunction instead of keeping a correct copy of its own next to the wrong ones.
entriesWithIdinstrength-exercises.jskeeps-Infinityfor the undatedcase on purpose, because
isNewerOccurrencecompares with!==then>,and a NaN pair would answer "not equal, not greater" instead of falling
through to insertion order.
frontend 9 new tests in
workout-at.test.js, run withnpx vitest run --maxWorkers=2, including a source-tree grep that fails if any file outsidehistory.js, infrontend/srcormcp/src, hand-rolls the pattern again.7 of the 9 fail against the old code (checked by reverting the fix and
re-running), and the grep test names all eight offending files. With the fix
in, the full frontend, mcp and api suites pass on 39bc71e.
Conflicts with two open PRs, beyond the ones each already has with main:
coach-demo.js,coach-insights.jsandexercise-history.js.recovery.js.🤖 Generated with Claude Code