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
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
//! Acceptance test closing the same coverage-gap class in TR-10
//! (`.volter/tracker/markdown/TR-10.md`) that `tr2_dedup_guarantor.rs`/
//! `tr3_diff_guarantor.rs`/`tr4_normalize_guarantor.rs` already closed for
//! `DuplicateOutput`/`FileReadDiffed`/`OutputNormalized`: every existing
//! `ToolInputElided` test (`tool_input_elision.rs`) mints AND inverts against
//! the SAME in-memory `Session`/message vector (`project_messages` called
//! directly on a hand-built slice). None of them drive `ToolInputElided`
//! through the path the control guarantor actually re-runs: live `Agent` ->
//! recorder(disk sidecar) -> **reload from disk** -> offline
//! `verify_log`/`invert`.
//!
//! THE GAP: TR-12's regression (`tr12_cap_supersession.rs`) proved that a
//! hash minted from an in-memory copy of `history` can silently diverge from
//! what a reloaded sidecar recomputes, once `cap_tool_output` mutates the
//! bytes behind the mint site. `ToolInputElided`'s mint site (`reduce.rs`'s
//! TR-10 pass, run from `Agent::build_request_messages` over
//! `self.history[1..]`) sits in exactly the same position in the pipeline —
//! nothing in the existing TR-10 suite would have caught an equivalent
//! divergence, because none of those tests ever touch a recorder, a sidecar
//! file, or a disk reload. This test fills that gap, reusing the exact
//! harness idiom `tr2_dedup_guarantor.rs`/`tr4_normalize_guarantor.rs`
//! established (`Agent::with_parts` + a scripted `Provider`, a REAL builtin
//! tool, `SidecarWriter`/`SessionStore`, offline reload via
//! `Session::from_sidecar_str`, `verify_log` + `invert`) — with the actual
//! built-in `write_file` tool (the one TR-10's default
//! `tool_input_elidable_fields` names) so the call genuinely executes,
//! genuinely persists to disk, and genuinely succeeds — never a
//! hand-built/synthetic success marker.
//!
//! dev/01 (guarantor-path regression): a live agent runs a real `write_file`
//! tool call with a 20,000-byte `content` argument. The call executes
//! successfully (the file really lands on disk), minting a `ToolInputElided`
//! reduction over the assistant's `tool_calls` arguments. The sidecar and
//! reduction log are persisted and then reloaded from disk via
//! `SessionStore` (the exact primitive `cli/main.rs`'s
//! `show-reductions`/`convert`/`inspect` use) — never the live
//! `Agent`/in-memory `Session`. `verify_log` and `invert` both run OFFLINE
//! against that reloaded state and must pass clean, with `invert` restoring
//! the exact original `write_file` arguments byte-exact — never the elided
//! stub.
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use async_trait::async_trait;
use supercode_harness::reduce::{
invert, project_messages, verify_log, ReductionKind, ReductionPolicy,
};
use supercode_harness::session::Session;
use supercode_harness::sidecar::SidecarWriter;
use supercode_harness::store::SessionStore;
use supercode_harness::tools::WriteFileTool;
use supercode_harness::{
Agent, ChatMessage, ChatRequest, Config, FunctionCall, Provider, Role, ToolCall, Usage,
};
fn temp_dir(tag: &str) -> PathBuf {
static N: AtomicUsize = AtomicUsize::new(0);
let dir = std::env::temp_dir().join(format!(
"supercode-tr10-guarantor-{tag}-{}-{}",
std::process::id(),
N.fetch_add(1, Ordering::SeqCst)
));
std::fs::create_dir_all(&dir).unwrap();
dir
}
/// A deterministic all-ASCII filler string of exactly `len` bytes.
fn filler(len: usize) -> String {
(0..len).map(|i| (b'a' + (i % 26) as u8) as char).collect()
}
fn write_call_msg(id: &str, path: &str, content: &str) -> ChatMessage {
ChatMessage {
role: Role::Assistant,
content: None,
content_parts: None,
tool_calls: Some(vec![ToolCall {
id: id.to_string(),
kind: "function".to_string(),
function: FunctionCall {
name: "write_file".to_string(),
arguments: serde_json::json!({ "path": path, "content": content }).to_string(),
},
}]),
tool_call_id: None,
name: None,
metadata: Default::default(),
}
}
/// One `write_file` tool call, then a plain-text reply ends the turn (mirrors
/// `tr4_normalize_guarantor.rs`'s `BashThenPlain` shape).
struct WriteThenPlain {
calls: AtomicUsize,
path: String,
content: String,
}
#[async_trait]
impl Provider for WriteThenPlain {
async fn complete(
&self,
_req: &ChatRequest,
_on_delta: &(dyn for<'a> Fn(&'a str) + Send + Sync),
) -> supercode_harness::Result<(ChatMessage, Usage)> {
let n = self.calls.fetch_add(1, Ordering::SeqCst);
match n {
0 => Ok((
write_call_msg("w0", &self.path, &self.content),
Usage::default(),
)),
_ => Ok((
ChatMessage::assistant(format!("done {n}")),
Usage::default(),
)),
}
}
}
/// dev/01 (guarantor-path regression, TR-10 coverage-gap closure): a live
/// agent run with a recorder + `ReductionPolicy` both active produces a
/// `ToolInputElided` reduction from a REAL, successfully-executed
/// `write_file` call; `verify_log` AND `invert` then run OFFLINE against the
/// sidecar and reduction log reloaded from disk (never the live
/// `Agent`/in-memory `Session`). Both must pass clean, and `invert` must
/// restore the exact original `write_file` arguments byte-exact — the large
/// `content` field included.
#[tokio::test]
async fn tool_input_elided_survives_live_agent_disk_reload_offline_verify_and_invert() {
let dir = temp_dir("dev01");
let store_dir = dir.join("store");
let store = SessionStore::open(&store_dir).unwrap();
let name = "tr10-dev01";
let sidecar_path = store.sidecar_path(name);
// 20,000 bytes: comfortably above the default 8,192-byte
// `tool_input_trigger_bytes`, so this test's mint is unambiguously
// TR-10's own pass.
let big = filler(20_000);
let rel_path = "reports/out.txt";
let config = Config::builder().cwd(dir.clone()).build();
let mut reg = supercode_harness::tools::ToolRegistry::new();
reg.register(WriteFileTool);
let mut agent = Agent::with_parts(
config,
Box::new(WriteThenPlain {
calls: AtomicUsize::new(0),
path: rel_path.to_string(),
content: big.clone(),
}),
reg,
);
let empty_session = Session::from_claude_code_str("").unwrap();
let writer = SidecarWriter::create(&sidecar_path, &empty_session).unwrap();
agent.set_recorder(writer);
let policy = ReductionPolicy::default();
agent.set_reduction_policy(policy.clone());
let reply = agent.send("please write the report").await.unwrap();
assert!(reply.starts_with("done"), "unexpected reply: {reply}");
// The call really executed and really landed on disk — a genuinely
// successful write, not a hand-built success marker.
let written_path = dir.join(rel_path);
assert_eq!(
std::fs::read_to_string(&written_path).unwrap(),
big,
"the real write_file tool must have actually written the file"
);
let log_live = agent.reduction_log().clone();
let elided: Vec<_> = log_live
.reductions
.iter()
.filter(|r| matches!(r.kind, ReductionKind::ToolInputElided { .. }))
.collect();
assert_eq!(
elided.len(),
1,
"the large successful write_file call must mint exactly one \
ToolInputElided reduction: {:?}",
log_live.reductions
);
let elided_idx = elided[0].ptr.addr.index;
let (original_bytes, call_id, field) = match &elided[0].kind {
ReductionKind::ToolInputElided {
original_bytes,
call_id,
field,
..
} => (*original_bytes, call_id.clone(), field.clone()),
_ => unreachable!(),
};
assert_eq!(original_bytes, big.len());
assert_eq!(call_id, "w0");
assert_eq!(field, "content");
// Never claimed by any other pass this run.
assert_eq!(
log_live
.reductions
.iter()
.filter(|r| r.ptr.addr.index == elided_idx)
.count(),
1,
"the elided call's message must carry exactly one reduction, not double-claimed"
);
// Persist the reduction log the way the CLI does (`sessions
// show-reductions`/`convert`/`inspect` all call `store.save_reduction_log`
// via the resume/chat path).
store.save_reduction_log(name, &log_live).unwrap();
// --- OFFLINE from here: fresh reads from disk, no live Agent/Session ---
let sidecar_jsonl = store
.load_sidecar(name)
.unwrap()
.expect("sidecar must exist on disk");
let sidecar = Session::from_sidecar_str(&sidecar_jsonl).unwrap();
let log_reloaded = store
.load_reduction_log(name)
.unwrap()
.expect("reduction log must exist on disk");
// Confirm the reloaded-from-disk log still carries the ToolInputElided
// reduction before verifying/inverting against it.
assert!(
log_reloaded
.reductions
.iter()
.any(|r| matches!(r.kind, ReductionKind::ToolInputElided { .. })),
"the reloaded-from-disk log must still carry the ToolInputElided reduction: {:?}",
log_reloaded.reductions
);
// The sidecar itself must hold the FULL original tool_call arguments at
// this index — A3's "sidecar keeps everything" contract, independent of
// whatever the projected view showed.
let sidecar_args = sidecar.messages[elided_idx].tool_calls()[0]
.function
.arguments
.clone();
let sidecar_parsed: serde_json::Value = serde_json::from_str(&sidecar_args).unwrap();
assert_eq!(
sidecar_parsed.get("content").unwrap().as_str().unwrap(),
big,
"the sidecar must retain the FULL original write_file content, never the elided stub"
);
// The exact primitive `cli/main.rs`'s `show-reductions`/`convert`/
// `inspect` all call before doing anything else with a reduced session.
verify_log(&log_reloaded, &sidecar)
.expect("verify_log must pass clean against the reloaded-from-disk sidecar");
let (final_view, reprojected_log) = project_messages(&sidecar.messages, &policy, &log_reloaded);
assert_eq!(
reprojected_log, log_reloaded,
"re-projecting from the reloaded sidecar with its own log must not invent new reductions"
);
// The reduced VIEW must still show the stub in the tool_call arguments,
// not the full content.
let view_args = final_view[elided_idx].tool_calls()[0]
.function
.arguments
.clone();
let view_parsed: serde_json::Value = serde_json::from_str(&view_args).unwrap();
assert!(
view_parsed
.get("content")
.unwrap()
.as_str()
.unwrap()
.contains(supercode_harness::reduce::REDUCTION_SENTINEL),
"the reprojected view must still show the elided stub, not the full content"
);
let inverted = invert(&final_view, &log_reloaded, &sidecar)
.expect("invert must pass clean against the reloaded-from-disk sidecar");
assert_eq!(inverted.len(), sidecar.messages.len());
// Byte-exact restore of the original write_file arguments — content
// included — from the disk-reloaded sidecar.
let inverted_args = inverted[elided_idx].tool_calls()[0]
.function
.arguments
.clone();
assert_eq!(
inverted_args, sidecar_args,
"invert must restore the exact original write_file arguments byte-exact from disk"
);
let inverted_parsed: serde_json::Value = serde_json::from_str(&inverted_args).unwrap();
assert_eq!(
inverted_parsed.get("content").unwrap().as_str().unwrap(),
big,
"invert must restore the full original content, not the elided stub"
);
std::fs::remove_dir_all(&dir).ok();
}