diff --git a/src/main/runtime/orca-runtime.ts b/src/main/runtime/orca-runtime.ts index c580c077885..f6689004c22 100644 --- a/src/main/runtime/orca-runtime.ts +++ b/src/main/runtime/orca-runtime.ts @@ -34101,6 +34101,12 @@ export class OrcaRuntimeService { break case 'exited': provenAbsent = isConfirmedPtyAbsence(unlistedPresence) + // The probe positively answered absence, so lost-contact doubt from an + // earlier unanswerable probe is stale; leaving it would publish a pane + // we hold proof about as `unverifiable`. + if (provenAbsent) { + this.forgetPtyLivenessVerdict(leaf.ptyId) + } break } } diff --git a/src/main/runtime/terminal-list-stale-leaf-liveness.test.ts b/src/main/runtime/terminal-list-stale-leaf-liveness.test.ts index 9288512b559..0afb3942546 100644 --- a/src/main/runtime/terminal-list-stale-leaf-liveness.test.ts +++ b/src/main/runtime/terminal-list-stale-leaf-liveness.test.ts @@ -195,6 +195,27 @@ describe('listTerminals liveness truth for restored leaves', () => { expect(runtime.getPtyLivenessVerdict('pty-proven-absent')).toBeNull() }) + // A confirmed absence is positive evidence of the exit, so lost-contact doubt + // recorded by an earlier unanswerable probe is stale. Publishing + // `connected:false` while still reporting `unverifiable` would under-report a + // pane we hold proof about. + it('clears recorded doubt when the presence query later proves the pane absent', async () => { + let answer: boolean | null = null + const runtime = makeRuntimeWithLeaf({ + leafPtyId: 'pty-doubted-then-absent', + controllerSessions: [], + hasPty: () => answer + }) + + await runtime.listTerminals(`id:${WORKTREE_ID}`) + expect(runtime.getPtyLivenessVerdict('pty-doubted-then-absent')?.status).toBe('unverifiable') + + answer = false + const { terminals } = await runtime.listTerminals(`id:${WORKTREE_ID}`) + expect(terminals[0]).toMatchObject({ connected: false, writable: false }) + expect(runtime.getPtyLivenessVerdict('pty-doubted-then-absent')).toBeNull() + }) + it('clears recorded doubt when the presence query later proves the pane live', async () => { let answer: boolean | null = null const runtime = makeRuntimeWithLeaf({