fix(#667): CLI no longer hangs on the receipt socket; resolve captains by socket path - #696
Merged
Merged
Conversation
…s by socket path Two more defects found by the slice 4 live smoke, both invisible to unit tests. 1. `squadrant ping` delivered its message and then HUNG FOREVER. A listening server keeps Node's event loop alive, so any short-lived CLI that built a captain channel never exited (observed: process still resident, work complete). The server is now unref'd — safe for the daemon too, which stays alive on its own control socket. stop() also removes the socket FILE, which close() does not, so processes stop leaving squadrantd-<pid>.sock behind. 2. Every captain ping reported `accepted-unconfirmed` for a captain that was demonstrably alive and answering. The captain channel resolved the registry entry by cwd, and cwd is not canonical: a captain in /tmp/s4lab registers cwd "/private/tmp/s4lab" on macOS (/tmp is a symlink), so the string compare silently missed. Added readClaudeStatusBySocketPath and switched the captain channel to it — the same identifier #689 adopted for crews, chosen by squadrant at launch and echoed back verbatim by the session. This also removes the last cwd-based match from the delivery path. Slice 1 already dropped cwd for crews because the operator's own window shares the project root; the non-canonical-path problem is a second, independent reason. Live-verified after the fix, on a throwaway project: on -> "✔ Delivered ... (accepted via claude-peer)", returns in 8s shadow -> "shadow probe — reachable", message delivered EXACTLY once gone -> "session gone — falling back to pane" then "⚠ not reachable", one fallback, logged both times off -> unchanged, and the no-auto-boot refusal still fires 6 new tests. 2660 green.
Merged
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.
Two more defects from the slice 4 live smoke. Neither was reachable from unit tests.
1.
squadrant pingdelivered, then hung foreverThe message arrived and the captain answered — and the CLI process never exited:
A listening server keeps Node's event loop alive. Any short-lived CLI that built a captain channel bound a receipt socket and could never terminate. Anything scripting
squadrant pingwould block indefinitely.server.unref()after listen — the process can now exit once its own awaits settle. Safe for the daemon, which stays alive on its own control socket rather than this one.stop()now also unlinks the socket file;close()does not, so every process that bound one was leaving asquadrantd-<pid>.sockbehind in the shared directory.2. Every captain ping reported
accepted-unconfirmedFor a captain that was alive and answering:
The captain channel resolved the registry entry by cwd, and cwd is not canonical:
{"pid":44257,"cwd":"/private/tmp/s4lab","status":"idle", "messagingSocketPath":"/tmp/cc-socks/squadrant-captain-s4lab.sock"}The project path is
/tmp/s4lab; the session registers/private/tmp/s4labbecause/tmpis a symlink on macOS. The raw string compare silently missed,statusForreturned undefined, and the confirmation branch never ran.Added
readClaudeStatusBySocketPathand switched the captain channel to it — the same identifier #689 adopted for crews: squadrant picks it at launch and the session echoes it back verbatim.This removes the last cwd-based match from the delivery path. Slice 1 had already dropped cwd for crews because the operator's own Claude window shares the project root; non-canonical paths are a second, independent reason. Worth treating "never match a session by cwd" as settled.
Verification — slice 4 smoke now passes all four cases
offon✔ Delivered to 's4lab' (accepted via claude-peer), returns in 8s, captain answeredshadowshadow probe — reachable, message delivered exactly oncegone(captain killed)session gone — falling back to pane→⚠ not reachable, one fallback, both logged6 new tests (unref, optional-unref, file cleanup, plus the earlier reject/unlink cases).
pnpm buildclean, 2660 tests green.Related: #667 slice 4 (#685), #689, #691, #695.