"The payload is frozen the instant you hit submit. After that, the only thing the world can touch is a status flag."
Two Kinds of State in One Turn
A captured turn has two very different kinds of state, and keeping them separate is what makes interruptions harmless:
- The payload — the question text and its image blobs. This is immutable from the moment of capture. Nothing about a network event, an app kill, or a retry ever rewrites it.
- The sync status —
pending → sending → answered | failed. This is the only mutable part, and every transition is a durable write.
Once you see a turn this way, "what happens when the app is killed mid-send?" has a boring, correct answer: the payload is untouched (it was frozen and durable), and the status is either still sending or already flipped to failed. Either way, the next launch knows exactly what to do. Interruption is not a data-loss event. It's a status-transition event.
Why Immutability of the Payload Matters
If interruptions could mutate the payload, every failure would be a potential corruption. A retry that re-encodes the question, a background sync that re-reads a half-written blob, a crash between two field updates — each becomes a way for the user's actual words to change without consent. By freezing the payload at capture and only ever transitioning status, you collapse a huge space of failure modes into one small, well-understood state machine. The scary question "is my data still correct after that crash?" becomes "which status is it in?" — a question with four possible answers, all safe.
The Status Machine Is the Contract
Design the status transitions explicitly and the resilience follows. There is no transition that deletes a payload. There is no status that means "lost." The worst status is failed, which still holds the full turn and simply invites a retry. That's the promise made visible: an interrupted turn is never gone — it's just somewhere on a small, safe map, waiting.