fix(sdk): prevent transcript memory leaks in scan tracking - #830
Open
msapelov wants to merge 1 commit into
Open
Conversation
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
During long-running concurrent audits sharing a Codex home, several
codex-securityCLI processes reached roughly 2 GiB of resident memory per process. These measurements were for the local CLI scan processes. Investigating that growth revealed transcript-derived activity retained byScanCostTrackereven when it would never be delivered.The tracker currently parses unrelated session transcripts, keeps unused parent activity, and stores complete message text for prose deduplication. This patch indexes ownership before reading transcripts, collects only consumed activity, and retains compact deduplication fingerprints.
An isolated reproduction on 0.1.26 adds 18.66 MiB of retained heap from 6.04 MiB of unrelated messages; this patch reduces that growth to 0.09 MiB. It uses synthetic logs and makes no model calls. The reproduction confirms this retention bug; the observed process RSS includes other allocations and is not attributed entirely to this cause.
Changes
Related work: #177 changes refresh scheduling; #465 changes spending-limit verification in the same tracker; #278 restructures an older rollout reader. None provides this fix for the current tracker. Changes to this file in #465 may require integration if it merges first.
Testing
Validated on the patch rebased onto
2536d104deef9bca8ced84c6f6263b915418253b(0.1.26).pnpm run test --seed 12345: 2,420 passed, 43 platform-specific skips, 0 failures.pnpm run test(seed 100061061): 2,420 passed, 43 platform-specific skips, 0 failures.pnpm run types,pnpm run format,tsc -p tsconfig.build.jsonandgit diff --check: passed.Tests use CI-pinned Bun 1.3.14 and pnpm 11.19.0. A temporary test PATH supplies the
pythoncommand used by one CI fixture.The Node 26.8.1 reproduction compares current main and patched tracker code compiled with the same TypeScript compiler and dependencies. Each sample runs garbage collection before measuring retained heap; figures are growth from an initialized tracker, not total process memory.
The worker scenario delivers all 3,000 activities both before and after the change. The reasoning scenario preserves all 750 updates. The unrelated scenario delivers zero unrelated activities in both versions, demonstrating that excluded output was still retained internally.
Self-contained memory reproduction
Save the script as
reproduce-memory.mjs. After building the SDK, run it against each version'sdist/cost.js:The script creates and removes its own temporary session files. It uses no existing Codex home or credentials. Optional modes are
parent,worker,usage-only, andreasoning.Risk and rollout
Session ownership and replay order are the main compatibility risks. Descendant, independent Deep worker, inherited-history, receipt, incremental-read and large-event tests exercise those paths. There are no public CLI, authentication, pricing, artifact-schema or polling-interval changes.
The patch retains compact ownership metadata and deduplication identities; it does not impose transcript limits or promise constant memory usage. Observers may still retain the output they receive. Running scans do not load the fix until a new process starts.
Public disclosure review