mirror of
https://github.com/saymrwulf/proof-aware-crypto-tooling-agent.git
synced 2026-09-04 20:03:40 +00:00
fix: axiom-output parser mis-attributed cones to axiom-free certificates
Found by the entry-13 rehearsal (the accumulator corpus is the first
subject with axiom-free certificates — every fork certificate carries
at least the boundary axiom, so this path was never exercised):
- an axiom-free certificate ('X' does not depend on any axioms) was
parsed by opening a 16-line window and taking the first bracket in
it — which belongs to the NEXT certificate. domsep/Hash/
instDecidableEqHash/take_append_drop were reported with their
neighbors' cones and flagged dirty.
- certificate names were matched as bare substrings, so 'Foo' could
anchor on the line for 'Foo_bar'. Now anchored on the exact quoted
name Lean prints.
The no-axioms decision is now made on the anchor line itself, before
any window. Two regression tests added (steal-next-cone, exact-name);
suite 108 passed / 0 failed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
3d81d5380c
commit
34a04572f0
2 changed files with 41 additions and 4 deletions
|
|
@ -320,10 +320,22 @@ def parse_axiom_output(output: str, certificates: list[str]) -> dict[str, list[s
|
|||
results: dict[str, list[str]] = {}
|
||||
lines = output.splitlines()
|
||||
for cert in certificates:
|
||||
# Anchor on the exact quoted name Lean prints ('X' depends on … /
|
||||
# 'X' does not depend on any axioms). A bare substring match would
|
||||
# let 'Foo' hit the line for 'Foo_bar' first.
|
||||
needle = f"'{cert}'"
|
||||
cert_results: list[str] | None = None
|
||||
for i, line in enumerate(lines):
|
||||
if cert not in line:
|
||||
if needle not in line:
|
||||
continue
|
||||
# Axiom-free certificates print a bracketless sentence. Decide
|
||||
# on THIS line before opening any window: a window would reach
|
||||
# into the NEXT certificate's bracket and steal its cone (found
|
||||
# by the entry-13 rehearsal — the accumulator corpus is the
|
||||
# first subject with axiom-free certificates).
|
||||
if _mentions_no_axioms(line):
|
||||
cert_results = []
|
||||
break
|
||||
# Lean wraps long axiom lists (the apex tiers carry 11 axioms)
|
||||
# across many lines; take a window wide enough for the largest
|
||||
# documented boundary and flatten it before matching, the same
|
||||
|
|
@ -333,9 +345,6 @@ def parse_axiom_output(output: str, certificates: list[str]) -> dict[str, list[s
|
|||
if bracket:
|
||||
cert_results = [item.strip() for item in bracket.group(1).split(",") if item.strip()]
|
||||
break
|
||||
if _mentions_no_axioms(window):
|
||||
cert_results = []
|
||||
break
|
||||
if cert_results is not None:
|
||||
results[cert] = cert_results
|
||||
return results
|
||||
|
|
|
|||
|
|
@ -24,6 +24,34 @@ def test_parse_axiom_output_no_axioms_wording():
|
|||
assert parsed["CurveFieldProofs.fieldImplementation"] == []
|
||||
|
||||
|
||||
def test_parse_axiom_output_axiom_free_cert_does_not_steal_next_cone():
|
||||
# Regression (found by the entry-13 rehearsal, 2026-07-16): an
|
||||
# axiom-free certificate is followed by a cone-carrying one. The old
|
||||
# windowed search reached past the bracketless "does not depend"
|
||||
# sentence and attributed the NEXT certificate's cone. The
|
||||
# accumulator corpus is the first subject with axiom-free
|
||||
# certificates (domsep, Hash, instDecidableEqHash, take_append_drop),
|
||||
# so no fork attestation ever exercised this path.
|
||||
output = (
|
||||
"'LTLAcc.domsep' does not depend on any axioms\n"
|
||||
"'LTLAcc.eq_dropLast_append_of_getLast?' depends on axioms: [propext]\n"
|
||||
)
|
||||
parsed = parse_axiom_output(output, ["LTLAcc.domsep", "LTLAcc.eq_dropLast_append_of_getLast?"])
|
||||
assert parsed["LTLAcc.domsep"] == []
|
||||
assert parsed["LTLAcc.eq_dropLast_append_of_getLast?"] == ["propext"]
|
||||
|
||||
|
||||
def test_parse_axiom_output_exact_name_not_prefix():
|
||||
# 'LTLAcc.MTH' must not match the line for 'LTLAcc.MTH_single' even
|
||||
# when the latter comes first in the output.
|
||||
output = (
|
||||
"'LTLAcc.MTH_single' depends on axioms: [propext, LTLAcc.sha256, Quot.sound]\n"
|
||||
"'LTLAcc.MTH' depends on axioms: [propext, LTLAcc.sha256, Quot.sound]\n"
|
||||
)
|
||||
parsed = parse_axiom_output(output, ["LTLAcc.MTH"])
|
||||
assert parsed["LTLAcc.MTH"] == ["propext", "LTLAcc.sha256", "Quot.sound"]
|
||||
|
||||
|
||||
def test_mac_safe_lean_command_is_argument_list():
|
||||
tools = LeanTools(lean="/usr/local/bin/lean", lake=None)
|
||||
cmd = build_lean_invocation(Path("Proofs/A.lean"), tools, output_path=Path("Proofs/A.olean"), root_path=Path("."))
|
||||
|
|
|
|||
Loading…
Reference in a new issue