Skip to content

feat(spawn): boot-process presence sentinel independent of the ready sentinel#456

Open
Masashi-Ono0611 wants to merge 3 commits into
fujibee:mainfrom
Masashi-Ono0611:upstream-boot-pid-sentinel
Open

feat(spawn): boot-process presence sentinel independent of the ready sentinel#456
Masashi-Ono0611 wants to merge 3 commits into
fujibee:mainfrom
Masashi-Ono0611:upstream-boot-pid-sentinel

Conversation

@Masashi-Ono0611

Copy link
Copy Markdown

Fixes #455

Summary

  • spawn.sh's generated boot script now writes its own pid to run/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).
  • This is a liveness signal independent of the existing 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.
  • No consumer of the new sentinel is added in this PR (e.g. a spawn/status command 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 after
  • bats tests/test_resurrect_panes.bats, bats tests/test_actas_lock.bats — no regressions (14/14, 22/22)
  • Manually verified the generated boot script is valid bash (bash -n) and that kill -TERM sent to a running boot script removes the sentinel via the trap
  • Self multi-model review (Codex, bounded codex exec, medium effort) before this branch was rebased onto current upstream/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-atomic echo $$ > file write matches the existing pattern in watch.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

…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

grok-build: liveness check has no way to tell 'CLI alive but stuck before watcher registration' from 'dead'

1 participant