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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
//! The failure modes the contract names, and the process exit codes it assigns.
// llmlint: ignore-file[invalid_states_unrepresentable] the run and node a failure names
// are `String`s because `RunId`/`NodeId` newtypes are public items `docs/contract.md`
// does not name. The engine validates a node reference against the live graph before it
// reaches a failure, so a newtype here would restate that check rather than add one.
use PathBuf;
/// What can go wrong driving a run.
///
/// The variants are the failures `docs/contract.md` distinguishes, and they
/// carry the exit codes it assigns: [`EXIT_QUEUED`], [`EXIT_REFUSED`], and
/// [`EXIT_NOTHING_DRIVING`].
/// The result of anything in this crate that can fail.
pub type Result<T> = Result;
// llmlint: ignore-block[cli_output_contract] the two outcomes are told apart on stdout, by
// the receipt's `state`; this status answers acceptance. Divergence 67.
/// The run settled, or the reply's every edit was **accepted** — applied, or
/// durable on the run's command queue and waiting for a driver.
///
/// One status for both, because both are acceptances and the receipt is where
/// which one it was is read. See divergence 67.
pub const EXIT_SUCCESS: i32 = 0;
// llmlint: ignore-end[cli_output_contract]
/// A run's own "unfinished": a graph that is waiting or has a failed node has
/// not settled.
///
/// Neither an error nor completion. It is **not** what `reply` answers for
/// accepted-but-unreconciled edits any more: a queued envelope is accepted, and
/// a caller reading a status has to be able to tell one from a refusal to
/// correct. See divergence 67.
pub const EXIT_QUEUED: i32 = 1;
/// The reply was malformed, or an edit was refused.
pub const EXIT_REFUSED: i32 = 2;
/// Nothing is driving the run — the state to intervene in.
pub const EXIT_NOTHING_DRIVING: i32 = 3;
/// A blocking surface is waiting to be answered.
///
/// `watch`'s own, and the one of its four returns that has no code above it
/// already: `0` is the run settling, [`EXIT_NOTHING_DRIVING`] is the state
/// `adopt` is the way back from, and [`EXIT_QUEUED`] and [`EXIT_REFUSED`] are
/// each spoken for by a different question. A caller branches on this rather
/// than on prose — which is the failure the verb exists to end, a watch that
/// matched a word and called a healthy run dead.
pub const EXIT_SURFACE_WAITING: i32 = 4;
/// A bounded wait elapsed with the run still live.
///
/// Not a failure and not completion: the run is being driven and had not
/// finished when the wait ran out, so the caller resumes from the cursor the
/// watch printed.
pub const EXIT_WATCH_ELAPSED: i32 = 5;
/// At least one run this session owns has nothing watching it.
///
/// `unwatched`'s own answer, and a status rather than the refused
/// [`EXIT_REFUSED`] because a caller has to tell "runs are unwatched" from "this
/// verb could not answer": a hook that read a refusal as an answer would go quiet
/// on exactly the runs it was installed to find, and one that read the answer as a
/// refusal would report every turn as broken.
///
/// **The same number [`EXIT_NODE_SETTLED`] carries, on a different verb**, because
/// every code above [`EXIT_NOTHING_DRIVING`] belongs to one verb's protocol and a
/// caller always knows which verb it ran. Divergence entry 68 is where that is
/// argued and ruled on; it is named on both constants so a reader meets it at
/// whichever one they open.
// llmlint: ignore-block[cli_output_contract] the rule reads these as one global code space, in
// which two outcomes sharing `6` are indistinguishable. They are not one space: every code
// above `3` belongs to a single verb's protocol, `watch` alone spells `4`, `5` and `6`, and
// `watch` already *reuses* `3` from the shared set by the contract owner's own ruling in
// divergence entry 58. A caller runs one verb and branches on its returns, so no caller can
// meet both meanings; giving this verb a seventh number instead would be inventing surface
// the proposal in entry 68 does not carry. Raise it there, not here.
pub const EXIT_RUNS_UNWATCHED: i32 = 6;
// llmlint: ignore-end[cli_output_contract]
/// A node the wait was told to return on settled.
///
/// `watch`'s fifth return, and a status of its own for the same reason the two
/// above it are: a caller that asked to be woken when a node settles has to be
/// able to tell that from the run settling, from a surface waiting and from the
/// wait running out — and the record beside it names *which* node, so neither
/// answer is read out of prose.
///
/// **Shared with [`EXIT_RUNS_UNWATCHED`]**, which is `unwatched`'s answer that an
/// owned run has nothing watching it, on the reading above: a code above
/// [`EXIT_NOTHING_DRIVING`] belongs to one verb's protocol. Divergence entries 58
/// and 68 argue it.
pub const EXIT_NODE_SETTLED: i32 = 6;