feat: expand autonomous fleet supervision and delivery - #2019
Closed
quinnbot-ai wants to merge 3 commits into
Closed
quinnbot-ai wants to merge 3 commits into
quinnbot-ai wants to merge 3 commits into
Conversation
added 3 commits
August 9, 2026 11:17
A bare `heartbeat` wake said nothing about fleet capacity, so refilling a fleet that drained overnight depended on the supervisor deciding to go look. Twice this week that left finished work parked and a ready queue undispatched until morning. An emitted heartbeat now carries `refill: ready=<n> live=<m> ids=<...>` on its durable queue payload: how many queued items the configured backlog backend reports as dispatchable, and how many ship and scout endpoints are still live. Acting on it becomes part of the ordinary wake-handling contract rather than a judgment call. bin/fm-refill.sh owns the probe and the line format, and fails open in every direction: a manual backlog backend, an absent or incompatible tasks-axi, an unreadable backlog, a probe past its hard time bound, or any unexpected error emits nothing and the heartbeat goes out exactly as before. The probe runs as a bounded child that reports raw fields, so neither a truncated run nor a crafted backlog id can shape the payload. The evidence rides the queue payload rather than the printed reason line because the arm, checkpoint, and Stop auto-arm layers pattern-match that line as `heartbeat($|:)`; it stays exactly `heartbeat`, and every supervision protocol already drains the queue before handling a wake, so the change is harness-agnostic.
quinnbot-ai
force-pushed
the
fm/fm-refill-wake
branch
from
August 9, 2026 18:18
8414c13 to
ade68ea
Compare
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.
Intent
Build the mechanism that wakes firstmate to autonomously refill fleet capacity. Twice this week the captain returned to an under-capacity fleet: workers finished, finished work parked, and the ready queue sat undispatched all night because nothing structurally forced a refill. The fix: make the watcher's heartbeat wake CARRY refill evidence, and make refillable work able to WAKE firstmate, so acting on it is part of the existing wake-handling contract instead of a judgment call the model can skip.
This changes firstmate's shared tracked material, so the firstmate-coding-guidelines skill governs it: one-owner rule, AGENTS.md size discipline, repo style (one sentence per line in tracked Markdown, plain dash never an em dash, shellcheck-clean bin scripts via bin/fm-lint.sh, no agent commit co-author), and colocated behavior-through-interface tests in tests/.
Accepted design, including every decision made and approved during this validation:
bin/fm-refill.sh is the single owner of the refill probe and its one-line format, refill: ready= live= ids=<id,id,...>. Ready work comes from the configured backlog backend (compatible tasks-axi ready, which already excludes blocked and captain-held work); live capacity counts state/*.meta records of kind=ship or kind=scout whose recorded endpoint is alive, reusing the existing cheap liveness helper the session-start digest uses (fm_backend_target_exists) rather than a second liveness reader.
The evidence rides the DURABLE QUEUE payload of the heartbeat wake record, and the watcher's printed reason line stays exactly 'heartbeat'. This is a deliberate deviation from the original one-extra-printed-line suggestion: bin/fm-watch-arm.sh, bin/fm-watch-checkpoint.sh, and bin/fm-claude-stop-autoarm.sh match watcher stdout as heartbeat($|:), bin/fm-supervise-daemon.sh's is_wake_reason matches heartbeat exactly, and tests/fm-watch-triage.test.sh asserts grep -Fx heartbeat. Every supervision protocol drains the queue with bin/fm-wake-drain.sh before handling a wake, so the payload reaches all six primary harnesses unchanged.
FAIL OPEN ON DATA. A manual backlog backend, a missing or incompatible tasks-axi, an unreadable backlog, malformed or incomplete backend output, or a probe past its hard bound emits no refill line, and the heartbeat goes out exactly as it would have otherwise. Malformed output is a probe failure, never a false ready=0; ready=0 is reported only for the backend's exact supported empty response, so silence means 'cannot answer' and never 'nothing ready'. The bound is hard in both implementations: kill-after escalation on timeout/gtimeout, and TERM escalating to KILL in the portable Perl fallback that stock macOS actually uses.
APPROVED SCOPE EXPANSION from the review gate: the commission was a mechanism that WAKES firstmate on refillable work, so the refill condition itself fires a wake in normal mode - dispatchable ready work with live capacity below FM_REFILL_MIN_LIVE (default 1) produces an actionable wake even when no unsurfaced captain-relevant status exists - on the existing heartbeat cadence and its doubling backoff, never a per-poll path, and still fail-open when the probe cannot answer. In away mode the same actionable refill condition is routed into the sub-supervisor's EXISTING escalation digest so it reaches a handling turn, while evidence-free heartbeats stay force-self-handled. That wiring is bounded: away mode itself is not redesigned and none of its approval boundaries change, so it still never expands authority for merges, ask-user findings, destructive, irreversible, or security-sensitive choices.
AGENTS.md section 8's heartbeat bullet carries the minimum contract language - a heartbeat carrying a refill line requires the handling turn to dispatch every eligible ready item or record in the backlog why each named item stays queued - patched into the existing bullet rather than a new section. docs/architecture.md's 'Event-driven supervision' section is the single owner of heartbeat wake semantics and states the new behavior, with bin/fm-refill.sh named as owner of the probe, its bound, and the line format. docs/scripts.md carries the one-row toolbelt entry.
Colocated coverage in tests/fm-refill.test.sh and tests/fm-daemon.test.sh: payload shape with ready ids and live ship and scout capacity (dead, secondmate, and window-less records excluded), captain-gated work non-dispatchable while a genuinely empty queue still reports ready=0, id capping with the count intact, every fail-open path including malformed output producing silence, the hard bound including the no-timeout-binary portable fallback, a normal-mode heartbeat firing from refillable work alone, an away-mode heartbeat with refill evidence reaching the escalation path while an evidence-free one stays self-handled, and a heartbeat still firing unchanged when the probe is broken.
SETTLED DECISIONS for this run, both made by the task owner during validation:
Scope discipline: this is also the seed of a future upstream proposal (upstream-closeout-refill-proposal), so the change stays well-scoped and free of unrelated cleanups. This repo's .firstmate/test-inventory.json is 'testless' (the Python-literal contract; this repo's tests are shell), so no receipt regeneration applies.
What Changed
Testing
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
.agents/skills/ahoy/SKILL.md- branch carries 52 commit(s) that exist on your local main branch but were never pushed to origin/main; rebasing would bundle this unrelated work (219 file(s)) into the PR:Push main to origin, or rebase your branch onto origin/main, before gating.
⏭️ **Review** - skipped
Step was skipped.
⏭️ **Test** - skipped
Step was skipped.
⏭️ **Document** - skipped
Step was skipped.
⏭️ **Lint** - skipped
Step was skipped.
✅ **Push** - passed
✅ No issues found.