Sync / Replicated state

When things go wrong

Each of these is designed for. The ones that change how you build come first.

FailureWhat happens
The network is goneedits apply and save; pending grows; the loop retries
The server rejects an editdropped from pending, the rest replayed, the Model re-installed
The local save failsthe edit is reverted and onPersistenceFailure says so
Another device commits firstthe base advances; local edits replay on top
An operation is retriedthe stable opId is answered from history, never applied twice
The replica is far behindpages (more), or a checkpoint when the tail was compacted
The server lost its historya new epoch: the replica rebuilds from 0 and resends its outbox; what the old server committed is gone everywhere; a replica that never heard an epoch cannot tell and fails until its storage is cleared
Another actor sends a replica's operationsDurable refuses them: a replica is bound to its first committing actor
Local storage was evictedthe replica catches up from the server, but unsent edits are lost: the outbox is user data
Two tabs share one storage namecompare-and-swap fails the stale writer rather than merging histories
Stored state is from another versionopening fails naming both versions; the bytes are kept for a deliberate migration
The server answers nonsensea malformed answer, a gap in the order, an ack for an operation never sent, or a checkpoint behind the cursor fails the exchange; local work is untouched
An external effect succeeded before a crash recorded itthe provider call may repeat; use provider idempotency with Durable's effect ledger

The last row is the one the libraries cannot close. A committed operation may imply work outside SQLite (an email, a charge), and no local database can commit atomically with a provider. Durable's runEffect and recover record intents and reuse known outcomes; they do not make the provider transactional. Read external effects before wiring one.