Skip to content11. Determinism and guarantees
- Read-only. A user query never writes the graph. Nothing it materializes outlives the run,
projected nodes and relationships it creates included (§2, §7.9); the sole persisted side effect is a write-through identity bridge (a
cache of who an external identity is, not what data they hold). The single, explicitly
opted-in exception is the dedicated annotation-write surface (§12) — ordinary queries remain
read-only and continue to reject mutating clauses on stored or fetched data.
- Scoped, fail-closed. Every keyed probe goes through the world/context scope rewriter; vector
searches are filtered by world, context, and access-policy revision at the source. A query can
never read another context without an explicit authorized bridge, and never another PRINCIPAL’s
data; between two worlds of one principal the boundary is focus rather than confidentiality
(§15). Deployment-approved, revisioned
Public/reference datasets are the explicit exception. An
unparseable or unscopable query is rejected, not run — and what the ENGINE writes is never the
reason it is: a probe binds only positions it can scope, and drops the rest (§2). Which positions
a statement must label for it to be scopable is §15.5, the same in either spelling of a subquery.
- Bounded. Every fetch is bounded by a bound anchor,
maxAnchors/maxFanoutTotal, paging
caps, k, and rate budgets. Truncation is reported.
- One answer whichever engine holds the graph. A deployment may keep the graph in Neo4j or in
the appliance’s own in-process engine, and a query answers the same on both: the same values,
nulls and conversions, the same column names, the same refusals by type. A statement that fails
changes nothing on either. A difference between the two is a defect in the engine that differs,
not a dialect for queries to allow for.
- Idempotent re-runs. A re-run re-fetches; caching (
ttl/immutable) makes repeated runs of the
same query agree, including on any LLM-derived value — repeatability is a correctness property, not
just a speed one. Without a cache, an LLM-derived value may differ between runs.
- A refusal is stable, and it is actionable. A refused statement, re-issued unchanged, is
refused again with the same text; every refusal names what was counted, the size and the limit it
passed, and a lever that changes the outcome; and a figure that is only a floor says so. §9
states the contract in full, because a caller rewriting a query has nothing else to go on.