Repository navigation
fix(web): paint synchronized terminal updates atomically - #9867
Conversation
Extract the web synchronization gate from #9027. Add lifecycle and real WASM regression coverage without its streaming, replay, native, or theme changes. Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com>
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
ApprovabilityVerdict: Needs Human Approval Macroscope's review found this PR requires human approval — The PR changes the shared terminal rendering pipeline by suppressing paints and canvas updates during synchronized output, adding escape-aware processing, and forcibly recovering after a 500 ms deadline. Its timing and rendering-state behavior merits human review despite strong focused test coverage. No code changes detected at You can add or adjust custom eligibility rules. Learn more. |
|
Current-client verification on 84b99f3f, with the exact two production-file changes from 9aacd204 integrated for the after run. The disposable fixture runs in the real integrated terminal. Each synchronized group writes FIRST, waits 160 ms, writes SECOND, then closes the group. Before the patch, the recording contains FIRST 02 / SECOND 01. The after recording shows the previous complete frame retained until the next pair is available. This is a controlled terminal-output reproduction in Chromium 152, not a native nvim/lazygit session or proof for every source of flicker in the linked reports. Before: After: Recordings use the existing live browser tab, sampled at 20 fps with wall-clock timing preserved. The fixture writes only to its terminal and restores the alternate-screen and cursor modes on exit. No provider turn was started. The full four-file change and focused tests have been reviewed. This remains human-held: the 500 ms recovery deadline for an unterminated synchronized update is a behavior decision, not a value established by this fixture. Audited by GPT 6 Astra via Codex in T3 Code. |
|
Note: GPT-6 on behalf of shivam (@shivamhwp). The synchronized-output timer can expire a new group using the previous group's deadline. Open group A, then 450 ms later deliver A's closing Track the closed-and-reopened group even when both markers arrive in one write, and give the new group its own deadline. Preserve the existing rule that additional output within one unterminated group cannot extend its deadline. The human decision about the 500 ms recovery policy remains separate, and #7790 should remain open for its other reported variants. |
|
Taking over this one. I will merge current main into the existing branch, preserve the newer terminal lifecycle, minimize the regression coverage, and address the reported close/reopen deadline bug. The 500 ms recovery policy remains for human review; no merge will be performed. |
|
Maintainer rebuild pushed with current main merged. The same-write close/reopen deadline regression now fails before and passes after; all 105 focused core/surface tests and web typecheck pass. Fresh independent Opus 5.5 and GPT-6 Sol full-diff reviews found no code blockers. The body records measured ANSI-heavy overhead and missing current-head live proof. Human approval of the 500 ms recovery policy remains required; this is unmerged. |
) Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com> (cherry picked from commit 26338ea)


Terminal programs can split a synchronized-output update across PTY chunks. The renderer previously painted a partial new frame and cleared dirty rows before the closing marker. It now defers snapshots, paint and canvas backing-store changes while Ghostty mode 2026 is open, then paints the complete frame.
Each unterminated group gets one 500 ms recovery deadline. Additional output does not extend it. When a write closes one group and opens another, Ghostty’s actual mode transition cancels the first deadline so it cannot prematurely paint the second group. Hidden, zero-sized, disposed and reset surfaces cancel pending deadlines; actual grid resize keeps Ghostty’s behavior of ending synchronization immediately.
Maintainer takeover of this PR, preserving Wout Stiens’ original extraction credit. Merged current main into the existing branch and preserved the newer font/cursor/visibility lifecycle. Discarded the original core-only assertion tests and consolidated surface coverage from 11 added cases to eight using the existing real Surface/WASM fixture.
Validation: 105 focused core and surface tests pass (97 main tests plus eight takeover cases). The close/reopen regression failed against the original timer gate and passes after the fix. Web typecheck and formatting pass; targeted lint reports one existing
new Arraywarning in unchanged grapheme code. 566 native split-sequence observations matched byte-by-byte Ghostty behavior. Ordinary writes keep one allocation and one VT feed. A synthetic escape-heavy 1 MiB write inside an already-open group measured about 69 ms vs 46 ms before; observing real transitions adds WASM calls only while that pending group remains open.Independent full-diff Opus 5.5 and GPT-6 Sol reviews found no remaining code blockers. Both require human policy approval and fresh integrated-client proof before merging.
Current-head browser proof is missing. The previous screenshots/recordings were for the old implementation; they are not verification of this rebuilt head. T3’s Browser panel cannot start on this Linux host because required shared libraries are missing, so no fresh capture was obtained. Real Neovim/lazygit, macOS, Windows, iOS, Android and Electron desktop remain unverified. This changes the shared web terminal used by web and desktop; native mobile is unchanged. Local and remote PTY output uses this same rendering path.
Human review is required for the 500 ms recovery duration and the decision to end an unterminated group. This PR fixes partial frame painting; it does not establish that all reported terminal freezes are fixed. No merge is requested.
Models: tests by GPT-6 Astra and implementation by GPT-6.1 Sol through Codex in T3 Code; adversarial reviews by Claude Opus 5.5 and GPT-6 Sol through T3 delegation.