feat(supervision): add resting vs active state for secondmate in-flight counting#391
feat(supervision): add resting vs active state for secondmate in-flight counting#391Freudator86 wants to merge 5 commits into
Conversation
3d5dade to
86dc12f
Compare
|
Thanks for the PR! This branch currently has a merge conflict with the base branch. When you get a chance, please rebase onto (or merge) the latest base branch, resolve the conflict, and push. After that, checks will re-run and the PR will get looked at again. Noted for firstmate#391 at |
86dc12f to
e832ee4
Compare
|
Thanks for the PR! This branch currently has a merge conflict with the base branch. When you get a chance, please rebase onto (or merge) the latest base branch, resolve the conflict, and push. After that, checks will re-run and the PR will get looked at again. Noted for firstmate#391 at |
…ht counting A persistent secondmate's own state/<id>.meta counted as in-flight for stop-hook/turnend-guard supervision exactly like a crewmate/scout, so a secondmate that is deliberately idle-but-alive still blocked turn-end whenever its supervising primary had no fresh watcher beacon. kind=secondmate meta can now carry supervision=resting to exclude it from that count while staying fully alive; supervision=active and legacy meta with no field still count as before. Liveness probing/respawn and dormant registry entries are untouched - this is purely a supervision-counting change.
… leaked CLAUDECODE env var
…ion counting in remaining docs
e832ee4 to
54f8974
Compare
|
Thanks for the PR! This branch currently has a merge conflict with the base branch. When you get a chance, please rebase onto (or merge) the latest base branch, resolve the conflict, and push. After that, checks will re-run and the PR will get looked at again. Noted for firstmate#391 at |
Intent
Add a 'resting vs active' supervision state for persistent secondmates, so a resting secondmate does not count as in-flight work for stop-hook/turnend-guard supervision, while an active one still does. Background: state/.meta records kind=secondmate for persistent secondmates; previously ANY secondmate meta counted as in-flight for supervision purposes exactly like an ordinary crewmate/scout task, so a secondmate that is deliberately idle-but-alive still blocked the primary's turn-end whenever there was no fresh watcher beacon. This is purely a supervision-COUNTING change, not a lifecycle change: persistent secondmates/bosuns stay alive regardless of this field. Implementation: bin/fm-supervision-lib.sh's fm_supervision_status (the shared predicate used by both fm-guard.sh and fm-turnend-guard.sh) now reads kind= and supervision= from each state/*.meta file via a new fm_sup_resting_secondmate helper, and skips a meta file only when it is BOTH kind=secondmate AND supervision=resting when computing FM_SUP_IN_FLIGHT. supervision=active and legacy meta with no supervision= field at all (the pre-existing case) still count exactly as before - this is a deliberate safe default so pre-existing secondmates are never silently dropped from supervision. Ordinary crewmate/scout meta (kind=ship, kind=scout, or no kind field) is completely unaffected. dormant is a distinct, pre-existing, unrelated concept (a registry-only entry in data/secondmates.md with no live state/.meta at all) and this change does not touch or conflate it. Deliberately out of scope (per explicit instruction from the task brief): no command or plumbing was added to actually set/toggle supervision=resting on a live secondmate - that lifecycle mechanism is left for a future task; this change only wires the counting predicate and documents the field. bin/fm-turnend-guard.sh itself was deliberately NOT modified: the predicate change in fm-supervision-lib.sh alone was sufficient to fix its behavior (verified by a new passing test), so per the brief's explicit guidance the hook script was left untouched to keep the change minimal. Secondmate liveness probing and respawn behavior in bin/fm-bootstrap.sh (SECONDMATE_LIVENESS sweep) is unrelated to this predicate and was verified unaffected by supervision=resting via a new test. Tests were written first (TDD), confirmed failing against the old predicate, then the implementation was added and confirmed passing. Added tests to the existing tests/fm-turnend-guard.test.sh (predicate-level: resting excluded, active counts, legacy counts, ordinary crewmate/scout unaffected, a resting secondmate plus real co-located in-flight work still counts; hook-level: turn-end guard silent with only a resting secondmate in flight, still blocks with an active one) and one new test in tests/fm-secondmate-liveness.test.sh proving the liveness/respawn sweep is unaffected by supervision=resting. Documentation: one clause added to AGENTS.md's existing state/.meta field-list line (section 2) describing the new optional supervision= field, one new sentence in AGENTS.md section 8 cross-referencing it, and docs/turnend-guard.md's 'Shared Predicate' and 'Tests' sections updated to describe the exception and the new test coverage - all one-line pointers per this repo's one-owner/inline-stub documentation conventions (loaded the firstmate-coding-guidelines skill before making these changes, per this repo's own CONTRIBUTING.md). No yolo: this is the core firstmate-core template repo, and PR merge decisions belong to the upstream maintainer (the captain), never auto-merged by me.
What Changed
bin/fm-supervision-lib.sh'sfm_supervision_status(shared byfm-guard.shandfm-turnend-guard.sh) now readskind=/supervision=from eachstate/*.metavia a newfm_sup_resting_secondmatehelper, excluding a meta only when it is bothkind=secondmateandsupervision=restingfromFM_SUP_IN_FLIGHT;supervision=active, legacy meta with nosupervision=field, and ordinary crewmate/scout meta all still count exactly as before.tests/fm-turnend-guard.test.sh(resting excluded, active/legacy counts, ordinary crewmate/scout unaffected, resting-secondmate-plus-real-in-flight-work still counts, silent-vs-blocking hook behavior) and a new test intests/fm-secondmate-liveness.test.shproving the liveness/respawn sweep is unaffected bysupervision=resting; also fixed portable test assertions intests/fm-session-start.test.sh(mkdir wording, leakedCLAUDECODEenv var) and a shellcheck SC1007 warning in the same file.state/<id>.metasupervision=field and the resting/active exception inAGENTS.md,CONTRIBUTING.md,docs/architecture.md,docs/scripts.md, anddocs/turnend-guard.md.Risk Assessment
✅ Low: Small, well-scoped change to a single shared predicate function with a safe default (absent/non-"resting" values still count as in-flight), backed by thorough new tests covering the predicate, the hook-level behavior, and non-interference with the unrelated liveness/respawn sweep; docs and AGENTS.md are updated consistently with the code.
Testing
Ran the full portable test suite (51 files via tests/*.test.sh) with tmux 3.6, and it passed end-to-end with a clean worktree afterward; targeted runs of tests/fm-turnend-guard.test.sh and tests/fm-secondmate-liveness.test.sh confirm the new fm_sup_resting_secondmate behavior end-to-end: a kind=secondmate meta with supervision=resting is excluded from FM_SUP_IN_FLIGHT (predicate) and does not block the turn-end hook when it's the only in-flight entry, while supervision=active or legacy meta with no field still counts and still blocks the hook exactly as before; a separate test confirms the secondmate liveness/respawn sweep in fm-bootstrap.sh is unaffected by supervision=resting (a dead resting secondmate is still killed and respawned). Ordinary crewmate/scout meta (kind=ship/kind=scout) is unaffected in all cases.
Evidence: fm-turnend-guard.test.sh output (predicate + hook resting-vs-active cases)
Evidence: fm-secondmate-liveness.test.sh output (liveness sweep unaffected by supervision=resting)
Evidence: Full test suite run (all 51 tests/*.test.sh)
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
🔧 **Test** - 1 issue found → auto-fixed (2) ✅
command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"🔧 Fix: Fix portable test assertions for mkdir wording and leaked CLAUDECODE env var
1 error still open:
command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"🔧 Fix: placeholder
✅ Re-checked - no issues remain.
command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"bash tests/fm-turnend-guard.test.sh(38 assertions incl. resting/active/legacy predicate cases and hook-level silent-vs-block cases)bash tests/fm-secondmate-liveness.test.sh(11 assertions incl. sweep-unaffected-by-supervision=resting)for t in tests/*.test.sh; do bash "$t"; donefull 51-file suite, exit code 0git status --shortbefore and after testing to confirm a clean worktree✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.