fix(chat): reap replaced stream buffers#3825
Open
CompleteDotTech wants to merge 1 commit into
Open
Conversation
CompleteDotTech
force-pushed
the
agent/fix-heap-retention-3803
branch
from
July 25, 2026 04:11
d4edab1 to
cc8c95a
Compare
Member
Author
|
@BunsDev This PR is ready to merge after testing. |
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
Fixes #3803.
A finished live-chat resume buffer could become permanently reachable when a follow-up turn reused the same conversation ID.
openRunBuffer()replaced the shared conversation mapping but cleared the predecessor's two-minute reap timer, even though the predecessor remained mapped by its unique run ID.The fix keeps the predecessor timer armed. Its existing identity guard removes only mappings that still point to that predecessor, so it cannot delete the replacement conversation mapping.
Bead:
cave-r13xMeasured root cause
No in-the-wild snapshot was present on this Windows machine, so the live-
/chat/sendsuspect was reproduced directly with 300 finished runs sharing one conversation, each filling the bounded 512 KiB resume ring.Before the fix, after GC:
(string)136.817 MiB,Object136.037 MiB,Map132.015 MiBMapinstance retained 131.292 MiBThe retainer path from the V8 snapshot was:
chat-stream-buffer module Context → buffers Map → RunBuffer → events Array → serialized StreamEvent JSON stringsAfter the fix and the virtual two-minute retention window:
Regression coverage
The new test finishes an old run, replaces its shared conversation key with a new run, advances the two-minute timer, and proves:
The regression failed before the implementation change and passes after it.
Verification
Passed:
pnpm typecheckpnpm lintpnpm check:tests-wired(1,234 test files wired)git diff --checkBroader local runners encountered unrelated Windows harness assumptions:
pnpm test:appstopped after 74 files becausesrc-tauri/release-runtime.test.mjsexpects LF-only Rust source while this checkout uses CRLFpnpm test:apistopped after 6 files becausescripts/git-hooks-pre-commit.test.mjsrequires/bin/bash, which is unavailable on this machineRemaining uncertainty
This is a controlled reproduction rather than the originally requested in-the-wild capture because no production snapshot or
[heap-monitor]warning existed. The reproduction exercises the prime live-chat suspect directly, produces the expected unbounded per-turn retention, identifies the retaining path in a V8 heap snapshot, and demonstrates bounded post-fix behavior.