diff --git a/src/renderer/src/app-shell/remote-workspace-unplaced-upload-suppression.test.tsx b/src/renderer/src/app-shell/remote-workspace-unplaced-upload-suppression.test.tsx index 1ade1716d65..28724c4068b 100644 --- a/src/renderer/src/app-shell/remote-workspace-unplaced-upload-suppression.test.tsx +++ b/src/renderer/src/app-shell/remote-workspace-unplaced-upload-suppression.test.tsx @@ -227,7 +227,8 @@ describe('uploads from a client that could not place the host tabs', () => { const persistence = renderHook(() => useAppSessionPersistence()) const sync = createSync() - expect(await sync.applyUnsolicitedSnapshot(TARGET_ID, snapshot())).toBe('placed') + await sync.applyUnsolicitedSnapshot(TARGET_ID, snapshot()) + // Adoption is the observable outcome; the apply reports nothing back by design. expect(useAppStore.getState().tabsByWorktree[WORKTREE_ID]?.map((tab) => tab.id)).toEqual([ 'T1', 'T2' diff --git a/src/renderer/src/hooks/remote-workspace-snapshot-apply.ts b/src/renderer/src/hooks/remote-workspace-snapshot-apply.ts index d1657d56f1f..68af13743fa 100644 --- a/src/renderer/src/hooks/remote-workspace-snapshot-apply.ts +++ b/src/renderer/src/hooks/remote-workspace-snapshot-apply.ts @@ -74,16 +74,6 @@ function currentRecoveryTabIds( ) } -/** - * `placed` — every terminal-tab row in the snapshot landed on a local workspace, so this client's - * picture is the host's and may be declared authoritative. - * `unplaced` — the snapshot carried tab rows whose worktree path the local catalog could not - * resolve. That is `unverifiable` (the host lineage read came back degraded, so `worktreesByRepo` - * is still empty), never proof the rows are not ours — so the target stays un-hydrated and the - * caller re-pulls. See docs/reference/ssh-execution-boundary.md. - */ -export type DirectSshSnapshotPlacement = 'placed' | 'unplaced' | 'not-applied' - export async function applyDirectSshRemoteWorkspaceSnapshot({ store, snapshot, @@ -93,16 +83,16 @@ export async function applyDirectSshRemoteWorkspaceSnapshot({ isPreparationTokenCurrent, waitForWorkspaceSessionReady, finalizeHydratedTerminals -}: RemoteWorkspaceSnapshotApplyInput): Promise { +}: RemoteWorkspaceSnapshotApplyInput): Promise { const { authority } = token if (!isArrivalCurrent(authority.targetId, arrival)) { - return 'not-applied' + return } if ( !isPreparationTokenCurrent(token) || !admitDirectSshSnapshotApplyToken(token, authority, snapshot.revision) ) { - return 'not-applied' + return } if (!(await waitForWorkspaceSessionReady())) { if (isArrivalCurrent(authority.targetId, arrival) && isPreparationTokenCurrent(token)) { @@ -115,7 +105,7 @@ export async function applyDirectSshRemoteWorkspaceSnapshot({ ) }) } - return 'not-applied' + return } const state = store.getState() const worktreeIds = exactTargetWorktreeIds(state, authority) @@ -135,10 +125,9 @@ export async function applyDirectSshRemoteWorkspaceSnapshot({ snapshot.revision ) if (!isArrivalCurrent(authority.targetId, arrival) || !isPreparationTokenCurrent(token)) { - return 'not-applied' + return } - const placement: DirectSshSnapshotPlacement = - unplacedTabWorktreePaths.length > 0 ? 'unplaced' : 'placed' + const hasUnplacedTerminalTabs = unplacedTabWorktreePaths.length > 0 snapshotApplyDepth += 1 try { const currentStore = store.getState() @@ -149,7 +138,7 @@ export async function applyDirectSshRemoteWorkspaceSnapshot({ }) currentStore.hydrateTabsSession(merged, { replaceWorkspaceKeys }) // Why: direct SSH snapshots project terminal state only; global editor/browser hydration would reset unrelated hosts. - if (placement === 'placed') { + if (!hasUnplacedTerminalTabs) { currentStore.markRemoteWorkspaceHydrated(authority.targetId) currentStore.setRemoteWorkspaceSyncStatus(authority.targetId, { phase: 'synced', @@ -207,5 +196,4 @@ export async function applyDirectSshRemoteWorkspaceSnapshot({ snapshotWriteSuppressUntil = Date.now() + REMOTE_WORKSPACE_SNAPSHOT_WRITE_SUPPRESS_MS snapshotApplyDepth -= 1 } - return placement } diff --git a/src/renderer/src/hooks/remote-workspace-target-sync.ts b/src/renderer/src/hooks/remote-workspace-target-sync.ts index d9cf3cff7c7..260c3e50b8c 100644 --- a/src/renderer/src/hooks/remote-workspace-target-sync.ts +++ b/src/renderer/src/hooks/remote-workspace-target-sync.ts @@ -15,10 +15,7 @@ import type { } from './direct-ssh-reconnect-coordinator' import { buildDirectSshSnapshotApplyToken } from './direct-ssh-reconnect-coordinator' import { resolveDirectSshTargetScope } from '../lib/direct-ssh-target-scope' -import { - applyDirectSshRemoteWorkspaceSnapshot, - type DirectSshSnapshotPlacement -} from './remote-workspace-snapshot-apply' +import { applyDirectSshRemoteWorkspaceSnapshot } from './remote-workspace-snapshot-apply' const WORKSPACE_HYDRATION_TIMEOUT_MS = 10_000 @@ -46,10 +43,7 @@ export type RemoteWorkspaceTargetSyncDeps = { export type RemoteWorkspaceTargetSync = { syncAfterConnect: (token: DirectSshPreparationToken) => Promise - applyUnsolicitedSnapshot: ( - targetId: string, - snapshot: RemoteWorkspaceSnapshot - ) => Promise + applyUnsolicitedSnapshot: (targetId: string, snapshot: RemoteWorkspaceSnapshot) => Promise stop: () => void } @@ -217,11 +211,11 @@ export function createRemoteWorkspaceTargetSync( const applyUnsolicitedSnapshot = async ( targetId: string, snapshot: RemoteWorkspaceSnapshot - ): Promise => { + ): Promise => { const arrival = beginArrival(targetId) const authority = deps.getCurrentAuthority(targetId) if (!authority) { - return 'not-applied' + return } const input = await deps.capturePreparationInput( authority, @@ -229,17 +223,17 @@ export function createRemoteWorkspaceTargetSync( snapshot.revision ) if (!input || !isArrivalCurrent(targetId, arrival)) { - return 'not-applied' + return } const prepared = await deps.prepareOnly(input) if (!prepared.token || !isArrivalCurrent(targetId, arrival)) { - return 'not-applied' + return } const applyToken = buildDirectSshSnapshotApplyToken(prepared.token, snapshot.revision) if (!applyToken) { - return 'not-applied' + return } - const placement = await applyDirectSshRemoteWorkspaceSnapshot({ + await applyDirectSshRemoteWorkspaceSnapshot({ store: deps.store, snapshot, token: applyToken, @@ -249,7 +243,6 @@ export function createRemoteWorkspaceTargetSync( waitForWorkspaceSessionReady, finalizeHydratedTerminals: deps.finalizeHydratedTerminals }) - return placement } return {