Suspend watch edit locks on background; degrade oversized pushes

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
This commit is contained in:
2026-07-09 23:04:19 -04:00
parent abb223daca
commit 25a111a6b4
4 changed files with 53 additions and 14 deletions
+4
View File
@@ -31,6 +31,10 @@ struct WorkoutsApp: App {
// the app is backgrounded, so re-assert it each time the scene becomes active.
.onChange(of: scenePhase, initial: true) { _, phase in
UIApplication.shared.isIdleTimerDisabled = (phase == .active)
// An editor left open when the app leaves the foreground must not keep the
// watch's run parked ("Editing on iPhone") suspend the published edit
// locks while backgrounded; returning to the editor re-asserts them.
services.watchBridge.setLocksSuspended(phase != .active)
// Last chance before suspension: push any queued document writes out
// now rather than waiting out a retry backoff we may not live to see.
if phase == .background {