mirror of
https://github.com/nearai/ironclaw.git
synced 2026-09-03 08:06:01 +08:00
* fix(web): prevent browser crash from timer leaks, DOM growth, SSE buffer (#2406) Extended sessions with heavy bot interactions caused Chrome's "Pages Unresponsive" dialog due to accumulated browser resources that were never cleaned up. Fixes: - Add cleanupConnectionState() to clear leaked setInterval/setTimeout timers on SSE reconnect, tab visibility change, and page unload - Cap DOM at 200 message nodes via pruneOldMessages() with streaming- aware pruning (skips data-streaming elements, called at turn boundaries and after loadHistory) - Cap jobEvents Map at 50 entries with LRU eviction (excludes current job from eviction scan) - Increase SSE broadcast buffer from 256 to 1024 (configurable via SSE_BROADCAST_BUFFER env var, with zero-guard to prevent panic) Closes #2406 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(web): address PR #2433 review — move SSE buffer to GatewayConfig, fix E2E timer test Move SSE_BROADCAST_BUFFER env var from direct std::env::var() in sse.rs to GatewayConfig in config/channels.rs, following the convention that all gateway env vars flow through structured config. Add MAX_BROADCAST_BUFFER (65,536) clamp to prevent OOM from misconfiguration. Fix E2E timer leak test to install setInterval monkey-patch via page.add_init_script() before navigation so initialization timers are tracked. Add test_dom_resource_limits.py to E2E CLAUDE.md scenario table. Add unit test for buffer config parsing, zero-rejection, and clamp. [skip-regression-check] Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(web): address review — clean gatewayStatusInterval, prune user msgs, use constants - Add gatewayStatusInterval to cleanupConnectionState() so it is cleared on reconnect/tab-hide/unload; add guard in startGatewayStatusPolling() to prevent double-start; restart polling on tab visibility restore - Call pruneOldMessages() after addMessage('user', ...) in sendMessage() so DOM stays bounded even during rapid user input - Replace hardcoded broadcast_buffer: 1024 with DEFAULT_BROADCAST_BUFFER in all test construction sites (5 occurrences across 4 files) - Document in from_sender() doc comment why broadcast_buffer is absent - Tighten E2E timer leak assertion from baseline+1 to baseline [skip-regression-check] Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(web): address PR #2441 review — prune/timer/assert/doc fixes - Remove pruneOldMessages() from loadHistory() pagination path to avoid immediately evicting just-prepended older messages - Move MAX_DOM_MESSAGES constant to top-level constants block - Add _loadThreadsTimer to cleanupConnectionState() for consistency - Add assert!(broadcast_buffer > 0) to SseManager constructor with panic doc (tokio broadcast channel requires capacity > 0) - Use Set-based interval tracking in E2E test to prevent counter underflow from double-clear - Update CLAUDE.md broadcast buffer docs (256 → 1024, SSE_BROADCAST_BUFFER) [skip-regression-check] Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(web): remove assert! from SseManager to pass no-panics CI check Replace assert!(broadcast_buffer > 0) with a doc comment noting the precondition. GatewayConfig already rejects 0 at the config layer. [skip-regression-check] Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(web): address ilblackdragon review — correctness, e2e tests, docs (#2406) Correctness: - pruneOldMessages: clean up orphaned leading time-separators after pruning - jobEvents LRU: replace O(n) scan with O(1) Map insertion-order eviction - Document degenerate all-streaming under-prune case Playwright e2e tests: - Tab hide/restore: no duplicate gateway status polling intervals - DOM cap + streaming: 260 elements prune to ≤200, streaming preserved, no orphan separators - jobEvents bounded: 60 jobs stay capped at ≤50 via LRU eviction - Fix assertion selector to match pruneOldMessages superset, tighten lower bound Rust: - Unit test: SseManager buffer size parameter actually controls lag behavior - Document MAX_BROADCAST_BUFFER memory impact (65K×100×200B ≈ 1.3 GB) - Move "capacity baked into tx" comment from from_sender to rebuild_state Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(web): protect currentJobId from LRU eviction in jobEvents map (#2441) The O(1) LRU eviction skips the job that just received an event (moved to end via delete+set), but did not protect the job the user is actively viewing in the detail panel (currentJobId). If the user views a quiet job while 50+ other jobs fire events, the viewed job's events would be evicted and the activity tab would appear empty. Add a currentJobId guard to the eviction loop and a Playwright e2e test that verifies the actively-viewed job survives LRU pressure. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test(e2e): add real-flow Playwright tests for DOM resource limits (#2406) Add 4 E2E tests that exercise pruning and timer cleanup through actual UI interactions (mock LLM round-trips, real SSE reconnects) instead of page.evaluate() injection. Also fix the existing timer leak test which failed due to execution context destruction from add_init_script. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: serrrfirat <f@nuff.tech>