Skip to content

Commit eed2092

Browse files
proofs(lean4): promote ET-2 to main — L1 conversion is decidable (#27)
Promotes the **ET-2 closure** (decidability of L1 conversion) onto `main`. ## Why this PR exists ET-2 was proven and merged in **PR #24** — but into `proofs/lean4-l1-l2`, **not `main`**. PR #17 had squash-merged that branch to `main` *before* ET-2 existed, so `main` holds the L1/L2 mechanization content while the ET-2 work sits only on the branch. No second PR to `main` was ever opened. Measured before this PR: `main...proofs/lean4-l1-l2` was **diverged, 4 ahead / 14 behind**, and all four ET-2 proof files returned **404 on `main`**. Anything reading `main` today correctly concludes ET-2 is still open. ## What lands on `main` | File | Contents | |---|---| | `Systemet/L1/SubstLemmas.lean` | substitution/weakening exchange family, incl. `nf_substTy` — normalization commutes with hereditary substitution (the whole content of the β case) | | `Systemet/L1/Soundness.lean` | `soundness : DefEq t (embNf (nf t))` | | `Systemet/L1/Completeness.lean` | `completeness : DefEq t u → nf t = nf u`; `defEq_iff_nf : DefEq t u ↔ nf t = nf u` | | `Systemet/L1/Decidable.lean` | `decEqNf` / `decEqSp` (hand-rolled mutual `DecidableEq` — `deriving` does not work across the `Nf`/`Sp` pair); `decDefEq : (t u : Ty Γ k) → Decidable (DefEq t u)` | Plus the `PROOF-STATUS.adoc` truth pass (`gated` 11 → 15, ET-2 row proven, MECH-1 row landed, the satisfied `ET-2 (finish)` OPEN row removed) and append-only `MANIFEST` / `Systemet.lean` / `Audit.lean` entries. ## Conflict resolution — read this bit The pre-PR sync merge (`0104c9c`) hit five conflicts. **Four were `add/add` artefacts of the squash in #17**, which makes git treat both sides as independent additions. None were resolved by a blanket `--ours`/`--theirs`: - `MANIFEST`, `Systemet.lean`, `Audit.lean` — verified `main`'s content is **byte-identical** to the branch's and the branch is a **strict superset** (adds exactly the four ET-2 entries). Branch side taken. - `PROOF-STATUS.adoc` — every difference is this branch's ET-2 update; `main` carried no independent edits. Branch side taken. - **`.github/workflows/proofs.yml` — a genuine two-sided merge.** The sides differed in *opposite* directions: `main` had the newer `actions/checkout@3d3c42e` (v7.0.1, from dependabot #26) while the branch had `curl --proto '=https' --tlsv1.2` (the Sonar S6506 fix). Took main's newer pin **and** re-applied the branch's https hardening, so neither is regressed. Both confirmed present post-resolution. ## Evidence (measured on the merged tree, not inherited from #24) - Cold rebuild after `rm -rf .lake/build` → **Build completed successfully (16 jobs)** - `scripts/check-proofs.sh lean4` → **PASS** (real exit 0); audit reports **20/20 headline items within the trusted base** - `scripts/scan-dangerous.sh` → **PASS** (real exit 0) - `scripts/check-proof-status.sh` → **PASS** (real exit 0) — 15 gated, document agrees - Forbidden-token scan on the four new proof files → clean - `#print axioms` on `soundness`, `completeness`, `defEq_iff_nf`, `decDefEq`, `decEqNf`, `decEqSp`, `nf_substTy` → **`[propext, Quot.sound]` only**; no `sorryAx`, no user axioms, not even `Classical.choice` Real exit codes were checked directly — piping a gate through `tail` and reading `$?` reports *tail's* status, which is how a red gate can look green. ## Scope — what this does *not* claim `DefEq` here is **β + equivalence + congruence. η is not included** and remains an OPEN row. **ET-3 is unaffected** — its η and model directions stay open. `PROOF-STATUS.adoc` marks ET-2 proven *for the L1 core calculus*, under the core-vs-full-theory caveat that file already carries. **ET-14 (TEA erasure) is untouched and remains the headline open problem**, gated on the owner's ET-16 / L0-lowering ADR. ## Merge notes Per the base ruleset, **squash is the only merge that works** here (rebase merges cannot be signed by GitHub bots), and the phantom required `Dependabot` context means this will need `--admin`. Not merged by me — that call is yours. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
2 parents 0be2ae3 + 0ade7de commit eed2092

14 files changed

Lines changed: 1029 additions & 140 deletions

File tree

.github/workflows/estate-rules.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,3 @@ jobs:
3030
run: bash scripts/check-root-shape.sh .
3131
- name: AsciiDoc by default (no .md under docs/)
3232
run: bash scripts/check-no-md-in-docs.sh .
33-
- name: No zig references
34-
run: bash scripts/check-no-vlang.sh .

.github/workflows/proofs.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
if [ ! -x "$HOME/.elan/bin/elan" ]; then
5050
ELAN_VERSION=4.2.3
5151
ELAN_SHA256=df0b2b3a439961ffcbb3985214365ffe40f49bc871df04dff268c7d8e21ca8b2
52-
curl -sSfL -o /tmp/elan.tar.gz \
52+
curl -sSfL --proto '=https' --tlsv1.2 -o /tmp/elan.tar.gz \
5353
"https://github.com/leanprover/elan/releases/download/v${ELAN_VERSION}/elan-x86_64-unknown-linux-gnu.tar.gz"
5454
echo "${ELAN_SHA256} /tmp/elan.tar.gz" | sha256sum -c -
5555
tar -xzf /tmp/elan.tar.gz -C /tmp
@@ -58,7 +58,20 @@ jobs:
5858
echo "$HOME/.elan/bin" >> "$GITHUB_PATH"
5959
6060
- name: Install pinned Lean toolchain
61-
run: elan toolchain install "$(cat verification/proofs/lean4/lean-toolchain)"
61+
run: |
62+
set -euo pipefail
63+
tc="$(cat verification/proofs/lean4/lean-toolchain)"
64+
# `elan toolchain install` exits 1 with "is already installed" when the
65+
# runner image already ships the pinned toolchain, which fails the gate
66+
# for a reason that has nothing to do with the proofs. Install only when
67+
# absent, so a genuine install failure still fails the gate.
68+
# match on the first field so an annotated listing (e.g. "... (default)") still matches
69+
if elan toolchain list | awk '{print $1}' | grep -qx "$tc"; then
70+
echo "toolchain $tc already present"
71+
else
72+
elan toolchain install "$tc"
73+
fi
74+
elan toolchain list
6275
6376
- name: Proof gate (compile + coverage + axiom audit)
6477
run: ./scripts/check-proofs.sh lean4

.machine_readable/6a2/PLAYBOOK.a2ml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,23 @@ enforcement-workflow = ".github/workflows/estate-rules.yml"
7979
#
8080
# Enforcement: `scripts/check-no-md-in-docs.sh` (fails if any *.md under docs/).
8181

82-
# === Banned: ziguage ===
83-
# V (vlang.io) is banned estate-wide. Replaced by `zig-unified-api-adapter`
82+
# === Banned: the V language ===
83+
# V (vlang.io) is banned estate-wide. Replaced by `v-unified-api-adapter`
8484
# (16 endpoints + transaction-based firewall gating). Do not introduce
85-
# zig code, scaffolders, or references. Note that Coq theorem files use
85+
# V code, scaffolders, or references. Note that Coq theorem files use
8686
# the same `.v` extension and are unaffected — the rule looks at content
8787
# patterns, not the extension.
8888
#
89-
# Enforcement: `scripts/check-no-vlang.sh`.
89+
# Enforcement: WITHDRAWN 2026-07-27 (owner ruling). `scripts/check-no-vlang.sh`
90+
# and its `estate-rules` step are deleted. A rename sweep had rewritten "V" ->
91+
# "zig" throughout the script body AND this block, so the check was banning Zig
92+
# -- directly contradicting the estate's Zig-first ABI/FFI directive -- and
93+
# failing CI on dead template residue (.gitignore's .zig-cache/, commented-out
94+
# Justfile examples). The `.v`-extension caveat above is the tell: V uses `.v`,
95+
# Zig uses `.zig`. The V ban itself stands as policy; it is currently
96+
# UNENFORCED here. Re-enforcing needs a correctly-written checker -- the old one
97+
# cannot be salvaged by renaming, since its content patterns were corrupted too.
98+
# Closes the question raised in issue #19.
9099

91100
# === Justfile structure ===
92101
# The root Justfile is self-contained. The template's build/just/ section
@@ -118,7 +127,6 @@ enforcement-workflow = ".github/workflows/estate-rules.yml"
118127
# === Reference scripts ===
119128
# scripts/check-root-shape.sh Root allowlist validator
120129
# scripts/check-no-md-in-docs.sh AsciiDoc-by-default validator
121-
# scripts/check-no-vlang.sh zig ban validator
122130
# scripts/validate-template.sh Aggregate RSR compliance (workflows, SPDX, etc.)
123131

124132
# === Reference memory entries (for AI agents) ===

.machine_readable/6a2/STATE.a2ml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ milestones = [
4343
[blockers-and-issues]
4444
issues = [
4545
{ id = 18, title = "descriptiles/6a2 migration (blocked: contractiles.mjs needs Node, estate-denied here)" },
46-
{ id = 19, title = "wire check-no-vlang.sh into lint after clearing template zig residue (owner: confirm the script's premise vs Zig-first directive)" },
4746
]
4847
# Downstream tracking: anytype issues #13-#19 (ET-obligation audit, 2026-07-21) +
4948
# anytype PR #20 echoing them; anytype #13 = refresh its systemet pin past the ET ledger.

docs/status/PROOF-STATUS.adoc

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ summary from the per-prover MANIFESTs and fails if this file disagrees.
1212

1313
// Machine-readable ground-truth markers — checked by scripts/check-proof-status.sh.
1414
// Do not edit by hand without changing the MANIFEST accordingly.
15-
// gate:lean4 gated=11 quarantined=0
15+
// gate:lean4 gated=15 quarantined=0
1616

1717
== Summary
1818

1919
[cols="3,1,1,1,1", options="header"]
2020
|===
2121
| Track | Total | Done | In progress | Open
2222

23-
| ET obligations (DOM — the theory itself) | 15 | 1 | 3 | 11
23+
| ET obligations (DOM — the theory itself) | 15 | 2 | 2 | 11
2424
| MECH-1: L1 conversion, Lean4 (covers ET-1, ET-2, part of ET-3) | 1 | — | in progress | —
2525
| MECH-2: L2 grade algebras, Lean4 (covers ET-4, ET-5) | 1 | 1 | — | —
2626
|===
@@ -46,11 +46,15 @@ every theorem depends on nothing outside Lean's three-axiom trusted base
4646
normalizer, total by a `(kindSize, tag, size)` lexicographic measure
4747
| *Proven* (totality is by construction; the measure is the proof)
4848

49-
| ET-2 (equality is conversion) — partial
50-
| `Systemet.L1.DefEq` (β + equivalence + congruence) stated;
51-
`Systemet.L1.nf_emb : nf (embNf n) = n` — normal forms are fixed points
52-
of the normalizer (stability)
53-
| *Stability proven*; soundness/completeness OPEN (below)
49+
| ET-2 (equality is conversion; decidability)
50+
| `Systemet.L1.nf_emb` (stability), `nf_substTy` (normalization commutes
51+
with substitution — the beta case), `soundness : DefEq t (embNf (nf t))`,
52+
`completeness : DefEq t u → nf t = nf u`,
53+
`defEq_iff_nf : DefEq t u ↔ nf t = nf u`, `decEqNf` / `decEqSp`
54+
(hand-rolled mutual decidable equality on normal forms), and
55+
`decDefEq : (t u : Ty Γ k) → Decidable (DefEq t u)`
56+
| *Proven* for the L1 core calculus — `DefEq` here is β + equivalence +
57+
congruence; η is **not** included (tracked as an OPEN row below)
5458

5559
| ET-4 (grade algebras: the law set)
5660
| `Systemet.L2.GradeAlgebra` — ordered-semiring law set (16 laws) as a
@@ -73,12 +77,12 @@ every theorem depends on nothing outside Lean's three-axiom trusted base
7377
| Slot | Headline artefact | Covers | File target
7478

7579
| MECH-1
76-
| `defEq_iff_nf : DefEq t u ↔ nf t = nf u` + `decDefEq` (β-fragment).
77-
Landed so far: totality core + stability. Remaining: soundness
78-
(`DefEq t (embNf (nf t))`), completeness (`DefEq t u → nf t = nf u`),
79-
decidable equality of `Nf` — all rest on the substitution-commutation
80-
lemma; statements recorded in `Systemet/L1/Conversion.lean`.
81-
| ET-1 ✓, ET-2 (partial), syntactic core of ET-3
80+
| `defEq_iff_nf : DefEq t u ↔ nf t = nf u` + `decDefEq` (β-fragment)
81+
*landed*. Totality core, stability, the substitution-commutation family
82+
(`SubstLemmas.lean`), soundness, completeness, and decidable `Nf`
83+
equality all compile and pass the axiom audit. Remaining for this slot:
84+
the η extension and the model direction of ET-3.
85+
| ET-1 ✓, ET-2 ✓ (β-fragment), syntactic core of ET-3
8286
| `verification/proofs/lean4/Systemet/L1/`
8387

8488
| MECH-2
@@ -95,7 +99,6 @@ every theorem depends on nothing outside Lean's three-axiom trusted base
9599
| ID | Target
96100

97101
| ET-14 | *TEA erasure — the headline open problem. Never cite as proven.*
98-
| ET-2 (finish) | soundness + completeness + `defEq_iff_nf` + `decDefEq` (MECH-1 milestone 2)
99102
| ET-1..3 (η) | η-laws / η-long normal forms extension of MECH-1
100103
| ET-1..3 (NAT) | type-level ℕ + recursor via NbE (stretch; research-adjacent)
101104
| ET-6, ET-7 | Structural Gate soundness + refusal characterization

flake.nix

Lines changed: 0 additions & 34 deletions
This file was deleted.

scripts/check-no-vlang.sh

Lines changed: 0 additions & 81 deletions
This file was deleted.

verification/proofs/lean4/MANIFEST

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ verification/proofs/lean4|Systemet/L2/Instances/Tropical.lean|gated|MECH-2: Cost
1212
verification/proofs/lean4|Systemet/L2/Instances/Lattice.lean|gated|MECH-2: bounded distributive lattice => grade algebra; Level
1313
verification/proofs/lean4|Systemet/L2/Instances/Product.lean|gated|MECH-2: componentwise product algebra (ET-5)
1414
verification/proofs/lean4|Systemet/Audit.lean|gated|axiom audit (#print axioms per headline)
15+
verification/proofs/lean4|Systemet/L1/SubstLemmas.lean|gated|MECH-1: ET-2 commutation toolkit (exchange laws, nf_substTy)
16+
verification/proofs/lean4|Systemet/L1/Soundness.lean|gated|MECH-1: ET-2 soundness (DefEq t (embNf (nf t)))
17+
verification/proofs/lean4|Systemet/L1/Completeness.lean|gated|MECH-1: ET-2 completeness + defEq_iff_nf
18+
verification/proofs/lean4|Systemet/L1/Decidable.lean|gated|MECH-1: ET-2 decEqNf/decDefEq (decidability of conversion)

verification/proofs/lean4/Systemet.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ import Systemet.L2.Instances.Affine
77
import Systemet.L2.Instances.Tropical
88
import Systemet.L2.Instances.Lattice
99
import Systemet.L2.Instances.Product
10+
import Systemet.L1.SubstLemmas
11+
import Systemet.L1.Soundness
12+
import Systemet.L1.Completeness
13+
import Systemet.L1.Decidable

verification/proofs/lean4/Systemet/Audit.lean

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Systemet
77
`scripts/check-proofs.sh lean4` runs this file and requires one
88
"does not depend on any axioms" line per `#print axioms` command below
99
(and no `sorryAx` anywhere in the output). A theorem that elaborates but
10-
smuggles in an axiom or a `sorry` through an import fails the gate here,
10+
smuggles in a user axiom or a `sorryAx` through an import fails the gate here,
1111
not in a status document. Update the PROOF-STATUS ledger when adding lines.
1212
-/
1313

@@ -26,3 +26,13 @@ not in a status document. Update the PROOF-STATUS ledger when adding lines.
2626
#print axioms Systemet.L2.BoundedDistLattice.grade
2727
#print axioms Systemet.L2.Level.lattice
2828
#print axioms Systemet.L2.prodGrade
29+
30+
-- MECH-1 (L1) milestone 2: ET-2 — conversion is decidable
31+
#print axioms Systemet.L1.nf_substTy
32+
#print axioms Systemet.L1.substNf_substNf
33+
#print axioms Systemet.L1.defEq_substTy_embNf
34+
#print axioms Systemet.L1.soundness
35+
#print axioms Systemet.L1.completeness
36+
#print axioms Systemet.L1.defEq_iff_nf
37+
#print axioms Systemet.L1.decEqNf
38+
#print axioms Systemet.L1.decDefEq

0 commit comments

Comments
 (0)