From 7845cb8b46f8d36c9a186788d6b9dbdd0caa5752 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:39:55 -0700 Subject: [PATCH] Revert "fix(terminal): report the replay destination grid from measured hidden panes" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts the behavior of 390ae5ce52, restoring the visibility gate on the replay destination-grid report. Neither position had a confirmed failure. Withholding the report leaves the host on the snapshot grid only until the next layout change after reveal — any window resize, split drag, or pane switch fires onResize and reports through the normal guard chain — whereas an unguarded send from a hidden pane is remembered before the claim branch and replayed with claim intent on the next subscribe, reaching other clients. A stale grid that self-heals is the more conservative failure than a durable wrong-grid claim, and gating matches the sibling at the hidden-snapshot restore. The condition and the test assertion are byte-identical to 6a032296b3; the comments now record the accepted tradeoff so this line is not flipped again. --- .../terminal-pane/pty-connection.test.ts | 10 +++++----- .../terminal-pane/pty-connection.ts | 19 ++++++++++++------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/renderer/src/components/terminal-pane/pty-connection.test.ts b/src/renderer/src/components/terminal-pane/pty-connection.test.ts index bfde8f99a5e..784f329a102 100644 --- a/src/renderer/src/components/terminal-pane/pty-connection.test.ts +++ b/src/renderer/src/components/terminal-pane/pty-connection.test.ts @@ -9094,10 +9094,7 @@ describe('connectPanePty', () => { expect(transport.resize.mock.calls).toEqual([]) }) - it('reports the destination grid from a background measure-lease pane', async () => { - // Why this test: the report is deliberately NOT gated on visibility here. A hidden - // pane that still measures is under the background measure lease, so its grid is - // authoritative — and reveal never re-sends it, because the pixels never changed. + it('refits but does not report the destination grid from a background measure-lease pane', async () => { const { pane, transport, replayCallback } = await connectRemoteSnapshotGridPane( 'remote:web-env-1@@pty-replay-grid-hidden', { visible: false } @@ -9106,9 +9103,12 @@ describe('connectPanePty', () => { replayCallback.current?.('remote snapshot bytes', { snapshotCols: 80, snapshotRows: 24 }) await flushAsyncTicks(20) + // A measure-lease pane is fully sized, so the fit lands — but reporting from a + // hidden pane would persist as a claim on the next subscribe. Its grid stays + // unreported until the next layout change after reveal; see the send condition. expect(pane.fitAddon.fit).toHaveBeenCalled() expect(pane.terminal.cols).toBe(120) - expect(transport.resize).toHaveBeenCalledWith(120, 40) + expect(transport.resize).not.toHaveBeenCalled() }) it('arms no fit retry after replaying into an unmeasurable pane', async () => { diff --git a/src/renderer/src/components/terminal-pane/pty-connection.ts b/src/renderer/src/components/terminal-pane/pty-connection.ts index 5d0ddb7c8fd..0f0b0052184 100644 --- a/src/renderer/src/components/terminal-pane/pty-connection.ts +++ b/src/renderer/src/components/terminal-pane/pty-connection.ts @@ -5813,16 +5813,21 @@ export function connectPanePty( } const destinationCols = pane.terminal.cols const destinationRows = pane.terminal.rows - // Why NOT gated on visibility, unlike the sibling fits: reaching here - // means the fit measured a real box, which for a hidden pane means the - // background measure lease deliberately laid it out full size — an - // authoritative grid, not hidden-layout churn. Reveal will not re-send - // it either: the pixels never changed, so fitRevealedPane skips, and - // remote PTYs are excluded from ptySizeReassertion. This is the only - // chance to report. (This path never signals SIGWINCH.) + // Why the visibility gate, matching the sibling at the hidden-snapshot + // restore: the transport remembers every viewport handed to resize() + // before the claim branch and replays it with claim intent on the next + // subscribe, so a send from a hidden pane reaches other clients as a + // durable claim. Accepted tradeoff: a background measure-lease pane is + // fully sized, so its fit succeeds and its grid then goes unreported + // until the next layout change after reveal — fitRevealedPane will not + // re-fit a pane whose pixels never changed (opacity does not affect + // getBoundingClientRect) and remote PTYs have no ptySizeReassertion + // drift repair. A stale grid until the next resize is the more + // conservative failure than an unrevocable wrong-grid claim. if ( destinationCols > 0 && destinationRows > 0 && + isRendererPtyResizeAuthoritative() && !shouldSuppressDesktopPtyResize() ) { transport.resize(destinationCols, destinationRows)