Skip to content

Query Lifetimes and Determinism ​

What lives for how long, and why the same inputs always produce the same answer. The lifetime classes below come straight from the ratified state-lifetime rows in tests/architecture-health/ARH1/products/dependency-contracts.json; the deterministic-ordering obligations come from the semantic determinism matrix and the scheduler contracts.

Lifetime classes ​

Five lifetimes appear across the hotspots. Knowing which one a piece of state has tells you when it may change and who may observe it:

LifetimeMeaningExamples
sessionlives as long as the host/sessionScheduler.nodes, Scheduler.dag, the SemanticGraphStore memo
snapshot-epochMVCC epoch; readers capture an O(1) view and never see it moveScheduler.source_root (crates/verter_scheduler/src/source_root.rs)
content-versionre-planned once per file content versionFunctionFlowGraph, FlowSliceIR, stable keys (crates/verter_type_engine/src/semantic_query/stable_key.rs)
dispatch-transactiontransient per-obligation-root cold-compute frameCheckerDispatchTransaction (crates/verter_type_engine/src/project_semantic_dispatch/dispatch_txn.rs)
requestexists for one query/request only, never cachedparse-snapshot leases, admission budget outcomes, cancellation tokens, scoped cache flights

Two rules follow. First: request-lifetime state is never a cache entry — a scoped cache flight or a cancelled compute frame publishes nothing. Second: content-version identity is what lets an unrelated edit preserve a narrow slice hash while still producing a distinct graph artifact key; never key a content-version artifact by request identity.

The memo: identity is semantic meaning ​

crates/verter_type_engine/src/semantic_query.rs defines the query envelope (SemanticQueryKey and friends); the host-owned memo is the SemanticGraphStore in crates/verter_type_engine/src/semantic_query_memo/mod.rs, dispatched through ProjectSemanticDispatch. Its founding rule: memo identity is semantic meaning, not request identity. Two different callers asking the same question share one entry; the same caller asking after an edit gets a different answer because the key's content-free identity is pinned by a versioned value inside the entry, not by who asked.

Cache admission is decided in exactly one place — crates/verter_type_engine/src/semantic_query/admit.rs (admit_decision) — and is typed: Unknown, budget-exhausted, cancelled and superseded results route through ReturnOnly, which never publishes an entry, never registers reverse-index metadata, and never becomes a persistent artifact. A partial result is a truthful partial (ResultCompleteness, PartialReasonSet), not a cacheable approximation.

Scheduler: generations fence everything ​

The scheduler (crates/verter_scheduler/src/scheduler.rs) keeps per-file FileNode state with atomic generation counters. A generation bump makes the prior source immediately unreachable: stale snapshots are invisible by construction (current_analysis() returns nothing when the generation does not match), and the per-canonical retirement floor only ever advances — everything below it can never be admitted again. Batch admission is atomic: submit_batch_atomic lands one batch submission the driver drains under a single DAG lock acquisition (generation bumps and supersede sweeps for every request in one critical section), so observers can never see a half-admitted batch. Source snapshot publication and Source-stage readiness are distinct — a request arriving in that window joins the still-live Source identity instead of forcing an early stage.

If you drive the scheduler in a test, use the cooperative/test seams the crate itself ships; the test_-prefixed hooks are recorded test-only seams under ratified narrowing (see the architecture contracts page), not a supported API.

Determinism ​

Determinism is enforced on two bases at once — see crates/verter_session/tests/cases/g_block/semantic_determinism_matrix.rs:

  1. The completed observation rendered to stable text (kinds, names, literal values, structural order) — never node ids, pointers or allocation ordinals.
  2. The digest of the generated bytes themselves.

A schedule-dependent answer cannot hide behind an unstable print, and a fixed observation cannot hide drifting bytes. In practice this means:

  • Union and intersection normalization produce a deterministic order (not input order); relation results publish only decided outcomes.
  • Admission, dedup, generation supersession and capacity accounting all flow through the one readiness authority (dag.rs), so wakeup order does not affect results.
  • Docs/tooling receipts follow the same discipline: the reference harness canonicalizes its receipt (sorted pages, links, errors) and requires a perturbed discovery order to yield an identical canonical receipt.

When you add a query or a cache, add the discriminating determinism twin: same inputs, perturbed order, byte-identical canonical result. "It passed once" is not determinism evidence.

Released under the MIT License.