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
//! What the step loop does on its way out (ARCH §2.9, §2.11, §6).
//!
//! Three terminal shapes reach [`finish`], keyed by epitaph value (§2.6
//! — code branches on the value, never on shape): a `stopped` branch
//! (§2.9), an exhausted branch (§6), and the ordinary final-response
//! branch. Only a `stopped` branch has an outstanding deposit to make
//! here; the final response deposited in the loop and the exhausted
//! branch at the boundary check.
//!
//! **There is no terminal compaction** (§2.7: "There is no terminal
//! compaction stage anymore"). The v0.3 compactor dispatch that fired at
//! every final response is deleted: a child's result message carries its
//! own terminal response (§2.6), not a compactor product, and with
//! merge-back gone there is no merge payload to slim before returning.
//! Compaction now runs only at configured checkpoints during a branch's
//! life ([`crate::prompt::compactor::checkpoint`]).
//!
//! The stopped deposit is the §2.9 step-3 return performed *outside* the
//! signal handler ([`super::stop_signal`]) — the executor's SIGTERM
//! handler set a flag, the loop broke at a check point, and this is the
//! final deposit before the process exits. It reads the branch tip as the
//! terminal ref and deposits a `stopped`-epitaph result with no body (a
//! stopped agent has almost never finished speaking; [`deposit_result`]
//! renders a body-absent message either way). A stop is an **obituary**
//! (§2.6), so it is addressed to the dispatcher whoever prompted the
//! agent last, and a root has no dispatcher — the deposit is a
//! structural no-op there ([`super::result_deposit::recipient`]). The
//! stop *signature*
//! — the missing trailing `end` on the branch's own `response.json` —
//! lives on a different tree and is untouched by this deposit.
//!
//! [`conclude`] is the whole terminal tail, shared by both drivers. Its
//! lease release runs the §2.11 **release rule**
//! ([`super::driver::release_then_reprobe`]): a deposit that raced the
//! executor's last inbox read is launched for whatever the epitaph — it
//! is new work, and §2.9 makes messaging a stopped branch the resume
//! path. [`exit_launch`] then closes the §2.11 exit protocol with the
//! epitaph-*funded* launches: a driver spawned at the exiting agent
//! itself, fire-and-forget, and — following the result deposit that just
//! landed — a driver at the **recipient** ([`revive_recipient`]). Both
//! are decided by one epitaph value (§2.11 pin 2): a final response
//! launches; `stopped` never does (a relaunch funded by nothing new
//! would resurrect the branch the operator just killed, and waking the
//! dispatcher would hand it a stop to undo one level up);
//! `budget-exhausted` never does (an epitaph-spam cycle against a hard
//! ceiling — one the dispatcher shares, since the ceiling is derived
//! over the whole tree, §6).
//!
//! **Two launches, one sequence.** §2.11's terminal sequence — deposit
//! the result message → release own lock → spawn a driver at own agent →
//! exit — names only the self-directed launch, because the recipient-side
//! one is not the exit protocol's: it is the *deposit's*, the same "a
//! deposit into a quiescent agent starts a driver" rule `litany message`
//! obeys (Writer/driver totality — a writer deposits, probes, and
//! launches). The terminal deposit is that writer act, so it rides the
//! same seam ([`crate::prompt::inbox::probe_and_launch`], not a second
//! copy of the probe/spawn logic) and it runs *after* the exiting
//! executor releases its own lock: from then on the exiting process has
//! no authority over its own branch, and a revived recipient that
//! immediately messages or stops this agent meets no lingering lease.
//! Deposit and wake address the same [`super::result_deposit::recipient`]
//! — the one home of the addressing rule — so they cannot disagree about
//! who the message was for.
//!
//! [`deposit_result`]: crate::prompt::inbox::deposit_result
use budget;
use ;
use ;
use ;
use crate;
use cratenotice;
use Path;
/// The whole §2.11 terminal tail — one sequence for both drivers
/// ([`super::run_exchange`]'s tail and the `litany advance` hop), so the
/// two terminal lease releases are literally one code path: finish by
/// epitaph value ([`finish`]), evaluate the workflow's terminal-lifecycle
/// bindings (§6 — the epitaph names the event), release the lease through
/// the §2.11 **release rule** ([`super::driver::release_then_reprobe`] —
/// a deposit that raced this executor's last inbox read, `seen`, is
/// launched for *regardless of the epitaph*: it is new work, and §2.9
/// makes messaging a stopped branch the resume path), then the
/// epitaph-valued launches at own agent and at the recipient the result
/// deposit revived ([`exit_launch`]). After the release this process has
/// no authority: spawn and return are its only acts.
pub
/// The §6 budget check at a model-call boundary: tokens/wall/depth derived
/// live over the tree (no stored counter, PRINCIPLES SSOT). On exhaustion
/// it writes `refs/litany/budget-exhausted/<branch>`, deposits a
/// `budget-exhausted` result (the agent did not speak this step, so no
/// body), and returns `true` so the loop ceases — an ordinary terminal
/// state (§2.9). `false` continues the loop.
pub
/// Finish the exchange by epitaph value (§2.6). Only `stopped` has an
/// outstanding deposit here — its result is deposited on the way out
/// (§2.9 step 3). A final response deposited inside the loop and a
/// `budget-exhausted` branch at the boundary check, so both are no-ops.
/// No terminal compaction is dispatched (§2.7 — the stage is deleted).
/// The launches closing the §2.11 exit protocol, called *after* the
/// executor lock is released: a driver at this agent (the self-directed
/// launch) and a driver at the `recipient` the result deposit just landed
/// in ([`revive_recipient`]), both fire-and-forget and both by epitaph
/// value (§2.11 pin 2). These are the epitaph-*funded* launches — the
/// launch a racing deposit funds is the release rule's, made in
/// [`conclude`] before this runs, whatever the epitaph. Fire-and-forget
/// is literal — a launch failure is logged and swallowed, never
/// propagated: it falls into the accepted crash class (§2.11), where the
/// stranding is late, not lost, and the next touch (a reprompt, or a
/// hand-run `litany scan`) heals it.
/// Start a driver at the agent whose inbox this agent's result message
/// just landed in (§2.11 "a deposit into a quiescent agent starts a
/// driver" — revival-on-deposit, §2.5). The address is the *same*
/// [`result_deposit::recipient`] the deposit derived — the deposit and
/// the wake-up cannot disagree about who the message was for — so a
/// terminal that addressed nobody (an operator-prompted reply, a root's
/// obituary) skips it exactly as the deposit did.
///
/// This is the writer's post-deposit probe, unmodified and unduplicated:
/// [`inbox::probe_and_launch`] — the seam `litany message` runs — so a
/// recipient whose lease is held gets nothing (its own executor drains
/// at its next boundary, §2.11 Delivery) and a quiescent one gets exactly
/// one detached `litany advance`, whose warrant is decided under the
/// lock like any other driver's.