From 45d303efbaef480c9f11aff20d35763c9b4e8447 Mon Sep 17 00:00:00 2001 From: Merge Sim Date: Mon, 31 Aug 2026 11:10:46 -0700 Subject: [PATCH] fix(runtime): fence diagnostics by shared-control capability --- .../runtime-status-diagnostics-generation.ts | 4 ++- .../slices/runtime-status-diagnostics.test.ts | 32 +++++++++++++++++-- ...-runtime-shared-control-connection.test.ts | 5 +++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/store/slices/runtime-status-diagnostics-generation.ts b/src/renderer/src/store/slices/runtime-status-diagnostics-generation.ts index 9e94cbc77c9..b6fabe7f49b 100644 --- a/src/renderer/src/store/slices/runtime-status-diagnostics-generation.ts +++ b/src/renderer/src/store/slices/runtime-status-diagnostics-generation.ts @@ -1,3 +1,5 @@ +import { REMOTE_RUNTIME_SHARED_CONTROL_CAPABILITY } from '../../../../shared/protocol-version' + const diagnosticsGenerationByEnvironment = new Map() export function acceptRuntimeEnvironmentDiagnosticsGeneration( @@ -25,7 +27,7 @@ export function mergePushedRuntimeEnvironmentDiagnostics(args: { }): void { if ( !acceptRuntimeEnvironmentDiagnosticsGeneration(args.environmentId, args.transportGeneration) || - !args.current?.status + !args.current?.status?.capabilities?.includes(REMOTE_RUNTIME_SHARED_CONTROL_CAPABILITY) ) { return } diff --git a/src/renderer/src/store/slices/runtime-status-diagnostics.test.ts b/src/renderer/src/store/slices/runtime-status-diagnostics.test.ts index 29469ff6284..9faecdcabf1 100644 --- a/src/renderer/src/store/slices/runtime-status-diagnostics.test.ts +++ b/src/renderer/src/store/slices/runtime-status-diagnostics.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from 'vitest' import { create } from 'zustand' +import { REMOTE_RUNTIME_SHARED_CONTROL_CAPABILITY } from '../../../../shared/protocol-version' import type { RuntimeStatus } from '../../../../shared/runtime-types' import { createRuntimeStatusSlice, type RuntimeStatusSlice } from './runtime-status' @@ -27,7 +28,9 @@ function createSliceStore() { describe('runtime-status diagnostics', () => { it('merges transport diagnostics into the complete status and fences stale pushes', () => { const store = createSliceStore() - const status = makeStatus() + const status = makeStatus({ + capabilities: ['browser.screencast.v1', REMOTE_RUNTIME_SHARED_CONTROL_CAPABILITY] + }) store.getState().setRuntimeEnvironmentStatus('env-a', { status, checkedAt: 1 }) const closed = { state: 'closed' as const, @@ -45,7 +48,10 @@ describe('runtime-status diagnostics', () => { }) expect(store.getState().runtimeStatusByEnvironmentId.get('env-a')?.status).toMatchObject({ runtimeId: 'runtime-a', - capabilities: ['browser.screencast.v1'], + capabilities: expect.arrayContaining([ + 'browser.screencast.v1', + REMOTE_RUNTIME_SHARED_CONTROL_CAPABILITY + ]), liveTabCount: 3, remoteControl: closed }) @@ -58,4 +64,26 @@ describe('runtime-status diagnostics', () => { store.getState().runtimeStatusByEnvironmentId.get('env-a')?.status?.remoteControl?.state ).toBe('closed') }) + + it('ignores diagnostics after the latest status drops shared-control support', () => { + const store = createSliceStore() + const status = makeStatus({ capabilities: [] }) + store.getState().setRuntimeEnvironmentStatus('env-a', { status, checkedAt: 1 }) + + store.getState().publishRuntimeEnvironmentDiagnostics({ + environmentId: 'env-a', + transportGeneration: 3, + diagnostics: { + state: 'reconnecting', + pendingRequestCount: 0, + subscriptionCount: 1, + reconnectAttempt: 2, + lastConnectedAt: 1, + lastClose: { code: 1006, reason: 'network' }, + lastError: 'connection lost' + } + }) + + expect(store.getState().runtimeStatusByEnvironmentId.get('env-a')?.status).toBe(status) + }) }) diff --git a/src/shared/remote-runtime-shared-control-connection.test.ts b/src/shared/remote-runtime-shared-control-connection.test.ts index 466dbf3c972..e55805725c4 100644 --- a/src/shared/remote-runtime-shared-control-connection.test.ts +++ b/src/shared/remote-runtime-shared-control-connection.test.ts @@ -32,11 +32,16 @@ describe('RemoteRuntimeSharedControlConnection', () => { expect(first).toMatchObject({ ok: true, result: { method: 'worktree.ps' } }) expect(second).toMatchObject({ ok: true, result: { method: 'session.tabs.listAll' } }) + expect(server.connectionCount()).toBe(1) expect(server.auths).toContainEqual({ type: 'e2ee_auth', deviceToken: 'device-token', clientCapabilities: remoteRuntimeClientCapabilities() }) + expect(server.requests.map((request) => request.method)).toEqual([ + 'worktree.ps', + 'session.tabs.listAll' + ]) expect((connection.close(), states)).toEqual( expect.arrayContaining(['awaiting_ready', 'ready', 'closed']) )