diff --git a/src/main/daemon/daemon-pty-adapter-protocol-compatibility.test.ts b/src/main/daemon/daemon-pty-adapter-protocol-compatibility.test.ts index 8132f2de4e2..3fc255b60ec 100644 --- a/src/main/daemon/daemon-pty-adapter-protocol-compatibility.test.ts +++ b/src/main/daemon/daemon-pty-adapter-protocol-compatibility.test.ts @@ -243,16 +243,29 @@ describe('DaemonPtyAdapter (IPtyProvider)', () => { }) describe('background stream thinning compatibility', () => { - it('reports authoritative snapshot support only for the corrected serializer protocol', () => { + it('reports authoritative snapshot support only for the corrected serializer protocol', async () => { + const { id } = await adapter.spawn({ cols: 80, rows: 24 }) const legacy = new DaemonPtyAdapter({ socketPath, tokenPath, protocolVersion: 31 }) try { - expect(legacy.canProvideAuthoritativeBufferSnapshot('legacy-session')).toBe(false) - expect(adapter.canProvideAuthoritativeBufferSnapshot('current-session')).toBe(true) + expect(legacy.canProvideAuthoritativeBufferSnapshot(id)).toBe(false) + expect(adapter.canProvideAuthoritativeBufferSnapshot(id)).toBe(true) } finally { legacy.dispose() } }) + // Why this matters beyond tidiness: getProviderForPty falls back to the local provider for + // any id it cannot place, so these ids reach this adapter for real. Answered from the + // protocol flag alone they came back `true`, which the renderer caches as a definitive + // per-pty licence to unmount a pane whose bytes this daemon never held. + it('refuses an authoritative snapshot claim for a session it does not own', async () => { + const { id } = await adapter.spawn({ cols: 80, rows: 24 }) + + expect(adapter.canProvideAuthoritativeBufferSnapshot(id)).toBe(true) + expect(adapter.canProvideAuthoritativeBufferSnapshot('remote:env-1:pty-1')).toBe(false) + expect(adapter.canProvideAuthoritativeBufferSnapshot('never-spawned-session')).toBe(false) + }) + it('reports background state on the authoritative-snapshot protocol', () => { const notifySpy = vi.spyOn(DaemonClient.prototype, 'notify') try { diff --git a/src/main/daemon/daemon-pty-runtime-state.ts b/src/main/daemon/daemon-pty-runtime-state.ts index e471f698748..38480af1489 100644 --- a/src/main/daemon/daemon-pty-runtime-state.ts +++ b/src/main/daemon/daemon-pty-runtime-state.ts @@ -237,8 +237,12 @@ export abstract class DaemonPtyRuntimeState { return this.protocolVersion >= GIT_CREDENTIAL_GUARD_HOST_PROTOCOL_VERSION } - canProvideAuthoritativeBufferSnapshot(_id: string): boolean { - return this.supportsAuthoritativeBufferSnapshots + // Why the id is read rather than ignored: the contract promises a fact about THIS pty, and + // getProviderForPty falls back to the local provider for any id it cannot place. A + // remote-runtime id therefore reaches this adapter, and answering from the protocol flag + // alone returned `true` for a session this daemon has never owned. + canProvideAuthoritativeBufferSnapshot(id: string): boolean { + return this.supportsAuthoritativeBufferSnapshots && this.activeSessionIds.has(id) } protected get canDelegateBackgroundToDaemon(): boolean {