Skip to content

feat: Optional per-set power (watts) tracking for weighted exercises - #906

Draft
jhoblitt wants to merge 2 commits into
LiamMorrow:mainfrom
jhoblitt:power-tracking
Draft

jhoblitt wants to merge 2 commits into
LiamMorrow:mainfrom
jhoblitt:power-tracking

Conversation

@jhoblitt

@jhoblitt jhoblitt commented Jul 16, 2026

Copy link
Copy Markdown

Implements optional per-set power (watts) tracking for weighted exercises.

Discussion: #904.

Updated 2026-07-16: rebased onto current main and adapted to the
intervening refactors — the repsPerSetrepsConfig rework and the
schema v2 → v3 bump. Now conflict-free against main. Full suite green
(774 tests), typecheck and oxlint/oxfmt clean.

Why

Some strength equipment reports the peak power produced during a set — e.g.
Keiser functional trainers show max watts per set. LiftLog has no concept of
power today, so the only workaround is a parallel "Chest Press power" exercise
whose "weight" is really watts, which distorts total-weight-lifted stats and
graphs the value in the wrong unit.

What

All of this is opt-in per exercise and defaults off — nothing changes for
users who don't enable it:

  • A "Track Power" toggle on weighted exercise blueprints, next to the
    superset toggle.
  • On first completing a set of a power-tracked exercise, a skippable dialog
    asks for the max power (whole watts). Also captured when a set is completed
    via the long-press rep dialog; editable there afterward.
  • Recorded watts show as a small line on the set tile (312 W) and in
    history/summary chips.
  • The toggle propagates through the plan-diff flow, so flipping it
    mid-workout persists to the program (otherwise it would produce a phantom
    empty diff).
  • Stats: a Max Power over time chart on the exercise stats page, shown only
    for exercises that have recorded power.

Data model

  • RecordedSetJSON gains optional power?: number (integer watts); power lives
    only on a completed set.
  • WeightedExerciseBlueprintJSON gains optional trackPower?: boolean.
  • Both are additive within schema v3 — no new migration. Old data loads
    unchanged (fromJSON defaults trackPower to false). Regenerated
    docs/schemas/** (and the plan-builder schema/validator) are included.
  • No backend changes (feed payloads are client-encrypted; the C# models don't
    include recorded sessions).
  • Also preserved through the AI-plan fill path, so a trackPower returned by
    the planner survives ingest.

Compatibility caveat: older clients read newer data fine (unknown fields
drop at parse), but an older client that loads-then-saves newer data (e.g. a
downgrade) rewrites it without the new fields, dropping recorded power in its
local copy. This is the app's existing behavior for every additive schema
change; flagging it in case you'd want a different policy.

Testing

  • Unit tests for the model semantics (power preservation across rep edits, JSON
    round-trip, equality, maxPower/latestRecordedPower, the trackPower
    plan-diff round-trip, AI-plan fill preservation, max-power stats). Full suite
    green (774 tests); oxlint/oxfmt and typecheck clean.
  • Manually validated on-device (Android): toggle → completion popup → skip →
    set-tile watts → long-press entry → plan-diff prompt → history chips →
    Max Power chart → mid-workout persistence.

Checklist

  • The code compiles and passes all tests.
  • Linting and formatting checks pass.
  • The PR description clearly explains the changes.
  • Related documentation is updated. — no user-facing docs exist for this
    area; the generated schema JSON is regenerated and included.
  • No sensitive information is included.

AI assistance: developed with AI help (locating change sites, drafting the
edits and this description); design decisions and review are mine.

🤖 Generated with Claude Code

@LiamMorrow

LiamMorrow commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Thanks @jhoblitt I'll be honest I saw the discussion but did not read it fully as I noticed it was written by AI. This is not inherently bad, I use claude myself but what tends to happen is that rather than coming with a problem statement which can be worked into the app, claude is so eager to do the thing it will just come up with a solution that will work at any cost. I should have replied then I'm sorry about that.

I'm still ironing out LiftLog's AI policy, but the main thing I want to instill is:

  • AI is totally valid as a tool for writing code, however it will be held to the same standards as a human's code.
  • PR descriptions, discussions, issues should all be written by a human. To me it demonstrates that the problem has been thought through and not just been handed to claude with a one liner. There's a lot of extraneous information in this PR description which you would never write, but claude thinks is necessary and it just reads frustratingly to me.
  • Work should still be split up, ideally into different PRs. This feature PR is actually a few different features working together.

I'd love any feedback on these policies, and they are currently being outlined in https://github.com/LiamMorrow/LiftLog/blob/main/CONTRIBUTING.md.

I don't mean to single you out, you just happen to be the first PR since the policy. This isn't a criticism of the work or you! I just immediately get put off when I start reading someone else's AI output. I read this blog post once and it did a great job of describing how I feel https://www.seangoedecke.com/dont-feed-me-slop/

Apologies, now with that all out of the way! You did start on this before that policy was uploaded.

There's a few things here:

  1. I'd love some screenshots of what you have currently it will help me visualise
  2. There are 3 PRs I feel could be here, which would help split up this ~700 line pr into reviewable chunks:
    a. Update the data model
    b. Update the exercise editor and session component
    c. Add stats
  3. I'd like to avoid using bare numbers for power, can we add a Power class, like the Weight one.
  4. We can iterate on the UI after I've seen it in action, but my gut is saying I'd love to have something more like the cardio input cards than a dialog which pops up after completion.

Philosophically this change brings in another question as well. Is it valid to track power, without weight?

jhoblitt and others added 2 commits July 16, 2026 16:09
Records peak power (watts) per completed set for equipment with a power
readout (e.g. Keiser trainers). Adds an optional power field on
RecordedSet and an opt-in trackPower flag on the weighted exercise
blueprint, both additive within schema v3. Propagates the toggle through
the plan diff, preserves it when filling AI-generated plans, and adds a
max-power-per-session stat series.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A Track Power toggle in the weighted exercise editor; a skippable
watts dialog on set completion (and via the long-press rep dialog);
watts shown on set tiles and summary chips; and a Max Power chart on
the exercise stats page. All gated on the per-exercise trackPower flag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jhoblitt

Copy link
Copy Markdown
Author

The human subagent acknowledges and will respond soon. ;)

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.

2 participants