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
//! TR-6 (T16) — superseded-output eviction: deterministic same-tool/
//! canonicalized-args supersession behind [`super::ReductionKind::Superseded`].
//!
//! **The rule.** Two (or more) tool results in the same slice were produced
//! by the SAME tool, called with the SAME canonicalized arguments (a re-run
//! of `cargo test`, a re-run of `git diff`, a re-listed directory). Only the
//! chronologically LATEST such result is ever worth keeping in full — an
//! older run of the identical command is superseded information, exactly the
//! way an old failing `cargo test` run becomes noise once the fixed re-run
//! lands. Unlike [`super::ReductionKind::DuplicateOutput`] (TR-2), the
//! superseded and superseding contents are NOT required to be byte-identical
//! — that is the whole point (a stale failing run vs. a later passing one).
//!
//! **v1 canonicalization ([`canonical_key`]).** Deliberately narrow: EXACT
//! match after only the most trivial normalization (trim leading/trailing
//! whitespace; for a tool with a configured "command" field —
//! [`ReductionPolicy::supersede_command_fields`] — collapse internal
//! whitespace RUNS in that one field to a single space). No semantic
//! equivalence guessing of any kind: `ls -la` and `ls -al` list the same
//! information to a human but are DIFFERENT commands here, and stay that way
//! — TR-6.md's frozen spec is explicit that a false supersession (silently
//! hiding a result that was NOT actually superseded) is worse than a missed
//! one (an old result that could have been evicted stays visible instead).
//! Every detection here is a pure function of `(tool_name, arguments)` — no
//! disk I/O, no ambient state — so re-running it against the same transcript
//! always yields the same key for the same call (SPEC.md TR-6 dev/05:
//! determinism).
//!
//! [`ReductionPolicy::supersede_command_fields`]: super::ReductionPolicy::supersede_command_fields
use ;
use ;
/// One non-read tool-result occurrence in a slice, paired back to the
/// assistant `tool_calls` entry that produced it (by `tool_call_id`, searched
/// BACKWARD from the result — the same direction [`super::detect_reads`]
/// searches in, for the same reason: the result is what [`super::project_messages`]
/// actually reduces, and the call is only consulted to learn what produced
/// it). `key` is this occurrence's [`canonical_key`] — two occurrences with
/// the same key are supersession candidates against each other.
pub
/// Find every candidate tool-result occurrence in `msgs`: a `Role::Tool`
/// result (excluding `read_indices` — the read-family passes, A8/TR-3, own
/// that address space exclusively, with strictly richer path-aware
/// redundancy handling than a flat "same tool+args" key could express, the
/// same carve-out [`super::project_messages`]'s TR-2 pass makes) whose
/// `tool_call_id` resolves to a paired assistant `tool_calls` entry. A result
/// with no resolvable pairing (e.g. an imported transcript that never
/// recorded the originating call) is never a candidate — there is no
/// `(tool, args)` identity to key it by.
pub
/// v1 supersession canonicalization key for one `(tool_name, arguments)` call
/// — see the module doc comment for the exact-match-after-trivial-
/// normalization contract this upholds. `arguments` is the tool call's raw
/// serialized JSON argument string (`FunctionCall::arguments`).
///
/// When `tool_name` has a configured command-bearing field
/// (`command_fields`, e.g. `bash`/`shell`/`exec_command` -> `"command"`) and
/// `arguments` parses as a JSON object with that field present as a string,
/// the key is built from the WHOLE-STRING-trimmed, internal-whitespace-
/// collapsed value of just that field — so `"cargo test\n"` and
/// `"cargo test"` key identically, but `"cargo test"` and `"cargo test --lib"`
/// never do (no token-level or flag-level equivalence reasoning). For every
/// other tool (no configured field, or the field is absent/non-string/the
/// arguments don't parse as an object), the key falls back to the entire
/// `arguments` string, trimmed only — never whitespace-collapsed internally,
/// since a multi-argument JSON object's internal whitespace is not safely
/// collapsible the way one shell command line's is.
pub
/// Collapse every run of Unicode whitespace in `s` to a single ASCII space —
/// QUOTE-AWARE: whitespace runs are only ever collapsed OUTSIDE a `"..."` or
/// `'...'` shell literal. Whitespace (and everything else) INSIDE a quoted
/// literal is preserved byte-for-byte, because it is part of the literal
/// VALUE the shell would pass to the command, not inter-token separator
/// whitespace — collapsing it would make `echo "a b"` and `echo "a b"`
/// (two textually DIFFERENT commands whose quoted arguments differ) key
/// identically, a false supersession (TR-6.md: worse than a missed one).
///
/// Quote handling follows POSIX shell lexing close enough for this narrow
/// purpose:
/// - a `'...'` (single-quoted) literal has NO escaping at all — a `\` inside
/// it is a literal backslash, and only a following `'` closes it;
/// - OUTSIDE single-quotes (i.e. both unquoted and inside `"..."`), a `\`
/// escapes the very next character: the pair is copied through verbatim
/// and, critically, an escaped quote character (`\"`) does NOT toggle
/// quote state — `"a\"b"` is one continuous double-quoted literal, not two
/// adjacent ones.
///
/// CONSERVATIVE FALLBACK: if `s` ends still inside an open quote (unbalanced
/// — e.g. a truncated/malformed capture), the lex is ambiguous about which
/// bytes are "inside a literal" at all, so this returns `s` completely
/// UNCHANGED (trim was already applied by the caller before this is called;
/// no internal collapsing is attempted) rather than guess — an ambiguous
/// command must never risk being falsely equated with another.
///
/// Pure, allocation-only — never touches anything outside `s` itself.
/// The built-in default for [`ReductionPolicy::supersede_command_fields`]:
/// the same command-bearing tool identities T30/TR-4's
/// [`super::normalize::NORMALIZE_TOOLS`] normalizes (`bash`, `shell`,
/// `exec_command`), each keyed to their shared `"command"` argument field —
/// the one argument whose value is a literal shell command line, the case
/// TR-6.md's frozen spec calls out by name (`git diff` vs `git diff --stat`,
/// `ls a/` vs `ls b/`).
///
/// [`ReductionPolicy::supersede_command_fields`]: super::ReductionPolicy::supersede_command_fields
pub