Skip to content

Commit a360533

Browse files
hyperpolymathclaude
andcommitted
fix(proofs): census reads logical roots from _CoqProject; restore FilesystemCNO.lean pending #167
Cause 1 (#176): proofs/coq/census-assumptions.sh hardcoded `CNO.` for every theory's Require/Print Assumptions statement. `_CoqProject` binds `malbolge` to the logical root `Malbolge`, not `CNO`, so the generated Census.v driver died with "Cannot find a physical path bound to logical path CNO.MalbolgeCore." The script now reads each directory's root from _CoqProject's own `-R <dir> <Root>` lines; a directory with no `-R` binding is a hard census failure, never a silent skip. Cause 1b (found while fixing #176, masked by the above): the census's awk parser matched coqc's echoed `Print Assumptions X.` command to attribute each verdict to a theory — but coqc never echoes that command in batch mode, so the per-theory table was silently empty (only the two-cause bug's early exit had hidden this). The parser now walks a recorded emission order instead and asserts in its END block that every verdict was consumed exactly once and closed+axiom-dependent sums to the theorem total. Cause 2 (#176): #174 (b7c780f) claimed to finish the #167 Lean port of FilesystemCNO.lean but it does not compile in the six-module job (unresolved Directory/Symlink alternatives, unknown identifiers, failed rewrites). FilesystemCNO.lean and its paired AxiomAudit.lean guards are restored to b7c780f^ (byte-identical to 877ede2, the last green main run) — the last revision that compiled. #167 stays open; finishing the port is its own acceptance criterion, not re-opened here. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QYY8Gp4v4x2J7iSNn1vZ57
1 parent b7c780f commit a360533

4 files changed

Lines changed: 265 additions & 416 deletions

File tree

‎PROOF-STATUS.adoc‎

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -184,17 +184,27 @@ capstone) remains open by design — see `docs/OND-ROADMAP.adoc`.
184184
signature, the three occupancy predicates in full, the #125 derivations as
185185
negative controls, and `#print axioms` for every theorem (no `sorryAx` anywhere).
186186
`just verify-lean-core` runs the same script locally.
187-
* **FilesystemCNO ported from Coq (issue #167):**
188-
`FilesystemCNO.lean` defines `Filesystem` as a concrete list structure and operations
189-
as executable functions (`mkdir`, `rmdir`, `create`, `unlink`, `readFile`, `writeFile`,
190-
`stat`, `chmod`, `chown`, `rename`, `snapshot`, `restore`). All 21 former axioms
191-
(`mkdir_rmdir_inverse`, `create_unlink_inverse`, `rename_inverse`, `read_write_identity`,
192-
`chmod_identity`, `rename_identity`, `mkdir_not_identity`, `mkdir_idempotent`,
193-
`snapshot_restore_identity`, and the 12 primitive op declarations) are fully discharged
194-
to concrete definitions and proved theorems. `AxiomAudit.lean` verifies that all
195-
FilesystemCNO theorems depend on zero axioms.
196-
Lean axiom count: `FilesystemCNO` 21 → **0**, `LambdaCNO` 3 → 1
187+
* **Issue #125 fixed — the Lean axioms no longer derive `False`:**
188+
`FilesystemCNO.lean` stated `mkdir_rmdir_inverse`, `create_unlink_inverse` and
189+
`rename_inverse` without the occupancy preconditions of the Coq lemmas they mirror;
190+
with `mkdir_idempotent` and `mkdir_not_identity` that proved `False`. They now
191+
carry `noDirAt` / `noFileAt` / `noEntryAt`, mirrored verbatim from
192+
`proofs/coq/filesystem/FilesystemCNO.v`, and the unconditional statement is refuted
193+
in-file (`unconditional_mkdir_rmdir_inverse_is_false`). `LambdaCNO.lean` carried the
194+
unrestricted `eta_equivalence` axiom (false as stated, the same `LVar 5`
195+
counterexample the Coq side documents above); it is now the proved
196+
`noLambda`-guarded theorem, `subst_closed_term` is proved, and the unrestricted
197+
claim is refuted (`unrestricted_eta_equivalence_is_false`). Lean axiom count:
198+
`FilesystemCNO` 21 → 21 (same names, three strengthened), `LambdaCNO` 3 → 1
197199
(`y_combinator_not_identity`, the Lean twin of Coq's class-A `y_not_cno`).
200+
* **#167 port reverted pending completion (issue #176):** #174 attempted to port
201+
`FilesystemCNO.lean`'s 21 axioms to concrete definitions and proved theorems, but
202+
the port did not compile in the six-module job (unresolved `Directory`/`Symlink`
203+
alternatives, unknown identifiers, failed rewrites). Per #176's ruling, a half-port
204+
must not sit red on `main`: `FilesystemCNO.lean` and its paired `AxiomAudit.lean`
205+
guards are restored here to the revision above (their last state that compiled,
206+
identical to the pre-#174 commit and to the last green `main` run before #174).
207+
#167 stays open with finishing the port as its own acceptance criterion.
198208

199209
== Z3 — VERIFIED (this environment)
200210

@@ -240,7 +250,13 @@ capstone) remains open by design — see `docs/OND-ROADMAP.adoc`.
240250
of 182 top-level theorems across the 14 theories, exactly **109 are closed under
241251
the global context** (zero axioms), and 73 rest on Coq stdlib classical axioms
242252
(`ClassicalDedekindReals.*`, `FunctionalExtensionality.*`, `Classical_Prop.classic`,
243-
`ProofIrrelevance.*`) and/or the tagged project parameters.
253+
`ProofIrrelevance.*`) and/or the tagged project parameters. Each theory's logical
254+
root is read from `_CoqProject`'s own `-R <dir> <Root>` bindings rather than
255+
hardcoded (issue #176: the census previously assumed every theory lived under
256+
`CNO.`, which is false for `malbolge/` — bound to `Malbolge` — and made the
257+
generated driver fail outright instead of censusing it; the table now shows
258+
`Malbolge.MalbolgeCore | 7 | 7 | 0`). A directory with no `-R` binding is a hard
259+
census failure, never a silent skip.
244260
* All top-level declarations are verified by `proofs/coq/check-axiom-tags.sh` to carry
245261
a unified tag grammar: `(* AXIOM: [METAL-BOUNDARY] ... *)` for physical constants
246262
and laws, or `(* AXIOM: [CLASS-A] ... *)` for provable-in-principle mathematics.

‎proofs/coq/census-assumptions.sh‎

Lines changed: 78 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,32 @@ set -uo pipefail
1717
HERE="$(cd "$(dirname "$0")" && pwd)"
1818
AUDIT_FILE="${1:-}"
1919

20-
# Find all 14 theories under proofs/coq
20+
# Logical root for each theory directory, read from _CoqProject (`-R <dir> <Root>`)
21+
# rather than hardcoded — issue #176: the census used to assume every theory lived
22+
# under `CNO.`, which is false for malbolge/ (`-R malbolge Malbolge`) and made the
23+
# generated driver fail outright instead of censusing it.
24+
declare -A dir_root
25+
while read -r flag dir ns; do
26+
[ "$flag" = "-R" ] && dir_root["$dir"]="$ns"
27+
done < "$HERE/_CoqProject"
28+
29+
# Find all 14 theories under proofs/coq, resolving each theory's logical root.
30+
# A directory with no `-R` binding in _CoqProject is a hard error, never a silent
31+
# skip — a skip here would turn a missing binding into a vacuous pass.
2132
theories=()
33+
declare -A base_root
2234
for d in common category quantum lambda filesystem physics ond malbolge; do
2335
if [ -d "$HERE/$d" ]; then
36+
root="${dir_root[$d]:-}"
37+
if [ -z "$root" ]; then
38+
echo "CENSUS FAILED: directory '$d' has no -R binding in _CoqProject" >&2
39+
exit 1
40+
fi
2441
while IFS= read -r f; do
25-
[ -f "$f" ] && theories+=("$f")
42+
if [ -f "$f" ]; then
43+
theories+=("$f")
44+
base_root["$(basename "${f%.v}")"]="$root"
45+
fi
2646
done < <(find "$HERE/$d" -maxdepth 1 -name "*.v" | sort)
2747
fi
2848
done
@@ -48,15 +68,17 @@ if command -v coqc >/dev/null 2>&1 && [ -f "$HERE/common/CNO.vo" ]; then
4868
tmp="$(mktemp -d "${TMPDIR:-/tmp}/az-census.XXXXXX")"
4969
trap 'rm -rf "$tmp"' EXIT
5070

51-
# Generate Census.v
71+
# Generate Census.v — each theory is Required under its own logical root
72+
# (from _CoqProject), not a hardcoded `CNO.`.
5273
{
5374
echo "(* Auto-generated by census-assumptions.sh *)"
5475
for f in "${theories[@]}"; do
5576
base="$(basename "${f%.v}")"
56-
echo "Require CNO.$base."
77+
echo "Require ${base_root[$base]}.$base."
5778
done
5879
for t in "${thm_lines[@]}"; do
59-
echo "Print Assumptions CNO.$t."
80+
base="${t%%.*}"
81+
echo "Print Assumptions ${base_root[$base]}.$t."
6082
done
6183
} > "$tmp/Census.v"
6284

@@ -73,29 +95,42 @@ if command -v coqc >/dev/null 2>&1 && [ -f "$HERE/common/CNO.vo" ]; then
7395
exit 1
7496
fi
7597

76-
# Parse census output
98+
# `coqc` does NOT echo the `Print Assumptions X.` command back in its output —
99+
# it prints only the verdict ("Closed under the global context" or "Axioms:"
100+
# + the axiom list). So the theorem each verdict belongs to cannot be read off
101+
# the coqc output; it is read off the ORDER the Print Assumptions calls were
102+
# emitted into Census.v instead, which is exactly thm_lines' order. The order
103+
# file lists each theorem as "root.base.thm" so the table can key rows by
104+
# "root.base" (issue #176 criterion: malbolge/ theorems shown under `Malbolge.`,
105+
# not folded into a bare basename column that hides the root entirely).
106+
for t in "${thm_lines[@]}"; do
107+
base="${t%%.*}"
108+
echo "${base_root[$base]}.$t"
109+
done > "$tmp/order.txt"
110+
111+
# Parse census output against the order file. END asserts every emitted verdict
112+
# was consumed exactly once and the closed/axiom-dependent split accounts for
113+
# every theorem — a positive control that the block-to-theorem mapping is 1:1,
114+
# not a hopeful zip. A mismatch fails the gate (script exits with awk's rc, not
115+
# an unconditional 0).
77116
printf '%s\n' "$out" | awk -v total="$total_theorems" '
78-
BEGIN {
79-
current_thm = ""
80-
in_axioms = 0
81-
}
82-
/^Print Assumptions/ {
83-
current_thm = $3
84-
sub(/\.$/, "", current_thm)
85-
split(current_thm, p, ".")
86-
theory = p[2]
87-
thm = p[3]
88-
thms_per_theory[theory]++
89-
in_axioms = 0
90-
next
91-
}
117+
NR == FNR { order[++n] = $0; next }
118+
FNR == 1 { idx = 0; in_axioms = 0 }
92119
/^Closed under the global context/ {
120+
idx++
121+
split(order[idx], p, ".")
122+
theory = p[1] "." p[2]
123+
thms_per_theory[theory]++
93124
closed_per_theory[theory]++
94125
total_closed++
95126
in_axioms = 0
96127
next
97128
}
98129
/^Axioms:/ {
130+
idx++
131+
split(order[idx], p, ".")
132+
theory = p[1] "." p[2]
133+
thms_per_theory[theory]++
99134
axiom_dep_per_theory[theory]++
100135
total_dep++
101136
in_axioms = 1
@@ -108,21 +143,39 @@ if command -v coqc >/dev/null 2>&1 && [ -f "$HERE/common/CNO.vo" ]; then
108143
next
109144
}
110145
END {
146+
if (idx != total) {
147+
printf "CENSUS FAILED: %d verdict blocks parsed, expected %d theorems\n", idx, total > "/dev/stderr"
148+
exit 1
149+
}
150+
if (total_closed + total_dep != total) {
151+
printf "CENSUS FAILED: closed(%d) + axiom-dependent(%d) != total(%d)\n", total_closed, total_dep, total > "/dev/stderr"
152+
exit 1
153+
}
111154
printf "\n== Census: %d top-level theorems across 14 theories ==\n", total
112155
printf "Closed under global context: %d\nAxiom-dependent: %d\n\n", total_closed, total_dep
113-
printf "| %-22s | %-8s | %-6s | %-15s |\n", "Theory", "Theorems", "Closed", "Axiom-Dependent"
114-
printf "|------------------------|----------|--------|-----------------|\n"
115-
for (t in thms_per_theory) {
156+
printf "| %-24s | %-8s | %-6s | %-15s |\n", "Theory", "Theorems", "Closed", "Axiom-Dependent"
157+
printf "|--------------------------|----------|--------|-----------------|\n"
158+
# Manual sort (no asorti — that is a gawk extension, and the CI runner is
159+
# not guaranteed to alias /usr/bin/awk to gawk).
160+
n_rows = 0
161+
for (t in thms_per_theory) sorted[++n_rows] = t
162+
for (i = 1; i <= n_rows; i++)
163+
for (j = i + 1; j <= n_rows; j++)
164+
if (sorted[j] < sorted[i]) { tmp = sorted[i]; sorted[i] = sorted[j]; sorted[j] = tmp }
165+
for (i = 1; i <= n_rows; i++) {
166+
t = sorted[i]
116167
c = closed_per_theory[t] + 0
117168
d = axiom_dep_per_theory[t] + 0
118-
printf "| %-22s | %-8d | %-6d | %-15d |\n", t, thms_per_theory[t], c, d
169+
printf "| %-24s | %-8d | %-6d | %-15d |\n", t, thms_per_theory[t], c, d
119170
}
120171
printf "\n== Axioms in non-closed blocks ==\n"
121172
for (ax in axiom_counts) {
122173
printf " %-50s : %d\n", ax, axiom_counts[ax]
123174
}
124175
}
125-
'
176+
' "$tmp/order.txt" -
177+
rc=$?
178+
exit "$rc"
126179
else
127180
# Static / pre-computed census display when coqc / .vo is not yet built
128181
echo "== Census: $total_theorems top-level theorems across 14 theories =="

‎proofs/lean4/AxiomAudit.lean‎

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -519,27 +519,35 @@ info: 'FilesystemCNO.fs_nop_is_cno' does not depend on any axioms
519519
#guard_msgs (whitespace := lax) in #print axioms fs_nop_is_cno
520520

521521
/--
522-
info: 'FilesystemCNO.mkdir_rmdir_is_cno' does not depend on any axioms
522+
info: 'FilesystemCNO.mkdir_rmdir_is_cno' depends on axioms: [FilesystemCNO.mkdir,
523+
FilesystemCNO.mkdir_rmdir_inverse,
524+
FilesystemCNO.rmdir]
523525
-/
524526
#guard_msgs (whitespace := lax) in #print axioms mkdir_rmdir_is_cno
525527

526528
/--
527-
info: 'FilesystemCNO.create_unlink_is_cno' does not depend on any axioms
529+
info: 'FilesystemCNO.create_unlink_is_cno' depends on axioms: [FilesystemCNO.create,
530+
FilesystemCNO.create_unlink_inverse,
531+
FilesystemCNO.unlink]
528532
-/
529533
#guard_msgs (whitespace := lax) in #print axioms create_unlink_is_cno
530534

531535
/--
532-
info: 'FilesystemCNO.read_write_is_cno' does not depend on any axioms
536+
info: 'FilesystemCNO.read_write_is_cno' depends on axioms: [FilesystemCNO.readFile,
537+
FilesystemCNO.read_write_identity,
538+
FilesystemCNO.writeFile]
533539
-/
534540
#guard_msgs (whitespace := lax) in #print axioms read_write_is_cno
535541

536542
/--
537-
info: 'FilesystemCNO.chmod_nop_is_cno' does not depend on any axioms
543+
info: 'FilesystemCNO.chmod_nop_is_cno' depends on axioms: [FilesystemCNO.chmod,
544+
FilesystemCNO.chmod_identity,
545+
FilesystemCNO.stat]
538546
-/
539547
#guard_msgs (whitespace := lax) in #print axioms chmod_nop_is_cno
540548

541549
/--
542-
info: 'FilesystemCNO.rename_nop_is_cno' does not depend on any axioms
550+
info: 'FilesystemCNO.rename_nop_is_cno' depends on axioms: [FilesystemCNO.rename, FilesystemCNO.rename_identity]
543551
-/
544552
#guard_msgs (whitespace := lax) in #print axioms rename_nop_is_cno
545553

@@ -549,7 +557,7 @@ info: 'FilesystemCNO.fs_cno_composition' does not depend on any axioms
549557
#guard_msgs (whitespace := lax) in #print axioms fs_cno_composition
550558

551559
/--
552-
info: 'FilesystemCNO.mkdir_alone_not_cno' does not depend on any axioms
560+
info: 'FilesystemCNO.mkdir_alone_not_cno' depends on axioms: [FilesystemCNO.mkdir, FilesystemCNO.mkdir_not_identity]
553561
-/
554562
#guard_msgs (whitespace := lax) in #print axioms mkdir_alone_not_cno
555563

@@ -559,12 +567,17 @@ info: 'FilesystemCNO.valence_reversible_pair_is_cno' does not depend on any axio
559567
#guard_msgs (whitespace := lax) in #print axioms valence_reversible_pair_is_cno
560568

561569
/--
562-
info: 'FilesystemCNO.snapshot_restore_is_cno' does not depend on any axioms
570+
info: 'FilesystemCNO.snapshot_restore_is_cno' depends on axioms: [FilesystemCNO.restore,
571+
FilesystemCNO.snapshot,
572+
FilesystemCNO.snapshot_restore_identity]
563573
-/
564574
#guard_msgs (whitespace := lax) in #print axioms snapshot_restore_is_cno
565575

566576
/--
567-
info: 'FilesystemCNO.unconditional_mkdir_rmdir_inverse_is_false' does not depend on any axioms
577+
info: 'FilesystemCNO.unconditional_mkdir_rmdir_inverse_is_false' depends on axioms: [FilesystemCNO.mkdir,
578+
FilesystemCNO.mkdir_idempotent,
579+
FilesystemCNO.mkdir_not_identity,
580+
FilesystemCNO.rmdir]
568581
-/
569582
#guard_msgs (whitespace := lax) in #print axioms unconditional_mkdir_rmdir_inverse_is_false
570583
end
@@ -650,6 +663,14 @@ run_cmd do
650663
let modules : Array Name := #[`CNO, `OND, `CNOCategory, `CNOBridge, `FilesystemCNO, `LambdaCNO]
651664
let allowed : Array Name := #[
652665
`propext, `Quot.sound,
666+
`FilesystemCNO.mkdir, `FilesystemCNO.rmdir, `FilesystemCNO.create,
667+
`FilesystemCNO.unlink, `FilesystemCNO.readFile, `FilesystemCNO.writeFile,
668+
`FilesystemCNO.chmod, `FilesystemCNO.stat, `FilesystemCNO.rename,
669+
`FilesystemCNO.mkdir_rmdir_inverse, `FilesystemCNO.create_unlink_inverse,
670+
`FilesystemCNO.read_write_identity, `FilesystemCNO.chmod_identity,
671+
`FilesystemCNO.rename_identity, `FilesystemCNO.mkdir_not_identity,
672+
`FilesystemCNO.snapshot, `FilesystemCNO.restore,
673+
`FilesystemCNO.snapshot_restore_identity, `FilesystemCNO.mkdir_idempotent,
653674
`LambdaCNO.y_combinator_not_identity
654675
]
655676
let mut checked := 0

0 commit comments

Comments
 (0)