A workout flow you can explain and edit
INCREMNT is a strength-training app that helps athletes plan, log, and learn from their training. This week’s work connected workout editing, score explanations, and Ask Coach so the path from a completed set to a useful next decision is clearer and more honest.
- The workout logger gained a single overview for selecting, reordering, swapping, linking, adding, and removing exercises.
- Increment Score moved to a plan-independent v4 model and now records typed before-and-after workout evidence.
- Automatic post-workout Coach prose was removed; athletes can open Ask Coach with the workout and score context attached.
- The weight field gained an inline calculator that handles plates, percentages, decimals, and repeated operations without leaving the set row.
Product: feedback that stays attached to the workout
The useful question after a workout isn’t just “Did I finish?” It’s “What changed, and what should I do with that information?” This week I worked on making that question answerable without sending the athlete through three unrelated screens.
The logger’s new Workout overview is the practical foundation. It opens above the persistent bottom control, so the athlete can see the whole session without losing the current navigation target. Exercises are grouped, supersets are visible, the current exercise is marked, and completed work has a clear state. When the workout is still editable, the same surface supports reorder, swap, link, unlink, add, and remove actions. A read-only history view gets the overview without pretending old work can be changed.
That boundary matters. An athlete can adjust an unfinished session, but once all sets for an exercise are logged, a swap is rejected with an explicit notice. The app also keeps temporary workout edits separate from permanent programme changes. That makes “change what I’m doing today” a real operation instead of a disguised plan mutation.
The score now follows the same product rule: show what the recorded work can support, and label what it can’t. Increment Score v4 no longer uses plan adherence as a hidden penalty. It evaluates actual training signal, stimulus, progression, recovery, and movement coverage, with a plan-independent set of default muscle targets. A workout can contribute useful evidence even when the athlete is training outside a formal programme.
The recap makes that evidence inspectable. It can show completed working sets, weekly muscle-set changes, exercise-strength comparisons, movement-family coverage, and same-muscle spacing where those measurements exist. The score tiles still show component values, but the underlying explanation is now a paired before/after record rather than a sentence generated after the fact.
That is why the automatic Coach recap went away. A background request that quietly writes a paragraph into the summary sounds convenient, but it makes the product responsible for an unsolicited interpretation and a second source of truth. The summary now offers an explicit “Ask Coach about this workout” action. When a valid score handoff exists, the question includes the score change and the evidence needed to discuss it. When it doesn’t, the question stays general. The athlete chooses whether to continue.
Building INCREMNT: make the boundary typed, not aspirational
The hard part was not adding another card. It was deciding which object owns the handoff between logging, scoring, and coaching.
The logger work consolidated structural changes behind editWorkout. Add, remove, move, link, unlink, and swap all pass through the same path, with execution policy checks at the boundary. The overview is therefore a presentation of the editing model, not a parallel set of mutations. That reduced a particularly dangerous class of bugs: two exercises with the same name could be reordered while their stable identities and prescription history drifted apart. The fix compares UUID slot order first and only falls back to name occurrence matching for older or unmatched data. Tests cover identical-name reorders, distinct targets, cold restore, and mixed add/remove changes.
The score took a similar shape. IncrementScoreEngine now emits an IncrementScoreWorkoutEvidence value alongside the score delta. The evidence is built from the same before and after evaluations used to calculate the number. It is not a second explanation algorithm. That lets the summary say, for example, that a workout added working sets for a muscle or changed a recent strength comparison without inventing a causal story later in the UI. History views that lack recorded evidence recalculate the paired v4 result and label that state instead of attaching new evidence to legacy numbers.
The Coach handoff is typed as well. WorkoutScoreHandoff carries the completion time, formula version, before and after score, component changes, first-score state, and a small set of evidence strings. The prompt builder changes its question based on whether that handoff is present. Tests check both branches, including preservation of the session identity and score context. The hosted Coach route has matching conversation tests, so the mobile request and the service contract move together.
There’s a useful engineering constraint here: explanation should be a by-product of the decision data, not a parallel feature that tries to reconstruct it. When the data is missing, the interface should narrow its claim. That is less magical, but it is much easier to test and much harder to mislead someone who is deciding what to train next.
The last-mile interaction got the same treatment. The logger’s weight calculator is a small parser and draft state machine in StrengthTrackerCore, not string concatenation in a SwiftUI view. It handles multiplication for mirrored plates, percentage adjustments, decimal input, repeated equals, backspace, invalid expressions, and negative intermediate results while refusing to commit a negative weight. Core tests cover the parser and editing semantics; UI tests cover the accessory in the set row. An athlete can enter 20 + 22.5 × 2 and commit the result without leaving the workout.
On Apple Watch, the week also tightened the workout surface across display sizes and kept rest controls reachable. The same principle applies: preserve the active workout state, make the next action obvious, and keep the presentation responsive to the device rather than assuming one screen shape. The changes were exercised through layout snapshots and Watch connectivity tests.
Also moved forward
- The workout score can now be handed to Coach with the same component breakdown shown in the summary.
- Live Activity state records the set currently displayed by the logger, with snapshot-store tests for the handoff.
- The current release train was prepared and validated through the repository’s release checks; that is preparation, not a claim about App Store availability.
The pattern I’m keeping is simple: let athletes edit the work, let the score explain only the evidence it has, and make coaching an explicit next step. That gives INCREMNT one coherent path from set entry to decision without pretending certainty where the record is thin.