Summary
WorkoutSet.calculateVolume() (in workout-logger/lib/models/models.dart) now computes volume differently depending on whether assistWeight is set:
- Sets logged before this feature existed (or before a user's exercise got reclassified as bodyweight-assisted):
assistWeight == null → volume = weight × reps.
- Sets logged after:
assistWeight is populated → volume = (bodyweight − assist + extra) × reps.
Both encodings coexist permanently in stored data. Anything that compares volume/weight across sessions spanning the upgrade boundary sees a step change that has nothing to do with actual training progress.
The most concrete downstream break is in workout-logger/lib/services/ml_service.dart (recommendSets, around lines 398-410): the deload-detection logic compares w0/v0 from the most recent session against w1/v1 from the session before it. If one of those two sessions used the old encoding and the other the new one, the comparison is comparing incompatible numbers — a normal progression can be misclassified as a deload (or the reverse), which changes the weight/rep recommendation the AI coach and the in-app suggestion card show the user.
How to reproduce (user-visible impact)
- Have at least one existing logged set for a bodyweight-assisted exercise (
pull_ups, chin_ups, dips, or push_ups) from before this app version — i.e. assistWeight is null on that historical set, so its stored volume is plain weight × reps.
- Update to this app version and log a new set for the same exercise. This new set gets
assistWeight/bodyWeightAtLog populated, so its volume uses the new formula.
- Open the exercise's progress/volume chart (Analytics tab) — there will be a visible discontinuity in the volume trend line exactly at the upgrade point, unrelated to any real change in training.
- Alternatively: with exactly two past sessions logged for the exercise (one pre-upgrade, one post-upgrade), open the workout screen for that exercise and check the AI set recommendation / "recovering from deload" messaging. Because
ml_service.dart compares the two sessions' effective load directly, the recommendation can flip into deload-recovery mode (or fail to) based on the encoding mismatch alone, not the user's actual last two sessions.
Why this isn't a quick fix
Resolving it requires picking a real compatibility strategy up front, not a local code change:
- Backfill
assistWeight/bodyWeightAtLog onto historical sets during/after the SQLite migration (needs a defensible default assist value — there isn't one, since old sets never recorded it), or
- Record an explicit encoding version per set and teach every volume/trend consumer (
calculateVolume, ml_service.dart's deload comparison, any future analytics) to normalize across versions.
Either path is a deliberate data-modeling decision, not something to guess at while resolving PR review comments. Flagging as a known limitation to design properly.
Pointers
Summary
WorkoutSet.calculateVolume()(inworkout-logger/lib/models/models.dart) now computes volume differently depending on whetherassistWeightis set:assistWeight == null→ volume =weight × reps.assistWeightis populated → volume =(bodyweight − assist + extra) × reps.Both encodings coexist permanently in stored data. Anything that compares volume/weight across sessions spanning the upgrade boundary sees a step change that has nothing to do with actual training progress.
The most concrete downstream break is in
workout-logger/lib/services/ml_service.dart(recommendSets, around lines 398-410): the deload-detection logic comparesw0/v0from the most recent session againstw1/v1from the session before it. If one of those two sessions used the old encoding and the other the new one, the comparison is comparing incompatible numbers — a normal progression can be misclassified as a deload (or the reverse), which changes the weight/rep recommendation the AI coach and the in-app suggestion card show the user.How to reproduce (user-visible impact)
pull_ups,chin_ups,dips, orpush_ups) from before this app version — i.e.assistWeightis null on that historical set, so its stored volume is plainweight × reps.assistWeight/bodyWeightAtLogpopulated, so its volume uses the new formula.ml_service.dartcompares the two sessions' effective load directly, the recommendation can flip into deload-recovery mode (or fail to) based on the encoding mismatch alone, not the user's actual last two sessions.Why this isn't a quick fix
Resolving it requires picking a real compatibility strategy up front, not a local code change:
assistWeight/bodyWeightAtLogonto historical sets during/after the SQLite migration (needs a defensible default assist value — there isn't one, since old sets never recorded it), orcalculateVolume,ml_service.dart's deload comparison, any future analytics) to normalize across versions.Either path is a deliberate data-modeling decision, not something to guess at while resolving PR review comments. Flagging as a known limitation to design properly.
Pointers
workout-logger/lib/models/models.dartlines 155-173 (calculateVolume,effectiveWeight)workout-logger/lib/services/ml_service.dartlines 398-410 (deload-recency comparison)