code-yeongyu / code-yeongyu/senpi
bug(codemode): settled/detached eval result cards repaint at 1 Hz forever; missing dispose accumulates timers (idle CPU burn)
- Dominant language
- TypeScript
- Stars
- 429
- Forks
- 98
- Avg merge
- 5h 3m
- Merged PRs (30d)
- 526
Description
## Summary
packages/senpi-codemode/src/tool/render.ts:
- syncLiveTicker arms a 1-second setInterval (line 95) whenever hasLiveCell(details) is true (line 929), and hasLiveCell treats detached cells as live. Detached/peek snapshots remain in detached state forever, so their cards keep repainting at 1 Hz after completion.
- PlainTextComponent has no dispose. Every transcript rebuild (interactive-mode.ts) creates fresh components with fresh tickers while old intervals can never be stopped, so timers accumulate over the session lifetime.
Measured: 9 idle sessions each sustained 2-8% CPU over 25 minutes (35-99 CPU-seconds each); sampling an idle 4-day-old session showed ~20% of main-thread samples in JIT JS execution — leaked repaint timers.
## Context
Root-caused during a profiling investigation of a long-lived macOS host (M4 Pro, 64 GB) running ~28 concurrent senpi/omo sessions for several days. Symptoms: load average ~150 with only ~50% CPU utilization (threads blocked on swap I/O), 20 GB swap in use, idle sessions each burning 2-8% CPU sustained, and idle session heaps growing to multiple GB (one 4-day-idle session: 648 MB resident JSC heap + 1.4 GB swapped, 3.3 GB peak footprint). All file:line references are against main (b19491745). Raw profiling evidence held locally.
## Expected (ideal state)
Terminal-state and detached snapshot cards are static (no ticker). Components own a dispose() that clears their interval, and transcript rebuilds dispose replaced components. An idle session's render path arms zero intervals.
## Acceptance criteria
- Unit tests: rendering a settled/detached cell card arms no interval; dispose() clears armed tickers; a rebuild cycle leaves zero live intervals.
- Idle-session CPU attributable to the render ticker drops to ~0.
## Related
- sibling eval-cell retention issue (same profiling run)
Contributor guide
Research direction
Start in packages/senpi-codemode/src/tool/render.ts at syncLiveTicker and hasLiveCell, then inspect the transcript rebuild path in interactive-mode.ts. Add or update unit tests covering settled and detached cards, dispose(), and rebuilds; done means those cases leave zero live intervals and the render ticker no longer burns idle CPU.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 62/100