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
//! The **compaction product** (ARCH §2.6, §2.7): what one pass takes
//! out of the dispatching branch's context and what it leaves in its
//! place — classified entirely from git, never from a sidecar.
//!
//! Three things reach the base commit and nothing else does.
//!
//! - **Nominations.** A path *deleted* in `dispatch..tip` on the
//! compactor's branch is a `mark_for_deletion` call (the fork-time
//! prunes — the empty-grant `descriptions/**` derivation, the
//! unsettled-tool-step removal — all land *on* the dispatch commit and
//! are thereby excluded, structurally). This is where the compactor's
//! judgement lives: work products, and the earlier summary this pass
//! supersedes.
//! - **The summary.** A path *added under `summary/`* in the same range
//! is the `write_summary` product.
//! - **The span's transcript entries**, swept by the landing itself
//! ([`span_transcript`], bl-2071,
//! `docs/DESIGN_CONTEXT_ECONOMY.md` §5.5). Which entries a summary
//! replaces is not a judgement — it is the span, and the span is
//! derived from git ([`super::span`]). So a pass that wrote a summary
//! takes **every** `messages/**` path in the tree at the compaction
//! point out of the base, save two: the branch's dispatch entry
//! (`eligibility::is_dispatch_entry`, §2.7's first not-eligible class)
//! and a trailing **unsettled tool window**, which is one unit with
//! the results replaying on top of it ([`span_transcript`], bl-2d93).
//! A retained tail is already outside the sweep: `keep_recent` /
//! `keep_recent_tokens` move the compaction point back, and only the
//! point's tree is read here.
//!
//! Nothing else exists to a landing: the compactor's dialog, goal, and
//! soul are additions outside `summary/` and rewrites, which this module
//! never reads.
//!
//! **Why the sweep is the landing's and not the soul's** (bl-2071).
//! Measured: four landed compactions over 94 transcript commits
//! reclaimed *nothing*. The shipped soul told the model to supersede its
//! predecessor's summary and never named the entries the summary stood
//! for, so compaction became pure addition — a model dispatch per
//! checkpoint carrying the whole inherited transcript, and a prompt that
//! grew from 8k to 91k tokens across the four. Prose cannot carry an
//! invariant a landing can derive.
use Error;
use eligibility;
use ;
use Span;
use crate;
use crateGitRunner;
use Content;
use Path;
/// The compaction product: what the compactor's two tools committed after
/// its dispatch commit (module docs), plus the one product no model
/// authors — the **extract** the landing itself derives (docs/TAXONOMY.md
/// §3, [`extract`]) — and nothing else.
pub
/// Classify the compaction product from the compactor's branch (module
/// docs): deletions and `summary/**` additions in `dispatch..tip`, then
/// the extract derived from the first of those two.
pub
/// Paths of one `--diff-filter` class between two trees, optionally
/// limited to a pathspec. `--no-renames` keeps the classes exhaustive: an
/// add/delete pair must not collapse into an `R` that escapes both.
/// The span's transcript entries — every `messages/**` path in the tree
/// at the compaction point except the branch's dispatch entry (module
/// docs) and except a trailing **unsettled tool window** (below). Read
/// from the point, never the worktree: the live branch has kept
/// stepping past it, and the point's tree is what the base is cut from.
///
/// `ls-tree` rather than a diff against the span's lower bound: what the
/// summary replaces is everything in context at the point, and after the
/// previous landing those are the same set. Stating it as the tree's
/// contents rather than as a range makes the base's invariant one a test
/// can read off the base alone — its `messages/` holds the dispatch
/// entry and nothing else.
///
/// **The sweep stops at the last settled boundary** (bl-2d93). A
/// compaction point is an arbitrary commit — `HEAD~keep_recent` counts
/// commits, and the token tail lands on a model entry's own commit
/// (§5.2) — while a **tool window** spans several: the model output
/// entry commits, then each `tool_result` entry commits after its tool
/// returns (§2.5). So a point routinely falls *inside* a window, with
/// the call in the point's tree and its results in the live tail. Swept
/// flat, that takes the call out of the base and leaves the results
/// replaying on top of it — an orphan `tool_result`, which every
/// provider refuses (`pairing`: Anthropic as "tool_result without
/// tool_use", the OpenAI Responses API as "No tool call found for
/// function call output with call_id …") on *every* later prompt, so
/// the branch is wedged rather than merely mis-compacted. A tool call
/// and its result are one unit for every cut, so the trailing unsettled
/// window stays in the base: the same tail the fork prune deletes from
/// the compactor's own tree ([`crate::prompt::dispatch::step_commit`]),
/// which is also exactly what the compactor never read and never
/// summarized.
/// The canonical blocks of one transcript entry as of `point` — the
/// blob, never the worktree, for the same reason the listing is the
/// point's tree: the live branch has moved on. Read through the entry
/// shape's one home (§2.3, [`entry`]).