Skip to content

Commit 34c09a4

Browse files
feat(provers): finish T1 GNN coverage + sweep T2 (35 backends) (#136)
## Summary Completes the Tier-1 GNN-routing surface and extends to all of Tier-2 per `docs/PROVER_COUNT.md`. Builds on #135 (which wired 5 Tier-1 backends earlier today). | Wave | Backends | Tier | |---|---|---| | T1 finisher | altergo, eprover | 1 | | T2 sweep | acl2, agsyhol, aprove, athena, cameleer, cbmc, chuffed, csi, dreal, glpk, HOL4, hol_light, imandra, iprover, key, lash, leo3, metamath, metitarski, minizinc, minlog, mizar, nuprl, ortools, princess, PVS, satallax, scip, spass, tlaps, twee, twelf, why3 | 2 | **Coverage progression**: session start 8/91 → after #135 13/91 → after this **46/91** (all of Tier-1 + all of Tier-2). ## Notable per-backend decisions - **6 empty-vec backends** (aprove, csi, iprover, metitarski, princess, twee) had `_state, _limit` returning `Ok(vec![])`. Wired with empty hints so GNN apply-tactics surface when enabled. - **dreal** had a redundant `if !neural_enabled { return Ok(vec![]) }` guard; removed since `gnn_augment_tactics` already gates on `neural_enabled`. - **5 backends** (hol4, hol_light, mizar, cbmc, dreal) had a redundant `suggestions.truncate(limit)` before `Ok(suggestions)`; dropped since the helper enforces `limit`. - **HOL4 / PVS** use uppercase prover-name strings matching their existing `Tactic::Custom { prover: ... }` usage. - All 33 T2 files use plain `&self.config` (no sub-config wrapper). ## Test plan - [x] `cargo build --lib` clean - [x] `cargo build --tests` clean - [x] `cargo test --test gnn_augment_integration` → **46 passed; 0 failed** in 0.25s (was 11) - [x] `docs/handover/S5-VERIFICATION-RUNBOOK.md` Step 1 expected count bumped 11 → 46 - [ ] CI rust-ci / Live-Provers / MVP Smoke green ## Follow-up Remaining unwired: ~53 Tier-3 / Tier-4 / niche backends. `coq.rs` in particular is unwired while `rocq.rs` is — same logical prover, different file. Will be addressed in a follow-up sweep alongside ROADMAP §S5 + PROVER_COUNT.md doc close-out. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ade479f commit 34c09a4

37 files changed

Lines changed: 293 additions & 82 deletions

docs/handover/S5-VERIFICATION-RUNBOOK.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,17 @@ Spawns an in-process mock HTTP server and asserts:
2828

2929
- `GnnClient::health_status()` returns the richer payload (model_path, vocab_size,
3030
training_records_received).
31-
- For each of rocq, lean, agda, isabelle, z3 (the S5 pilot) plus idris2, fstar,
32-
cvc5, vampire, dafny (the Tier-1 extension): `suggest_tactics` returns
33-
`Tactic::Custom { command: "apply", args: ["lemma_foo"] }` as the first tactic,
34-
proving the `/gnn/rank` wire format is consumed correctly by every backend.
35-
36-
Expected output: `test result: ok. 11 passed; 0 failed`.
31+
- For each of rocq, lean, agda, isabelle, z3 (the S5 pilot), idris2, fstar,
32+
cvc5, vampire, dafny (the Tier-1 extension), altergo, eprover (the Tier-1
33+
finisher), and the 33 Tier-2 backends (acl2, agsyhol, aprove, athena,
34+
cameleer, cbmc, chuffed, csi, dreal, glpk, HOL4, hol_light, imandra, iprover,
35+
key, lash, leo3, metamath, metitarski, minizinc, minlog, mizar, nuprl,
36+
ortools, princess, PVS, satallax, scip, spass, tlaps, twee, twelf, why3):
37+
`suggest_tactics` returns `Tactic::Custom { command: "apply", args: ["lemma_foo"] }`
38+
as the first tactic, proving the `/gnn/rank` wire format is consumed
39+
correctly by every backend.
40+
41+
Expected output: `test result: ok. 46 passed; 0 failed`.
3742

3843
---
3944

src/rust/provers/acl2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1550,7 +1550,7 @@ impl ProverBackend for ACL2Backend {
15501550
args: vec![],
15511551
});
15521552

1553-
Ok(suggestions.into_iter().take(limit).collect())
1553+
Ok(crate::provers::gnn_augment_tactics(&self.config, state, "acl2", suggestions, limit).await)
15541554
}
15551555

15561556
async fn search_theorems(&self, pattern: &str) -> Result<Vec<String>> {

src/rust/provers/agsyhol.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,13 @@ impl ProverBackend for AgsyholBackend {
161161
self.to_tptp(state)
162162
}
163163

164-
async fn suggest_tactics(&self, _state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
164+
async fn suggest_tactics(&self, state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
165165
let tactics = vec![Tactic::Custom {
166166
prover: "agsyhol".to_string(),
167167
command: "timeout".to_string(),
168168
args: vec![format!("{}", self.config.timeout)],
169169
}];
170-
Ok(tactics.into_iter().take(limit).collect())
170+
Ok(crate::provers::gnn_augment_tactics(&self.config, state, "agsyhol", tactics, limit).await)
171171
}
172172

173173
async fn search_theorems(&self, _pattern: &str) -> Result<Vec<String>> {

src/rust/provers/altergo.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ impl ProverBackend for AltErgoBackend {
212212
self.to_altergo(state)
213213
}
214214

215-
async fn suggest_tactics(&self, _state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
215+
async fn suggest_tactics(&self, state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
216216
// Alt-Ergo is an SMT solver; suggestions are option-level strategy hints
217217
// rather than interactive proof tactics.
218218
let tactics = vec![
@@ -238,7 +238,7 @@ impl ProverBackend for AltErgoBackend {
238238
args: vec!["--sat-solver CDCL-Tableaux".to_string()],
239239
},
240240
];
241-
Ok(tactics.into_iter().take(limit).collect())
241+
Ok(crate::provers::gnn_augment_tactics(&self.config, state, "altergo", tactics, limit).await)
242242
}
243243

244244
async fn search_theorems(&self, _pattern: &str) -> Result<Vec<String>> {

src/rust/provers/aprove.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,8 @@ impl ProverBackend for AProVEBackend {
168168
self.to_trs(state)
169169
}
170170

171-
async fn suggest_tactics(&self, _state: &ProofState, _limit: usize) -> Result<Vec<Tactic>> {
172-
Ok(vec![])
171+
async fn suggest_tactics(&self, state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
172+
Ok(crate::provers::gnn_augment_tactics(&self.config, state, "aprove", vec![], limit).await)
173173
}
174174

175175
async fn search_theorems(&self, _pattern: &str) -> Result<Vec<String>> {

src/rust/provers/athena.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ impl ProverBackend for AthenaBackend {
108108
.map(String::from)
109109
.unwrap_or_default())
110110
}
111-
async fn suggest_tactics(&self, _state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
111+
async fn suggest_tactics(&self, state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
112112
// Athena is a multi-logic deduction language. Its core reasoning
113113
// methods map onto the following canonical proof steps.
114114
let tactics = vec![
@@ -136,7 +136,7 @@ impl ProverBackend for AthenaBackend {
136136
},
137137
Tactic::Simplify,
138138
];
139-
Ok(tactics.into_iter().take(limit).collect())
139+
Ok(crate::provers::gnn_augment_tactics(&self.config, state, "athena", tactics, limit).await)
140140
}
141141

142142
async fn search_theorems(&self, _pattern: &str) -> Result<Vec<String>> {

src/rust/provers/cameleer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ impl ProverBackend for CameleerBackend {
131131
.unwrap_or_default())
132132
}
133133

134-
async fn suggest_tactics(&self, _state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
134+
async fn suggest_tactics(&self, state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
135135
// Cameleer is a deductive verification tool for OCaml programs; it
136136
// lowers to Why3. Suggestions are Gospel contract annotations and
137137
// Why3 proof hints rather than interactive proof tactics.
@@ -163,7 +163,7 @@ impl ProverBackend for CameleerBackend {
163163
args: vec!["split_vc".to_string()],
164164
},
165165
];
166-
Ok(tactics.into_iter().take(limit).collect())
166+
Ok(crate::provers::gnn_augment_tactics(&self.config, state, "cameleer", tactics, limit).await)
167167
}
168168

169169
async fn search_theorems(&self, _pattern: &str) -> Result<Vec<String>> {

src/rust/provers/cbmc.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,8 @@ impl ProverBackend for CBMCBackend {
414414
self.to_c_source(state)
415415
}
416416

417-
async fn suggest_tactics(&self, _state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
418-
let mut tactics = vec![
417+
async fn suggest_tactics(&self, state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
418+
let tactics = vec![
419419
Tactic::Custom {
420420
prover: "cbmc".to_string(),
421421
command: "set_unwind_bound".to_string(),
@@ -433,8 +433,7 @@ impl ProverBackend for CBMCBackend {
433433
},
434434
];
435435

436-
tactics.truncate(limit);
437-
Ok(tactics)
436+
Ok(crate::provers::gnn_augment_tactics(&self.config, state, "cbmc", tactics, limit).await)
438437
}
439438

440439
async fn search_theorems(&self, _pattern: &str) -> Result<Vec<String>> {

src/rust/provers/chuffed.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ impl ProverBackend for ChuffedBackend {
136136
async fn export(&self, state: &ProofState) -> Result<String> {
137137
self.to_input_format(state)
138138
}
139-
async fn suggest_tactics(&self, _state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
139+
async fn suggest_tactics(&self, state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
140140
// Chuffed is a lazy-clause-generation CP solver. Suggestions are
141141
// MiniZinc solve annotations and propagation strategy hints.
142142
let tactics = vec![
@@ -162,7 +162,7 @@ impl ProverBackend for ChuffedBackend {
162162
args: vec!["--prop-fifo".to_string()],
163163
},
164164
];
165-
Ok(tactics.into_iter().take(limit).collect())
165+
Ok(crate::provers::gnn_augment_tactics(&self.config, state, "chuffed", tactics, limit).await)
166166
}
167167

168168
async fn search_theorems(&self, _pattern: &str) -> Result<Vec<String>> {

src/rust/provers/csi.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,12 @@ impl ProverBackend for CSIBackend {
164164
self.to_trs(state)
165165
}
166166

167-
async fn suggest_tactics(&self, _state: &ProofState, _limit: usize) -> Result<Vec<Tactic>> {
167+
async fn suggest_tactics(&self, state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
168168
// CSI is a fully automated TRS confluence/termination solver.
169169
// It has no user-facing tactic language — correctness certificates
170-
// are produced internally. Returning empty is correct behaviour.
171-
Ok(vec![])
170+
// are produced internally. GNN-ranked premises (when enabled) are
171+
// still surfaced as apply hints; otherwise the result is empty.
172+
Ok(crate::provers::gnn_augment_tactics(&self.config, state, "csi", vec![], limit).await)
172173
}
173174

174175
async fn search_theorems(&self, _pattern: &str) -> Result<Vec<String>> {

0 commit comments

Comments
 (0)