"An update moves the data container. Nothing may treat an absolute container path as identity."
The App Is Not Running Most of the Time
A Mac utility runs until someone quits it. An iPhone app is in the foreground for a few minutes, then backgrounded, suspended, and eventually terminated by the system without a word. SwiftUI reports the part you can act on through scenePhase: active, inactive and background. For a thin client, backgrounding is the ordinary case rather than an error path. When the scene goes to the background, save the draft, hand resting changes to the outbox and close the socket. When it becomes active again, reopen and replay from the record instead of assuming the old connection survived. Anything that must reach the person while no screen is attached belongs to push, not to a socket kept alive in hope.
The prose editor's phone app took this literally: it sends its changes once writing rests and again when the app leaves the foreground, and it keeps a recovery draft for the case where the app is killed mid-sentence. Nothing depends on getting one more second of background time.
The Sync That Stopped After an Update
The same app's device sync worked on the first TestFlight build. After the second build installed, every sync stopped at once with "Sync recovery belongs to another initiating replica", before checking anything. The sync journal had recorded the data root's absolute path and compared it byte for byte. Two more path-derived things were waiting behind it: an identity cache keyed by a hash of the root path, which would have minted a new replica identity with no shared history, and per-note sidecar files named by a hash of each note's absolute path, which would have looked orphaned and been planned as deletions.
The assumption was that an installed app's container path stays put. Measured in the Simulator, reinstalling over the installed app moved Data/Application/4DE73F62… to Data/Application/2C5B5925…, the old path no longer existed, and the device and inode numbers of a folder and a file inside were unchanged: the container had been renamed, and the phone's symptom matched. The rules that follow are simple. Re-derive container locations on every launch through FileManager. Never persist an absolute container path as identity, and never feed one into a persisted name. Store paths relative to the root. Where an older build already wrote absolute paths, rebase them on read. And when you need to know that a file is "the same file", compare device and inode, which survive the move.