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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
//! The nomination gate: which branch-relative paths a compaction pass
//! may **not** shed (ARCH §2.7).
//!
//! **What is not the branch's history is not a pass's to shed** (§2.7,
//! §2.8; bl-898f, bl-541b, bl-c7bb), and
//! [`not_compaction_eligible`] is the one predicate saying which paths
//! those are. Three classes are in it.
//!
//! The **dispatch entry** is the goal in transcript form. A goal has two
//! projections written at one dispatch and neither ever rewritten — the
//! pinned `goal.md` (§2.8) and the entry the same text was deposited as
//! through the front door (§2.11: a root's opening user message, a
//! child's dispatch message). The compactor is shown one of them — its
//! own goal quotes the dispatching branch's `goal.md` verbatim (§2.7) —
//! while the other sits in the transcript it is told to prune, so that
//! entry is the one that reads as *pure duplication* to a model
//! nominating superseded files. It was nominated and deleted in
//! practice, and what it deleted was the operator's only copy of the
//! prompt the conversation exists to serve.
//!
//! The **dispatch-written head** is the second class, and strictly
//! worse when it fires: the system slot's files — `goal.md`, `soul.md`
//! and `name` ([`crate::prompt::dispatch::step_commit::SYSTEM_SLOT_FILES`],
//! §5.2 structural wire homes) — and the lineage's `facts.md`
//! ([`crate::facts`], §5.5), cut into the tree at the same dispatch
//! commit and pinned at the head of every call after it. A compactor
//! writes its own at its dispatch commit, so a nomination of one after
//! that is a deletion inside the `dispatch..tip` range the landing
//! classifies as the compactor's product (`compactor::land`): it lands
//! as a `git rm` against the *dispatching* branch's tree, which then
//! keeps stepping with no goal, no soul, no identity line or no durable
//! memory. One class and not two: a dispatch-written fact is not the
//! branch's history to shed.
//!
//! **This pass's own product** is the third, and the one with the
//! largest blast radius (bl-c7bb). A live compactor accepted
//! `mark_for_deletion` of the `summary/001.md` it had written seconds
//! earlier through the other half of this same pair; the landing admits
//! the summary and the deletions and nothing else (§2.6), so a landing
//! carrying a `git rm` of its own summary carries away the entire span
//! it was dispatched to preserve and leaves a base holding nothing of
//! it. A **blanket** `summary/**` refusal would be wrong — superseding
//! an *earlier* pass's summary is the shipped soul's own instruction
//! (`template/souls/compactor.md`) and the only thing that keeps the
//! chain from growing without bound — so the class is *this run's*
//! output, not the directory. It is read from the same place the landing
//! reads the compaction product from ([`super::land::base`]): what
//! changed after the compactor's **own dispatch commit** is the pass's,
//! and everything at or before it is the inherited branch. One
//! definition of "the product", now read by the landing that carries it
//! and by the door that refuses to shed it.
//!
//! **The landing's own product needs no fourth class.** Since bl-e655 a
//! landing writes an **extract** beside the summary
//! (`summary/NNN.refs.md`, [`super::land::extract`]), and ARCH §2.7 puts
//! *this pass's* extract in the not-eligible class exactly as this pass's
//! summary. It is there by the same predicate and by construction: the
//! extract is derived and staged by the landing, into the *dispatching*
//! branch's base commit, so it never exists on the compactor's branch for
//! the pass to nominate. An **earlier** pass's extract does exist in the
//! inherited tree, at or before this compactor's dispatch commit, and is
//! nominable — the same distinction its summary draws, for the same
//! reason: superseding it is the compaction.
//!
//! All three are read against the **removal set** — every path
//! `git rm -r` would take, not the string nominated (bl-7234) — so an
//! ancestor nomination cannot walk around a class its own member is in.
//! And all three are declined **at the nomination**, in-band, so the
//! compactor's summary is never premised on a deletion that did not
//! happen. Live-branch-wins is dropped at the landing instead, precisely
//! because *its* fact — a race with the live branch — is not knowable
//! when the compactor nominates (§2.6).
use Error;
use crateMESSAGES_DIR;
use crateGitRunner;
use Path;
/// Transcript counter of the **dispatch entry** — the entry every
/// branch's opening prompt lands as (module docs, §2.3, §2.11). The
/// counter is monotonic and never reused (`dispatch::transcript`), so
/// `001` names that entry for the life of the branch.
const DISPATCH_SEQ: u32 = 1;
/// What makes the branch-relative `path` un-eligible for compaction
/// (module docs), or `None` when nothing does. The returned phrase is
/// the noun the decline names it by, so the model is told which rule it
/// hit rather than being refused anonymously.
///
/// The first two classes are derived from the path alone — the dispatch
/// entry from the same `NNN-` prefix reading `dispatch::transcript`'s
/// counter uses, the system slot from the file names the composer pins —
/// and they hold for a `.md` delivery and a resumed conversation's
/// inherited first entry alike. The third cannot be: "whose output is
/// this file" is not in the name, and a blanket `summary/**` refusal
/// would forbid the supersede the chain depends on (module docs). It
/// reads the branch instead, at the one anchor the landing already
/// classifies the product by.
///
/// **The subject is the removal set, not the string** (bl-7234).
/// `mark_for_deletion` runs `git rm -r`, so a nomination of an ancestor
/// takes a not-eligible path with it while an exact-match predicate says
/// nothing: `.` sheds the system slot, `messages` sheds the dispatch
/// entry. So the two path-derived classes are read against the
/// nomination *and* against every path [`removes`] says the nomination
/// would remove, and the third is read with the nomination as a
/// pathspec, which git already resolves over the subtree. One shape for
/// all three, no ancestor/exact split: **a nomination is declined when
/// what it would remove holds a path this pass may not shed**, and the
/// decline names that path. Shedding `messages` wholesale is therefore
/// refused — the dispatch entry's reason (the operator's only copy of
/// the opening prompt, §2.7) does not weaken because the gesture was
/// coarser, and every other entry stays nominable one by one.
pub
/// The third class's phrase, shared by the nomination arm and the
/// removal-set arm below.
const OWN_PRODUCT: &str = "this compaction pass's own product — a file this compactor has written since \
its own dispatch commit, which is what the landing carries forward (ARCH §2.6), \
not history it may shed";
/// The decline's phrasing when the nomination is not itself the
/// not-eligible path but removes it. The model is told the member and
/// the rule, so it can re-nominate the siblings rather than guess which
/// file in the subtree it hit.
/// What the **dispatch wrote** — the two classes knowable from the path
/// alone, or `None` when the path is neither. Read once against the
/// nomination and once against every path the nomination removes.
/// Whether the branch-relative `rel` is the **dispatch entry** — the
/// `messages/001-…` the branch's opening prompt landed as (module docs).
/// One home for the fact, read twice: here, where a nomination of it is
/// declined, and at the landing, where the span's transcript entries are
/// swept out of the base and this one is the entry that stays
/// ([`super::super::land`], bl-2071).
pub
/// Every tracked path `git rm -r -- <rel>` would remove — the index
/// entries the nomination's pathspec matches, which for a file is that
/// file and for a directory is its whole subtree.
///
/// This is the **removal set**, and it is what the predicate judges: a
/// nomination is a gesture, and the invariant is about the files the
/// gesture takes away. `git ls-files` reads the index, which is the same
/// list `git rm` acts on, so the two can never disagree. An untracked or
/// nonexistent path answers with an empty set and falls through to the
/// nonexistent-path decline `git rm` raises itself.
/// Which path *this* compaction pass has written under `rel` — the
/// first addition or rewrite in the range after the compactor's own
/// dispatch commit, or `None` when there is none.
///
/// A **directory** nomination is covered by the same call and needs no
/// arm of its own: a git pathspec naming a directory matches its whole
/// subtree, so `-- summary` answers with `summary/002.md` exactly as
/// `-- summary/002.md` does. That is why the removal set above judges
/// only the two path-derived classes — this one already reads the
/// gesture, not the string.
///
/// That range is the landing's definition of the compaction product
/// ([`super::land::base`]: "a path *added under `summary/`* is the
/// `write_summary` product"), read here against the **index** rather
/// than a commit pair, which is exactly the set `git rm` could carry
/// away: a summary already committed by its tool step and one merely
/// staged both answer the same, and an untracked one answers `None`
/// because `git rm` refuses it anyway — the nonexistent-path decline
/// takes that case, and nothing is lost either way.
///
/// `--diff-filter=AM` excludes deletions on purpose: a path this pass
/// already staged for removal is not its product, and a re-nomination of
/// one should meet the nonexistent-path decline it has always met, not
/// this one.
///
/// No dispatch commit reachable — a tree that was never founded — is the
/// general path with empty inputs: nothing was added after a commit that
/// does not exist, so nothing is this pass's ([`crate::prompt::role::founding_sha`]
/// answers `None` the same way [`super::checkpoint::origin`] does).