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 slice

Put 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.