Skip to content

Commit ec3f06c

Browse files
fix(proofs+ci): repair proof corpus, unbreak Agda CI, and gate every proof in CI (#234)
## Summary Brings the full multi-language proof corpus to compile-clean **and** puts it under CI so the green checkmark actually means something. **All proof jobs are green on this PR** (Coq, Lean 4, Agda, Idris2 ABI + validator). ### CI infrastructure (commit `6c01819`) - **Agda meta-checker**: `--overwrite-policy=always` on `cabal install` - **Justfile**: drop duplicate `heal` recipe in `contractile.just` ### Idris2 / Agda scope fixes (commit `7f94f89`) - `proofs/agda/Basic.agda`, `verification/proofs/idris2/{DispatchCorrectness,ProverKindInjectivity}.idr` ### Proof corpus repair (commit `0a190ba`) - **Agda** `DispatchOrdering.agda`: `z<s`/`s<s` → `s≤s z≤n` - **Coq** `nat.v`, `list.v` (`in_filter` via case-split + `congruence`), `algebra/GroupTheory.v` (implicit `G`, rewrite directions) - **Lean4** `Nat/List/Propositional/algebra.GroupTheory`, `ECHIDNA.lean` - **Idris2** `Validator.idr`: `proof` → `pterm` (reserved keyword) ### 🔒 Proof CI coverage — *the gap this PR closes* The corpus had **zero CI coverage**: `agda-meta-checker.yml` → `meta-checker/**`, `idris2-abi-ci.yml` → `src/abi/**`, and **no Coq/Lean workflow at all**. So `proofs/{coq,lean,agda}` and `src/idris` were never type-checked — a green PR proved nothing about the proofs. - **New `dogfood-proofs-ci.yml`** — three jobs (Coq, Lean 4, Agda), each calling a `just` recipe (RSR-H14) so local and CI run identical commands. - **`idris2-abi-ci.yml`** extended to also type-check the `src/idris` validator (adds `src/idris/**` to the trigger; reuses the Idris2 install). - **New Justfile recipes**: `proofs{,-coq,-lean,-agda,-idris}`. **Two latent bugs the absent CI had hidden:** 1. `proofs/lean/lakefile.lean` rooted only `ECHIDNA` (umbrella imported 4 of 6 files); `lake build` actually **failed** (`unknown module prefix 'Basic'`) because top-level modules weren't in the lib's module space. Now every file is a root and the umbrella imports the whole corpus. 2. `src/idris/echidna-validator.ipkg` declares an executable but `Validator.idr` had no `main` → `idris2 --build` failed. Added `main = testValidation`. ### Two CI-environment gotchas found and worked around - **`taiki-e/install-action` reproducibly `startup_failure`s in this workflow** (bisected: header + checkout + `run` steps start fine; adding the action fails before any job runs — even though `mvp-smoke.yml` uses the same pin on `main`). Worked around by installing every toolchain with plain `run:` steps (apt + curl tarballs), matching the idris2/chapel workflows — only `actions/checkout` is used. *Worth a follow-up: the repo's allowed-actions policy may need a look, since the same pin works on `main`.* - **`apt-get --fix-missing` silently dropped `agda-stdlib`** (exit 0, no library → `Installed libraries: (none)`). Agda now installs the binary via apt and fetches stdlib **v1.7.3** from GitHub (matching apt's agda 2.6.3), the same deterministic pattern the meta-checker uses. ## Verified locally against real toolchains | Assistant | Toolchain | Result | |---|---|---| | Coq | `coqc` 8.18.0 | 5/5 ✅ | | Lean 4 | Lean **v4.13.0** (`lake build`) | 6 modules + umbrella ✅ | | Agda | `agda` 2.6.3 + stdlib **v1.7.3** (fresh GitHub tarball, isolated AGDA_DIR) | 13/13 ✅ | | Idris2 | `idris2` 0.8.0 `--typecheck` | ✅ | …and **green end-to-end on this PR's CI**. https://claude.ai/code/session_01UAqDQaMwpUqWHUSZekGZWv --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent a26e628 commit ec3f06c

21 files changed

Lines changed: 732 additions & 746 deletions

.github/workflows/agda-meta-checker.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ jobs:
4949
- name: Install Agda
5050
run: |
5151
cabal update
52-
cabal install Agda-2.7.0.1
52+
# --overwrite-policy=always: the cached ~/.cabal restore already
53+
# carries the agda symlink, so a plain install aborts with
54+
# "Path '.../bin/agda' already exists" on a warm cache.
55+
cabal install Agda-2.7.0.1 --overwrite-policy=always
5356
5457
- name: Install Agda standard library
5558
run: |
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Gates the ECHIDNA dogfood proof corpus: every theorem under proofs/{coq,lean,agda}
3+
# must type-check. These proofs had no CI coverage before this workflow -- the other
4+
# proof workflows are path-filtered to meta-checker/** (agda-meta-checker) and
5+
# src/abi/** (idris2-abi-ci), and there was no Coq or Lean workflow at all, so
6+
# regressions in proofs/ landed silently.
7+
#
8+
# Toolchains are installed with plain `run:` steps (apt / curl tarballs, matching the
9+
# idris2 + chapel workflows) rather than marketplace setup actions: a third-party
10+
# setup action (taiki-e/install-action) reproducibly tripped a startup_failure in this
11+
# workflow's context, so this workflow uses only actions/checkout plus run steps.
12+
# `just` stays the single source of truth for the commands (RSR-H14) -- CI installs it
13+
# and calls the same recipes a developer runs locally.
14+
name: Dogfood Proof Corpus
15+
16+
on:
17+
push:
18+
branches: [main]
19+
paths:
20+
- 'proofs/**'
21+
- 'Justfile'
22+
- '.github/workflows/dogfood-proofs-ci.yml'
23+
pull_request:
24+
branches: [main]
25+
paths:
26+
- 'proofs/**'
27+
- 'Justfile'
28+
- '.github/workflows/dogfood-proofs-ci.yml'
29+
workflow_dispatch:
30+
31+
concurrency:
32+
group: ${{ github.workflow }}-${{ github.ref }}
33+
cancel-in-progress: true
34+
35+
permissions:
36+
contents: read
37+
38+
jobs:
39+
coq:
40+
name: Coq
41+
runs-on: ubuntu-latest
42+
steps:
43+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
44+
45+
- name: Install Coq
46+
run: |
47+
set -euo pipefail
48+
sudo apt-get update -qq || sudo apt-get update -qq --fix-missing
49+
sudo apt-get install -y --fix-missing coq
50+
coqc --version
51+
52+
- name: Install just
53+
run: |
54+
set -euo pipefail
55+
curl -fsSL --retry 3 \
56+
"https://github.com/casey/just/releases/download/1.51.0/just-1.51.0-x86_64-unknown-linux-musl.tar.gz" \
57+
-o /tmp/just.tar.gz
58+
mkdir -p "$HOME/.local/bin"
59+
tar xzf /tmp/just.tar.gz -C "$HOME/.local/bin" just
60+
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
61+
62+
- name: Type-check Coq corpus
63+
run: just proofs-coq
64+
65+
lean:
66+
name: Lean 4
67+
runs-on: ubuntu-latest
68+
steps:
69+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
70+
71+
- name: Install elan + Lean toolchain
72+
run: |
73+
set -euo pipefail
74+
# The toolchain version is pinned by proofs/lean/lean-toolchain; lake reads
75+
# it and fetches that exact Lean on first invocation.
76+
curl -fsSL --retry 3 \
77+
https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh \
78+
-o /tmp/elan-init.sh
79+
sh /tmp/elan-init.sh -y --default-toolchain none
80+
echo "$HOME/.elan/bin" >> "$GITHUB_PATH"
81+
82+
- name: Install just
83+
run: |
84+
set -euo pipefail
85+
curl -fsSL --retry 3 \
86+
"https://github.com/casey/just/releases/download/1.51.0/just-1.51.0-x86_64-unknown-linux-musl.tar.gz" \
87+
-o /tmp/just.tar.gz
88+
mkdir -p "$HOME/.local/bin"
89+
tar xzf /tmp/just.tar.gz -C "$HOME/.local/bin" just
90+
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
91+
92+
- name: Build Lean corpus
93+
run: just proofs-lean
94+
95+
agda:
96+
name: Agda
97+
runs-on: ubuntu-latest
98+
steps:
99+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
100+
101+
- name: Install Agda + standard library
102+
run: |
103+
set -euo pipefail
104+
sudo apt-get update -qq
105+
sudo apt-get install -y agda
106+
agda --version
107+
# stdlib from GitHub, pinned to v1.7.3 (the version apt ships for the
108+
# agda 2.6.3 the corpus is verified against). apt's agda-stdlib is NOT
109+
# used: `apt --fix-missing` can silently drop it, leaving the library
110+
# unregistered ("Installed libraries: (none)"). The corpus .agda-lib in
111+
# proofs/agda is auto-detected from the working dir; this registration
112+
# resolves its `depend: standard-library`.
113+
cd /tmp
114+
curl -fsSL --retry 3 -o agda-stdlib.tar.gz \
115+
https://github.com/agda/agda-stdlib/archive/refs/tags/v1.7.3.tar.gz
116+
tar xzf agda-stdlib.tar.gz
117+
mkdir -p ~/.agda
118+
echo "/tmp/agda-stdlib-1.7.3/standard-library.agda-lib" > ~/.agda/libraries
119+
echo "standard-library" > ~/.agda/defaults
120+
121+
- name: Install just
122+
run: |
123+
set -euo pipefail
124+
curl -fsSL --retry 3 \
125+
"https://github.com/casey/just/releases/download/1.51.0/just-1.51.0-x86_64-unknown-linux-musl.tar.gz" \
126+
-o /tmp/just.tar.gz
127+
mkdir -p "$HOME/.local/bin"
128+
tar xzf /tmp/just.tar.gz -C "$HOME/.local/bin" just
129+
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
130+
131+
- name: Type-check Agda corpus
132+
run: just proofs-agda

.github/workflows/idris2-abi-ci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ on:
55
push:
66
paths:
77
- 'src/abi/**'
8+
- 'src/idris/**'
89
- '.github/workflows/idris2-abi-ci.yml'
910
pull_request:
1011
paths:
1112
- 'src/abi/**'
13+
- 'src/idris/**'
1214
- '.github/workflows/idris2-abi-ci.yml'
1315

1416
# Cause-B mitigation (#77): cancel superseded runs so stacked pushes
@@ -57,6 +59,16 @@ jobs:
5759
idris2 --build echidnaabi.ipkg
5860
echo "✓ All ABI modules type-check successfully"
5961
62+
- name: Type-check Idris2 proof validator (src/idris)
63+
run: |
64+
# Mirrors `just proofs-idris`. --typecheck (not --build) so no codegen
65+
# backend is required; the declared executable's `main` is exercised
66+
# by `idris2 --build` locally where a backend is present.
67+
cd src/idris
68+
echo "=== Type-checking ECHIDNA proof validator ==="
69+
idris2 --typecheck echidna-validator.ipkg
70+
echo "✓ Validator modules type-check successfully"
71+
6072
- name: Verify no dangerous patterns
6173
run: |
6274
echo "=== Scanning for dangerous patterns in ABI code ==="

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,12 @@ proofs/coq/**/*.vok
190190
proofs/coq/**/*.glob
191191
proofs/coq/**/.*.aux
192192
proofs/agda/**/*.agdai
193+
proofs/agda/**/dist-newstyle/
194+
proofs/lean/**/.lake/
195+
proofs/lean/**/.lia.cache
196+
proofs/lean/**/.nia.cache
197+
.lia.cache
198+
.nia.cache
193199
proofs/metamath/.metamath*
194200
target/
195201
node_modules/

Justfile

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,46 @@ test-s4-loop:
244244
@echo "Test will skip cleanly if the endpoint is unreachable."
245245
cargo test --features verisim --test s4_loop_closure -- --nocapture
246246

247+
# ── Dogfood proof corpus (proofs/{coq,lean,agda} + src/idris validator) ──
248+
# Each recipe assumes its toolchain is already installed (see `just doctor`);
249+
# CI installs the toolchains first, then calls these so local and CI run the
250+
# exact same commands.
251+
252+
# Type-check the whole dogfood proof corpus across every assistant.
253+
proofs: proofs-coq proofs-lean proofs-agda proofs-idris
254+
255+
# Compile the Coq proof corpus (proofs/coq/**/*.v).
256+
proofs-coq:
257+
#!/usr/bin/env bash
258+
set -euo pipefail
259+
cd proofs/coq
260+
for f in $(find . -name '*.v' | sort); do
261+
echo "coqc $f"
262+
coqc -q "$f"
263+
done
264+
echo "Coq corpus: all files type-check"
265+
266+
# Build the Lean 4 proof corpus via Lake (proofs/lean).
267+
proofs-lean:
268+
cd proofs/lean && lake build
269+
270+
# Type-check the Agda proof corpus (proofs/agda/*.agda).
271+
proofs-agda:
272+
#!/usr/bin/env bash
273+
set -euo pipefail
274+
# Agda writes UTF-8 to stdout and aborts under a non-UTF-8 locale (C/POSIX).
275+
export LC_ALL="${LC_ALL:-C.UTF-8}"
276+
cd proofs/agda
277+
for f in $(find . -name '*.agda' -not -path './_build/*' -not -path './dist-newstyle/*' | sort); do
278+
echo "agda $f"
279+
agda "$f"
280+
done
281+
echo "Agda corpus: all files type-check"
282+
283+
# Type-check the Idris2 validator (src/idris) — --typecheck needs no codegen backend.
284+
proofs-idris:
285+
cd src/idris && idris2 --typecheck echidna-validator.ipkg
286+
247287
# Format code
248288
fmt:
249289
cargo fmt

contractile.just

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,13 +190,10 @@ intend-list:
190190
@echo ''
191191
@echo 'Run `cat .machine_readable/contractiles/intend/Intentfile.a2ml` for the source of truth.'
192192

193-
# ── HEAL (recovery shortcuts referenced by bust/dust recipes) ─────────
194-
195-
heal:
196-
@echo 'just heal: workspace healing entry point'
197-
@cargo --version >/dev/null 2>&1 && echo ' rust toolchain OK' || echo ' rust toolchain MISSING'
198-
@julia --version >/dev/null 2>&1 && echo ' julia OK' || echo ' julia MISSING — see juliaup'
199-
@echo 'For prover binaries: just heal-provers'
193+
# ── HEAL-PROVERS (recovery shortcut referenced by bust/dust recipes) ──
194+
# NB: `heal` itself is defined in the root Justfile. Defining it here too
195+
# made `just` abort with a duplicate-recipe error across the `import?`,
196+
# which broke every `just` invocation (and thus MVP Smoke's `just mvp-env`).
200197

201198
heal-provers:
202199
@echo 'heal-provers: install missing Tier-1 prover binaries'

proofs/agda/Basic.agda

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@
88

99
module Basic where
1010

11+
-- Propositional equality at module scope (used by trans-assoc, id-left, id-right)
12+
data _≡_ {A : Set} (x : A) : A Set where
13+
refl : x ≡ x
14+
15+
infix 4 _≡_
16+
17+
-- Natural numbers at module scope (used by id-nat)
18+
data : Set where
19+
zero :
20+
suc :
21+
1122
--------------------------------------------------------------------------------
1223
-- Identity Proof
1324
--------------------------------------------------------------------------------
@@ -21,10 +32,6 @@ id x = x
2132
-- Example: identity for a specific type
2233
id-nat : (n : ℕ)
2334
id-nat = id
24-
where
25-
data ℕ : Set where
26-
zero :
27-
suc :
2835

2936
-- The identity function can also be written explicitly with a lambda
3037
id′ : {A : Set} A A
@@ -75,28 +82,14 @@ trans-assoc : {A B C D : Set}
7582
(f : A B) (g : B C) (h : C D)
7683
(h ∘ (g ∘ f)) ≡ ((h ∘ g) ∘ f)
7784
trans-assoc f g h = refl
78-
where
79-
-- Propositional equality
80-
data _≡_ {A : Set} (x : A) : A Set where
81-
refl : x ≡ x
82-
83-
infix 4 _≡_
8485

8586
-- Proof that identity is a left identity for composition
8687
id-left : {A B : Set} (f : A B) (id ∘ f) ≡ f
8788
id-left f = refl
88-
where
89-
data _≡_ {A : Set} (x : A) : A Set where
90-
refl : x ≡ x
91-
infix 4 _≡_
9289

9390
-- Proof that identity is a right identity for composition
9491
id-right : {A B : Set} (f : A B) (f ∘ id) ≡ f
9592
id-right f = refl
96-
where
97-
data _≡_ {A : Set} (x : A) : A Set where
98-
refl : x ≡ x
99-
infix 4 _≡_
10093

10194
--------------------------------------------------------------------------------
10295
-- Additional Basic Combinators
@@ -125,13 +118,9 @@ infixr 0 _$_
125118
--------------------------------------------------------------------------------
126119

127120
module CombinatorLaws where
128-
data _≡_ {A : Set} (x : A) : A Set where
129-
refl : x ≡ x
130-
131-
infix 4 _≡_
132-
133121
-- SKK = I (a famous combinator identity)
134-
SKK : {A : Set} (x : A) S const const x ≡ id x
122+
-- The second const needs B instantiated explicitly to resolve the implicit argument.
123+
SKK : {A : Set} (x : A) S const (const {B = A}) x ≡ id x
135124
SKK x = refl
136125

137126
-- Flip is involutive (applying it twice gets you back where you started)
@@ -164,9 +153,6 @@ uncurry f (x , y) = f x y
164153

165154
-- Proof that curry and uncurry are inverses
166155
module CurryUncurryLaws where
167-
data _≡_ {A : Set} (x : A) : A Set where
168-
refl : x ≡ x
169-
170156
-- INTENTIONAL AXIOM: Function extensionality (funext)
171157
-- Justification: funext is consistent with Agda's type theory and is
172158
-- provable in Cubical Agda (--cubical). In plain Agda it must be

proofs/agda/DispatchOrdering.agda

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ module DispatchOrdering where
1414
open import Data.Fin using (Fin; zero; suc; toℕ; _<_)
1515
open import Data.Fin.Properties
1616
using (<-irrefl; <-trans; <-cmp; <-isStrictTotalOrder)
17-
open import Data.Nat.Base using (z<s; s<s)
17+
open import Data.Nat.Base using (z≤n; ss)
1818
open import Relation.Binary.Definitions
1919
using (Irreflexive; Transitive; Trichotomous; Asymmetric)
2020
open import Relation.Binary.Structures
@@ -79,26 +79,26 @@ stage-strictTotalOrder = <-isStrictTotalOrder
7979

8080
-- Integrity strictly precedes Sandbox.
8181
integrity-before-sandbox : Integrity < Sandbox
82-
integrity-before-sandbox = z<s
82+
integrity-before-sandbox = s≤s z≤n
8383

8484
-- Integrity strictly precedes Verify.
8585
integrity-before-verify : Integrity < Verify
86-
integrity-before-verify = z<s
86+
integrity-before-verify = s≤s z≤n
8787

8888
-- Integrity strictly precedes Certs.
8989
integrity-before-certs : Integrity < Certs
90-
integrity-before-certs = z<s
90+
integrity-before-certs = s≤s z≤n
9191

9292
-- Integrity strictly precedes Axioms.
9393
integrity-before-axioms : Integrity < Axioms
94-
integrity-before-axioms = z<s
94+
integrity-before-axioms = s≤s z≤n
9595

9696
-- Integrity strictly precedes Confidence.
9797
integrity-before-confidence : Integrity < Confidence
98-
integrity-before-confidence = z<s
98+
integrity-before-confidence = s≤s z≤n
9999

100100
-- The general statement: for any stage that is not Integrity, Integrity precedes it.
101-
-- We pattern-match: zero would give h refl : ⊥ (absurd); any suc s gives z<s.
101+
-- We pattern-match: zero would give h refl : ⊥ (absurd); any suc s gives s≤s z≤n.
102102
integrity-precedes : (s : Stage) Integrity ≢ s Integrity < s
103103
integrity-precedes zero h = ⊥-elim (h refl)
104-
integrity-precedes (suc s) _ = z<s
104+
integrity-precedes (suc s) _ = s≤s z≤n

0 commit comments

Comments
 (0)