fix(coding-agent): restore externally deleted supervisor owner records - #1225
Open
irl-dan wants to merge 1 commit into
Open
fix(coding-agent): restore externally deleted supervisor owner records#1225irl-dan wants to merge 1 commit into
irl-dan wants to merge 1 commit into
Conversation
A daemon supervisor's durable owner record (owner.json / scope.json) lives in a registry directory under the OS temporary directory. System temp cleaners - notably the macOS /var/folders reaper, which deletes regular files it considers old enough - can remove those files out from under a long-running supervisor while leaving its socket, lockfiles, and process intact. The supervisor re-validates its registry entry on every daemon command, so after such a removal it permanently refuses every command with Daemon supervisor generation <uuid> no longer owns its registry entry while still holding the socket and greeting clients with a current-version hello. Clients therefore neither succeed nor replace it: every new CLI launch connects, sends its first command, and exits 1. The daemon is poisoned until manually shut down. Teach the supervisor to repair this state: when an ownership assertion fails because the durable record is gone, re-run the acquisition conflict scan under the registry guard and rewrite the record (same generation and token) if - and only if - no other live supervisor owns a conflicting scope. A superseded generation still cannot resurrect itself past a live successor. The restore is single-flight across concurrent commands, and the periodic idle-eviction sweep piggybacks the same check so an idle supervisor heals without waiting for the next client command. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
irl-dan
force-pushed
the
fix/daemon-supervisor-owner-record-restore
branch
from
August 11, 2026 13:42
7685d08 to
2dc9224
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A daemon that runs for several days can stop accepting work. Every new CLI launch then fails within seconds. The daemon looks healthy from the outside, so nothing replaces it. Only a manual shutdown clears the state. This change lets the supervisor repair itself and keep serving.
Crash signature
Every CLI launch exits with code 1 after 1-2 seconds:
Root cause
The supervisor writes an owner record to the registry. The registry is in the OS temporary directory:
os.tmpdir()/prime-agent-<uid>/supervisor-owners/<generation>.owner/. The owner record has two files:owner.jsonandscope.json.OS cleaners delete old files in temporary directories. The macOS
/var/folderscleaner removes files after about three days. It deletes the two record files in place. It keeps the record directory, the socket, and the lockfile directories. We observed this on a supervisor with four days of uptime. The same sweep emptied hundreds of unrelated temporary directories.The supervisor validates the owner record for each command (
daemon-supervisor-ownership.ts:130-138). After the deletion, validation always fails. The supervisor rejects every command with the error above.The supervisor keeps its socket. It still sends a current-version
daemon_hello. Client probes report the daemon as current. So no client starts a replacement. The daemon stays in this state until a person stops it.Workers validate the same owner record every 250 ms (
daemon-mode.ts). They drop their supervisor connections for the same reason.Reproduction
The steps are deterministic and need no API keys:
On
main(14d6e74), 15 of 15 concurrent CLI launches fail with the signature. With this fix, 0 of 15 fail. The supervisor logs one line:Restored supervisor owner record for generation <uuid> after external removal.Fix
The fix has two goals. A live supervisor must survive the loss of its owner record. A superseded generation must not replace its live successor.
DaemonSupervisorOwnership.restoreIfUnowned(). It runs under the registry guard. It confirms that the owner record is absent. It then runs the same conflict scan as acquisition. If no live conflicting owner exists, it writes the owner record again with the same generation and token. If a live conflicting owner exists, it refuses. If a different record is present, it also refuses.DaemonSupervisor.assertCurrentOwnership()calls the restore when validation fails withsupervisor_generation_stale. It then validates again. The restore is single-flight: concurrent commands share one scan. If the restore refuses, the original error propagates.Tests
Three new cases in
test/suite/regressions/4600-supervisor-singleton.test.ts:list. It writes the owner record again with the same generation and token.Results:
4600-supervisor-singleton18/18 pass.daemon-supervisor-process8 pass, 8 tag-skipped.daemon-supervisor-eviction13/13 pass.daemon-socket7/7 pass.npm run checkpasses.Generated with Claude Code