You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
proofs(idris2): close all proof holes at the root — 0 holes, 0 new axioms (#151) (#152)
## What & why
Resolves the **root** of #151 (the Idris2 propositional-`Equiv` /
follow-on work): the Idris2 ABI proof layer previously built but carried
**17 `?holes`** standing in for unproven obligations. This PR discharges
**every one** with a real, total, machine-checked term.
- `idris2 --build valence-shell.ipkg` builds green under `--total`.
- `grep -rohE '\?[A-Za-z_][A-Za-z0-9_]*' proofs/idris2/src
--include='*.idr'` → **0** (was 17).
- Verified locally against a from-source **Idris2 0.8.0 (Chez)**
toolchain, mirroring `idris-verification.yml`.
- `check-idris2-believe-me.sh` passes: **2** registered axioms,
unchanged.
**No new axioms were added.** Where a stated theorem was a genuine
non-theorem in the ordered-list model, its *signature* was redesigned to
the true statement rather than closed with `believe_me`, following the
#60/#61/#119 precedent.
## How each hole was closed
| Theorem | Closure |
|---|---|
| `mkdirRmdirReversible` | `removeAddAbsent`; rmdir applicability is now
an explicit precondition (mkdir does not preclude orphan children) |
| `touchRmReversible` | `removeAddAbsent` + unconditional
`RmPrecondition` after touch |
| `rmdirMkdirReversible`, `rmTouchReversible` | canonical-form
precondition + `cong MkFS` (restore direction is not injective in
general) |
| `writeFileReversible` | `updateOverwrite` + `updateCanonicalId` |
| `operationIndependence` | restated `=`→`Equiv` via `equivAddSwap` (the
`=` version was a non-theorem — list order differs) |
| `cnoWriteSameContent` | canonical-form precondition +
`updateCanonicalId` + `equivRefl` |
| `sequenceReversible` | induction over a new `TraceReversible` witness
(replaces the vacuous `isReversible = True`) |
| `compositionReversible` | genuine per-step reversibility hypotheses
(the `isReversible = True` gates were vacuous) |
| `undoRedoIdentity` | `opInvOpId` + an `Applicable` precondition |
| `undoRedoComposition` | induction over a new `Undoable` witness +
`Maybe`-monad laws (`applyNSnoc`, `bindAssoc`, `bindCong`) |
| `overwriteIrreversible`, `hardwareEraseIrreversible` | redesigned to
non-injectivity (information loss); prior `recovery … = Nothing` / `… ->
Void` shapes were refutable |
`Model.idr` gains a proved structural lemma kit (`removeAbsentId`,
`removeAddAbsent`, `filterIdem`, `updateOverwrite`, `updateCanonicalId`,
`removeAddRemove`, `equivSwapHead`, `equivAddSwap`, …), and
`addEntry`/`removeEntry`/`updateEntry` are promoted to `public export`
so downstream modules can compute with them.
## The 2 remaining axioms
`axStringEqRefl` / `axBits8EqRefl` (`Filesystem.Axioms`) are the
**irreducible primitive-`String`/`Bits8` equality boundary** in
intensional type theory — morally identical to Idris2's own `DecEq
String` internals (which also rest on `believe_me`) and to Agda's
`postulate funext`. Eliminating them would require an inductive
(non-primitive) component representation, trading a standard axiom for
unnatural encoding overhead; deliberately not done. Notably, the
restore-cluster theorems were closed with canonical-form preconditions
**specifically so that no `==`→`=` soundness axiom was needed**.
## Honest frontier (unchanged model limitation, documented)
The fully-general restore-cluster theorems (arbitrary in-list position
with uniqueness, rather than canonical head form) would require a
`NoDupKeys` well-formedness invariant on the filesystem. This is
recorded in `PROOF-NEEDS.md` / `proofs/idris2/README.md` as the one
remaining model strengthening for this layer.
## Docs & tooling
Updated `PROOF-NEEDS.md`, `proofs/idris2/README.md`,
`docs/PROOF-NARRATIVE.adoc`, `docs/PROOF_HOLES_AUDIT.md`, `CLAUDE.md`,
`.machine_readable/IDRIS2_AXIOMS.a2ml` to reflect 0 holes. Also fixed a
pre-existing `just verify-idris2` recipe bug (recipe used make-style
`$$`, which this `just` passes to the shell as the PID) so the hole
count prints correctly.
## Test plan
```
cd proofs/idris2 && idris2 --build valence-shell.ipkg # green under --total
just verify-idris2 # Distinct holes: 0
.github/scripts/check-idris2-believe-me.sh # 2 axioms, pass
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01KfgJznd6jzSeDYsSXGAXkU
---
_Generated by [Claude
Code](https://claude.ai/code/session_01KfgJznd6jzSeDYsSXGAXkU)_
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: PROOF-NEEDS.md
+36-10Lines changed: 36 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,20 +31,46 @@
31
31
| Coq | (closed) `obliterate_not_injective`|`rmo_operations.v`| Closed via threaded strengthened `Hgeom` through `multi_pass_same_start_same_result` (#58 closed — only standard funext) |
32
32
| Idris2 |`axStringEqRefl` (primitive-eq axiom) |`proofs/idris2/src/Filesystem/Axioms.idr:42`|`believe_me`-backed; registered in `.machine_readable/IDRIS2_AXIOMS.a2ml`; CI-gated via `.github/scripts/check-idris2-believe-me.sh` (Q1-C pilot 2026-06-02 PM) |
|`Model.idr`| 0 (`equivSym` closed via constructor-swap on the propositional form; `equivRefl` + `equivTrans` closed structurally via `Data.List.Quantifiers` Q5-option-3 migration) | 0 |
43
-
|`RMO.idr`| 3 (`overwriteIrreversibleProof`, `hardwareEraseIrreversibleProof`, `auditTrailCompletenessProof`; `appendOnlyAuditLogProof` is closed via `Refl`) | 0 |
44
-
45
-
Drift from previous PROOF-NEEDS.md tally (22 holes) to current (16 holes) is mechanical: `equivSymProof` and `appendOnlyAuditLogProof` closed silently during the 2026-06-02 morning sweep (visible by grep but the inventory text was not updated). No body changes — this paragraph reconciles the count.
46
-
47
-
All `partial` markers in `proofs/idris2/src/Filesystem/*.idr` were cleared 2026-06-02 (PRs #108 + #109, closing #89). The total `partial` count is zero.
| `RMO.idr` | 82 | `secureDeleteNotInjective` (was `?secureDeleteIrreversibleProof`) | CLOSED 2026-06-01 (#60) — signature redesigned to mirror Coq's `obliterate_not_injective`. The prior `recovery fs = fs -> Void` shape was a non-theorem (refuted by `recovery = id`). Closes via `removeEntryDeterminedByFilter` in `Filesystem.Model`.
507
-
| `RMO.idr` | 112 | `?overwriteIrreversibleProof` | PARTIAL — depends on the *information-theoretic random data* assumption (random data of sufficient length destroys information about the original).
508
-
| `RMO.idr` | 178 | `gdprDeletionCompliant` (was `?gdprDeletionCompliantProof`) | CLOSED 2026-06-01 (#61) — signature redesigned to mirror Coq's `obliterate_leaves_no_trace` shape. The prior `recovery = id` shape was a non-theorem (refuted by `recovery = const empty`). Compliance is now a structural property of the deletion record (carries an obliteration witness for the deleted path).
509
-
| `RMO.idr` | 201 | `?hardwareEraseIrreversibleProof` | PARTIAL — depends on a *physical hardware* assumption.
| `mkdirRmdirReversible` | `removeAddAbsent`; rmdir applicability made an explicit precondition (mkdir does not preclude orphan children).
499
+
| `touchRmReversible` | `removeAddAbsent` + unconditional `RmPrecondition` after touch.
500
+
| `rmdirMkdirReversible`, `rmTouchReversible` | canonical-form precondition + `cong MkFS` — the restore direction is not injective in general (a shadowed duplicate key would be lost).
0 commit comments