contract assurance · 80-formal.md · 81-engineering.md · 82-consumer.md · 83-gate.md · guide · card
The formal model
Two Lean 4 packages stand beside the engine: one specifying the policy core, and one holding an executable state machine of the store’s lease, compare-and-swap and fence protocol, its invariants stated as theorems. The nightly formal stage checks both, and one differential harness ties each model to the code it describes: the policy model to both builds of the decision module, the protocol model to the store’s two lease paths.
The two models, the checks over them, and where each meets the engine:
model
The Lean policy package and the Lean protocol state machine, their pins, and the definitions theorems and checks range over.
packagetestThe policy model is a Lean package rooted atformal/:lakefile.tomldeclares onelean_libtarget and norequirestanza, andlean-toolchainnames one exact release string.declared-dependencytestArequirestanza in the policy package’slakefile.tomlreaching any external library raisesFormalPackageDependency, naming the library.toolchain-drifttestA build whose resolved toolchain string differs from the pinned one raisesProofToolchainDrift, printing both strings.build-costtestA cold elaboration of the package completes within 60 s and writes at most 2048 KiB of artifacts.Why
because the nightly formal stage elaborates it cold on every runbuild-commandtestlake buildat the package root elaborates every declaration and writes the environment the audit reads.module-layouttestFive modules carry the package — the layer algebra, placement with the floor, the authority mapping, connector host containment and statement execution — and the library root re-exports all five.layeritemA layer is a total function from a row identifier toBool;composedfolds a list of layers by conjunction, admitting a row when every member admits it.flooritemAn allow-set is a decidable predicate over a placement value;floorintersects a list of allow-sets pointwise, andfloor []admits every caller as the unit of that fold.placement-inductiveitemThe declared placement is an inductive type carrying its identifier inside the constructor, with one case per category the manifest admits and one case for an absent declaration.unmodelled-constructortestA category the manifest admits with no case in the placement inductive raisesUnmodelledConstructorat elaboration, naming the category.total-definitionstestEvery definition is total and computable: none is markedpartial,noncomputableoropaque, and decidable equality on each finite enumeration is derived.from-the-spectestEach definition is written from the specification text and derived from no engine source.Why
because a definition copied from code makes every theorem restate the code instead of checking the specificationout-of-modeltestThe policy package defines no credential bytes, signature verification, SQL semantics, journal write, process state or attacker observation, and no theorem reaches one.protocol-packagetestThe protocol model is a second Lean 4 package rooted atformal/protocol/, beside the policy package, pinned to the samelean-toolchainstring, with onelean_libtarget, onelean_exetarget and norequirestanza.protocol-modelitemThe protocol model is a total, computable step function over two lease paths, the compaction lease guarding a table pointer and the run lease guarding a commit log: grant, raise, renewal, expiry, release, fenced commit, pause, message delay and crash.protocol-safetytheoremFive invariants are Lean theorems over every reachable state of both paths: one lease holder per fence, fences only increase, no commit after a successor’s acquisition, no lost update, and release keeps the lease object and its fence.protocol-theoremstestEach protocol invariant theorem is a required constant in the protocol package’s inventory, audited bycheck-commandagainst the same allowlist.protocol-checktestThe gate evaluates every invariant on each state reached by every step sequence over three nodes and four lease generations; a breaking state raisesProtocolInvariantViolated, printing the shortest sequence reaching it.Why
P7protocol-pinsteststale-fenceandpointer-fencepin to the protocol model’s invariant theoremno_commit_after_successor_acquire.Why
because the model’s guarded objects are the table pointer and the commit log; the catalog cursor row and a snapshot’s sidecars lie outside itjournal-modeltestThe journal model is a total, computable step function over three callers and two keys; each journal-store and blob-store port call, effect, lapse, crash, sweep and retirement is one step.journal-safetytestSeven journal properties are Lean theorems over every reachable state: recorded values stay, journaled resolutions agree, one record per key, effects under a claim or lapsed lease, takeover from a lapsed holder, no dangling blob, nomissing-blob.journal-gracetestno_dangling_blobassumes an aged sweep spares a blob between its put and its record;protocol journal check --no-graceprints the shortest sequence reachingmissing-blob.journal-checktestprotocol journal checkevaluates every journal property on each state three callers reach on one key; a breaking state raisesJournalInvariantViolated, printing the shortest sequence reaching it.Why
P7merge-modeltestThe merge model decides each key from its local entry, remote entry, remote tombstone, held flag and verification flag; one differing commit-log copy refuses the whole merge.merge-theoremstestSix merge properties are Lean theorems over every input: the scoped union, a foreign or unverified tombstone keeping its entry, only live tombstones listed, the commit-log refusal, and one writer’s convergence at a fixednow.fold-modeltestThe fold model is a total, computable step function over two passes staging, committing and dying, lease acquisition, collection and two readers; a pass commits only while its fence is the highest granted.fold-theoremstestSix fold properties are Lean theorems: commits conditioned on the version read, lost commits publishing nothing, collection sparing reachable and in-flight directories, supersession without deletion, readers’ snapshots present, and lease-ordered fences.
prove
The theorem inventory: layer composition, placement, the evidence floor, the proof targets over the authority mapping, and the mediation relation over statement execution.
composition-soundtheoremcomposed_sound: a row the fold over a list admits is admitted by every member of that list.narrowingtheoremcomposed_narrows: a row admitted byl :: lsis admitted byls.Why
because appending a layer then removes rows and adds noneorder-is-specifiedtheoremThe composition theorem ranges over the single orderrelation-orderfixes, and filtering then masking is a different relation from masking then filtering.commutation-claimtestA claim that the enforcement stages commute raisesCommutationClaimed.placement-is-a-layertheoremzone_layer_sound: with the placement check as one more list member, a row the whole list admits was admitted by that check, with no bridging hypothesis.floor-no-downgradetheoremfloor_no_downgrade: a floor admitting a caller forces every member of its evidence list to admit that caller.fail-closedtheoremAn evidence list holding one fail-closed member yields a floor admitting no public-cloud caller, and the fail-closed allow-set rejects both cloud categories.evidence-nonemptytestfloor_no_downgrade’s negative space names a non-empty evidence list, whichempty-evidenceholds at the engine.symbolic-inclusiontheoremZone inclusion is decided by subsumption over patterns, quantified over every constructor and every identifier, the named provider and the undeclared case included.subsumption-exacttheoremPer-entry subsumption decides zone inclusion exactly, a bare category subsuming every identifier under it, so no normal form on allow-sets precedes the decision.sampled-inclusiontesttheoremInclusion decided by evaluating a fixed set of example values raisesZoneInclusionSampled.effective-policytheoremAn effective policy computed from two allow-sets is included in both.proof-targetstesttheoremThe authority mapping ofdelegation-profilecarries four proof targets: inclusion; narrowing, where an attenuated child’s permission implies its parent’s; profile meaning, where permission holds exactly when the audience matches and every block admits; andrestriction-preservation.Why
because all four are pure decision functions over a verified credential; the mediation relation covers read-path releases, and the rest of scoped-session execution stays unprovedrestriction-preservationtesttheoremattenuateAll_permits_every_parent_block: every block of a credential admits each request that any chain of attenuations of that credential permits, under one trusted environment.mediation-relationtesttheoremstatement_reach_released_rows_pass_session_layers: the mediation induction ranges over the read path’s statement execution, and every row a reachable state has released passed every layer of the session.target-bindingtestA proof target is bound to one authenticated query path, recorded beside it as a module path and a test, before the claim names it.unbound-targettestA target the claim names with no binding raisesProofTargetUnbound, naming the target.negative-spacetestBeside each theorem, its negative space states what it leaves open: that the required members were in the list, that a member removes rather than tests, and that execution reaches the fold before an effect.no-negative-spacetestA theorem published without its negative space raisesTheoremWithoutNegativeSpace, naming the constant.mediation-from-compositiontestA filter-composition theorem offered as a mediation theorem raisesMediationClaimedFromComposition.Why
because mediation quantifies over the reachable states of an execution; composition quantifies over a listnames-carry-reachtestA constant’s name states the object it ranges over, not the property a reader hopes for.
audit-assumptions
The assumption allowlist, the transitive footprint audit over the elaborated environment, the inventory and the report.
assumptiontestAn assumption is a declaration the Lean kernel accepts without proof: the set#print axiomsreports for a constant, which the audit reads throughcollectAxioms.allowlisttestThe assumption allowlist holds 2 entries,propextandQuot.sound, and every theorem’s footprint is a subset of it.Why
because no required constant draws onClassical.choicetransitive-audittestEach required constant’s assumption footprint is read transitively off the elaborated environment, naming every assumption reached.verdict-inputtestA verdict is a function of the elaborated environment and the inventory alone; source text, declaration counts and the build’s exit status decide nothing.Why
because elaboration reports a hole as a warning and exits zero, and a character pattern misses a hole spelled in parenthesesassumption-outside-allowlisttestAn assumption in a footprint and absent from the allowlist raisesAssumptionOutsideAllowlist, printing the constant and the assumption.hole-assumptiontestA footprint containing the hole assumption raisesProofHoleAssumption, naming the declaration, whatever its syntax spells.native-evaluation-assumptiontestA footprint containing a per-declaration native-evaluation assumption raisesNativeEvaluationAssumption, naming the declaration that minted it.inventorytestformal/inventory.tomlholds one row per required constant — name, module, expected statement text, admitted assumptions, binding, negative space — edited apart from the declarations satisfying it.missing-constanttestA required constant absent from the elaborated environment raisesTheoremConstantMissing.statement-drifttestA required constant whose elaborated statement differs from its expected text raisesTheoremStatementDrift, printing both.inventory-changetestA change to a required statement lands in the commit carrying the proof it admits.allowlist-admissiontestAn assumption joins the allowlist through anA-assurancesection naming it, and each inventory row admitting it cites that section in arecordfield.reporttestThe report names the commit, the resolved toolchain, the allowlist and inventory revision applied, and for each required constant its statement match and the assumptions it reaches.check-commandtestcontextful formal checkelaborates the package, matches every inventory row, audits every footprint, writes the report, and exits non-zero naming the first failing constant.
recheck
Rebuilding and re-auditing from pinned source in a credential-free environment.
two-phasetestA recheck rebuilds the package from the commit’s own source and pinned toolchain into an empty artifact directory, fetching nothing, and re-runs the audit against the rebuilt environment.credential-freetestA recheck environment exposing a token, a signing key or a registry login raisesRecheckEnvironmentCredentialed, naming the variable or file carrying it.report-mismatchtestA recheck whose per-constant statement text or assumption set differs from the first phase’s raisesRecheckReportMismatch, naming the constant.Why
because.oleanoutput is not byte-reproducible across hosts and paths, while the per-constant report is the fact under checkwall-timetestA recheck completes within 600 s.
scope-claim
The sentence the assurance claim is allowed to be: named decisions, named specifications and trusted dependencies.
claim-sentencetestThe assurance claim reads: these named decisions satisfy these named Lean specifications under these stated runtime assumptions; each list resolves to code paths, constants and components in the tree.beyond-named-decisionstestA claim that the enforcement engine, or any object wider than the named decisions, is verified raisesClaimBeyondNamedDecisions.trusted-dependenciestestThe claim names the delegation library, its cryptography and its parser as trusted dependencies, and proves none of them.unnamed-dependencytestA claim resting on a component absent from its trusted-dependency list raisesTrustedDependencyUnnamed, naming the component.
unsettled: Which translator, external models and refinement scope does a claim name once a theorem reaches the Rust decision functions through translated code? owner: build affects: assurance.scope-claim
differential-test
The executable reference models, the case generators, the minimized counterexample corpus and the command running them.
reference-modeltestThe reference model is the policy package’s proved decision definitions, compiled with JSON case decoding and decision rendering into a binary that reads one case on standard input and prints one decision.reference-theoremstestEach theorem the reference package proves over a decision it executes is a required constant in its inventory, audited bycheck-commandand bound to the differential test running that decision.Why
because a theorem pin performs only beside a differential that drives the code its clause namesreference-vocabularytestBefore any case, the harness reads the reference binary’s operation listing; an operation one of the reference and the harness lists and the other lacks raisesReferenceVocabularyDrift, printing both lists.Why
because the reference’s case decoder and the harness spell the operations twice, and an operation one side lacks is never comparedharnesstestThe harness drives the reference binary and the decision module’s native and WebAssembly builds over each generated case and compares their decisions field by field.buildstestThe native build decides in process and thewasm32-unknown-unknownbuild under the decision-module host; absent--wasm, the command compiles the module from the working tree, and the report names the builds compared.decision-casestestA case names one decision: table-pattern coverage, grant narrowing, zone admission against an allow-set, session-zone resolution, or credential admission; a placement decision also carries the zone it resolved.credential-casestestAverifycase admits one credential against pinned keys as a network checkpoint does; both builds decide it and are compared, the reference model decides none, and the report counts each credential verdict.Why
because the reference model carries no signature scheme, and a gateway admits the credential before it places the requestcase-classestestEach run generates malformed inputs, boundary values and well-formed requests, and its report names the classes it drew from.Why
because a green run is evidence over the generated classes, not an equivalence proofmalformed-bytestestThe malformed class draws case texts carrying invalid UTF-8 or an integer literal outside the unsigned 64-bit range, handed as bytes to every decider, and each decides such a text malformed.Why
because a 32-bit WebAssembly build and a 64-bit native build part ways first at byte decoding and integer widthminimizedtestA disagreement is shrunk until no single field removal, string shortening or byte removal keeps any two of the three decisions apart, and the minimized case is recorded.corpus-replaytestEvery counterexample-corpus case replays before any freshly generated case.corpus-entriestestThe counterexample corpus retains at most 256 entries, evicting the oldest case a fresh seed reproduces.run-budgettestOne invocation, corpus replay included, completes within 300 s.disagreementtestA case on which any two of the three decisions differ raisesReferenceModelDrift, printing the minimized case and every decision.discarded-counterexampletestA run reporting a disagreement and writing no corpus entry raisesCounterexampleDiscarded.seedtestEach run records its generator seed, and re-running with that seed reproduces the same case sequence.protocol-casestestProtocol cases are operation sequences and node interleavings aproptest-state-machinegenerator draws over grant, raise, renew, expire, release, send, deliver, pause, resume and crash steps across three nodes, each replayed on both lease paths.protocol-harnesstestThe harness drives the protocol executable and the store’s own lease calls,Syncerover a scripted bucket and the local catalog with the commit log, through each case, comparing lease, fence, head, write count and node views after every step.protocol-drifttestA step after which the model’s state and the store’s projected state differ raisesProtocolConformanceDrift, printing the minimized operation sequence and both states.protocol-vocabularytestBefore any case, the harness reads the protocol executable’s step listing; a step kind one of the model and the harness lists and the other lacks raisesProtocolVocabularyDrift, printing both lists.Why
because the step type and the harness enum spell the vocabulary twice, and a step one side lacks is never comparedjournal-harnesstestThe journal harness runs each caller’sJournal::stepon a thread over gated memory, file and SQLite adapters, one port call per step, comparing rows, blobs and caller phases with the model.journal-drifttestA step after which the journal model and an adapter differ raisesJournalConformanceDrift, printing the adapter, the minimized sequence and both states.journal-commandtestcontextful formal journal-differentialreplaysformal/protocol/journal-regressions.jsonlin each entry’s grace mode, then generated cases;--no-gracereplays and saves the model’s sequence tomissing-blob.merge-harnesstestcontextful formal merge-differentialcompares the merge model withmerge_verifiedkey by key on each generated case: entry, tombstone and refusal, orcursor-recency.merge-drifttestA case on which the merge model andmerge_verifieddiffer raisesMergeConformanceDrift, printing the minimized case and both merges.fold-harnesstestThe fold differential replays seeded step sequences throughprepare_under,commitandcollectover a file-backed store, comparing pointer, chain, directories and readers withprotocol fold runafter every step.commandtestcontextful formal differential --seed <n> --cases <n>replays the corpus, then runs the generated cases, exiting non-zero on the first disagreement.
Shapes
One inventory row:
[constant.composed_sound]
module = "Contextful.Layer"
statement = "∀ {ls : List Layer} {r : RowId}, composed ls r = true → ∀ l ∈ ls, l r = true"
assumptions = ["propext", "Quot.sound"]
binding = "engine/policy/src/relation.rs::compose_layers"
negative = """
Leaves open: that the required members were present in the list; that a member
performs removal rather than a test; that an execution reaches the fold ahead of
an effect.
"""