From c40d3172acf40d3479ee6d45a2d116772c9dd96c Mon Sep 17 00:00:00 2001 From: alt-glitch Date: Tue, 9 Jun 2026 09:41:37 +0000 Subject: [PATCH] opentui(harden): slice the resume snapshot before mounting (no transient over-cap) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commitSnapshot set the full fetched history then trimmed — briefly handing the whole transcript to . Since Yoga (WASM) layout memory is grow-only, even a transient over-cap mount permanently ratchets the high-water mark, partly defeating the cap when resuming a large session (a real one has ~1980 messages). Slice to MESSAGE_CAP BEFORE the first setState so resume mounts at most the cap. --- ui-tui-opentui-v2/src/logic/store.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ui-tui-opentui-v2/src/logic/store.ts b/ui-tui-opentui-v2/src/logic/store.ts index c17939e12ce..5ba9d846c1c 100644 --- a/ui-tui-opentui-v2/src/logic/store.ts +++ b/ui-tui-opentui-v2/src/logic/store.ts @@ -780,9 +780,14 @@ export function createSessionStore() { /** Replace history with the resume snapshot, then replay events buffered meanwhile. */ function commitSnapshot(snapshot: Message[]): void { - setState('messages', snapshot) - // An over-cap resume snapshot must be trimmed too (it sets the whole array). - setState(produce(capMessages)) + // Slice to the cap BEFORE the first setState, not after. Yoga (WASM) layout + // memory is grow-only, so even a TRANSIENT mount of an over-cap resume + // snapshot would permanently ratchet the high-water mark — a set-then-trim + // briefly hands the full fetched history to . Pre-slicing guarantees + // resuming ANY session mounts at most MESSAGE_CAP rows. (Events buffered + // across the resume RPC, replayed below, self-cap via capMessages per push.) + const capped = snapshot.length > MESSAGE_CAP ? snapshot.slice(-MESSAGE_CAP) : snapshot + setState('messages', capped) const pending = buffering ?? [] buffering = null for (const event of pending) applyNow(event)