diff --git a/src/main/runtime/mobile-session-terminal-retirement-proof.ts b/src/main/runtime/mobile-session-terminal-retirement-proof.ts index 5c445515409..0c487891801 100644 --- a/src/main/runtime/mobile-session-terminal-retirement-proof.ts +++ b/src/main/runtime/mobile-session-terminal-retirement-proof.ts @@ -1,10 +1,24 @@ import type { RuntimeMobileSessionRetiredTerminalSurface, + RuntimeMobileSessionSnapshotTab, RuntimeMobileSessionTabsSnapshot } from '../../shared/runtime-types' const MAX_RETIRED_TERMINAL_SURFACE_PROOFS = 64 +const surfaceKey = (surface: { parentTabId: string; leafId: string }): string => + `${surface.parentTabId}\0${surface.leafId}` + +/** A surface published again is no longer retired, whatever handle now occupies it. */ +export function dropRetirementProofsForLiveSurfaces( + retired: readonly RuntimeMobileSessionRetiredTerminalSurface[], + tabs: readonly RuntimeMobileSessionSnapshotTab[] +): RuntimeMobileSessionRetiredTerminalSurface[] { + const live = new Set(tabs.flatMap((tab) => (tab.type === 'terminal' ? [surfaceKey(tab)] : []))) + return retired.filter((surface) => !live.has(surfaceKey(surface))) +} + +/** Renderer snapshots omit the host's durable close acknowledgements; carry them forward. */ export function preserveTerminalRetirementProofs( snapshot: RuntimeMobileSessionTabsSnapshot, existing: RuntimeMobileSessionTabsSnapshot | undefined @@ -12,22 +26,23 @@ export function preserveTerminalRetirementProofs( if ( !existing?.retiredTerminalSurfaces?.length || existing.worktree !== snapshot.worktree || + // Fence on instance identity only when both sides know it: host-authored snapshots never set it. (existing.worktreeInstanceId !== undefined && snapshot.worktreeInstanceId !== undefined && existing.worktreeInstanceId !== snapshot.worktreeInstanceId) ) { return snapshot } - const liveSurfaces = new Set( - snapshot.tabs.flatMap((tab) => - tab.type === 'terminal' ? [`${tab.parentTabId}\0${tab.leafId}`] : [] + return { + ...snapshot, + retiredTerminalSurfaces: dropRetirementProofsForLiveSurfaces( + appendRetiredTerminalSurfaceProofs( + existing.retiredTerminalSurfaces, + snapshot.retiredTerminalSurfaces ?? [] + ), + snapshot.tabs ) - ) - const retiredTerminalSurfaces = appendRetiredTerminalSurfaceProofs( - existing.retiredTerminalSurfaces, - snapshot.retiredTerminalSurfaces ?? [] - ).filter((surface) => !liveSurfaces.has(`${surface.parentTabId}\0${surface.leafId}`)) - return { ...snapshot, retiredTerminalSurfaces } + } } export function appendRetiredTerminalSurfaceProofs( diff --git a/src/main/runtime/orca-runtime-runtime-id.ts b/src/main/runtime/orca-runtime-runtime-id.ts index 336c5e77364..ed4302f6e4b 100644 --- a/src/main/runtime/orca-runtime-runtime-id.ts +++ b/src/main/runtime/orca-runtime-runtime-id.ts @@ -103,7 +103,6 @@ export class OrcaRuntimeWithRuntimeId { snapshot: RuntimeMobileSessionTabsSnapshot ): RuntimeMobileSessionTabsSnapshot { const existing = this.mobileSessionTabsByWorktree.get(worktreeId) - // Renderer snapshots do not carry the host's durable close acknowledgements. snapshot = preserveTerminalRetirementProofs(snapshot, existing) const snapshotVersion = existing ? Math.max(snapshot.snapshotVersion, existing.snapshotVersion + 1) diff --git a/src/main/runtime/runtime-mobile-session-result-finalization.ts b/src/main/runtime/runtime-mobile-session-result-finalization.ts index 2c3af07b6f9..1848ae56793 100644 --- a/src/main/runtime/runtime-mobile-session-result-finalization.ts +++ b/src/main/runtime/runtime-mobile-session-result-finalization.ts @@ -1,4 +1,5 @@ import type { RuntimeMobileSessionTabsResult } from '../../shared/runtime-types' +import { dropRetirementProofsForLiveSurfaces } from './mobile-session-terminal-retirement-proof' import type { RuntimeMobileSessionProjectionHost, RuntimeMobileSessionProjectionInput @@ -41,14 +42,9 @@ export function finalizeRuntimeMobileSessionTabsResult( ...(snapshot.tabGroupLayout !== undefined ? { tabGroupLayout } : {}), ...(snapshot.retiredTerminalSurfaces ? { - retiredTerminalSurfaces: snapshot.retiredTerminalSurfaces.filter( - (retired) => - !snapshot.tabs.some( - (tab) => - tab.type === 'terminal' && - tab.parentTabId === retired.parentTabId && - tab.leafId === retired.leafId - ) + retiredTerminalSurfaces: dropRetirementProofsForLiveSurfaces( + snapshot.retiredTerminalSurfaces, + snapshot.tabs ) } : {}),