feat(spawn): boot-process presence sentinel independent of the ready sentinel#456
Open
Masashi-Ono0611 wants to merge 3 commits into
Open
feat(spawn): boot-process presence sentinel independent of the ready sentinel#456Masashi-Ono0611 wants to merge 3 commits into
Masashi-Ono0611 wants to merge 3 commits into
Conversation
…e ready sentinel The boot script spawn.sh generates now records its own pid to run/boot-pid.<team>__<agent> right before exec'ing the role's CLI, and clears it right after that CLI exits. This is a liveness signal that does not depend on the CLI/model ever reaching its own watcher-registration step. Some types (grok-build) start their watcher only when the model follows the actas template's instructions (ADR 0003). When the very first model turn itself fails -- e.g. an unresolved rate/usage-limit dialog the CLI presents instead of continuing -- that step is never reached: no watcher starts, no ready sentinel is written or updated, even though the CLI process is still alive and visibly stuck on screen. An external liveness check relying solely on the ready sentinel (e.g. a statusline) cannot tell that apart from "nothing was ever launched, or it already exited" -- both read as fully dead. The new sentinel is boot-script-owned (not model/watcher-driven), so it survives that gap: present + a live pid means "launched and still running, registration incomplete," matching neither "dead" nor a watcher's "healthy." Scoped to spawn.sh's boot script only; resurrect-panes.sh's tmux-send-keys relaunch path (no boot-script process of its own) is not covered here.
…mal exit Codex review (self-multi-model) flagged that the sentinel added in the previous commit only cleared on normal CLI return: a closed window/tab (HUP), a killed pane (TERM), or Ctrl-C (INT) during the CLI's run would leave it behind, since the only cleanup was the explicit rm after the CLI line. Consumers already validate via kill(pid, 0) before trusting the file (same contract as every other sentinel in this codebase), so a stale file was never a correctness bug -- but it needlessly lingered. A trap covers the three trappable signals; only SIGKILL still leaves it for the next liveness check to invalidate.
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.
Fixes #455
Summary
spawn.sh's generated boot script now writes its own pid torun/boot-pid.<team>__<agent>right before exec'ing the role's CLI, and clears it right after (normal exit, and via a trap on HUP/TERM/INT for abrupt termination — SIGKILL still leaves it for the next liveness check to invalidate, same contract as every other sentinel here).ready.<team>__<agent>sentinel, which only appears once the CLI/model reaches its own watcher-registration step.Why
See #455 for the full field incident. Short version: grok-build's watcher starts only when the model follows the actas template's instructions (ADR-0003). When the very first model turn itself fails — an unresolved rate/usage-limit dialog the CLI presents instead of continuing — that step is never reached: no watcher, no ready sentinel, even though the CLI process is still alive and visibly stuck on screen. Nothing distinguishes that from "never launched, or already exited."
What this does NOT cover
resurrect-panes.sh's tmux-send-keys relaunch path (after a server restart) has no boot-script process of its own to own a pid file — out of scope here.spawn/statuscommand surfacing it). It's a primitive other tooling (in-repo or external, e.g. a statusline) can build on — I'm already consuming it from an external statusline against my own install.Test plan
bats tests/test_spawn.bats— 65/65 pass, including a new test asserting the sentinel is written before the CLI line and cleared afterbats tests/test_resurrect_panes.bats,bats tests/test_actas_lock.bats— no regressions (14/14, 22/22)bash -n) and thatkill -TERMsent to a running boot script removes the sentinel via the trapcodex exec, medium effort) before this branch was rebased onto currentupstream/main: 1 Warning (stale sentinel on abrupt termination) addressed via the HUP/TERM/INT trap; 2 Suggestions reviewed and left as-is (test style matches existing repo convention; the non-atomicecho $$ > filewrite matches the existing pattern inwatch.sh's own pidfile, not something newly introduced here). Diff is identical to what was reviewed — only the base commit changed.🤖 Generated with Claude Code