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
}