mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
* fix(resource-manager): never destroy a session Orca cannot prove is idle (#8459) Resource Manager decided a session was an "orphan" from the absence of a renderer binding, then force-killed it with no prompt. Absence of a binding is not evidence a session is idle — during restore the binding map is legitimately empty, and deferred SSH sessions never appear in it at all. Live agent sessions were destroyed this way, losing unrecoverable work. Three gaps, one rule: only positive evidence authorizes destruction. - `pty:listSessions` dropped `agentSessionOwners` at the IPC boundary, so the renderer could not see the one fact that proves work is running. It now reports `hasAgentOwner`, typed once in `shared/pty-listed-session.ts` so the main handler, both preload surfaces, and the renderer cannot drift. - The binding index ignored `deferredSshSessionIdsByTabId` — sessions restore knows are live on an SSH host but has not reattached. No other binding source can see them. - The bulk-kill handler filtered sessions separately from the button's count, so the set killed could differ from the set advertised. Both now call `selectUnboundDaemonSessions`. The single-row kill path had the same defect: it skipped confirmation whenever `bound` was false. `requiresKillConfirmation` now also holds for agent-owned sessions, and snapshot-derived rows carry ownership across from the daemon list rather than reporting `false`. * fix(resource-manager): distinguish unprovable ownership from proven absence Adversarial review of the previous commit found it committed the same class of error it was fixing: it collapsed "no agent owns this" and "this provider cannot tell me" into one boolean `false`, and both destructive paths read that as proof. A daemon generation below the claim protocol, an older SSH relay, or the in-process local fallback all list no owners for a session that may well have one. `pty.ts` already encodes the rule at :613 — "only providers that serialize claims may make listing absence authoritative" — and the new IPC row ignored it. So after upgrading with a legacy daemon still holding a live agent terminal, bulk cleanup would have destroyed it: exactly #8459, one layer down. `hasAgentOwner: boolean` is now `agentOwnership: 'present' | 'absent' | 'unknown'`, derived via `providesAgentSessionOwnerListings`. Only `absent` authorizes destruction, so `unknown` protects and confirms. Second defect, found independently by four review lenses: the deferred-SSH bindings reached the bulk selector but not `mergeSnapshotAndSessions`, because the merge call site re-listed the binding fields instead of reusing the object. A deferred SSH session therefore rendered `bound: false`, and its single-row kill skipped confirmation while bulk cleanup correctly spared it. The call site now spreads `resourceSessionBindings`, and a parity test fails if any binding field is re-listed inline — the drift itself is now impossible to reintroduce quietly. The e2e ownership assertion was also weak: it checked only that a boolean arrived. It now asserts the exact arm, and that the live local provider reports `absent` rather than `unknown`, so a degenerate all-unknown implementation fails. --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>