Skip to content

Commit 32de46a

Browse files
hyperpolymathclaude
andcommitted
feat(specialists): expand playbooks with session-derived proof-repair patterns
Each playbook grew from 4 → 10-12 tactics, lifting real patterns from the 2026-04-26 Tropical_Semirings dogfood session into the swarm so they're named, citable in the ledger, and reusable across goals. Algebraist (4 → 10): + ac-simps (replaces looping metis chains on +/* monoids) + semiring-distrib (both-sided distributivity) + metis-empty (no-hint equational reasoning) + linarith-after-simp (Isabelle 2025-1 omega→linarith fallback) + comm-monoid-add (add.commute is the post-rebrand name) + transfer-then-simp (quotient/representation-type goals) OrderTheorist (4 → 12): + linarith (omega→linarith drift in 2025-1) + sum-mono (Kleene 237 pattern) + monoI-then-auto + force (Kleene 403 list-decomp fallback) + meson-order (transitive chains where blast loops) + le-supI (sup introduction either side) + subset-trans (replaces blast loops on nested ⊆) + order-trans-OF (transitivity with assumption pre-substituted) Combinatorialist (4 → 12): + induction-arbitrary (Matrices_Full helper pattern) + cases-list (list-non-empty pattern) + sum-insert (replaces deprecated sum.atLeastAtMost_Suc) + sum-distrib (replaces renamed sum_add_distrib) + unfolding-walks-def (beats `proof (intro conjI)` for Collect sets) + metis-append (Kleene 403 [v]@ys vs v#ys decomposition) + force (list-decomp obtain goals) + permutes-in-image (Det 153/207 type-class regression fix) + transposition-2x2 (Fun.swap is input-only in 2025-1) Tests: 4 new lock-in tests assert minimum tactic counts and the presence of the named session-repair patterns by name, so future shrink-regressions fail loudly. Full burrower-core suite: 27/27 passing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 0bbfe59 commit 32de46a

1 file changed

Lines changed: 165 additions & 1 deletion

File tree

crates/burrower-core/src/specialist.rs

Lines changed: 165 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,36 @@ impl Specialist for Algebraist {
232232
script: "by (simp add: field_simps)".to_string(),
233233
description: "Field/ring arithmetic simplification.".to_string(),
234234
},
235+
TacticTemplate {
236+
name: "ac-simps".to_string(),
237+
script: "by (simp add: ac_simps)".to_string(),
238+
description: "Associativity + commutativity rewriting — replaces looping metis chains on +/* monoids.".to_string(),
239+
},
240+
TacticTemplate {
241+
name: "semiring-distrib".to_string(),
242+
script: "by (simp add: distrib_left distrib_right)".to_string(),
243+
description: "Both-sided distributivity for semiring goals.".to_string(),
244+
},
245+
TacticTemplate {
246+
name: "metis-empty".to_string(),
247+
script: "by metis".to_string(),
248+
description: "Equational reasoning without hints — succeeds where simp loses orientation.".to_string(),
249+
},
250+
TacticTemplate {
251+
name: "linarith-after-simp".to_string(),
252+
script: "by (simp; linarith)".to_string(),
253+
description: "Simplifier reduction followed by linear arithmetic — Isabelle 2025-1 omega→linarith drift fallback.".to_string(),
254+
},
255+
TacticTemplate {
256+
name: "comm-monoid-add".to_string(),
257+
script: "by (simp add: ac_simps add.commute)".to_string(),
258+
description: "Commutative-monoid rewriting (add.commute is the post-rebrand name).".to_string(),
259+
},
260+
TacticTemplate {
261+
name: "transfer-then-simp".to_string(),
262+
script: "by (transfer, simp add: algebra_simps)".to_string(),
263+
description: "Transfer to representation type then simplify — useful for tropical/quotient goals.".to_string(),
264+
},
235265
],
236266
}
237267
}
@@ -265,7 +295,7 @@ impl Specialist for OrderTheorist {
265295
TacticTemplate {
266296
name: "order-trans".to_string(),
267297
script: "by (rule order_trans)".to_string(),
268-
description: "Transitivity of ≤.".to_string(),
298+
description: "Transitivity of ≤ (Isabelle 2025-1 canonical name; le_trans was deprecated).".to_string(),
269299
},
270300
TacticTemplate {
271301
name: "order-auto".to_string(),
@@ -277,6 +307,46 @@ impl Specialist for OrderTheorist {
277307
script: "by (auto simp: subset_iff)".to_string(),
278308
description: "Element-wise subset reasoning.".to_string(),
279309
},
310+
TacticTemplate {
311+
name: "linarith".to_string(),
312+
script: "by linarith".to_string(),
313+
description: "Linear arithmetic decision procedure — replaces omega in Isabelle 2025-1.".to_string(),
314+
},
315+
TacticTemplate {
316+
name: "sum-mono".to_string(),
317+
script: "by (rule sum_mono) auto".to_string(),
318+
description: "Pointwise monotonicity of sums (Kleene 237 pattern).".to_string(),
319+
},
320+
TacticTemplate {
321+
name: "monoI-then-auto".to_string(),
322+
script: "by (intro monoI) auto".to_string(),
323+
description: "Introduce monotonicity then resolve elementwise.".to_string(),
324+
},
325+
TacticTemplate {
326+
name: "force".to_string(),
327+
script: "by force".to_string(),
328+
description: "Stronger than blast for goals needing list/sequence decomposition (Kleene 403 pattern: [v] vs v#[]).".to_string(),
329+
},
330+
TacticTemplate {
331+
name: "meson-order".to_string(),
332+
script: "by (meson order_trans)".to_string(),
333+
description: "Meson with transitive chain — succeeds on multi-hop ≤ goals where blast loops.".to_string(),
334+
},
335+
TacticTemplate {
336+
name: "le-supI".to_string(),
337+
script: "by (auto intro: le_supI1 le_supI2)".to_string(),
338+
description: "Sup introduction on either side — for goals against a join.".to_string(),
339+
},
340+
TacticTemplate {
341+
name: "subset-trans".to_string(),
342+
script: "by (meson subset_trans)".to_string(),
343+
description: "Subset transitivity chain — replaces blast loops on nested ⊆ obligations.".to_string(),
344+
},
345+
TacticTemplate {
346+
name: "order-trans-OF".to_string(),
347+
script: "by (rule order_trans[OF assms]) simp".to_string(),
348+
description: "Apply transitivity with the assumption pre-substituted — often the missing instantiation.".to_string(),
349+
},
280350
],
281351
}
282352
}
@@ -321,6 +391,51 @@ impl Specialist for Combinatorialist {
321391
script: "by (induction xs) auto".to_string(),
322392
description: "Structural induction on a list named xs.".to_string(),
323393
},
394+
TacticTemplate {
395+
name: "induction-arbitrary".to_string(),
396+
script: "by (induction k arbitrary: j) auto".to_string(),
397+
description: "Generalised induction (Matrices_Full helper pattern: arbitrary: j keeps the IH usable across positions).".to_string(),
398+
},
399+
TacticTemplate {
400+
name: "cases-list".to_string(),
401+
script: "by (cases w; auto)".to_string(),
402+
description: "Case-split on list constructors then auto — the list-non-empty pattern.".to_string(),
403+
},
404+
TacticTemplate {
405+
name: "sum-insert".to_string(),
406+
script: "by (subst sum.insert) auto".to_string(),
407+
description: "Step a sum at an insert (replaces sum.atLeastAtMost_Suc, deprecated in 2025-1).".to_string(),
408+
},
409+
TacticTemplate {
410+
name: "sum-distrib".to_string(),
411+
script: "by (simp add: sum.distrib)".to_string(),
412+
description: "Sum distributivity (replaces sum_add_distrib, renamed in 2025-1).".to_string(),
413+
},
414+
TacticTemplate {
415+
name: "unfolding-walks-def".to_string(),
416+
script: "unfolding walks_def by simp".to_string(),
417+
description: "Unfold walks_def then simp — beats `proof (intro conjI)` because walks_def yields a Collect set.".to_string(),
418+
},
419+
TacticTemplate {
420+
name: "metis-append".to_string(),
421+
script: "by (metis append_Cons append_Nil)".to_string(),
422+
description: "List concatenation lemmas — closes obtain-decompositions of [v]@ys vs v#ys (Kleene 403 pattern).".to_string(),
423+
},
424+
TacticTemplate {
425+
name: "force".to_string(),
426+
script: "by force".to_string(),
427+
description: "Stronger than blast for list-decomposition obtain goals.".to_string(),
428+
},
429+
TacticTemplate {
430+
name: "permutes-in-image".to_string(),
431+
script: "by (rule permutes_in_image[OF assms])".to_string(),
432+
description: "Permutations as image-preserving — closes Det 153/207 type-class regression goals.".to_string(),
433+
},
434+
TacticTemplate {
435+
name: "transposition-2x2".to_string(),
436+
script: "by (cases a; cases b) (auto simp: Transposition.transpose)".to_string(),
437+
description: "2x2 case split using Transposition.transpose (Fun.swap is input-only in 2025-1).".to_string(),
438+
},
324439
],
325440
}
326441
}
@@ -543,6 +658,55 @@ mod tests {
543658
assert!(s.relevance(&g) > 0.0, "should engage on walks + finite");
544659
}
545660

661+
#[test]
662+
fn playbooks_expanded_2026_04_26() {
663+
// After the swarm-dogfood session against Tropical_Semirings, each
664+
// playbook was expanded with proof-repair patterns observed in real
665+
// failure sites (cycle-excise, Det 153/207, Kleene 403, etc.) plus
666+
// Isabelle 2025-1 drift fixes (omega→linarith, sum.atLeastAtMost_Suc
667+
// deprecation, Fun.swap input-only). Lock in the new minimums so
668+
// future shrink-regressions are caught.
669+
assert!(Algebraist.playbook().tactics.len() >= 10,
670+
"Algebraist playbook should have ≥10 tactics post-2026-04-26 expansion");
671+
assert!(OrderTheorist.playbook().tactics.len() >= 12,
672+
"OrderTheorist playbook should have ≥12 tactics post-2026-04-26 expansion");
673+
assert!(Combinatorialist.playbook().tactics.len() >= 12,
674+
"Combinatorialist playbook should have ≥12 tactics post-2026-04-26 expansion");
675+
}
676+
677+
#[test]
678+
fn combinatorialist_carries_session_repair_patterns() {
679+
// The Tropical_Semirings session-close added these specific tactics
680+
// because real failures pointed at them. They must stay named-and-
681+
// findable so a future ledger entry can cite them by name.
682+
let names: Vec<String> = Combinatorialist.playbook().tactics
683+
.iter().map(|t| t.name.clone()).collect();
684+
assert!(names.iter().any(|n| n == "permutes-in-image"),
685+
"Combinatorialist must carry the Det 153/207 fix");
686+
assert!(names.iter().any(|n| n == "metis-append"),
687+
"Combinatorialist must carry the Kleene 403 list-decomp fix");
688+
assert!(names.iter().any(|n| n == "induction-arbitrary"),
689+
"Combinatorialist must carry the Matrices_Full generalised-induction pattern");
690+
}
691+
692+
#[test]
693+
fn order_theorist_carries_2025_drift_fixes() {
694+
let names: Vec<String> = OrderTheorist.playbook().tactics
695+
.iter().map(|t| t.name.clone()).collect();
696+
assert!(names.iter().any(|n| n == "linarith"),
697+
"OrderTheorist must carry linarith (omega→linarith drift in 2025-1)");
698+
assert!(names.iter().any(|n| n == "force"),
699+
"OrderTheorist must carry force (Kleene 403 list-decomp fallback)");
700+
}
701+
702+
#[test]
703+
fn algebraist_carries_ac_simps_replacement() {
704+
let names: Vec<String> = Algebraist.playbook().tactics
705+
.iter().map(|t| t.name.clone()).collect();
706+
assert!(names.iter().any(|n| n == "ac-simps"),
707+
"Algebraist must carry ac-simps (replaces looping metis chains)");
708+
}
709+
546710
#[test]
547711
fn swarm_routes_to_relevant_specialists_first() {
548712
let g = parse_goal("lemma foo: \"finite T \\<Longrightarrow> trop_walks_sum A S \\<le> trop_walks_sum A T\"");

0 commit comments

Comments
 (0)