This is the engineering plan for the single largest remaining body of proof work
in docs/PROOF-NEEDS.adoc §6 Wave 3: replacing the deliberately-small models the
formal/ track proves today with the real objects, so that K-1 / F-1 / F-2 and
the dynamic halves of P-2 / P-4 become discharged obligations rather than
meaning-pinning seeds.
It is grounded in the actual compiler: the source AST is lib/ast.ml, the target
IR is lib/wasm.ml, the compiler is lib/codegen.ml (+ lib/codegen_gc.ml),
and the reference dynamic semantics is lib/interp.ml.
|
Important
|
The lift is XL (CompCert-scale for a substantial language). It is delivered
as a ladder of strict-superset fragments, each fully mechanized and axiom-free
before the next — the way |
For the real compiler compile : Ast.program → Wasm.wasm_module and the real
operational semantics on each side:
⟦ compile(p) ⟧_wasm = ⟦ p ⟧_source (for every well-typed p)K-1 is the backend half; F-1 (⟦T_F(p)⟧ = ⟦T_canonical(canon(p))⟧) composes the
face transformers on top of it; F-2 (#601) is the observational corollary across
faces. All three collapse to "grow K-1 onto the real objects, then re-chain the
existing F-1/F-2 scaffolding."
The real expr has ~30 constructors. Grouped by the order the ladder tackles
them:
| Group | Constructors |
|---|---|
Core values/binding |
|
Control |
|
Functions |
|
Aggregates (heap) |
|
Operators |
|
Elaboration nodes (post-typecheck, backend-only — |
|
Effects |
|
Unsafe |
|
The type layer (type_expr) carries the substructural data the proofs care
about: quantity {QZero,QOne,QOmega} (→ already mechanized in QttSemiring.v),
ownership {Own,Ref,Mut}, origin_var (ADR-022 Polonius regions, → P-3 /
P3_BorrowGraph.v), effect rows (→ P-6, blocked on #555), and record rows.
A faithful WebAssembly-1.0 IR: value_type {I32,I64,F32,F64}, ~150 instr
constructors (numeric i32/i64/f32/f64, LocalGet/Set/Tee, GlobalGet/Set, the
load/store family with align+offset, Block/Loop/If/Br/BrIf/Return/Call/CallIndirect,
MemorySize/Grow), and a wasm_module with funcs/mems/tables/globals/
exports/imports/elems/datas/custom_sections. The
typedwasm.ownership custom section carries TyOwn/TyRef/TyMut to the binary
for typed-wasm Level-7/10 verification — the seam where P-3 (borrow soundness)
connects to the target.
K1_CodegenPreservation.v invents an ad-hoc stack machine; RealWasm.v
(this directory, milestone R0, below) re-targets the actual instr /
value_type names with a stack-arity soundness theorem (wexec_sound:
arity-checked code never gets stuck). That is the first real foundation stone.
| Module | Contents | Status |
|---|---|---|
|
Target IR (real |
R0 landed |
|
The full target operational semantics as the ladder reaches control/memory: fuel-indexed step relation, linear-memory model, frame/locals. |
planned (R2+) |
|
The real source |
R1 inline |
|
The reference dynamic semantics (mirrors |
R1 inline |
|
The real |
R1 landed |
|
|
planned |
Each rung is a strict superset; each is fully proven (axiom-free) before the
next. The rung names are stable references the PROOF-NEEDS.adoc rows will cite.
| Rung | Adds | Retires / advances |
|---|---|---|
R0 ✅ |
Pure i32 numeric stack core ( |
The toy stack machine’s target — real names now. |
R1 ✅ |
Source |
Subsumes K1 and K1Let on real objects. |
R2 ✅ (conditionals) |
Structured control. Done: the |
Closed the toy K-1’s "`if`/control is the next increment" gap. The remaining
value-returning-tail story lets F-2 (#601) be settled concretely: the
statement-tail vs expression-tail lowerings become two real |
R-mem |
Linear memory: load/store family, |
Heap layout — the precondition for strings and the "cell" elaboration nodes. |
R-float |
|
The "float wall" / "float heap wall" become preservation lemmas. |
R-str |
The string wall: |
String-wall slices 8b/9/10 (#458) as preservation lemmas. |
R-call |
|
Whole-program K-1. |
R-wrap |
Replace |
Bit-exact integer fidelity. |
R-eff |
Effects/handlers ( |
P-6 effect-row soundness; the #555 proof-blocking defect. |
The source-side rungs S0…Sn track the target rungs one-for-one (each RealAst/
RealAstSem increment matches the RealWasm/RealCompile increment it is
proven against).
-
Nested control & termination — DONE for conditionals (R2). Because
instrnestslist instr(theIfElsebranches), even forward structured control defeats Coq’s structural guard checker — sowexecis already fuel-indexed as of R2 (wexec : nat → …), with the standard monotonicity lemma (wexec_mono: more fuel never changes aSomeresult) and an additive sequencing lemma (wexec_app_some) replacing the structuralwexec_seq; preservation is stated existentially in the fuel. Backward jumps (Loop/Br, and the sourcewhile/for) reuse the very same device — that is R2-loops. -
Linear memory. Model memory as
Z → byte(or a finite map) + a bound; load/store mirrorlib/wasm.ml’s align/offset. The allocator (`runtime/src/alloc.rs) is modelled abstractly (a bump pointer in a global) — enough for the deterministic layout the elaboration nodes assume. -
Floats. Start with an abstract IEEE carrier: opaque
f64with the arithmetic/compare ops as deterministic uninterpreted functions, so R-float proves layout/dispatch preservation without a NaN-bit model. A later R-float-exact swaps in Flocq if bit-fidelity is ever load-bearing. -
The elaboration nodes.
ExprStringConcat/Float*/Cell*are introduced byTypecheck.elaborate_string_concatafter typing. The proof must include that elaboration as part ofcompile(source semantics is on the pre-elaboration AST; the elaboration must be shown meaning-preserving — itself a clean lemma per node). -
Borrowing / QTT at the seam.
origin_var+ thetypedwasm.ownershipcustom section connect to typed-wasm Level-7/10. P-3 (P3_BorrowGraph.v) and P-4 (QttTyping.v/QttDynamic.v) are the static+dynamic discipline; the lift showscompilepreserves the multiplicity/ownership facts into the custom section (a refinement, not a re-proof). -
Effects. The genuinely hardest, and blocked: do it last (R-eff), only after #555 is resolved per K-2.
hyperpolymath/typed-wasm and ephapax both have Coq (Semantics.v). The
target operational semantics (RealWasmSem.v) and value_type/instr encoding
should be imported or aligned with typed-wasm’s, not independently reinvented —
the compile target is the one genuinely shared surface across the estate
(per .claude/CLAUDE.md’s disambiguation table). The `typedwasm.ownership
custom section is the contracted hand-off point; the crates/typed-wasm-verify/
verifier crate is the executable companion to the Coq semantics.
| Phase | Rungs | Size |
|---|---|---|
First-order K-1 |
R0 ✅ → R1 → R2 |
M (multi-week) |
Heap & data |
R-mem → R-float → R-str |
M–L |
Whole program |
R-call → R-wrap |
M |
The long tail |
R-eff (after #555), generics/traits, |
L–XL |
"First-order K-1" (R0→R2) is the natural first publishable milestone: it
discharges K-1 for the nat/bool/let/if/control fragment on the real AST and
real wasm IR, retires K1/K1Let, and settles #601 concretely. The estate
already has the front-end scaffolding (F1_TransformerPreservation.v,
SameCube.agda) waiting to re-chain onto it.
-
R0 landed —
RealWasm.v: realinstr/value_typenames + a stack-machinewexec, axiom-free. -
R1 landed —
RealWasm.vgrown with locals (LocalGet/LocalSet)
comparison ops;RealCompile.vgives the resolved int/bool/let/binary sourcerexpr, the referenceeval, thecompileto real wasm, and the first real⟦compile p⟧ = ⟦p⟧—compile_correct(env↔locals agreement, fresh-slot allocation, low-slot preservation) +compile_program_correct. RetiresK1/K1Leton real objects. -
R2 landed (conditionals) —
RealWasm.vgrown with the structuredIfElseinstruction; this forcedwexecto become fuel-indexed (the nestedlist instrdefeats the structural guard checker), withwexec_mono
wexec_app_somereplacingwexec_seq.RealCompile.vgrowscompilewithRIf;compile_correctnow covers value-returningif, stated existentially in the fuel. (The R1 arity lemmawexec_sound/wcheckwas retired in the fuel refactor; it can be restated over fuel later, but is not load-bearing —compile_correctis.) Axiom-free. -
Next: R2-loops —
Loop/Br+ sourcewhile/foron the same fuel device; this is the rung that settles #601 concretely.
Tracked against docs/PROOF-NEEDS.adoc §6 Wave 3 and #513.