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
|
|
|
|
/- Environment-derived declaration inventory (Phase 3b of check.sh).
|
|
|
|
|
|
|
|
|
|
|
|
Review round 2 (GPT H1) proved the previous source-regex enumerator
|
|
|
|
|
|
evadable: attributed / private / indented / `instance` declarations
|
|
|
|
|
|
were invisible, and a nested `namespace Hidden theorem MTH` collided
|
|
|
|
|
|
with the basename of an audited declaration. This module replaces
|
|
|
|
|
|
source scanning entirely: the inventory is read from the compiled
|
|
|
|
|
|
Lean ENVIRONMENT, so it sees exactly what the kernel saw.
|
|
|
|
|
|
|
|
|
|
|
|
Design (fail-closed by construction):
|
|
|
|
|
|
· The corpus module list below must match check.sh's compile
|
|
|
|
|
|
manifest (check.sh verifies this textually, both directions).
|
|
|
|
|
|
A listed module that is not actually imported is an elaboration
|
|
|
|
|
|
ERROR here, not a silent skip.
|
|
|
|
|
|
· EVERY constant whose originating module is a corpus module is
|
|
|
|
|
|
emitted — fully qualified, NO filtering. Compiler-generated
|
|
|
|
|
|
auxiliaries (equation lemmas, match/eq/induct helpers, private
|
|
|
|
|
|
mangles) are emitted too and pinned in the allowlist; anything
|
|
|
|
|
|
new, renamed, or removed shows up as a diff. There is no name
|
|
|
|
|
|
shape that can hide.
|
|
|
|
|
|
· Each constant carries its declaration KIND and its full axiom
|
|
|
|
|
|
cone, computed by the independent walker below (not by
|
|
|
|
|
|
#print axioms — Phase 3 still runs #print axioms separately, so
|
|
|
|
|
|
the two cone computations cross-check each other in check.sh).
|
|
|
|
|
|
· Output lines are prefixed `INV|` and sorted, so check.sh can
|
|
|
|
|
|
extract them robustly from compiler chatter.
|
|
|
|
|
|
|
|
|
|
|
|
This file is audit INFRASTRUCTURE, not corpus: it is excluded from
|
|
|
|
|
|
the compile manifest (like AxiomCheck.lean) and its own constants
|
|
|
|
|
|
are not inventoried (they live in the current module, which has no
|
|
|
|
|
|
module index). It proves nothing and is imported by nothing. -/
|
|
|
|
|
|
import Lean
|
|
|
|
|
|
import LTLAcc.HashExternal
|
|
|
|
|
|
import Proofs.Basic
|
|
|
|
|
|
import Proofs.Completeness
|
|
|
|
|
|
import Proofs.Extract
|
|
|
|
|
|
import Proofs.Descent
|
|
|
|
|
|
import Proofs.Consistency
|
|
|
|
|
|
import Proofs.Binding3
|
|
|
|
|
|
import Proofs.Refactor
|
|
|
|
|
|
import Proofs.Theorem3
|
|
|
|
|
|
import Proofs.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
|
|
|
|
import Proofs.AxiomCheck
|
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
|
|
|
|
|
|
|
|
|
|
open Lean
|
|
|
|
|
|
|
|
|
|
|
|
namespace LTLAccAudit
|
|
|
|
|
|
|
|
|
|
|
|
/-- Exactly check.sh's GEN_MODULES ++ PROOFS, as module names. -/
|
|
|
|
|
|
def corpusModules : Array Name :=
|
|
|
|
|
|
#[`LTLAcc.HashExternal,
|
|
|
|
|
|
`Proofs.Basic, `Proofs.Completeness, `Proofs.Extract, `Proofs.Descent,
|
|
|
|
|
|
`Proofs.Consistency, `Proofs.Binding3, `Proofs.Refactor,
|
|
|
|
|
|
`Proofs.Theorem3, `Proofs.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 INSTRUMENTS, as opposed to the corpus. They are Lean modules in
|
|
|
|
|
|
the audited tree, so what they declare is part of this repository's
|
|
|
|
|
|
surface — but they are not proofs, and nothing may rest on them.
|
|
|
|
|
|
|
|
|
|
|
|
`Proofs.AxiomCheck` is reachable here because this module imports it; this
|
|
|
|
|
|
module ITSELF has no module index while it is being elaborated, so its own
|
|
|
|
|
|
declarations are the ones the environment reports with no originating
|
|
|
|
|
|
module, and they are checked that way below. That is what makes this
|
|
|
|
|
|
inventory cover the instrument that produces it. -/
|
|
|
|
|
|
def driverModules : Array Name := #[`Proofs.AxiomCheck]
|
|
|
|
|
|
|
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
|
|
|
|
def kindOf : ConstantInfo → String
|
|
|
|
|
|
| .axiomInfo _ => "axiom"
|
|
|
|
|
|
| .defnInfo _ => "def"
|
|
|
|
|
|
| .thmInfo _ => "theorem"
|
|
|
|
|
|
| .opaqueInfo _ => "opaque"
|
|
|
|
|
|
| .quotInfo _ => "quot"
|
|
|
|
|
|
| .inductInfo _ => "inductive"
|
|
|
|
|
|
| .ctorInfo _ => "ctor"
|
|
|
|
|
|
| .recInfo _ => "recursor"
|
|
|
|
|
|
|
|
|
|
|
|
/-- Proof/definition body of a constant. NOTE: `ConstantInfo.value?`
|
|
|
|
|
|
returns `none` for theorems on this toolchain (observed on
|
|
|
|
|
|
4.30.0-rc2), which would silently truncate every cone at the first
|
|
|
|
|
|
theorem — so we match constructors directly. The cross-check against
|
|
|
|
|
|
core `collectAxioms` below would catch any such truncation. -/
|
|
|
|
|
|
def valueOf : ConstantInfo → Option Expr
|
|
|
|
|
|
| .defnInfo v => some v.value
|
|
|
|
|
|
| .thmInfo v => some v.value
|
|
|
|
|
|
| .opaqueInfo v => some v.value
|
|
|
|
|
|
| _ => none
|
|
|
|
|
|
|
|
|
|
|
|
/-- Full axiom cone of `root`: transitive closure over types AND values.
|
|
|
|
|
|
Written independently of core's `CollectAxioms`; the `#eval` below
|
|
|
|
|
|
insists both agree on every constant, and Phase 3 of check.sh
|
|
|
|
|
|
additionally cross-checks the audited names against `#print axioms`
|
|
|
|
|
|
output. -/
|
|
|
|
|
|
def axiomCone (env : Environment) (root : Name) : Array Name := Id.run do
|
|
|
|
|
|
let mut visited : NameSet := {}
|
|
|
|
|
|
let mut axioms : Array Name := #[]
|
|
|
|
|
|
let mut stack : Array Name := #[root]
|
|
|
|
|
|
while h : stack.size > 0 do
|
|
|
|
|
|
let n := stack[stack.size - 1]'(by omega)
|
|
|
|
|
|
stack := stack.pop
|
|
|
|
|
|
unless visited.contains n do
|
|
|
|
|
|
visited := visited.insert n
|
|
|
|
|
|
if let some ci := env.find? n then
|
|
|
|
|
|
if ci matches .axiomInfo _ then
|
|
|
|
|
|
axioms := axioms.push n
|
|
|
|
|
|
stack := stack ++ ci.type.getUsedConstants
|
|
|
|
|
|
if let some v := valueOf ci then
|
|
|
|
|
|
stack := stack ++ v.getUsedConstants
|
|
|
|
|
|
return (axioms.qsort (fun a b => a.toString < b.toString))
|
|
|
|
|
|
|
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
|
|
|
|
/-- Whitespace-canonical: every whitespace run collapses to one space, so the
|
|
|
|
|
|
pretty-printer's line wrapping cannot perturb the digest. -/
|
|
|
|
|
|
def normWs (s : String) : String :=
|
|
|
|
|
|
(s.foldl (fun (acc : String × Bool) c =>
|
|
|
|
|
|
let c := if c.isWhitespace then ' ' else c
|
|
|
|
|
|
if c == ' ' then (if acc.2 then acc else (acc.1.push ' ', true))
|
|
|
|
|
|
else (acc.1.push c, false))
|
|
|
|
|
|
("", true)).1
|
|
|
|
|
|
|
|
|
|
|
|
/-- Fully-explicit (`pp.all`) rendering, whitespace-canonicalized. Implicit
|
|
|
|
|
|
arguments, instances and universe levels are all made visible, so two
|
|
|
|
|
|
statements that merely LOOK alike cannot share a rendering. -/
|
|
|
|
|
|
def ppAll (e : Expr) : MetaM String := do
|
|
|
|
|
|
let fmt ← withOptions (fun o => o.setBool `pp.all true) (Meta.ppExpr e)
|
|
|
|
|
|
return normWs fmt.pretty
|
|
|
|
|
|
|
|
|
|
|
|
#eval show MetaM Unit from do
|
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
|
|
|
|
let env ← getEnv
|
|
|
|
|
|
-- Resolve every corpus module to its index; a miss is a hard error.
|
|
|
|
|
|
let mut idxs : Array Nat := #[]
|
|
|
|
|
|
for m in corpusModules do
|
|
|
|
|
|
match env.getModuleIdx? m with
|
|
|
|
|
|
| some i => idxs := idxs.push i
|
|
|
|
|
|
| none => throwError "INVENTORY ERROR: corpus module {m} is not imported"
|
|
|
|
|
|
let mut lines : Array String := #[]
|
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
|
|
|
|
-- STATEMENT SURFACE (P1-a). The INV lines above record what each constant
|
|
|
|
|
|
-- IS and what it RESTS ON. They do not record what it SAYS: a theorem gutted
|
|
|
|
|
|
-- to a tautology keeps its name, its kind and its axiom cone, and a `def`
|
|
|
|
|
|
-- redefined to BE the thing it was meant to specify keeps all three too,
|
|
|
|
|
|
-- while the certificate stated against it silently becomes vacuous. So every
|
|
|
|
|
|
-- constant additionally contributes its fully-elaborated TYPE, and every
|
|
|
|
|
|
-- definition its fully-elaborated BODY. Proof terms are NOT emitted: by
|
|
|
|
|
|
-- proof irrelevance a theorem's content is its statement, and its term is
|
|
|
|
|
|
-- both enormous and irrelevant to what is being claimed.
|
|
|
|
|
|
let mut stmts : Array String := #[]
|
|
|
|
|
|
let mut nTypes := 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
|
|
|
|
for (n, ci) in env.constants.toList do
|
|
|
|
|
|
if let some i := env.getModuleIdxFor? n then
|
|
|
|
|
|
if idxs.contains i then
|
|
|
|
|
|
let cone := axiomCone env n
|
|
|
|
|
|
-- Cross-check against core's collector (the same machinery
|
|
|
|
|
|
-- `#print axioms` uses): any divergence is a hard error.
|
|
|
|
|
|
let coreCone := (← collectAxioms n).qsort (fun a b => a.toString < b.toString)
|
|
|
|
|
|
unless cone == coreCone do
|
|
|
|
|
|
throwError "INVENTORY ERROR: cone divergence on {n}: walker={cone} core={coreCone}"
|
|
|
|
|
|
let coneStr := ",".intercalate (cone.toList.map (·.toString))
|
|
|
|
|
|
lines := lines.push s!"INV|{n}|{kindOf ci}|{coneStr}"
|
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
|
|
|
|
stmts := stmts.push s!"STMT|{n}|{kindOf ci}|type={← ppAll ci.type}"
|
|
|
|
|
|
nTypes := nTypes + 1
|
|
|
|
|
|
match ci with
|
|
|
|
|
|
| .defnInfo v => stmts := stmts.push s!"STMT|{n}|{kindOf ci}|value={← ppAll v.value}"
|
|
|
|
|
|
| _ => pure ()
|
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
|
|
|
|
let sorted := lines.qsort (· < ·)
|
|
|
|
|
|
for l in sorted do
|
|
|
|
|
|
IO.println l
|
|
|
|
|
|
IO.println s!"INV-COUNT|{sorted.size}"
|
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 instruments' own declaration surface ────────────────────
|
|
|
|
|
|
-- The loop above walks the CORPUS. It says nothing about the two modules
|
|
|
|
|
|
-- that perform the audit, and until 2026-07-31 nothing else did either: an
|
|
|
|
|
|
-- `axiom` or a `theorem` added to Proofs.AxiomCheck or to this file was
|
|
|
|
|
|
-- invisible to every phase of the button. Both are covered here.
|
|
|
|
|
|
--
|
|
|
|
|
|
-- Proofs.AxiomCheck is reachable by module index because this module imports
|
|
|
|
|
|
-- it. THIS module has no index yet — it is still being elaborated — so its
|
|
|
|
|
|
-- own declarations are exactly those the environment reports with no
|
|
|
|
|
|
-- originating module, which is how the inventory covers the instrument that
|
|
|
|
|
|
-- produces it rather than exempting itself.
|
|
|
|
|
|
--
|
|
|
|
|
|
-- The policy is not "declare nothing": this file legitimately declares the
|
|
|
|
|
|
-- machinery above. The policy 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
|
|
|
|
|
|
-- that no certificate covers and no allowlist pins.
|
|
|
|
|
|
let mut drvIdxs : Array Nat := #[]
|
|
|
|
|
|
for m in driverModules do
|
|
|
|
|
|
match env.getModuleIdx? m with
|
|
|
|
|
|
| some i => drvIdxs := drvIdxs.push i
|
|
|
|
|
|
| none => throwError "INVENTORY ERROR: driver module {m} is not imported"
|
|
|
|
|
|
let mut drvNames : Std.HashSet Name := {}
|
|
|
|
|
|
let mut drvConsts : Array (Name × ConstantInfo) := #[]
|
|
|
|
|
|
for (n, ci) in env.constants.toList do
|
|
|
|
|
|
let here : Bool :=
|
|
|
|
|
|
match env.getModuleIdxFor? n with
|
|
|
|
|
|
| some i => drvIdxs.contains i
|
|
|
|
|
|
| none => true -- declared by this file, still being elaborated
|
|
|
|
|
|
if here then
|
|
|
|
|
|
drvNames := drvNames.insert n
|
|
|
|
|
|
drvConsts := drvConsts.push (n, ci)
|
|
|
|
|
|
let mut drv : Array String := #[]
|
|
|
|
|
|
for (n, ci) in drvConsts do
|
|
|
|
|
|
let k := kindOf ci
|
|
|
|
|
|
-- An AXIOM in an instrument is never acceptable: it would widen the trusted
|
|
|
|
|
|
-- base without appearing in any certificate's cone.
|
|
|
|
|
|
if k == "axiom" then
|
|
|
|
|
|
throwError "DRIVER SURFACE VIOLATION: {n} is an axiom declared by the audit \
|
|
|
|
|
|
infrastructure. An instrument may not widen the trusted base."
|
|
|
|
|
|
-- A THEOREM needs care rather than a flat ban. Defining a function by
|
|
|
|
|
|
-- well-founded recursion makes the elaborator emit its own proof
|
|
|
|
|
|
-- obligations — `LTLAccAudit.axiomCone._proof_1` is one, and a flat ban
|
|
|
|
|
|
-- rejected this very file. The distinction that matters is whether the
|
|
|
|
|
|
-- theorem is a CLAIM someone wrote or an ARTEFACT of a definition here:
|
|
|
|
|
|
-- an artefact's name extends the name of a constant declared alongside it,
|
|
|
|
|
|
-- a standalone claim's does not.
|
|
|
|
|
|
if k == "theorem" && !drvNames.contains n.getPrefix then
|
|
|
|
|
|
throwError "DRIVER SURFACE VIOLATION: {n} is a standalone theorem declared by \
|
|
|
|
|
|
the audit infrastructure. An instrument may declare definitions \
|
|
|
|
|
|
and whatever the elaborator generates for them — never a claim \
|
|
|
|
|
|
of its own, which no certificate covers and no allowlist pins."
|
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
|
|
|
|
-- THE CONE. Round-8 review (Claude, `drv-surface-no-cones`,
|
|
|
|
|
|
-- `accounting-certifies-enumeration`): these rows carried name and kind
|
|
|
|
|
|
-- only, so when the accounting identity proved every kernel constant was
|
|
|
|
|
|
-- ENUMERATED, a claim planted in an instrument satisfied it and was then
|
|
|
|
|
|
-- examined by nothing. The reviewer's payload was exactly
|
|
|
|
|
|
-- DRV|LTLAccAudit.bait.smuggled|theorem
|
|
|
|
|
|
-- with cone [propext, Classical.choice, Quot.sound] — admitted, counted,
|
|
|
|
|
|
-- and covered by no allowlist row, no statement digest and no cone check.
|
|
|
|
|
|
-- Their verdict: the identity "converted 36 declarations nobody enumerated
|
|
|
|
|
|
-- into 36 declarations nobody examined."
|
|
|
|
|
|
--
|
|
|
|
|
|
-- With the cone here and the rows pinned in driver-allowlist.txt by the
|
|
|
|
|
|
-- same gate the corpus uses, the identity and the audit coincide. The
|
|
|
|
|
|
-- name-prefix rule above stays as a readable first check but is no longer
|
|
|
|
|
|
-- load-bearing: the reviewer showed it breaks in one line, and membership
|
|
|
|
|
|
-- in a committed allowlist does not.
|
|
|
|
|
|
let drvCone := axiomCone env n
|
|
|
|
|
|
let drvConeStr := ",".intercalate (drvCone.toList.map (·.toString))
|
|
|
|
|
|
drv := drv.push s!"DRV|{env.mainModule}|{n}|{k}|{drvConeStr}"
|
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
|
|
|
|
let drvSorted := drv.qsort (· < ·)
|
|
|
|
|
|
for l in drvSorted do
|
|
|
|
|
|
IO.println l
|
|
|
|
|
|
IO.println s!"DRV-COUNT|{drvSorted.size}"
|
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
|
|
|
|
-- FAIL CLOSED: the statement surface must cover the inventory exactly. If
|
|
|
|
|
|
-- these ever diverge, some constant is inventoried but unbound — which is
|
|
|
|
|
|
-- precisely the gap this section exists to close.
|
|
|
|
|
|
let sortedStmts := stmts.qsort (· < ·)
|
|
|
|
|
|
unless nTypes == sorted.size do
|
|
|
|
|
|
throwError "INVENTORY ERROR: {sorted.size} constants inventoried but {nTypes} carry a statement"
|
|
|
|
|
|
IO.println "STMT-BEGIN"
|
|
|
|
|
|
for l in sortedStmts do
|
|
|
|
|
|
IO.println l
|
|
|
|
|
|
IO.println "STMT-END"
|
|
|
|
|
|
IO.println s!"STMT-COUNT|{sortedStmts.size}"
|
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
|
|
|
|
|
|
|
|
|
|
end LTLAccAudit
|