From 03a785aadd3c0a2edf70de80efe37e2a6f361ff4 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Sun, 16 Aug 2026 19:57:18 -0700 Subject: [PATCH] fix(orchestration): expose unverifiable read liveness --- .../rpc/methods/orchestration-federation-control.ts | 13 ++++++++++++- .../rpc/methods/orchestration-worker-control.ts | 13 ++++++++++++- .../rpc/methods/orchestration-worker-output.test.ts | 13 +++++++++++++ .../rpc/methods/orchestration-worker-output.ts | 13 +++++++++++-- src/shared/orchestration-worker-output.ts | 3 +++ 5 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/main/runtime/rpc/methods/orchestration-federation-control.ts b/src/main/runtime/rpc/methods/orchestration-federation-control.ts index 4f186fb7cc2..eb8a29bce74 100644 --- a/src/main/runtime/rpc/methods/orchestration-federation-control.ts +++ b/src/main/runtime/rpc/methods/orchestration-federation-control.ts @@ -91,7 +91,18 @@ export const ORCHESTRATION_FEDERATION_CONTROL_METHODS: RpcMethod[] = [ dispatchId: params.dispatchId, terminalHandle: observation.terminal.handle, workerState: attachment.state, - terminalStatus: observation.status === 'exited' ? 'exited' : 'running', + terminalStatus: + observation.status === 'exited' + ? 'exited' + : observation.status === 'unverifiable' + ? 'unknown' + : 'running', + terminalLiveness: + observation.status === 'unverifiable' + ? 'unverifiable' + : observation.status === 'exited' + ? 'exited' + : 'live', attachedAt: attachment.created_at, source: params.source, cursor: params.cursor, diff --git a/src/main/runtime/rpc/methods/orchestration-worker-control.ts b/src/main/runtime/rpc/methods/orchestration-worker-control.ts index 917ffa61027..480e7d3db88 100644 --- a/src/main/runtime/rpc/methods/orchestration-worker-control.ts +++ b/src/main/runtime/rpc/methods/orchestration-worker-control.ts @@ -208,7 +208,18 @@ export const ORCHESTRATION_WORKER_CONTROL_METHODS: RpcMethod[] = [ dispatchId: params.dispatch, terminalHandle: worker.agent_terminal_handle, workerState: worker.state, - terminalStatus: observation.status === 'exited' ? 'exited' : 'running', + terminalStatus: + observation.status === 'exited' + ? 'exited' + : observation.status === 'unverifiable' + ? 'unknown' + : 'running', + terminalLiveness: + observation.status === 'unverifiable' + ? 'unverifiable' + : observation.status === 'exited' + ? 'exited' + : 'live', attachedAt: worker.created_at, source: params.source, cursor: params.cursor, diff --git a/src/main/runtime/rpc/methods/orchestration-worker-output.test.ts b/src/main/runtime/rpc/methods/orchestration-worker-output.test.ts index 6db96efe33d..0e24a6bced8 100644 --- a/src/main/runtime/rpc/methods/orchestration-worker-output.test.ts +++ b/src/main/runtime/rpc/methods/orchestration-worker-output.test.ts @@ -83,6 +83,19 @@ describe('exact orchestration worker output', () => { expect(readTerminal).not.toHaveBeenCalled() }) + it('reports unverifiable liveness without claiming the terminal is running', async () => { + const result = await read({ + terminalStatus: 'unknown', + terminalLiveness: 'unverifiable' + }) + + expect(result.status).toEqual({ + worker: 'ready', + terminal: 'unknown', + liveness: 'unverifiable' + }) + }) + it('reads Grok through the shared Native Chat transcript decoder', async () => { await writeFile( transcriptA, diff --git a/src/main/runtime/rpc/methods/orchestration-worker-output.ts b/src/main/runtime/rpc/methods/orchestration-worker-output.ts index 2b222f01586..bd63da46546 100644 --- a/src/main/runtime/rpc/methods/orchestration-worker-output.ts +++ b/src/main/runtime/rpc/methods/orchestration-worker-output.ts @@ -20,6 +20,7 @@ export async function readExactWorkerOutput(args: { terminalHandle: string workerState: string terminalStatus: RuntimeTerminalState + terminalLiveness?: 'live' | 'unverifiable' | 'exited' attachedAt: string source?: OrchestrationWorkerReadSource cursor?: string | number @@ -100,7 +101,11 @@ export async function readExactWorkerOutput(args: { returnedMessageCount: transcript.messages.length }, cursor: nextCursor, - status: { worker: args.workerState, terminal: args.terminalStatus }, + status: { + worker: args.workerState, + terminal: args.terminalStatus, + ...(args.terminalLiveness ? { liveness: args.terminalLiveness } : {}) + }, fallbackReason: null, warnings: transcript.warnings } @@ -145,7 +150,11 @@ async function readTerminalOutput( sourceIdentity, terminal: { ...terminal, tail: redactedTerminal.lines }, cursor: nextCursor, - status: { worker: args.workerState, terminal: terminal.status }, + status: { + worker: args.workerState, + terminal: args.terminalLiveness === 'unverifiable' ? args.terminalStatus : terminal.status, + ...(args.terminalLiveness ? { liveness: args.terminalLiveness } : {}) + }, fallbackReason: null, warnings: redactedTerminal.warnings } diff --git a/src/shared/orchestration-worker-output.ts b/src/shared/orchestration-worker-output.ts index 8e61d1d3b97..767623f96f8 100644 --- a/src/shared/orchestration-worker-output.ts +++ b/src/shared/orchestration-worker-output.ts @@ -1,6 +1,7 @@ import type { AgentProviderSessionMetadata } from './agent-session-resume' import type { AgentType, NativeChatMessage } from './native-chat-types' import type { RuntimeTerminalRead, RuntimeTerminalState } from './runtime-types' +import type { PtyLivenessVerdict } from './pty-liveness-verdict' export const ORCHESTRATION_WORKER_READ_SOURCES = ['auto', 'transcript', 'terminal'] as const export type OrchestrationWorkerReadSource = (typeof ORCHESTRATION_WORKER_READ_SOURCES)[number] @@ -41,6 +42,7 @@ export type OrchestrationWorkerReadTranscriptResult = { status: { worker: string terminal: RuntimeTerminalState + liveness?: PtyLivenessVerdict['status'] } fallbackReason: null warnings: string[] @@ -57,6 +59,7 @@ export type OrchestrationWorkerReadTerminalResult = { status: { worker: string terminal: RuntimeTerminalState + liveness?: PtyLivenessVerdict['status'] } fallbackReason: OrchestrationWorkerReadFallbackReason | null warnings: string[]