Skip to content

fix(codemode): prevent eval status heap exhaustion#4

Closed
minpeter wants to merge 1 commit into
fix/compaction-tui-stabilityfrom
fix/eval-status-memory-bound
Closed

fix(codemode): prevent eval status heap exhaustion#4
minpeter wants to merge 1 commit into
fix/compaction-tui-stabilityfrom
fix/eval-status-memory-bound

Conversation

@minpeter

@minpeter minpeter commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Third PR in the stack:

  1. Upstream Draft code-yeongyu/senpi#310
  2. Stacked Draft minpeter/saneagent#3
  3. This PR

Review this PR as the single commit on top of fix/compaction-tui-stability.

Summary

  • bound Code Mode eval status history to 100 rows per cell
  • reserve one row for an exact omitted-event count after overflow
  • retain the newest 99 real events without changing normal small histories or agent-status coalescing
  • render and document the bounded-history contract

Root cause

The reported process died near V8's 4.1-GB heap limit while child task st_019f92dc was visible. Raw artifact
analysis showed that the child itself had only a 3,634-byte task log and a 778-byte state record.

The actual concurrent workset was a Code Mode eval that recursively called Python read() over an estimated:

  • 955,757 files
  • 8,420,416,838 bytes / 7.842 GiB

Every helper read emitted a status event containing its path and up to 500 preview characters.
upsertStatusEvent() appended every event, while CellHandler copied the complete accumulated history into both
cell-level and top-level details for every partial update. The retained state grew linearly and aggregate cloning
grew quadratically until V8 exhausted its heap.

Fix

  • retain at most 100 status rows
  • on event 101, replace the oldest two events with one { op: "status-events-omitted", count: 2 } marker
  • increment that marker while retaining the latest 99 real events
  • preserve existing agent-event replacement by task id
  • show the omission count in expanded terminal/HTML status rendering

RED -> GREEN

  • RED: bounded-history regression expected 100 events and received 125
  • GREEN event 101: 100 rows, omitted count 2, first retained event 2
  • GREEN event 125: 100 rows, omitted count 26, first retained event 26
  • every partial update and both final detail copies are asserted at or below 100 rows

Verification

  • focused status/output/render tests: passed
  • full @code-yeongyu/senpi-codemode: 54 files / 372 tests passed; 1 file / 12 tests skipped
  • root npm run build: passed
  • root npm run check: passed
  • changed-file Biome: passed
  • git diff --check: passed
  • workspace package tests: passed

Root npm test is blocked before workspace execution by a pre-existing missing local v0.82.0 git tag in
scripts/check-upstream-release.test.mjs; the same test fails on the unchanged stack base.

Real fixpi QA

Hermetic localhost fake provider; real auth unchanged:

  • real fixpi launcher loaded this third-stack worktree
  • NODE_OPTIONS=--max-old-space-size=256
  • 125 Python reads: exit 0, 100 retained rows, omitted count 26
  • 20,000 Python reads: exit 0, 100 retained rows, omitted count 19,901
  • completion marker observed, two expected fake-model requests, sandbox cleaned
  • fixpi --version, fixpi --help, and bad input passed

Review

Independent goal, code-quality, security, hands-on QA, and stacked/upstream-context reviewers all returned PASS with
no remaining blockers or findings.


Summary by cubic

Prevents heap exhaustion in Code Mode by capping eval status history to 100 rows per cell. Adds an omission marker and renderer support while keeping agent status coalescing intact.

  • Bug Fixes
    • Cap status history at 100 rows (STATUS_EVENT_HISTORY_LIMIT); on overflow, insert { op: "status-events-omitted", count } as the first row and keep the latest 99 events.
    • Preserve upsert-by-id for agent events and trim after updates.
    • Render “N earlier events omitted” in terminal/HTML; document the bounded-history contract in the README.
    • Add tests to ensure partial and final details never exceed 100 rows and that cell and top-level histories match.

Written for commit 2ac7b36. Summary will update on new commits.

Review in cubic

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. To trigger a review, include @crb review in the PR description. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 42412cb9-df0e-4135-a404-1a69d559cf07

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/eval-status-memory-bound

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@minpeter

Copy link
Copy Markdown
Owner Author

Superseded by standalone upstream Draft PR code-yeongyu#324. The replacement is based directly on upstream main and contains only the bounded eval status history fix plus its package changelog entry.

@minpeter minpeter closed this Jul 24, 2026
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