Skip to content

Merge upstream template up to a7e01bc (43 commits) - #3

Merged
samchu8 merged 44 commits into
mainfrom
fm/upstream-sync-44
Jul 28, 2026
Merged

samchu8 merged 44 commits into
mainfrom
fm/upstream-sync-44

Conversation

@samchu8

@samchu8 samchu8 commented Jul 28, 2026

Copy link
Copy Markdown

Merge upstream template up to a7e01bc (43 commits)

Brings the fork up to date with kunchenguid/firstmate as far as is safe, stopping deliberately short of the commit that breaks brief generation on this machine.

origin/main is 2 ahead of upstream as well as behind, so this is structurally a merge, not a fast-forward. The fast-forward-only rule governs the home ← origin leg and is untouched by this.

Two corrections to the assessment this implements

The scout report (data/firstmate-upstream-gap/report.md) was written earlier and two of its load-bearing facts did not survive re-verification:

Report claim Measured
a7e01bc is ec09871^, so it is 44 of 71 commits ec09871^ is 6b0d21d. a7e01bc sits 7 commits earlier and brings 43, leaving 28 behind.
Stopping at a7e01bc "should therefore merge clean" False. 2 of the 3 conflicts remain. Only bin/fm-brief.sh — the one that mattered most — auto-merged.

The conflicts do not all trace to ec09871. CONTRIBUTING.md conflicts via six test-infrastructure commits (b843c66, f02eef1, 622d467, f6c281a, 673b6ad, bd43c73); tests/fm-brief.test.sh conflicts via a7e01bc itself plus ea3ac2e, 3729081, bc1a21b.

The report's core recommendation still held: a7e01bc parses, ec09871 does not, and the absorb fix is included.

Verification — all four mandatory gates passed

Gate Result
/bin/bash -n bin/fm-brief.sh under stock Bash 3.2.57 pass — and 0 parse failures across all 88 bin/*.sh + bin/backends/*.sh
Real brief generated end-to-end pass — ship, scout, secondmate charter, and filled-pre-flight variants; 92 lines, all sections, no leaked placeholders beyond the intended {TASK}
tests/fm-brief.test.sh pass 20/20, including both sides' newly added tests
Full suite (bin/fm-test-run.sh --all) 95 scripts, 1583 passing, 3 failing — all pre-existing, see below
bin/fm-lint.sh (ShellCheck 0.11.0 pinned) clean

Confirmed the breakage boundary directly rather than trusting it:

origin/main      PARSE OK
a7e01bc          PARSE OK      <- merged to here
ec09871          PARSE FAIL: line 314: unexpected EOF while looking for matching `)'
upstream/main    PARSE FAIL: line 314: unexpected EOF while looking for matching `)'

The 3 suite failures are not from this merge

Each was reproduced against a pristine a7e01bc tree extracted with git archive:

Test Pre-merge (origin/main) Pristine a7e01bc Cause
fm-gate-refuse.test.sh already failing failing This machine's system Ruby 2.6 cannot require "yaml" at all — psych is broken. Environmental.
fm-nm-test-contract.test.sh test did not exist failing Same broken Ruby. New test arriving from upstream.
fm-backend-orca.test.sh passing failing Upstream defect imported by the merge — fm-spawn --backend orca no longer fails when metadata cannot be written. Not a resolution artifact; reproduces on untouched upstream code. Deferred as out of scope.

Resolved hunks — every one, explicitly

All three resolved by merging intent. Our round-discipline content survives in full.

1. CONTRIBUTING.md — one hunk, 5 lines vs 4.
Kept our fork's sentence bin/fm-brief.sh adds firstmate's version-independent gate-response policy only to no-mistakes ship briefs. and our That wrapper also routes ask-user findings... sentence. Took upstream's fuller lead sentence and both of its .no-mistakes.yaml sentences, because upstream's are now the factually correct ones: the merged .no-mistakes.yaml (which we never edited, so it took upstream's version wholesale) drops commands.test and pins only commands.lint. Our old prose describing a pinned portable-behavior command had become stale against the file it describes.

Behavior change worth noting: local no-mistakes Test is now intent-targeted rather than a full tests/*.test.sh walk. CI owns broad regression. The full suite in this PR was run manually.

2. tests/fm-brief.test.sh, DOD-wording hunk — 4 lines vs 9. Kept ours.
Traced the line across all three refs first. Base 6de9278 and upstream a7e01bc are identical here; only our cf13c9b changed it. So bin/fm-brief.sh auto-merged to our wording correctly, and upstream's three assertions (no-mistakes itself provides for the mechanics, `no-mistakes axi run --help`, `help`) would have asserted against text the generator no longer emits. Upstream's actual intent — that the DOD point at no-mistakes' own installed guidance with literal backticks and no apostrophe artifact — is preserved by our assertion plus the assert_no_grep "no-mistakes' own guidance" guard that both sides already share.

3. tests/fm-brief.test.sh, new-tests hunk — 96 lines vs 19. Kept both sides.
Not a semantic conflict at all: both sides appended different new test functions at the same file position. Ours (pre-flight section ×3, blast-radius framing ×1) and upstream's (test_scout_and_secondmate_scaffold) all survive. The runner list at the bottom of the file had already auto-merged to include all of them.

AGENTS.md auto-merged with all four of our fork lines intact (verified individually): the gate-response policy, the blast-radius line, the pre-flight harvest, and the pre-flight recording instruction.

The headline fix — and exactly what it covers

ab8cea6 "fix(watcher): bound stale wakes for parked crew (kunchenguid#743)" is included. As the report said, crew_absorb_class is byte-identical between us and upstream; the fix is in the caller, pause_state_class in bin/fm-watch.sh.

Against our two live cases, it is a partial fix. Evaluated the merged predicate against the real status lines:

Live case Status verb Covered?
Work parked awaiting a captain decision (spec31d-impl) needs-decision No.
Validation run parked (crew-absorb-cancelled-run) paused Only once the agent is confirmed gone.

status_is_paused_or_captain_held admits exactly two verbs — paused and captain-held. A needs-decision: line is rejected at the gate and early-returns straight into crew_absorb_class, which returns none; the new dead-agent upgrade sits downstream of that early return and never executes. So our most expensive case — a worker parked on a captain decision — is untouched by this fix.

For the paused: case the fix engages, but only via [ "$class" = none ] && [ "$agent_alive" = dead ] && class=paused. Note the merge also adds an earlier short-circuit: for a non-secondmate window whose agent reads alive-or-unknown, pause_state_class now returns none where our current code returned paused unconditionally in the fresh-recheck branch. For a live idle pane this is slightly more surfacing than today, not less. The gain is confined to the dead-agent tail.

Net: upstream handles the dead-agent tail; it does not declare the wait at the source. crew-absorb-cancelled-run (currently held) is not made redundant — the captain's choice between the two implementations still stands, and this merge does not pre-empt it.

The other 42 commits, by area

skills/ — the public installer surface — is completely unchanged (0 commits), as the report found.

Of the four surfaces a running firstmate loads:

Surface Commits Delta
bin/ 35 50 files, +7966 −640
.agents/skills/ 16 8 files, +158 −44
AGENTS.md 14 +20 −14
skills/ 0 —

Non-loaded: tests/ 55 files (+12122), docs/ 25 files (+1802), .github/ 2 files (+264).

Supervision and watcher robustness (the largest and most relevant cluster) — bounded stale wakes for parked crew; ordinary-vs-recovery wake distinction; enriched drained signals with bounded status context; AFK idle stalls and stale run attribution; continuous supervision across child cycles; safe teardown during watcher recovery; watcher process identity immune to Linux wall-clock changes.

Harness breadth — pi session-local Calm mode and its follow-ups (transcript rendering, duplicate replies, stale lock handling, redundant re-arms); Grok exit guidance; opencode busy-queued composer state; canonical operational-input classification across harnesses.

Delivery and forge — GitLab merge requests followed to merge; current PR head fetched for review diffs; every PR body compliance event executed.

Test infrastructure (most of the +12122) — canonical timed runner (bin/fm-test-run.sh), portable shards with bounded local parallelism, concurrent isolation proof, pinned real-Herdr CI coverage.

Herdr — optional presentation spaces, ordering while preserving focus, projected children grouped under owning parents.

Other — quota-aware dispatch profiles; built-in ahoy recap skill (new); Bearings partial-snapshot and main-inventory fixes; secondmate report guards and vocabulary; X-mode pending-mention dedupe.

14 new bin/ scripts and 1 new skill (ahoy) arrive. Note quota-axi becomes a bootstrap tool — already installed here, so no new dependency blocker.

Two things landing that deserve the captain's eye before merge

1. Primary-session delegation fence (50cc24a, kunchenguid#854). The report described this as a permissions.deny list removing 18 tools from the tracked .claude/settings.json. That is not what lands. The tracked settings gain hooks only (+24 lines, no permissions block); the script's own header states the deny list "must not be tracked". Enforcement is a runtime PreToolUse hook, bin/fm-subagent-pretool-check.sh, which denies delegation-shaped tool names by substring — the shipped stem list is agent subagent task workflow cron schedul worktree delegate spawn dispatch handoff remote sendmessage monitor — while exempting observe/stop tools so runaway work can always be inspected or ended.

It is scoped to a genuine primary home (crew worktrees unaffected) and has an FM_ALLOW_SUBAGENT=1 escape hatch. Why it still matters: this home's /pr-review, /implement, /spec-discuss, /merge-train, and /followups fan out sub-agents, and data/captain.md puts the pr-review↔implement loop at the centre of the delivery model. Whether that loop can still run from the primary session is the captain's call, not something this merge should decide silently.

Also arriving on the same surface: a SessionStart nudge hook and a fm-continuity-pretool-check.sh on the Bash matcher.

2. Upstream issue kunchenguid#1188 — watchers and daemons stranded unhealthy after crossing the fm_pid_identity format change (a26b37c). That commit is inside this range. Worth confirming the supervision chain comes back healthy after the home picks this up.

What this does not do

Stops 28 commits behind upstream. Closing the rest requires upstream's Bash 3.2 fix for bin/fm-brief.sh to land first — four competing PRs are open on issue kunchenguid#1179 (kunchenguid#1200, kunchenguid#1199, kunchenguid#1198, and others), none merged. No commits were cherry-picked; this is one contiguous merge, so no third divergence lineage is created.

kunchenguid and others added 30 commits July 17, 2026 14:31
* fix(pi): distinguish stale locks when arming watcher

* no-mistakes(test): Stabilize watcher extension async waits

* no-mistakes(document): Document Pi lock recovery
* fix: accept secondmate as house vocabulary

* no-mistakes(test): Update captain vocabulary contract test

* no-mistakes(document): Align secondmate documentation vocabulary
…uid#686)

* fix: parse secondmate home after pre-field parentheses

Registry summaries often include parentheticals before the structured
(home: ...) field. Match that field with a greedy prefix so handoff
no longer reports "has no home" for those entries.

* no-mistakes(document): Refresh handoff test comments
* feat: add native session-start nudges

* no-mistakes(document): Document nudge script inventory
…nguid#688)

Relabel absent-captain and related domain defaults wording so it names
the firstmate repo rather than treating "template" as this domain's
identity label. Keep the design-tenet "shared template" statements and
unrelated launch/PR-poll template uses unchanged.
…nsion (kunchenguid#205)

* fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn

Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4
(notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom
in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(brief): harden fm-brief regression coverage for parse and scaffolds

Tighten bash -n checking, pin literal backtick rendering in the no-mistakes
DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the

Co-authored-by: Cursor <cursoragent@cursor.com>
kunchenguid#166 apostrophe regression cannot return unnoticed.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…nchenguid#693)

* fix: make watcher supervision continuous

* no-mistakes(review): Bound watcher retries and log attached signals

* no-mistakes(review): Add bounded successor-recovery wake fallbacks

* no-mistakes(review): Prevent overlapping successor-arm retries

* no-mistakes(review): Resume supervision after late arm closes

* no-mistakes(review): Bind OpenCode recovery to attempted arm

* no-mistakes(test): Synchronize peer beacon regression fixture

* no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures

* no-mistakes(document): Captain: document watcher successor protocol behavior

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes
* fix: always fetch PR head for review diffs

Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded
pr_head= so reviewers never hold a merge over a "missing" fix that already
landed on the remote PR. Recorded SHA is offline fallback only; local branch
is last resort with a warning. Store the tip under refs/fm-review/ so a later
base-branch fetch cannot clobber the compare tip via FETCH_HEAD.

* no-mistakes(test): Isolate session-start nudge tests from gate state

* no-mistakes(document): Correct review-diff documentation
…and skills (kunchenguid#736)

* docs: resolve five contract contradictions

* no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck
* docs(harness): reverify grok exit command

* no-mistakes(test): Correct Grok exit resume attribution
* fix(watcher): bound stale wakes for exited paused crew

* no-mistakes(review): Gate pause suppression on confirmed agent death

* no-mistakes(test): Fixed stale pause cadence

* no-mistakes(document): Document dead-agent hold cadence
…id#744)

* fix(supervision): distinguish ordinary wakes from repair

* no-mistakes(review): Make passive guard follow-ups recovery-only

* no-mistakes(document): Clarify recovery-only turn-end guard documentation
* fix(x-mode): dedupe pending mention wakes

* no-mistakes(review): fix x-poll claim error deduplication

* no-mistakes(review): separate claim diagnostics from relay recovery

* no-mistakes(document): Document X-mode once-only mention wakes
…enguid#747)

* feat(wake): enrich drained signal context

* no-mistakes(review): Bound wake enrichment reads

* no-mistakes(document): Document wake-drain annotations

* docs(wake): explain at-least-once drain boundary

* no-mistakes(review): Prevent symlink races in wake annotations

* no-mistakes(review): Exercise wake symlink race regression

* test: document intentional AFK marker subprocesses

* fix(wake): isolate annotation marker state
* feat(herdr): add optional presentation spaces

* no-mistakes(review): Harden Herdr projection creation and spawn serialization

* no-mistakes(review): Captain, disarm Herdr cleanup before launch submission

* no-mistakes(test): Correct stale Orca metadata failure fixture

* no-mistakes(document): Document Herdr presentation projection accurately
…nchenguid#775)

* fix(send): treat opencode busy-queued composer state as submitted

When fm-send sends a message to a BUSY opencode crewmate on the tmux
backend, opencode accepts the Enter and queues the message for the next
turn, but leaves the typed text visible in the composer row.  The
submit-verification loop sees a pending composer, exhausts retries, and
reports a false "Enter swallowed" failure while the message is actually
delivered.

Fix: after Enter retries are exhausted and the composer still shows
pending, check fm_pane_is_busy.  If the pane is busy (agent mid-turn,
footer shows "esc interrupt"), the harness queued the message, so
return "empty" (accepted).  On an idle pane, keep returning "pending"
(genuine swallow detection preserved).

Regression tests cover four scenarios:
- busy pane + pending composer -> empty (message queued)
- idle pane + pending composer -> pending (genuine swallow)
- busy pane + composer clears on first Enter -> empty
- idle pane + composer clears on first Enter -> empty (existing path)

* docs: document busy-queued Enter exception across backend docs and skills

Add explanatory comments and backend documentation for the
busy-queued Enter fix (opencode 1.18.4 accepts Enter mid-turn
but keeps typed text in composer until the turn ends):

- bin/fm-tmux-lib.sh: document the busy-aware fallback in the
  file header and above fm_tmux_submit_enter_core
- .agents/skills/afk/SKILL.md: daemon-facing policy note
- .agents/skills/harness-adapters/SKILL.md: harness-specific fact
- docs/tmux-backend.md: submit-acknowledgement section with the
  busy-queue exception
- docs/herdr-backend.md: record the known gap
- docs/architecture.md: cross-reference in the daemon section

* test(tmux): fix SC2181 and make busy-submit test executable
…unchenguid#765)

* fix(spawn): require two stable reads before accepting worktree path

The treehouse-get worktree-detection loop in fm-spawn.sh accepted the
first pane_current_path read that differed from the project path, but
on some tmux/WSL setups a brand-new window transiently reports a
stale-but-real path before the pane actually settles into the
worktree. Since that stale path is itself a real, distinct git
checkout, it also passes validate_spawn_worktree's isolation check,
so the loop silently recorded the wrong worktree in state/<id>.meta
(and, for claude harness spawns, installed the turn-end hook there
too).

Require two consecutive polls to agree on the same non-project path
before accepting it, using the existing inter-poll sleep as the
confirmation gap so an already-settled pane isn't slowed down by an
extra cycle.

* fix(tests): drop unused CASE_DIR read in worktree-settle test

ShellCheck SC2034: CASE_DIR is split out of the case record but
never referenced; discard it with _ instead.

---------

Co-authored-by: Freudator86 <tim@allesknut.de>
…anges (kunchenguid#752)

* fix(watcher): stabilize Linux process identity

* no-mistakes(document): document FM_PROC_ROOT_OVERRIDE and Linux starttime identity rationale
* fix(supervision): verb-aware captain relevance, AFK wedge, head-bound state

Stop free-text tokens like "merged" from promoting nonterminal working: lines
to captain-relevant, so AFK no longer permanently suppresses idle recovery.
Defend wedge aging independently for nonterminal progress verbs, bind
no-mistakes current-state attribution to code identity (not branch alone),
and mark setup-complete as nonterminal in the ship brief scaffold.

* no-mistakes(review): Enforce nonterminal suppression and head-bound run attribution

* no-mistakes(document): Document current-code-bound run attribution

* no-mistakes(test): Wait for stable Herdr shell readiness

* no-mistakes(test): Make Herdr and watcher readiness tests deterministic

* no-mistakes(test): Make tmux capture and watcher lifecycle deterministic

* no-mistakes(document): Document corrected supervision contracts
* fix: allow safe teardown during watcher recovery

* no-mistakes(review): Distinguish unsafe-teardown deny guidance via policy reason code

* no-mistakes(document): Sync continuity-gate docs to allow teardown recovery

* test: mark dynamic teardown fixture literal

* no-mistakes(document): docs: add teardown to continuity gate allow list
…nguid#790)

* feat(herdr): order presentation worker spaces

* fix(herdr): preserve focus during projected cleanup

* no-mistakes(review): Serialize Herdr cleanup and protect active seeded tabs

* no-mistakes(review): Serialize Herdr aborts with guarded focus regressions

* no-mistakes(review): Fall back flat when Herdr serialization is unavailable

* no-mistakes(test): Stabilize watcher startup and AFK handoff tests

* no-mistakes(document): Correct Herdr ordering and focus documentation
…#809)

* Send literal config reread after inherited config push

When declared inherited config changes under an already-running secondmate,
build a per-home instruction from validated destination post-write bytes and
deliver it on the routed secondmate path. Unchanged config sends nothing;
ABSENT represents removal; captain-shared is never inlined. Covers mid-session
config-push and the locked bootstrap convergence path without hardening spawn
against deliberate runtime choice.

* no-mistakes(review): Fix config reread framing, partial propagation, and respawn order

* no-mistakes(review): Send config rereads via durable single-line pointers

* no-mistakes(review): Make failed config rereads retryable

* no-mistakes(review): Make config reread retries generation-safe

* no-mistakes(review): Make config rereads durable and ordered

* no-mistakes(review): Drain retries, bound history, preserve detect-only read-only mode

* no-mistakes(review): Retain write retries and quarantine stale respawn generations

* no-mistakes(review): Preserve exact config reread retries and delivery order

* no-mistakes(review): Preserve exact retry bytes and bounded quarantine pruning

* no-mistakes(document): Consolidated config-reread documentation
* feat(watch): follow GitLab merge requests to merge

The merge watch only understood GitHub pull requests, so a task whose
deliverable is a GitLab merge request was never followed to merge.

Generalize the stored poll identity from owner/repository to a
provider-tagged provider/url/host/path/number record. GitLab runs mostly on
self-hosted instances and its projects nest under groups at no fixed depth,
so the host and the full project path are data in the record rather than
constants, and every consumer rebuilds the URL from those parts and refuses
any record that does not reconstruct it exactly.

The GitLab state is read with plain glab, matching the GitHub path's use of
plain gh, so an upstream checkout needs no extra tooling. Two things about
glab were established by running it rather than assumed, because a wrong
invocation here fails silently into a permanent "not merged":

- glab has no field selector, and its JSON would need a JSON processor that
  firstmate does not require, so the state is read from glab's own field
  output. Only an exact "merged" wakes firstmate, so a changed format stays
  silent instead of reporting a merge.
- glab cannot take a merge request URL the way gh can, because that form
  resolves through the current git repository and the watcher has none. It
  is addressed by project URL and merge request number instead.

An absent glab produces no wake rather than a false merge, and arming
refuses with a clear message since that is the one point where a missing
CLI can still be reported. A GitLab task records no pr_head, which both
consumers already treat as optional. The merge path still addresses GitHub
only and refuses a merge request URL rather than sending it to the wrong
forge.

The record version moves to v2, and the existing non-executing migration
rebuilds an already-armed watch from its recorded URL, so no watch is lost
by upgrading.

docs/gitlab-merge-watch.md records the evidence, taken against the public
fixture project https://gitlab.com/KarotKris/gitlab-merge-watch-fixture.

* no-mistakes(review): Reject github.com host in GitLab MR URL/sidecar validation

* no-mistakes(document): Note GitLab MR URLs are explicitly refused, not just malformed ones, in fm-pr-merge.sh docs
…uid#821)

* feat(herdr): correct all-home child presentation topology

Inherit the presentation opt-in to secondmate homes, label new projected
spaces with the approved corner format, insert each child under its owning
parent under one session-scoped lock, and keep flat non-destructive fallback.

* no-mistakes(review): Exclude secondmates from Herdr presentation projection

* no-mistakes(review): Harden shared Herdr locks and ambiguous child ordering

* no-mistakes(review): Use adjacency-only Herdr child ownership

* no-mistakes(review): Reject foreign legacy projections safely

* no-mistakes(review): Validate Herdr session sockets before projection

* no-mistakes(test): Fix Herdr teardown fixture session socket metadata

* fix(herdr): canonicalize presentation lock socket paths

Always resolve the session socket parent directory so symlink parents
such as /tmp -> /private/tmp cannot split the shared cross-home lock
identity. Refuse relative socket paths. Clarify lock-unavailable warnings.

* no-mistakes(test): Fix Bash-compatible GitLab merge request URL parsing

* no-mistakes(document): Document all-home Herdr child topology

* no-mistakes(lint): Quote fallback provenance string for ShellCheck
* fix(no-mistakes): drop full-suite local Test override

Local no-mistakes Test is intent-targeted; CI Behavior keeps the broad
tests/*.test.sh suite. Keep commands.lint on bin/fm-lint.sh and add a
focused contract test so the override cannot silently return.

* no-mistakes(lint): Make CI contract assertion ShellCheck-clean
* feat(test): add canonical timed suite runner and honest CI timeout

Introduce bin/fm-test-run.sh as the single serial owner for selecting
one script, a family, a conservative changed-file set, or the explicit
complete suite, with per-script timing markers and a JSON artifact.
Wire CI Behavior through the runner, raise the hang-tripwire timeout to
25 minutes, and document entry points without restoring a full-suite
local no-mistakes Test command.

* no-mistakes(review): Captain: fix changed selection and empty summaries

* no-mistakes(review): Captain: fail closed on unmapped changed sources

* no-mistakes(document): Document canonical timed test entry points
* fix: disclose main-home orphan and unstructured inventory gaps

Main Bearings could report an empty fleet while structured in-flight rows
lacked meta or current backlog rows were free-form. Emit main_inventory from
the fleet snapshot, map it into Bearings omitted surfaces and a Charted Next
gate, and keep meta as the only live Underway source.

* no-mistakes(document): Document Bearings inventory-integrity projection

* no-mistakes: apply CI fixes
* feat: add concurrent test isolation proof for Phase 2

Prove an audited portable candidate set passes under concurrent
workers with private mode-0700 temp roots, without enabling
production CI sharding or fm-test-run --jobs.

* no-mistakes(review): Pin isolation proof to audited candidate manifest
* feat(secondmate): parent-owned guards for missed status reports

Marked parent-to-secondmate requests now create a durable pending-reply
expectation with a privacy-safe correlation id before delivery. Transport
success never resolves it; only a correlated parent status or document
pointer does. After a completed turn with no report, the parent sends one
recovery repost and escalates once if that turn is also missed, without
scraping the secondmate conversation or looping.

* no-mistakes(review): Deduplicate wrong-home pending-reply sightings

* no-mistakes(review): Harden pending-reply recovery and escalation guards

* no-mistakes(review): Bound pending-reply backend polling

* no-mistakes(review): Cache pending-reply status scans

* no-mistakes(review): Protect undelivered pending-reply records from scans

* no-mistakes(review): Close pending-reply delivery durability gaps

* no-mistakes(review): Separate pending-reply transport outcomes

* no-mistakes(review): Escalate stalled pending-reply deliveries once

* no-mistakes(review): Resolve attempted deliveries from correlated reports

* no-mistakes(review): Resolve late reports after delivery escalation

* no-mistakes(document): Document pending-reply grace and ownership

* no-mistakes(lint): Silence intentional pending-reply test fixture lint warnings
* feat: add required pinned Herdr CI lane

Install exact Herdr 0.7.4 and Treehouse 2.0.1 with official assets and
SHA-256 pins, run the real-herdr-gated family serially through
fm-test-run with hard-fail on herdr-not-found, and keep portable
Behavior free of claimed Herdr coverage.

* no-mistakes(document): Consolidate real-Herdr CI documentation ownership

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes
kunchenguid and others added 14 commits July 22, 2026 01:16
…guid#841)

* feat: shard portable CI tests after isolation proof

Balance the Phase 2 proven-isolated set into two LPT portable parallel
lanes from Phase 1 timing evidence, keep stateful work in a required
portable serial lane, exclude real Herdr to its dedicated required lane,
and prove complete inventory coverage with a deterministic guard.
Add bounded local --jobs only for the proven set, per-lane timing plus
aggregate artifacts, and reduce the interim portable hang tripwire now
that the serial remainder owns the long wall-clock path.

* no-mistakes(review): Captain, fix CI contracts and completion-order worker scheduling

* no-mistakes(review): Captain, preserve stderr gate-skip detection in parallel tests

* no-mistakes(document): Document portable sharding and timing aggregation

* no-mistakes: apply CI fixes
)

* feat: fence primary-session delegation outside the fleet

A firstmate primary that delegates through Claude Code's built-in
delegation tools creates work with no state/<id>.meta. Because
fm-supervision-lib.sh counts *.meta and fm-turnend-guard.sh exits
silently at zero, such work does not merely go unsupervised: it makes
the whole guard stack structurally inert, and it dies with the primary
session. On 2026-07-22 that cost two workers mid-flight and left
supervision down for 73 minutes unnoticed.

Layer 1, the primary fix: a permissions.deny list in
.claude/settings.json removes the 18 delegation, scheduling, worktree,
and task-tracking tools from the model's schema, so they are never
offered. This is removal rather than interception, so there is no call
to intercept and no fail-open path. The list is flat and in one file so
its width stays reviewable; the captain owns that width.

Layer 2, bin/fm-subagent-pretool-check.sh: a deny list is fail-open
against tools that do not exist yet, and permissions.allow is a
pre-approval list rather than an availability list, so there is no
fail-closed allowlist to use instead. This backstop classifies the tool
NAME by shape rather than against a fixed list, so a delegation tool
that ships before the deny list is updated is still refused. It excludes
mcp__* names and observe-or-stop operations, scopes itself to a genuine
primary home via the shared fm_primary_scope_matches predicate so a
crewmate's task worktree is unaffected, and offers one deliberate
FM_ALLOW_SUBAGENT=1 escape hatch that must be set at launch.

Verified live against Claude Code 2.1.217, including a deny-key A/B with
a nonsense-name control, layer 2 denying an un-denied Workflow call, the
same call allowed in a linked worktree, and the escape hatch. Corrects a
prior finding: both Task and Agent work as deny keys, so both are
pinned. Codex 0.144.1 verified to expose no delegation tool; grok,
opencode, and pi are inspected and documented as not wired because those
binaries are absent from this host and the repo requires live validation
before trusting a harness hook. Evidence in docs/subagent-guard.md.

* no-mistakes(review): Ship scoped Claude delegation guard

* no-mistakes(test): Ship Claude delegation deny list

* no-mistakes(document): Clarify PreToolUse guard ownership

* no-mistakes(lint): Keep Claude deny list local
Reproduction: portable-parallel-2 completed successfully without tasks-axi while fm-decision-hold-lifecycle emitted a gate skip in 30 ms. The pre-shard lane installed tasks-axi and exercised the test fully. Installing tasks-axi is the smallest counterfactual and makes the representative shard execute the test with gate_skip=false in about 20 seconds. Both parallel jobs receive symmetric setup, while the exact 91-test inventory and coverage guard remain unchanged.
* feat: make dispatch profiles quota aware

* no-mistakes(review): Fix quota window and Grok product scoping

* no-mistakes(document): Document implicit quota-aware dispatch accurately
…guid#875)

* fix: preserve mixed Bearings projections

* no-mistakes(review): Enforce strict invalidity precedence for partial snapshots

* no-mistakes(review): Enforce ownership for unknown child metadata

* no-mistakes(document): Document partial structured Bearings projections

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes
* Add session-local Pi calm mode

* no-mistakes(review): Preserve Pi HTML exports during calm mode

* no-mistakes(review): Preserve calm exports across submit bindings and share

* no-mistakes(document): Document calm-mode feasibility across supported harnesses
* fix(pi): limit watcher arm tool to recovery

* no-mistakes(review): Strengthen Pi live re-arm regression coverage

* no-mistakes(document): Document Pi first-cycle and recovery-only watcher arming
* fix(pi): clean up Calm transcript rendering

* no-mistakes(review): Captain, preserve Calm exports and classify Pi launch briefs

* no-mistakes(review): Captain, eliminate Calm gaps and verify exported conversations

* no-mistakes(review): Restore Calm rows received while active

* no-mistakes(review): Preserve diagnostics during Calm restoration

* no-mistakes(document): Clarify Calm transcript behavior and injection paths
* fix: execute every PR body compliance event

* no-mistakes(document): Document independent PR compliance events
…#899)

* fix: distinguish operational input in ahoy

* no-mistakes(review): Handle legacy Ahoy operational boundaries

* no-mistakes(review): Narrow legacy Ahoy boundaries with live regressions

* no-mistakes(document): Document Ahoy operational marker ownership

* no-mistakes(lint): Suppress intentional literal fixture lint warnings
…nguid#909)

* fix: type canonical operational inputs

* no-mistakes(document): Correct canonical operational-input documentation ownership
* fix: avoid generic secondmate acknowledgements

* no-mistakes(document): Document sparse secondmate acknowledgement behavior

* no-mistakes: apply CI fixes
Sync the fork with kunchenguid/firstmate up to a7e01bc (2026-07-23), stopping
deliberately one region short of ec09871, which introduces a bin/fm-brief.sh
that does not parse under stock macOS Bash 3.2 and would break every worker
dispatch in this home.

origin/main is 2 ahead of upstream as well as behind, so this is structurally a
merge, not a fast-forward. The fast-forward-only rule governs the home<-origin
leg and is untouched.

Headline fix imported: ab8cea6 (kunchenguid#743) bounds stale wakes for parked crew by
teaching pause_state_class about captain-held work plus an agent-liveness check.

Conflicts resolved by merging intent, not by picking a side:
- CONTRIBUTING.md: kept the fork's gate-response-policy sentence, took
  upstream's fuller guidance wording and its two factually-current sentences
  about .no-mistakes.yaml, which now pins only commands.lint.
- tests/fm-brief.test.sh (DOD wording): kept the fork's assertion, which is the
  one matching the merged generator; upstream never changed that line, so
  bin/fm-brief.sh correctly auto-merged to the fork's wording and upstream's
  three assertions would have failed against real output. Upstream's intent is
  preserved by the apostrophe guard both sides share.
- tests/fm-brief.test.sh (new tests): purely additive collision at one file
  position; both sides' new tests kept.

Verification: bash 3.2 parses all 88 bin scripts; a real brief generates
well-formed across ship, scout, secondmate, and filled-pre-flight variants;
tests/fm-brief.test.sh passes 20/20; full suite 95 scripts, 1583 passing;
bin/fm-lint.sh clean.

Three suite failures remain, all reproduced at pristine upstream a7e01bc and
none introduced by this merge: two from a broken system Ruby YAML on this
machine, one an upstream Orca spawn defect.
@samchu8
samchu8 merged commit 9805c4d into main Jul 28, 2026
8 of 9 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.