mirror of
https://github.com/saymrwulf/ltl-accumulator-verified.git
synced 2026-09-03 19:53:48 +00:00
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>
123 lines
5.2 KiB
Text
123 lines
5.2 KiB
Text
/- 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
|
|
|
|
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]
|
|
|
|
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))
|
|
|
|
#eval show CoreM Unit from do
|
|
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 := #[]
|
|
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}"
|
|
let sorted := lines.qsort (· < ·)
|
|
for l in sorted do
|
|
IO.println l
|
|
IO.println s!"INV-COUNT|{sorted.size}"
|
|
|
|
end LTLAccAudit
|