Skip to content

Commit 2edf1a8

Browse files
feat(provers): extend GNN-ranking from 5 to 10 Tier-1 backends (#135)
## Summary Extends `gnn_augment_tactics` (the S5 sprint wrapper that prepends GNN-ranked apply tactics ahead of heuristic hints) from the 5 pilot backends (rocq / lean / agda / isabelle / z3, commit c8a4f25) to the remaining five **Tier-1** backends per the canonical tier table in `docs/PROVER_COUNT.md`: | Backend | Type | Surface | |---|---|---| | idris2 | interactive dependent types | uses `state.context.theorems` | | fstar | interactive + SMT | canned tactic list | | cvc5 | SMT | uses `self.config.base` (cvc5 wraps `ProverConfig`) | | vampire | FOL ATP | strategy scheduling | | dafny | auto-active verifier | shape-driven heuristics | After this PR: **10 of 12 Tier-1 backends are GNN-routed** (altergo + eprover remain — split into a follow-up so this PR stays atomic). The wrapper preserves behaviour when the Julia GNN service is unavailable (`gnn_api_url` None or `neural_enabled` false → returns raw heuristic hints). ## Test plan - [x] `cargo build --lib` clean - [x] `cargo test --test gnn_augment_integration` → `11 passed; 0 failed` (was 6) - [ ] CI rust-ci / Live-Provers / MVP Smoke green - [ ] `docs/handover/S5-VERIFICATION-RUNBOOK.md` Step 1 manual re-run when next reviewer touches the runbook ## ROADMAP impact §S5 status will progress from \"mostly done — GNN wired into the 5 pilot backends\" to \"core Tier-1 surface complete — 10 of 12 GNN-wired, altergo + eprover queued\". Roadmap update deferred to a follow-up doc PR to keep this one tightly scoped. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f8511a4 commit 2edf1a8

7 files changed

Lines changed: 47 additions & 12 deletions

File tree

docs/handover/S5-VERIFICATION-RUNBOOK.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ 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: `suggest_tactics` returns
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
3233
`Tactic::Custom { command: "apply", args: ["lemma_foo"] }` as the first tactic,
3334
proving the `/gnn/rank` wire format is consumed correctly by every backend.
3435

35-
Expected output: `test result: ok. 6 passed; 0 failed`.
36+
Expected output: `test result: ok. 11 passed; 0 failed`.
3637

3738
---
3839

src/rust/provers/cvc5.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ impl ProverBackend for CVC5Backend {
696696
Ok(output)
697697
}
698698

699-
async fn suggest_tactics(&self, _state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
699+
async fn suggest_tactics(&self, state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
700700
let mut tactics = vec![Tactic::Custom {
701701
prover: "cvc5".to_string(),
702702
command: "check-sat".to_string(),
@@ -719,7 +719,7 @@ impl ProverBackend for CVC5Backend {
719719
args: vec![],
720720
});
721721
}
722-
Ok(tactics.into_iter().take(limit).collect())
722+
Ok(crate::provers::gnn_augment_tactics(&self.config.base, state, "cvc5", tactics, limit).await)
723723
}
724724

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

src/rust/provers/dafny.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ impl ProverBackend for DafnyBackend {
329329
_ => {},
330330
}
331331

332-
Ok(suggestions.into_iter().take(limit).collect())
332+
Ok(crate::provers::gnn_augment_tactics(&self.config, state, "dafny", suggestions, limit).await)
333333
}
334334

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

src/rust/provers/fstar.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ impl ProverBackend for FStarBackend {
215215
async fn export(&self, state: &ProofState) -> Result<String> {
216216
self.to_input_format(state)
217217
}
218-
async fn suggest_tactics(&self, _state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
218+
async fn suggest_tactics(&self, state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
219219
// F* supports both a tactic DSL (Tactics monad) and SMT-backed
220220
// verification. The canonical first-pass tactics are listed below.
221221
let tactics = vec![
@@ -248,7 +248,7 @@ impl ProverBackend for FStarBackend {
248248
Tactic::Assumption,
249249
Tactic::Reflexivity,
250250
];
251-
Ok(tactics.into_iter().take(limit).collect())
251+
Ok(super::gnn_augment_tactics(&self.config, state, "fstar", tactics, limit).await)
252252
}
253253

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

src/rust/provers/idris2.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,10 @@ impl ProverBackend for Idris2Backend {
956956
});
957957
}
958958

959-
Ok(suggestions.into_iter().take(limit).collect())
959+
Ok(
960+
crate::provers::gnn_augment_tactics(&self.config, state, "idris2", suggestions, limit)
961+
.await,
962+
)
960963
}
961964

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

src/rust/provers/vampire.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ impl ProverBackend for VampireBackend {
236236
self.to_tptp(state)
237237
}
238238

239-
async fn suggest_tactics(&self, _state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
239+
async fn suggest_tactics(&self, state: &ProofState, limit: usize) -> Result<Vec<Tactic>> {
240240
// Vampire is a fully-automated first-order ATP and proof checker.
241241
// Suggestions are strategy and scheduling options passed to the binary.
242242
let tactics = vec![
@@ -267,7 +267,7 @@ impl ProverBackend for VampireBackend {
267267
},
268268
Tactic::Simplify,
269269
];
270-
Ok(tactics.into_iter().take(limit).collect())
270+
Ok(crate::provers::gnn_augment_tactics(&self.config, state, "vampire", tactics, limit).await)
271271
}
272272

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

tests/gnn_augment_integration.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
33

44
//! Integration test: mock HTTP server proves the GNN wire format works and
5-
//! that the 5 key backends (rocq, lean, agda, isabelle, z3) consume
6-
//! `/gnn/rank` and prepend model-derived apply tactics.
5+
//! that the 10 GNN-augmented Tier-1 backends (rocq, lean, agda, isabelle, z3
6+
//! from the S5 pilot, plus idris2, fstar, cvc5, vampire, dafny extending it)
7+
//! consume `/gnn/rank` and prepend model-derived apply tactics.
78
//!
89
//! No Julia installation needed — the mock server is an in-process axum
910
//! server bound to a random port. Run with:
@@ -203,3 +204,33 @@ async fn test_z3_gnn_wires_top_premise() {
203204
let base_url = spawn_mock_gnn_server().await;
204205
assert_top_tactic_is_apply(ProverKind::Z3, "z3", &base_url).await;
205206
}
207+
208+
#[tokio::test]
209+
async fn test_idris2_gnn_wires_top_premise() {
210+
let base_url = spawn_mock_gnn_server().await;
211+
assert_top_tactic_is_apply(ProverKind::Idris2, "idris2", &base_url).await;
212+
}
213+
214+
#[tokio::test]
215+
async fn test_fstar_gnn_wires_top_premise() {
216+
let base_url = spawn_mock_gnn_server().await;
217+
assert_top_tactic_is_apply(ProverKind::FStar, "fstar", &base_url).await;
218+
}
219+
220+
#[tokio::test]
221+
async fn test_cvc5_gnn_wires_top_premise() {
222+
let base_url = spawn_mock_gnn_server().await;
223+
assert_top_tactic_is_apply(ProverKind::CVC5, "cvc5", &base_url).await;
224+
}
225+
226+
#[tokio::test]
227+
async fn test_vampire_gnn_wires_top_premise() {
228+
let base_url = spawn_mock_gnn_server().await;
229+
assert_top_tactic_is_apply(ProverKind::Vampire, "vampire", &base_url).await;
230+
}
231+
232+
#[tokio::test]
233+
async fn test_dafny_gnn_wires_top_premise() {
234+
let base_url = spawn_mock_gnn_server().await;
235+
assert_top_tactic_is_apply(ProverKind::Dafny, "dafny", &base_url).await;
236+
}

0 commit comments

Comments
 (0)