ltl-accumulator-verified/verification/check.sh

739 lines
41 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────────
# check.sh — THE button (accumulator corpus). Same discipline as the
# *-ed25519-verified repos: compiles every shipped .lean through lean-guard
# and axiom-audits every certificate against its DOCUMENTED exact cone,
# both directions.
#
# Phases: 0 resource/integrity · 1 stub+axiom-smuggling audit ·
verification: bind statements and specification bodies (P1-a); un-stale the fidelity pin STATEMENT BINDING (Phase 3d). The coverage gate pins every constant's name, kind and axiom cone, both directions, and none of selftest_audit.sh's nine attacks defeat it. It is nevertheless blind to what a declaration SAYS — and that is demonstrated here rather than argued: Wrapping one branch of `LTLAcc.pinAccept`'s body in `id (…)` is definitionally equal. Every downstream proof still compiles. The name, the kind, the type and the axiom cone are unchanged. The inventory gate reports "222 constants, environment == allowlist" — GREEN. That edit is harmless by construction; the point is that nothing stood between it and a genuinely vacuous redefinition of a specification. Proofs/Inventory.lean now also emits, for every inventoried constant, its fully-elaborated TYPE, and for every definition its fully-elaborated BODY — 266 lines over 222 constants. Proof terms are deliberately absent: by proof irrelevance a theorem's content is its statement. check.sh Phase 3d binds the SHA-256 and the block is committed as AUDIT-MANIFEST.txt so a mismatch is DIFFED, not merely reported. The existing gate is untouched, per the standing rule that the port flows FROM this repo, not to it: INV lines are byte-identical, inventory_gate.sh is unchanged, and all nine of its attacks still fail as before. selftest_statements.sh replays the defeq edit as case 1, asserting BOTH that the coverage gate passes it and that Phase 3d catches it — so if the coverage gate ever grows to see this, the test says so instead of quietly re-labelling. Cases 2-4 cover a hand-edited committed block, a truncated block, and a constant inventoried without a statement. FIDELITY PIN (unrelated, found while running the button). Phase 4 had been failing since 2026-07-23: LIED_PIN_DIV expected 3,867 divergences between the Lean model and the deployed consistency verifier, and observed 0. Cause is pacta ddbb5a4, which restored the RFC 9162 2.1.4.2 Step-7 terminal `sn == 0` condition; that one conjunct removes every divergence in the pinned 73,573-case family. KNOWN-GAPS gap 14 already recorded the closure on the day it landed — only this constant was stale, so the button had been red for five days with nobody running it. The pin now reads 0 with the history in a comment. Nothing about the paper, public log entry 13, or the attested commit 172a1d0 changes; the historical divergence stays reproducible at the tagged pre-fix commit. KNOWN-GAPS gap 16 records what the binding does not buy: identity, not meaning; an author who edits and re-pins in one commit is caught by review and not by the script; and proof terms are unbound by design. Button green end to end: ATTESTATION GREEN (Lean + fidelity). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 07:07:13 +00:00
# 2 compile manifest · 3 boundary-exact axiom audit ·
# 3b environment-derived coverage · 3c doc-consistency ·
# 3d statement + specification binding · 4 definition fidelity
# ─────────────────────────────────────────────────────────────────────────────
set -euo pipefail
Review round 4: F1* absorbed (lied-size boundary), acceptCons_sound, kit reproducibility Round-3 verdicts: GPT-5.6 conditionally approves (blockers closed, one portability finding); the Claude reviewer's Socratic addendum produced F1*, the strongest finding of the series — deployed verify_consistency and mechanized ConsRec are NOT extensionally equal. Reproduced exactly (witness verify_consistency(1,3,R2,R3,P(2→3))=True vs ConsRec reject; 3,405 divergences n<60; strictly one-sided; power-of-two seeding mechanism confirmed in source). - KNOWN-GAPS gap 14: witness, mechanism, one-sidedness, and the pinned-pair side condition under which Theorem 3 transfers to the deployed verifier (pacta's pin-store flow supplies it by construction). No pacta code change; deployed behavior matches upstream RFC 9162 implementations. - fidelity: lied-size family — 73,573 boundary cases, 3,867 expected divergences PINNED, one-sided direction asserted per case. Banner rescoped: agreement over pinned families, not extensional equality. - Theorem3.lean: acceptCons_sound (F2) — soundness over the named acceptCons predicate, n₀=0 discharged from the non-prefix premise, size bound derived from acceptance via new consRec_some_le. Cones read from #print axioms; CONES/AxiomCheck/allowlist updated (218 → 222 constants, diff = the two theorems + two generated auxiliaries). - F3/GPT§7: verification/lean-toolchain pin + run_bare.sh (reviewer's standalone runner, plain public lean — verified green: 61 cones, 222 constants, gate green) + AENEAS_ENV override in check.sh and selftest_audit.sh. - F4: awk field-equality replaces regex-with-dots in Phase 3b. - F5: git-tracked .pyc removed (worse than reported — it was in the repo, not just the kit); __pycache__ gitignored; round-4 kit ships a corpus MANIFEST.sha256 + pinned commit (also GPT's governance condition). check.sh exit 0, ATTESTATION GREEN; selftest exit 0, 9/9 + control. Live LTL untouched (12 leaves, bcd15f9d…); attestation still gated on ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 13:07:57 +00:00
# Toolchain bootstrap is overridable for reviewers with their own install
# (review round 3, GPT §7); the operator default stays pinned.
AENEAS_ENV="${AENEAS_ENV:-$HOME/aeneas-toolchain/env.sh}"
[ -f "$AENEAS_ENV" ] || { echo "FATAL: Aeneas environment not found: $AENEAS_ENV (set AENEAS_ENV; or use run_bare.sh with a plain lean per lean-toolchain)"; exit 1; }
source "$AENEAS_ENV"
HERE="$(cd "$(dirname "$0")" && pwd)"
AENEAS_LEAN="$AENEAS_HOME/backends/lean"
TIMEOUT="${LEAN_TIMEOUT:-600}"
export LEAN_MEM_MB="${LEAN_MEM_MB:-4096}"
CORES="${LEAN_MAX_CORES:-0-3}"
GEN_MODULES=( LTLAcc/HashExternal )
PROOFS=( Basic Completeness Extract Descent Consistency Binding3 Refactor Theorem3 PinStore )
P2-b: close classes 9 and 15 — the instruments, and the places nothing looked CLASS 15 — a Lean file where no phase was looking. The dead-file scan read Proofs/*.lean and gen/LTLAcc/*.lean and nothing else. A module at the verification root, or under any other gen/ subdirectory, was neither compiled nor rejected — while remaining importable by name, since LEAN_PATH contains both roots. That is a source of the corpus that no phase reads and no pin covers, which is exactly what the dead-file gate exists to forbid; it was simply looking in two places instead of everywhere. Now nothing may live in either root but the two enumerated sets. CLASS 9 — the instruments' own declaration surface. AxiomCheck.lean and Inventory.lean perform the audit and are therefore not corpus, so nothing inventoried what THEY declare. Inventory.lean now walks both: AxiomCheck by module index, and itself as the module still being elaborated, whose declarations are the ones the environment reports with no originating module. That is what makes the inventory cover the instrument that produces it rather than exempting itself. The policy is not "declare nothing" — this file legitimately declares its machinery. It is that an instrument may declare only inert definitions. An axiom here would widen the trusted base without appearing in any certificate's cone; a theorem here would be a claim no certificate covers and no allowlist pins. A flat ban on theorems was WRONG and was measured to be wrong: defining a function by well-founded recursion makes the elaborator emit its own obligations, and axiomCone._proof_1 rejected this very file. The distinction that holds is whether a theorem is a claim someone wrote or an artefact of a definition declared alongside it — an artefact's name extends the name of a constant declared with it. Observed surface: 18 declarations, 16 def and 2 generated obligations, no axiom, no standalone claim. The drivers are byte-pinned already, so this does not pin WHICH definitions they contain — that would add a thing to maintain without adding a thing to catch. It adds the property byte-pinning cannot give: that no instrument declares an axiom or a claim, whatever its bytes are. selftest_audit.sh: 10 cases -> 14. Case 12 uses an INDENTED axiom, because Phase 1's source grep catches an unindented one and the point is to reach the kernel-side walk standing behind it. TWO DEFECTS IN THE TEST HARNESS, found while adding the cases. · The scratch tree copied verification/ only, but the button also reads README.md and STATEMENT-MAP.md from the repository root. check.sh therefore ALWAYS died in Phase 3c in the scratch tree, which made every `if check.sh; then <attack not caught>` guard unfirable — check.sh could not pass in there even with no attack at all. Only the diagnostic greps were doing any work. The documents are now copied, and the negative test below proves the guard is live: with the driver-surface check disabled, check.sh PASSES a tree whose inventory driver declares `axiom driver_cheat : False`. · Case 9 was the last case when it was written and left its rogue gen file in place. Harmless then; the new cases inherited it. Cleaned up between the blocks rather than inside case 9, so that case still tests what it did. Also fixed while here: Phase 3b compared the compile manifest against Inventory.lean by grepping the WHOLE FILE for a backticked module name, so prose counted — a doc comment naming a module broke the count, and in the other direction a doc mention of a module missing from the array would have satisfied the presence check and hidden the omission. It now reads the arrays. Both new gates negative-tested by removal. Button green, self-test green.
2026-07-31 12:18:40 +00:00
# The audit infrastructure, named ONCE. These are not corpus — they are the
# instruments — but they are Lean modules in the audited tree, so the dead-file
# scan must know them by membership rather than by two hard-coded basename
# comparisons, and Phase 3b must inventory what they declare. CLASS 9: until
# 2026-07-31 nothing looked at the drivers' own declaration surface, so an
# `axiom` or a `theorem` added to either was invisible to every phase.
DRIVERS=( AxiomCheck Inventory )
# Certificates and their exact expected cones (observed via #print axioms,
# never guessed; any drift in EITHER direction is a failure).
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
# AUDIT SURFACE: Phase 3b pins the FULL environment of the corpus modules
Round 5 (housekeeping): doc-consistency welded into the button; both round-4 approvals recorded Round-4 verdicts: Claude reviewer — nothing blocks the freeze, no remaining findings; GPT-5.6 — approve after minor documentation fixes, attestation scoped to the mechanized model. This round is those fixes; no Lean surface changed. - 218/59 → 222/61 everywhere, and STRUCTURALLY: check.sh Phase 3c asserts the audit counts (STATEMENT-MAP + README vs allowlist/CONES) and the four fidelity pins (STATEMENT-MAP vs run_fidelity.py constants) on every run — stale-count drift is a red button now (R4-1, third recurrence of the class). - Gap 14 reworded to evidence-vs-inference (the invariant "is assumed", not "transfers"), witnesses cited (paper §5.3/§5.4; pacta sthstore.py/logclient.py — outside the fidelity target). New gap 15: deployment refinement invariant unmechanized (GPT's principal finding, split out because it carries the deployed-soundness claim). - Runbook: A1 marked done (both approvals on SD); B2 gains the REQUIRED scoped attestation wording (GPT §11) as a gate condition — entry 13 cannot claim "deployed verifier formally verified". - run_bare.sh fail-closes on Lean version AND commit (rejection path tested with a fake toolchain: FATAL, exit 1). - Harness: "consistency baseline family" line (GPT §8); gap 14 says "fixed offsets n−1/n+1/n+7" (R4-5). - RESPONSE round 5, incl. refutation of GPT §7 (the target tarball demonstrably contains MANIFEST.sha256 + TARGET-PROVENANCE.md; the round-5 kit also ships both unpacked as a courtesy). check.sh exit 0 ATTESTATION GREEN (Phases 0-4 incl. new 3c); selftest exit 0, 9/9 + control. Live LTL untouched (12 leaves, bcd15f9d…). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 07:40:20 +00:00
# (inventory-allowlist.txt, every compiler-generated auxiliary included —
# the count is pinned by the allowlist itself and asserted against the
# docs in Phase 3c); the entries below are the human-reviewed statement
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
# surface, additionally queried through #print axioms in Phase 3 and
# cross-checked against the inventory's independently computed cones.
declare -A CONES=(
[LTLAcc.domsep]=""
[LTLAcc.kbelow_pos]="propext, Quot.sound"
[LTLAcc.kbelow_lt]="propext, Quot.sound"
[LTLAcc.le_two_kbelow]="propext, Quot.sound"
[LTLAcc.kbelow_pow2]="propext, Quot.sound"
[LTLAcc.MTH]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.Root]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.ConsRec]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.Path]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.incl_complete]="propext, Classical.choice, LTLAcc.sha256, Quot.sound"
S3/L4-L5: root binding (Lemma 2, Path instance) + Theorem 2, constructive The crux layer — the statement whose HAND proof once carried the frontier coverage bug is now kernel-checked. - gen: hash outputs refactored to Hash = {l : List UInt8 // l.length = 32}. MECHANIZATION FINDING: the paper's pair-coincidence step ('equal hnode values of distinct argument pairs are a collision') is load-bearing on FIXED-WIDTH outputs — with unconstrained byte strings x++s = X++Y does not split. hnode_preimage_inj (cone: propext) makes this explicit via List.append_inj on equal-length components. Queued as a half-sentence for the paper's next cycle. - HasCollision := ∃ x y, x ≠ y ∧ sha256 x = sha256 y — appears ONLY as a conclusion, never a hypothesis (no collision-resistance assumed). - hnode_inj_or_collision / hleaf_inj_or_collision: the per-node dichotomy. - root_binding: any accepting reconstruction from (v,P) to the honest root either IS the honest receipt (leaf hash AND full path P = Path m D — case (ii) pinning every consumed sibling) or exhibits a collision. Motive quantifies (v,P); induction on Path; k-fold discipline. - incl_sound (Theorem 2, position binding): accepting a wrong leaf at m yields a collision. Cone [propext, Classical.choice, LTLAcc.sha256, Quot.sound] — the single hash axiom, pinned in check.sh. ALL GREEN. Also: Root n=1 branch changed from list-match to decidable 'if P = []' (well-founded unfolding generated a spurious exhaustiveness obligation); Root_one_cons added. Fable-5 statement-audit passed. LTL untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:21:17 +00:00
[LTLAcc.hnode_preimage_inj]="propext"
S3.5: explicit collision extractor — Theorem 2 made non-vacuous, vacuous forms removed The S3 Socratic re-audit found incl_sound was kernel-perfect but VACUOUS: its '... ∨ HasCollision' disjunct (∃ x y, x≠y ∧ sha256 x = sha256 y) is provable by pigeonhole ALONE (sha256: infinite List UInt8 → finite 32-byte Hash), so the theorem said nothing about forgeries. Even a data-carrying {p // IsCollision p} disjunct fails (Classical.choice inhabits it). The only faithful rendering of the paper's 'explicit algorithm 𝓔' is a NAMED FUNCTION whose correctness is a claim about ITS OUTPUT. - extractIncl (m D d P): total function that walks the honest tree and returns the concrete colliding preimage pair at the first divergence (a node preimage pair, or the leaf preimage pair at the bottom). - extractIncl_correct: d ≠ D[m] ∧ accepting-receipt → IsCollision (extractIncl …).1 (extractIncl …).2. A statement ABOUT the fixed function's output; pigeonhole cannot discharge it. ADVERSARIAL CHECK (probe, since removed): proved ¬ IsCollision (extractIncl 0 [[7]] [7] []) — i.e. on a NON-forgery input the output is provably NOT a collision, so the conclusion is genuinely false for some inputs ⇒ non-vacuous, choice-proof. - Removed the vacuous theorems entirely (incl_sound, root_binding, hnode/hleaf_inj_or_collision, HasCollision def) so no hollow statement survives in a corpus destined for the log. Kept the real building blocks (hnode_preimage_inj [propext]; eq_dropLast helper moved to Completeness; Binding.lean deleted). extractIncl_correct cone [propext, Classical.choice, LTLAcc.sha256, Quot.sound]. THE button green (14 certs). Fable statement-audit passed. LTL untouched (12 leaves, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 13:31:21 +00:00
[LTLAcc.IsCollision]="LTLAcc.sha256"
[LTLAcc.extractIncl]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.extractIncl_correct]="propext, Classical.choice, LTLAcc.sha256, Quot.sound"
[LTLAcc.extractIncl_nonvacuous]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.extractMTH]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.extractMTH_correct]="propext, Classical.choice, LTLAcc.sha256, Quot.sound"
[LTLAcc.extractMTH_nonvacuous]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.kbelow_prefix_eq]="propext, Quot.sound"
[LTLAcc.take_take_le]="propext, Quot.sound"
[LTLAcc.take_drop_prefix]="propext, Classical.choice, Quot.sound"
[LTLAcc.extractConsNode]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.take_all]="propext"
[LTLAcc.consRecBinding]="propext, Classical.choice, LTLAcc.sha256, Quot.sound"
[LTLAcc.consRec_base_false_eq]="propext, Classical.choice, Quot.sound"
[LTLAcc.consRec_base_true_eq]="propext"
[LTLAcc.extractCons]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.extractCons_correct]="propext, Classical.choice, LTLAcc.sha256, Quot.sound"
[LTLAcc.extractCons_nonvacuous]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.pinAccept_monotone]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.pin_prefix_correct]="propext, Classical.choice, LTLAcc.sha256, Quot.sound"
[LTLAcc.fork_distinct]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.pin_prefix_nonvacuous]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.MTH_single]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.MTH_split]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.Root_left]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.Root_one]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.Root_one_cons]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.Root_right]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.acceptCons]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.exists_singleton_of_length_one]="propext, Classical.choice, Quot.sound"
[LTLAcc.getD_drop]="propext, Quot.sound"
[LTLAcc.getD_take]="propext, Quot.sound"
[LTLAcc.hleaf]="LTLAcc.sha256"
[LTLAcc.hnode]="LTLAcc.sha256"
[LTLAcc.kbelow]="propext, Quot.sound"
[LTLAcc.kbelow_eq_of_pow2_between]="propext, Quot.sound"
[LTLAcc.pinAccept]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.pinExtract]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.pow2_exp_unique]="propext, Quot.sound"
[LTLAcc.take_append_drop]=""
[LTLAcc.eq_dropLast_append_of_getLast?]="propext"
[LTLAcc.instInhabitedHash]="propext"
[LTLAcc.instDecidableEqHash]=""
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
[LTLAcc.Hash]=""
[LTLAcc.acceptIncl]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.acceptIncl_complete]="propext, Classical.choice, LTLAcc.sha256, Quot.sound"
[LTLAcc.acceptIncl_sound]="propext, Classical.choice, LTLAcc.sha256, Quot.sound"
[LTLAcc.extractCons_correct_paper]="propext, Classical.choice, LTLAcc.sha256, Quot.sound"
Review round 4: F1* absorbed (lied-size boundary), acceptCons_sound, kit reproducibility Round-3 verdicts: GPT-5.6 conditionally approves (blockers closed, one portability finding); the Claude reviewer's Socratic addendum produced F1*, the strongest finding of the series — deployed verify_consistency and mechanized ConsRec are NOT extensionally equal. Reproduced exactly (witness verify_consistency(1,3,R2,R3,P(2→3))=True vs ConsRec reject; 3,405 divergences n<60; strictly one-sided; power-of-two seeding mechanism confirmed in source). - KNOWN-GAPS gap 14: witness, mechanism, one-sidedness, and the pinned-pair side condition under which Theorem 3 transfers to the deployed verifier (pacta's pin-store flow supplies it by construction). No pacta code change; deployed behavior matches upstream RFC 9162 implementations. - fidelity: lied-size family — 73,573 boundary cases, 3,867 expected divergences PINNED, one-sided direction asserted per case. Banner rescoped: agreement over pinned families, not extensional equality. - Theorem3.lean: acceptCons_sound (F2) — soundness over the named acceptCons predicate, n₀=0 discharged from the non-prefix premise, size bound derived from acceptance via new consRec_some_le. Cones read from #print axioms; CONES/AxiomCheck/allowlist updated (218 → 222 constants, diff = the two theorems + two generated auxiliaries). - F3/GPT§7: verification/lean-toolchain pin + run_bare.sh (reviewer's standalone runner, plain public lean — verified green: 61 cones, 222 constants, gate green) + AENEAS_ENV override in check.sh and selftest_audit.sh. - F4: awk field-equality replaces regex-with-dots in Phase 3b. - F5: git-tracked .pyc removed (worse than reported — it was in the repo, not just the kit); __pycache__ gitignored; round-4 kit ships a corpus MANIFEST.sha256 + pinned commit (also GPT's governance condition). check.sh exit 0, ATTESTATION GREEN; selftest exit 0, 9/9 + control. Live LTL untouched (12 leaves, bcd15f9d…); attestation still gated on ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 13:07:57 +00:00
[LTLAcc.consRec_some_le]="propext, LTLAcc.sha256, Quot.sound"
[LTLAcc.acceptCons_sound]="propext, Classical.choice, LTLAcc.sha256, Quot.sound"
)
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
# (The former EXCLUDE table is gone: since Phase 3b reads the environment,
# sha256 and Bytes are ordinary allowlist entries — the axiom is pinned as
# the SINGLE axiom-kind constant, the abbrev carries its empty cone.)
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
free -m | awk '/Mem:/{if($7<2048){print "FATAL: <2GB RAM available — refusing to compile"; exit 1}}'
echo "=== Phase 0: source integrity ==="
for f in "$HERE"/gen/LTLAcc/*.lean "$HERE"/Proofs/*.lean; do
[ -f "$f" ] || continue
if ! grep -qE '^(/-|import |namespace |theorem |def |noncomputable |open |set_option |--|abbrev )' "$f"; then
echo "CORRUPTED: $f is not Lean source. Restore: git checkout HEAD -- $f"; exit 1
fi
done
echo " all sources valid"
# ── Phase 0a: build hygiene ─────────────────────────────────────────────────
# P0-a was applied to the four ed25519 repositories on 2026-07-30 and never
# here — found on 2026-07-31 by the control repo's capability matrix, which
# asks the property rather than looking for a phase by name.
#
# The finding that made it matter there applies verbatim: a verification that
# never cleans up cannot distinguish "these proofs check" from "these proofs
# check GIVEN WHATEVER IS LYING AROUND". Compiled artifacts are gitignored, so
# no `git status` can show a reader that a verdict rested on an object from an
# earlier run of a different script. Purge, and compile from source.
#
# This repository has no --audit-only mode, so there is no case in which the
# artifacts must be kept: the purge is unconditional.
echo "=== Phase 0a: build hygiene ==="
find "$HERE" -name '*.olean' -delete 2>/dev/null || true
find "$HERE" -name '*.ilean' -delete 2>/dev/null || true
echo " purged every compiled artifact — this run compiles from source"
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
# Recursive: no compiled artifact anywhere in the tree may lack its source
# (review round 2, GPT M1 — previously scanned Proofs/*.olean only).
while IFS= read -r -d '' o; do
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
[ -f "${o%.olean}.lean" ] || { echo "ORPHAN OLEAN: $o has no sibling .lean (stale artifact)"; exit 1; }
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
done < <(find "$HERE" -name '*.olean' -print0)
verification: pin the harness, audit drivers and policy files (P1-c) This repository has the estate's strongest gates, which makes them the most valuable to switch off. Until now every one of them was executed by scripts that nothing pinned. Phase 0c requires every harness file to match HARNESS.sha256 — 15 files: check.sh, lean-guard, inventory_gate.sh, run_bare.sh, all three self-tests, both audit drivers (Proofs/Inventory.lean, Proofs/AxiomCheck.lean), the policy tables (inventory-allowlist.txt, AUDIT-MANIFEST.txt), the toolchain pin, the fidelity harness and its Python transcription, and the extracted model. WHICH files must be pinned is policy and lives in check.sh, never in the map being consulted: the required set is derived from the filesystem (the executable bit, plus gen/**.lean, plus an explicit list for the rest), so deleting a pin entry is a set mismatch rather than a silent un-pinning. gen/LTLAcc/HashExternal.lean was previously bound by nothing at all — it was compiled and trusted. It is now pinned, and the derivation is by set, so a new model file fails closed. selftest_audit.sh case 9 is split rather than relabelled. Phase 0c now catches an unpinned rogue gen module BEFORE the dead-file gate runs, so asserting only the new diagnostic would have quietly retired the dead-file gate from the test suite. 9a asserts the harness-set mismatch on the unpinned file; 9b pins it — an author who added it deliberately — and asserts Phase 2 still dies with DEAD FILE (gen). Ten cases now, all defeated. KNOWN-GAPS and the trusted base record the circularity plainly: an author who edits a script and refreshes its pin in one commit passes every phase. The pin removes the silent path, not the possibility. Review at the pinned commit remains the consumer's protection. Verified green after the fix: button (75s), harness self-test, binding self-test, and the ten-case audit self-test. ATTESTATION GREEN (Lean + fidelity), all fidelity case counts identical to the pre-change run. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 18:13:21 +00:00
# ── Phase 0c: harness integrity ─────────────────────────────────────────────
# WHY. Every gate below is executed by a script that, until now, nothing
# pinned. Round-5 review of the companion SLH-DSA repository stubbed the
# compiler wrapper alone and its button printed ALL GREEN in 3.6 seconds over
# deliberately destroyed proofs. Depth of checking is worth nothing if the
# thing doing the checking is unbound — and this repo's gates are the estate's
# strongest, which makes them the most valuable to switch off.
#
# WHICH files must be pinned is POLICY, and policy lives here — in the root of
# trust — never inside the map being consulted. If the required set were read
# from HARNESS.sha256, deleting an entry would silently un-pin that file
# instead of failing the build.
#
# Membership is SELF-DERIVING from two sources the filesystem can answer: the
# executable bit (anything this script can shell out to) and gen/**.lean (the
# extracted model, which nothing else byte-pins in this repo). Load-bearing
# files that are neither — the audit drivers, the policy tables, the toolchain
# pin, the fidelity harness — cannot be discovered and are listed explicitly.
HARNESS_EXTRA=(
AUDIT-MANIFEST.txt # the statement block Phase 3d's digest is taken over
inventory-allowlist.txt # the pinned audit surface Phase 3b diffs against
lean-toolchain # which Lean the corpus claims to have been checked by
fidelity/lean_defs.py # the Python transcription the differential compares
fidelity/run_fidelity.py # the differential itself
audit: bind the scalar statements, and make the accounting identity mean audit Closes four round-7/8 findings. Certified by the round-12 sweep: five repositories, both buttons and every self-test, 48/48 GREEN. ── `scalar-statements-unbound` (gpt, round 7, CRITICAL) ──────────────────── The main button bound its 31 certificates' elaborated statements and reachable specification bodies. This button bound NONE of its thirteen, while TRUSTED-BASE item 8 said the audit covers "every certificate" — false across the 44-certificate surface. The finding was raised in round 7, lost from the round-8 work list by an F-number collision between two reviewers, and re-raised in round 8. Proofs/ScalarAudit.lean is generated from each fork's OWN Audit.lean, so the canonicalisation is provably the same code: pp.all rendering, whitespace normalisation, transitive specification closure. check-scalar.sh Phase 3c pins the block's digest, requires the committed copy to match byte-for-byte so a mismatch can be DIFFED, and cross-checks the auditor's certificate set against the button's CERTS array. dalek ecf3a3f8 · anza 0d942e47 · risc0 4b550a61 · betrusted 4b550a61 risc0 and betrusted share a digest and that is correct, not a collision: their ScalarSubSpec.lean differs only in doc prose and in `black_box` entries inside `simp only [...]` lists AFTER `:= by`. Proof scripts. They bind the same statements over the same specifications, which is the documented scope. selftest-scalar-statements.sh ships the two attacks the reviewer asked for: ok gutted statement caught (cone unchanged) ok rewritten specification body caught (name and cone unchanged) The second rewrites a reachable reference body to `id (…)` — DEFINITIONALLY EQUAL, so the corpus compiles and every proof typechecks and the cone is byte-identical. Every earlier phase is blind to it. ── `drv-surface-no-cones` + `accounting-certifies-enumeration` (claude) ──── The round-7 accounting identity proved every kernel constant was ENUMERATED. The reviewer showed enumeration is not audit: their planted claim WAS enumerated, as DRV|LTLAccAudit.bait.smuggled|theorem with a real cone, and nothing examined it — rows had no cone, no allowlist covered them, the statement digest does not reach instruments, and Phase 2b gates DECLARED AXIOMS, a different question. "Progress of one step, not two." DRV rows now carry their axiom cone and are pinned in driver-allowlist.txt by inventory_gate.sh with a DRV tag — the same implementation that pins the corpus, in both directions, because a second copy of a coverage gate is a second thing to drift. The axiom policy is per-surface and enforced per surface: the corpus admits exactly the sanctioned boundary, the instruments admit none, and an instrument axiom fails EVEN WHEN ALLOWLISTED. Verified with the reviewer's own payload, both placements: before the walk -> UNCLASSIFIED: DRV|…|bait.smuggled|theorem|Classical.choice,Quot.sound,propext after the walk -> ACCOUNTING FAILED names it (kernel-side) ── `drv-naming-heuristic` (claude, round 7) ──────────────────────────────── Retired as load-bearing rather than patched. The rule admits a theorem whose name extends a constant declared alongside it, and "breaks in one line" — declare `def bait`, then `theorem bait.smuggled` walks through. It stays as a fast readable first check; membership in a committed allowlist is what now carries the weight, and a new row fails closed whatever it is called. ── what round 11 caught, which was mine ─────────────────────────────────── DRV rows first shipped WITHOUT their originating driver. dalek and anza run two drivers, each declaring its own `corpus`; keyed on name alone those two distinct declarations produced one byte-identical row, `sort -u` collapsed them, and the trailers summed to 37 against 36. The estate had already learned this on the corpus walk — INV rows carry their module because two modules both declare CurveFieldProofs.zero_spec — and I rebuilt the record without it. Rows now carry their driver, and the gate FAILS CLOSED ON DUPLICATE RECORDS naming the collision: two declarations sharing one entry means one is covered by the other's, which is exactly how a real declaration hides. The trailer now checks what the drivers EMITTED, not what survives de-duplication — conflating "the run was truncated" with "two rows were identical" is what let a record-format defect present itself as an arithmetic complaint. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 10:15:26 +00:00
driver-allowlist.txt # the INSTRUMENTS' own declaration surface, with cones.
# Not executable, so it would otherwise sit outside the
# harness set — and an allowlist an attacker may rewrite
# pins nothing, the same shape as a forgeable .audit-basis.
accumulator: a run that is not attestation-ready must not exit 0, and must name its subject Two round-7/8 findings, both closed here. `acc-exit0-fidelity` — CRITICAL, raised INDEPENDENTLY by both reviewers (Claude F1, GPT-5.6 F10) and lost from the round-8 work list by the F-number collision the finding register now prevents. check.sh emitted a careful pair of markers — ATTESTATION GREEN only when fidelity actually ran — and then returned 0 either way. The marker discipline was right; the exit code contradicted it. A caller doing the obvious thing ./check.sh && append read success from a run whose own last line said NOT attestation-ready. And because pacta is not part of this estate, the skip branch is the ONLY branch a third party ever takes: for everyone but the author the button always returned 0 without ever checking definition fidelity. Reproduced here before fixing — PACTA_SRC=/nonexistent ./check.sh printed "FIDELITY NOT RUN" and exited 0. An exit code is what programs read. The contract is now: fidelity ran exit 0 ATTESTATION GREEN SKIP_FIDELITY=1 exit 3 explicit opt-out, distinguishable, not success pacta absent exit 1 nobody opted out; a real failure to establish the property the button exists for All three verified. The self-tests are unaffected: every SKIP_FIDELITY case already expected a non-zero exit and asserts on a diagnostic from an earlier phase, and the control compiles modules directly rather than invoking check.sh. 29 assertions across the three self-tests, all green. `pacta-subject-unpinned` — HIGH, GPT-5.6 round 8. Phase 4 compared this repository's Lean definitions against "the deployed verifier" by importing whatever sat at $PACTA_SRC — no repository, no commit, no clean state, no hashes. It pinned the fidelity OUTPUTS while leaving the SUBJECT anonymous, so any program producing the same finite family of answers passed, and the recorded result named no version of the thing it agreed with. fidelity/pacta_pin.py pins the transitive set of pacta modules the harness ACTUALLY LOADS — discovered by importing its entry point and reading sys.modules, a membership property rather than a directory glob. A glob would pin files the comparison never touches and miss anything loaded from elsewhere; this estate has been bitten by name-shaped measurement before. Five modules at pacta cd3b1bc — the same checkout the reviewer independently recorded. Negative-tested, all three rejected by name: tampered bytes, a module loaded but absent from the pin, and the pin file deleted. Refusing to pin a dirty pacta tree is also enforced — a pin taken over uncommitted edits names a subject nobody else can obtain. PACTA-PIN.sha256 joins HARNESS_EXTRA. It is not executable, so it would otherwise have sat outside the harness set, and a subject pin an attacker may rewrite pins nothing — the same shape as the forgeable .audit-basis that remains open as `auditonly-basis-forgeable`. This does not widen the claim: byte identity of a source tree is not proof the deployed service runs it, and finite-family agreement is not extensional equality. It names the subject. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-02 19:40:35 +00:00
PACTA-PIN.sha256 # WHICH pacta the differential is entitled to compare
# against. Pinned here because it is not executable
# and would otherwise sit outside the harness set —
# a subject pin an attacker may rewrite pins nothing,
# the same shape as a forgeable .audit-basis.
verification: pin the harness, audit drivers and policy files (P1-c) This repository has the estate's strongest gates, which makes them the most valuable to switch off. Until now every one of them was executed by scripts that nothing pinned. Phase 0c requires every harness file to match HARNESS.sha256 — 15 files: check.sh, lean-guard, inventory_gate.sh, run_bare.sh, all three self-tests, both audit drivers (Proofs/Inventory.lean, Proofs/AxiomCheck.lean), the policy tables (inventory-allowlist.txt, AUDIT-MANIFEST.txt), the toolchain pin, the fidelity harness and its Python transcription, and the extracted model. WHICH files must be pinned is policy and lives in check.sh, never in the map being consulted: the required set is derived from the filesystem (the executable bit, plus gen/**.lean, plus an explicit list for the rest), so deleting a pin entry is a set mismatch rather than a silent un-pinning. gen/LTLAcc/HashExternal.lean was previously bound by nothing at all — it was compiled and trusted. It is now pinned, and the derivation is by set, so a new model file fails closed. selftest_audit.sh case 9 is split rather than relabelled. Phase 0c now catches an unpinned rogue gen module BEFORE the dead-file gate runs, so asserting only the new diagnostic would have quietly retired the dead-file gate from the test suite. 9a asserts the harness-set mismatch on the unpinned file; 9b pins it — an author who added it deliberately — and asserts Phase 2 still dies with DEAD FILE (gen). Ten cases now, all defeated. KNOWN-GAPS and the trusted base record the circularity plainly: an author who edits a script and refreshes its pin in one commit passes every phase. The pin removes the silent path, not the possibility. Review at the pinned commit remains the consumer's protection. Verified green after the fix: button (75s), harness self-test, binding self-test, and the ten-case audit self-test. ATTESTATION GREEN (Lean + fidelity), all fidelity case counts identical to the pre-change run. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 18:13:21 +00:00
Proofs/Inventory.lean # audit driver: emits the inventory AND the statements
Proofs/AxiomCheck.lean # audit driver: the #print axioms queries of Phase 3
)
echo "=== Phase 0c: harness integrity ==="
if [ ! -s "$HERE/HARNESS.sha256" ]; then
echo "FATAL: HARNESS.sha256 is missing or empty — the harness is unpinned."
exit 1
fi
# check.sh is pinned like everything else: that catches drift and accident. It
# does NOT stop an author who edits this script and refreshes its pin in one
# commit — nothing executed by the harness can. The defence there is that both
# changes appear in the diff at the pinned commit.
HARNESS_REQUIRED=$( { find "$HERE" -type f -executable -not -path '*/.git/*' -printf '%P\n'
find "$HERE/gen" -type f -name '*.lean' -printf 'gen/%P\n'
printf '%s\n' "${HARNESS_EXTRA[@]}"; } | sort -u )
HARNESS_PINNED=$(awk '{print $2}' "$HERE/HARNESS.sha256" | sort -u)
if [ "$HARNESS_REQUIRED" != "$HARNESS_PINNED" ]; then
echo "FATAL: the set of harness files does not match HARNESS.sha256."
echo " (< pinned, > present and requiring a pin)"
diff <(echo "$HARNESS_PINNED") <(echo "$HARNESS_REQUIRED") | sed 's/^/ /'
exit 1
fi
if ! ( cd "$HERE" && sha256sum -c --quiet HARNESS.sha256 ) ; then
echo "FATAL: a harness file does not match its pin. The button you are"
echo "running is not the button that was reviewed."
exit 1
fi
echo " $(wc -l < "$HERE/HARNESS.sha256") harness files match their pins"
echo "=== Phase 1: stub + axiom-smuggling audit ==="
if grep -rn 'by trivial' "$HERE"/Proofs/*.lean 2>/dev/null; then
echo "STUB DETECTED"; exit 1; fi
if grep -rn ' : True :=' "$HERE"/Proofs/*.lean 2>/dev/null; then
echo "STUB DETECTED: True-target theorem"; exit 1; fi
if grep -rnE '^(private |protected |noncomputable )*axiom ' "$HERE"/Proofs/*.lean 2>/dev/null; then
echo "AXIOM SMUGGLING DETECTED: axiom under Proofs/ — gen/ is the only sanctioned site."; exit 1
fi
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
# gen/ is the sanctioned site for exactly ONE axiom (review round 2, GPT M1).
# This textual pin is the fast belt; the semantic guarantee is Phase 3b's
# environment inventory (exactly one axiom-kind constant, LTLAcc.sha256).
AXCOUNT=$(grep -hcE '^(private |protected |noncomputable )*axiom ' "$HERE"/gen/LTLAcc/*.lean | paste -sd+ - | bc)
[ "$AXCOUNT" = 1 ] || { echo "AXIOM COUNT DRIFT: gen/ declares $AXCOUNT axioms, sanctioned: 1 (sha256)"; exit 1; }
echo " clean"
echo "=== Phase 2: compile ==="
LOG=$(mktemp /tmp/acc-check-XXXX.log)
cd "$AENEAS_LEAN"
lake env bash -c "
set -euo pipefail
cd '$HERE/gen' && export LEAN_PATH=\"\$LEAN_PATH:\$PWD:$HERE\"
compile() {
echo \" · \$1\"
LEAN_TIMEOUT=$TIMEOUT LEAN_MAX_CORES=$CORES '$HERE/lean-guard' \"\${1}.lean\" 2>&1 | tee -a '$LOG' || { echo \"FAIL: \$1\"; exit 1; }
}
for m in ${GEN_MODULES[*]}; do compile \"\$m\"; done
cd '$HERE'
for m in ${PROOFS[*]}; do
[ -f \"Proofs/\$m.lean\" ] || { echo \"MISSING: Proofs/\$m.lean\"; exit 1; }
compile \"Proofs/\$m\"
done
for f in Proofs/*.lean; do
b=\$(basename \"\$f\" .lean)
P2-b: close classes 9 and 15 — the instruments, and the places nothing looked CLASS 15 — a Lean file where no phase was looking. The dead-file scan read Proofs/*.lean and gen/LTLAcc/*.lean and nothing else. A module at the verification root, or under any other gen/ subdirectory, was neither compiled nor rejected — while remaining importable by name, since LEAN_PATH contains both roots. That is a source of the corpus that no phase reads and no pin covers, which is exactly what the dead-file gate exists to forbid; it was simply looking in two places instead of everywhere. Now nothing may live in either root but the two enumerated sets. CLASS 9 — the instruments' own declaration surface. AxiomCheck.lean and Inventory.lean perform the audit and are therefore not corpus, so nothing inventoried what THEY declare. Inventory.lean now walks both: AxiomCheck by module index, and itself as the module still being elaborated, whose declarations are the ones the environment reports with no originating module. That is what makes the inventory cover the instrument that produces it rather than exempting itself. The policy is not "declare nothing" — this file legitimately declares its machinery. It is that an instrument may declare only inert definitions. An axiom here would widen the trusted base without appearing in any certificate's cone; a theorem here would be a claim no certificate covers and no allowlist pins. A flat ban on theorems was WRONG and was measured to be wrong: defining a function by well-founded recursion makes the elaborator emit its own obligations, and axiomCone._proof_1 rejected this very file. The distinction that holds is whether a theorem is a claim someone wrote or an artefact of a definition declared alongside it — an artefact's name extends the name of a constant declared with it. Observed surface: 18 declarations, 16 def and 2 generated obligations, no axiom, no standalone claim. The drivers are byte-pinned already, so this does not pin WHICH definitions they contain — that would add a thing to maintain without adding a thing to catch. It adds the property byte-pinning cannot give: that no instrument declares an axiom or a claim, whatever its bytes are. selftest_audit.sh: 10 cases -> 14. Case 12 uses an INDENTED axiom, because Phase 1's source grep catches an unindented one and the point is to reach the kernel-side walk standing behind it. TWO DEFECTS IN THE TEST HARNESS, found while adding the cases. · The scratch tree copied verification/ only, but the button also reads README.md and STATEMENT-MAP.md from the repository root. check.sh therefore ALWAYS died in Phase 3c in the scratch tree, which made every `if check.sh; then <attack not caught>` guard unfirable — check.sh could not pass in there even with no attack at all. Only the diagnostic greps were doing any work. The documents are now copied, and the negative test below proves the guard is live: with the driver-surface check disabled, check.sh PASSES a tree whose inventory driver declares `axiom driver_cheat : False`. · Case 9 was the last case when it was written and left its rogue gen file in place. Harmless then; the new cases inherited it. Cleaned up between the blocks rather than inside case 9, so that case still tests what it did. Also fixed while here: Phase 3b compared the compile manifest against Inventory.lean by grepping the WHOLE FILE for a backticked module name, so prose counted — a doc comment naming a module broke the count, and in the other direction a doc mention of a module missing from the array would have satisfied the presence check and hidden the omission. It now reads the arrays. Both new gates negative-tested by removal. Button green, self-test green.
2026-07-31 12:18:40 +00:00
case \" ${DRIVERS[*]} \" in (*\" \$b \"*) continue;; esac # audit infrastructure, compiled in Phase 3/3b
case \" ${PROOFS[*]} \" in (*\" \$b \"*) ;; (*) echo \"DEAD FILE: \$f\"; exit 1;; esac
done
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
# gen/ gets the same unmanifested-source check (review round 2, GPT M1)
for f in gen/LTLAcc/*.lean; do
b=\"LTLAcc/\$(basename \"\$f\" .lean)\"
case \" ${GEN_MODULES[*]} \" in (*\" \$b \"*) ;; (*) echo \"DEAD FILE (gen): \$f\"; exit 1;; esac
done
P2-b: close classes 9 and 15 — the instruments, and the places nothing looked CLASS 15 — a Lean file where no phase was looking. The dead-file scan read Proofs/*.lean and gen/LTLAcc/*.lean and nothing else. A module at the verification root, or under any other gen/ subdirectory, was neither compiled nor rejected — while remaining importable by name, since LEAN_PATH contains both roots. That is a source of the corpus that no phase reads and no pin covers, which is exactly what the dead-file gate exists to forbid; it was simply looking in two places instead of everywhere. Now nothing may live in either root but the two enumerated sets. CLASS 9 — the instruments' own declaration surface. AxiomCheck.lean and Inventory.lean perform the audit and are therefore not corpus, so nothing inventoried what THEY declare. Inventory.lean now walks both: AxiomCheck by module index, and itself as the module still being elaborated, whose declarations are the ones the environment reports with no originating module. That is what makes the inventory cover the instrument that produces it rather than exempting itself. The policy is not "declare nothing" — this file legitimately declares its machinery. It is that an instrument may declare only inert definitions. An axiom here would widen the trusted base without appearing in any certificate's cone; a theorem here would be a claim no certificate covers and no allowlist pins. A flat ban on theorems was WRONG and was measured to be wrong: defining a function by well-founded recursion makes the elaborator emit its own obligations, and axiomCone._proof_1 rejected this very file. The distinction that holds is whether a theorem is a claim someone wrote or an artefact of a definition declared alongside it — an artefact's name extends the name of a constant declared with it. Observed surface: 18 declarations, 16 def and 2 generated obligations, no axiom, no standalone claim. The drivers are byte-pinned already, so this does not pin WHICH definitions they contain — that would add a thing to maintain without adding a thing to catch. It adds the property byte-pinning cannot give: that no instrument declares an axiom or a claim, whatever its bytes are. selftest_audit.sh: 10 cases -> 14. Case 12 uses an INDENTED axiom, because Phase 1's source grep catches an unindented one and the point is to reach the kernel-side walk standing behind it. TWO DEFECTS IN THE TEST HARNESS, found while adding the cases. · The scratch tree copied verification/ only, but the button also reads README.md and STATEMENT-MAP.md from the repository root. check.sh therefore ALWAYS died in Phase 3c in the scratch tree, which made every `if check.sh; then <attack not caught>` guard unfirable — check.sh could not pass in there even with no attack at all. Only the diagnostic greps were doing any work. The documents are now copied, and the negative test below proves the guard is live: with the driver-surface check disabled, check.sh PASSES a tree whose inventory driver declares `axiom driver_cheat : False`. · Case 9 was the last case when it was written and left its rogue gen file in place. Harmless then; the new cases inherited it. Cleaned up between the blocks rather than inside case 9, so that case still tests what it did. Also fixed while here: Phase 3b compared the compile manifest against Inventory.lean by grepping the WHOLE FILE for a backticked module name, so prose counted — a doc comment naming a module broke the count, and in the other direction a doc mention of a module missing from the array would have satisfied the presence check and hidden the omission. It now reads the arrays. Both new gates negative-tested by removal. Button green, self-test green.
2026-07-31 12:18:40 +00:00
# CLASS 15. The two loops above look only INSIDE Proofs/ and gen/LTLAcc/, so
# until 2026-07-31 a Lean file anywhere else was invisible: one at the
# verification root, or under gen/AnythingElse/, was neither compiled nor
# rejected. It could be imported by name from a manifested module — the
# manifest names modules, and LEAN_PATH includes both roots — which is a
# source of the corpus that no phase reads and no pin covers. Nothing may
# live in either root but the two enumerated sets.
shopt -s nullglob
for f in *.lean; do echo \"DEAD FILE (verification root): \$f\"; exit 1; done
for d in gen/*/; do
[ \"\$d\" = 'gen/LTLAcc/' ] && continue
for f in \"\$d\"*.lean; do echo \"DEAD FILE (gen subdirectory): \$f\"; exit 1; done
done
for f in gen/*.lean; do echo \"DEAD FILE (gen root): \$f\"; exit 1; done
shopt -u nullglob
"
if grep -q "uses 'sorry'" "$LOG"; then echo "STUB: sorry detected"; exit 1; fi
rm -f "$LOG"
echo "=== Phase 3: boundary-exact axiom audit ==="
AUD=$(mktemp /tmp/acc-audit-XXXX.log)
cd "$AENEAS_LEAN"
lake env bash -c "
cd '$HERE' && export LEAN_PATH=\"\$LEAN_PATH:$HERE/gen:$HERE\"
LEAN_TIMEOUT=300 LEAN_MAX_CORES=$CORES '$HERE/lean-guard' Proofs/AxiomCheck.lean
" > "$AUD" 2>&1 || { cat "$AUD"; exit 1; }
FAIL=0
for cert in "${!CONES[@]}"; do
want="${CONES[$cert]}"
if [ -z "$want" ]; then
exp="'$cert' does not depend on any axioms"
else
exp="'$cert' depends on axioms: [$want]"
fi
if ! grep -qF "$exp" "$AUD"; then
echo " CONE DRIFT: $cert"
echo " expected: $exp"
echo " observed: $(grep -F "'$cert'" "$AUD" || echo '(missing)')"
FAIL=1
else
echo "$cert [$want]"
fi
done
rm -f "$AUD"
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
# -- Phase 3b: ENVIRONMENT-derived audit-surface coverage (fail-closed) ------
# Review round 2 (GPT H1 / Claude NEW-1): the previous source-regex
# enumerator was evadable (attributes, indentation, private/protected,
# instance, and namespace-nested basename collisions). Replaced entirely:
# Proofs/Inventory.lean reads the compiled Lean ENVIRONMENT and emits every
# constant of every corpus module — fully qualified, unfiltered, each with
# kind and axiom cone (its own walker, cross-checked in-process against
# core collectAxioms). inventory_gate.sh diffs that against the pinned
# allowlist, fail-closed BOTH directions. No name shape can hide: what the
# kernel saw is what gets audited.
echo "=== Phase 3b: environment-derived audit-surface coverage ==="
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
COVFAIL=0
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
INVLOG=$(mktemp /tmp/acc-inv-XXXX.log)
cd "$AENEAS_LEAN"
lake env bash -c "
cd '$HERE' && export LEAN_PATH=\"\$LEAN_PATH:$HERE/gen:$HERE\"
LEAN_TIMEOUT=600 LEAN_MAX_CORES=$CORES '$HERE/lean-guard' Proofs/Inventory.lean
" > "$INVLOG" 2>&1 || { cat "$INVLOG"; echo "INVENTORY COMPILE FAILED"; exit 1; }
"$HERE/inventory_gate.sh" "$INVLOG" "$HERE/inventory-allowlist.txt" || COVFAIL=1
Round-7 F2: account for every constant the kernel sees THE DEFECT, demonstrated by a reviewer with a working payload. The driver surface is reported by an `#eval` inside Proofs/Inventory.lean. Anything declared AFTER that command is in the compiled object file but does not exist in the environment while the command runs, so the walk cannot see it. The reviewer appended def bait : Nat := 0 theorem bait.smuggled : forall n : Nat, n + 0 = n := ... re-pinned, and ran the button. It printed "no axiom, no claim", the statement digest was BYTE-IDENTICAL to the clean tree, and the run went green — while a theorem with a real axiom cone sat in the environment. In neither walk: not corpus, because an instrument is not corpus; not driver surface, because it post-dates the emitter. In no allowlist. Pinned by nothing. This repository also had no kernel-side scan at all. Its axiom gate was a source-text grep, evadable by a leading space — which its own selftest case 12 already exploited. THE FIX, ported from the ed25519 forks: · a kernel-side axiom-declaration gate that reads every compiled .olean via readModuleData. It sees what was actually stored, regardless of indentation, attributes, privacy, or where a declaration sits relative to any #eval. Membership self-derives from the manifest and the module count must match, so a deleted artifact cannot make the scan vacuous. · the ACCOUNTING IDENTITY, as set containment: every constant the kernel sees in corpus inventory union instrument surface The two walks read ENVIRONMENTS; the gate reads OBJECT FILES. What a walk cannot see because of where it sits in a file, the object file still holds. That asymmetry is the entire content of this fix. Compared as SETS deliberately. Counts cannot express the relation — an object file may hold two physical copies of one lazily-materialised equation lemma while an environment holds one constant per name — and arithmetic between those views misled the ed25519 version twice before it was stated as containment. PLACEMENT differs from the forks, for a reason worth recording: there the audit drivers are members of the compile manifest, so a gate beside the compile phase finds them. Here AxiomCheck is compiled by Phase 3 and Inventory by Phase 3b, so an earlier gate fails on a missing artifact — which it did, correctly, on the first port. It runs inside Phase 3b, because the instruments are exactly what it must see. VERIFIED with the reviewer's own payload, which previously went green: ACCOUNTING FAILED: the kernel holds constants that neither walk accounts for: bait bait.smuggled selftest_audit.sh: 14 attack cases -> 15. Note in the new case, because it cost two iterations: `theorem bait.smuggled : True := trivial` does NOT exercise this gate — Phase 1's stub audit greps for `: True :=` and catches it first. Real defence in depth, but the naive payload never reaches the gate under test, so the case uses the reviewer's original. Two residues fixed while adding it, both the same shape: a case that was last when written, leaving state the next case inherits. Case 13 restored AxiomCheck.lean but not its pin; case 9 left its rogue gen file. Fixed at the point of use so each case keeps testing what it tested before. Button green (234 declarations across 11 modules, all accounted for), 15/15 self-test green, ATTESTATION GREEN with fidelity.
2026-08-02 00:51:55 +00:00
# ── Phase 3b-kernel: kernel-side axiom-declaration gate ─────────────────────
# PORTED FROM THE ed25519 FORKS after round-7 review (Claude, finding F2).
#
# What this repository had: a SOURCE-TEXT axiom grep in Phase 1, and an
# environment walk in Phase 3b that runs inside Inventory.lean. Both have the
# same blind spot from opposite directions. The grep misses ` axiom c : ...`
# with a leading space — this repo's own selftest_audit.sh case 12 exploits
# exactly that. And the environment walk is an `#eval`: a declaration placed
# AFTER it in the same file exists in the compiled object file but not in the
# environment when the walk runs, so the button reported "no axiom, no claim"
# over a claim that was sitting in the environment, with the statement digest
# byte-identical. A reviewer demonstrated it.
#
# The fix is the one the forks already carry: ask the KERNEL, by reading every
# compiled object file directly. readModuleData sees what was actually stored,
# regardless of indentation, attributes, privacy, or where in the file a
# declaration sits relative to any #eval. Membership self-derives from the
# manifest, so a new module cannot escape by being unlisted, and the module
# count must match so a deleted .olean cannot make the scan vacuous.
# PLACEMENT. This deliberately runs INSIDE Phase 3b rather than beside the
# compile phase, unlike the ed25519 forks. There the audit drivers are members
# of the compile manifest, so they exist by the time the kernel gate runs. Here
# they are not: AxiomCheck is compiled by Phase 3 and Inventory by Phase 3b, so
# an earlier gate would fail on a missing artifact — which it did, correctly,
# when this was first ported. It must run after both drivers exist, because the
# instruments are exactly what it has to see.
echo "=== Phase 3b-kernel: kernel-side axiom-declaration gate ==="
KERNLOG=$(mktemp /tmp/acc-kernel-XXXX.log)
AXGATE=$(mktemp "$HERE/.axgate-XXXX.lean")
ALL_MODULES=$(printf '"%s.olean", ' "${PROOFS[@]}" "${DRIVERS[@]}" | sed 's/, $//')
cat > "$AXGATE" <<LEANGATE
import Lean
open Lean System
#eval show CoreM Unit from do
let dir : FilePath := "$HERE/Proofs"
let expected : List String := [$ALL_MODULES]
let mut errs : Array String := #[]
let mut nConst := 0
let mut nMod := 0
verification: separate the two accounting questions (round-9 review, Claude N2) Phase 2c-accounting asked one question with a name-keyed identity: is every kernel constant covered by the corpus inventory or the instrument surface? Keying on the name alone conflates that with a second, different question -- does the kernel attribute a declaration to the same module the walk does? Pair-keying the identity (module|name) was the obvious fix and is wrong: it fails on legitimate per-module duplicates. Lean materialises equation lemmas lazily, so each module forcing an unfold gets its own copy in its object file (GPT-5.6 round-7 F8). Those records differ from the walk only in module attribution, and every one of their names is accounted for elsewhere. So the block now asks both questions and reports them separately: coverage stays name-keyed and fail-closed, module attribution is counted and printed rather than suppressed. A divergence is now visible instead of either passing silently or failing for the wrong reason. The accumulator declines the second question and says why: its INV rows carry no module column (4 fields), so its records cannot be compared as pairs at all. Gating on the field count rather than on the row tag -- the shape of the record, not the spelling of its label. Adding that column is the open follow-up; until then the identity there is name-keyed only, which is weaker and now says so. Certified by the round-14 sweep: 50/50 green across all six repositories, both buttons and every self-test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 01:17:05 +00:00
let mut seen : Std.HashSet (String × Name) := {}
Round-7 F2: account for every constant the kernel sees THE DEFECT, demonstrated by a reviewer with a working payload. The driver surface is reported by an `#eval` inside Proofs/Inventory.lean. Anything declared AFTER that command is in the compiled object file but does not exist in the environment while the command runs, so the walk cannot see it. The reviewer appended def bait : Nat := 0 theorem bait.smuggled : forall n : Nat, n + 0 = n := ... re-pinned, and ran the button. It printed "no axiom, no claim", the statement digest was BYTE-IDENTICAL to the clean tree, and the run went green — while a theorem with a real axiom cone sat in the environment. In neither walk: not corpus, because an instrument is not corpus; not driver surface, because it post-dates the emitter. In no allowlist. Pinned by nothing. This repository also had no kernel-side scan at all. Its axiom gate was a source-text grep, evadable by a leading space — which its own selftest case 12 already exploited. THE FIX, ported from the ed25519 forks: · a kernel-side axiom-declaration gate that reads every compiled .olean via readModuleData. It sees what was actually stored, regardless of indentation, attributes, privacy, or where a declaration sits relative to any #eval. Membership self-derives from the manifest and the module count must match, so a deleted artifact cannot make the scan vacuous. · the ACCOUNTING IDENTITY, as set containment: every constant the kernel sees in corpus inventory union instrument surface The two walks read ENVIRONMENTS; the gate reads OBJECT FILES. What a walk cannot see because of where it sits in a file, the object file still holds. That asymmetry is the entire content of this fix. Compared as SETS deliberately. Counts cannot express the relation — an object file may hold two physical copies of one lazily-materialised equation lemma while an environment holds one constant per name — and arithmetic between those views misled the ed25519 version twice before it was stated as containment. PLACEMENT differs from the forks, for a reason worth recording: there the audit drivers are members of the compile manifest, so a gate beside the compile phase finds them. Here AxiomCheck is compiled by Phase 3 and Inventory by Phase 3b, so an earlier gate fails on a missing artifact — which it did, correctly, on the first port. It runs inside Phase 3b, because the instruments are exactly what it must see. VERIFIED with the reviewer's own payload, which previously went green: ACCOUNTING FAILED: the kernel holds constants that neither walk accounts for: bait bait.smuggled selftest_audit.sh: 14 attack cases -> 15. Note in the new case, because it cost two iterations: `theorem bait.smuggled : True := trivial` does NOT exercise this gate — Phase 1's stub audit greps for `: True :=` and catches it first. Real defence in depth, but the naive payload never reaches the gate under test, so the case uses the reviewer's original. Two residues fixed while adding it, both the same shape: a case that was last when written, leaving state the next case inherits. Case 13 restored AxiomCheck.lean but not its pin; case 9 left its rogue gen file. Fixed at the point of use so each case keeps testing what it tested before. Button green (234 declarations across 11 modules, all accounted for), 15/15 self-test green, ATTESTATION GREEN with fidelity.
2026-08-02 00:51:55 +00:00
for name in expected do
let p := dir / name
-- FAIL CLOSED ON ABSENCE: a missing artifact would make this scan vacuous
-- for that module, so it is an error and never a skip.
unless (← p.pathExists) do
throwError "MISSING ARTIFACT: {p} — the kernel gate would be vacuous for it"
let (mod, _) ← readModuleData p
nMod := nMod + 1
for ci in mod.constants do
nConst := nConst + 1
verification: separate the two accounting questions (round-9 review, Claude N2) Phase 2c-accounting asked one question with a name-keyed identity: is every kernel constant covered by the corpus inventory or the instrument surface? Keying on the name alone conflates that with a second, different question -- does the kernel attribute a declaration to the same module the walk does? Pair-keying the identity (module|name) was the obvious fix and is wrong: it fails on legitimate per-module duplicates. Lean materialises equation lemmas lazily, so each module forcing an unfold gets its own copy in its object file (GPT-5.6 round-7 F8). Those records differ from the walk only in module attribution, and every one of their names is accounted for elsewhere. So the block now asks both questions and reports them separately: coverage stays name-keyed and fail-closed, module attribution is counted and printed rather than suppressed. A divergence is now visible instead of either passing silently or failing for the wrong reason. The accumulator declines the second question and says why: its INV rows carry no module column (4 fields), so its records cannot be compared as pairs at all. Gating on the field count rather than on the row tag -- the shape of the record, not the spelling of its label. Adding that column is the open follow-up; until then the identity there is name-keyed only, which is weaker and now says so. Certified by the round-14 sweep: 50/50 green across all six repositories, both buttons and every self-test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 01:17:05 +00:00
seen := seen.insert ("Proofs." ++ (name.dropRight 6), ci.name)
Round-7 F2: account for every constant the kernel sees THE DEFECT, demonstrated by a reviewer with a working payload. The driver surface is reported by an `#eval` inside Proofs/Inventory.lean. Anything declared AFTER that command is in the compiled object file but does not exist in the environment while the command runs, so the walk cannot see it. The reviewer appended def bait : Nat := 0 theorem bait.smuggled : forall n : Nat, n + 0 = n := ... re-pinned, and ran the button. It printed "no axiom, no claim", the statement digest was BYTE-IDENTICAL to the clean tree, and the run went green — while a theorem with a real axiom cone sat in the environment. In neither walk: not corpus, because an instrument is not corpus; not driver surface, because it post-dates the emitter. In no allowlist. Pinned by nothing. This repository also had no kernel-side scan at all. Its axiom gate was a source-text grep, evadable by a leading space — which its own selftest case 12 already exploited. THE FIX, ported from the ed25519 forks: · a kernel-side axiom-declaration gate that reads every compiled .olean via readModuleData. It sees what was actually stored, regardless of indentation, attributes, privacy, or where a declaration sits relative to any #eval. Membership self-derives from the manifest and the module count must match, so a deleted artifact cannot make the scan vacuous. · the ACCOUNTING IDENTITY, as set containment: every constant the kernel sees in corpus inventory union instrument surface The two walks read ENVIRONMENTS; the gate reads OBJECT FILES. What a walk cannot see because of where it sits in a file, the object file still holds. That asymmetry is the entire content of this fix. Compared as SETS deliberately. Counts cannot express the relation — an object file may hold two physical copies of one lazily-materialised equation lemma while an environment holds one constant per name — and arithmetic between those views misled the ed25519 version twice before it was stated as containment. PLACEMENT differs from the forks, for a reason worth recording: there the audit drivers are members of the compile manifest, so a gate beside the compile phase finds them. Here AxiomCheck is compiled by Phase 3 and Inventory by Phase 3b, so an earlier gate fails on a missing artifact — which it did, correctly, on the first port. It runs inside Phase 3b, because the instruments are exactly what it must see. VERIFIED with the reviewer's own payload, which previously went green: ACCOUNTING FAILED: the kernel holds constants that neither walk accounts for: bait bait.smuggled selftest_audit.sh: 14 attack cases -> 15. Note in the new case, because it cost two iterations: `theorem bait.smuggled : True := trivial` does NOT exercise this gate — Phase 1's stub audit greps for `: True :=` and catches it first. Real defence in depth, but the naive payload never reaches the gate under test, so the case uses the reviewer's original. Two residues fixed while adding it, both the same shape: a case that was last when written, leaving state the next case inherits. Case 13 restored AxiomCheck.lean but not its pin; case 9 left its rogue gen file. Fixed at the point of use so each case keeps testing what it tested before. Button green (234 declarations across 11 modules, all accounted for), 15/15 self-test green, ATTESTATION GREEN with fidelity.
2026-08-02 00:51:55 +00:00
if ci matches .axiomInfo _ then
errs := errs.push s!" {name}: {ci.name}"
unless errs.isEmpty do
throwError "AXIOM DECLARED under Proofs/ (kernel-side gate):\n{String.intercalate "\n" errs.toList}"
logInfo s!" kernel confirms: {nConst} declarations across {nMod} compiled modules, none is an axiom"
verification: separate the two accounting questions (round-9 review, Claude N2) Phase 2c-accounting asked one question with a name-keyed identity: is every kernel constant covered by the corpus inventory or the instrument surface? Keying on the name alone conflates that with a second, different question -- does the kernel attribute a declaration to the same module the walk does? Pair-keying the identity (module|name) was the obvious fix and is wrong: it fails on legitimate per-module duplicates. Lean materialises equation lemmas lazily, so each module forcing an unfold gets its own copy in its object file (GPT-5.6 round-7 F8). Those records differ from the walk only in module attribution, and every one of their names is accounted for elsewhere. So the block now asks both questions and reports them separately: coverage stays name-keyed and fail-closed, module attribution is counted and printed rather than suppressed. A divergence is now visible instead of either passing silently or failing for the wrong reason. The accumulator declines the second question and says why: its INV rows carry no module column (4 fields), so its records cannot be compared as pairs at all. Gating on the field count rather than on the row tag -- the shape of the record, not the spelling of its label. Adding that column is the open follow-up; until then the identity there is name-keyed only, which is weaker and now says so. Certified by the round-14 sweep: 50/50 green across all six repositories, both buttons and every self-test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 01:17:05 +00:00
for (m, n) in seen do IO.println s!"KERNEL-NAME|{m}|{n}"
Round-7 F2: account for every constant the kernel sees THE DEFECT, demonstrated by a reviewer with a working payload. The driver surface is reported by an `#eval` inside Proofs/Inventory.lean. Anything declared AFTER that command is in the compiled object file but does not exist in the environment while the command runs, so the walk cannot see it. The reviewer appended def bait : Nat := 0 theorem bait.smuggled : forall n : Nat, n + 0 = n := ... re-pinned, and ran the button. It printed "no axiom, no claim", the statement digest was BYTE-IDENTICAL to the clean tree, and the run went green — while a theorem with a real axiom cone sat in the environment. In neither walk: not corpus, because an instrument is not corpus; not driver surface, because it post-dates the emitter. In no allowlist. Pinned by nothing. This repository also had no kernel-side scan at all. Its axiom gate was a source-text grep, evadable by a leading space — which its own selftest case 12 already exploited. THE FIX, ported from the ed25519 forks: · a kernel-side axiom-declaration gate that reads every compiled .olean via readModuleData. It sees what was actually stored, regardless of indentation, attributes, privacy, or where a declaration sits relative to any #eval. Membership self-derives from the manifest and the module count must match, so a deleted artifact cannot make the scan vacuous. · the ACCOUNTING IDENTITY, as set containment: every constant the kernel sees in corpus inventory union instrument surface The two walks read ENVIRONMENTS; the gate reads OBJECT FILES. What a walk cannot see because of where it sits in a file, the object file still holds. That asymmetry is the entire content of this fix. Compared as SETS deliberately. Counts cannot express the relation — an object file may hold two physical copies of one lazily-materialised equation lemma while an environment holds one constant per name — and arithmetic between those views misled the ed25519 version twice before it was stated as containment. PLACEMENT differs from the forks, for a reason worth recording: there the audit drivers are members of the compile manifest, so a gate beside the compile phase finds them. Here AxiomCheck is compiled by Phase 3 and Inventory by Phase 3b, so an earlier gate fails on a missing artifact — which it did, correctly, on the first port. It runs inside Phase 3b, because the instruments are exactly what it must see. VERIFIED with the reviewer's own payload, which previously went green: ACCOUNTING FAILED: the kernel holds constants that neither walk accounts for: bait bait.smuggled selftest_audit.sh: 14 attack cases -> 15. Note in the new case, because it cost two iterations: `theorem bait.smuggled : True := trivial` does NOT exercise this gate — Phase 1's stub audit greps for `: True :=` and catches it first. Real defence in depth, but the naive payload never reaches the gate under test, so the case uses the reviewer's original. Two residues fixed while adding it, both the same shape: a case that was last when written, leaving state the next case inherits. Case 13 restored AxiomCheck.lean but not its pin; case 9 left its rogue gen file. Fixed at the point of use so each case keeps testing what it tested before. Button green (234 declarations across 11 modules, all accounted for), 15/15 self-test green, ATTESTATION GREEN with fidelity.
2026-08-02 00:51:55 +00:00
LEANGATE
cd "$AENEAS_LEAN"
AXGATE_RC=0
lake env bash -c "
set -euo pipefail
cd '$HERE/gen' && export LEAN_PATH=\"\$LEAN_PATH:\$PWD:$HERE\"
cd '$HERE'
LEAN_TIMEOUT=$TIMEOUT LEAN_MAX_CORES=$CORES '$HERE/lean-guard' '$AXGATE'
" 2>&1 | tee "$KERNLOG" || AXGATE_RC=${PIPESTATUS[0]}
cd "$HERE"
rm -f "$AXGATE" "${AXGATE%.lean}.olean"
if [ "$AXGATE_RC" -ne 0 ]; then
echo "AXIOM SMUGGLING GATE FAILED (kernel-side) — see the error above."
rm -f "$KERNLOG" "$INVLOG"; exit 1
fi
echo ""
# ── THE ACCOUNTING IDENTITY ─────────────────────────────────────────────────
# Ported from the ed25519 forks, and the reason it is here is a demonstrated
# attack, not symmetry. A reviewer appended to Proofs/Inventory.lean, AFTER the
# `#eval` that performs the driver walk:
#
# def bait : Nat := 0
# theorem bait.smuggled : ... := ...
#
# re-pinned, and ran the button. It printed "no axiom, no claim", the statement
# digest was byte-identical to the clean tree, and the run went green — while a
# theorem with a real axiom cone sat in the compiled environment. It was in
# neither walk: not corpus, because an instrument is not corpus; not driver
# surface, because it post-dates the emitter that reports the driver surface.
#
# The two walks read ENVIRONMENTS. Phase 2b reads OBJECT FILES. What a walk
# cannot see because of where it sits in a file, the object file still holds.
# So the property enforced here is containment, and it is what closes the hole:
#
# every constant the kernel sees ⊆ corpus inventory instrument surface
#
# Compared as SETS, deliberately. Counts cannot express this relation: an
# object file may hold two physical copies of one lazily-materialised equation
# lemma, while an environment holds one constant per name — arithmetic between
# those views misled the ed25519 version of this check twice before it was
# stated as containment.
KERN_NAMES=$(mktemp /tmp/acc-kernnames-XXXX.txt)
ACCT_NAMES=$(mktemp /tmp/acc-acctnames-XXXX.txt)
verification: separate the two accounting questions (round-9 review, Claude N2) Phase 2c-accounting asked one question with a name-keyed identity: is every kernel constant covered by the corpus inventory or the instrument surface? Keying on the name alone conflates that with a second, different question -- does the kernel attribute a declaration to the same module the walk does? Pair-keying the identity (module|name) was the obvious fix and is wrong: it fails on legitimate per-module duplicates. Lean materialises equation lemmas lazily, so each module forcing an unfold gets its own copy in its object file (GPT-5.6 round-7 F8). Those records differ from the walk only in module attribution, and every one of their names is accounted for elsewhere. So the block now asks both questions and reports them separately: coverage stays name-keyed and fail-closed, module attribution is counted and printed rather than suppressed. A divergence is now visible instead of either passing silently or failing for the wrong reason. The accumulator declines the second question and says why: its INV rows carry no module column (4 fields), so its records cannot be compared as pairs at all. Gating on the field count rather than on the row tag -- the shape of the record, not the spelling of its label. Adding that column is the open follow-up; until then the identity there is name-keyed only, which is weaker and now says so. Certified by the round-14 sweep: 50/50 green across all six repositories, both buttons and every self-test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 01:17:05 +00:00
LC_ALL=C grep '^KERNEL-NAME|' "$KERNLOG" | cut -d'|' -f3 | LC_ALL=C sort -u > "$KERN_NAMES"
Round-7 F2: account for every constant the kernel sees THE DEFECT, demonstrated by a reviewer with a working payload. The driver surface is reported by an `#eval` inside Proofs/Inventory.lean. Anything declared AFTER that command is in the compiled object file but does not exist in the environment while the command runs, so the walk cannot see it. The reviewer appended def bait : Nat := 0 theorem bait.smuggled : forall n : Nat, n + 0 = n := ... re-pinned, and ran the button. It printed "no axiom, no claim", the statement digest was BYTE-IDENTICAL to the clean tree, and the run went green — while a theorem with a real axiom cone sat in the environment. In neither walk: not corpus, because an instrument is not corpus; not driver surface, because it post-dates the emitter. In no allowlist. Pinned by nothing. This repository also had no kernel-side scan at all. Its axiom gate was a source-text grep, evadable by a leading space — which its own selftest case 12 already exploited. THE FIX, ported from the ed25519 forks: · a kernel-side axiom-declaration gate that reads every compiled .olean via readModuleData. It sees what was actually stored, regardless of indentation, attributes, privacy, or where a declaration sits relative to any #eval. Membership self-derives from the manifest and the module count must match, so a deleted artifact cannot make the scan vacuous. · the ACCOUNTING IDENTITY, as set containment: every constant the kernel sees in corpus inventory union instrument surface The two walks read ENVIRONMENTS; the gate reads OBJECT FILES. What a walk cannot see because of where it sits in a file, the object file still holds. That asymmetry is the entire content of this fix. Compared as SETS deliberately. Counts cannot express the relation — an object file may hold two physical copies of one lazily-materialised equation lemma while an environment holds one constant per name — and arithmetic between those views misled the ed25519 version twice before it was stated as containment. PLACEMENT differs from the forks, for a reason worth recording: there the audit drivers are members of the compile manifest, so a gate beside the compile phase finds them. Here AxiomCheck is compiled by Phase 3 and Inventory by Phase 3b, so an earlier gate fails on a missing artifact — which it did, correctly, on the first port. It runs inside Phase 3b, because the instruments are exactly what it must see. VERIFIED with the reviewer's own payload, which previously went green: ACCOUNTING FAILED: the kernel holds constants that neither walk accounts for: bait bait.smuggled selftest_audit.sh: 14 attack cases -> 15. Note in the new case, because it cost two iterations: `theorem bait.smuggled : True := trivial` does NOT exercise this gate — Phase 1's stub audit greps for `: True :=` and catches it first. Real defence in depth, but the naive payload never reaches the gate under test, so the case uses the reviewer's original. Two residues fixed while adding it, both the same shape: a case that was last when written, leaving state the next case inherits. Case 13 restored AxiomCheck.lean but not its pin; case 9 left its rogue gen file. Fixed at the point of use so each case keeps testing what it tested before. Button green (234 declarations across 11 modules, all accounted for), 15/15 self-test green, ATTESTATION GREEN with fidelity.
2026-08-02 00:51:55 +00:00
{ LC_ALL=C awk -F'|' '/^INV\|/{print $2}' "$INVLOG"
audit: bind the scalar statements, and make the accounting identity mean audit Closes four round-7/8 findings. Certified by the round-12 sweep: five repositories, both buttons and every self-test, 48/48 GREEN. ── `scalar-statements-unbound` (gpt, round 7, CRITICAL) ──────────────────── The main button bound its 31 certificates' elaborated statements and reachable specification bodies. This button bound NONE of its thirteen, while TRUSTED-BASE item 8 said the audit covers "every certificate" — false across the 44-certificate surface. The finding was raised in round 7, lost from the round-8 work list by an F-number collision between two reviewers, and re-raised in round 8. Proofs/ScalarAudit.lean is generated from each fork's OWN Audit.lean, so the canonicalisation is provably the same code: pp.all rendering, whitespace normalisation, transitive specification closure. check-scalar.sh Phase 3c pins the block's digest, requires the committed copy to match byte-for-byte so a mismatch can be DIFFED, and cross-checks the auditor's certificate set against the button's CERTS array. dalek ecf3a3f8 · anza 0d942e47 · risc0 4b550a61 · betrusted 4b550a61 risc0 and betrusted share a digest and that is correct, not a collision: their ScalarSubSpec.lean differs only in doc prose and in `black_box` entries inside `simp only [...]` lists AFTER `:= by`. Proof scripts. They bind the same statements over the same specifications, which is the documented scope. selftest-scalar-statements.sh ships the two attacks the reviewer asked for: ok gutted statement caught (cone unchanged) ok rewritten specification body caught (name and cone unchanged) The second rewrites a reachable reference body to `id (…)` — DEFINITIONALLY EQUAL, so the corpus compiles and every proof typechecks and the cone is byte-identical. Every earlier phase is blind to it. ── `drv-surface-no-cones` + `accounting-certifies-enumeration` (claude) ──── The round-7 accounting identity proved every kernel constant was ENUMERATED. The reviewer showed enumeration is not audit: their planted claim WAS enumerated, as DRV|LTLAccAudit.bait.smuggled|theorem with a real cone, and nothing examined it — rows had no cone, no allowlist covered them, the statement digest does not reach instruments, and Phase 2b gates DECLARED AXIOMS, a different question. "Progress of one step, not two." DRV rows now carry their axiom cone and are pinned in driver-allowlist.txt by inventory_gate.sh with a DRV tag — the same implementation that pins the corpus, in both directions, because a second copy of a coverage gate is a second thing to drift. The axiom policy is per-surface and enforced per surface: the corpus admits exactly the sanctioned boundary, the instruments admit none, and an instrument axiom fails EVEN WHEN ALLOWLISTED. Verified with the reviewer's own payload, both placements: before the walk -> UNCLASSIFIED: DRV|…|bait.smuggled|theorem|Classical.choice,Quot.sound,propext after the walk -> ACCOUNTING FAILED names it (kernel-side) ── `drv-naming-heuristic` (claude, round 7) ──────────────────────────────── Retired as load-bearing rather than patched. The rule admits a theorem whose name extends a constant declared alongside it, and "breaks in one line" — declare `def bait`, then `theorem bait.smuggled` walks through. It stays as a fast readable first check; membership in a committed allowlist is what now carries the weight, and a new row fails closed whatever it is called. ── what round 11 caught, which was mine ─────────────────────────────────── DRV rows first shipped WITHOUT their originating driver. dalek and anza run two drivers, each declaring its own `corpus`; keyed on name alone those two distinct declarations produced one byte-identical row, `sort -u` collapsed them, and the trailers summed to 37 against 36. The estate had already learned this on the corpus walk — INV rows carry their module because two modules both declare CurveFieldProofs.zero_spec — and I rebuilt the record without it. Rows now carry their driver, and the gate FAILS CLOSED ON DUPLICATE RECORDS naming the collision: two declarations sharing one entry means one is covered by the other's, which is exactly how a real declaration hides. The trailer now checks what the drivers EMITTED, not what survives de-duplication — conflating "the run was truncated" with "two rows were identical" is what let a record-format defect present itself as an arithmetic complaint. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 10:15:26 +00:00
LC_ALL=C grep '^DRV|' "$INVLOG" | cut -d'|' -f3
Round-7 F2: account for every constant the kernel sees THE DEFECT, demonstrated by a reviewer with a working payload. The driver surface is reported by an `#eval` inside Proofs/Inventory.lean. Anything declared AFTER that command is in the compiled object file but does not exist in the environment while the command runs, so the walk cannot see it. The reviewer appended def bait : Nat := 0 theorem bait.smuggled : forall n : Nat, n + 0 = n := ... re-pinned, and ran the button. It printed "no axiom, no claim", the statement digest was BYTE-IDENTICAL to the clean tree, and the run went green — while a theorem with a real axiom cone sat in the environment. In neither walk: not corpus, because an instrument is not corpus; not driver surface, because it post-dates the emitter. In no allowlist. Pinned by nothing. This repository also had no kernel-side scan at all. Its axiom gate was a source-text grep, evadable by a leading space — which its own selftest case 12 already exploited. THE FIX, ported from the ed25519 forks: · a kernel-side axiom-declaration gate that reads every compiled .olean via readModuleData. It sees what was actually stored, regardless of indentation, attributes, privacy, or where a declaration sits relative to any #eval. Membership self-derives from the manifest and the module count must match, so a deleted artifact cannot make the scan vacuous. · the ACCOUNTING IDENTITY, as set containment: every constant the kernel sees in corpus inventory union instrument surface The two walks read ENVIRONMENTS; the gate reads OBJECT FILES. What a walk cannot see because of where it sits in a file, the object file still holds. That asymmetry is the entire content of this fix. Compared as SETS deliberately. Counts cannot express the relation — an object file may hold two physical copies of one lazily-materialised equation lemma while an environment holds one constant per name — and arithmetic between those views misled the ed25519 version twice before it was stated as containment. PLACEMENT differs from the forks, for a reason worth recording: there the audit drivers are members of the compile manifest, so a gate beside the compile phase finds them. Here AxiomCheck is compiled by Phase 3 and Inventory by Phase 3b, so an earlier gate fails on a missing artifact — which it did, correctly, on the first port. It runs inside Phase 3b, because the instruments are exactly what it must see. VERIFIED with the reviewer's own payload, which previously went green: ACCOUNTING FAILED: the kernel holds constants that neither walk accounts for: bait bait.smuggled selftest_audit.sh: 14 attack cases -> 15. Note in the new case, because it cost two iterations: `theorem bait.smuggled : True := trivial` does NOT exercise this gate — Phase 1's stub audit greps for `: True :=` and catches it first. Real defence in depth, but the naive payload never reaches the gate under test, so the case uses the reviewer's original. Two residues fixed while adding it, both the same shape: a case that was last when written, leaving state the next case inherits. Case 13 restored AxiomCheck.lean but not its pin; case 9 left its rogue gen file. Fixed at the point of use so each case keeps testing what it tested before. Button green (234 declarations across 11 modules, all accounted for), 15/15 self-test green, ATTESTATION GREEN with fidelity.
2026-08-02 00:51:55 +00:00
} | LC_ALL=C sort -u > "$ACCT_NAMES"
verification: separate the two accounting questions (round-9 review, Claude N2) Phase 2c-accounting asked one question with a name-keyed identity: is every kernel constant covered by the corpus inventory or the instrument surface? Keying on the name alone conflates that with a second, different question -- does the kernel attribute a declaration to the same module the walk does? Pair-keying the identity (module|name) was the obvious fix and is wrong: it fails on legitimate per-module duplicates. Lean materialises equation lemmas lazily, so each module forcing an unfold gets its own copy in its object file (GPT-5.6 round-7 F8). Those records differ from the walk only in module attribution, and every one of their names is accounted for elsewhere. So the block now asks both questions and reports them separately: coverage stays name-keyed and fail-closed, module attribution is counted and printed rather than suppressed. A divergence is now visible instead of either passing silently or failing for the wrong reason. The accumulator declines the second question and says why: its INV rows carry no module column (4 fields), so its records cannot be compared as pairs at all. Gating on the field count rather than on the row tag -- the shape of the record, not the spelling of its label. Adding that column is the open follow-up; until then the identity there is name-keyed only, which is weaker and now says so. Certified by the round-14 sweep: 50/50 green across all six repositories, both buttons and every self-test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 01:17:05 +00:00
# TWO QUESTIONS, NOT ONE — round-9 review (Claude, N2), and the measurement
# that answered it.
#
# The reviewer was right that keying this identity on NAME ALONE is weaker than
# it reads: the allowlists are keyed module|name precisely because a name is not
# unique, and this corpus holds two distinct CurveFieldProofs.zero_spec
# declarations. So the pair is the right key — and keying on it revealed why the
# straightforward fix is not available.
#
# 36 kernel pairs in this fork do not match a walk pair, and EVERY ONE of them
# has its name accounted for under a DIFFERENT module. Example:
# kernel: Proofs.ConstSpecs|CurveFieldProofs.denote.eq_1
# kernel: Proofs.SubNegSpec|CurveFieldProofs.denote.eq_1 <- same name twice
# walk: Proofs.SubNegSpec|CurveFieldProofs.denote.eq_1
# That is GPT-5.6's round-7 F8: lazy equation lemmas are materialised PER
# MODULE, so every module forcing an unfold gets its own copy in its object
# file. The kernel reads object files and sees both copies; the environment walk
# reads one merged environment and sees the name once. Both views are correct
# about different things, so a pair mismatch here is not evidence of an
# unexamined declaration, and suppressing it with an exception list would be the
# fudge term four-fork data already refuted once.
#
# So the phase asks both questions and answers them separately:
# UNACCOUNTED a name the kernel holds that NO walk mentions -> FAILS
# MULTI-MODULE a pair that differs only in module attribution -> COUNTED and
# REPORTED, never silently dropped, so the F8 phenomenon is
# visible every run and a change in it is a change a reader sees
KERN_PAIRS=$(mktemp /tmp/check-kernpairs-XXXX.txt)
ACCT_PAIRS=$(mktemp /tmp/check-acctpairs-XXXX.txt)
LC_ALL=C grep '^KERNEL-NAME|' "$KERNLOG" | cut -d'|' -f2,3 | LC_ALL=C sort -u > "$KERN_PAIRS"
{ LC_ALL=C awk -F'|' '/^INV\|/{print $2"|"$3}' "$HERE/inventory-allowlist.txt"
LC_ALL=C grep '^DRV|' "$INVLOG" | cut -d'|' -f2,3
} | LC_ALL=C sort -u > "$ACCT_PAIRS"
# THIS COMPARISON IS NOT AVAILABLE HERE, and saying so beats printing a number.
# The ed25519 repositories and fips205 use INV|module|name|kind|cone; THIS
# repository uses INV|name|kind|cone — four fields, no module column. The tag is
# the same and the record is not. Keying field 2 as a module here yields
# `name|kind`, which matches nothing, and the first run of this port duly
# reported 216 of 234 records as module-attribution differences. That number was
# meaningless. A wrong number in a green banner is the failure this estate keeps
# committing, so the check now tests its own applicability from the record shape
# rather than assuming it from the tag.
INV_FIELDS=$(LC_ALL=C grep -m1 '^INV|' "$HERE/inventory-allowlist.txt" | awk -F'|' '{print NF}')
if [ "${INV_FIELDS:-0}" -ge 5 ]; then
MULTIMOD=$(LC_ALL=C comm -23 "$KERN_PAIRS" "$ACCT_PAIRS" | wc -l)
MULTIMOD_NOTE="$MULTIMOD kernel record(s) differ from a walk only in module attribution (lazy equation lemmas materialised per module — GPT-5.6 round-7 F8, reported not suppressed)"
else
MULTIMOD=0
MULTIMOD_NOTE="not computed — this repository's INV rows carry no module column ($INV_FIELDS fields), so kernel and walk records cannot be compared as module|name pairs. Adding that column is the open follow-up; until then the identity here is name-keyed only, which is weaker (round-9 review, Claude N2)."
fi
Round-7 F2: account for every constant the kernel sees THE DEFECT, demonstrated by a reviewer with a working payload. The driver surface is reported by an `#eval` inside Proofs/Inventory.lean. Anything declared AFTER that command is in the compiled object file but does not exist in the environment while the command runs, so the walk cannot see it. The reviewer appended def bait : Nat := 0 theorem bait.smuggled : forall n : Nat, n + 0 = n := ... re-pinned, and ran the button. It printed "no axiom, no claim", the statement digest was BYTE-IDENTICAL to the clean tree, and the run went green — while a theorem with a real axiom cone sat in the environment. In neither walk: not corpus, because an instrument is not corpus; not driver surface, because it post-dates the emitter. In no allowlist. Pinned by nothing. This repository also had no kernel-side scan at all. Its axiom gate was a source-text grep, evadable by a leading space — which its own selftest case 12 already exploited. THE FIX, ported from the ed25519 forks: · a kernel-side axiom-declaration gate that reads every compiled .olean via readModuleData. It sees what was actually stored, regardless of indentation, attributes, privacy, or where a declaration sits relative to any #eval. Membership self-derives from the manifest and the module count must match, so a deleted artifact cannot make the scan vacuous. · the ACCOUNTING IDENTITY, as set containment: every constant the kernel sees in corpus inventory union instrument surface The two walks read ENVIRONMENTS; the gate reads OBJECT FILES. What a walk cannot see because of where it sits in a file, the object file still holds. That asymmetry is the entire content of this fix. Compared as SETS deliberately. Counts cannot express the relation — an object file may hold two physical copies of one lazily-materialised equation lemma while an environment holds one constant per name — and arithmetic between those views misled the ed25519 version twice before it was stated as containment. PLACEMENT differs from the forks, for a reason worth recording: there the audit drivers are members of the compile manifest, so a gate beside the compile phase finds them. Here AxiomCheck is compiled by Phase 3 and Inventory by Phase 3b, so an earlier gate fails on a missing artifact — which it did, correctly, on the first port. It runs inside Phase 3b, because the instruments are exactly what it must see. VERIFIED with the reviewer's own payload, which previously went green: ACCOUNTING FAILED: the kernel holds constants that neither walk accounts for: bait bait.smuggled selftest_audit.sh: 14 attack cases -> 15. Note in the new case, because it cost two iterations: `theorem bait.smuggled : True := trivial` does NOT exercise this gate — Phase 1's stub audit greps for `: True :=` and catches it first. Real defence in depth, but the naive payload never reaches the gate under test, so the case uses the reviewer's original. Two residues fixed while adding it, both the same shape: a case that was last when written, leaving state the next case inherits. Case 13 restored AxiomCheck.lean but not its pin; case 9 left its rogue gen file. Fixed at the point of use so each case keeps testing what it tested before. Button green (234 declarations across 11 modules, all accounted for), 15/15 self-test green, ATTESTATION GREEN with fidelity.
2026-08-02 00:51:55 +00:00
UNACCOUNTED=$(LC_ALL=C comm -23 "$KERN_NAMES" "$ACCT_NAMES")
if [ ! -s "$KERN_NAMES" ]; then
echo " ACCOUNTING FAILED: Phase 2b reported no constant names — the scan was vacuous"
COVFAIL=1
elif [ -n "$UNACCOUNTED" ]; then
echo " ACCOUNTING FAILED: the kernel holds constants that neither walk accounts for:"
printf '%s\n' "$UNACCOUNTED" | head -20 | sed 's/^/ /'
COVFAIL=1
else
verification: separate the two accounting questions (round-9 review, Claude N2) Phase 2c-accounting asked one question with a name-keyed identity: is every kernel constant covered by the corpus inventory or the instrument surface? Keying on the name alone conflates that with a second, different question -- does the kernel attribute a declaration to the same module the walk does? Pair-keying the identity (module|name) was the obvious fix and is wrong: it fails on legitimate per-module duplicates. Lean materialises equation lemmas lazily, so each module forcing an unfold gets its own copy in its object file (GPT-5.6 round-7 F8). Those records differ from the walk only in module attribution, and every one of their names is accounted for elsewhere. So the block now asks both questions and reports them separately: coverage stays name-keyed and fail-closed, module attribution is counted and printed rather than suppressed. A divergence is now visible instead of either passing silently or failing for the wrong reason. The accumulator declines the second question and says why: its INV rows carry no module column (4 fields), so its records cannot be compared as pairs at all. Gating on the field count rather than on the row tag -- the shape of the record, not the spelling of its label. Adding that column is the open follow-up; until then the identity there is name-keyed only, which is weaker and now says so. Certified by the round-14 sweep: 50/50 green across all six repositories, both buttons and every self-test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 01:17:05 +00:00
echo " accounting: every one of $(wc -l < "$KERN_NAMES") kernel constant names is covered by the corpus inventory or the instrument surface"
echo " multi-module: $MULTIMOD_NOTE"
Round-7 F2: account for every constant the kernel sees THE DEFECT, demonstrated by a reviewer with a working payload. The driver surface is reported by an `#eval` inside Proofs/Inventory.lean. Anything declared AFTER that command is in the compiled object file but does not exist in the environment while the command runs, so the walk cannot see it. The reviewer appended def bait : Nat := 0 theorem bait.smuggled : forall n : Nat, n + 0 = n := ... re-pinned, and ran the button. It printed "no axiom, no claim", the statement digest was BYTE-IDENTICAL to the clean tree, and the run went green — while a theorem with a real axiom cone sat in the environment. In neither walk: not corpus, because an instrument is not corpus; not driver surface, because it post-dates the emitter. In no allowlist. Pinned by nothing. This repository also had no kernel-side scan at all. Its axiom gate was a source-text grep, evadable by a leading space — which its own selftest case 12 already exploited. THE FIX, ported from the ed25519 forks: · a kernel-side axiom-declaration gate that reads every compiled .olean via readModuleData. It sees what was actually stored, regardless of indentation, attributes, privacy, or where a declaration sits relative to any #eval. Membership self-derives from the manifest and the module count must match, so a deleted artifact cannot make the scan vacuous. · the ACCOUNTING IDENTITY, as set containment: every constant the kernel sees in corpus inventory union instrument surface The two walks read ENVIRONMENTS; the gate reads OBJECT FILES. What a walk cannot see because of where it sits in a file, the object file still holds. That asymmetry is the entire content of this fix. Compared as SETS deliberately. Counts cannot express the relation — an object file may hold two physical copies of one lazily-materialised equation lemma while an environment holds one constant per name — and arithmetic between those views misled the ed25519 version twice before it was stated as containment. PLACEMENT differs from the forks, for a reason worth recording: there the audit drivers are members of the compile manifest, so a gate beside the compile phase finds them. Here AxiomCheck is compiled by Phase 3 and Inventory by Phase 3b, so an earlier gate fails on a missing artifact — which it did, correctly, on the first port. It runs inside Phase 3b, because the instruments are exactly what it must see. VERIFIED with the reviewer's own payload, which previously went green: ACCOUNTING FAILED: the kernel holds constants that neither walk accounts for: bait bait.smuggled selftest_audit.sh: 14 attack cases -> 15. Note in the new case, because it cost two iterations: `theorem bait.smuggled : True := trivial` does NOT exercise this gate — Phase 1's stub audit greps for `: True :=` and catches it first. Real defence in depth, but the naive payload never reaches the gate under test, so the case uses the reviewer's original. Two residues fixed while adding it, both the same shape: a case that was last when written, leaving state the next case inherits. Case 13 restored AxiomCheck.lean but not its pin; case 9 left its rogue gen file. Fixed at the point of use so each case keeps testing what it tested before. Button green (234 declarations across 11 modules, all accounted for), 15/15 self-test green, ATTESTATION GREEN with fidelity.
2026-08-02 00:51:55 +00:00
fi
rm -f "$KERN_NAMES" "$ACCT_NAMES" "$KERNLOG"
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
# The inventory's corpus-module list must BE the compile manifest — both
# directions, so neither can drift from the other silently.
P2-b: close classes 9 and 15 — the instruments, and the places nothing looked CLASS 15 — a Lean file where no phase was looking. The dead-file scan read Proofs/*.lean and gen/LTLAcc/*.lean and nothing else. A module at the verification root, or under any other gen/ subdirectory, was neither compiled nor rejected — while remaining importable by name, since LEAN_PATH contains both roots. That is a source of the corpus that no phase reads and no pin covers, which is exactly what the dead-file gate exists to forbid; it was simply looking in two places instead of everywhere. Now nothing may live in either root but the two enumerated sets. CLASS 9 — the instruments' own declaration surface. AxiomCheck.lean and Inventory.lean perform the audit and are therefore not corpus, so nothing inventoried what THEY declare. Inventory.lean now walks both: AxiomCheck by module index, and itself as the module still being elaborated, whose declarations are the ones the environment reports with no originating module. That is what makes the inventory cover the instrument that produces it rather than exempting itself. The policy is not "declare nothing" — this file legitimately declares its machinery. It is that an instrument may declare only inert definitions. An axiom here would widen the trusted base without appearing in any certificate's cone; a theorem here would be a claim no certificate covers and no allowlist pins. A flat ban on theorems was WRONG and was measured to be wrong: defining a function by well-founded recursion makes the elaborator emit its own obligations, and axiomCone._proof_1 rejected this very file. The distinction that holds is whether a theorem is a claim someone wrote or an artefact of a definition declared alongside it — an artefact's name extends the name of a constant declared with it. Observed surface: 18 declarations, 16 def and 2 generated obligations, no axiom, no standalone claim. The drivers are byte-pinned already, so this does not pin WHICH definitions they contain — that would add a thing to maintain without adding a thing to catch. It adds the property byte-pinning cannot give: that no instrument declares an axiom or a claim, whatever its bytes are. selftest_audit.sh: 10 cases -> 14. Case 12 uses an INDENTED axiom, because Phase 1's source grep catches an unindented one and the point is to reach the kernel-side walk standing behind it. TWO DEFECTS IN THE TEST HARNESS, found while adding the cases. · The scratch tree copied verification/ only, but the button also reads README.md and STATEMENT-MAP.md from the repository root. check.sh therefore ALWAYS died in Phase 3c in the scratch tree, which made every `if check.sh; then <attack not caught>` guard unfirable — check.sh could not pass in there even with no attack at all. Only the diagnostic greps were doing any work. The documents are now copied, and the negative test below proves the guard is live: with the driver-surface check disabled, check.sh PASSES a tree whose inventory driver declares `axiom driver_cheat : False`. · Case 9 was the last case when it was written and left its rogue gen file in place. Harmless then; the new cases inherited it. Cleaned up between the blocks rather than inside case 9, so that case still tests what it did. Also fixed while here: Phase 3b compared the compile manifest against Inventory.lean by grepping the WHOLE FILE for a backticked module name, so prose counted — a doc comment naming a module broke the count, and in the other direction a doc mention of a module missing from the array would have satisfied the presence check and hidden the omission. It now reads the arrays. Both new gates negative-tested by removal. Button green, self-test green.
2026-07-31 12:18:40 +00:00
# Read the module LISTS, not the file. This comparison used to grep the whole
# of Inventory.lean for a backticked name, which meant any PROSE mention of a
# module counted: a doc comment naming `Proofs.AxiomCheck` broke the count, and
# — worse in the other direction — a doc mention of a module missing from the
# array would have satisfied the presence check and hidden the omission. The
# manifest is the arrays; read the arrays.
MODLISTS=$(sed -n '/^def corpusModules/,/\]/p;/^def driverModules/,/\]/p' "$HERE/Proofs/Inventory.lean")
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
for m in "${GEN_MODULES[@]}" "${PROOFS[@]}"; do
mod=$(echo "$m" | sed 's|^LTLAcc/|LTLAcc.|; s|^\([A-Z]\)|Proofs.\1|; s|^Proofs\.LTLAcc\.|LTLAcc.|')
P2-b: close classes 9 and 15 — the instruments, and the places nothing looked CLASS 15 — a Lean file where no phase was looking. The dead-file scan read Proofs/*.lean and gen/LTLAcc/*.lean and nothing else. A module at the verification root, or under any other gen/ subdirectory, was neither compiled nor rejected — while remaining importable by name, since LEAN_PATH contains both roots. That is a source of the corpus that no phase reads and no pin covers, which is exactly what the dead-file gate exists to forbid; it was simply looking in two places instead of everywhere. Now nothing may live in either root but the two enumerated sets. CLASS 9 — the instruments' own declaration surface. AxiomCheck.lean and Inventory.lean perform the audit and are therefore not corpus, so nothing inventoried what THEY declare. Inventory.lean now walks both: AxiomCheck by module index, and itself as the module still being elaborated, whose declarations are the ones the environment reports with no originating module. That is what makes the inventory cover the instrument that produces it rather than exempting itself. The policy is not "declare nothing" — this file legitimately declares its machinery. It is that an instrument may declare only inert definitions. An axiom here would widen the trusted base without appearing in any certificate's cone; a theorem here would be a claim no certificate covers and no allowlist pins. A flat ban on theorems was WRONG and was measured to be wrong: defining a function by well-founded recursion makes the elaborator emit its own obligations, and axiomCone._proof_1 rejected this very file. The distinction that holds is whether a theorem is a claim someone wrote or an artefact of a definition declared alongside it — an artefact's name extends the name of a constant declared with it. Observed surface: 18 declarations, 16 def and 2 generated obligations, no axiom, no standalone claim. The drivers are byte-pinned already, so this does not pin WHICH definitions they contain — that would add a thing to maintain without adding a thing to catch. It adds the property byte-pinning cannot give: that no instrument declares an axiom or a claim, whatever its bytes are. selftest_audit.sh: 10 cases -> 14. Case 12 uses an INDENTED axiom, because Phase 1's source grep catches an unindented one and the point is to reach the kernel-side walk standing behind it. TWO DEFECTS IN THE TEST HARNESS, found while adding the cases. · The scratch tree copied verification/ only, but the button also reads README.md and STATEMENT-MAP.md from the repository root. check.sh therefore ALWAYS died in Phase 3c in the scratch tree, which made every `if check.sh; then <attack not caught>` guard unfirable — check.sh could not pass in there even with no attack at all. Only the diagnostic greps were doing any work. The documents are now copied, and the negative test below proves the guard is live: with the driver-surface check disabled, check.sh PASSES a tree whose inventory driver declares `axiom driver_cheat : False`. · Case 9 was the last case when it was written and left its rogue gen file in place. Harmless then; the new cases inherited it. Cleaned up between the blocks rather than inside case 9, so that case still tests what it did. Also fixed while here: Phase 3b compared the compile manifest against Inventory.lean by grepping the WHOLE FILE for a backticked module name, so prose counted — a doc comment naming a module broke the count, and in the other direction a doc mention of a module missing from the array would have satisfied the presence check and hidden the omission. It now reads the arrays. Both new gates negative-tested by removal. Button green, self-test green.
2026-07-31 12:18:40 +00:00
grep -qF "\`$mod" <<<"$MODLISTS" || {
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
echo " MANIFEST DRIFT: $mod compiled by check.sh but not inventoried"; COVFAIL=1; }
done
P2-b: close classes 9 and 15 — the instruments, and the places nothing looked CLASS 15 — a Lean file where no phase was looking. The dead-file scan read Proofs/*.lean and gen/LTLAcc/*.lean and nothing else. A module at the verification root, or under any other gen/ subdirectory, was neither compiled nor rejected — while remaining importable by name, since LEAN_PATH contains both roots. That is a source of the corpus that no phase reads and no pin covers, which is exactly what the dead-file gate exists to forbid; it was simply looking in two places instead of everywhere. Now nothing may live in either root but the two enumerated sets. CLASS 9 — the instruments' own declaration surface. AxiomCheck.lean and Inventory.lean perform the audit and are therefore not corpus, so nothing inventoried what THEY declare. Inventory.lean now walks both: AxiomCheck by module index, and itself as the module still being elaborated, whose declarations are the ones the environment reports with no originating module. That is what makes the inventory cover the instrument that produces it rather than exempting itself. The policy is not "declare nothing" — this file legitimately declares its machinery. It is that an instrument may declare only inert definitions. An axiom here would widen the trusted base without appearing in any certificate's cone; a theorem here would be a claim no certificate covers and no allowlist pins. A flat ban on theorems was WRONG and was measured to be wrong: defining a function by well-founded recursion makes the elaborator emit its own obligations, and axiomCone._proof_1 rejected this very file. The distinction that holds is whether a theorem is a claim someone wrote or an artefact of a definition declared alongside it — an artefact's name extends the name of a constant declared with it. Observed surface: 18 declarations, 16 def and 2 generated obligations, no axiom, no standalone claim. The drivers are byte-pinned already, so this does not pin WHICH definitions they contain — that would add a thing to maintain without adding a thing to catch. It adds the property byte-pinning cannot give: that no instrument declares an axiom or a claim, whatever its bytes are. selftest_audit.sh: 10 cases -> 14. Case 12 uses an INDENTED axiom, because Phase 1's source grep catches an unindented one and the point is to reach the kernel-side walk standing behind it. TWO DEFECTS IN THE TEST HARNESS, found while adding the cases. · The scratch tree copied verification/ only, but the button also reads README.md and STATEMENT-MAP.md from the repository root. check.sh therefore ALWAYS died in Phase 3c in the scratch tree, which made every `if check.sh; then <attack not caught>` guard unfirable — check.sh could not pass in there even with no attack at all. Only the diagnostic greps were doing any work. The documents are now copied, and the negative test below proves the guard is live: with the driver-surface check disabled, check.sh PASSES a tree whose inventory driver declares `axiom driver_cheat : False`. · Case 9 was the last case when it was written and left its rogue gen file in place. Harmless then; the new cases inherited it. Cleaned up between the blocks rather than inside case 9, so that case still tests what it did. Also fixed while here: Phase 3b compared the compile manifest against Inventory.lean by grepping the WHOLE FILE for a backticked module name, so prose counted — a doc comment naming a module broke the count, and in the other direction a doc mention of a module missing from the array would have satisfied the presence check and hidden the omission. It now reads the arrays. Both new gates negative-tested by removal. Button green, self-test green.
2026-07-31 12:18:40 +00:00
# The drivers are named in Inventory.lean too, now that it walks their
# declaration surface — so they count on both sides of this equality.
for d in "${DRIVERS[@]}"; do
[ "$d" = Inventory ] && continue # covered as the current module, which has
# no module index while it elaborates and
# so is not named in its own module list
grep -qF "\`Proofs.$d" <<<"$MODLISTS" || {
echo " MANIFEST DRIFT: driver Proofs.$d is not inventoried"; COVFAIL=1; }
done
NMANIFEST=$(( ${#GEN_MODULES[@]} + ${#PROOFS[@]} + ${#DRIVERS[@]} - 1 ))
NINV=$(grep -oE '`(LTLAcc|Proofs)\.[A-Za-z0-9_.]+' <<<"$MODLISTS" | wc -l)
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
[ "$NMANIFEST" = "$NINV" ] || {
echo " MANIFEST DRIFT: check.sh compiles $NMANIFEST modules, Inventory lists $NINV"; COVFAIL=1; }
P2-b: close classes 9 and 15 — the instruments, and the places nothing looked CLASS 15 — a Lean file where no phase was looking. The dead-file scan read Proofs/*.lean and gen/LTLAcc/*.lean and nothing else. A module at the verification root, or under any other gen/ subdirectory, was neither compiled nor rejected — while remaining importable by name, since LEAN_PATH contains both roots. That is a source of the corpus that no phase reads and no pin covers, which is exactly what the dead-file gate exists to forbid; it was simply looking in two places instead of everywhere. Now nothing may live in either root but the two enumerated sets. CLASS 9 — the instruments' own declaration surface. AxiomCheck.lean and Inventory.lean perform the audit and are therefore not corpus, so nothing inventoried what THEY declare. Inventory.lean now walks both: AxiomCheck by module index, and itself as the module still being elaborated, whose declarations are the ones the environment reports with no originating module. That is what makes the inventory cover the instrument that produces it rather than exempting itself. The policy is not "declare nothing" — this file legitimately declares its machinery. It is that an instrument may declare only inert definitions. An axiom here would widen the trusted base without appearing in any certificate's cone; a theorem here would be a claim no certificate covers and no allowlist pins. A flat ban on theorems was WRONG and was measured to be wrong: defining a function by well-founded recursion makes the elaborator emit its own obligations, and axiomCone._proof_1 rejected this very file. The distinction that holds is whether a theorem is a claim someone wrote or an artefact of a definition declared alongside it — an artefact's name extends the name of a constant declared with it. Observed surface: 18 declarations, 16 def and 2 generated obligations, no axiom, no standalone claim. The drivers are byte-pinned already, so this does not pin WHICH definitions they contain — that would add a thing to maintain without adding a thing to catch. It adds the property byte-pinning cannot give: that no instrument declares an axiom or a claim, whatever its bytes are. selftest_audit.sh: 10 cases -> 14. Case 12 uses an INDENTED axiom, because Phase 1's source grep catches an unindented one and the point is to reach the kernel-side walk standing behind it. TWO DEFECTS IN THE TEST HARNESS, found while adding the cases. · The scratch tree copied verification/ only, but the button also reads README.md and STATEMENT-MAP.md from the repository root. check.sh therefore ALWAYS died in Phase 3c in the scratch tree, which made every `if check.sh; then <attack not caught>` guard unfirable — check.sh could not pass in there even with no attack at all. Only the diagnostic greps were doing any work. The documents are now copied, and the negative test below proves the guard is live: with the driver-surface check disabled, check.sh PASSES a tree whose inventory driver declares `axiom driver_cheat : False`. · Case 9 was the last case when it was written and left its rogue gen file in place. Harmless then; the new cases inherited it. Cleaned up between the blocks rather than inside case 9, so that case still tests what it did. Also fixed while here: Phase 3b compared the compile manifest against Inventory.lean by grepping the WHOLE FILE for a backticked module name, so prose counted — a doc comment naming a module broke the count, and in the other direction a doc mention of a module missing from the array would have satisfied the presence check and hidden the omission. It now reads the arrays. Both new gates negative-tested by removal. Button green, self-test green.
2026-07-31 12:18:40 +00:00
# CLASS 9. The driver-surface block must actually have RUN. Its violations are
# raised inside Lean, so a walk that silently did not execute would look exactly
# like a clean one — the same vacuous-pass shape the INV-COUNT trailer exists to
# close. Require the trailer, and require it to agree with the lines.
NDRV=$(grep -c '^DRV|' "$INVLOG" || true)
DRVTRAILER=$(grep '^DRV-COUNT|' "$INVLOG" | tail -1 | cut -d'|' -f2)
if [ -z "$DRVTRAILER" ] || [ "$DRVTRAILER" != "$NDRV" ]; then
echo " DRIVER SURFACE NOT OBSERVED: trailer=${DRVTRAILER:-absent}, observed $NDRV lines"
COVFAIL=1
elif [ "$NDRV" -eq 0 ]; then
echo " DRIVER SURFACE NOT OBSERVED: the instruments declare nothing at all,"
echo " which cannot be true — Inventory.lean declares its own machinery."
COVFAIL=1
else
echo " driver surface: $NDRV declarations across the audit instruments, no axiom, no claim"
fi
audit: bind the scalar statements, and make the accounting identity mean audit Closes four round-7/8 findings. Certified by the round-12 sweep: five repositories, both buttons and every self-test, 48/48 GREEN. ── `scalar-statements-unbound` (gpt, round 7, CRITICAL) ──────────────────── The main button bound its 31 certificates' elaborated statements and reachable specification bodies. This button bound NONE of its thirteen, while TRUSTED-BASE item 8 said the audit covers "every certificate" — false across the 44-certificate surface. The finding was raised in round 7, lost from the round-8 work list by an F-number collision between two reviewers, and re-raised in round 8. Proofs/ScalarAudit.lean is generated from each fork's OWN Audit.lean, so the canonicalisation is provably the same code: pp.all rendering, whitespace normalisation, transitive specification closure. check-scalar.sh Phase 3c pins the block's digest, requires the committed copy to match byte-for-byte so a mismatch can be DIFFED, and cross-checks the auditor's certificate set against the button's CERTS array. dalek ecf3a3f8 · anza 0d942e47 · risc0 4b550a61 · betrusted 4b550a61 risc0 and betrusted share a digest and that is correct, not a collision: their ScalarSubSpec.lean differs only in doc prose and in `black_box` entries inside `simp only [...]` lists AFTER `:= by`. Proof scripts. They bind the same statements over the same specifications, which is the documented scope. selftest-scalar-statements.sh ships the two attacks the reviewer asked for: ok gutted statement caught (cone unchanged) ok rewritten specification body caught (name and cone unchanged) The second rewrites a reachable reference body to `id (…)` — DEFINITIONALLY EQUAL, so the corpus compiles and every proof typechecks and the cone is byte-identical. Every earlier phase is blind to it. ── `drv-surface-no-cones` + `accounting-certifies-enumeration` (claude) ──── The round-7 accounting identity proved every kernel constant was ENUMERATED. The reviewer showed enumeration is not audit: their planted claim WAS enumerated, as DRV|LTLAccAudit.bait.smuggled|theorem with a real cone, and nothing examined it — rows had no cone, no allowlist covered them, the statement digest does not reach instruments, and Phase 2b gates DECLARED AXIOMS, a different question. "Progress of one step, not two." DRV rows now carry their axiom cone and are pinned in driver-allowlist.txt by inventory_gate.sh with a DRV tag — the same implementation that pins the corpus, in both directions, because a second copy of a coverage gate is a second thing to drift. The axiom policy is per-surface and enforced per surface: the corpus admits exactly the sanctioned boundary, the instruments admit none, and an instrument axiom fails EVEN WHEN ALLOWLISTED. Verified with the reviewer's own payload, both placements: before the walk -> UNCLASSIFIED: DRV|…|bait.smuggled|theorem|Classical.choice,Quot.sound,propext after the walk -> ACCOUNTING FAILED names it (kernel-side) ── `drv-naming-heuristic` (claude, round 7) ──────────────────────────────── Retired as load-bearing rather than patched. The rule admits a theorem whose name extends a constant declared alongside it, and "breaks in one line" — declare `def bait`, then `theorem bait.smuggled` walks through. It stays as a fast readable first check; membership in a committed allowlist is what now carries the weight, and a new row fails closed whatever it is called. ── what round 11 caught, which was mine ─────────────────────────────────── DRV rows first shipped WITHOUT their originating driver. dalek and anza run two drivers, each declaring its own `corpus`; keyed on name alone those two distinct declarations produced one byte-identical row, `sort -u` collapsed them, and the trailers summed to 37 against 36. The estate had already learned this on the corpus walk — INV rows carry their module because two modules both declare CurveFieldProofs.zero_spec — and I rebuilt the record without it. Rows now carry their driver, and the gate FAILS CLOSED ON DUPLICATE RECORDS naming the collision: two declarations sharing one entry means one is covered by the other's, which is exactly how a real declaration hides. The trailer now checks what the drivers EMITTED, not what survives de-duplication — conflating "the run was truncated" with "two rows were identical" is what let a record-format defect present itself as an arithmetic complaint. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 10:15:26 +00:00
# AND THE ROWS ARE PINNED, WITH THEIR CONES, BY THE SAME GATE THE CORPUS USES.
#
# This block used to end with a note explaining why the instruments' internals
# were deliberately NOT pinned: they are byte-pinned in HARNESS.sha256, so "a
# second policy file listing their internals would add a thing to maintain
# without adding a thing to catch."
#
# Round-8 review (Claude, register keys `drv-surface-no-cones`,
# `accounting-certifies-enumeration`) showed that reasoning was wrong, by
# demonstration. Their payload
# DRV|LTLAccAudit.bait.smuggled|theorem
# is a genuine claim with cone [propext, Classical.choice, Quot.sound]. It
# passed the name-prefix rule above — `bait` is declared alongside it, so it
# looks like an elaborator artefact — it was enumerated by the accounting
# identity, and then NOTHING examined it: the rows carried no cone, no
# allowlist covered them, and the statement digest does not reach instruments.
# Byte-pinning shows that a driver CHANGED. It does not show what appeared in
# it or what that thing rests on, and "the file changed" is not a finding a
# reader can act on.
#
# So the rows now carry their cone and are diffed against a committed
# allowlist, in both directions, by inventory_gate.sh with the DRV tag — the
# same implementation, so the two surfaces cannot drift apart in their gating.
# The axiom policy differs by surface and is enforced per surface: the corpus
# admits exactly the sanctioned hash boundary, the instruments admit none.
"$HERE/inventory_gate.sh" "$INVLOG" "$HERE/driver-allowlist.txt" DRV || COVFAIL=1
P2-b: close classes 9 and 15 — the instruments, and the places nothing looked CLASS 15 — a Lean file where no phase was looking. The dead-file scan read Proofs/*.lean and gen/LTLAcc/*.lean and nothing else. A module at the verification root, or under any other gen/ subdirectory, was neither compiled nor rejected — while remaining importable by name, since LEAN_PATH contains both roots. That is a source of the corpus that no phase reads and no pin covers, which is exactly what the dead-file gate exists to forbid; it was simply looking in two places instead of everywhere. Now nothing may live in either root but the two enumerated sets. CLASS 9 — the instruments' own declaration surface. AxiomCheck.lean and Inventory.lean perform the audit and are therefore not corpus, so nothing inventoried what THEY declare. Inventory.lean now walks both: AxiomCheck by module index, and itself as the module still being elaborated, whose declarations are the ones the environment reports with no originating module. That is what makes the inventory cover the instrument that produces it rather than exempting itself. The policy is not "declare nothing" — this file legitimately declares its machinery. It is that an instrument may declare only inert definitions. An axiom here would widen the trusted base without appearing in any certificate's cone; a theorem here would be a claim no certificate covers and no allowlist pins. A flat ban on theorems was WRONG and was measured to be wrong: defining a function by well-founded recursion makes the elaborator emit its own obligations, and axiomCone._proof_1 rejected this very file. The distinction that holds is whether a theorem is a claim someone wrote or an artefact of a definition declared alongside it — an artefact's name extends the name of a constant declared with it. Observed surface: 18 declarations, 16 def and 2 generated obligations, no axiom, no standalone claim. The drivers are byte-pinned already, so this does not pin WHICH definitions they contain — that would add a thing to maintain without adding a thing to catch. It adds the property byte-pinning cannot give: that no instrument declares an axiom or a claim, whatever its bytes are. selftest_audit.sh: 10 cases -> 14. Case 12 uses an INDENTED axiom, because Phase 1's source grep catches an unindented one and the point is to reach the kernel-side walk standing behind it. TWO DEFECTS IN THE TEST HARNESS, found while adding the cases. · The scratch tree copied verification/ only, but the button also reads README.md and STATEMENT-MAP.md from the repository root. check.sh therefore ALWAYS died in Phase 3c in the scratch tree, which made every `if check.sh; then <attack not caught>` guard unfirable — check.sh could not pass in there even with no attack at all. Only the diagnostic greps were doing any work. The documents are now copied, and the negative test below proves the guard is live: with the driver-surface check disabled, check.sh PASSES a tree whose inventory driver declares `axiom driver_cheat : False`. · Case 9 was the last case when it was written and left its rogue gen file in place. Harmless then; the new cases inherited it. Cleaned up between the blocks rather than inside case 9, so that case still tests what it did. Also fixed while here: Phase 3b compared the compile manifest against Inventory.lean by grepping the WHOLE FILE for a backticked module name, so prose counted — a doc comment naming a module broke the count, and in the other direction a doc mention of a module missing from the array would have satisfied the presence check and hidden the omission. It now reads the arrays. Both new gates negative-tested by removal. Button green, self-test green.
2026-07-31 12:18:40 +00:00
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
# CONES ⊆ allowlist with IDENTICAL cones: the #print-axioms-pinned table
# and the environment inventory are two independent computations of the
# same facts — any disagreement is a failure of one of them.
# (cones are compared as SETS: CONES keeps #print-axioms order, the
# inventory emits byte-sorted order — canonicalize both before comparing)
canon() { tr -d ' ' <<<"$1" | tr ',' '\n' | LC_ALL=C sort | paste -sd, -; }
while IFS='|' read -r _ name _ cone; do
if [ -n "${CONES[$name]+x}" ]; then
want=$(canon "${CONES[$name]}")
got=$(canon "$cone")
[ "$want" = "$got" ] || {
echo " CONE CROSS-CHECK FAILED: $name CONES=[$want] inventory=[$got]"; COVFAIL=1; }
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
fi
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
done < <(grep '^INV|' "$HERE/inventory-allowlist.txt")
Review round 4: F1* absorbed (lied-size boundary), acceptCons_sound, kit reproducibility Round-3 verdicts: GPT-5.6 conditionally approves (blockers closed, one portability finding); the Claude reviewer's Socratic addendum produced F1*, the strongest finding of the series — deployed verify_consistency and mechanized ConsRec are NOT extensionally equal. Reproduced exactly (witness verify_consistency(1,3,R2,R3,P(2→3))=True vs ConsRec reject; 3,405 divergences n<60; strictly one-sided; power-of-two seeding mechanism confirmed in source). - KNOWN-GAPS gap 14: witness, mechanism, one-sidedness, and the pinned-pair side condition under which Theorem 3 transfers to the deployed verifier (pacta's pin-store flow supplies it by construction). No pacta code change; deployed behavior matches upstream RFC 9162 implementations. - fidelity: lied-size family — 73,573 boundary cases, 3,867 expected divergences PINNED, one-sided direction asserted per case. Banner rescoped: agreement over pinned families, not extensional equality. - Theorem3.lean: acceptCons_sound (F2) — soundness over the named acceptCons predicate, n₀=0 discharged from the non-prefix premise, size bound derived from acceptance via new consRec_some_le. Cones read from #print axioms; CONES/AxiomCheck/allowlist updated (218 → 222 constants, diff = the two theorems + two generated auxiliaries). - F3/GPT§7: verification/lean-toolchain pin + run_bare.sh (reviewer's standalone runner, plain public lean — verified green: 61 cones, 222 constants, gate green) + AENEAS_ENV override in check.sh and selftest_audit.sh. - F4: awk field-equality replaces regex-with-dots in Phase 3b. - F5: git-tracked .pyc removed (worse than reported — it was in the repo, not just the kit); __pycache__ gitignored; round-4 kit ships a corpus MANIFEST.sha256 + pinned commit (also GPT's governance condition). check.sh exit 0, ATTESTATION GREEN; selftest exit 0, 9/9 + control. Live LTL untouched (12 leaves, bcd15f9d…); attestation still gated on ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 13:07:57 +00:00
# (field-equality, not regex — dots in names must not act as wildcards;
# review round 3, F4)
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
for cert in "${!CONES[@]}"; do
Review round 4: F1* absorbed (lied-size boundary), acceptCons_sound, kit reproducibility Round-3 verdicts: GPT-5.6 conditionally approves (blockers closed, one portability finding); the Claude reviewer's Socratic addendum produced F1*, the strongest finding of the series — deployed verify_consistency and mechanized ConsRec are NOT extensionally equal. Reproduced exactly (witness verify_consistency(1,3,R2,R3,P(2→3))=True vs ConsRec reject; 3,405 divergences n<60; strictly one-sided; power-of-two seeding mechanism confirmed in source). - KNOWN-GAPS gap 14: witness, mechanism, one-sidedness, and the pinned-pair side condition under which Theorem 3 transfers to the deployed verifier (pacta's pin-store flow supplies it by construction). No pacta code change; deployed behavior matches upstream RFC 9162 implementations. - fidelity: lied-size family — 73,573 boundary cases, 3,867 expected divergences PINNED, one-sided direction asserted per case. Banner rescoped: agreement over pinned families, not extensional equality. - Theorem3.lean: acceptCons_sound (F2) — soundness over the named acceptCons predicate, n₀=0 discharged from the non-prefix premise, size bound derived from acceptance via new consRec_some_le. Cones read from #print axioms; CONES/AxiomCheck/allowlist updated (218 → 222 constants, diff = the two theorems + two generated auxiliaries). - F3/GPT§7: verification/lean-toolchain pin + run_bare.sh (reviewer's standalone runner, plain public lean — verified green: 61 cones, 222 constants, gate green) + AENEAS_ENV override in check.sh and selftest_audit.sh. - F4: awk field-equality replaces regex-with-dots in Phase 3b. - F5: git-tracked .pyc removed (worse than reported — it was in the repo, not just the kit); __pycache__ gitignored; round-4 kit ships a corpus MANIFEST.sha256 + pinned commit (also GPT's governance condition). check.sh exit 0, ATTESTATION GREEN; selftest exit 0, 9/9 + control. Live LTL untouched (12 leaves, bcd15f9d…); attestation still gated on ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 13:07:57 +00:00
awk -F'|' -v n="$cert" '$1=="INV" && $2==n {found=1} END {exit !found}' \
"$HERE/inventory-allowlist.txt" || {
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
echo " PINNED BUT NOT INVENTORIED: $cert (in CONES, not in allowlist)"; COVFAIL=1; }
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
done
verification: bind statements and specification bodies (P1-a); un-stale the fidelity pin STATEMENT BINDING (Phase 3d). The coverage gate pins every constant's name, kind and axiom cone, both directions, and none of selftest_audit.sh's nine attacks defeat it. It is nevertheless blind to what a declaration SAYS — and that is demonstrated here rather than argued: Wrapping one branch of `LTLAcc.pinAccept`'s body in `id (…)` is definitionally equal. Every downstream proof still compiles. The name, the kind, the type and the axiom cone are unchanged. The inventory gate reports "222 constants, environment == allowlist" — GREEN. That edit is harmless by construction; the point is that nothing stood between it and a genuinely vacuous redefinition of a specification. Proofs/Inventory.lean now also emits, for every inventoried constant, its fully-elaborated TYPE, and for every definition its fully-elaborated BODY — 266 lines over 222 constants. Proof terms are deliberately absent: by proof irrelevance a theorem's content is its statement. check.sh Phase 3d binds the SHA-256 and the block is committed as AUDIT-MANIFEST.txt so a mismatch is DIFFED, not merely reported. The existing gate is untouched, per the standing rule that the port flows FROM this repo, not to it: INV lines are byte-identical, inventory_gate.sh is unchanged, and all nine of its attacks still fail as before. selftest_statements.sh replays the defeq edit as case 1, asserting BOTH that the coverage gate passes it and that Phase 3d catches it — so if the coverage gate ever grows to see this, the test says so instead of quietly re-labelling. Cases 2-4 cover a hand-edited committed block, a truncated block, and a constant inventoried without a statement. FIDELITY PIN (unrelated, found while running the button). Phase 4 had been failing since 2026-07-23: LIED_PIN_DIV expected 3,867 divergences between the Lean model and the deployed consistency verifier, and observed 0. Cause is pacta ddbb5a4, which restored the RFC 9162 2.1.4.2 Step-7 terminal `sn == 0` condition; that one conjunct removes every divergence in the pinned 73,573-case family. KNOWN-GAPS gap 14 already recorded the closure on the day it landed — only this constant was stale, so the button had been red for five days with nobody running it. The pin now reads 0 with the history in a comment. Nothing about the paper, public log entry 13, or the attested commit 172a1d0 changes; the historical divergence stays reproducible at the tagged pre-fix commit. KNOWN-GAPS gap 16 records what the binding does not buy: identity, not meaning; an author who edits and re-pins in one commit is caught by review and not by the script; and proof terms are unbound by design. Button green end to end: ATTESTATION GREEN (Lean + fidelity). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 07:07:13 +00:00
# (INVLOG is NOT removed here: Phase 3d binds the statement block emitted by
# this same run. Removed at the end of 3d.)
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
# every pinned cert must actually be queried by AxiomCheck (no pin-but-never-check)
for cert in "${!CONES[@]}"; do
grep -qF "#print axioms $cert" "$HERE/Proofs/AxiomCheck.lean" || {
echo " PINNED BUT NOT QUERIED: $cert (in CONES, absent from AxiomCheck.lean)"; COVFAIL=1; }
done
Review round 3: environment-derived audit surface, self-contained kit Round-2 external reviews (GPT-5.6 + second Claude) converged on the coverage gate being evadable (H1/NEW-1); GPT additionally proved the kit's fidelity target could not run (H2) and the namespace-collision attack that defeats any source-regex fix. This round adopts GPT's required correction in full: - Proofs/Inventory.lean: declaration inventory read from the compiled Lean environment — every constant of every corpus module, fully qualified, unfiltered (compiler auxiliaries and _private mangles pinned too), with kind and axiom cone; own cone walker cross-checked in-process against core collectAxioms (hard error on divergence). - verification/inventory-allowlist.txt: all 218 constants pinned. - inventory_gate.sh: fail-closed diff both directions (UNCLASSIFIED / STALE), INV-COUNT truncation guard, exactly-one-axiom invariant. - check.sh Phase 3b rewritten around the gate + manifest⇔inventory drift checks + CONES⇔inventory cone cross-check (two independent computations must agree). EXCLUDE table gone (sha256/Bytes are ordinary audited entries now). - selftest_audit.sh: 9 adversarial cases against the production gate (attributed/indented/private/instance, namespace collision, smuggled axiom, deleted decl, unmanifested Proofs/ and gen/ modules) + positive control — all defeated (GPT release condition 2). - M1: recursive orphan-olean guard (caught a stray dev artifact on its first run), gen/ dead-file check, corpus-wide single-axiom pin. - L1/NEW-2: acceptIncl_sound drops the redundant hm (derived from hacc.1); cone unchanged. - M2/M3: STATEMENT-MAP counts 230,271/230,016; non-vacuity guard wording narrowed to what the guards actually certify. - README layer table: stale L4/pin-store rows fixed (missed by both round-2 reviewers AND the round-2 revision — found in self-review). - KNOWN-GAPS 12 (audit-gate lineage + residual limits), 13 (round-2 kit target not self-contained); gap 2 count fixed. - RESPONSE-TO-REVIEWERS.md: round-3 disposition of every finding. Kit round 3 additionally ships the complete stdlib-only import closure of pacta.transparency (content-addressed vs pacta 3d81d53), the clean-extraction fidelity transcript (exit 0, 230,271+230,016, zero mismatches), the ATTESTATION GREEN check.sh transcript, and the self-test transcript. The live LTL remains untouched (12 leaves, root bcd15f9d…); attestation stays blocked pending ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:32:18 +00:00
[ "$COVFAIL" = 0 ] && echo " coverage complete: environment == allowlist, CONES cross-checked"
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
[ "$COVFAIL" = 0 ] || { echo "COVERAGE FAILED"; FAIL=1; }
[ "$FAIL" = 0 ] || exit 1
Round 5 (housekeeping): doc-consistency welded into the button; both round-4 approvals recorded Round-4 verdicts: Claude reviewer — nothing blocks the freeze, no remaining findings; GPT-5.6 — approve after minor documentation fixes, attestation scoped to the mechanized model. This round is those fixes; no Lean surface changed. - 218/59 → 222/61 everywhere, and STRUCTURALLY: check.sh Phase 3c asserts the audit counts (STATEMENT-MAP + README vs allowlist/CONES) and the four fidelity pins (STATEMENT-MAP vs run_fidelity.py constants) on every run — stale-count drift is a red button now (R4-1, third recurrence of the class). - Gap 14 reworded to evidence-vs-inference (the invariant "is assumed", not "transfers"), witnesses cited (paper §5.3/§5.4; pacta sthstore.py/logclient.py — outside the fidelity target). New gap 15: deployment refinement invariant unmechanized (GPT's principal finding, split out because it carries the deployed-soundness claim). - Runbook: A1 marked done (both approvals on SD); B2 gains the REQUIRED scoped attestation wording (GPT §11) as a gate condition — entry 13 cannot claim "deployed verifier formally verified". - run_bare.sh fail-closes on Lean version AND commit (rejection path tested with a fake toolchain: FATAL, exit 1). - Harness: "consistency baseline family" line (GPT §8); gap 14 says "fixed offsets n−1/n+1/n+7" (R4-5). - RESPONSE round 5, incl. refutation of GPT §7 (the target tarball demonstrably contains MANIFEST.sha256 + TARGET-PROVENANCE.md; the round-5 kit also ships both unpacked as a courtesy). check.sh exit 0 ATTESTATION GREEN (Phases 0-4 incl. new 3c); selftest exit 0, 9/9 + control. Live LTL untouched (12 leaves, bcd15f9d…). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 07:40:20 +00:00
# -- Phase 3c: documentation consistency (review R4-1: hand-maintained ------
# counts went stale three rounds running — so the docs' numbers are now
# ASSERTED against their sources: allowlist, CONES, and the fidelity pins.
echo "=== Phase 3c: doc-consistency ==="
DOCFAIL=0
NALLOW=$(grep -c '^INV|' "$HERE/inventory-allowlist.txt")
NCONES=${#CONES[@]}
SMAP="$HERE/../STATEMENT-MAP.md"
RDME="$HERE/../README.md"
grep -qF "$NALLOW constants" "$SMAP" || { echo " DOC DRIFT: STATEMENT-MAP lacks '$NALLOW constants'"; DOCFAIL=1; }
grep -qF "$NCONES human-reviewed" "$SMAP" || { echo " DOC DRIFT: STATEMENT-MAP lacks '$NCONES human-reviewed'"; DOCFAIL=1; }
grep -qF "$NALLOW constants" "$RDME" || { echo " DOC DRIFT: README lacks '$NALLOW constants'"; DOCFAIL=1; }
grep -qF "$NCONES human-reviewed" "$RDME" || { echo " DOC DRIFT: README lacks '$NCONES human-reviewed'"; DOCFAIL=1; }
# fidelity pins quoted in the docs must equal the harness's pinned constants
for n in $(python3 -c "
import re
src = open('$HERE/fidelity/run_fidelity.py').read()
vals = [re.search(r'assert ti == ([0-9_]+)', src).group(1),
re.search(r'assert tc == ([0-9_]+)', src).group(1),
re.search(r'LIED_PIN_TOTAL = ([0-9_]+)', src).group(1),
re.search(r'LIED_PIN_DIV = ([0-9_]+)', src).group(1)]
print(' '.join(f'{int(v.replace(chr(95),\"\")):,}' for v in vals))"); do
grep -qF "$n" "$SMAP" || { echo " DOC DRIFT: STATEMENT-MAP lacks fidelity pin '$n'"; DOCFAIL=1; }
done
[ "$DOCFAIL" = 0 ] && echo " docs agree with allowlist ($NALLOW), CONES ($NCONES), fidelity pins"
[ "$DOCFAIL" = 0 ] || { echo "DOC-CONSISTENCY FAILED"; exit 1; }
verification: bind statements and specification bodies (P1-a); un-stale the fidelity pin STATEMENT BINDING (Phase 3d). The coverage gate pins every constant's name, kind and axiom cone, both directions, and none of selftest_audit.sh's nine attacks defeat it. It is nevertheless blind to what a declaration SAYS — and that is demonstrated here rather than argued: Wrapping one branch of `LTLAcc.pinAccept`'s body in `id (…)` is definitionally equal. Every downstream proof still compiles. The name, the kind, the type and the axiom cone are unchanged. The inventory gate reports "222 constants, environment == allowlist" — GREEN. That edit is harmless by construction; the point is that nothing stood between it and a genuinely vacuous redefinition of a specification. Proofs/Inventory.lean now also emits, for every inventoried constant, its fully-elaborated TYPE, and for every definition its fully-elaborated BODY — 266 lines over 222 constants. Proof terms are deliberately absent: by proof irrelevance a theorem's content is its statement. check.sh Phase 3d binds the SHA-256 and the block is committed as AUDIT-MANIFEST.txt so a mismatch is DIFFED, not merely reported. The existing gate is untouched, per the standing rule that the port flows FROM this repo, not to it: INV lines are byte-identical, inventory_gate.sh is unchanged, and all nine of its attacks still fail as before. selftest_statements.sh replays the defeq edit as case 1, asserting BOTH that the coverage gate passes it and that Phase 3d catches it — so if the coverage gate ever grows to see this, the test says so instead of quietly re-labelling. Cases 2-4 cover a hand-edited committed block, a truncated block, and a constant inventoried without a statement. FIDELITY PIN (unrelated, found while running the button). Phase 4 had been failing since 2026-07-23: LIED_PIN_DIV expected 3,867 divergences between the Lean model and the deployed consistency verifier, and observed 0. Cause is pacta ddbb5a4, which restored the RFC 9162 2.1.4.2 Step-7 terminal `sn == 0` condition; that one conjunct removes every divergence in the pinned 73,573-case family. KNOWN-GAPS gap 14 already recorded the closure on the day it landed — only this constant was stale, so the button had been red for five days with nobody running it. The pin now reads 0 with the history in a comment. Nothing about the paper, public log entry 13, or the attested commit 172a1d0 changes; the historical divergence stays reproducible at the tagged pre-fix commit. KNOWN-GAPS gap 16 records what the binding does not buy: identity, not meaning; an author who edits and re-pins in one commit is caught by review and not by the script; and proof terms are unbound by design. Button green end to end: ATTESTATION GREEN (Lean + fidelity). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 07:07:13 +00:00
# -- Phase 3d: statement + specification binding (P1-a) ---------------------
# WHAT PHASES 3/3b DO NOT ESTABLISH. Phase 3 pins each certificate's exact
# axiom cone; Phase 3b pins the full environment surface, kind and cone, both
# directions. Neither records what a declaration SAYS. A theorem gutted to a
# tautology keeps its name, its kind and its cone. A `def` redefined to BE the
# thing it was meant to specify keeps all three, and every certificate stated
# against it silently becomes vacuous — with the allowlist unmoved.
#
# Proofs/Inventory.lean therefore also emits, for every inventoried constant,
# its fully-elaborated TYPE, and for every definition its fully-elaborated
# BODY. Proof terms are deliberately absent: by proof irrelevance a theorem's
# content is its statement. This phase binds the SHA-256 of that block, and
# the block itself is committed as AUDIT-MANIFEST.txt so a mismatch is DIFFED
# rather than merely reported.
#
# To rotate deliberately: run check.sh, take the printed OBSERVED digest, and
# update the constant below AND AUDIT-MANIFEST.txt in the same reviewable
# commit. Visibility in review is the defence; no harness audits its author.
EXPECTED_STMT_SHA256="e7d422f0be9a9e6f5465058292e30c711d52856428da2b01c470a57ec181540c"
echo "=== Phase 3d: statement + specification binding ==="
STMTFAIL=0
STMT_BLOCK=$(awk '/^STMT-BEGIN/{f=1;next} /^STMT-END/{f=0} f' "$INVLOG")
# FAIL CLOSED ON ABSENCE: no block and a matching block must not share a path.
if [ -z "$STMT_BLOCK" ]; then
echo " NO STATEMENT BLOCK emitted by Proofs/Inventory.lean (fail-closed)"; STMTFAIL=1
else
# Output integrity, same discipline as the INV-COUNT trailer: a truncated or
# crashed run must not pass as a short-but-matching block.
N_STMT=$(printf '%s\n' "$STMT_BLOCK" | grep -c '^STMT|')
STMT_TRAILER=$(grep '^STMT-COUNT|' "$INVLOG" | tail -1 | cut -d'|' -f2)
if [ -z "$STMT_TRAILER" ] || [ "$STMT_TRAILER" != "$N_STMT" ]; then
echo " STATEMENT BLOCK TRUNCATED: trailer=${STMT_TRAILER:-absent}, observed $N_STMT"; STMTFAIL=1
fi
# Every inventoried constant must carry a statement line. Inventory.lean
# asserts this internally too; asserting it here as well means a tampered
# Inventory.lean cannot simply drop its own check.
N_INV=$(grep -c '^INV|' "$INVLOG")
N_TYPES=$(printf '%s\n' "$STMT_BLOCK" | grep -c '|type=')
if [ "$N_TYPES" != "$N_INV" ]; then
echo " STATEMENT COVERAGE GAP: $N_INV constants inventoried, $N_TYPES carry a statement"; STMTFAIL=1
fi
GOT_STMT_SHA=$(printf '%s\n' "$STMT_BLOCK" | sha256sum | cut -d' ' -f1)
if [ "$GOT_STMT_SHA" != "$EXPECTED_STMT_SHA256" ]; then
printf '%s\n' "$STMT_BLOCK" > "$HERE/.stmt-manifest.observed"
echo " STATEMENT DIGEST MISMATCH."
echo " expected: $EXPECTED_STMT_SHA256"
echo " observed: $GOT_STMT_SHA"
echo " A statement or a definition body changed. First differences:"
diff -u "$HERE/AUDIT-MANIFEST.txt" "$HERE/.stmt-manifest.observed" 2>/dev/null \
| head -30 | sed 's/^/ /' || echo " (AUDIT-MANIFEST.txt absent — cannot diff)"
rm -f "$HERE/.stmt-manifest.observed"
STMTFAIL=1
elif ! printf '%s\n' "$STMT_BLOCK" | cmp -s - "$HERE/AUDIT-MANIFEST.txt"; then
# The digest's INPUT must be committed and current, or the diff above would
# compare against a stale reference and quietly mislead the next reader.
echo " COMMITTED BLOCK STALE: AUDIT-MANIFEST.txt does not match the emitted block"
echo " (the digest matched, so the committed copy needs refreshing)"; STMTFAIL=1
fi
fi
[ "$STMTFAIL" = 0 ] && echo " statements bound: $N_STMT lines over $N_INV constants, sha256 = $GOT_STMT_SHA"
[ "$STMTFAIL" = 0 ] || { echo "STATEMENT BINDING FAILED"; rm -f "$INVLOG"; exit 1; }
rm -f "$INVLOG"
# -- Phase 4: definition fidelity (Lean defs vs deployed pacta verifiers) --
echo "=== Phase 4: definition fidelity ==="
PACTA_SRC="${PACTA_SRC:-$HERE/../../proof-aware-crypto-tooling-agent/src}"
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
FIDELITY_RAN=0
if [ "${SKIP_FIDELITY:-0}" = "1" ]; then
echo " skipped (SKIP_FIDELITY=1)"
elif [ -d "$PACTA_SRC/pacta" ]; then
accumulator: a run that is not attestation-ready must not exit 0, and must name its subject Two round-7/8 findings, both closed here. `acc-exit0-fidelity` — CRITICAL, raised INDEPENDENTLY by both reviewers (Claude F1, GPT-5.6 F10) and lost from the round-8 work list by the F-number collision the finding register now prevents. check.sh emitted a careful pair of markers — ATTESTATION GREEN only when fidelity actually ran — and then returned 0 either way. The marker discipline was right; the exit code contradicted it. A caller doing the obvious thing ./check.sh && append read success from a run whose own last line said NOT attestation-ready. And because pacta is not part of this estate, the skip branch is the ONLY branch a third party ever takes: for everyone but the author the button always returned 0 without ever checking definition fidelity. Reproduced here before fixing — PACTA_SRC=/nonexistent ./check.sh printed "FIDELITY NOT RUN" and exited 0. An exit code is what programs read. The contract is now: fidelity ran exit 0 ATTESTATION GREEN SKIP_FIDELITY=1 exit 3 explicit opt-out, distinguishable, not success pacta absent exit 1 nobody opted out; a real failure to establish the property the button exists for All three verified. The self-tests are unaffected: every SKIP_FIDELITY case already expected a non-zero exit and asserts on a diagnostic from an earlier phase, and the control compiles modules directly rather than invoking check.sh. 29 assertions across the three self-tests, all green. `pacta-subject-unpinned` — HIGH, GPT-5.6 round 8. Phase 4 compared this repository's Lean definitions against "the deployed verifier" by importing whatever sat at $PACTA_SRC — no repository, no commit, no clean state, no hashes. It pinned the fidelity OUTPUTS while leaving the SUBJECT anonymous, so any program producing the same finite family of answers passed, and the recorded result named no version of the thing it agreed with. fidelity/pacta_pin.py pins the transitive set of pacta modules the harness ACTUALLY LOADS — discovered by importing its entry point and reading sys.modules, a membership property rather than a directory glob. A glob would pin files the comparison never touches and miss anything loaded from elsewhere; this estate has been bitten by name-shaped measurement before. Five modules at pacta cd3b1bc — the same checkout the reviewer independently recorded. Negative-tested, all three rejected by name: tampered bytes, a module loaded but absent from the pin, and the pin file deleted. Refusing to pin a dirty pacta tree is also enforced — a pin taken over uncommitted edits names a subject nobody else can obtain. PACTA-PIN.sha256 joins HARNESS_EXTRA. It is not executable, so it would otherwise have sat outside the harness set, and a subject pin an attacker may rewrite pins nothing — the same shape as the forgeable .audit-basis that remains open as `auditonly-basis-forgeable`. This does not widen the claim: byte identity of a source tree is not proof the deployed service runs it, and finite-family agreement is not extensional equality. It names the subject. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-02 19:40:35 +00:00
# PIN THE SUBJECT BEFORE COMPARING AGAINST IT (round-8 review, GPT-5.6,
# register key `pacta-subject-unpinned`). This phase used to import whatever
# sat at $PACTA_SRC: no repository, no commit, no clean state, no hashes. It
# pinned the fidelity OUTPUTS while leaving the SUBJECT anonymous, so any
# program producing the same finite family of answers passed and the recorded
# result named no version of the thing it agreed with. Agreement with an
# unnamed program is not evidence about a deployed one.
PACTA_SRC="$PACTA_SRC" python3 "$HERE/fidelity/pacta_pin.py" --verify \
|| { echo "FIDELITY FAILED — the pacta subject is not the pinned one."; exit 1; }
PACTA_SRC="$PACTA_SRC" python3 "$HERE/fidelity/run_fidelity.py" || { echo "FIDELITY FAILED"; exit 1; }
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
FIDELITY_RAN=1
else
echo " SKIPPED: pacta repo not found at $PACTA_SRC (set PACTA_SRC to run)"
fi
accumulator: a run that is not attestation-ready must not exit 0, and must name its subject Two round-7/8 findings, both closed here. `acc-exit0-fidelity` — CRITICAL, raised INDEPENDENTLY by both reviewers (Claude F1, GPT-5.6 F10) and lost from the round-8 work list by the F-number collision the finding register now prevents. check.sh emitted a careful pair of markers — ATTESTATION GREEN only when fidelity actually ran — and then returned 0 either way. The marker discipline was right; the exit code contradicted it. A caller doing the obvious thing ./check.sh && append read success from a run whose own last line said NOT attestation-ready. And because pacta is not part of this estate, the skip branch is the ONLY branch a third party ever takes: for everyone but the author the button always returned 0 without ever checking definition fidelity. Reproduced here before fixing — PACTA_SRC=/nonexistent ./check.sh printed "FIDELITY NOT RUN" and exited 0. An exit code is what programs read. The contract is now: fidelity ran exit 0 ATTESTATION GREEN SKIP_FIDELITY=1 exit 3 explicit opt-out, distinguishable, not success pacta absent exit 1 nobody opted out; a real failure to establish the property the button exists for All three verified. The self-tests are unaffected: every SKIP_FIDELITY case already expected a non-zero exit and asserts on a diagnostic from an earlier phase, and the control compiles modules directly rather than invoking check.sh. 29 assertions across the three self-tests, all green. `pacta-subject-unpinned` — HIGH, GPT-5.6 round 8. Phase 4 compared this repository's Lean definitions against "the deployed verifier" by importing whatever sat at $PACTA_SRC — no repository, no commit, no clean state, no hashes. It pinned the fidelity OUTPUTS while leaving the SUBJECT anonymous, so any program producing the same finite family of answers passed, and the recorded result named no version of the thing it agreed with. fidelity/pacta_pin.py pins the transitive set of pacta modules the harness ACTUALLY LOADS — discovered by importing its entry point and reading sys.modules, a membership property rather than a directory glob. A glob would pin files the comparison never touches and miss anything loaded from elsewhere; this estate has been bitten by name-shaped measurement before. Five modules at pacta cd3b1bc — the same checkout the reviewer independently recorded. Negative-tested, all three rejected by name: tampered bytes, a module loaded but absent from the pin, and the pin file deleted. Refusing to pin a dirty pacta tree is also enforced — a pin taken over uncommitted edits names a subject nobody else can obtain. PACTA-PIN.sha256 joins HARNESS_EXTRA. It is not executable, so it would otherwise have sat outside the harness set, and a subject pin an attacker may rewrite pins nothing — the same shape as the forgeable .audit-basis that remains open as `auditonly-basis-forgeable`. This does not widen the claim: byte identity of a source tree is not proof the deployed service runs it, and finite-family agreement is not extensional equality. It names the subject. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-02 19:40:35 +00:00
# Fail-closed markers AND A FAIL-CLOSED EXIT CODE (round-7 review: raised
# independently by both reviewers — Claude F1, GPT-5.6 F10; register key
# `acc-exit0-fidelity`).
#
# Until now this emitted the weak marker and RETURNED 0. The marker discipline
# was right and the exit code contradicted it: a caller doing the obvious thing
#
# ./check.sh && append
#
# read success from a run whose own last line says NOT attestation-ready. And
# because pacta is not part of this estate, the skip branch is the ONLY branch
# any third party ever takes — so for everyone but the author, the button
# always returned 0 without ever checking definition fidelity. A procedure of
# the form "run the button, then append" was unsound for this component.
#
# An exit code is what programs read. If the button cannot establish
# attestation-readiness it must not return success, whatever it prints.
#
# fidelity ran -> ATTESTATION GREEN, exit 0
# SKIP_FIDELITY=1 -> exit 3: the caller opted out EXPLICITLY, so the
# code is distinguishable, but it is not 0
# pacta absent -> exit 1: nobody opted out; this is a real failure
# to establish the property the button exists for
#
# The self-tests are unaffected: every SKIP_FIDELITY=1 case already expects a
# non-zero exit and asserts on a diagnostic from an earlier phase, and the
# control case compiles modules directly rather than invoking this script.
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
echo "=== LEAN GREEN ==="
if [ "$FIDELITY_RAN" = 1 ]; then
echo "=== ATTESTATION GREEN (Lean + fidelity) ==="
accumulator: a run that is not attestation-ready must not exit 0, and must name its subject Two round-7/8 findings, both closed here. `acc-exit0-fidelity` — CRITICAL, raised INDEPENDENTLY by both reviewers (Claude F1, GPT-5.6 F10) and lost from the round-8 work list by the F-number collision the finding register now prevents. check.sh emitted a careful pair of markers — ATTESTATION GREEN only when fidelity actually ran — and then returned 0 either way. The marker discipline was right; the exit code contradicted it. A caller doing the obvious thing ./check.sh && append read success from a run whose own last line said NOT attestation-ready. And because pacta is not part of this estate, the skip branch is the ONLY branch a third party ever takes: for everyone but the author the button always returned 0 without ever checking definition fidelity. Reproduced here before fixing — PACTA_SRC=/nonexistent ./check.sh printed "FIDELITY NOT RUN" and exited 0. An exit code is what programs read. The contract is now: fidelity ran exit 0 ATTESTATION GREEN SKIP_FIDELITY=1 exit 3 explicit opt-out, distinguishable, not success pacta absent exit 1 nobody opted out; a real failure to establish the property the button exists for All three verified. The self-tests are unaffected: every SKIP_FIDELITY case already expected a non-zero exit and asserts on a diagnostic from an earlier phase, and the control compiles modules directly rather than invoking check.sh. 29 assertions across the three self-tests, all green. `pacta-subject-unpinned` — HIGH, GPT-5.6 round 8. Phase 4 compared this repository's Lean definitions against "the deployed verifier" by importing whatever sat at $PACTA_SRC — no repository, no commit, no clean state, no hashes. It pinned the fidelity OUTPUTS while leaving the SUBJECT anonymous, so any program producing the same finite family of answers passed, and the recorded result named no version of the thing it agreed with. fidelity/pacta_pin.py pins the transitive set of pacta modules the harness ACTUALLY LOADS — discovered by importing its entry point and reading sys.modules, a membership property rather than a directory glob. A glob would pin files the comparison never touches and miss anything loaded from elsewhere; this estate has been bitten by name-shaped measurement before. Five modules at pacta cd3b1bc — the same checkout the reviewer independently recorded. Negative-tested, all three rejected by name: tampered bytes, a module loaded but absent from the pin, and the pin file deleted. Refusing to pin a dirty pacta tree is also enforced — a pin taken over uncommitted edits names a subject nobody else can obtain. PACTA-PIN.sha256 joins HARNESS_EXTRA. It is not executable, so it would otherwise have sat outside the harness set, and a subject pin an attacker may rewrite pins nothing — the same shape as the forgeable .audit-basis that remains open as `auditonly-basis-forgeable`. This does not widen the claim: byte identity of a source tree is not proof the deployed service runs it, and finite-family agreement is not extensional equality. It names the subject. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-02 19:40:35 +00:00
elif [ "${SKIP_FIDELITY:-0}" = "1" ]; then
echo "=== FIDELITY SKIPPED ON REQUEST — NOT attestation-ready (exit 3) ==="
echo " The Lean corpus is green. Definition fidelity against the deployed"
echo " verifier was not checked, so this run does NOT certify that this"
echo " repository may be attested."
exit 3
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
else
accumulator: a run that is not attestation-ready must not exit 0, and must name its subject Two round-7/8 findings, both closed here. `acc-exit0-fidelity` — CRITICAL, raised INDEPENDENTLY by both reviewers (Claude F1, GPT-5.6 F10) and lost from the round-8 work list by the F-number collision the finding register now prevents. check.sh emitted a careful pair of markers — ATTESTATION GREEN only when fidelity actually ran — and then returned 0 either way. The marker discipline was right; the exit code contradicted it. A caller doing the obvious thing ./check.sh && append read success from a run whose own last line said NOT attestation-ready. And because pacta is not part of this estate, the skip branch is the ONLY branch a third party ever takes: for everyone but the author the button always returned 0 without ever checking definition fidelity. Reproduced here before fixing — PACTA_SRC=/nonexistent ./check.sh printed "FIDELITY NOT RUN" and exited 0. An exit code is what programs read. The contract is now: fidelity ran exit 0 ATTESTATION GREEN SKIP_FIDELITY=1 exit 3 explicit opt-out, distinguishable, not success pacta absent exit 1 nobody opted out; a real failure to establish the property the button exists for All three verified. The self-tests are unaffected: every SKIP_FIDELITY case already expected a non-zero exit and asserts on a diagnostic from an earlier phase, and the control compiles modules directly rather than invoking check.sh. 29 assertions across the three self-tests, all green. `pacta-subject-unpinned` — HIGH, GPT-5.6 round 8. Phase 4 compared this repository's Lean definitions against "the deployed verifier" by importing whatever sat at $PACTA_SRC — no repository, no commit, no clean state, no hashes. It pinned the fidelity OUTPUTS while leaving the SUBJECT anonymous, so any program producing the same finite family of answers passed, and the recorded result named no version of the thing it agreed with. fidelity/pacta_pin.py pins the transitive set of pacta modules the harness ACTUALLY LOADS — discovered by importing its entry point and reading sys.modules, a membership property rather than a directory glob. A glob would pin files the comparison never touches and miss anything loaded from elsewhere; this estate has been bitten by name-shaped measurement before. Five modules at pacta cd3b1bc — the same checkout the reviewer independently recorded. Negative-tested, all three rejected by name: tampered bytes, a module loaded but absent from the pin, and the pin file deleted. Refusing to pin a dirty pacta tree is also enforced — a pin taken over uncommitted edits names a subject nobody else can obtain. PACTA-PIN.sha256 joins HARNESS_EXTRA. It is not executable, so it would otherwise have sat outside the harness set, and a subject pin an attacker may rewrite pins nothing — the same shape as the forgeable .audit-basis that remains open as `auditonly-basis-forgeable`. This does not widen the claim: byte identity of a source tree is not proof the deployed service runs it, and finite-family agreement is not extensional equality. It names the subject. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-02 19:40:35 +00:00
echo "=== FIDELITY NOT RUN — NOT attestation-ready (exit 1) ==="
echo " pacta was not found at: $PACTA_SRC"
echo " Set PACTA_SRC to a pacta checkout and re-run, or pass"
echo " SKIP_FIDELITY=1 to acknowledge deliberately skipping it (exit 3)."
exit 1
revision round 1: address both external reviews (GPT-5.6 + second Claude) No theorem was wrong; every fix is spec-surface, audit-mechanism, docs, or harness coverage. Changes: LEAN (Claude F1, GPT M4): - acceptIncl: the consumer's inclusion accept (m<n ∧ Root=some r) is now a named object, not just a theorem hypothesis. Root alone accepts out-of-range m; acceptIncl pins the guard. - acceptIncl_complete / acceptIncl_sound: route Thm 1/2 through it. - extractCons_correct_paper: Thm 3 at the paper's exact quantifiers (n₀≤n₁, no separate 0<n₀; n₀=0 discharged since D₀=[]=take 0). SCRIPT (GPT H1/H2, Claude F3): - Phase 3b: fail-closed audit-surface COVERAGE — every named decl under Proofs/ and gen/ must be in CONES or a documented EXCLUDE (sha256, Bytes); anonymous gen instances count-pinned; every CONES key must be queried by AxiomCheck (no pin-but-never-check). Tested: an unclassified theorem now makes the button exit 1. - H2: distinct markers — LEAN GREEN always, ATTESTATION GREEN only when fidelity actually ran; SKIP/absent-pacta no longer emit the strong marker. Attestation gate keys on ATTESTATION GREEN. - Phase 0: orphan-olean guard (every Proofs/*.olean needs a sibling .lean); deleted 6 orphans; untracked all *.olean/.lake from git and gitignored them (root cause of the F3 tarball leak). HARNESS (Claude F1, GPT M3): - added out-of-range families (m≥n, m>n, n₀>n₁, n₀=0); re-pinned counts 230,271 / 230,016 (match the reviewer's independent RFC difftest exactly); narrowed 'exhaustive' wording to the tested domain. DOCS: README stale rows fixed (freeze banner no longer contradicts table); KNOWN-GAPS gap 3 reworded (general Lemma 2 = specializations), +gaps 9 (cost), 10 (pin init), 11 (acceptIncl resolved); STATEMENT-MAP +acceptIncl rows, +Lemma-2-general note, +constant-vs-property clarification for §10(i). Button: EXIT 0, coverage complete, ATTESTATION GREEN, 230,271/230,016. 56 pinned cones over an ENFORCED surface. LTL untouched (12, bcd15f9d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:53:47 +00:00
fi