supercode-harness 0.4.5

The optional native Supercode agent and tool harness
Documentation
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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
//! Guarantees about the typed schema's coverage of the real corpus.
//!
//! The fixture-level tests run always; the corpus-level guarantee (no record
//! type anywhere in thousands of real logs falls into an `Unknown` typed
//! bucket) is opt-in via `SUPERCODE_CORPUS=1`.

use std::path::PathBuf;

use supercode_harness::audit::{audit_dir, Corpus};

#[test]
fn claude_frame_link_is_typed_and_audited_as_named_dropped_metadata() {
    let tmp = std::env::temp_dir().join(format!("sc-cov-claude-frame-link-{}", std::process::id()));
    std::fs::create_dir_all(&tmp).unwrap();
    let jsonl = r#"{"type":"frame-link","sessionId":"s","path":"artifact.html","frameUrl":"https://claude.ai/frame/example","timestamp":"2026-07-12T00:00:00Z"}
"#;
    std::fs::write(tmp.join("session.jsonl"), jsonl).unwrap();

    let report = audit_dir(&tmp, Corpus::ClaudeCode, None);
    assert_eq!(report.parse_errors, 0);
    let (coverage, tally) = report
        .records
        .get("frame-link")
        .expect("frame-link must be a named typed record, not <line>/frame-link");
    assert_eq!(*coverage, supercode_harness::audit::Coverage::Dropped);
    assert_eq!(tally.count, 1);
    for field in ["sessionId", "path", "frameUrl", "timestamp"] {
        assert_eq!(
            tally.unmodeled_fields.get(field),
            Some(&1),
            "the named Dropped residue must enumerate frame-link field `{field}`"
        );
    }
    assert!(!report.records.contains_key("<line>/frame-link"));

    std::fs::remove_dir_all(&tmp).ok();
}

/// Claude Code started emitting `file-history-delta` on 2026-07-25 — the
/// per-file half of the `/rewind` state whose whole-set sibling
/// `file-history-snapshot` was already typed. It landed in the anonymous
/// `Unknown` bucket, which is what `corpus_has_no_unknown_record_types`
/// caught on the real corpus (119 of 2455 transcripts, 2235 records). The
/// corpus-free half of that guard is here: a real record must be a NAMED
/// typed discriminant, not `<line>/…`.
#[test]
fn claude_file_history_delta_is_a_named_typed_record_not_unknown() {
    let tmp = std::env::temp_dir().join(format!("sc-cov-claude-fh-delta-{}", std::process::id()));
    std::fs::create_dir_all(&tmp).unwrap();
    // Verbatim shape from the corpus (paths/ids anonymized).
    let jsonl = r#"{"type":"file-history-delta","messageId":"ba614ba8-6fcc-4138-ac56-3d579ea35f05","snapshotMessageId":"16f1900f-97ad-462e-abe0-fba9d376acfd","trackingPath":"SERIES.md","backup":{"backupFileName":null,"version":1,"backupTime":"2026-07-31T18:59:13.747Z","realParentDir":"/tmp/work"},"timestamp":"2026-07-31T18:59:13.756Z"}
"#;
    std::fs::write(tmp.join("session.jsonl"), jsonl).unwrap();

    let report = audit_dir(&tmp, Corpus::ClaudeCode, None);
    assert_eq!(report.parse_errors, 0);
    assert!(
        !report.records.contains_key("<line>/file-history-delta"),
        "file-history-delta must be a named typed record, not an Unknown-bucket line"
    );
    let (_coverage, tally) = report
        .records
        .get("file-history-delta")
        .expect("file-history-delta must be a named typed record");
    assert_eq!(tally.count, 1);

    std::fs::remove_dir_all(&tmp).ok();
}

/// D5 (Fable-5 review, confirmed): the audit used to blanket-mark every
/// `image` content block `Coverage::Normalized`, regardless of whether the
/// loader could actually convert its `source`. A Files-API image reference
/// (`{"type":"image","source":{"type":"file","file_id":..}}`) is NOT
/// convertible (`claude_image_block_to_part` only handles `base64`/`url`),
/// so auditing it as `Normalized` overclaimed fidelity for content that's
/// actually dropped down to a bracketed marker. Fails against the pre-fix
/// `block_coverage`, which reported `Normalized` for every `image` tag
/// unconditionally.
#[test]
fn files_api_image_block_is_audited_as_dropped_not_normalized() {
    let tmp =
        std::env::temp_dir().join(format!("sc-cov-d5-files-api-image-{}", std::process::id()));
    std::fs::create_dir_all(&tmp).unwrap();
    let jsonl = r#"{"type":"user","message":{"role":"user","content":[{"type":"image","source":{"type":"file","file_id":"file_abc123"}}]},"sessionId":"s"}
"#;
    std::fs::write(tmp.join("session.jsonl"), jsonl).unwrap();

    let report = audit_dir(&tmp, Corpus::ClaudeCode, None);
    // N1: `blocks` is now keyed on `(tag, coverage)` — look the Dropped
    // bucket up directly rather than a single tag -> (Coverage, count) pair.
    let count = report
        .blocks
        .get(&(
            "image".to_string(),
            supercode_harness::audit::Coverage::Dropped,
        ))
        .copied()
        .expect("the `image` block discriminant must be tallied under Dropped");
    assert_eq!(count, 1);
    assert!(
        !report.blocks.contains_key(&(
            "image".to_string(),
            supercode_harness::audit::Coverage::Normalized
        )),
        "an unconvertible (Files-API) image source must be audited as Dropped, not Normalized"
    );
    std::fs::remove_dir_all(&tmp).ok();
}

/// A base64 image source (the one shape the loader DOES fully convert into
/// replayable `content_parts`) must still be audited `Normalized` — this
/// fix must not regress the common case.
#[test]
fn base64_image_block_is_still_audited_as_normalized() {
    let tmp = std::env::temp_dir().join(format!("sc-cov-d5-base64-image-{}", std::process::id()));
    std::fs::create_dir_all(&tmp).unwrap();
    let jsonl = r#"{"type":"user","message":{"role":"user","content":[{"type":"image","source":{"type":"base64","media_type":"image/png","data":"aGVsbG8="}}]},"sessionId":"s"}
"#;
    std::fs::write(tmp.join("session.jsonl"), jsonl).unwrap();

    let report = audit_dir(&tmp, Corpus::ClaudeCode, None);
    let count = report
        .blocks
        .get(&(
            "image".to_string(),
            supercode_harness::audit::Coverage::Normalized,
        ))
        .copied()
        .expect("the `image` block discriminant must be tallied under Normalized");
    assert_eq!(count, 1);
    assert!(!report.blocks.contains_key(&(
        "image".to_string(),
        supercode_harness::audit::Coverage::Dropped
    )));
    std::fs::remove_dir_all(&tmp).ok();
}

/// N3 (Fable-5 review, LOW, fixed alongside N1 since it's the same
/// `Image{source}` inspection): a well-typed-but-EMPTY base64 image source
/// (`{"type":"base64","data":""}`) must audit as Dropped, matching
/// `claude_image_block_to_part`'s own non-empty check (an empty `data` makes
/// the loader treat it as unconvertible — the `UNCONVERTIBLE_IMAGE_MARKER`
/// path, same as a Files-API reference) — not blanket `Normalized` just
/// because `source.type == "base64"`. Fails against the pre-N3
/// `block_coverage`, which matched on `type` alone.
#[test]
fn empty_base64_image_block_is_audited_as_dropped_not_normalized() {
    let tmp = std::env::temp_dir().join(format!(
        "sc-cov-n3-empty-base64-image-{}",
        std::process::id()
    ));
    std::fs::create_dir_all(&tmp).unwrap();
    let jsonl = r#"{"type":"user","message":{"role":"user","content":[{"type":"image","source":{"type":"base64","data":""}}]},"sessionId":"s"}
"#;
    std::fs::write(tmp.join("session.jsonl"), jsonl).unwrap();

    let report = audit_dir(&tmp, Corpus::ClaudeCode, None);
    let count = report
        .blocks
        .get(&(
            "image".to_string(),
            supercode_harness::audit::Coverage::Dropped,
        ))
        .copied()
        .expect("the `image` block discriminant must be tallied under Dropped");
    assert_eq!(count, 1);
    assert!(
        !report.blocks.contains_key(&(
            "image".to_string(),
            supercode_harness::audit::Coverage::Normalized
        )),
        "an empty base64 image source must be audited as Dropped, not Normalized, \
         matching the loader's own unconvertible treatment"
    );
    std::fs::remove_dir_all(&tmp).ok();
}

/// N1 (Fable-5 review, MEDIUM must-fix): before this fix, `Report::blocks`
/// kept exactly ONE `(Coverage, count)` per tag, overwritten last-write-wins
/// by whichever file's block was audited last. D5 made `image` coverage
/// PER-INSTANCE (a base64/url source is Normalized, a Files-API/`file`
/// source is Dropped) — so a corpus with ONE file of each kind used to
/// report `image -> Normalized, count 2` (or `Dropped, count 2`, depending
/// on file iteration order) instead of the true `Normalized:1, Dropped:1`.
/// That's the exact over-claim D5 was reopened to fix, resurfacing on a
/// multi-file real-corpus run. This audits a directory with BOTH a
/// Files-API image file and a base64 image file in one invocation and
/// requires the Dropped instance to be reported as Dropped — not collapsed
/// into Normalized (or vice versa). Fails against 27607794504d26ae, whose
/// `bump_block` did `entry.0 = cov` (plain overwrite) and whose `blocks`
/// map was keyed on tag alone, so this two-file corpus reports a single
/// `image` entry with only one (whichever-was-last) coverage.
#[test]
fn mixed_corpus_image_coverage_is_not_collapsed_by_last_write() {
    let tmp = std::env::temp_dir().join(format!(
        "sc-cov-n1-mixed-corpus-image-{}",
        std::process::id()
    ));
    std::fs::create_dir_all(&tmp).unwrap();
    // a.jsonl: Files-API image reference -> Dropped (unconvertible source).
    let a = r#"{"type":"user","message":{"role":"user","content":[{"type":"image","source":{"type":"file","file_id":"file_abc123"}}]},"sessionId":"s"}
"#;
    // b.jsonl: base64 image -> Normalized (fully convertible source).
    let b = r#"{"type":"user","message":{"role":"user","content":[{"type":"image","source":{"type":"base64","media_type":"image/png","data":"aGVsbG8="}}]},"sessionId":"s"}
"#;
    std::fs::write(tmp.join("a.jsonl"), a).unwrap();
    std::fs::write(tmp.join("b.jsonl"), b).unwrap();

    let report = audit_dir(&tmp, Corpus::ClaudeCode, None);

    let dropped = report
        .blocks
        .get(&(
            "image".to_string(),
            supercode_harness::audit::Coverage::Dropped,
        ))
        .copied()
        .unwrap_or(0);
    let normalized = report
        .blocks
        .get(&(
            "image".to_string(),
            supercode_harness::audit::Coverage::Normalized,
        ))
        .copied()
        .unwrap_or(0);

    assert_eq!(
        dropped, 1,
        "the Files-API image instance must be counted as Dropped, not collapsed away \
         (got dropped={dropped}, normalized={normalized})"
    );
    assert_eq!(
        normalized, 1,
        "the base64 image instance must independently be counted as Normalized \
         (got dropped={dropped}, normalized={normalized})"
    );

    std::fs::remove_dir_all(&tmp).ok();
}

/// PARITY-11 (skeptic-confirmed on a real session): an `image` block nested
/// INSIDE a `tool_result`'s own `content` array (the everyday "Read a PNG /
/// screenshot tool output" shape) used to be invisible to the audit
/// entirely — `block_coverage` blanket-labeled the enclosing `tool_result`
/// `Normalized` with no separate signal for the image it swallowed, so a
/// session whose `tool_result` held nothing but 4 real base64 screenshots
/// reported ZERO `image` blocks and a clean `tool_result: Normalized` line —
/// coverage claiming "retained" while `extract_tool_result` silently dropped
/// the bytes to a bare `[image]` marker. This proves a WELL-FORMED nested
/// image is now censused under its own `tool_result/image` discriminant as
/// `Normalized` — matching that it's genuinely captured into `content_parts`
/// (`claude_tool_result_nested_image_survives_load_and_round_trip`,
/// `session_fidelity.rs`). Fails against `parity/integrated-v3@e7b15fd`,
/// whose `audit_blocks` never looked inside a `ToolResult` block's `content`
/// at all.
#[test]
fn nested_tool_result_image_is_audited_as_normalized() {
    let tmp = std::env::temp_dir().join(format!(
        "sc-cov-parity11-nested-image-normalized-{}",
        std::process::id()
    ));
    std::fs::create_dir_all(&tmp).unwrap();
    let jsonl = r#"
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"t1","name":"Read","input":{}}]},"sessionId":"s"}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"t1","content":[{"type":"text","text":"screenshot"},{"type":"image","source":{"type":"base64","media_type":"image/png","data":"aGVsbG8="}}]}]},"sessionId":"s"}
"#;
    std::fs::write(tmp.join("session.jsonl"), jsonl).unwrap();

    let report = audit_dir(&tmp, Corpus::ClaudeCode, None);
    let normalized = report
        .blocks
        .get(&(
            "tool_result/image".to_string(),
            supercode_harness::audit::Coverage::Normalized,
        ))
        .copied()
        .expect("a well-formed nested image must be tallied under tool_result/image: Normalized");
    assert_eq!(normalized, 1);
    assert!(
        !report.blocks.contains_key(&(
            "tool_result/image".to_string(),
            supercode_harness::audit::Coverage::Dropped
        )),
        "a well-formed base64 nested image must not also show up as Dropped"
    );
    // The enclosing tool_result itself is still (honestly) Normalized for
    // its own text portion — the per-instance nested-image census is
    // ADDITIONAL signal, not a replacement for it.
    assert!(report.blocks.contains_key(&(
        "tool_result".to_string(),
        supercode_harness::audit::Coverage::Normalized
    )));
    std::fs::remove_dir_all(&tmp).ok();
}

/// The Dropped-side counterpart: a nested image whose source is genuinely
/// unconvertible (missing `media_type` — the same shape
/// `claude_image_block_to_part` already rejects for a TOP-LEVEL image) must
/// be censused as `tool_result/image: Dropped`, not silently folded into the
/// enclosing `tool_result`'s own `Normalized` label. This is the exact "audit
/// must stop lying" case: before this fix there was no way to tell, from the
/// audit alone, that this session's screenshot data never actually made it
/// into the canonical model.
#[test]
fn nested_tool_result_image_unconvertible_source_is_audited_as_dropped() {
    let tmp = std::env::temp_dir().join(format!(
        "sc-cov-parity11-nested-image-dropped-{}",
        std::process::id()
    ));
    std::fs::create_dir_all(&tmp).unwrap();
    let jsonl = r#"
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"t1","name":"Read","input":{}}]},"sessionId":"s"}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"t1","content":[{"type":"image","source":{"type":"base64","data":"x"}}]}]},"sessionId":"s"}
"#;
    std::fs::write(tmp.join("session.jsonl"), jsonl).unwrap();

    let report = audit_dir(&tmp, Corpus::ClaudeCode, None);
    let dropped = report
        .blocks
        .get(&(
            "tool_result/image".to_string(),
            supercode_harness::audit::Coverage::Dropped,
        ))
        .copied()
        .expect("an unconvertible nested image must be tallied under tool_result/image: Dropped");
    assert_eq!(dropped, 1);
    assert!(
        !report.blocks.contains_key(&(
            "tool_result/image".to_string(),
            supercode_harness::audit::Coverage::Normalized
        )),
        "an unconvertible nested image must not be miscounted as Normalized"
    );
    std::fs::remove_dir_all(&tmp).ok();
}

#[test]
fn fixtures_have_no_unknown_records() {
    // Each committed fixture must parse fully into modeled discriminants when
    // read with its OWN format's parser. (They live in one dir, so isolate each
    // into a temp dir keyed by format before auditing.)
    let fixtures = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures");
    for (file, corpus) in [
        ("claude_code_session.jsonl", Corpus::ClaudeCode),
        ("codex_session.jsonl", Corpus::Codex),
        // PARITY-9/PARITY-12/PARITY-13 (P009/P012/P013): a real-schema Codex
        // rollout carrying `event_msg/{patch_apply,mcp_tool_call}_end` (the
        // only ones of that family upstream `should_persist_event_msg`
        // actually persists — `_begin` variants and `exec_command_*` are
        // deliberately absent, see `codex_fidelity_cli.rs`'s module doc /
        // D1/D3), `turn_context` (x2, either side of a compaction boundary),
        // `compacted` (with the real `window_number`/`window_id`/
        // `first_window_id`/`previous_window_id` chain), `thread_rolled_back`,
        // `thread_goal_updated`, and `entered_review_mode`/`exited_review_mode`
        // — every discriminant these three items are about must still parse
        // into a modeled (not `<line>/...` Unknown) bucket.
        ("codex_session_eventmsg.jsonl", Corpus::Codex),
        ("codex_session_eventmsg_precompact.jsonl", Corpus::Codex),
    ] {
        let tmp = std::env::temp_dir().join(format!(
            "sc-cov-{}-{}",
            std::process::id(),
            file.replace('.', "_")
        ));
        std::fs::create_dir_all(&tmp).unwrap();
        std::fs::copy(fixtures.join(file), tmp.join(file)).unwrap();

        let report = audit_dir(&tmp, corpus, None);
        assert_eq!(report.parse_errors, 0, "{corpus:?}: typed parse errors");
        let unknown: Vec<_> = report
            .records
            .keys()
            .filter(|k| k.starts_with("<line>/"))
            .collect();
        assert!(
            unknown.is_empty(),
            "{corpus:?}: unknown record discriminants: {unknown:?}"
        );
        std::fs::remove_dir_all(&tmp).ok();
    }
}

/// P6 sub-discriminant guard: the top-level `Unknown` check can't see payload
/// types nested under `event_msg`/`response_item`, `system.subtype`, or
/// `attachment.type`. This walks the corpus and fails if a record key the audit
/// reports is **not** in our known set — so a newly-appearing sub-discriminant
/// surfaces instead of being silently dropped.
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn corpus_subdiscriminants_are_all_known() {
    if std::env::var("SUPERCODE_CORPUS").is_err() {
        panic!(
            "SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
             the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
        );
    }
    let home = std::env::var("HOME").unwrap();
    // Known record keys (prefix match) the audit may emit. A new sub-discriminant
    // produces a key not covered here, failing the test with its name.
    let known_prefixes = [
        // Codex
        "response_item/",
        "event_msg/",
        "session_meta",
        "turn_context",
        "compacted",
        // Claude
        "user",
        "assistant",
        "system/",
        "attachment",
        "file-history-snapshot",
        "file-history-delta",
        "ai-title",
        "permission-mode",
        "mode",
        "last-prompt",
        "queue-operation",
        "pr-link",
        "frame-link",
        "agent-name",
        "started",
        "result",
        "worktree-state",
    ];
    let known = |k: &str| known_prefixes.iter().any(|p| k.starts_with(p));

    for (sub, corpus) in [
        (".claude/projects", Corpus::ClaudeCode),
        (".codex/sessions", Corpus::Codex),
    ] {
        let dir = PathBuf::from(&home).join(sub);
        let report = audit_dir(&dir, corpus, Some(800));
        let unknown: Vec<&String> = report
            .records
            .keys()
            .filter(|k| !k.starts_with("<line>/") && !known(k))
            .collect();
        assert!(
            unknown.is_empty(),
            "{corpus:?}: unmodeled sub-discriminants (add handling or extend the known set): {unknown:?}"
        );
    }
}

#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn corpus_has_no_unknown_record_types() {
    if std::env::var("SUPERCODE_CORPUS").is_err() {
        panic!(
            "SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
             the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
        );
    }
    let home = std::env::var("HOME").unwrap();
    for (sub, corpus) in [
        (".claude/projects", Corpus::ClaudeCode),
        (".codex/sessions", Corpus::Codex),
    ] {
        let dir = PathBuf::from(&home).join(sub);
        let report = audit_dir(&dir, corpus, Some(1500));
        eprintln!(
            "{corpus:?}: files={} lines={} parse_errors={}",
            report.files, report.lines, report.parse_errors
        );
        // Every line must deserialize into the typed schema.
        assert_eq!(report.parse_errors, 0, "{corpus:?}: typed parse errors");
        // No record/envelope type may fall into the Unknown bucket — if a new
        // one appears, this fails and tells us exactly what to model.
        let unknown: Vec<_> = report
            .records
            .keys()
            .filter(|k| k.starts_with("<line>/"))
            .collect();
        assert!(
            unknown.is_empty(),
            "{corpus:?}: unmodeled record discriminants found: {unknown:?}"
        );
    }
}