"Neither Office reachability nor Pippa availability may stand between Dad and a captured thought."
Save Locally First, Always
The strongest promise Vesta makes is that a thought is never lost to a dead network. That promise has a precise engineering shape: local write precedes network sync, always. When you capture a crumb, it commits to a device-local outbox first and confirms immediately — before any request leaves the phone. Only later, when the engine is reachable, does the outbox drain the crumb up to the server. The network is not on the critical path to 'saved'; it's on the path to 'synced', which is a different, later thing.
This is the Switzerland lesson, inherited from Waystone: a hotel network that half-works, a tunnel with no signal, an engine that's asleep — none of them may sit between you and a captured thought. If saving required the server, then every weak-signal moment would be a moment you couldn't journal, which is exactly the moments most worth capturing. Local-first turns the network from a precondition into an afterthought.
The Outbox State Machine
The outbox makes that promise concrete with a small state machine. A crumb moves LOCAL_ONLY (written on device, not yet queued) to QUEUED (waiting to sync) to SYNCING (in flight) to SYNCED (the server acknowledged) — and if a drain fails, to FAILED_NEEDS_ATTENTION, surfaced plainly so nothing fails silently. The critical rule: the local payload is never deleted before an idempotent server acknowledgement. The crumb only leaves the device once the server has provably taken it, and because the acknowledgement is idempotent (keyed by a client-generated request id), a retry after an ambiguous failure can't create a duplicate.
Two more details make it trustworthy under real outages. Capture order survives: while the queue is non-empty, a new crumb joins the back of it rather than racing ahead, so your morning note can't sync after your afternoon one. And a server 4xx — a genuinely invalid payload — surfaces inline instead of queueing forever, because the outbox exists to defeat flaky networks, not to hide a bug the user needs to see.
Synced Is Not the Same as Saved
The mental shift this forces is healthy: 'saved' and 'synced' are two different states, and the UI must be honest about which one you're in. A crumb that's LOCAL_ONLY or QUEUED is already safe on the device — the thought is not going to be lost — but it hasn't reached the server yet. The stream surfaces that unsynced count openly, treating device storage as a staging area rather than the final archive. You're never left guessing whether a thought made it; the honest answer is always visible, and the safe state is reached the instant you finish typing.