Skip to main content
Integrity comes from a combination of deterministic storage, cryptographic proofs, and operational guardrails. EventDBX makes drift obvious so you can repair it before it becomes a customer-facing issue.

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.
dbx aggregate verify person p-110 --json
# {
#   "aggregate_type": "person",
#   "aggregate_id": "p-110",
#   "merkle_root": "92e2b1..."
# }
Compare two domains by checking each one’s active checkout:
dbx checkout primary
dbx aggregate verify person p-110 --json > primary.json

dbx checkout standby
dbx aggregate verify person p-110 --json > standby.json

diff primary.json standby.json
Any divergence signals tampering or replication lag.

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.
Set the mode when starting the daemon (or via EVENTDB_RESTRICT):
dbx start --restrict strict     # enforce schemas before writes
dbx start --restrict default    # allow undeclared aggregates, validate when schemas exist
dbx start --restrict off        # most permissive
Changes take effect on restart; there is no per-aggregate override.

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.
If verification fails, the command aborts and leaves the target untouched; there is no --repair flag.

Inspecting and repairing drift

  • To spot drift, script against dbx aggregate list --json and dbx aggregate verify <type> <id> --json on each node, then diff Merkle roots.
  • When dbx push/dbx pull reports 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.
Because EventDBX stores the entire history, you never lose the data needed to rebuild a consistent state.