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
//! Checkpoint trigger evaluation (ARCH §2.6, §2.7, §6).
//!
//! Compaction runs at **checkpoints** during a branch's execution. The
//! triggers are declared in the governing config's `workflow.yaml`
//! `compaction:` block (§6) — `every_n_commits`, `every_t_seconds`, or
//! the agent-elected `on_flush` — and are read **at the step boundary by
//! the executor**, which already holds the loaded workflow config (§6 hop
//! step 4). A branch with no configured trigger never compacts (§2.7).
//!
//! This module is the evaluation, kept **minimal and binding-shaped** so
//! it slots into the workflow-binding interpreter (§6) rather than
//! standing as a parallel path: [`due`] is a pure predicate over the
//! config and a [`CheckpointState`] the executor derives from disk, and
//! [`state`] is that derivation. When the interpreter evaluates the
//! `compaction:` block at a boundary and the `worker_flush` event, it
//! computes the same state and asks the same predicate; today's boundary
//! hook calls them directly.
//!
//! The **checkpoint commit `C`** is the branch tip at the boundary where
//! [`due`] fires — the commit the dispatched compactor forks off (§2.6).
//! "Since the last checkpoint" is derived from git, never stored
//! (`docs/PRINCIPLES.md` Single source of truth).
//!
//! # Three invariants on eligibility
//!
//! **The clock starts at the branch's own founding commit.** A branch is
//! forked off its parent's tip and inherits the parent's whole history
//! (§2.3 *Fork and inheritance*), so "commits on this branch" can never
//! mean "commits reachable from HEAD": a seconds-old child would read its
//! parent's hundred commits as its own and be instantly due. The one
//! commit that founds a branch is its **dispatch commit**, `dispatch:
//! <role> [<agent-id>]` for child and root alike, plus the pre-bl-946c
//! root spelling `step 001: dispatch [<agent-id>]`
//! ([`crate::prompt::dispatch::step_commit`]). One anchored
//! pattern matches both spellings exactly
//! ([`crate::prompt::role::founding_pattern`] — the single home of that
//! question), so the root is not a special case; matching the
//! `[<agent-id>]` tail alone would not do, because the executor's own
//! transcript commits end in it too and would answer as the founding
//! ([`crate::prompt::dispatch::transcript`], bl-89f7). A branch's
//! checkpoint reference is therefore the newest of {its dispatch commit,
//! its last compaction base}, and the root commit only when neither
//! exists ([`reference::origin`]).
//!
//! **A checkpoint child is never a checkpoint subject** — machinery is
//! never the subject of machinery (§2.7). A compactor *is* the
//! compaction, not a subject of one: compacting it would fork a compactor
//! off a compactor, whose own transcript is the compaction it was
//! dispatched to perform. Stated of the compactor alone, that recurred
//! one role later at the reviewer (bl-08b4), so it is stated at the class
//! instead: the excluded set is exactly the roles the harness mints at a
//! checkpoint, whose one home is [`crate::prompt::procedure`]. The role
//! is derived from the same founding commit
//! ([`crate::prompt::role::derive`] — the single authoritative home for
//! an agent's role), so the exclusion costs no new state.
//!
//! **A compaction already in flight is a checkpoint that has fired.**
//! The two above bound *which branches* may be compacted; this one
//! bounds *when* a branch that may be is due, and it is a case neither
//! of them reaches — a branch legitimately eligible, firing the same
//! checkpoint again because the answer to its last firing has not come
//! back. The whole argument, and the residual it leaves, is
//! [`inflight`]'s.
//!
//! Either of the first two alone stops the runaway cascade of bl-a9eb
//! (yog bl-ebbd); all three are stated because they are different facts.
pub
use Error;
use crate;
use craterole;
use crateGitRunner;
use Path;
pub use LastUsage;
// The clock's reference commit and its subject vocabulary live one level
// down ([`reference`]); the landing reads them through this path, so the
// split is invisible to every consumer.
pub use ;
/// Branch state a checkpoint trigger is evaluated against (§6), derived
/// from disk by [`state`]. Every field is a live derivation, never a
/// stored counter (`docs/PRINCIPLES.md` Single source of truth).
/// Whether a checkpoint is due this boundary (§2.6, §2.7) — the one home
/// of compaction eligibility. `None` config — no configured trigger —
/// never compacts (§2.7). Two facts about the branch answer ahead of the
/// config and under **every** trigger, the agent-elected flush included:
/// **a checkpoint child is never eligible** (module docs: machinery is
/// never the subject of machinery), and **a branch with a compaction in
/// flight is not due** (its checkpoint has already fired; a second pass
/// over the same span cannot land). Otherwise the trigger kind selects the
/// predicate; a `None`/`0` `n` (guarded out at config load, §6) is never
/// due, so a malformed config fails closed rather than compacting every
/// step.
///
/// **Fallible for one trigger only.** `window_percent` measures against
/// a number only the provider can state, so a branch whose last usage
/// carries no context window is *declined* here rather than answered
/// "not due" — the one outcome that would leave a configured trigger
/// silently dead ([`usage`], `docs/DESIGN_CONTEXT_ECONOMY.md` §5.1).
/// Every other trigger's answer is total, and the two suppressors above
/// answer ahead of all of them.
/// Derive [`CheckpointState`] for the agent `agent_id`, whose branch is
/// checked out at `worktree` (§6). `now_unix` is the current wall-clock in
/// Unix seconds, supplied by the caller so this stays a pure derivation
/// over its inputs (§6 binding-shaped); `flush_requested` is the
/// agent-elected input. The commit count and the checkpoint timestamp both
/// measure from [`origin`] — the branch's own founding commit or its last
/// compaction base, whichever is newer — so an inherited history is never
/// counted as this branch's own (module docs).
/// Count commits on `HEAD` after `last` (exclusive), or the whole branch
/// when `last` is `None`.
/// Committer Unix timestamp of the reference commit: the branch's
/// [`origin`] when one exists, else the branch's root commit — the point
/// elapsed time is measured from.