fix(desktop): let a per-profile remote override win over the forced-local route (#90477)
resolveRegistryLocalRoute collapsed globalRemote and profileRemoteOverride into one forced-local branch. The two cases are different: - globalRemote: forcing "This device" to spawn genuinely-local children is the intended migration behavior — unchanged. - profileRemoteOverride: the per-profile SSH/remote override is an explicit, authoritative routing decision for that profile. Forcing local made the roster enumerate the profile via its override but open the thread in a forced-local child, which dies with 'Profile "x" no longer exists' when the profile only exists on the remote — reproduced on a macOS Desktop in global SSH mode where mythony-agent/q-agent exist only on the NAS. The registry 'local' entry now delegates to the legacy profile route when a per-profile override is present, so the override stays authoritative. Tests: the override case now pins delegation, and a new witness pins that globalRemote alone still forces local; both contracts are asserted together. 88 connection-registry + 91 remote-lifecycle + 73 routing tests pass; tsc --build clean.
This commit is contained in:
@@ -697,9 +697,22 @@ test('registry local route: v1 REMOTE global mode forces a genuinely-local backe
|
||||
assert.notEqual(route.poolKey, backendScopeKey(LOCAL_CONNECTION_ID, 'default'))
|
||||
})
|
||||
|
||||
test('registry local route: a per-profile remote override also forces local', () => {
|
||||
test('registry local route: a per-profile remote override delegates to the override (#90477)', () => {
|
||||
// The per-profile SSH/remote override is the authoritative route for that
|
||||
// profile. Forcing local here made the roster list the profile via its
|
||||
// override but open the thread in a local child — which fails when the
|
||||
// profile exists only on the remote. The override must win.
|
||||
const route = resolveRegistryLocalRoute('research', { profileRemoteOverride: true })
|
||||
|
||||
assert.deepEqual(route, { delegate: true, poolKey: 'research' })
|
||||
})
|
||||
|
||||
test('registry local route: global remote keeps forced-local even when a profile override is absent', () => {
|
||||
// Witness for the other half of the split: app-global remote mode still
|
||||
// forces "This device" to spawn genuinely-local children (migration
|
||||
// scenario above) — only the per-profile override delegates.
|
||||
const route = resolveRegistryLocalRoute('research', { globalRemote: true })
|
||||
|
||||
assert.deepEqual(route, { delegate: false, poolKey: 'conn:local::research' })
|
||||
})
|
||||
|
||||
|
||||
@@ -493,7 +493,17 @@ export function resolveRegistryLocalRoute(
|
||||
): RegistryLocalRoute {
|
||||
const profileKey = String(profile ?? '').trim() || 'default'
|
||||
|
||||
if (opts.globalRemote || opts.profileRemoteOverride) {
|
||||
// A per-profile SSH/remote override is an explicit per-profile routing
|
||||
// decision: the override owns this profile's backend, so the 'local' entry
|
||||
// must delegate to the legacy profile route (which resolves the override),
|
||||
// not spawn a forced-local child. Forcing local here is the #90477 split:
|
||||
// the roster lists the profile via its override, but opening the thread
|
||||
// spawned a local backend that fails when the profile doesn't exist locally.
|
||||
if (opts.profileRemoteOverride) {
|
||||
return { delegate: true, poolKey: profileKey }
|
||||
}
|
||||
|
||||
if (opts.globalRemote) {
|
||||
return { delegate: false, poolKey: `${backendScopePrefix(LOCAL_CONNECTION_ID)}${profileKey}` }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user