fix(observer): uuid-dedup in parseLines (C-1 root fix for quirk #101)
Bug: Claude Code's transcript JSONL file accumulates duplicated context- rebuild snapshots — the same entry re-printed with the SAME `uuid`. Without dedup, session_turn / task_size / events double-count, and session_turn becomes non-monotonic across episodes parsed at different file-growth states. Live evidence: episodes-2026-05.jsonl lines 14/15/16 of the same session showed session_turn 139 → 140 → 91 (backwards in time). Probe on transcript 553717ec: 22400 entries, only 6074 unique uuid (68% dup rate); real user prompts 264 total vs 92 unique-uuid. Fix: parseLines now tracks a `seenUuid` Set and skips entries whose uuid has already been encountered (keep-first). Entries without `uuid` (synthetic test fixtures) pass through unchanged. All downstream functions (findTurnStart, extractEnvironment, extractTaskSize, etc.) operate on the deduped entries array, so the fix is single-point and total. Tests: new `parseTranscript — uuid-dedup` describe block covers (1) duplicated-uuid prompts collapse → session_turn counts once, (2) distinct-uuid entries preserved (no over-dedup), (3) no-uuid entries pass through (synthetic-fixture safety), (4) duplicated-uuid assistant turns → tool_calls / files_touched counted once. 110/110 parser tests green (was 106). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,15 +23,29 @@ function parseLines(text) {
|
||||
const entries = [];
|
||||
let broken = 0;
|
||||
let total = 0;
|
||||
// quirk #101 root fix: Claude Code's transcript file accumulates duplicated
|
||||
// context-rebuild snapshots — the same entry is re-printed with the SAME
|
||||
// `uuid`. Without dedup, session_turn / task_size / events double-count and
|
||||
// session_turn becomes non-monotonic across episodes parsed at different
|
||||
// file-growth states. Keep the first occurrence per uuid; entries without a
|
||||
// uuid (synthetic test fixtures) pass through unchanged.
|
||||
const seenUuid = new Set();
|
||||
for (const line of String(text || '').split('\n')) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) continue;
|
||||
total += 1;
|
||||
let e;
|
||||
try {
|
||||
entries.push(JSON.parse(trimmed));
|
||||
e = JSON.parse(trimmed);
|
||||
} catch {
|
||||
broken += 1; // broken line — counted for parse_gap, never thrown
|
||||
continue;
|
||||
}
|
||||
if (e && e.uuid) {
|
||||
if (seenUuid.has(e.uuid)) continue;
|
||||
seenUuid.add(e.uuid);
|
||||
}
|
||||
entries.push(e);
|
||||
}
|
||||
return { entries, broken, total };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user