Skip to content

perf(server): make terminal history updates incremental - #9357

Closed
burnmandont wants to merge 1 commit into
pingdotgg:mainfrom
burnmandont:perf/incremental-terminal-history
Closed

perf(server): make terminal history updates incremental#9357
burnmandont wants to merge 1 commit into
pingdotgg:mainfrom
burnmandont:perf/incremental-terminal-history

Conversation

@burnmandont

@burnmandont burnmandont commented Sep 3, 2026

Copy link
Copy Markdown

What Changed

  • Replace repeated full-string terminal history rebuilding with an incremental bounded line buffer.
  • Materialize retained history only for snapshots and coalesced persistence writes.
  • Preserve partial lines, empty lines, trailing newlines, clearing, and the configured line cap.
  • Document the server-owned terminal output and persistence path.

Why

Every PTY output chunk currently concatenates, splits, caps, and rejoins the entire retained history. Once the default 5,000-line buffer is full, sustained output repeatedly copies the whole buffer and makes callback cost proportional to retained history size.

The bounded buffer processes only newly received text during the hot path while keeping the existing wire format, persistence format, and terminal behavior unchanged.

A local Node 26.2 benchmark appended 50,000 representative one-line chunks while retaining 5,000 lines. The existing implementation took 7,342.5 ms; the incremental buffer took 5.5 ms (approximately 1,325x faster). Both produced byte-for-byte identical 230,000-byte output. These are machine-specific measurements rather than a product budget.

Verification

  • vp test run apps/server/src/terminal/Manager.test.ts — 55 tests passed
  • vp run --filter t3 typecheck — passed (pre-existing Effect suggestions only)
  • vp fmt --check apps/server/src/terminal/Manager.ts apps/server/src/terminal/Manager.test.ts docs/internals/terminal-runtime.md — passed

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • UI screenshots are not applicable
  • Interaction video is not applicable

Created with GPT-5.6 in the Codex harness.


Note

Medium Risk
Touches core terminal output and persistence on every PTY chunk; behavior is heavily tested but regressions in line boundaries or capping would affect all integrated terminals.

Overview
Replaces per-chunk full-string history rebuild (concatenate, split, cap, rejoin) with an incremental BoundedTerminalHistory line buffer on the PTY output hot path. Sessions now append sanitized chunks and only value() materialize the full transcript for client snapshots and debounced disk writes.

Clear, restart, and cwd/context resets use history.clear() instead of assigning an empty string; the coalescing persist worker still receives the live buffer object and writes history.value() after debounce. Wire format and line-cap semantics stay the same, with a new test covering chunked partial lines, empty lines, and trailing newlines.

Adds docs/internals/terminal-runtime.md documenting the output path and the performance invariant that retained history must not be copied on every PTY callback.

Reviewed by Cursor Bugbot for commit ed17b7d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Make terminal history updates incremental in TerminalManager

  • Replaces full-string concatenation on every PTY output event with an incremental line buffer (BoundedTerminalHistory) that caps retained lines and materializes the full string only on demand
  • Persistence worker now holds the bounded buffer reference and calls value() at write time, so debounced writes reflect the latest state instead of a snapshot string enqueued earlier
  • Session open, reset, clear, and restart paths all operate on the bounded buffer API; initial history is capped during construction and existing buffers are cleared before re-persistence on context change or error
  • Adds a regression test for empty lines, partial-line continuation, and line-limit preservation, plus internal runtime documentation
  • Risk: BoundedTerminalHistory handles trailing-newline and partial-line state internally; any out-of-tree code reading the history field via snapshot will still get a string, but the value is now materialized through BoundedTerminalHistory.value() rather than maintained eagerly
📊 Macroscope summarized ed17b7d. 2 files reviewed, 1 issue evaluated, 1 issue filtered, 0 comments posted

🗂️ Filtered Issues

apps/server/src/terminal/Manager.ts — 0 comments posted, 1 evaluated, 1 filtered
  • line 823: append drops a newline-only chunk when the existing history already ends in a newline. For example, appending "\n" to retained "a\n" takes the this.trailingNewline branch with an empty appendedLines array, leaving the value "a\n" rather than "a\n\n". PTY chunk boundaries can split consecutive blank lines this way, so terminal history and persisted/snapshotted output silently lose empty lines. [ Out of scope (triage) ]

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 3, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR changes the production terminal output hot path and persistence lifecycle through a new stateful buffering abstraction. Although the scope is focused and the external formats remain stable, the runtime impact is broad enough to merit human review.

You can add or adjust custom eligibility rules. Learn more.

t3dotgg added a commit that referenced this pull request Sep 4, 2026
Append terminal history incrementally and materialize text for snapshots and coalesced disk writes.
Clear evicted line references without changing retained output.

Continues [#9357](#9357). The original contribution and author credit are preserved.
The current line limit and wire format stay unchanged. A strict byte limit remains separate work.

Created with GPT-6 Astra (preview) in Codex.

Co-authored-by: will <will@moondiner.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Superseded by #9703 (perf(server): stop rebuilding terminal history per chunk), which continues this work and has merged to main.

Closing this PR in favor of that continuation.

richardsolomou added a commit to richardsolomou/ras-code that referenced this pull request Sep 5, 2026
* feat(server): measure provider turn token usage (#9132)

(cherry picked from commit 1587f24)

* chore(upstream): record the provider turn token measurement

* chore(upstream): record the marketing motion skip

* perf(server): avoid full patches for checkpoint summaries (#9694)

(cherry picked from commit c163d50)

* chore(upstream): record the checkpoint summary change

* perf(web): defer diff workers until a code view opens (#9692)

(cherry picked from commit b3e1d88)

* chore(upstream): record the deferred diff workers

* chore(upstream): record the marketing font skip

* perf(server): stop rebuilding terminal history per chunk (#9703)

Append terminal history incrementally and materialize text for snapshots and coalesced disk writes.
Clear evicted line references without changing retained output.

Continues [#9357](pingdotgg/t3code#9357). The original contribution and author credit are preserved.
The current line limit and wire format stay unchanged. A strict byte limit remains separate work.

Created with GPT-6 Astra (preview) in Codex.

Co-authored-by: will <will@moondiner.com>

(cherry picked from commit 3bbbc1d)

* chore(upstream): record aligned changes through 3bbbc1d

* perf(server): use one query for buffered provider events (#9706)

(cherry picked from commit dffb4cd)

* chore(upstream): record the buffered event query

* perf(relay): avoid repeated activity decoding (#9708)

(cherry picked from commit c75299e)

* chore(upstream): record aligned changes through c75299e

* perf(web): stop continuous chat status animations (#9709)

(cherry picked from commit c7c1dfe)

* chore(upstream): record the chat status animation change

* fix(mobile): preserve saved work after storage read failures (#9710)

(cherry picked from commit 7839140)

* perf(web): stop replaying terminal buffers on rollover (#9707)

Keep bounded, byte-counted terminal chunks and append only unread output. Use UTF-16 cursors so compaction preserves live terminal replies. Reset on lifecycle changes or a real retained-data gap.

Keep the existing wire protocol, native buffer interface, and client retention limit. Native streaming and strict server replay byte bounds remain separate.

Continue the client helpers from pingdotgg/t3code#9027 at source head 9391da2b48439d1d7a2b01d169e785682bf8abb8.

Created with GPT-6 Astra (preview) in Codex.

Co-Authored-By: Wout Stiens <71498452+StiensWout@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

(cherry picked from commit da7e46d)

* feat(web): preview pull request links (#9631)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

(cherry picked from commit 9510390)

* perf(client): reduce thread-list update work (#9716)

(cherry picked from commit c66f15f)

* fix(server): settle inactive threads with open PRs (#9610)

(cherry picked from commit d536b05)

* fix(server): bound slow-client event buffers (#9715)

(cherry picked from commit 108f295)

* test(server): allow either valid file-search match (#9720)

(cherry picked from commit 8ccb933)

* chore(upstream): record aligned changes through 8ccb933

* fix(web): match provider settings layout for disconnected devices (#9619)

(cherry picked from commit 8357eef)

* chore(upstream): record the provider placeholder layout

* fix(web): keep the slash menu above the composer when vertical space is short (#9625)

(cherry picked from commit 120fab1)

* chore(upstream): record aligned changes through 120fab1

* fix(mobile): remove provider setup (#9721)

(cherry picked from commit 9eb4d71)

* chore(upstream): record the mobile provider setup removal

* perf(web): stop rendering hidden terminals (#9718)

Stop post-construction terminal snapshots, canvas paint, and cursor timers while a drawer or right panel is hidden. Keep parsing output and answering VT queries, then render current state once on reveal.

Cover delayed WASM initialization, selection behavior, zero-size mounts, and reveal with real-core headless tests. Keep the existing startup background fill.

Continue the zero-size guard from source commit eb5b68103506b1bb5bd81c3b9e27f11e349743c9 in the terminal streaming contribution.

Created with GPT-6 Astra (preview) in Codex.

Co-Authored-By: Wout Stiens <71498452+StiensWout@users.noreply.github.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

(cherry picked from commit 5eab021)

* chore(upstream): record aligned changes through 5eab021

* fix(mobile): read file-backed image drafts before enabling them (#9713)

Accept file-backed image drafts and v4 outbox records while keeping current inline image creation and v3 outbox writes.

Retain image files during previews, uploads, and legacy inline reads. Preserve image MIME types and stop canceled sends after asynchronous reads.

The later file-backed writers remain held until new native runtime fingerprints contain these readers and the storage guards.

Continue Wout Stiens' mobile draft work with separate reader-only corrections. The original contribution remains unchanged.

Created with GPT-6 Astra (preview) in Codex.

Co-Authored-By: Wout Stiens <71498452+StiensWout@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit c4353bc)

* chore(upstream): record the image draft rebase

* perf(server): replay only the selected thread (#9726)

Read only the selected thread's events when resuming its detail stream. Measure bounded row counts and serialized payload bytes before replay, using the existing aggregate index and a captured authoritative head.

Keep snapshot resets for oversized or invalid cursors. Reset recreated threads when a snapshot exists, and keep bounded replay for deleted threads whose snapshot is absent. Shell replay and the detail-event filter are unchanged.

Created with GPT-6 Astra (preview) in Codex.

(cherry picked from commit 50bfca4)

* fix(web): mute composer helper text (#9654)

(cherry picked from commit 7d5dc66)

* feat(web): unpin threads from the sidebar multi-select menu (#9651)

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>

(cherry picked from commit c7bf311)

* chore(upstream): record aligned changes through c7bf311

* perf(web): reuse timeline rows while text streams (#9725)

Reuse ordered timeline entries and raw rows for safe streaming text updates. Keep full derivation for structural, metadata, activity, and control changes.

Preserve immutable attachment-preview objects when their current URLs are unchanged. Cover URL renewal/removal, completion, grouping, pagination, and earlier-row immutability.

Continue extoci's ordered timeline projection work with separate integration and attachment corrections. The original contribution remains unchanged.

Created with GPT-6 Astra (preview) in Codex.

Co-Authored-By: extoci <hi@extoci.lol>
(cherry picked from commit 19c1710)

* chore(upstream): record the timeline row reuse

* fix(relay): bound stalled push requests (#9734)

Give HTTP sends and response-body reads ten seconds each. Keep the existing typed transport errors, delivery records, and queue policy.

Abort stalled requests and let the next signed job run. JWT retrieval is outside these deadlines. Do not add retries for an uncertain response result.

Created with GPT-6 Astra (preview) in Codex.

(cherry picked from commit 088cc3f)

* perf(server): stop caching unused OpenCode tool parts (#9738)

Do not retain OpenCode tool parts after emitting their runtime events. The remaining cache readers need text, reasoning, or step-usage parts, not tool input and output.

Keep tool lifecycle events, output bytes, late-role assistant text, and usage handling unchanged. Add focused lifecycle coverage and verify retained memory through the real adapter.

Created with GPT-6 Astra (preview) in Codex.

(cherry picked from commit c8f77e0)

* chore(upstream): record aligned changes through c8f77e0

* fix(web): fold single trailing activity (#9739)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>
(cherry picked from commit cfc9bf3)

* chore(upstream): record the trailing activity fold

* fix(web): show project settings for new threads (#9743)

(cherry picked from commit cbe93e8)

* perf(mobile): bound the parsed review cache (#9749)

Bound cached parsed review sections by eight entries and 4,194,304 full source characters. Evicted inactive parsed and native results can be collected. Raw patches, comments, and view state stay unchanged.

Prewarm only nearby sections that fit beside the selected section. Use actual retained source weights for normalized cache hits, and skip oversized prewarms.

Created with GPT-6 Astra (preview) in Codex.

(cherry picked from commit d6e29dc)

* perf(web): avoid repeated terminal metadata scans (#9747)

Build one ordered terminal metadata index per immutable snapshot. Reuse unchanged session wrappers and thread groups across consumers, with separate environment targets.

Keep numeric ordering, picker ties, attach state, and subscription lifetimes unchanged. Let retired snapshots and groups be collected.

Created with GPT-6 Astra (preview) in Codex.

(cherry picked from commit fec606f)

* perf(server): bound terminal history by bytes (#9748)

Keep at most 5,000 lines and 8 MiB of retained UTF-8 terminal history. Discard the oldest text at either limit while preserving complete live output.

Track bytes and newlines in small chunks. Join split surrogates before eviction. Restore only the needed file tail, handle short reads, and close the file before rewriting current or legacy history.

Created with GPT-6 Astra (preview) in Codex.

Co-authored-by: will <will@moondiner.com>

(cherry picked from commit cf9729d)

* feat(web): link pull request authors to profiles (#9627)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

(cherry picked from commit a76b898)

* fix(web): refine server update notice (#9744)

(cherry picked from commit 0de956e)

* perf(client): stop thread streams when unused (#9740)

Close a thread's live detail stream when its last consumer leaves. Retain a registry-local completed state and replay cursor for five idle minutes.

Keep warm lookup independent of collectible raw atom definitions. Preserve paging and deletion state, reject stale owners, and cache only completed data/cursor updates.

Skip repeated saves of unchanged data while retaining dirty-data flushes and failed-write retries. Verify real GC/remount behavior and focused lifecycle cases.

Created with GPT-6 Astra (preview) in Codex.

(cherry picked from commit d7cf8aa)

* perf(mobile): defer file preview highlighter startup (#9752)

(cherry picked from commit 77b655c)

* perf(server): skip history reads for metadata commands (#9758)

(cherry picked from commit 6365919)

* chore(upstream): record aligned changes through 6365919

* perf(web): defer image URL requests for thread history (#9760)

(cherry picked from commit 15eda89)

* fix(server): read thread history where the fork transcript needs it

The metadata-command split moved turn dispatch onto the message-free shell
read, which the fork and provider-handoff transcripts depend on, and left
two fork-only call sites pointing at the removed resolveThread.

* chore(upstream): record the deferred image URLs and the history-read split

* docs(upstream): typecheck after each adopt-aligned run

verify is the only check between its picks, so a removed export that only a
fork file used survives to whichever later commit happens to typecheck.

* fix(models): make GPT-6-Astra current (#9762)

(cherry picked from commit bc03c36)

* fix(web): stop empty diffs replacing pull requests (#9753)

(cherry picked from commit d115a96)

* fix(sidebar): mute background working threads (#9759)

(cherry picked from commit 45bd3b6)

* fix(web): reset automatic pull to default (#9763)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

(cherry picked from commit f6db420)

* fix(web): restore file comment focus in editable preview (#9061)

(cherry picked from commit 13427ec)

* chore(upstream): record aligned changes through 13427ec

* chore(upstream): defer the internal docs restructure

* chore(upstream): defer the user docs restructure

* fix(web): stop panel motion during navigation (#9766)

(cherry picked from commit cd71367)

* chore(upstream): record the panel motion suppression

* fix(web): open composer selectors below controls (#9767)

(cherry picked from commit 8e056a0)

* perf(server): skip unused Linux process detail reads (#9768)

(cherry picked from commit 163d86a)

* fix(server): remove retired Codex models after refresh (#9773)

(cherry picked from commit bfef973)

* chore(upstream): record aligned changes through bfef973

* test: stop path and platform tests depending on the host OS (#9564)

Co-authored-by: Claude Code <noreply@anthropic.com>
(cherry picked from commit cc60753)

* chore(upstream): record the host-independent path tests

* test(server): skip posix executable fixtures on a Windows host (#9565)

Co-authored-by: Claude Code <noreply@anthropic.com>
(cherry picked from commit 4701041)

* chore(upstream): record the Windows fixture skip

* test(mobile): assert cold-start highlighting per entry point

Comparing the two entry points' token arrays assumes both resolve the same
regex engine. Linux CI produced a different split for the same grammar and
theme, so each path is checked for the behaviour the test names instead.

---------

Co-authored-by: Theo Browne <me@t3.gg>
Co-authored-by: maria <maria@kuuro.net>
Co-authored-by: Guillermo Casanova <75276669+Gigioxx@users.noreply.github.com>
Co-authored-by: oliver <97427849+flamboh@users.noreply.github.com>
Co-authored-by: Igor Makowski <56691628+Mnigos@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jake Leventhal <jakeleventhal@me.com>
Co-authored-by: Gianmarco <gianmarcosimone89@gmail.com>
Co-authored-by: extoci <hi@extoci.lol>
Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>
Co-authored-by: Shpetim <32248437+ShpetimA@users.noreply.github.com>
rynfar added a commit to pylon-code/pylon that referenced this pull request Sep 6, 2026
* perf(web): speed up terminal snapshots (#9663)

(cherry picked from commit cccd7e3c885065e925f559c5708378cdb3b51eb3)

* perf(server): stop rebuilding terminal history per chunk (#9703)

Append terminal history incrementally and materialize text for snapshots and coalesced disk writes.
Clear evicted line references without changing retained output.

Continues [#9357](pingdotgg/t3code#9357). The original contribution and author credit are preserved.
The current line limit and wire format stay unchanged. A strict byte limit remains separate work.

Created with GPT-6 Astra (preview) in Codex.

Co-authored-by: will <will@moondiner.com>
(cherry picked from commit 3bbbc1d9fd8b3d649c60ba0137c7dae93a6aab3f)

* perf(web): stop replaying terminal buffers on rollover (#9707)

Keep bounded, byte-counted terminal chunks and append only unread output. Use UTF-16 cursors so compaction preserves live terminal replies. Reset on lifecycle changes or a real retained-data gap.

Keep the existing wire protocol, native buffer interface, and client retention limit. Native streaming and strict server replay byte bounds remain separate.

Continue the client helpers from pingdotgg/t3code#9027 at source head 9391da2b48439d1d7a2b01d169e785682bf8abb8.

Created with GPT-6 Astra (preview) in Codex.

Co-Authored-By: Wout Stiens <71498452+StiensWout@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit da7e46d08e85bcb07ecd78721a40f7b612fac2f2)

* perf(server): bound terminal history by bytes (#9748)

Keep at most 5,000 lines and 8 MiB of retained UTF-8 terminal history. Discard the oldest text at either limit while preserving complete live output.

Track bytes and newlines in small chunks. Join split surrogates before eviction. Restore only the needed file tail, handle short reads, and close the file before rewriting current or legacy history.

Created with GPT-6 Astra (preview) in Codex.

Co-authored-by: will <will@moondiner.com>
(cherry picked from commit cf9729d5ee9660c08556e823080d3bb19648ed28)

* fix(server): advertise truecolor in the integrated terminal (#7680)

Co-authored-by: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com>
(cherry picked from commit 89ee69e4430b21ee14565abf5c34dae43f38c1d8)

* docs(terminal): describe history limits with Pylon identity

---------

Co-authored-by: Theo Browne <me@t3.gg>
Co-authored-by: will <will@moondiner.com>
Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Shubh <shubh@shubhxho.com>
Co-authored-by: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants