scope: l0_only) or also consumed runtime topology facts (scope: runtime_dependent).
Phase 1: Validation
Validation checks that your model is structurally coherent before any proof attempt. It resolves every reference, confirms that all declared IDs exist, checks that field paths resolve against their schemas, verifies program termination, and confirms that every artifact a step consumes is definitely available on every incoming path. Validation errors are printed to stderr, each with a subject ID and a message explaining the structural problem. Common causes include broken cross-references, program paths that never reach a terminal (return or complete), and artifacts consumed before they are established on every incoming path.
Phase 2: Verification
Once a model is structurally valid, the verification engine analyzes each declared requirement and produces a verdict. Verification proceeds across five families:Idempotency
Proves that repeated attempts at the same logical invocation produce no externally distinguishable duplicate work. Analyzed per admitted path across three legs: state, effect, and control. The effect leg follows the cascade through publications, requests, external effects, and outbox writes. An outbox boundary does not terminate the causal graph.
Result Replay
Proves that repeated attempts return the same result variant and a replay-equivalent payload, for requirements that declare
result: replay_consistent.Serialization
Proves that same-key invocations of an operation never overlap. Evidence comes from routing, single-owner member assignment, and
ExecutionPool.member_concurrency = bounded(1).Ordering
Proves that same-key invocations execute in their semantic precedence order. Requires both a precedence source and a mechanism that preserves it.
Recoverability
Proves that an interrupted invocation can be resumed and driven to a terminal (
return or complete). A progress obligation, distinct from idempotency.How Each Family Is Proved
Idempotency: greatest-fixpoint (coinductive) analysis
Idempotency analysis evaluates every admitted program path (each path ending atcomplete or at a return for the triggering input) under the governing key’s population. Three legs must hold on every admitted path:
- State leg: Every transaction step must be retry-safe, either through a
deduplicated_bykeyed commit or through natural replayability derived from deterministic provenance. - Effect leg: Every effect-executing step must be duplicate-safe. A publication is safe when the topic (or outbox) carries a keyed message identity for the published schema and every modeled consumer proves idempotency for that input. A request effect is safe when the target operation proves idempotency keyed from the targeted input. An external effect is safe when it declares
deduplicated_byover a replay-stable key. An outbox write is safe when its containing transaction suppresses a second commit, or when every modeled consumer of the outbox collapses duplicate deliveries. The cascade continues through every outbox input admitting the written schema: an outbox boundary does not terminate the causal graph. - Control leg: Every decision on the path must replay. The branch condition must be deterministic over replay-stable roots, or the matched result must be replay-stable.
at_most_once delivery whose payload is identity-pinned by the key.
Serialization
Serialization (same-key invocations must not overlap) is proven from one of four routes:- Vacuous population: The key’s message-driven input admits no message schemas, so the constrained population is empty by declaration. This is the only
l0_onlyroute. - Request-routed: A
Routerserves the key’s request boundary, every component of its semantic routing key carries the same logical value as the requirement key, itsMemberAssignmentgives that domain one active owning member (including through handoff), and the target pool declaresmember_concurrency = bounded(1). - Subscription-routed: The same argument on the delivery side, with
key: grouping_keynaming the effective grouping domain and the requirement key established to carry the grouping key for every admitted schema. - Outbox-routed: The same argument over an outbox input’s keyed partitioning. Every partition-key component carries the requirement key for every admitted schema, the dispatch’s
MemberAssignmentgives each partition one active owning member, the pool is serial, and the dispatch declares no batching stage. A declared batching stage stops the route: batch-internal overlap is intentionally unmodeled, andmember_concurrencymust not be silently read as a fact about it.
Ordering
Ordering requires serialization plus a proven semantic precedence. The V1 engine recognizes two precedence sources:- Transport ordering (
within_grouporglobal) for a subscription-triggered key. - Outbox runtime ordering (
partitionorglobal) for an outbox-triggered key.
key: grouping_key routes by that same domain, MemberAssignment gives it one active owning member, and member_concurrency = bounded(1) stops a later invocation overtaking an earlier one.
For the outbox route, a declared batching stage is judged explicitly. Absent batching, there is no obstacle. batching.ordering: preserved lets the established precedence pass through the stage. batching.ordering: unspecified stops the proof, because the stage then provides no evidence the order survives execution. Order preservation is an ordering fact only: it is never read as a no-overlap guarantee, which is why the serialization route refuses batching outright while the ordering route accepts preserved.
Recoverability
Recoverability analysis asks whether a resumed invocation can reach a terminal for every admitted path. It checks that every transaction on a path resolves on re-encounter (by keyed commit recovery or natural replay) and that every artifact the path consumes (effect intents, transaction outputs) is available on resumption via the same two routes. Unlike idempotency, decisions are never obstacles: a retry may take any admitted path, and each path is analyzed independently.completion: resumable requires that resumption be possible. completion: guaranteed additionally requires a modeled retry driver: delivery: at_least_once on the triggering subscription’s runtime or outbox input’s runtime (L1 facts, so the proof is runtime_dependent), or an inbound RequestEffect whose retry is may_repeat (an L0 guarantee, so the proof stays l0_only).
What happens when L1 is removed
Deleting theruntime block from a valid model leaves it valid. Requirements discharged from runtime facts become unproven — never violated, and never a structural error. That asymmetry is the point of the layering: L0 stands alone, and L1 is what a particular realization adds. Every proof records its scope so you can identify which obligations would revert to unproven when runtime declarations change.
Verdicts are epistemic
Every verdict is an epistemic statement about declared facts, not an observation of runtime behavior:provenmeans the declared facts are sufficient to establish the property. The proof is conditional on the implementation conforming to those declarations. The proof’s scope (l0_onlyorruntime_dependent) records which semantic layers were consumed.unknownmeans the declared facts are insufficient to prove or disprove the property. It is not evidence of a violation.disprovenmeans a counterexample exists within the declared model.