> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eventdbx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Integrity

> Guarantee append-only behavior and verifiable state across replicas.

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.

```bash theme={null}
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:

```bash theme={null}
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`):

```bash theme={null}
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.
