Repository navigation
fix(claude): bump claude-code-headless to the rotating proxy-events log (#1273) - #1376
Conversation
…esidual) Refs #1273 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Claude proxy addon now rotates proxy-events.jsonl into proxy-events.1.jsonl at 512 MiB. Right after a rotation the live file holds a few lines, so a bundle would miss the recent traffic a report is about. When the live file is under the 5 MiB cap, the rest is filled from the end of the previous generation, cut at a line boundary. Refs #1273 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wnership Refs #1273 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…og (#1273) claude-code-headless#64 (merged, f52fc82): the addon rotates proxy-events.jsonl at 512 MiB keeping one previous generation, each generation stamped with a header; the app's tail holds a FileHandle on the generation it reads and reports generations deleted unread as a `transport-gap`. A live Claude run is now bounded instead of growing for the life of the session. No lockfile resync: the app consumes the package from source and its runtime deps are root deps; the bump changes only the package's devDependencies. The plan records the header design, the accepted crash limitation, and that #1332 (W1) owns the rotation-safe bundle reader. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… retention (review) Review of #1376 (a, b, c): - ClaudeSession listened to the proxy's `event` channel only, so the `transport-gap` claude-code-headless#64 emits for generations deleted unread never left the package. attachProxyServer subscribes both and re-emits `proxy-transport-gap`; SessionManager records a claude.proxy_transport_gap incident and re-emits it with the session id. The normal event wiring is now pinned (deleting it passed every test before). - collectProxyRunDirs counts a run holding only proxy-events.1.jsonl. - sslkeylog.log is a separate unbounded file (and TLS secrets on disk): filed as #1380; the PR narrows to Refs #1273. Mutations killed: session ignoring transport-gap, session ignoring event, manager ignoring the gap, retention ignoring `.1`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review disposition (round 1: a, b, c codex at
|
| # | Finding | Verdict | Disposition |
|---|---|---|---|
| a1 / b1 / c2 | The app drops transport-gap; the "exactly once, or an explicit gap" contract stops at the package boundary. Even the event wiring was untested. |
valid | Fixed in 0de54245: ClaudeSession subscribes to both channels, and SessionManager records a claude.proxy_transport_gap incident and re-emits it with the session id. Pinned at both layers; all four wiring mutants are red. |
| a2 | A run holding only .1 is invisible to retention |
valid | Fixed: collectProxyRunDirs counts it; test plus mutant. |
| c1 | sslkeylog.log in the same run directory grows without bound (and holds TLS secrets), so Fixes #1273 overclaimed |
valid | Filed as #1380 (outside this bump: it needs a package change). The PR is narrowed to Refs #1273, and the body states the real disk bound. |
| c3 | The sidecar bound omitted base64 expansion | valid | Fixed in the plan and body: ~21.3 MiB on disk, twice that briefly during the replace. |
Verification pass: a/b/c at 0de54245, queued under the reviewer cap.
Steering q87: the gap is diagnostic-only in the app: an always-on incident plus a manager re-emit. Nothing renders a missing-span marker yet, so the user-visible gap is filed as #1381. The body and plan say exactly that (33c046cf).
Focused verification (c, steering q87/q89) — the central diagnostic claim was found accurate. Three minors:
- Body said every generation has a header. Corrected: only generations created by a rotation carry one; generation 0 has none.
- Body stated the disk bound as absolute. Corrected: it holds under the default
PROXY_EVENTS_ROTATE_BYTES, and0(the forensic override) disables rotation. - The gap subscription's ownership guard was unpinned. Pinned in the new head: a replaced session's late gap is not recorded against its successor; the mutant is red.
Round 2 (verification, a/b/c codex at 49ee5985):
- a: MERGE-READY. One surviving mutation: stripping
{"kind":"generation"}lines from bundled JSONL inproxyEventsReader.tspasses. Accepted, not a defect. The bundle ships raw bytes on purpose; whether a header line appears in a diagnostic bundle changes no behaviour. - b: MERGE-READY. No survivors.
- c: FIX-BEFORE-MERGE, minor docs/format only. No survivors (all four replayed mutants are red).
- The plan's Decisions/Tests/Delivery sections still stated the pre-review scope. Fixed in
f04837d2: the events file is bounded, the run directory is not (claude proxy: sslkeylog.log grows unbounded in every live run dir (and holds TLS secrets on disk) #1380), and the app wiring and its tests are listed. - Extra EOF blank lines in three test files. Fixed in
f04837d2;git diff --check origin/main...HEADis clean. f04837d2touches no source: one plan doc and three trailing newlines. Both review rounds are spent, so this goes to manager-verify-c.
- The plan's Decisions/Tests/Delivery sections still stated the pre-review scope. Fixed in
Manager-verify-c (temp/review-1376/manager-verify-c.md) confirms f04837d2 by inspection: plan docs only, and the src changes are trailing blank lines. merge-gate --member --dry: GATE PASS (f04837d2, 0 behind, checks green). READY.
After batch F (69adefbd): merged origin/main because of a real conflict. The only conflicting path was the claude-code-headless gitlink, and this branch's f52fc82 contains main's 728cb494, so it is kept. The merged tree gives npx tsc -b 0 lines, the focused suites pass 17/17, and CI is green. merge-gate --member --dry: GATE PASS (69adefbd, 0 behind). READY.
… marker is #1381 (q87) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inst its successor (focused review) Focused review of #1376 (c): the ownership guard on the gap subscription was unpinned (deleting it passed). Also corrects the plan: generation 0 has no header, and PROXY_EVENTS_ROTATE_BYTES=0 disables the bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lank lines Reviewer C (round 2): Decisions/Tests/Delivery still stated the pre-review scope (a fully bounded run, no app tests, pointer-only). They now match the review appendix: the events file is bounded, the run directory is not (#1380), and the app-side wiring and its tests are listed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #1273. With the default rotation setting, the events file is now bounded. A live run directory still has one unbounded file,
sslkeylog.log, filed as #1380, so this PR does not close #1273.Problem
#1284 / claude-code-headless#62 capped request bodies per events file, but two items stayed open:
proxy-events.jsonlstill grew for the life of the session (responses, stream chunks, body-less requests);Change
This PR bumps
packages/claude-code-headlesstof52fc82, which is claude-code-headless#64 (merged after three reviews, a verification pass and a final round 3):PROXY_EVENTS_ROTATE_BYTES), keeping exactly one previous generation (proxy-events.1.jsonl). A live run holds at most ~2 × 512 MiB. The bound holds under the default setting only:PROXY_EVENTS_ROTATE_BYTES=0(the forensic override) disables rotation, and the events file then grows without bound.{"kind":"generation","generation":n}, created atomically. Generation 0 has no header: the run's first event creates it. The tail treats a missing header as generation 0 and uses the headers to know exactly which generation it holds.EventsFileTail) holds a FileHandle on its generation, finishes it on rotation, reads an unseen.1in order, and reports any generation deleted unread aslostGenerations.ProxyServeremits that as atransport-gapevent.On the app side:
.1and ships raw bytes, where the header is one more JSON line.debugRetentiondetects a run byproxy-events.jsonl, which the addon now recreates immediately after a rotation.file:dependency. Its runtime deps (chokidar,@xterm/headless) are root deps. The bump changes only the package's devDependencies, andnpm install --package-lock-onlyleavespackage-lock.jsonunchanged.ClaudeSessionnow subscribes to the proxy'stransport-gapas well asevent, andSessionManagerrecords aclaude.proxy_transport_gapincident for the session.proxy-events.1.jsonl(a rotation whose next file was never created) is now counted, so it cannot accumulate invisibly.PROXY_EVENTS_ROTATE_BYTES; unbounded if it is set to 0;sslkeylog.log: unbounded until claude proxy: sslkeylog.log grows unbounded in every live run dir (and holds TLS secrets on disk) #1380.docs/plans/2026-09-26-proxy-events-retention.md.Verification
npx tsc -bprints 0 lines.claudeSession.suspension.test.ts: proxyeventforwarding, the gap re-emit, and detach;sessionManager.proxyGap.test.ts: the incident and the re-emit;debugRetention.test.ts: a.1-only run is counted.transport-gap, the session ignoringevent, the manager ignoring the gap, retention ignoring.1.8996d9d3,src/providers/claude,proxyEventsReaderanddebugRetentionpassed 245/245.🤖 Generated with Claude Code