The UX redesign's first landing (spec in UX-REDESIGN.md): ContentView
becomes a Today / Progress / Settings TabView, "Routine" replaces
"Split" in every user-facing string and view name (code-level types
keep their names), and workout starting moves to shared
WorkoutStarter / StartedWorkoutNavigator plumbing.
- New Progress tab: weekly goal streaks, workout trends, per-exercise
weight progression, achievements, and the full history list
(WorkoutLogsView -> WorkoutHistoryView).
- Goals: stable categories workouts roll up to, managed from Settings.
- New Meditation exercise + starter routine; timed sits record to
Apple Health as Mind & Body sessions.
Claude-Session: https://claude.ai/code/session_012qw2itfzKyEJ1HpsFt8Ex4
Adds WorkoutActivityType.warmUp (HealthKit .preparationAndRecovery) and
.stretching (.flexibility), and retags the six starter splits that were all
mislabeled as Functional Strength:
- Warm-Up: Upper Body Warm-Up, Lower Body Warm-Up, Morning Wake-Up
- Stretching: Morning Mobility, Full Body Stretch, Evening Stretch
The split editor's activity picker surfaces them automatically (CaseIterable).
Older app versions decode the new raw values as the default type — additive and
not schema-gated, so no quarantine.
Every completed set now writes a SetEntry (reps/weight or seconds),
pre-filled from the plan by transition(to:) so the list checkbox, both
run flows, and One More all capture for free; reset clears, skip keeps
partials. The rest and finish pages show the just-done set as a pill
that opens a stepper sheet for correcting reps and weight (2.5 lb /
1.25 kg steps). The Weight Progression chart plots the top-set actual
weight and workout volume sums recorded sets, both falling back to the
plan for legacy logs via effectiveSetEntries.
Storage side of UX #3 rides along: plan weights are Double now.
Schema bumps: SplitDocument 2→3, WorkoutDocument 3→4 (a fractional
weight fails an older Int decode, and a rewrite would strip the
irreplaceable actuals), SwiftData cache 4→5. A per-log updatedAt is
reserved for the future cross-device log merge.
Claude-Session: https://claude.ai/code/session_01HJDQQDA9QdP8zByg43H5v3
The phone no longer writes estimated Health workouts: the watch, which
runs the live session, is the sole recorder. Replaces WorkoutHealthWriter
with a WorkoutHealthDeleter that only removes a legacy phone-estimate
workout when its record is deleted here, drops the MET calorie table and
the phone's write/read Health scopes, and keeps phoneEstimate decodable
for existing documents.
Claude-Session: https://claude.ai/code/session_01HJDQQDA9QdP8zByg43H5v3
Watch sessions now run an HKLiveWorkoutBuilder: heart rate and active
energy are collected live (shown in an in-workout HUD), saved to Health
as a real HKWorkout on completion, and carried back to the phone as
WorkoutMetrics on the workout document. Phone-only workouts get an
estimated Health workout (MET x bodyweight x duration) after a 10s
debounce that a late-arriving watch session cancels; a launch sweep
backfills workouts completed within the last day. Dedupe is keyed on
metrics.healthKitWorkoutUUID plus the metrics source.
Splits gain an activity type (strength, functional, HIIT, core, cardio,
cycling) that categorizes the Health workout and picks the MET value.
A post-workout summary sheet (duration, calories, avg/max HR, HR zones,
total volume) fills in live and is also shown on completed workouts.
Weights can now display in lb or kg (display-only relabel), synced to
the watch over the existing application context.
WorkoutDocument schema 1->2 (metrics are irreplaceable, so older apps
must quarantine rather than strip them); cache schema 2 rebuilds the
SwiftData store with the new metric columns. Deleting a workout in the
app intentionally leaves its Health record in place.