Sync / foldkit-durable
What append guarantees
For a new operation, inside one SQLite transaction:
decode → validate → authorize → assign sequence → stamp → reduce → persist op + snapshot + cursor → CommittedFor a retransmission, the stable opId is what matters:
same opId, same payload and actor answered from history, never applied twice
same opId, different payload or actor IdentityConflictErrorPayloads are canonicalized before hashing, so reordered JSON keys are the same operation. The guarantee lasts as long as the identity row does; see retention.
A commit stamp writes what only the commit decides into the operation:
type Edit = Operation & { readonly at?: number }
const stamping: Pick<JournalOptions<Edit, Snapshot, Principal>, 'stamp'> = {
stamp: (operation, { sequence }) => ({ ...operation, at: sequence }),
}It runs after validate and authorize, which see the operation as it was
sent, and before reduce. The stamped operation is what is stored, reduced,
read, loaded and handed to recover's intents, so every reader sees one
version of it. A retry is still recognized by what was sent: the payload hash is
of the operation as sent, so resending it is answered from history, while
resending the stamped form, or other data under the id, is an
IdentityConflictError. A stamp must keep the operation's opId; one that
changes it is an InvalidOperationError and commits nothing. Use it for a
fact a reader needs and a client cannot supply, such as the position a read
model compares with to know which commits it holds; Editing server data
through a journal is that case end to
end.
Read the results as three separate facts:
| You observe | It proves | It does not prove |
|---|---|---|
append returned Committed | the journal accepted and persisted it | any client has seen it |
load returned a snapshot and cursor | the snapshot is that committed prefix | pending client edits are in it |
| an effect result is recorded | the journal can reuse that outcome | the provider did not act before a crash |
append returns AlreadyCommitted instead of Committed when the operation
was committed before and compaction has since removed its payload: the journal
can prove the id committed without pretending to still have its content.
appendAll commits several in order in one transaction.
Snapshot writes are the expensive part of an append on a large document.
snapshotEvery: n writes one every n commits; load replays the few since.
The journal keeps each document's current state in memory (the most recent
256), checked against the stored cursor, so a commit or reset through another
connection is noticed. load hands out that remembered value, so treat it as
read-only, as reduce must.