fix(orcad): a connected but unused SSH host previews as movable (#24609)

The untransferred-dependency census counted activeConnectionIdsAtShutdown naming the
target as workspace-session state. The renderer rewrites that list on every connection
change, so merely connecting to an empty host blocked the move. It is a reconnect hint;
the remote work it can stand for is counted on its own. The empty-target claim check
likewise ignores global-field copies inside the host's session partition.

Co-authored-by: m4air <m4air@Mac.localdomain>
This commit is contained in:
OrcaWin
2026-10-02 02:22:31 -07:00
committed by GitHub
co-authored by m4air
parent d0d6977644
commit d6925c93c9
4 changed files with 44 additions and 4 deletions
@@ -97,9 +97,8 @@ export function countUnsupportedSessionState(
? 1
: 0
count += session.activeWorkspaceExecutionHostId === scope.hostId && !sourceHostPartition ? 1 : 0
count += (session.activeConnectionIdsAtShutdown ?? []).filter(
(targetId) => targetId === scope.targetId
).length
// activeConnectionIdsAtShutdown is not counted: it is the renderer's live "connected now" hint, and
// the remote work it can stand for (tab PTYs, remote session ids, leases) is counted on its own.
count +=
session.activeTabId && terminalTabIds.has(session.activeTabId) && !sourceHostPartition ? 1 : 0
for (const [ownerKey, files] of Object.entries(session.openFilesByWorktree ?? {})) {
@@ -25,6 +25,29 @@ describe('client state that still references an SSH target', () => {
expect(blockersFor({ getWorkspaceSessionHostIds: () => ['local', HOST] })).toEqual([])
})
it('ignores a connected host: the reconnect hint and global copies in its partition', () => {
const connected = {
...getDefaultWorkspaceSession(),
activeConnectionIdsAtShutdown: ['ssh-1'],
activeWorktreeId: 'local-wt',
browserUrlHistory: [
{
url: 'https://example.com',
normalizedUrl: 'https://example.com',
title: 'Example',
lastVisitedAt: 1,
visitCount: 1
}
]
}
expect(
blockersFor({
getWorkspaceSessionHostIds: () => ['local', HOST],
getWorkspaceSession: () => connected
})
).toEqual([])
})
it('blocks on the host session partition and names the fields holding state', () => {
const blockers = blockersFor({
getWorkspaceSessionHostIds: () => ['local', HOST],
+7 -1
View File
@@ -5,6 +5,7 @@
import type { Store } from '../persistence'
import { getDefaultWorkspaceSession } from '../../shared/constants'
import { toSshExecutionHostId } from '../../shared/execution-host'
import { GLOBAL_WORKSPACE_SESSION_FIELDS } from '../../shared/workspace-session-host-field-ownership'
import {
ORCAD_MIGRATION_DEPENDENCY_KINDS,
type OrcadMigrationBlocker,
@@ -112,7 +113,7 @@ export function collectUntransferredDependentBlockers(
: []
}
/** Non-default fields of the host's session partition, plus a local session pointed at the host. */
/** Non-default host-owned fields of the host's partition, plus a local session pointed at the host. */
function workspaceSessionReferences(store: DependentStateStore, hostId: string): string[] {
const references: string[] = []
if (store.getWorkspaceSession().activeWorkspaceExecutionHostId === hostId) {
@@ -122,7 +123,12 @@ function workspaceSessionReferences(store: DependentStateStore, hostId: string):
return references
}
const defaults: Record<string, unknown> = { ...getDefaultWorkspaceSession() }
// A partition's global fields are copies of client-wide focus and history, not host state.
const globalFields = new Set<string>(GLOBAL_WORKSPACE_SESSION_FIELDS)
for (const [field, value] of Object.entries(store.getWorkspaceSession(hostId))) {
if (globalFields.has(field)) {
continue
}
if (!isEmptyValue(value) && JSON.stringify(value) !== JSON.stringify(defaults[field])) {
references.push(field)
}
@@ -72,6 +72,18 @@ describe('migration export preflight', () => {
])
})
it('previews a connected but unused host as movable with no blockers', () => {
const store = preflightStore((store) => {
store.addSshTarget(TARGET)
// What the renderer writes on connect: the reconnect hint names the now-connected target.
store.patchWorkspaceSession({ activeConnectionIdsAtShutdown: [TARGET.id] })
})
expect(preflightOrcadMigrationExport(store, TARGET.id)).toMatchObject({
claimable: true,
blockers: []
})
})
it('blocks on a live relay terminal, which cannot move', () => {
const lease: SshRemotePtyLease = {
targetId: TARGET.id,