fix(native): hand a shutdown-interrupted startup to the next controller

Graceful shutdown closes the runtime API listener before it drains heartbeat
runs. A native execution between provider dispatch and runnerd backend setup
then failed with local_runtime_api_listener_unavailable, so the drain no longer
saw it as running and never suspended it for the next boot.

resolveLocalRuntimeApiUrl now raises LocalRuntimeApiListenerClosedError (same
failure code) once this process stopped serving, and the executor treats it
as a restart detach: the run stays running with its claim, the drain suspends
it, and the next controller adopts it. A listener that never started is still
a startup failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DottaandClaude Opus 5.5 committed 2026-11-06 13:25:02 -06:00
1 parent 65aee998a3
commit a35ec8b845
8 files changed
+125 -10

No files matched your search

+5
View File
@@ -3292,6 +3292,11 @@ A graceful shutdown can also suspend a restart-recovery claim whose execution
has not yet reached provider dispatch. That execution has lost its authority:
it leaves the run running, its budget hold held and its workspace unmarked, and
the next controller adopts the same run. It does not settle the run as failed.
Shutdown closes the runtime API listener before it drains runs. A native
execution that then needs the listener (for example, to give a new runner its
callback origin) detaches the same way instead of failing. It keeps its claim,
the drain suspends it, and the next controller adopts the run. A listener that
never started is still a startup failure.
Remote Runner processes use their authenticated connection lease as the bound
on disconnected lifetime. The controller's shorter connection-recovery budget
limits its own attempt; it must not terminate the remote owner while another