Sync / foldkit-sync
What makes a Message durable
Replay runs a durable Message through update on another machine, later,
possibly many times as the base beneath it moves. So it has to be a
deterministic, state-only transition of the shared slice. make derives replay
from update and refuses a durable Message whose transition:
- returns a Command, because an effect cannot be replayed; or
- changes a field outside
shared, because that change would be lost.
A refused Message fails submit with ReplayError and writes nothing, so a
mistake shows on the first edit instead of as diverging replicas later.
The consequence is a pattern you will use everywhere: an intent mints, a fact records.
RequestedTodo { title } local: its update returns a Command
| that reads the clock and mints an id
v
CreatedTodo { id, title, at } durable: pure over the shared slicePut every nondeterministic input (ids, timestamps, the result of a provider
call) inside the fact. update for the fact only applies it.
When the intent needs nothing outside the Model, say an id from a counter in
the shared slice, return the fact as Sync.fact(message) instead of an
ordinary Command. The mount applies it in the intent's own transition, before
any later Message, so two intents dispatched together cannot read the same
counter. Outside the mount it is an ordinary Command.
A durable update should also be idempotent where a retry could deliver one
operation twice, as in CreatedTodo ignoring an id it already holds.