Skip to content

Agentic invariant-mining toolkit for P (propose → check → repair → judge)#974

Closed
ankushdesai wants to merge 1 commit into
masterfrom
pinfer-agentic-invariants
Closed

Agentic invariant-mining toolkit for P (propose → check → repair → judge)#974
ankushdesai wants to merge 1 commit into
masterfrom
pinfer-agentic-invariants

Conversation

@ankushdesai

Copy link
Copy Markdown
Member

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:

agent proposes (from source + design intent)
   → prep_candidates.py   (deterministic P fixups)
   → repair loop          (LLM fixes non-compiling specs from the exact compiler error)
   → check_candidates.py  (model-check each: HOLDS / FAILS+cex / VACUOUS / INCONCLUSIVE)
   → agent judges          (verified / vacuous / bug / spurious, grounded in the cex)

Files (Src/PInfer/Scripts/)

File Role
check_candidates.py wire candidate monitors into a project, generate one test each, model-check, classify; vacuity canaries; flags pre-existing SUT failures as INCONCLUSIVE (not a false bug)
prep_candidates.py deterministic fixups for LLM-generated P (entity unescape, var-decl hoisting, !in/for rewrites)
diag_compile.py compile each candidate alone, capture its first compiler error
repair_workflow.js LLM-repair Workflow: rewrite a non-compiling spec given the exact error + P syntax rules (iterable)
verify_repairs.py recompile repaired specs to measure recovery
README_agentic_invariants.md how the pipeline fits together

Why this shape

  • Propose from intent, not the implementation — mirroring the code makes a bug look like a correct invariant. The gap between intent and implementation is where bugs live.
  • No trace pre-filter — a failing candidate is information: either a required property the system violates (bug) or an over-strong candidate. Only a sound check + a judgment over the concrete counterexample tells them apart.
  • Vacuity is checked — a <Name>_canary companion reveals a monitor whose assertion never fires.

Validation (4 tutorial benchmarks)

  • 82 proposed candidates → 50 machine-checked verified invariants (including rediscoveries of the authors' own specs plus many they didn't write).
  • The judge layer adjudicated 15 model-checker failures as 0 confirmed bugs, 6 monitor-encoding bugs, 9 spurious — a naive "fails = bug" pipeline would have filed 15 false reports.
  • The compile-and-repair loop recovered all 23 previously-uncompilable candidates in two rounds (compile yield ~72% → ~100%).

Scope / status

Experimental utility tooling, portable dotnet/p resolution (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

…→ 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>
Copilot AI review requested due to automatic review settings June 18, 2026 21:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.py to inject candidate specs + per-candidate tests into a P project, run p compile/p check, and classify results (HOLDS/FAILS/VACUOUS/INCONCLUSIVE).
  • Adds compile-diagnosis + repair support via diag_compile.py, repair_workflow.js, and verify_repairs.py.
  • Adds deterministic candidate cleanup with prep_candidates.py and end-to-end documentation in README_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, forforeach, 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*)\{')
Comment on lines +101 to +105
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
Comment on lines +111 to +113
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
Comment on lines +31 to +33
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
Comment on lines +49 to +50
).then(r => ({ benchmark: f.benchmark, name: f.name, changes: r && r.changes, fixedSource: r && r.fixedSource }))
)).then(a => a.filter(Boolean))
Comment on lines +67 to +70
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')
@ankushdesai

Copy link
Copy Markdown
Member Author

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).

@ankushdesai ankushdesai closed this Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants