This is the authoritative, dependency-sorted plan for driving the formal verification of the Ochránce estate to completion. It is the durable source of truth for the proof thread: it survives context compaction, so each working window starts from this file rather than from chat memory.
- 1. Scope & estate map
- 2. Decisions on record
- 3. Current proof state (ochrance, canonical)
- 4. The remaining proof program (dependency-sorted)
- 4.1. Stage 1 — Merkle closure + crypto-binding interface [model: Opus]
- 4.2. Stage 2 — Verify + Validator soundness [model: Opus → Sonnet if mechanical]
- 4.3. Stage 3 — Repair correctness (L3, linear types) [model: Opus]
- 4.4. Stage 4 — Completeness, binding discharge, write-up [model: Sonnet; Opus if binding is hard]
- 5. The IO↔pure bridge (estate-wide spine)
- 6. Build-with-proofs discipline
- 7. Optimisation ledger (against the proven backdrop)
- 8. Honestly-bounded items (NOT failures — boundaries by design)
- 9. Disposed tracks (handoff briefs)
- 10. Model guidance (per the thread’s operating model)
Three repositories are in scope. "Verification" means something different in each.
| Repo | What "verified" means | This thread executes? |
|---|---|---|
|
Idris2 dependent-type proofs (the canonical core). |
Yes — primary focus. |
|
Architecture + docs. Its |
Docs/Interface harvest only — core is deleted, not proven. |
|
ReScript edge gateway → migrating to Ephapax (replaces all ReScript). Type-safety and schema/property tests, not dependent types. |
No — disposed to a delegated session (see Disposed Tracks). Specs tracked here. |
| ID | Decision |
|---|---|
D1 — Converge on ochrance |
|
D2 — Crypto binding as a typed interface |
The security half of the Merkle argument (collision resistance) is modelled as
an Idris hypothesis |
D3 — svalinn: migrate before proving |
Prove where the language is final; migrate-then-prove where it is changing.
svalinn migrates ReScript → Ephapax — Ephapax replaces all the ReScript.
Its linear/exactly-once types make JWT/JTI single-use & revocation, OAuth
nonce/PKCE, and session/container lifecycle compile-time guarantees, and typed
boundary decoders eliminate the 20+ |
The core is clean: all 19 ochrance-core modules carry %default total (the
src/abi/ tree adds the ABI modules separately); zero
believe_me / assert_* / postulate / holes / partial on any proof symbol.
| Theorem | Statement (shape) |
|---|---|
|
inclusion-proof soundness; generic over the hash combiner |
|
|
|
supporting lemmas. |
|
constructor round-trip: |
|
reusable transport/append lemmas: |
|
grammar invertibility: |
|
progressive-assurance threshold witness. |
ABI |
|
Each stage is sized to roughly one context window; the thread compacts at each boundary with this file as the hand-off. Watch-fors are things that may force a design change or a model downshift mid-stage.
-
[DONE — 1.1]
buildMerkleTree↔getLeafHashround-trip:getLeafHash (buildMerkleTree hs) (finToNat i) = Just (index i hs)(buildGetLeafinOchrance.Filesystem.MerkleBuild, on the reusableOchrance.Util.VectLemmaslemmas). Machine-checked, axiom-free, onmain. -
[1.2] Root-fold law: characterise
rootHashWith h (buildMerkleTree hs)as a deterministic fold overhs— "the root is a function of the leaves". Pure; prerequisite of the binding argument. -
[1.3] IO↔pure bridge: prove
verifyProofIO/rootHashBytesIOcompute the…With (hashPairBlake3 …)spec modulo theEitherallocation-failure plumbing, against a typed combiner-equality hypothesis — connecting the proven theorem to the production crypto path. (The estate-wide spine; see "The IO↔pure bridge".) -
[1.4] D2: introduce
CollisionResistant hand statemerkleBinding(typed hypothesis / interface; discharged in Stage 4).RESOLVED (was WATCH-FOR): the
replace-by-powerTwoSucctransport inbuildMerkleTreewas discharged without reshaping the builder — via theindexReplace/finToNatReplace/splitAtConcattransport-cancellation lemmas inVectLemmas. No API change was forced.
-
Validator: validated manifest ⇒ structural invariants hold.
-
verifyStateagrees with the manifest, wired tomerkleCorrect. -
Hex codec:
hexStringToBytes (bytesToHex bs) = Just bsand the length law.WATCH-FOR:
VerifyandHexlikely rest on primitiveString/Bits8comparison — the same wall as the lexer round-trip. If so the honest theorem is propositional-over-decidable (document the boundary; do not reach forbelieve_me). This can shorten Stage 2 and justify a Sonnet downshift.
PRECONDITION (surfaced at Compaction 2): repair is currently a stub —
repairBlock (Repair.idr) updates the hash map but does not read or write
block data. Proving verify (repair s) = Valid against a no-op would be vacuous or
false. DECISION (recommended): introduce a pure
repairPure : FSState → Manifest → FSState that genuinely reconstructs the hash
map, prove correctness over that, and make the IO repair a proven-equivalent
shell (the IO↔pure pattern). Alternative: leave repair honestly-bounded until real
block-I/O lands (defers the linear-type theorem).
-
verifyPure (repairPure s m) m = True— the meaty (now well-founded) theorem. -
Repair idempotence as a proof (today only a property test).
-
Harvest framework’s mode-indexed Interface; state the
VerifiedSubsystemlawverify (repair s m) m = Right …and prove the FSState instance satisfies it.WATCH-FOR: may need proof witnesses threaded through the
1-quantified API — possible signature changes toRepair.idr.
-
Merkle completeness (converse of soundness): in-range leaf ⇒ a proof exists.
-
D2 discharge: prove the binding argument against
CollisionResistant. -
Progressive monotonicity: the remaining
SatisfiesMinimumcases (allRefl). -
Final ledger pass; thesis-aligned summary (ICFP/PLDI/SOSP framing).
CLEAR = every intended theorem proven or honestly bounded (primitive walls documented, never faked), disposed tracks handed off, PRs landed.
The same device recurs at every IO boundary — Merkle (1.3), Verify (2.2), Repair (3), signatures (4 / bounded). The shape is always:
pure spec (proven) --[extensional-equality lemma]--> IO production path
(modulo `Either`
allocation-failure +
a typed crypto hypothesis)
Treating this as one architectural pattern — not four ad-hoc stage items — is what
lets the proven backdrop reach production code without ever faking the FFI. The
typed crypto hypotheses (CollisionResistant h; hashPairBlake3 a b equals the
spec combiner) are introduced in Stage 1.4 and discharged-or-assumed explicitly,
never silently. It is also the mechanism that licenses optimisation (below).
The invariant: code never outstrips proofs. Operationally —
-
A correctness-claiming
public exportsymbol lands only when (a) it carries its lemma in the same PR, or (b) it is explicitly-- UNPROVEN:-marked with a tracking issue, or (c) it is a documented honestly-bounded wall. No silent (d). -
The
--totalCI build is the totality proof (already enforced) — a green build is the floor, not the ceiling. -
No proving stubs. If an implementation is a placeholder (Repair today), make it real or model it purely first — never point a theorem at a no-op.
-
This ledger’s proven-surface table is the source of truth;
README/TOPOLOGYmust not claim beyond it.
Governing principle: the proven surface is exactly the code you may optimise — the
proof is the optimisation’s regression contract. Keep the simple reference R
(proven), introduce optimised F, discharge F x = R x, and every theorem about R
transports to F by rewrite. Never optimise unproven code (nothing guards it).
| Target | Optimisation | Guard | Status |
|---|---|---|---|
|
bottom-up O(n) fold from the flat vector (vs. per-level |
|
unlocked now |
|
thread a |
|
unlocked now |
|
difference-list / vector path (vs. List append per step) |
|
unlocked now |
root combiner |
real BLAKE3 in IO (vs. abstract |
the Stage 1.3 bridge lemma |
after 1.3 |
A2ML production parser |
any fast String parser |
|
bounded (prim. wall) |
Repair (incremental / CoW) |
touch only broken blocks |
|
after Stage 3 |
-
Production-pipeline round-trip (
parse . lex . serialize = Right m) cannot carry a compile-time theorem:pack/unpack/parseIntegerare primitives with no equational theory. The honest guarantee isroundtripManifestover a reference token codec, complemented byroundtripPropertyat runtime. -
root == rootBool step inmerkleCorrect: the propositional digest equality is the strongest honest statement; discharging the residual primitive-Bits8==would need an unsafe reflexivity axiom.
These are not this thread’s work. Each is a brief for a delegated session, disposed at Compaction 1. Specs live here so nothing is lost.
PRECONDITION: language migration precedes proof (Decision D3). The first
deliverable is a migration map (the critical chain of blockers) — handed to an
offline Claude with hyperpolymath/ephapax access, targeting
svalinn/docs/ephapax-migration/BLOCKER-LINEAGE.adoc. ROOT of that chain, and the
one thing this session could not settle (ephapax is out of scope here): whether
Ephapax is yet an implementable application language (compiler, runtime,
HTTP/async I/O, JSON, fetch, crypto, FFI) or still a proof-level calculus.
-
Migrate ReScript → Ephapax (gateway, auth, policy, validation, MCP, vörðr, compose; ~27
src/modules + theui/ReScript frontend). Typed boundary decoders make the 20+Obj.magiccasts in security paths impossible. -
Ephapax linear tokens for exactly-once resources: JWT/JTI single-use + the revocation ledger (fixes the
hasRevocationList = false // TODOhazard by construction), OAuth nonce/PKCE, session/container lifecycle, vörðr delegation. -
Unblock CI: the 53 ReScript unit/security tests don’t execute under Deno (
@rescript/coreresolution) — they vanish with the migration; ensure the Ephapax suite runs in CI. (svalinnmainCI is currently red on pre-existing ReScript breakage — do not fix it in ReScript; it is being replaced.) -
Specs to discharge after migration (language-agnostic): policy determinism;
allow ∩ denycomposition + monotonicity; JWT single-use & revocation; no unchecked boundary casts; JSON-Schema conformance of all 9 gateway types. -
Planned SPARK properties (
cerro-torre-integration.adoc §6.2): attestation sig, key lookup, threshold sig, log inclusion, policy eval.DEPENDENCY: Ephapax has 3 Admitted (Coq) — svalinn’s linear guarantees inherit those holes until closed. Track upstream.
DISCHARGES: svalinn security issue #13 (19 Critical/High panic-attack findings —
decodeJwt()withoutjwtVerify(),JSON.parseExn) is addressed structurally by this migration (verified JWT + typed deserialisation), not by patching ReScript.RE-ENTRY: the outbound charter now lives at
svalinn/docs/ephapax-migration/HANDOFF.adoc; when this track returns, readdocs/AFTER-MIGRATION.adoc(the round-trip closure) before resuming the campaign.
-
Delete
ochrance-framework/ochrance-core; make the repo depend on / reference the canonical ochrance core. -
Harvest the mode-indexed
VerifiedSubsystemInterface into ochrance (Stage 3). -
Fix the weak spots that should not be carried over:
decodeSnapshotalways returnsNothing(repair unreachable);signatureValid : BoolandallPresent : Boolare unguarded runtime flags; no totality gate in CI. -
Keep and maintain the docs — they are the framework repo’s real value.
-
blake3Hashinsrc/abi/Ochrance/ABI/Foreign.idriscovering+ a stub returningreplicate 32 0— wire it to the real ZiglibochranceBLAKE3. -
ECHIDNA FFI is entirely stubbed (
echidnaProvereturnsLeft "FFI not yet implemented").
| Model | Use |
|---|---|
Opus 4.8 |
Proof discovery — "is this provable, what is the shape": Stages 1, 3, and any novel theorem or structural-wall reasoning. |
Sonnet 4.6 |
Proof mechanisation (known shape), refactors, tests, and the disposed-track application work (svalinn Ephapax migration, framework, ABI). |
Haiku 4.5 |
Grunt sweeps — suites, grep, SPDX/format, CI watch. |
RULE: when a stage’s remaining work is all mechanical, downshift this thread to Sonnet to conserve Opus budget; when a research-grade wall appears, pause for the design conversation rather than pushing proofs.