Skip to content

fix(proxy): mirror chunks as base64, as documented (agent-code#372) - #53

Merged
Juliusolsson05 merged 4 commits into
mainfrom
fix/mirror-buffer-base64
Sep 25, 2026
Merged

Juliusolsson05 merged 4 commits into
mainfrom
fix/mirror-buffer-base64

Conversation

@Juliusolsson05

@Juliusolsson05 Juliusolsson05 commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner

Refs Juliusolsson05/agent-code#372 (one part of it; caps and request bodies stay there).

Plan: docs/plans/2026-09-25-mirror-buffer-base64.md (first commit).

Why

ResponsesProxy.emit meant to mirror chunk bytes as { _buffer_b64 }, and API.md documents that. But JSON.stringify calls Buffer#toJSON before the replacer runs, so the replacer never saw a Buffer. Every chunk has been written as {"type":"Buffer","data":[123,34,…]}.

In a recorded 3.19 GB session file (2026-09-25), chunk lines are 2,266 MiB for 621 MiB of payload, a 3.65× blow-up. None of the 34 local dumps contains _buffer_b64.

Change

The replacer reads the holder's raw value (this[key]), so a Buffer becomes base64. base64 rather than text, because a chunk can split a UTF-8 character. The expected size of that file's chunk lines drops to about 830 MiB, with nothing lost. No reader depends on the old array form (checked this repo and agent-code).

Fixture redaction (steering q36)

testing/fixtures/proxy-mirror/models-chunk-2865.json is one recorded /v1/models chunk (2,865 bytes). The raw chunk carried provider instruction text (model_messages.instructions_template, "You are Codex…") and model descriptions. That text is not known to be public, so every JSON string literal longer than 24 bytes is replaced byte-for-byte with x. The event shape, byte length and JSON structure are real. oldMirroredLineBytes (11,148) is recomputed from the sanitized bytes with Node's own serializer.

The raw fixture was pushed briefly in b7885f5. That commit was amended out of the branch (head 0800cba), but GitHub may still serve it by SHA until garbage collection.

Tests

Four tests: a 24-byte recorded chunk, a split UTF-8 character, the sanitized 2,865-byte chunk (byte-exact, base64 size bound measured on the raw line, less than half the old line), and a nested Buffer.
responsesProxy.mirror.test.ts uses a recorded chunk event and a chunk that splits a UTF-8 character. It checks the exact byte round-trip and the base64 size bound. The first two tests were red on main (_buffer_b64 undefined) and are green here. The full suite passes (223 tests), and tsc --noEmit is clean.

🤖 Generated with Claude Code

Juliusolsson05 and others added 2 commits September 25, 2026 08:53
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JSON.stringify calls Buffer#toJSON before the replacer, so the mirror's
Buffer check never matched and every chunk was written as a decimal byte
array, 3.65x its payload. The replacer now reads the holder's raw value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Juliusolsson05 added a commit that referenced this pull request Sep 25, 2026
…e, nested Buffers

Review B: a size bound on a 24-byte chunk let a length-limited encoder pass;
the recorded 2,865-byte chunk (a 10,692-byte line before) now pins byte
exactness and the base64 bound on the raw mirrored line. Review A: a Buffer
nested anywhere in an event is inlined too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e, nested Buffers

Review B: a size bound on a 24-byte chunk let a length-limited encoder pass;
the recorded 2,865-byte chunk (a 10,692-byte line before) now pins byte
exactness and the base64 bound on the raw mirrored line. Review A: a Buffer
nested anywhere in an event is inlined too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Juliusolsson05
Juliusolsson05 force-pushed the fix/mirror-buffer-base64 branch from b7885f5 to 0800cba Compare September 25, 2026 16:04
…, UTF-8 and toJSON siblings pinned

Every earlier test wrote one event into a fresh file, so an overwrite, a
missing newline, mirroring other emits, a latin1 write or returning the raw
value for toJSON-bearing siblings all passed. API.md now says older dumps
hold byte arrays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Juliusolsson05

Copy link
Copy Markdown
Owner Author

Final disposition (pre-merge), head e31c670. Three reviewers: A (correctness, Codex), B (tests, Codex), C (forensic value, Pi).

Reviewer Round 1 Round 2
A (correctness) MERGE-READY (1 minor) MERGE-READY
B (tests) FIX-BEFORE-MERGE MERGE-READY
C (forensic value, blast radius) MERGE-READY (4 minors) —

Findings and dispositions:

  • B1 (major): the size regression was unprotected above 24 bytes. An encoder limited to 24 bytes passed; 987 of the first 1,000 recorded chunks are larger. Fixed in 0800cba with a recorded 2,865-byte chunk, byte-exact, and the base64 bound measured on the raw line. B confirmed the mutant dies.
  • B2 (minor): the size was measured after parsing, not on the line. Fixed in 0800cba.
  • A (minor): nested Buffers were untested. Fixed in 0800cba. A confirmed the key === 'chunk' mutant dies.
  • Steering q36: that fixture carried provider instruction text under base64. It is sanitized byte-for-byte (long string literals are replaced with x), and the size fields are recomputed. The raw commit was amended out of the branch. A and B verified the sanitized bytes in round 2.
  • C1 (minor): the append pipeline was unpinned. Every test wrote one event, so overwrite, missing-newline, filter and latin1 mutants survived. Fixed in e31c670 with a multi-event UTF-8 session. All four mutants now die.
  • C2 (minor): return raw survived. Fixed in e31c670 with a Date sibling test; the mutant dies.
  • C3 (minor): this[key] runs a getter twice. Documented in the code comment; payloads are plain literals.
  • C4 (minor): mixed-era dumps. API.md now says older dumps hold byte arrays.

Residual (agent-code#372): per-file byte caps, dropped counters, request-body mirroring (775 MiB in the recorded file) and the synchronous write. This PR removes only the 3.65× chunk blow-up; the recorded file's chunk lines drop from 2,266 MiB to about 830 MiB.

Merges on green package CI; then the agent-code bump.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant