Agentic invariant-mining toolkit for P (propose → check → repair → judge)#974
Agentic invariant-mining toolkit for P (propose → check → repair → judge)#974ankushdesai wants to merge 1 commit into
Conversation
…→ judge) Standalone tooling that drives `p compile` / `p check` to mine and verify candidate specification monitors for P programs. An LLM proposes intent-level invariants from the source; PChecker (the sound oracle) verifies every one; the agent then judges each result as verified / vacuous / bug / spurious. No dependency on the PInfer C# backend — these are pure utility scripts: - check_candidates.py : wire candidate monitors into a project, generate one test each, model-check, classify HOLDS / FAILS(+cex) / VACUOUS, with vacuity canaries and detection of pre-existing SUT failures (reported INCONCLUSIVE, not a false bug). - prep_candidates.py : deterministic P fixups for LLM-generated specs (entity unescape, var-decl hoisting, `!in`/`for` rewrites). - diag_compile.py / repair_workflow.js / verify_repairs.py : compile-and-repair loop that feeds the exact compiler error back to an LLM to fix non-compiling candidates (recovered all dropped candidates in two rounds on the tutorials). - README_agentic_invariants.md : how the pipeline fits together. Portable dotnet/`p` resolution (Linux + macOS). Experimental; intended for discussion alongside the PInfer effort. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a standalone, agent-oriented “propose → check → repair → judge” utility toolkit under Src/PInfer/Scripts/ to mechanically wire LLM-proposed P spec monitors into existing P tutorial projects, compile/check them with PChecker, diagnose compilation failures, and support iterative LLM repair.
Changes:
- Introduces
check_candidates.pyto inject candidate specs + per-candidate tests into a P project, runp compile/p check, and classify results (HOLDS/FAILS/VACUOUS/INCONCLUSIVE). - Adds compile-diagnosis + repair support via
diag_compile.py,repair_workflow.js, andverify_repairs.py. - Adds deterministic candidate cleanup with
prep_candidates.pyand end-to-end documentation inREADME_agentic_invariants.md.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| Src/PInfer/Scripts/check_candidates.py | Wires candidate specs/tests into a project and runs PChecker to classify outcomes, including vacuity canaries. |
| Src/PInfer/Scripts/diag_compile.py | Compiles candidates one-at-a-time to capture the first compiler error per spec for repair. |
| Src/PInfer/Scripts/prep_candidates.py | Applies deterministic transformations to LLM-generated P (unescape, !in rewrite, for→foreach, var hoisting). |
| Src/PInfer/Scripts/repair_workflow.js | Workflow wrapper to LLM-repair non-compiling monitors using compiler errors + syntax rules. |
| Src/PInfer/Scripts/verify_repairs.py | Recompiles repaired specs to measure recovery rate and report remaining failures. |
| Src/PInfer/Scripts/README_agentic_invariants.md | Documents the overall pipeline and how to run the scripts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import html, json, re, sys | ||
| from pathlib import Path | ||
|
|
||
| HANDLER_RE = re.compile(r'(on\s+\w+\s+do\s*\([^)]*\)\s*|on\s+\w+\s+goto\s+\w+\s+with\s*\([^)]*\)\s*|entry\s*(?:\([^)]*\))?\s*|exit\s*)\{') |
| def wire(subset): | ||
| cand_dst.write_text("\n".join(block_of[n] for n in subset)) | ||
| test_dst.write_text("// AUTO-GENERATED\n\n" + "\n".join( | ||
| f"test tc_{n} [main={args.main}]:\n assert {n} in {args.assert_in};\n" for n in subset)) | ||
| return "Compilation succeeded" in run(["p", "compile"], proj, env).stdout |
| out = run(["p", "check", "-tc", f"tc_{n}", "-i", str(args.iters)], proj, env).stdout | ||
| m = BUG_RE.search(out) | ||
| bugs = int(m.group(1)) if m else -1 |
| for i in range(len(spans) - 1): | ||
| name, block = spans[i][1], src[spans[i][0]:spans[i + 1][0]].strip() | ||
| diag.write_text(block) | ||
| out = subprocess.run(["p", "compile"], cwd=d, env=env, capture_output=True, text=True).stdout |
| def main(): | ||
| env = build_env() | ||
| data = json.loads(Path(sys.argv[1]).read_text()) |
| d = r["dir"] | ||
| diag = Path(d) / "PSpec" / "_diag.p" | ||
| diag.write_text(r["fixedSource"]) | ||
| out = subprocess.run(["p", "compile"], cwd=d, env=env, capture_output=True, text=True).stdout |
| ).then(r => ({ benchmark: f.benchmark, name: f.name, changes: r && r.changes, fixedSource: r && r.fixedSource })) | ||
| )).then(a => a.filter(Boolean)) |
| def main(): | ||
| data = json.loads(Path(sys.argv[1]).read_text()) | ||
| by = data.get('result', data) | ||
| outdir = Path(sys.argv[2]) if len(sys.argv) > 2 else Path('/tmp') |
|
Superseded by #977, which carries the hardened successors of these scripts (frozen candidate schema, auto-canary vacuity, static name gate, baseline-differential attribution, ranking) plus the design plan (Src/PInfer/Scripts/PLAN.md). |
What
Standalone tooling that uses an LLM to propose intent-level specification invariants for P programs, has PChecker verify every one (the sound oracle), and then judges each result. No dependency on the PInfer C# backend — these are pure utility scripts driving
p compile/p check.The loop:
Files (
Src/PInfer/Scripts/)check_candidates.pyINCONCLUSIVE(not a false bug)prep_candidates.pyvar-decl hoisting,!in/forrewrites)diag_compile.pyrepair_workflow.jsverify_repairs.pyREADME_agentic_invariants.mdWhy this shape
<Name>_canarycompanion reveals a monitor whose assertion never fires.Validation (4 tutorial benchmarks)
Scope / status
Experimental utility tooling, portable dotnet/
presolution (Linux + macOS). Opened for discussion alongside the PInfer effort; the propose/judge steps are LLM-driven (run with Claude Code or any agent), this PR is the deterministic middle.🤖 Generated with Claude Code