From b49bcd430758bacb884cfeb09d050a17f3f742a8 Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Fri, 4 Sep 2026 03:15:26 -0400 Subject: [PATCH] fix(cli): label the worker-read PTY verdict as terminal liveness The line printed the PTY verdict with the same word the fleet verdict uses, so a live pane holding a dead agent read as "Liveness: live". It is now "Terminal liveness", with "Agent liveness" printed from the fleet projection when the receipt carries one. --- .../orchestration/worker-output.test.ts | 26 ++++++++++++++++++- .../handlers/orchestration/worker-output.ts | 8 +++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/cli/handlers/orchestration/worker-output.test.ts b/src/cli/handlers/orchestration/worker-output.test.ts index bcffb1815ff..c58d1188448 100644 --- a/src/cli/handlers/orchestration/worker-output.test.ts +++ b/src/cli/handlers/orchestration/worker-output.test.ts @@ -171,6 +171,30 @@ describe('worker-read plain formatting', () => { 'No transcript messages returned. This exact transcript read did not request terminal evidence.' ) }) + it('separates the PTY verdict from the fleet agent verdict', () => { + const output = formatWorkerRead({ + dispatchId: 'dispatch_1', + status: { worker: 'ready', terminal: 'running', liveness: 'live' }, + projection: { liveness: 'unverifiable' }, + source: 'terminal', + sourceIdentity: 'private-source-identity', + terminal: { + handle: 'term_worker', + status: 'running', + tail: ['tail'], + truncated: false, + nextCursor: null + }, + cursor: null, + fallbackReason: null, + warnings: [] + } as unknown as OrchestrationWorkerReadResult) + + expect(output).toContain('Terminal liveness: live') + expect(output).toContain('Agent liveness: unverifiable') + expect(output).not.toMatch(/^Liveness:/mu) + }) + it('distinguishes a released archive read from a live one', () => { const output = formatWorkerRead({ dispatchId: 'dispatch_1', @@ -191,7 +215,7 @@ describe('worker-read plain formatting', () => { } as unknown as OrchestrationWorkerReadResult) expect(output).toContain('Archived: true') - expect(output).toContain('Liveness: unverifiable') + expect(output).toContain('Terminal liveness: unverifiable') expect(output).toContain('Worker: succeeded') }) }) diff --git a/src/cli/handlers/orchestration/worker-output.ts b/src/cli/handlers/orchestration/worker-output.ts index cf2541ccb84..61fab616b2d 100644 --- a/src/cli/handlers/orchestration/worker-output.ts +++ b/src/cli/handlers/orchestration/worker-output.ts @@ -73,8 +73,14 @@ function formatWorkerReadDetails(value: OrchestrationWorkerReadResult): string { lines.push(`Worker: ${value.status.worker}`) } lines.push(`Archived: ${value.archived === true}`) + // Two different verdicts: status.liveness is the PTY's, the fleet projection is the agent's. if (value.status?.liveness) { - lines.push(`Liveness: ${value.status.liveness}`) + lines.push(`Terminal liveness: ${value.status.liveness}`) + } + const agentLiveness = (value as { projection?: { liveness?: string } | null }).projection + ?.liveness + if (agentLiveness) { + lines.push(`Agent liveness: ${agentLiveness}`) } if (value.sourceExact !== undefined) { lines.push(`Source exact: ${value.sourceExact}`)