Engineering transparency

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.

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.

ADR-0002

Binary record format

Length-prefixed, versioned, checksum-verified rows. Every subsequent format bump keeps forward-compat with a single reader.

Accepted
ADR-0003

Write-ahead log frame format

Framed, sequence-numbered, fsynced before mutation is observable. Replay is idempotent under partial failure.

Accepted
ADR-0004

Sorted-string table format

The on-disk data-format contract: block layout, bloom filters, footer, integrity. Reader-compat rules for every future field.

Accepted
ADR-0005

Snapshot directory & lineage manifest

Immutable per-sequence snapshots. Every produced file is sha256-stamped in a lineage manifest; publish refuses on drift.

Accepted
ADR-0006

Node identity map

Monotonic integer identities, never renumbered. String-to-integer resolution is the boundary between the API and the engine.

Accepted
ADR-0009

Bitemporal history & audit chain

Every mutation is stamped with valid time and recorded time. History is append-only and hash-chained; drift is detectable.

Accepted
ADR-0010

Write-once, read-many mode & schema versioning

Per-graph WORM flag, refused at the engine layer. Schema evolves through numbered, diffable versions.

Accepted
ADR-0013

Snapshot witness for history

The published snapshot chain-anchors the history log. Restore refuses to advance past a witness that fails re-verification.

Accepted
ADR-0020

Backup & restore

Backups are self-describing archives with an integrity manifest. Restore is a two-phase apply: verify, then advance the pointer.

Accepted
ADR-0029

Provenance

Every property carries a subject, source, method, and confidence. Provenance is a first-class relation, not a stringly-typed metadata blob.

Accepted
ADR-0034

SSTable compression

Block-level compression contract, negotiable between reader and writer without touching the outer file format.

Accepted
ADR-0035

Covering indexes

Property indexes carry the value alongside the identity so common projections skip the row fetch entirely.

Accepted
ADR-0057

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.

Accepted
ADR-0058

Vector property type

Embeddings are first-class typed properties. Dimensionality and model boundaries are enforced by the engine, not the caller.

Accepted
ADR-0080

Bitemporal label index

Label membership is indexed on both valid and recorded axes. MATCH (n:Label) AT VALID hits an index, not a scan.

Accepted
ADR-0100

Bitemporal property index

Property indexes are two-dimensional rectangles over valid time and recorded time, so both clauses hit an index simultaneously.

Accepted
ADR-0105

Snapshot working-set accounting

Per-graph memory pressure is accounted at snapshot granularity so working-set caps and eviction are honest and predictable.

Accepted

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.

ADR-0015

Cypher parser

Public grammar and the compatibility rules for extending it. New syntax is additive; old queries always parse.

Accepted
ADR-0016

Cypher executor

Executor invariants: no fabrication on empty bindings, deterministic ordering rules, resource accounting per query.

Accepted
ADR-0011

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.

Accepted
ADR-0056

Execution warnings & strict mode

Every mismatched YIELD column, unresolved parameter, or shape drift surfaces as a typed warning; strict mode elevates them to refusal.

Accepted
ADR-0068

EXPLAIN / ANALYZE

Every query can be introspected before it runs. Cost estimates, index usage, and expected row counts are part of the public contract.

Accepted
ADR-0074

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.

Accepted
ADR-0091

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.

Accepted
ADR-0102

CALL-clause mutation contract

Procedures that mutate are marked as such in db.listProcedures(); read-only callers see them refused, not silently executed.

Accepted
ADR-0104

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.

Accepted
ADR-0028

Graph algorithm surface

Which algorithms live in the engine, which live as external tools, and what the shared traversal contract is.

Accepted
ADR-0059

Cosine similarity pushdown

Vector similarity filters push into the index instead of scanning-then-ranking, so hybrid queries stay bounded.

Accepted
ADR-0110

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.

Accepted
ADR-0114

Virtual edge projection (declined)

We evaluated on-the-fly edge synthesis inside MATCH and declined it — the semantics collide with provenance and bitemporal validity.

Declined

Security & tenancy

How principals are authenticated, how per-graph isolation is enforced below the API, and how short-lived capability tokens ride on top.

ADR-0018

HTTP API surface

The publicly documented endpoints, versioning rules, and the shape stability guarantee for request and response bodies.

Accepted
ADR-0060

Property-level provenance

Provenance is enforced at the query engine level so the same query returns different projections for different principals safely.

Accepted
ADR-0061

Field-level ACL

Access control runs inside the query engine, not the resolver. There is no bypass by picking a different endpoint or SDK.

Accepted
ADR-0063

Capability tokens

Short-lived, signed, scoped bearer tokens for read-after-write and cross-service delegation. Verification is stateless; signing keys rotate.

Accepted
ADR-0064

Multi-graph registry

How graphs are discovered, pinned, and evicted, and how a mis-tenanted request cannot leak identities across the registry.

Accepted
ADR-0066

Tenancy & API keys

Every request carries a tenant boundary. API keys are prefixed and scoped; verification happens once, at the edge.

Accepted
ADR-0067

Isolation & durability contract

Snapshot isolation for reads, linearizable writes, published durability guarantees for every acknowledged mutation.

Accepted
ADR-0071

Transitive CVE hygiene

Which dependencies we pin, which we mirror, and how we respond to advisories on the web PKI transitive graph.

Accepted
ADR-0072

Differential privacy

When aggregate queries carry a privacy budget, and how the engine tracks it across sessions without leaking through side channels.

Accepted
ADR-0101

Tenant admin role

A first-class admin scope inside the tenant boundary. Admin operations are gated separately from read and write.

Accepted

Cloud & billing

The commercial and operational envelope around the hosted product: regions, editions, tenant self-service, and the endpoints that drive the dashboard.

ADR-0076

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.

Accepted
ADR-0077

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.

Accepted
ADR-0078

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.

Accepted
ADR-0079

Region topology

Which regions serve traffic, how data residency is enforced, and how failover moves capacity without crossing residency boundaries.

Accepted
ADR-0115

Feature-disabled visibility

A disabled capability returns a typed refusal that names the feature, not a 404. Callers can branch on subcode.

Accepted
ADR-0019

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.

Accepted
ADR-0051

Language bindings

SDK versioning across Python, TypeScript, Rust, and Go. Backwards-compat guarantees on the wire format.

Accepted

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.

ADR-0069

OpenTelemetry tracing

Every request is traceable. Span shape, attribute names, and cardinality bounds are published and versioned.

Accepted
ADR-0073

Structured error codes

Every error carries a subcode. Wire shape is stable across releases; adding an error never renumbers the existing ones.

Accepted
ADR-0075

Stable contracts & release notes

What "stable" means for endpoints, procedures, metrics, and error subcodes — and the release-notes discipline that keeps it honest.

Accepted
ADR-0093

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.

Accepted
ADR-0108

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.

Accepted
ADR-0109

Error envelope & db.listProcedures()

Nine additional error subcodes and a canonical procedure catalog. Discovering the surface no longer requires reading the source.

Accepted

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.

ADR-0070

HA & DR drill

The scheduled disaster-recovery drill: what we simulate, how we score it, and the operator playbook the drill validates.

Accepted
ADR-0082

Stability incident response

The public discipline for stability incidents: how quickly a refusal envelope ships, how the audit chain is preserved during triage.

Accepted
ADR-0084

Snapshot orphan auto-clear

Partially-written snapshot directories are recognized and cleared on open. Never publish an unwitnessed snapshot.

Accepted
ADR-0086

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.

Accepted
ADR-0088

Deploy stability, shutdown, backfill

The full lifecycle contract: staged deploy, drained shutdown, backfill discipline for derived state after a version bump.

Accepted
ADR-0090

Deadline enforcement & query kill

Every query carries a deadline the executor honors. Deadlines close both the "runaway aggregation" and "hung poll" classes.

Accepted
ADR-0096

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.

Accepted
ADR-0098

Hot-reloadable execution policy

Deadlines, budgets, and refusal thresholds are hot-reloadable. An operator does not restart the engine to tune the envelope.

Accepted
ADR-0106

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.

Accepted

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.

Proposed

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.

Proposed
Proposed

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.

Proposed
Proposed

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.

Proposed
Proposed

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.

Proposed

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.