Dev Diary

Proof you can follow

INCREMNT is an iOS strength-training app that builds a programme, guides each workout, and adapts what comes next; this week I worked on a simple product standard: important promises should come with a proof trail an athlete can inspect.

  • New onboarding work lets people configure a programme, try two real product proofs, and inspect the generated plan before sign-in or payment.
  • The generated programme can be reviewed in place: replace, hide, or remove an exercise, then undo the edit before continuing.
  • Body now turns completed training into rolling volume history with period comparisons, filters, and drill-downs to the workouts behind each point.
  • Progression updates now target exercise slots by UUID and record only genuine applied increases, avoiding false history when a recommendation is a no-op, retry, or backoff.

Product: make the promise inspectable

INCREMNT is meant to help an athlete make the next training decision with more context than a static plan can provide. That promise is hard to judge from a feature list. You have to see the programme take shape, understand what the app is measuring, and know where a number came from.

The new value-proof onboarding is built around that sequence. It asks for the things that actually shape a plan—goal, experience, recent training, days, session length, equipment, exclusions, bodyweight, and an optional benchmark—then uses the production programme generator. The proof screens aren’t decorative mock-ups. One demonstrates adaptive prescription with isolated sample data. Another lets the user complete a small logger interaction and see the resulting evidence and recommendation. The generated programme is the payoff: actual days, exercises, sets, rep ranges, and targets, followed by a short explanation of how the plan will evolve.

The order matters. The athlete sees and inspects the result before being asked to sign in or pay. Sign-in is framed as saving the programme, not as a toll gate before the product has done anything. That makes the commercial boundary clearer and gives the user something concrete to decide about.

Review is also part of the product, not an escape hatch. On the programme reveal, an exercise can be replaced, hidden from future plans and swap suggestions, or removed from this programme. The journey keeps an undo history and rechecks the plan when needed. If a question changes earlier in the flow, the generated output is invalidated rather than quietly left stale. The rule is straightforward: a plan should be editable while its assumptions are still visible.

That same standard now shapes Body. Body is not a scorecard and it doesn’t prescribe the next workout. It answers a narrower question: where did completed work go, and how has that changed? Volume History covers inclusive rolling lookbacks of 7, 28, 91, 182, or 364 days. The week is daily; longer periods use consecutive seven-day buckets. A user can switch between effective sets and canonical load, then filter by focus, movement type, muscle, and equipment.

Most importantly, a plotted value is not a dead end. Selecting a point opens the completed workouts that contributed to that day or bucket, newest first, and the full workout remains available. The Muscle Map and Muscle Status use effective-set credit—primary muscle at 1.0, secondary at 0.5—and can drill into the exercise contributions behind the classification. If there isn’t enough matched history for a comparison, Body says so instead of manufacturing a trend.

These choices put a boundary around what the surface is claiming. Body explains completed training; Coach owns recommendations. A chart point is evidence, not a verdict. The onboarding plan is a proposal the athlete can inspect and adjust, not an opaque answer that has to be accepted whole.

Building INCREMNT: keep every claim attached to its evidence

The engineering problem underneath both surfaces is the same: several views want to summarise training, but they must not invent a different version of the underlying event.

For Body, I pulled the work into a domain model rather than letting each SwiftUI view calculate its own totals. BodyVolumeSnapshot carries the selected and prior ranges, history facts, contributing sessions, and the normalisation factors for longer periods. A fact retains the session ID, bucket, load, effective-set credits, primary muscle, and exercise taxonomy. Filters are applied before aggregation. The chart, comparison label, bucket sheet, and muscle detail view therefore consume the same rows.

The tests make the edge cases explicit. A Monday workout appears immediately in the correct rolling week and month. A long range reports average weekly sets rather than pretending four weeks and 52 weeks are the same unit. A zero prior baseline is labelled New; an absent matched prior period stays absent. Repeated exercises in one programme produce distinct evidence rows. A selected bucket can be traced back to the workouts that contributed to it. Those tests are a useful guard against a common analytics failure: a plausible total that no one can explain.

The progression fix applies the same discipline to saved state. Recommendations used to find a slot by exercise name, which is unsafe when the same movement appears twice. Completion-time updates now prefer the persisted exercise UUID, with canonical-name matching retained only for legacy callers. A consumed-slot set prevents a duplicate update or duplicate logged exercise from being applied twice.

There is a second boundary around what counts as progress. The store records a progression outcome only when the working sets actually change. A warm-up recalculation cannot turn a no-op recommendation into fake history. Decreases, retries, and deloads remain useful detailed outcomes, but they don’t count as cycle increases. The implementation keeps both facts without confusing them.

The tests cover the decisions rather than only the happy path: no-op recommendations, backoffs and retries, one genuine increase per exercise, duplicate updates, same-name slots, and duplicate logged exercises. That is a lot of fixture code for a small-looking bug. It is worth it because a false progression record changes what the athlete sees later, and later recommendations depend on that record.

The transferable design choice is to make the evidence object first-class. Keep the bucket, source session, slot identity, and comparison window alongside the display value. Then let the chart, explanation, history, and tests use that object. It costs more than calculating a number at the edge of the UI, but it gives every surface the same answer and gives the user a route back to the source.

What’s next

I’m going to keep tightening the handoff between proof and practice: the moment an athlete starts the generated programme, changes an exercise, and later sees the resulting work in Body. The useful test is not whether each screen looks convincing on its own. It’s whether the same decision remains understandable after the workout is complete.

This diary was generated and edited from the week’s commits, pull requests, tests, and development notes using AI, evidence-checked, and automatically published, and may describe work not yet publicly released.