Every database stores what. NEDB also stores when, when it was true, and why — as queryable, indexed primitives, sealed in the same hash chain as the data itself.
Two time axes
Transaction time — AS OF <seq> — answers "what did the system
know at sequence N?" The engine never garbage-collects versions, so every past state is
reachable forever (unless an operator explicitly runs compact(), which announces
that it is trading history for space).
Valid time — VALID AS OF "<date>" — answers "what was true in the
world on that date?" A row can carry valid_from/valid_to independent of
when it was written, which is bi-temporality: the two axes compose.
# What did the system know at seq 200 about what was true on 2024-02-15?
db.query('FROM policy AS OF 200 VALID AS OF "2024-02-15"')
Causal provenance
A write may carry caused_by — a list of parent writes — plus
evidence and confidence. This is not a comment field: it is an indexed
edge in the DAG. TRACE caused_by walks ancestors (why did this happen?);
TRACE caused_by REVERSE walks descendants (what did this cause?).
db.put("inputs", "msg_1", {"text": "user prefers dark mode"})
seq_msg = db.seq
db.put("beliefs", "dark_mode", {"value": True},
caused_by=[seq_msg], evidence="user_message", confidence=0.95)
db.query('FROM beliefs WHERE _id = "dark_mode" TRACE caused_by') # → msg_1
db.query('FROM inputs WHERE _id = "msg_1" TRACE caused_by REVERSE') # → dark_mode
caused_by goes at the
top level of a put request, not nested inside the document. A caused_by inside the document
is stored as ordinary user data and creates no edge. Stored rows expose the edge as
_caused_by.The three commitments
| Commitment | Answers | Where |
|---|---|---|
Merkle head (head) | "did this database's history change?" — chains every write by seq and object hash | returned on every response |
| State root | "do two databases say the same thing right now?" — computable from live state alone, equal for equal state regardless of route | docs/state-root-v1.md, test vectors in vectors/ |
| Merkle proofs | "prove this row existed at this time" — verifiable locally, without the server | proof() / verify_proof() |
Keeping head and state root separate is deliberate: a root that folded in history could not compare two replicas that arrived by different routes — and that comparison (replica agreement, drift detection, anchoring) is most of what a root is for. One subtlety the spec pins: with encryption on, a node's hash is a function of its ciphertext (a fresh AES-GCM nonce per write), so state-root leaves commit to logical content, never object hashes.
Provenance in SQL
The metadata is selectable like any column, and settable from SQL — the causal chain does not require the HTTP API or the Python client:
SELECT _id, _hash, _seq FROM audit ORDER BY _seq;
INSERT INTO audit (_id, _caused_by, kind) VALUES ('leaf', '<parent-hash>', 'reprice');
SELECT _id FROM audit TRACE caused_by;
What tamper-evidence actually means
verify() recomputes the chain (~21,000 BLAKE2b/sec; 30k objects in 1.38 s in the
dated benchmark). Content tampering is never masked — the self-healing pass repairs
structural gaps only, and a tampered log verifies false. A durable store answers "not
available at that sequence" for pruned history rather than returning a stale value.
tools/build_docs_site.py.