Commands and transactions
How changes are guarded, staged, validated, committed, and published.
Every persistent command joins one outer transaction.
- Command guards inspect an immutable description.
- Writable roots and plugin slices are staged.
- The command and nested commands update the candidate.
- Core and plugin invariants validate the candidate.
- Commit projectors finalize history and plugin effects.
- Subscriptions publish.
- Public events publish.
Atomic transaction
A failed batch restores the previous roots and discards queued publications.
Try this Run the successful batch, reset, then run the duplicate-ID batch. The failed candidate never becomes observable.
Run an action to inspect its publication order.
Before
{}After
{}Relevant code
engine.batch(() => {\n engine.updateNode(card.id, patch)\n engine.createNode({ id: card.id, ...input }) // duplicate\n})\n// Throws. State and queued publications are restored.Run the failing batch. The first nested update is staged, but the duplicate ID rejects the candidate. State, plugin slices, queued events, subscriptions, and history remain unchanged.
Subscriber callbacks receive the value from before the outer command as prev, even when nested commands updated the same concept several times.