Architecture Decision Records
The load-bearing decisions behind InvariantDB — grouped, dated, and versioned. If a capability is on the product surface, there is an ADR under it explaining what we picked and what we ruled out.
What an ADR is. An Architecture Decision Record is a short, dated document that names one durable choice, the alternatives considered, the tradeoffs accepted, and the constraints it imposes on future work. Every non-trivial decision on the engine gets one before it lands.
Why we publish them. Three reasons. Transparency for evaluators — you can see, before you commit, exactly which correctness and durability promises the engine is willing to make and where the seams are. Reproducibility for enterprise procurement — the ADR set is the artifact your architecture review board asks for, without a redlined PDF cycle. Discoverability for security reviewers — every published error subcode, capability token flow, tenant boundary, and refusal envelope maps back to a numbered decision.
This index summarizes the ADRs that are customer-visible. Full ADR text — including alternatives considered, benchmark numbers, and internal migration paths — ships under mutual NDA with production customers. Ask us in hello@invariantdb.com.
On this page
Storage & durability
How rows land on disk, how history is preserved forever, how snapshots are made verifiable, and how the graph opens quickly after a crash.
Binary record format
Length-prefixed, versioned, checksum-verified rows. Every subsequent format bump keeps forward-compat with a single reader.
Write-ahead log frame format
Framed, sequence-numbered, fsynced before mutation is observable. Replay is idempotent under partial failure.
Sorted-string table format
The on-disk data-format contract: block layout, bloom filters, footer, integrity. Reader-compat rules for every future field.
Snapshot directory & lineage manifest
Immutable per-sequence snapshots. Every produced file is sha256-stamped in a lineage manifest; publish refuses on drift.
Node identity map
Monotonic integer identities, never renumbered. String-to-integer resolution is the boundary between the API and the engine.
Bitemporal history & audit chain
Every mutation is stamped with valid time and recorded time. History is append-only and hash-chained; drift is detectable.
Write-once, read-many mode & schema versioning
Per-graph WORM flag, refused at the engine layer. Schema evolves through numbered, diffable versions.
Snapshot witness for history
The published snapshot chain-anchors the history log. Restore refuses to advance past a witness that fails re-verification.
Backup & restore
Backups are self-describing archives with an integrity manifest. Restore is a two-phase apply: verify, then advance the pointer.
Provenance
Every property carries a subject, source, method, and confidence. Provenance is a first-class relation, not a stringly-typed metadata blob.
SSTable compression
Block-level compression contract, negotiable between reader and writer without touching the outer file format.
Covering indexes
Property indexes carry the value alongside the identity so common projections skip the row fetch entirely.
Cryptographic shredding
Per-subject wrapping keys. db.destroySubjectKey renders every encrypted property for that subject unrecoverable across every backup while the audit chain stays verifiable.
Vector property type
Embeddings are first-class typed properties. Dimensionality and model boundaries are enforced by the engine, not the caller.
Bitemporal label index
Label membership is indexed on both valid and recorded axes. MATCH (n:Label) AT VALID hits an index, not a scan.
Bitemporal property index
Property indexes are two-dimensional rectangles over valid time and recorded time, so both clauses hit an index simultaneously.
Snapshot working-set accounting
Per-graph memory pressure is accounted at snapshot granularity so working-set caps and eviction are honest and predictable.
Cypher & query engine
The surface every caller talks to. Grammar, procedures, planning discipline, and the temporal syntax that turns bitemporal correctness into a query verb.
Cypher parser
Public grammar and the compatibility rules for extending it. New syntax is additive; old queries always parse.
Cypher executor
Executor invariants: no fabrication on empty bindings, deterministic ordering rules, resource accounting per query.
MERGE and DETACH DELETE semantics
MERGE is atomic and idempotent. DETACH DELETE resolves neighborhood upstream so the write path is a flat sequence of atomic ops.
Execution warnings & strict mode
Every mismatched YIELD column, unresolved parameter, or shape drift surfaces as a typed warning; strict mode elevates them to refusal.
EXPLAIN / ANALYZE
Every query can be introspected before it runs. Cost estimates, index usage, and expected row counts are part of the public contract.
Empty-bindings conformance
An unmatched pattern returns zero rows. It never fabricates a row with nulls. This invariant is pinned by a dedicated regression suite.
Chunked execution for large mutations
Bulk mutations chunk transparently so a single request cannot pin the engine indefinitely or blow the per-query memory budget.
CALL-clause mutation contract
Procedures that mutate are marked as such in db.listProcedures(); read-only callers see them refused, not silently executed.
Temporal AT VALID / AT RECORDED rewrite
The bitemporal clauses attach to the MATCH pattern, not to a projection, so they compose cleanly with WHERE, WITH, and CALL.
Graph algorithm surface
Which algorithms live in the engine, which live as external tools, and what the shared traversal contract is.
Cosine similarity pushdown
Vector similarity filters push into the index instead of scanning-then-ranking, so hybrid queries stay bounded.
db.relabel as a bulk mutation
Atomic per-node relabel with a kwarg where filter and a summary YIELD; safer than manual DELETE+CREATE loops.
Virtual edge projection (declined)
We evaluated on-the-fly edge synthesis inside MATCH and declined it — the semantics collide with provenance and bitemporal validity.
Security & tenancy
How principals are authenticated, how per-graph isolation is enforced below the API, and how short-lived capability tokens ride on top.
HTTP API surface
The publicly documented endpoints, versioning rules, and the shape stability guarantee for request and response bodies.
Property-level provenance
Provenance is enforced at the query engine level so the same query returns different projections for different principals safely.
Field-level ACL
Access control runs inside the query engine, not the resolver. There is no bypass by picking a different endpoint or SDK.
Capability tokens
Short-lived, signed, scoped bearer tokens for read-after-write and cross-service delegation. Verification is stateless; signing keys rotate.
Multi-graph registry
How graphs are discovered, pinned, and evicted, and how a mis-tenanted request cannot leak identities across the registry.
Tenancy & API keys
Every request carries a tenant boundary. API keys are prefixed and scoped; verification happens once, at the edge.
Isolation & durability contract
Snapshot isolation for reads, linearizable writes, published durability guarantees for every acknowledged mutation.
Transitive CVE hygiene
Which dependencies we pin, which we mirror, and how we respond to advisories on the web PKI transitive graph.
Differential privacy
When aggregate queries carry a privacy budget, and how the engine tracks it across sessions without leaking through side channels.
Tenant admin role
A first-class admin scope inside the tenant boundary. Admin operations are gated separately from read and write.
Cloud & billing
The commercial and operational envelope around the hosted product: regions, editions, tenant self-service, and the endpoints that drive the dashboard.
Three-tier edition model
Free, Team, and Regulated tiers. Which capabilities are gated by tier, and the guarantee that raw data never crosses a downgrade.
Build-time feature gating
The engine ships in flavors. Feature gating is at compile time so a lower tier cannot exercise a higher-tier procedure even by accident.
Multi-tenant isolation in cloud
Per-tenant data path, per-tenant identity path, per-tenant billing path. No shared state on a hot code path.
Region topology
Which regions serve traffic, how data residency is enforced, and how failover moves capacity without crossing residency boundaries.
Feature-disabled visibility
A disabled capability returns a typed refusal that names the feature, not a 404. Callers can branch on subcode.
MCP server
The stable MCP tool surface, its authentication contract, and the guarantee that MCP calls transit exactly the same query engine as SDK calls.
Language bindings
SDK versioning across Python, TypeScript, Rust, and Go. Backwards-compat guarantees on the wire format.
Observability & stable contracts
Every meter you can graph, every error subcode you can branch on, every counter you can alert on. The public contract for what the engine will tell you about itself.
OpenTelemetry tracing
Every request is traceable. Span shape, attribute names, and cardinality bounds are published and versioned.
Structured error codes
Every error carries a subcode. Wire shape is stable across releases; adding an error never renumbers the existing ones.
Stable contracts & release notes
What "stable" means for endpoints, procedures, metrics, and error subcodes — and the release-notes discipline that keeps it honest.
Per-graph memory instrumentation
Working-set, delta layers, and cached indexes are metered per graph so noisy neighbors are visible before they are a problem.
Per-graph query bytes budget
Each query carries a bytes-scanned budget. Overshoot is a typed refusal, not a slow read that starves the pool.
Error envelope & db.listProcedures()
Nine additional error subcodes and a canonical procedure catalog. Discovering the surface no longer requires reading the source.
Reliability & incident response
The decisions we made after an incident so it does not repeat. Each of these has a hard test in the regression suite; the ADR itself explains what class it closes.
HA & DR drill
The scheduled disaster-recovery drill: what we simulate, how we score it, and the operator playbook the drill validates.
Stability incident response
The public discipline for stability incidents: how quickly a refusal envelope ships, how the audit chain is preserved during triage.
Snapshot orphan auto-clear
Partially-written snapshot directories are recognized and cleared on open. Never publish an unwitnessed snapshot.
Graph warming-up signal
Callers can distinguish "graph is warming up" from "graph does not exist" without polling. Warm-up is a typed status, not a timeout.
Deploy stability, shutdown, backfill
The full lifecycle contract: staged deploy, drained shutdown, backfill discipline for derived state after a version bump.
Deadline enforcement & query kill
Every query carries a deadline the executor honors. Deadlines close both the "runaway aggregation" and "hung poll" classes.
Pin recently-used graphs
Working-set LRU with a pin list, so the largest customer graphs stay warm across restarts and cannot be evicted by a boot storm.
Hot-reloadable execution policy
Deadlines, budgets, and refusal thresholds are hot-reloadable. An operator does not restart the engine to tune the envelope.
Engine-owned embedding pipeline
The embedder registry lives in-process. Model boundaries and dimension locks are enforced at write time; stale models cannot corrupt an index.
Proposed decisions
On our forward-looking desk: storage scaling for the next order of magnitude. These are draft ADRs open to review; they may land as-drafted, land amended, or be withdrawn.
Storage scaling roadmap
A three-piece composition covering the next tier of graph size: memory-mapped identity, log retention, and snapshot pruning. Sets a shared refusal envelope for all three sub-designs.
Identity map memory-mapped
Move the identity map to a memory-mapped, layer-swappable file so the largest graphs stay open under a stable process budget.
History log retention
A per-graph retention envelope for the history log with a published refusal subcode when a query reaches for a truncated range.
Snapshot chain pruning
Retain a bounded chain of snapshots while preserving the witness anchor. Restore semantics stay unchanged; long-cold references get a typed refusal.
Reading the full text. The full ADR corpus — including alternatives considered, benchmark numbers, migration plans, and the adversarial-review notes we used to sharpen each decision — ships under mutual NDA with production customers. If you are evaluating InvariantDB for a regulated workload, ask us for the pack at hello@invariantdb.com and we will send it inside a signed NDA within one business day.
How we work
A short statement of engineering discipline. Every ADR is written under it; every deploy is gated on it.
Adversarial review before landing
Every non-trivial ADR goes through an adversarial review pass before merge. The reviewer's job is to find the case that breaks it. The verdict is recorded in the ADR itself.
Feature-flagged rollouts
New capabilities land behind a flag, exercised in staging first, promoted per tier, and only then general. A flag can be turned off without a deploy.
Sha-verified deploys
Every production binary is content-hashed at build time and re-verified at deploy time. The previous binary is preserved for rollback. Refusal on hash drift is loud and blocking.
Refusal envelope, not silent workaround
When the engine cannot honor a request, the response is a typed refusal with a published subcode. Silent partial-success is a bug class we treat as production-severity.
Bitemporal by default
Every landed change respects the two-clock invariant. If a mutation is not stamped with valid and recorded times, it does not land.
Public contracts stay stable
Endpoints, procedures, metrics, and error subcodes are additive across releases. Renumbering, silent rename, and breaking wire changes are treated as customer-facing incidents.
This index tracks decisions relevant to callers and evaluators. If you need a specific ADR that is not linked here, ask — we probably have it and can share under NDA. For the operational side, see Operations and Cluster. For the underlying capability set, see Features.