fix(daemon): keep a session closable while close withholds its device claim

Merged
TH
3d ago
+600-55

Summary

Refs #4237, close path only. The issue stays open for the open/relaunch follow-up.

close kept the device claim after a failed cleanup or platform close, but retired the session. A retried close got SESSION_NOT_FOUND; only a daemon restart freed the device.

Now a close that withholds the claim keeps the session and its lease, so a plain close retry releases it. Claimless sessions are still retired. A kept session doesn't block daemon idle reap until a successful reopen: an idle detached daemon shuts down, retries the cleanup, and leaves an unconfirmed claim stale. Embedded runtimes and AGENT_DEVICE_DAEMON_IDLE_TIMEOUT_MS=0 need a manual close. Help, docs, ADR 0036 updated.

Design: internal closes (bounded batch/replay, test cleanup) keep the session too. On main they left a claim nothing could free.

Validation

  • session-close-claim-retry.test.ts, 12 cases:
    • a retried close releases the claim; a leased session keeps its lease;
    • --save-script: the same-flag retry is refused, and a plain close releases the claim;
    • claimless: the session is retired;
    • lease-release and platform-close failures are reported correctly;
    • idle reap: fires for every kept session (incl. a failed lease release), not once reopened.
  • Bounded batch/replay IME tests: idle reap unblocked.
  • Each fix's cases fail on the code before that fix.
  • pnpm check:affected --run --head 899fee29b8: passed, exactCommit: true, receipt run-hNnhV9.
  • Live Android run at 899fee29b8 (emulator-5556): see the evidence comment.

Known gap: retrying after a committed repair dispatches the platform close again.

šŸ¤– Generated with Claude Code