Dev Diary

Show the work before asking for trust

INCREMNT is an iOS strength-training app that turns what you log into a clearer next workout. This week, onboarding moved from describing that promise to proving it: the path now uses a person’s goal and training need to show credible research, real product behavior, and a plan that can survive an interrupted setup.

  • Onboarding now asks for a personal training goal, explains the plan that goal leads to, and shows bounded research context without presenting study results as a personal forecast.
  • Each training-support choice now maps to a real INCREMNT demo: a plan, logger, exercise swap, or Coach conversation, with a still image for reduced motion and VoiceOver.
  • The generated programme can be reviewed, edited, and resumed without losing the answers that shaped it or accidentally keeping a stale proof state.
  • Added focused Swift tests and Maestro journeys for the proof screens, persistence, accessibility paths, analytics versioning, and interrupted onboarding.

Product: prove the next step before asking someone to take it

The first question in a training app is rarely “how many sets?” It’s closer to “will this make sense for me?” A person arriving at INCREMNT may want to get stronger, build muscle, lose fat, or simply feel more capable. They may need a plan, less fiddly logging, an alternative when equipment changes, or a clear answer when they get stuck. A generic tour can mention all of those things and still leave the user guessing.

This week I changed the order of the conversation. After someone chooses a personal goal, INCREMNT gives that goal a concrete explanation before continuing into setup. The strength path says what the plan is trying to build. The muscle path explains why the routine is structured the way it is. Fat loss and recomposition are described without pretending that resistance training can predict an individual result. General fitness gets the same treatment: useful context, with the boundary that an association in a study is not proof of cause or a statement about one person’s risk.

That restraint is part of the feature. The evidence card shows the size and type of the underlying review, names the source, and offers a research view. It doesn’t turn an average across studies into “you will lose this much” or “this will happen in four weeks.” Trust is easier to lose than to gain, especially during onboarding, so the copy has to carry its own caveats.

The next proof is practical. INCREMNT asks what kind of support would help, then shows the matching behavior instead of another illustration. Choose a clear plan and the screen shows an example programme with exercises, sets, and adjustable starting targets. Choose easy logging and it shows a set being recorded, the rest timer starting, and the option to log from Apple Watch. Choose flexibility and it demonstrates swapping an exercise for a recommended alternative. Choose guidance and it opens an example Coach exchange about starting a first workout.

Those demos are short recordings of the actual product, paired with a poster and an accessible still. They pause when the scene is inactive, avoid autoplay when reduced motion or VoiceOver is enabled, and expose a descriptive accessibility label rather than asking someone to infer the point from a moving phone mock-up. The result is less theatrical and more useful: the person can see what the decision buys them.

The proof also changes what “personalized” means. The selected goal and support need are not decorative labels; they drive the copy, media, and the generated programme request. The plan preview can be reviewed before the commercial handoff. Exercises can be replaced or hidden, and the preview keeps the surrounding intent intact. The user gets to inspect the thing they are about to save instead of accepting a black-box result.

Building INCREMNT: make proof a state transition, not a pile of screens

The hard part was not adding four videos. It was making a longer, more persuasive journey remain correct when people go back, change an answer, lose focus, background the app, or return later. I kept the decisions in a value-only journey state and let the views render that result. A goal selection, support choice, generated programme, and proof completion each have a typed place in the reducer rather than a private flag owned by whichever screen happens to be visible.

That gives us a useful invalidation rule. If an answer that shapes the programme changes, the generated result and any downstream logger-proof completion are cleared. If someone only revisits a presentational proof, the programme stays valid. The same distinction prevents a benchmark timestamp refresh or a back-navigation animation from silently changing the inputs that generated a plan. It’s a small example of a larger boundary: presentation can replay, but durable product decisions need an explicit owner.

Persistence made that boundary real. Drafts now carry the current step, pending input, selected personal goal, support choice, analytics attempt identity, and a lossless snapshot of the generated programme. Pending discrete answers are stored separately from committed answers, so an interrupted tap does not become a half-applied plan. Older drafts that used the previous support vocabulary are decoded into the nearest current choice instead of being discarded. The tests cover round trips, schema migration, pending answers, restored generated programmes, and the rule that changing upstream input resets proof completion.

The media layer follows the same discipline. A single descriptor chooses the resource, poster, accessible still, caption, and duration for each support need. The controller owns playback, cancels its work on exit, and switches to a static image for reduced motion or VoiceOver. That keeps the SwiftUI view about composition and the controller about lifecycle. It also makes the contract testable: every demo must have a poster, an accessible still, a video track, and a duration within tolerance.

Analytics got a typed boundary while the flow was changing. The funnel now records goal proof, support proof, programme review, and the current funnel version without scattering raw strings through the screens. Legacy events are normalized at the compatibility edge. This matters less for a dashboard than for debugging the product: if an old draft resumes in the new flow, we can tell which experience it actually used.

The test suite reflects the risks rather than the novelty. Unit tests check evidence units and disclaimers, progression copy, reducer transitions, accessibility disclosure timing, media resources, and autoplay cancellation. Source-level assertions make sure the logger showcase mounts the production logger instead of a scripted fake and that generation does not invent staged progress copy. Maestro journeys walk through goal proof, support proof, equipment changes, back-navigation, interrupted setup, and a reviewed programme. The point is not to prove that onboarding converts. It is to prove that the claims on the screen match what the app can actually do.

The transferable decision is simple: when a product asks for trust, make the proof use the same state and components as the thing it promises. That costs more than a static tour, but it prevents the most expensive kind of mismatch—the one a user discovers immediately after committing.

What’s next

The onboarding proof is prepared in the app and covered by focused checks; release and live behavior still need their own evidence. I’m keeping the next pass narrow: exercise the full journey on the built app, watch for draft migrations that only appear in older installs, and make sure the first real workout feels like the continuation of the proof rather than a new sales pitch.

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.