From e5a4d5c0749a8e43a082b5fd251cfa76ae11c3cf Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Tue, 14 Jul 2026 02:21:15 -0700 Subject: [PATCH] fix(terminal): skip output for certified-dead renderers --- .../pane-manager/pane-terminal-output-scheduler.test.ts | 3 +++ .../src/lib/pane-manager/pane-terminal-output-scheduler.ts | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts b/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts index d14defde9d9..92a5a2b5828 100644 --- a/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts +++ b/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts @@ -1534,6 +1534,9 @@ describe('pane terminal output scheduler', () => { expect(hasTerminalParseProgressSince(terminal, generation)).toBe(false) expect(recoveryReasons).toEqual(['write-stalled']) expect(isTerminalWritePipelineCertifiedDead(terminal)).toBe(true) + // Only the first rejection touches xterm; later PTY deliveries credit + // directly while recovery owns the certified-dead instance. + expect(terminal.write).toHaveBeenCalledTimes(1) expect(onParsed).not.toHaveBeenCalled() for (const ackCredit of ackCredits) { expect(ackCredit).toHaveBeenCalledTimes(1) diff --git a/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.ts b/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.ts index 4e1e08284cd..a641f0b0f81 100644 --- a/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.ts +++ b/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.ts @@ -21,6 +21,7 @@ import { armTerminalWriteStallWatch, cancelTerminalWriteStallWatch, failTerminalWriteStallWatch, + isTerminalWritePipelineCertifiedDead, settleTerminalWriteStallWatch } from './terminal-write-pipeline-health' import { @@ -1123,6 +1124,12 @@ export function writeTerminalOutput( options: WriteTerminalOutputOptions ): void { exposeDebugApi() + // Why: recovery may be budget-delayed while PTY output keeps flowing. Main + // owns the authoritative buffer; credit delivery without waking dead xterm. + if (isTerminalWritePipelineCertifiedDead(terminal)) { + options.ackCredit?.() + return + } if (!data) { // Why: an empty write still consumed its delivery — credit or main's // in-flight window leaks.