Variant A refuted on device 2026-07-10 (phone kept its higher count; the
win was timing, not a structural guard — the merge remains pure
newest-modTime-wins). Step 2 now lists ranked link-severing methods,
since phone-side Airplane Mode provably doesn't cut the watch link.
Claude-Session: https://claude.ai/code/session_01PVNBVKp5bcq52X722uMjwT
The rollback repro (watch-side airplane mode, phone-ahead/watch-behind
divergence, queued transferUserInfo delivery), the ready-made L4 Merge
Test split in the iCloud container, confirm/refute criteria, and the
deferral caveats (monotonic clamp would break the deliberate
swipe-back-to-Ready reset).
Claude-Session: https://claude.ai/code/session_01PVNBVKp5bcq52X722uMjwT
The decode-failure freeze (BULLETPROOFING.md L3) is production-reachable
after all - a phone app can update days before the watch app
auto-updates, and every push in between fails to decode, silently
freezing the watch at its last good sync. The bridge now tracks
schemaMismatch (set on a failed decode, cleared on the next good apply)
and ActiveWorkoutGateView shows an "Update both apps to resume sync"
banner while it's set.
Also give requestSync an error handler that logs the dropped pull (L2;
deliberately no retry - the activation/reachability edges re-pull), and
sync DEVICE-COMMUNICATION.md to the post-bulletproofing reality (T1 as
optimization, session recovery, degraded pushes, surfaced mismatch).
Claude-Session: https://claude.ai/code/session_01PVNBVKp5bcq52X722uMjwT
Two stale-UI traps in the run flow (BULLETPROOFING.md M2, M3):
A log resolved remotely (completed or skipped on the other device) left
the open exercise screen live - its next recorded set wrote the log
back to in-progress, resurrecting it through the per-log merge. Both
platforms' ExerciseProgressView now observe the log's status and
dismiss on a remote terminal flip (a locallyResolved flag exempts the
screen's own Done / flow hand-off). The watch also gains the phone's
startsSkipped terminal page, so opening a skipped exercise shows a
static badge instead of a live flow.
The live-mirror cover ran the flow engine with no onAdvance host, so an
auto-advance split's terminal between-exercise rest completed the
exercise then froze at 0:00. With no hand-off host it now dismisses
instead; the driver's next-exercise frame re-presents the cover.
Claude-Session: https://claude.ai/code/session_01PVNBVKp5bcq52X722uMjwT
Two watch-stranding fixes (BULLETPROOFING.md M1, M4):
The exclusive-edit lock rode in the latest-wins context and was cleared
only by onDisappear, so an editor left open in a pocketed (or
force-quit) phone parked the watch's run indefinitely ("Editing on
iPhone..."). The scene-phase hook now publishes the locks as cleared
while the app is backgrounded - without forgetting them locally - and
re-asserts them on return to the foreground.
pushAll treated a failed updateApplicationContext as log-only, so a
payload past WatchConnectivity's size ceiling silently froze the watch
out of all future state. A failed push now retries with the
recently-completed tail dropped (display-only on the watch); only a
failure of the slim push too remains an error.
Claude-Session: https://claude.ai/code/session_01PVNBVKp5bcq52X722uMjwT
The HKWorkoutSession could only ever be born via the phone's one-shot
startWatchApp handoff (BULLETPROOFING.md H1-H3): a dropped handoff, a
watch crash/reboot, or a run engaged manually on the wrist left the
whole workout sessionless - no heart rate, no Health save, app
suspending wrist-down - and "End Current & Start New" swallowed the
handoff against the old session's idempotency guard.
Now the coordinator self-starts a session on any reconcile that finds
an active run with none running (SessionEndPlanner.shouldStart /
runToStart, activity type from the run's split), recover() re-adopts a
crash-orphaned session at launch, and a system-ended session salvages
its Health save instead of dropping it. A .finish decided for a
session younger than 30s demotes to .discard so the stale-context
races can't save junk workouts attributed to the wrong run; parallel
completions now pick the survivor deterministically.
Claude-Session: https://claude.ai/code/session_01PVNBVKp5bcq52X722uMjwT
DEVICE-COMMUNICATION.md: exhaustive reference for every phone<->watch
exchange - triggers, wire datapoints, transports (T1-T4), and the internal
structures each side mutates - plus end-to-end sequences and failure modes.
BULLETPROOFING.md: ranked gap analysis (H1-H3 session lifecycle, M1-M4
stranding/stale-UI traps, L-tier) with code evidence, failure scenarios,
fix directions, and a recommended fix order.
Claude-Session: https://claude.ai/code/session_01PVNBVKp5bcq52X722uMjwT