fix(agent-status): preserve unverifiable remote rows

This commit is contained in:
Merge Sim
2026-09-10 14:32:10 -07:00
parent d0562329a5
commit 9471b345e7
2 changed files with 32 additions and 1 deletions
@@ -395,6 +395,30 @@ describe('headless hook agent-status projection (#11761)', () => {
statusWiring.statusStore.stop()
})
it('keeps an unverifiable remote row when its disconnected PTY record is pruned', async () => {
const statusWiring = makeAgentStatusStoreWiring()
const runtime = await createRuntimeWithHookRows([], statusWiring)
const internals = runtime as unknown as {
ptysById: Map<string, { connected: boolean; connectionId: string | null }>
dropDisconnectedPtyRecord: (ptyId: string) => void
}
const pty = internals.ptysById.get(PTY_ID)!
pty.connectionId = 'ssh-target'
runtime.onPtyData(
PTY_ID,
'\x1b]9999;{"state":"working","prompt":"remote work","agentType":"claude"}\x07',
1
)
pty.connected = false
internals.dropDisconnectedPtyRecord(PTY_ID)
expect(statusWiring.statusStore.getStatusSnapshot()).toEqual([
expect.objectContaining({ connectionId: 'ssh-target', prompt: 'remote work' })
])
statusWiring.statusStore.stop()
})
it('evicts a dismissed handle-joined remnant on certified PTY exit', async () => {
const statusWiring = makeAgentStatusStoreWiring()
const runtime = await createRuntimeWithHookRows([], statusWiring)
@@ -119,7 +119,14 @@ export class OrcaRuntimeWithRefreshFloatingWorkspacePtyLiveness extends OrcaRunt
protected dropDisconnectedPtyRecord(ptyId: string): void {
// Why: pruning can remove a PTY without the normal exit callback.
this.reconcileAgentStatusForEndedProcessFn?.(this.collectAgentStatusPaneKeysForPty(ptyId))
const pty = this.ptysById.get(ptyId)
// Remote disconnect is unverifiable; its host-owned status survives until certified exit.
const processDeathCertified =
pty?.connectionId === null ||
this.ptyLivenessVerdictByPtyId.get(ptyId)?.verdict.status === 'exited'
if (processDeathCertified) {
this.reconcileAgentStatusForEndedProcessFn?.(this.collectAgentStatusPaneKeysForPty(ptyId))
}
this.advancePtyLifecycleGeneration(ptyId)
this.pairedRendererSessionOwnedPtyIds.delete(ptyId)
this.ptysById.delete(ptyId)