Skip to content

feat(bin): add fleet bearings board and cross-origin decision-hold answers - #37

Merged
zeeshaanahmad merged 8 commits into
mainfrom
fm/upstream-batch-5-free-ride
Sep 2, 2026
Merged

zeeshaanahmad merged 8 commits into
mainfrom
fm/upstream-batch-5-free-ride

Conversation

@zeeshaanahmad

Copy link
Copy Markdown
Owner

Intent

Sync the fork forward to upstream waypoint a0cec26 (upstream PR kunchenguid#2710, "ci: require no-mistakes pipeline step attestation") as a single reviewed MERGE commit. This is batch 5 of eight in an upstream reconciliation campaign; batches 1-4 have landed and batch 4's waypoint b57c4d6 is in origin/main's ancestry. Six upstream commits are included: f242264, 7b38a2f (doc), 87681a4 (kunchenguid#2647 herdr steer confirmation), 1cb900c (kunchenguid#2659 Lavish fleet board), b96dba1 (kunchenguid#2707 decision options / close controls), a0cec26 (kunchenguid#2710).

REQUIRED SHAPE, deliberate and non-negotiable: branch off current origin/main, git fetch upstream (fetch-only remote), then git merge a0cec26 producing a MERGE COMMIT. Never rebase, squash or cherry-pick this branch - the upstream commit identities must remain in ancestry, because each subsequent batch computes its merge base from them. A flattened branch that carries identical file content is a FAILURE even though every file looks correct. The run is therefore started with --skip=rebase deliberately. The batch stops exactly at a0cec26: upstream 99b21d8 is batch 6 (the captain-hold collapse) and must be ported by hand in its own task, so it is deliberately NOT pulled forward here.

The plan originally costed this batch as zero-conflict. The fork moved since, and four files actually conflicted across seven hunks: bin/fm-decision-hold.sh, bin/fm-test-run.sh, docs/decision-hold-lifecycle.md, tests/fm-decision-hold-lifecycle.test.sh. All 25 other changed files auto-merged and are upstream's work unmodified.

RESOLUTION POLICY APPLIED (the repo owner's standing rule): where upstream fixed something the fork also fixed, take upstream's version, but first prove upstream's covers the behaviour the fork's covered; where upstream's covers less, keep the fork's for that gap only and say so. Where the two sides changed DIFFERENT things in one file, keep both. Every hunk here turned out to be the "different things" case, so both sides were kept rather than picked between:

  • bin/fm-test-run.sh: the live-harness-optin family registration list was unioned. The fork's fm-away-delivery-bound-live-e2e and fm-send-agent-pane-live-e2e entries and upstream's new fm-herdr-submit-confirm-live-e2e entry are all kept; upstream's fm-bearings-board entry auto-merged. The fork's FM_TEST_INHERITED_OVERRIDES scrub owner (PR 34) and co-author live guard registration (PR 35) are untouched.
  • bin/fm-decision-hold.sh: one conflicted line in command_answers, combined. Upstream's fix(bearings): restore decision options and add close controls kunchenguid/firstmate#2707 change retargets the child invocation at $k_origin/$k_key so a cross-origin full hold identity splits correctly; the fork's 918709d change adds "< /dev/null" so that child cannot consume the enclosing "while read" loop's remaining answer lines. Two different fixes to the same call; both are required and both are kept.
  • bin/fm-decision-hold.sh, second edit, deliberate and the ONLY place the merged text matches neither side verbatim: upstream's new "decline --drop" branch is a sibling child of that same read loop and shipped without the stdin redirect, so it carried the identical defect 918709d fixed. The fork's one-token redirect was extended to it. This is the "keep ours for the gap theirs does not cover" half of the standing rule, not new design.
  • tests/fm-decision-hold-lifecycle.test.sh: not a genuine conflict. Each side added a whole new test function and git aligned them on their shared fixture-channel heredoc body. Taking either side would have silently deleted the other side's test. Both functions were reassembled in full, each with its own copy of the heredoc and its own closing brace, and both are registered in the runner list.
  • docs/decision-hold-lifecycle.md: both hunks additive. All three verification dates are kept, and the quoted suite output lists both new "ok -" lines in the order the suite actually emits them, verified by diffing the quoted block against a live run rather than hand-editing it.

The merged result must carry ALL of the fork's decision-hold behaviours (PR 5's precondition recheck after resolve, 918709d's corrupted-binding diagnostics and stdin-leak fix, PR 29's fixture-cleanup guard that stops a test fixture deleting the working directory) AND all of upstream's new kunchenguid#2647/kunchenguid#2659/kunchenguid#2707 behaviour, each still proven by its own passing test. Plan section 2.7 assigns the full keyed-answer reconciliation to the batch 6 port, so this batch deliberately does the minimum that keeps every behaviour on both sides passing its own tests, and deliberately does not redesign that subsystem.

.github/workflows/no-mistakes-required.yml: a0cec26 rewrites this file from 54 to 123 lines, adding a required check that fails any PR to main whose body lacks a parseable no-mistakes pipeline step attestation, and requiring the review, test and document steps to each report status exactly "completed" (it explicitly rejects quota skips and agent skips). The merge leaves the file byte-identical to upstream, which is a true auto-merge and not a resolution choice: the fork had never modified that file. This check runs on THIS PR from the PR head. The workflow must NOT be edited to make anything pass; if the check fails, the reason is reported rather than worked around.

CONSTRAINTS: this is the firstmate repo's own shared tracked material, so the firstmate-coding-guidelines skill applies. One full sentence per line in tracked Markdown and plain dash never an em dash, EXCEPT that a file carried byte-identical from upstream is explicitly exempt from those two rules for as long as it is held byte-identical - reformatting such a file trades a permanent conflict on every future upstream sync for cosmetics. This merge carries several upstream-authored Markdown and workflow files in that exempt category, so the document step must not reflow them; a previous batch in this campaign had exactly that happen and it had to be reverted. Never add an agent name as a commit co-author. bin/.sh and bin/backends/.sh must pass bin/fm-lint.sh. This repo has real working GitHub Actions, so the ci step must NOT be skipped.

ALREADY VERIFIED LOCALLY on the committed head: waypoint ancestry (git merge-base --is-ancestor a0cec26 HEAD -> ancestor-ok); merge shape is exactly one merge commit plus the six upstream commits with no rebase/squash/cherry-pick and no co-author trailer; batch 6's 99b21d8 confirmed NOT an ancestor; tests/fm-decision-hold-lifecycle.test.sh 18 ok; tests/fm-bearings-board.test.sh 10 ok; tests/fm-backend-herdr.test.sh 180 ok; tests/fm-composer-lib.test.sh 33 ok; bin/fm-test-run.sh --check-coverage exit 0 with total=164 and every script covered; bin/fm-lint.sh exit 0; bin/fm-test-run.sh --proven-isolated --jobs 8 exit 0 with total=24 failed=0.

KNOWN PRE-EXISTING AND OUT OF SCOPE: tests/fm-watcher-lock.test.sh fails its guard-xmode case on pristine origin/main, environment-dependent on a registered Claude Stop hook. This merge touches neither that test nor bin/fm-watch.sh. It is not caused by this change and is not this batch's to fix. Herdr-gated failures on the "fleet-state tripwire" are environmental. tests/fm-herdr-submit-confirm-live-e2e.test.sh is in the env-gated opt-in live-harness family and needs a real installed herdr harness, so it is not run here.

What Changed

  • bin/fm-bearings-board.sh (new) and .agents/skills/bearings/assets/board-template.html (new) add an interactive Lavish fleet board for reviewing crew state and decisions from the browser; .agents/skills/bearings/SKILL.md documents it and the new decision options and close controls upstream added for the board.
  • bin/fm-decision-hold.sh extends the keyed-answer intake with --any-origin support so one source can carry answers for holds across multiple origins (split on the first -decision- separator), adds a reserved __drop__ answer that closes a stale hold via a new decline --drop path without closing routed dependents, and keeps the fork's existing stdin-redirect fix on the child answer invocation, extending it to the new drop path so neither child call can consume the enclosing read loop's remaining answer lines.
  • bin/backends/herdr.sh and .agents/skills/afk/SKILL.md make herdr steer-submission confirmation reliable; .github/workflows/no-mistakes-required.yml is rewritten to require a parseable no-mistakes pipeline-step attestation (with review/test/document each reporting completed) on PRs to main.
  • Adds tests/fm-bearings-board.test.sh and tests/fm-herdr-submit-confirm-live-e2e.test.sh, extends tests/fm-backend-herdr.test.sh, tests/fm-composer-lib.test.sh, and tests/fm-decision-hold-lifecycle.test.sh (reassembling both the fork's and upstream's added cases on their shared fixture), registers the new live-harness-optin test families in bin/fm-test-run.sh, and updates docs/architecture.md, docs/decision-hold-lifecycle.md, docs/herdr-backend.md, docs/scripts.md, docs/tmux-backend.md, and the verification docs to match.

Risk Assessment

✅ Low: Merge shape, upstream commit set, and batch-6 exclusion are all verified correct; each of the four claimed conflict hunks (bin/fm-decision-hold.sh x2, bin/fm-test-run.sh, docs/decision-hold-lifecycle.md, tests/fm-decision-hold-lifecycle.test.sh) was diffed against both parents and matches the described resolution exactly, including the one deliberately-neither-side-verbatim stdin-redirect extension; all 25 auto-merged files were confirmed to retain both sides' additions with zero lines lost; the workflow file is confirmed byte-identical to upstream; no conflict markers, em dashes, or agent co-author trailers were found; and new tests exercise real command behavior rather than source-text matching.

Testing

Ran the full set of targeted suites the batch's conflict resolution touches (decision-hold-lifecycle, bearings-board, composer-lib, backend-herdr) plus fm-lint.sh and the coverage check — all passed with exit 0, matching the counts claimed in the intent (except bearings-board, which is 9 ok in both the live run and the committed doc, not 10 as stated in the intent's summary — a harmless discrepancy in that prose, not in the code or docs). Directly inspected the merged fm-decision-hold.sh source to confirm the described "two different fixes to the same call, combined" resolution is byte-for-byte what's claimed. Merge ancestry, commit shape, absence of a co-author trailer, and workflow byte-identity were all independently confirmed via git. No product or test defects found; worktree left clean.

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

⏭️ **Rebase** - skipped

Step was skipped.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • git log -1 --format='%P' 7fe4726 (two-parent merge verification)
  • git merge-base --is-ancestor a0cec26 HEAD
  • git log -1 --format=%B 7fe4726 | grep -i co-authored (absence confirmed)
  • diff against git show a0cec26:.github/workflows/no-mistakes-required.yml (byte-identical)
  • bash bin/fm-lint.sh (full repo, incl. new workflow lint)
  • bash tests/fm-decision-hold-lifecycle.test.sh
  • bash tests/fm-bearings-board.test.sh
  • bash tests/fm-composer-lib.test.sh
  • bash tests/fm-backend-herdr.test.sh
  • bash bin/fm-test-run.sh --check-coverage
  • manual read of bin/fm-decision-hold.sh:800-893 to verify the combined k_origin/k_key + </dev/null conflict resolution on both command_answers child call sites
  • diffed docs/decision-hold-lifecycle.md quoted 'ok -' verification lines against actual live test output order for both suites
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

kunchenguid and others added 8 commits August 19, 2026 13:16
Added guidelines for decision communication to the captain.
Clarify communication protocols with crewmates regarding task delegation and reporting.
* fix(herdr): confirm local steers that native agent-state misses

Herdr can leave agent_status idle for a landed Claude turn and can keep
queued Enter text visible while busy, so fm-send was reporting false
swallows. Confirm those cases through the shared queued-Enter verdict
and a cleared composer, and keep a genuine idle pending composer as
unconfirmed.

* no-mistakes(review): Stop Herdr Enter retries on unreadable composers

* no-mistakes(review): Reject queued delivery when all Herdr Enter sends fail

* no-mistakes(review): Prevent confirmation after failed Herdr Enter

* no-mistakes(review): Pace Herdr retries and clarify submit fallback

* no-mistakes(review): Align Herdr submit docs with idle fallback

* no-mistakes(document): Correct Herdr submit-confirmation documentation
* feat(bin): accept any-origin decision bindings with full-identity keys

An aggregation surface (the bearings board) carries captain answers for holds
across origins, but a binding was one-origin-per-source and the Lavish adapter
capped question keys at 64 chars while real full hold identities measure 69-81.

- fm-decision-hold.sh: bind <source-id> --any-origin records the (any) marker;
  binding prints it verbatim and answers accepts it, so the runner's feed seam
  carries an any-origin source with no runner change. In any-origin mode each
  key is a full hold identity <origin>-decision-<key>, split at its first
  -decision-; a key with no separator (merge/dispatch instructions) is skipped
  and feeds nothing, keeping non-decision answers out of the hold ledger by
  construction. Every existing close guard applies unchanged.
- fm-procevent-lavish.sh: raise the question-key cap 64 -> 128 so a full hold
  identity fits; the slug-shape security property is unchanged.
- tests: cross-origin closure through the real runner seam, an 81-char
  identity through the adapter, cap and shape refusals, routed-work skips,
  nonexistent-identity skips, and idempotent replay.

* feat(bearings): add the /bearings lavish interactive fleet board

/bearings lavish renders the bearings snapshot onto a shipped, reusable board
template and arms it as a Lavish process-event source, so the captain answers
Captain's Call items on the board and firstmate is woken by an ordinary check
wake - no conversational turn ever blocks on a poll.

- .agents/skills/bearings/assets/board-template.html: the shipped template
  (myfirstmate design system inlined, one fm-bearings-board.v1 JSON slot,
  fail-closed schema guard that renders an error card instead of an empty
  fleet). Per-invocation agent work is composing the payload only.
- bin/fm-bearings-board.sh: build/refresh owner - fail-closed payload
  validation, slot injection with a round-trip check and \u003c escaping,
  stable board path, any-origin bind ALWAYS before arm, arm-if-absent.
- bearings SKILL.md: the lavish invocation option, board composition rules,
  board-wake handling, and the captain-ruled merge-click authorization with
  its mandatory safeguards (PR resolved from the task's own meta record,
  wake-time green re-verification, never a red or changed PR, merges only
  through bin/fm-pr-merge.sh, chat echo with the full PR URL).
- process-event-sources SKILL.md: one-line board-wake routing trigger.
- tests: payload refusals, injection round-trip, bind-before-arm, idempotent
  re-arm, and template slot integrity.

Fleet pickup: homes receive this after merge plus a firstmate self-update;
landing timing is coordinated with the main firstmate.

* no-mistakes(review): Harden bearings board validation and wake handling

* no-mistakes(review): Require HTTPS for bearings board PR links

* no-mistakes(review): Fail closed and bound bearings board answers

* no-mistakes(review): Enforce UTF-8 byte limits for board answers

* no-mistakes(review): Serve bearings board before arming and reject empty actions

* no-mistakes(review): Prove bind-before-arm ordering through live answer consumption

* no-mistakes(document): Document bearings board and cross-origin answers
…enguid#2707)

* fix(bearings): always show decision options and a close/drop control

Freeform-only Captain's Call cards hid the option buttons the board was designed around, and there was no way to drop a stale hold without inventing an answer. Require selectable options, keep freeform as a supplement, and route the reserved __drop__ answer through decline so the hold leaves Captain's Call.

* no-mistakes(review): Fix drop closure and decision-only option validation

* no-mistakes(review): Preserve answerability for non-decision cards

* no-mistakes(document): Clarify decision drop documentation
Signature-only PRs can hide skipped review, test, or document steps. Fail unless no-mistakes >= 1.46.0 attests those three steps completed.
…ne step attestation

Batch 5 of eight in the upstream reconciliation campaign, merging six upstream
commits (f242264, 7b38a2f, 87681a4 kunchenguid#2647, 1cb900c kunchenguid#2659, b96dba1 kunchenguid#2707,
a0cec26 kunchenguid#2710) as a single reviewed merge. The plan costed this batch at zero
conflicts; the fork moved since, and four files conflicted.

Resolutions:

bin/fm-test-run.sh - union of the live-harness-optin registrations. The fork's
fm-away-delivery-bound and fm-send-agent-pane entries and upstream's new
fm-herdr-submit-confirm entry are all kept; upstream's fm-bearings-board entry
auto-merged. The fork's FM_TEST_INHERITED_OVERRIDES scrub owner is untouched.

bin/fm-decision-hold.sh - one conflicted line, combined. Upstream's kunchenguid#2707 change
retargets the keyed-answer close at $k_origin/$k_key so a cross-origin full hold
identity resolves correctly; the fork's 918709d change redirects the child's
stdin so it cannot consume the enclosing read loop's remaining answer lines.
These are different fixes to the same call and both are kept. Upstream's new
decline --drop branch is a sibling child of that same loop and carried the
identical stdin defect, so the fork's redirect is extended to it - the gap the
standing upstream-alignment rule keeps ours for.

tests/fm-decision-hold-lifecycle.test.sh - both sides added a whole new test
function, and git aligned them on their shared fixture-channel heredoc. Both
functions are kept in full with their own heredoc and their own registration:
the fork's corrupted-binding diagnostic test and upstream's any-origin
cross-origin closure test.

docs/decision-hold-lifecycle.md - both verification-record hunks are additive;
all three dates are kept and the quoted test output lists both new cases in the
order the suite actually emits them.

.github/workflows/no-mistakes-required.yml arrives byte-identical to upstream:
the fork never modified that file, so it fast-forwarded cleanly.
@zeeshaanahmad
zeeshaanahmad merged commit e3fbc9e into main Sep 2, 2026
13 checks passed
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.

2 participants