Skip to content

Assisted-bodyweight volume encoding changes at the upgrade boundary, breaking trend comparisons #67

Description

@Devasy

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)

  1. 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.
  2. 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.
  3. 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.
  4. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions