1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! Tenth agentic recipe — classify an arbitrary failure and decide how to repair.
//!
//! This drives Formal AI to *classify an arbitrary failure and decide how to repair
//! itself*, for **every** class of failure, reachable via the agentic interface (issue
//! #558, `R558-02`).
//!
//! Issue #558 ("Auto learning") asks that a failure trace can trigger a repair run
//! that changes a **solver method**, a **data record**, or a **test**. The
//! self-healing recipe ([`super::self_heal`]) executes the *solver-method* path end to
//! end, but on a single canonical failure. [`crate::repair_strategy`] generalises the
//! *front* of the loop: given an arbitrary [`UnknownTrace`](crate::self_improvement::UnknownTrace),
//! it classifies which of the three classes the repair belongs to and composes the
//! grounded, human-gated strategy for it. This module makes that classifier reachable
//! *through the agentic interface*: an external agent CLI (`Codex`, `OpenCode`,
//! `Gemini`, `Agent CLI`) — or the in-repo driver — asks Formal AI to classify a
//! failure and decide which part to repair, and the deterministic planner walks a
//! write → verify → final recipe that emits the three canonical strategies (one per
//! target class) as Links Notation, exactly like the self-healing, ledger, and diagram
//! recipes emit their documents.
//!
//! Unlike the source-graph, explain, and change-request recipes, the emitted document
//! depends only on the three self-contained canonical failure traces (never on the
//! whole source tree), so it is committed byte-for-byte as
//! `data/meta/repair-strategies.lino` and asserted against a fresh render in the
//! issue-#558 tests — like [`super::self_heal`]'s repair case. Nothing here applies a
//! change: each strategy is a reviewable *plan*, so the "recompile and reattach"
//! guardrail (observable, testable, reversible, human-approved) is preserved. Neural
//! inference stays a NON-GOAL — the classification and the plan are deterministic
//! functions of the traces.
use Write as _;
use OnceLock;
use crate;
/// The workspace path the planner writes the generated repair-strategies document to,
/// and the committed byte-for-byte artifact under `data/meta/`.
pub const REPAIR_STRATEGY_PATH: &str = "repair-strategies.lino";
/// The three canonical strategies (one per repair target), computed once per process.
///
/// Classifying them scans real failure traces and composes a grounded plan for each;
/// the recipe touches them several times per run (planner write step, verify step,
/// final answer) and a server may serve them repeatedly, so memoising keeps the loop
/// responsive without changing its deterministic result.
/// A *differently worded* request for the general repair-classification recipe.
///
/// The router recognises the intent from the words, not a hardcoded string.
/// Deliberately avoids the self-healing keywords ("self-heal", "repair case", "repair
/// loop", and any pairing of "failure" with "heal"/"learn a"), the self-AST keywords
/// ("cst/ast"), the ledger keywords ("promote", "ledger"), the explain keywords
/// ("how … works"), and the change-request keywords ("change Formal AI", a
/// capability/feature/support change) so the recipes never collide: this recipe is the
/// *general classifier* that decides which part to repair for every failure class.
pub const REPAIR_STRATEGY_TASK: &str =
"Classify a failure and decide which part to repair: given a failure trace the \
system could not answer, determine whether the repair is a solver method, a data \
record, or a test change, then compose the grounded, human-gated repair strategy \
for it — for every class of failure, not just one.";
/// Keywords that mark a user turn as the general repair-classification recipe.
///
/// Deliberately narrow: every keyword pins the "classify the failure, decide which part
/// to repair" intent, and none overlaps the other recipes' keywords (in particular the
/// self-healing recipe owns "repair case"/"repair loop", which are absent here).
const REPAIR_STRATEGY_KEYWORDS: = ;
/// Whether `prompt` asks the general repair-classification recipe (issue #558's
/// `R558-02`).
/// Render the repair-strategies document (Links Notation) for the three canonical
/// strategies, one per target class. Deterministic and ends with exactly one trailing
/// newline.
///
/// The output is what the Agent CLI writes to [`REPAIR_STRATEGY_PATH`] and what
/// `data/meta/repair-strategies.lino` is committed as, asserted byte-for-byte in the
/// issue-#558 tests. The document depends only on the self-contained canonical traces,
/// so committing it does not couple it to unrelated source edits.
/// The canonical strategies backing the recipe. Exposed so tests can assert the
/// classifier covers every target class without rebuilding them.
/// The self-contained final answer: a natural-language summary plus the generated
/// repair-strategies document inline.