fix(protocols): bound opaque replay string memory - #506
Merged
Conversation
Recover raw UTF-16 carriers in bounded flat chunks so long replay histories do not retain a V8 rope node per code unit. Preserve every code unit and the existing wire format. Cover the full UTF-16 range, BOMs, surrogate and chunk boundaries, offset views, and isolated retained-heap growth. The bounded Node fixture drops retained heap from about 12 MiB to 0.35 MiB. Document how this regression runs through the standard verification workflow.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Recover raw opaque UTF-16 strings in bounded, compact chunks so long reasoning-replay histories do not retain a V8 rope node for every code unit. Preserve the existing carrier bytes, every UTF-16 code unit, BOMs, and lone surrogates.
The regression coverage exercises the full code-unit range, chunk boundaries, large values, nonzero-offset views, empty input, and incomplete code units. A separate retained-heap fixture protects the memory behavior, and the development documentation explains how it runs through standard verification.
Memory behavior
Affinity analysis retains decoded opaque values while subsequent history blocks are processed. Per-character concatenation retained approximately 12 MiB for a bounded fixture of 64 strings containing 393,216 ASCII code units; chunked recovery retains approximately 0.35 MiB for the same output.
The fixture launches an isolated Node.js process with explicit GC, warms the production helper, and measures heap usage while all decoded strings remain reachable. It compares their contents after sampling because comparisons can flatten ropes and hide the defect. These figures measure retained Node.js heap, not peak production Worker memory. The wire format and persisted data remain unchanged.
Test Plan
pnpm run verifychain: 548 test files and 5,733 tests passed; local installer verification passed 106 cases with four environment-dependent skips; lint, typecheck, repository checks, and web-build assertions passed.The client version also changed during the production trial, so recovery is not a single-variable experiment. The isolated before/after heap regression independently establishes the implementation's memory improvement.