diff --git a/apps/desktop/src/app/gateway/hooks/use-gateway-boot.test.tsx b/apps/desktop/src/app/gateway/hooks/use-gateway-boot.test.tsx index 3c592f346d..097943d981 100644 --- a/apps/desktop/src/app/gateway/hooks/use-gateway-boot.test.tsx +++ b/apps/desktop/src/app/gateway/hooks/use-gateway-boot.test.tsx @@ -9,7 +9,7 @@ import { selectConnection, setConnectionsRegistry } from '@/store/connections' -import { closeSecondaryGateways, isActivePrimary } from '@/store/gateway' +import { closeSecondaryGateways, isActivePrimary, requestGatewayForAgent } from '@/store/gateway' import { reconnectGateway } from '@/store/gateway-reconnect' import { $gatewaySwitching, @@ -869,6 +869,17 @@ describe('useGatewayBoot remote reconnect loop (real hook, fake socket)', () => expect(configPublications).toEqual(['settings-b']) }) + it('publishes the cold-boot primary registry identity for owned session RPCs', async () => { + render() + await flushAsync() + + expect($gatewayState.get()).toBe('open') + expect(FakeWebSocket.instances).toHaveLength(1) + + await expect(requestGatewayForAgent('primary-vps', 'default', 'ping')).resolves.toEqual({ pong: true }) + expect(FakeWebSocket.instances).toHaveLength(1) + }) + it('re-fetches the profile rail from the NEW backend after a connection apply (#85731)', async () => { // The reported repro: connected to backend A, the rail shows A's named // profiles; the user applies a different remote/Cloud connection (soft diff --git a/apps/desktop/src/store/gateway-profile-request.test.ts b/apps/desktop/src/store/gateway-profile-request.test.ts index 3721a7b975..5c2c16a28d 100644 --- a/apps/desktop/src/store/gateway-profile-request.test.ts +++ b/apps/desktop/src/store/gateway-profile-request.test.ts @@ -42,7 +42,7 @@ vi.mock('@/hermes', () => ({ }, setApiRequestConnection: vi.fn() })) -vi.mock('@/store/session', () => ({ setGatewayState: vi.fn() })) +vi.mock('@/store/session', () => ({ setConnection: vi.fn(), setGatewayState: vi.fn() })) vi.mock('@/store/notify-baseline', () => ({ markNativeNotifyBaseline: vi.fn() })) const { @@ -213,6 +213,9 @@ describe('requestGatewayForAgent', () => { } await ensureGatewayForProfile('default') + await openGatewayForAgent('remote-primary', 'default') + await ensureGatewayForAgent('remote-primary', 'default') + const result = await requestGatewayForAgent('remote-primary', 'default', 'session.resume', { session_id: 'stored-session' }) diff --git a/apps/desktop/src/store/gateway.ts b/apps/desktop/src/store/gateway.ts index 2f0a48e350..6186cefaa6 100644 --- a/apps/desktop/src/store/gateway.ts +++ b/apps/desktop/src/store/gateway.ts @@ -202,6 +202,12 @@ export function setPrimaryGatewayConnection(connection: Pick( // "session not found" while REST history from the primary remains visible. // Require both owner identities to agree before collapsing the route; a // different source or profile must retain its isolated secondary. - if ( - key === g.primaryProfile && - Boolean(g.primaryConnectionId) && - g.primaryConnectionId === String(connectionId).trim() - ) { + if (isPrimaryRegistryRoute(connectionId, key)) { return requestGatewayForProfile(key, method, params, timeoutMs, signal) } @@ -907,7 +909,7 @@ export async function openGatewayForAgent( ): Promise { const scope = registryBackendScopeKey(connectionId, profile) - if (scope === normKey(profile)) { + if (scope === normKey(profile) || isPrimaryRegistryRoute(connectionId, profile)) { return openGatewayForProfile(profile) } @@ -947,7 +949,7 @@ export async function ensureGatewayForAgent( ): Promise { const scope = registryBackendScopeKey(connectionId, profile) - if (scope === normKey(profile)) { + if (scope === normKey(profile) || isPrimaryRegistryRoute(connectionId, profile)) { if (signal?.aborted) { return false }