Skip to content

feat(spawn): opt-in actas readiness handshake for turn/off drivers#438

Open
Masashi-Ono0611 wants to merge 2 commits into
fujibee:mainfrom
Masashi-Ono0611:feat/actas-spawn-readiness-handshake
Open

feat(spawn): opt-in actas readiness handshake for turn/off drivers#438
Masashi-Ono0611 wants to merge 2 commits into
fujibee:mainfrom
Masashi-Ono0611:feat/actas-spawn-readiness-handshake

Conversation

@Masashi-Ono0611

@Masashi-Ono0611 Masashi-Ono0611 commented Jul 19, 2026

Copy link
Copy Markdown

Summary

  • Adds an optional agent-type manifest key handshake=actas: a driver declares
    that its actas flow has a reliable, explicit completion point (calling
    ready.sh mark <team> <agent> once identity claim + any delivery setup is
    done), independent of watcher liveness.
  • spawn.sh now branches on this key: types with handshake=actas wait on the
    one-shot actas-ready.<team>__<agent> sentinel (clearing stale ones first,
    consuming it after observation, 300s minimum timeout) instead of the
    existing watcher-liveness wait. Types without the key keep current behavior
    unchanged (monitor=yes watcher wait, monitor=no immediate return,
    --no-wait still an explicit opt-out everywhere).
  • Wires grok-build to this handshake (type.conf: handshake=actas,
    template.md step 6 calls ready.sh mark after identity claim — and after
    the monitor tool confirms the watcher is running/streaming in monitor mode).
  • New scripts/ready.sh (mark|check|clear <team> <agent>) and
    agmsg_actas_ready_path() in scripts/lib/actas-lock.sh, using a filename
    (actas-ready.*) deliberately disjoint from the existing watcher
    ready.<team>__<agent> sentinel so the two protocols (one-shot bootstrap
    edge vs. ongoing watcher liveness) never collide.
  • docs/adr/0003-actas-spawn-readiness-handshake.md records the alternatives
    considered (unconditional wait, default-on with opt-out, conditioning on
    delivery mode, reusing the watcher sentinel, staying fire-and-forget) and why
    each was rejected.

Motivation

Issue #338 (Gap 2, credit @Salmonellasarduri) reports that Grok Build spawns in
turn/off delivery mode have no watcher to wait on, so the existing
watcher-readiness wait either hangs forever or (if disabled) reopens a
cold-start race where the parent can address work to the new agent before it
has claimed its identity. Issue #338 also documents observed first-turn
startup times of 143–187 seconds, which motivated the 300s floor here (vs. the
existing 90s watcher-readiness default).

This is scoped narrowly to the handshake mechanism itself; it does not touch
monitor=yes watcher-readiness wait behavior, delivery mode selection, or any
other driver's type.conf.

Operations / Limitations

  • The handshake is model-driven: it depends on the spawned model actually
    following template.md step 6. If it doesn't, spawn waits out the 300s
    floor and exits with status=timeout (exit 3) — this is not a spawn
    failure, just an unconfirmed bootstrap. On timeout, check whether the agent
    is still booting before deciding between --no-wait (fire-and-forget) or
    re-spawn.
  • ready.sh mark records only "actas bootstrap completed," not watcher
    liveness. A separate PR (feat(delivery): per-identity watcher liveness in status #436) addresses per-identity watcher liveness
    reporting in delivery.sh status using the pre-existing watcher pidfile
    convention this PR does not change.

Test plan

  • bats tests/test_ready.bats tests/test_spawn.bats tests/test_type_registry.bats
    — 90/90 passing (new + updated coverage for the opt-in key, the 300s floor,
    spawnable-type-registry surface, and the node-launcher path).

  • bats tests/*.bats — 728/729 passing; the sole failure
    (install: watch.sh self-cleans a prior watcher on re-invocation for the same sid) is a pre-existing order-dependent flake unrelated to this diff —
    confirmed by running tests/test_install.bats alone (46/46 pass).

  • Cross-reviewed by two independent peers before submission (both approved,
    no P1 findings; P2 feedback on mark-timing and Operations wording is already
    incorporated above and in template.md step 4/6).

  • CI green

Update (2026-07-19): additional review pass, one more fix

A follow-up /review:self-multi-model pass (Codex + Fugu, independently
converging on the same gap) found a P2 before this had any maintainer eyes
on it, now fixed in the latest commit:

  • Cross-generation mark contamination: the readiness mark was keyed only
    by (team, agent), with no way to tell WHICH launch produced it. If an
    earlier spawn attempt for the same (team, agent) had already given up
    (--no-wait, or past its own 300s timeout) but its agent was still
    booting, that agent's eventual ready.sh mark could land after a LATER
    spawn's clear-before-launch and satisfy the later spawn's check —
    reporting status=ready before the later launch's own agent had actually
    completed bootstrap. Fixed by having spawn.sh generate a per-launch nonce
    and export it (with the resolved team) as
    AGMSG_SPAWN_TEAM/AGMSG_SPAWN_NONCE; the template echoes both back on
    mark, and check now requires an exact match.
  • Same pass separately caught that the template resolved which team to
    mark from identities.sh, which returns every team the agent name is
    registered under — ambiguous when the same name exists in more than one
    team. The template now prefers AGMSG_SPAWN_TEAM (set by spawn) over that
    resolution when present, and the mark arguments are quoted.

Full suite re-verified: 736/736 (this worktree's copy of the pre-existing
install: watch.sh self-cleans... flake did not reproduce on this run).

Two P2s found by /review:self-multi-model (Codex + Fugu, independently
converging on the same gap):

- ready.sh mark/check now take an optional per-launch nonce. spawn.sh
  generates one whenever handshake=actas applies, exports it (with the
  resolved team) as AGMSG_SPAWN_TEAM/AGMSG_SPAWN_NONCE before launch, and
  requires the exact nonce on check. Without this, a mark from an
  abandoned/timed-out earlier spawn attempt for the same (team, agent) could
  satisfy a LATER spawn's wait, reporting status=ready before that later
  launch's own agent had actually booted.

- The grok-build template now marks with AGMSG_SPAWN_TEAM/AGMSG_SPAWN_NONCE
  when present (i.e. launched by spawn) instead of the team resolved from
  identities.sh, which can return more than one team for the same agent name
  — previously causing a 300s timeout despite the agent completing bootstrap
  in the intended team. Also quotes the mark arguments (unquoted dynamic
  team/agent names could break/misparse).

ADR 0003 updated to record the nonce in the Decision section.
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.

1 participant