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
//! 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 root has no parent inbox,
//! so the deposit is a structural no-op there
//! ([`crate::prompt::inbox::deposit_child_result`]). 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 in the parent's inbox — a driver at the **parent**
//! ([`revive_parent`]). 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 parent would hand it a stop to undo one level
//! up); `budget-exhausted` never does (an epitaph-spam cycle against a
//! hard ceiling — one the parent shares, since the ceiling is derived
//! over the whole tree, §6).
//!
//! **Two launches, one sequence.** §2.11's terminal sequence — deposit
//! into the parent's inbox → release own lock → spawn a driver at own
//! agent → exit — names only the self-directed launch, because the
//! parent-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
//! `lernie message` obeys (Writer/driver totality — a writer deposits,
//! probes, and launches). The terminal deposit is that writer act with
//! the parent as recipient, 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 parent that immediately messages or
//! stops its child meets no lingering lease.
//!
//! [`deposit_result`]: crate::prompt::inbox::deposit_result
use budget;
use ;
use ;
use deposit_terminal;
use crate;
use Path;
/// The whole §2.11 terminal tail — one sequence for both drivers
/// ([`super::run_exchange`]'s tail and the `lernie 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 parent 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/lernie/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 parent the result deposit just landed in
/// ([`revive_parent`]), 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 `lernie
/// scan`) heals it.
/// Start a driver at the parent 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 parent's address is derived
/// from this agent's id ([`inbox::parent_of`], the id *is* the address),
/// so a parentless root skips it exactly as the deposit did.
///
/// This is the writer's post-deposit probe, unmodified and unduplicated:
/// [`inbox::probe_and_launch`] — the seam `lernie message` runs — so a
/// parent 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 `lernie advance`, whose warrant is decided under the
/// lock like any other driver's.