Per-aggregate Merkle trees
Every aggregate maintains a Merkle tree built from event payload + metadata hashes. The current root is persisted alongside snapshots, giving you a single value to compare across nodes.Validation modes
- off: Allows events without a declared schema (still enforces basic constraints like snake_case names and payload size).
- default: Validates events against schemas when they exist but does not require a schema to be present.
- strict: Requires a schema for the aggregate before the first event can be appended; validation still runs when schemas exist.
EVENTDB_RESTRICT):
Checksums during replication
dbx push and dbx pull refuse to overwrite divergent history and verify Merkle roots during transfer:
- Push: Fails if the remote has more events for an aggregate. When the remote has some history, the local Merkle root at the remote’s version must match before any new events are appended.
- Pull: Fails if the local copy is ahead. Missing events are fetched, the expected Merkle root is recomputed locally, and the pull aborts if it doesn’t match the remote’s root.
--repair flag.
Inspecting and repairing drift
- To spot drift, script against
dbx aggregate list --jsonanddbx aggregate verify <type> <id> --jsonon each node, then diff Merkle roots. - When
dbx push/dbx pullreports a divergence, pick the authoritative domain, create a fresh domain on the out-of-date node (dbx checkout recovered --create), and re-sync from the trusted copy.