The first workout should prove the plan
INCREMNT is an iOS strength-training app that turns your goals, experience, equipment, and schedule into a workout plan you can follow. This week I made the first workout part of that proof: onboarding now leads into a real, personalised logger with real history, recommendations, and a safe boundary around the sample data.
- Added a real four-set workout logger to onboarding, using the programme the athlete just generated.
- Seeded six weeks of varied history so recommendations, charts, previous sets, weekly sets, and personal records have something real to show.
- Added a personalised plan reveal with the selected goal, equipment, schedule, progression pace, and calibrated starting-weight explanation.
- Added a disposable execution policy so the sample can feel like production without writing to the athlete’s stores, Watch, HealthKit, widgets, or analytics.
Product: let the first workout answer the question
INCREMNT asks for a lot before it creates a programme: goal, lifting comfort, schedule, equipment, bodyweight, and—when available—a strength check. The old risk was obvious. An athlete could answer those questions, see a plan, and still have to trust that the plan would become useful once they reached the actual workout.
This week I moved that proof earlier. The programme reveal now says Your [programme name], shows the choices it was built around, and explains how the starting weights were calibrated. If the athlete selected a progression pace, the reveal names it plainly: Steady progression or Accelerated progression. The screen is intentionally quieter than the general plan-creation view. It removes generic trust and fit cards, keeps the facts short, and makes the personal inputs do the work.
Then the first workout uses that output. Onboarding mounts the production Logger with the generated programme’s first exercise and target. It is not a mock row or a one-tap animation. It is four editable working sets, with the same set editing, exercise information, history, recommendation explanation, chart, weekly-set context, and personal-record surfaces that exist in a normal session.
That distinction matters. A product can claim to recommend the next useful increment, but the athlete needs to see the chain: this is my plan; this is the movement it chose; this is what I did before; this is why the next target changed. The fixture seeds nine irregular sessions across six weeks to make that chain visible. Loads and reps vary. Notes vary. Recommendations change over time. The current sample is constructed to produce a genuine comparison rather than a decorative “great job” state.
The completion boundary is deliberately small and clear. The athlete must complete all four stable sample sets before onboarding enables Continue building my programme. There is no second Logger Finish button competing with that action, and there is no Skip Demo path that quietly turns an unfinished proof into a completed step. Going back discards the process-local sample world and preserves the answers already given.
The sample is also honest about scope. Notes, temporary swaps, recommendations, and score calculations can be explored, but the sample cannot mutate the saved programme, request a review, share a workout, start a HealthKit lifecycle, publish to Apple Watch, write a widget or Live Activity, or emit production workout analytics. The athlete gets to touch the real product without accidentally creating a fake workout in their real history.
Building INCREMNT: make the demo disposable, not fake
The technical problem was not rendering four rows. It was making the production Logger safe to run inside a journey that has not become a real athlete session yet.
I put that boundary in a typed LoggerExecutionPolicy. Production remains the default and keeps its normal capabilities. The onboarding showcase receives a different policy that disables durable persistence, HealthKit, Watch, widgets and Live Activities, production analytics, sharing, settings, programme-structure changes, and automatic target adjustment. Shared Logger boundaries ask the policy before performing those effects, rather than accumulating isDemo checks in individual views.
The other half is an isolated store graph. OnboardingLoggerShowcaseStore creates unique UserDefaults suites for the stores Logger needs, clears them before use, and removes them when the sample is disposed. The fixture builds a programme from the generated result, selects a suitable first exercise, gives it four stable set IDs, and creates the history around that same exercise. Recommendation storage receives a matching prescription fingerprint, so the visible recommendation is resolved by the same contextual machinery as a production one.
Stable IDs are doing real work here. Completion is calculated by matching the required set UUIDs, not by assuming that the fourth array element is still the fourth set after an edit or temporary swap. That makes the gate resilient to the kinds of mutations the real Logger permits while keeping the onboarding contract exact.
The test suite checks the boundary from both directions. Fixture tests verify that generated targets become four working sets, that the history populates previous-set and weekly-set calculations, that bodyweight exercises can still produce an effective-value personal record, and that the showcase store does not touch a production defaults suite. Presentation-policy tests verify that onboarding and existing-plan reveals share the compact personalised treatment while ordinary plan creation keeps its broader controls. Journey tests cover the path through the proof and paywall instead of treating the Logger as an isolated screen.
There is a useful engineering rule in this work: when a demo needs to prove a production surface, isolate the consequences—not the behaviour. Rebuilding a fake logger would have made the happy path easy and the proof weak. Running the real logger against disposable, deterministic stores lets the product stay honest while the policy makes the side effects reversible.
Also moved forward
Progression became more explicit across the app. Configurable overload strategies now distinguish Off, Steady, and Accelerated, with per-exercise overrides and a recommendation policy that carries prescription context. Turning progression off clears the stale strategy key, so re-enabling it cannot silently revive an old preference. The onboarding flow asks for the pace and carries it into the generated-plan reveal; tests cover the journey and the preference resolution.
The Apple Watch path also got safer. Restored workouts are reconciled against the current lifecycle instead of being allowed to replace an active session indiscriminately, and HealthKit errors now reach Sentry for diagnosis. Those changes are separate from the onboarding story, but they protect the same promise: a workout should remain understandable when it crosses a device or a process boundary.
What’s next
The next proof is release-facing: run the full onboarding journey against the built app, then exercise the sample on the accessibility and reduced-motion paths. The implementation is in place, but I’m keeping the language precise until those checks and the remaining release validation are complete.