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
//! 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.
//!
//! [`exit_launch`] is the closing act of the §2.11 exit protocol: after
//! [`super::run_exchange`] releases the executor lock, a driver is
//! spawned at the exiting agent itself, fire-and-forget, and the result
//! deposit that just landed in the parent's inbox is followed by a
//! driver at the **parent** ([`revive_parent`]). Both launches are
//! decided by one epitaph value (§2.11 pin 2): a final response
//! launches; `stopped` never does (a relaunch 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 crateBudgets;
use Path;
/// 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).
pub
/// 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). 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.
pub
/// 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.