Skip to content

feat(bin): sync upstream firstmate main through 43bf6d3d into the fork - #52

Merged
andrewesweet merged 21 commits into
mainfrom
fm/fm-upstream-sync-4
Sep 21, 2026
Merged

andrewesweet merged 21 commits into
mainfrom
fm/fm-upstream-sync-4

Conversation

@andrewesweet

@andrewesweet andrewesweet commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

Intent

Merge upstream firstmate main through 43bf6d3 into this fork's main using a true two-parent merge commit, then ship the result. Conflict policy: upstream wins where the fork merely carried upstream code; the fork's genuine additions are re-applied on top; the fork's behavior wins on genuine differences. Required fork invariants: the compact-adviser disable path stays removed (the compact adviser must remain enabled on every launch path) with the two upstream delete/modify tests kept deleted; the fork's brief contract (Captain's intent, Published intent, Firstmate spec) and dod-lib intent rules stay intact; upstream's brief-include and inbox-capture features are taken. Four follow-up commits align fork tests and fixtures with the merged contract (status-event stamps, away-words authority model, published-intent fixture, regenerated agent definition). Full local regression already ran before the PR; CI green is the remaining gate.

What Changed

  • Takes sixteen upstream commits: fm-inbox.sh gains idempotent capture, reply, receipts, ready and readiness JSON; fm-brief.sh appends an optional config/brief-include.md home-local section to ship and scout briefs; status events (done, needs-decision, resolved, CI-wait) carry [at=<epoch>] stamps; fm-afk-contract.sh is rewritten around the captain's away words as the single mandate, with fm-pr-merge.sh reading the record for away merge authority; plus Lavish feedback routing to owning workers, herdr endpoint reclaim, deferred wedge escalation at supervisor-owed gates, and long launch-command truncation fixes.
  • Keeps the fork's invariants across the merge: the compact-adviser disable path stays removed (adviser enabled on every launch path, the two upstream delete/modify tests stay deleted), and the brief contract (Captain's intent, Published intent, Firstmate spec) with fm-dod-lib.sh intent rules remains intact while its status-line templates adopt the epoch stamps.
  • Aligns fork tests and fixtures with the merged contract: fm-brief.test.sh expects stamped DOD lines, the merged-span trace test follows the away-words authority model, the herdr relaunch fixture gains a Published intent section, .claude/mods/fm-branch-mod/agents/fm-branch.md is regenerated, and .no-mistakes.yaml gains Herdr lab test instructions.

🤖 Generated with Claude Code

Risk Assessment

✅ Low: The rebased tree reproduces the true merge 6d2ac69 plus origin/main byte-for-byte apart from one correctly resolved docs conflict, every manual conflict resolution follows the stated policy (compact-adviser path removed, brief/DOD contract intact, upstream brief-include and inbox capture taken), and the four follow-up commits align tests and the regenerated agent definition with source that verifiably emits those forms.

Testing

Ran 13 targeted suites through bin/fm-test-run.sh (all green), then drove the product directly: a spawn probe that executes the real emitted launch under a synthetic pane with an env-printing harness across six launch shapes, a live fm-brief scaffold with a home include plus its refusal path, a spawn against a pre-contract brief, an fm-inbox capture/replay/ready/receipts/reply transcript, and a classify-lib round-trip of stamped status lines. bin/fm-branch-agent-md.sh --check confirms the regenerated agent definition is current. Everything passed; no UI surface in this change, so no screenshots.

  • Live validation: ✅ go - 13 of 13 scenarios driven live against the product
Scenario Result Live Evidence
Spawned ship worker (allowlist absent and enabled) starts with the compact adviser enabled: executed launch shows COMPACT_ADVISER_DISABLE unset ✅ pass live compact-adviser-enabled-probe.log cases ship-open, ship-filtered
Spawned secondmate (both allowlist postures) starts with the compact adviser enabled ✅ pass live compact-adviser-enabled-probe.log cases sm-absent, sm-enabled
fm-control relaunch rebuilds the launch without the compact-adviser switch (both allowlist postures) ✅ pass live compact-adviser-enabled-probe.log cases relaunch absent/enabled
Upstream delete/modify tests stay deleted and no compact-adviser-disable reference exists in the tree ✅ pass live ls tests/fm-spawn-compact-adviser-disable* no such file; grep empty
fm-brief scaffolds Captain's intent / Published intent / Firstmate spec, stamps status templates with [at=<epoch>], and appends the home brief include as the last section ✅ pass live brief-contract-live.txt; tests/fm-brief.test.sh in targeted-suites.log
Adversarial: a brief include carrying a Delivery contract line is refused before anything is written ✅ pass live brief-contract-live.txt (exit=1, only probe-a1 in data/)
Adversarial: spawn refuses a brief lacking ## Published intent, accepts once added ✅ pass live published-intent-refusal.txt
Inbox capture with --request-id is idempotent (replay, one note, one wake) and ready/receipts/reply JSON round-trip ✅ pass live inbox-capture-live.txt; tests/fm-inbox.test.sh in targeted-suites.log
Stamped status lines (needs-decision/resolved/done/paused with [at=<epoch>]) classify correctly through fm-classify-lib ✅ pass live status-stamp-classify.txt
Away-words authority model: AFK contract, return, launch and merged-span trace assertions hold ✅ pass live tests/fm-afk-contract.test.sh, tests/fm-pr-check-security.test.sh (targeted-suites.log); tests/fm-afk-return.test.sh, tests/fm-afk-launch.test.sh, tests/fm-pr-merge.test.sh (targeted-suites-2.log)
Herdr relaunch fixture carries Published intent and the relaunch suite passes ✅ pass live tests/fm-control-relaunch.test.sh in targeted-suites.log
Regenerated fm-branch agent definition matches its generator ✅ pass live bin/fm-branch-agent-md.sh --check exit 0; tests/fm-branch-claude-mod.test.sh
Orca staged-launch extraction keeps the fork's settings JSON needle (rebase-1 resolution) ✅ pass live tests/fm-backend-orca.test.sh in targeted-suites.log
Evidence: Compact adviser stays enabled on every launch path (executed launch env probe)

Source: Compact adviser stays enabled on every launch path (executed launch env probe)

case=ship-open allowlist=absent pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset case=ship-filtered allowlist=enabled pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset case=sm-absent allowlist=absent pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset case=sm-enabled allowlist=enabled pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset case=relaunch allowlist=absent pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset case=relaunch allowlist=enabled pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset all launch paths leave the compact adviser enabled

case=ship-open allowlist=absent pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset
case=ship-filtered allowlist=enabled pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset
case=sm-absent allowlist=absent pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset
case=sm-enabled allowlist=enabled pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset
case=relaunch allowlist=absent pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset
case=relaunch allowlist=enabled pane-exports-of-switch=0 launch-mentions-switch=0 agent-saw=unset
all launch paths leave the compact adviser enabled
Evidence: Probe script driving the real spawn/relaunch

Source: Probe script driving the real spawn/relaunch

#!/usr/bin/env bash
# Evidence probe: a spawned worker must NOT receive COMPACT_ADVISER_DISABLE from
# Firstmate on any launch path (allowlist absent, allowlist enabled, and a relaunch).
# Drives the real bin/fm-spawn.sh against the shared fake pane, then EXECUTES the
# launch command the pane received with the harness replaced by an env probe.
set -u
ROOT_DIR=${1:?worktree root}
. "$ROOT_DIR/tests/fixtures.sh"
TMP_ROOT=$(fm_test_tmproot fm-compact-adviser-enabled-probe)

probe_case() {  # <name> <allowlist:absent|enabled> [extra spawn args]
  local name=$1 allowlist=$2; shift 2
  local case_dir=$TMP_ROOT/$name home=$TMP_ROOT/$name/home proj=$TMP_ROOT/$name/project wt=$TMP_ROOT/$name/wt
  local fakebin launchlog=$case_dir/launch.log panelog=$case_dir/pane.log out seen
  fakebin=$(fm_test_make_spawn_fakebin "$case_dir/fake")
  fm_test_spawn_home "$home" codex
  fm_git_worktree "$proj" "$wt" "wt-$name"
  fm_test_spawn_brief "$home" "$name-a1"
  [ "$allowlist" = enabled ] && : > "$home/config/launch-env-allowlist"
  : > "$launchlog"; : > "$panelog"
  out=$(FM_FAKE_LAUNCH_LOG="$launchlog" FM_FAKE_PANE_LOG="$panelog" \
    fm_test_run_spawn "$home" "$wt" "$fakebin" "$name-a1" "$proj" --mode no-mistakes --yolo off)
  [ $? -eq 0 ] || { echo "SPAWN FAILED ($name): $out"; exit 1; }
  if [ "${1-}" = --relaunch ]; then
    : > "$launchlog"; : > "$panelog"
    out=$(FM_FAKE_LAUNCH_LOG="$launchlog" FM_FAKE_PANE_LOG="$panelog" \
      fm_test_run_spawn "$home" "$wt" "$fakebin" "$name-a1" --relaunch)
    [ $? -eq 0 ] || { echo "RELAUNCH FAILED ($name): $out"; exit 1; }
  fi
  # replace harness with env probe, then execute what the pane got
  printf '#!/bin/sh\nprintf "%%s\\n" "${COMPACT_ADVISER_DISABLE-unset}"\n' > "$fakebin/codex"; chmod +x "$fakebin/codex"
  local preamble; preamble=$(grep '^export ' "$panelog" || true)
  seen=$(env -i HOME="$TMP_ROOT/pane-home" PATH="$fakebin:$PATH" TERM=xterm TMUX=synthetic-pane \
    /bin/sh -c "$preamble
$(cat "$launchlog")")
  echo "case=$name allowlist=$allowlist pane-exports-of-switch=$(grep -c 'COMPACT_ADVISER_DISABLE' "$panelog" || true) launch-mentions-switch=$(grep -c 'COMPACT_ADVISER_DISABLE' "$launchlog" || true) agent-saw=$seen"
  [ "$seen" = unset ] || { echo "FAIL: agent started with COMPACT_ADVISER_DISABLE=$seen"; exit 1; }
}
probe_case ship-open absent
probe_case ship-filtered enabled

secondmate_case() {  # <setting>
  local setting=$1; local name=sm-$setting
  local case_dir=$TMP_ROOT/$name home=$TMP_ROOT/$name/home sm=$TMP_ROOT/$name/secondmate-home
  local fakebin launchlog=$case_dir/launch.log panelog=$case_dir/pane.log out seen
  fakebin=$(fm_test_make_spawn_fakebin "$case_dir/fake")
  fm_test_spawn_home "$home" codex
  fm_test_spawn_brief "$home" "$name"
  [ "$setting" = enabled ] && : > "$home/config/launch-env-allowlist"
  mkdir -p "$sm/bin" "$sm/data"
  printf '# Firstmate\n' > "$sm/AGENTS.md"
  printf '%s\n' "$name" > "$sm/.fm-secondmate-home"
  printf 'charter for %s\n' "$name" > "$sm/data/charter.md"
  : > "$launchlog"; : > "$panelog"
  out=$(FM_FAKE_LAUNCH_LOG="$launchlog" FM_FAKE_PANE_LOG="$panelog"     fm_test_run_spawn "$home" "$sm" "$fakebin" "$name" "$sm" --secondmate)
  [ $? -eq 0 ] || { echo "SECONDMATE SPAWN FAILED ($name): $out"; exit 1; }
  printf '#!/bin/sh\nprintf "%%s\\n" "${COMPACT_ADVISER_DISABLE-unset}"\n' > "$fakebin/codex"; chmod +x "$fakebin/codex"
  local preamble; preamble=$(grep '^export ' "$panelog" || true)
  seen=$(env -i HOME="$TMP_ROOT/pane-home" PATH="$fakebin:$PATH" TERM=xterm TMUX=synthetic-pane     /bin/sh -c "$preamble
$(cat "$launchlog")")
  echo "case=$name allowlist=$setting pane-exports-of-switch=$(grep -c 'COMPACT_ADVISER_DISABLE' "$panelog" || true) launch-mentions-switch=$(grep -c 'COMPACT_ADVISER_DISABLE' "$launchlog" || true) agent-saw=$seen"
  [ "$seen" = unset ] || { echo "FAIL: secondmate started with COMPACT_ADVISER_DISABLE=$seen"; exit 1; }
}
secondmate_case absent
secondmate_case enabled

# fm-control.sh relaunch: rebuilds the launch through bin/fm-spawn.sh --relaunch.
relaunch_case() {  # <setting>
  local setting=$1; local id=relaunch-$setting-a1 dir=$TMP_ROOT/relaunch-$setting
  local home=$dir/home proj=$dir/proj wt=$dir/wt fb=$dir/fakebin out seen launch preamble
  mkdir -p "$home/state" "$home/data" "$home/config" "$home/projects" "$dir/fake" "$fb" "$dir/user-home"
  touch "$home/state/.last-watcher-beat"
  [ "$setting" = enabled ] && : > "$home/config/launch-env-allowlist"
  cat > "$fb/tmux" <<'SH'
#!/usr/bin/env bash
set -u
D=$FM_FAKE_DIR
case "${1:-}" in
  send-keys)
    shift; literal=0
    while [ $# -gt 0 ]; do case "$1" in -t) shift 2 ;; -l) literal=1; shift ;; *) break ;; esac; done
    payload=${1:-}
    if [ "$literal" = 1 ]; then
      case "$payload" in
        ". '"*"'") staged=${payload#". '"}; staged=${staged%"'"}; [ ! -f "$staged" ] || payload=$(cat "$staged") ;;
      esac
      printf '%s\n' "$payload" >> "$D/literal"
      case "$payload" in /exit|/quit) printf 'zsh' > "$D/command" ;; *'encode launch-brief'*) printf 'codex' > "$D/command" ;; esac
    else printf '%s\n' "$payload" >> "$D/keys"; fi
    exit 0 ;;
  display-message)
    for a in "$@"; do case "$a" in *cursor_y*) printf '1\n'; exit 0 ;; *pane_current_command*) cat "$D/command"; printf '\n'; exit 0 ;; *pane_current_path*) cat "$D/cwd"; printf '\n'; exit 0 ;; esac; done
    printf 'fakepane\n'; exit 0 ;;
  capture-pane) printf '╭────╮\n│    │\n╰────╯\n'; exit 0 ;;
  list-windows) [ -f "$D/windows" ] && cat "$D/windows"; exit 0 ;;
esac
exit 0
SH
  printf '#!/usr/bin/env bash\nexit 0\n' > "$fb/sleep"; chmod +x "$fb/tmux" "$fb/sleep"
  fm_git_worktree "$proj" "$wt" "wt-$id"
  fm_test_spawn_brief "$home" "$id"
  : > "$dir/fake/literal"; : > "$dir/fake/keys"
  printf 'codex' > "$dir/fake/command"; printf '%s\n' "fm-$id" > "$dir/fake/windows"; printf '%s' "$wt" > "$dir/fake/cwd"
  { echo "window=fmses:fm-$id"; echo "endpoint_task_id=$id"; echo "worktree=$wt"; echo "project=$proj"; echo "harness=codex"
    echo "kind=ship"; echo "mode=no-mistakes"; echo "yolo=off"; echo "tasktmp=$dir/tasktmp"; echo "model=default"; echo "effort=default"; } > "$home/state/$id.meta"
  out=$(env PATH="$fb:$PATH" FM_HOME="$home" FM_FAKE_DIR="$dir/fake" HOME="$dir/user-home" CLAUDE_CONFIG_DIR='' FM_SPAWN_NO_GUARD=1     FM_CONTROL_POLL=0.01 FM_CONTROL_EXIT_WAIT=0.05 FM_CONTROL_LAUNCH_WAIT=0.05     "$ROOT_DIR/bin/fm-control.sh" "$id" relaunch --note 'replacement continues the same task' 2>&1)
  [ $? -eq 0 ] || { echo "RELAUNCH FAILED ($id): $out"; exit 1; }
  launch=$(grep 'encode launch-brief' "$dir/fake/literal" | tail -1)
  [ -n "$launch" ] || { echo "RELAUNCH ($id): no replacement launch sent"; exit 1; }
  printf '#!/bin/sh\nprintf "%%s\\n" "${COMPACT_ADVISER_DISABLE-unset}"\n' > "$fb/codex"; chmod +x "$fb/codex"
  preamble=$(grep '^export ' "$dir/fake/keys" || true)
  seen=$(env -i HOME="$dir/user-home" PATH="$fb:$PATH" TERM=xterm TMUX=synthetic-pane /bin/sh -c "$preamble
$launch")
  echo "case=relaunch allowlist=$setting pane-exports-of-switch=$(grep -c 'COMPACT_ADVISER_DISABLE' "$dir/fake/keys" || true) launch-mentions-switch=$(printf '%s' "$launch" | grep -c 'COMPACT_ADVISER_DISABLE' || true) agent-saw=$seen"
  [ "$seen" = unset ] || { echo "FAIL: relaunched agent started with COMPACT_ADVISER_DISABLE=$seen"; exit 1; }
}
relaunch_case absent
relaunch_case enabled
echo "all launch paths leave the compact adviser enabled"
Evidence: Live fm-brief scaffold: contract sections, [at=<epoch>] stamps, home include, refused include

Source: Live fm-brief scaffold: contract sections, [at=<epoch>] stamps, home include, refused include

$ fm-brief.sh probe-a1 some-proj --mode no-mistakes  (config/brief-include.md present)
scaffolded: /tmp/fm-brief-probe.uYqm/data/probe-a1/brief.md (ship, mode=no-mistakes; replace {TASK}, {PUBLISHED_INTENT}, and {FIRSTMATE_SPEC})
exit=0

--- section headings in data/probe-a1/brief.md
3:# Task
4:## Captain's intent
7:## Published intent
10:## Firstmate spec
13:# Herdr lifecycle declaration - NOT ENABLED
18:# Setup
28:# Rules
70:# Firstmate instruction inbox
75:# Project memory
82:# Definition of done
123:# Home brief additions

--- delivery contract + status stamp lines
23:If the top-level path is the primary checkout or not the worktree you were launched in, STOP - do not branch or commit here - append `blocked [at=<epoch>]: launched in primary checkout, not an isolated worktree` to the status file and stop.
33:   `echo "{state} [at=<epoch>]: {one short line}" >> '/tmp/fm-brief-probe.uYqm/state/probe-a1.status'`
49:5. If you hit the same obstacle twice, append `blocked [at=<epoch>]: {why}` and stop; firstmate will help.
51:   append `needs-decision [at=<epoch>]: {summary of options}` and stop. Firstmate will reply with the decision.
53:   `needs-decision [at=<epoch>] [key=nm-<run>-<step>]: ask-user findings=<id1>,<id2>,... file=/tmp/fm-brief-probe.uYqm/data/probe-a1/nm-<run>-findings.txt`
56:   Firstmate's reply normally writes that closing line at answer time; when a blocker or wait clears WITHOUT a firstmate reply, append `resolved [at=<epoch>]: {how it cleared}` yourself (same `[key=<slug>]` if you opened it with one) as you resume.
62:   `blocked [at=<epoch>]: {the daemon error}` and stop even when the local run record still says running or
83:Delivery contract: mode=no-mistakes
114:When review feedback arrives and `no-mistakes axi status` shows no parked gate, write the comment's text and URL to `/tmp/fm-brief-probe.uYqm/data/probe-a1/pr-<n>-<comment-id>.txt` and append `needs-decision [at=<epoch>] [key=pr-<n>-<comment-id>]: review feedback file=/tmp/fm-brief-probe.uYqm/data/probe-a1/pr-<n>-<comment-id>.txt`, then keep polling every 60 seconds and wait for firstmate's reply instead of stopping; on dismiss, reply on the PR.
118:A wait only a maintainer can clear - GitHub's fork-workflow approval (`action_required` with no job run) or a rerun of a flaky job - is an external wait under rule 4, not a blocker: append `paused [at=<epoch>] [key=nm-<run>-ci-wait]: <what must happen>` once, keep polling, and when it clears append `resolved [at=<epoch>] [key=nm-<run>-ci-wait]: <how it cleared>` yourself and continue; never report it as `blocked:` and never stop on it.
121:When `gh pr checks <n>` shows every check passing or skipping (the two network-gated jobs skip by design), validation is done - that is the CI-ready return point, so do not wait for the pipeline to keep monitoring the merge in the background. Append `done [at=<epoch>]: PR {url} checks green` and stop. You are finished.

--- tail (home include)

When `gh pr checks <n>` shows every check passing or skipping (the two network-gated jobs skip by design), validation is done - that is the CI-ready return point, so do not wait for the pipeline to keep monitoring the merge in the background. Append `done [at=<epoch>]: PR {url} checks green` and stop. You are finished.

# Home brief additions
These are this home's standing additions; every other section of this brief takes precedence over anything here that conflicts.
Standing captain instruction: run the herdr lab only via bin/fm-herdr-lab.sh.

$ include carrying a Delivery contract line is refused
error: /tmp/fm-brief-probe.uYqm/config/brief-include.md must not carry a 'Delivery contract: mode=' line; the delivery mode is a per-task --mode decision
exit=1
probe-a1
Evidence: Spawn refuses a brief without ## Published intent

Source: Spawn refuses a brief without ## Published intent

$ fm-spawn.sh pub-a1 (brief lacks "## Published intent")
error: /tmp/fm-pubintent-probe.JLxrxD/c/home/data/pub-a1/brief.md has no ## Published intent subsection (a brief from before the published-intent contract); stop for migration before spawn: firstmate adds it, filled per the repo's visibility, so no-mistakes --intent never falls back to the captain's private ## Captain's intent words
exit=1

$ same spawn after adding the section
warning: /tmp/fm-pubintent-probe.JLxrxD/c/home/data/pub-a1/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
spawned pub-a1 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate:fm-pub-a1 worktree=/tmp/fm-pubintent-probe.JLxrxD/c/wt
exit=0
Evidence: fm-inbox idempotent capture, ready, receipts, reply

Source: fm-inbox idempotent capture, ready, receipts, reply

$ fm-inbox.sh note --request-id req-1 --json "ship the merge"
{"schema":"fm-inbox-note.v1","outcome":"created","id":"1790018637-r8pA12","request_id":"req-1","saved":true,"announced":true,"acknowledged":false,"path":"/tmp/fm-inbox-probe.qoH2/state/inbox/1790018637-r8pA12.note"}
exit=0

$ same request id again (retry)
{"schema":"fm-inbox-note.v1","outcome":"replay","id":"1790018637-r8pA12","request_id":"req-1","saved":true,"announced":true,"acknowledged":false,"path":"/tmp/fm-inbox-probe.qoH2/state/inbox/1790018637-r8pA12.note"}
exit=0

notes on disk: 1   inbox wakes queued: 1

$ fm-inbox.sh ready
{"schema":"fm-primary-ready.v1","home":"tmp/fm-inbox-probe.qoH2","observed_at":"2026-09-21T19:23:58Z","lock":{"state":"free","pid":null,"live_harness":false},"wake_consumer":{"state":"unknown","reason":"supervision-model-unknown-for-home","beacon_age_seconds":null},"posture":{"state":"present"},"can_receive":false}
exit=0

$ fm-inbox.sh receipts
{"schema":"fm-inbox-receipts.v1","home":"tmp/fm-inbox-probe.qoH2","generated":"2026-09-21T19:23:58Z","pending":[{"id":"1790018637-r8pA12","at":"2026-09-21T19:23:57Z","source":"text","request_id":"req-1","body":"ship the merge","acknowledged":false,"announced":true,"reply":null}],"handled":[],"replies":[],"reply_cursor":"","omitted":[]}

$ fm-inbox.sh reply --json 1790018637-r8pA12 "merged, thanks"
{"schema":"fm-inbox-reply.v1","outcome":"created","id":"1790018637-r8pA12","path":"/tmp/fm-inbox-probe.qoH2/state/inbox/.replies/1790018637-r8pA12"}
exit=0

$ fm-inbox.sh receipts --all-replies
{"schema":"fm-inbox-receipts.v1","home":"tmp/fm-inbox-probe.qoH2","generated":"2026-09-21T19:23:58Z","pending":[{"id":"1790018637-r8pA12","at":"2026-09-21T19:23:57Z","source":"text","request_id":"req-1","body":"ship the merge","acknowledged":false,"announced":true,"reply":{"id":"1790018637-r8pA12","at":"2026-09-21T19:23:58Z","body":"merged, thanks","cursor":"000000000001"}}],"handled":[],"replies":[{"id":"1790018637-r8pA12","at":"2026-09-21T19:23:58Z","body":"merged, thanks","cursor":"000000000001"}],"reply_cursor":"000000000001","omitted":[]}
Evidence: Stamped status lines through fm-classify-lib

Source: Stamped status lines through fm-classify-lib

# stamped DOD status lines as a worker writes them, read back through bin/fm-classify-lib.sh
line: needs-decision [at=1790018000] [key=nm-42-review]: ask-user findings=r1 file=/x/nm-42-findings.txt
  verb=needs-decision  at_epoch=1790018000  open-needs-decision(run 42)=yes
after resolved: open-needs-decision=no  open-decisions=[]
line: done [at=1790018200]: PR https://github.com/x/y/pull/1 checks green
  verb=done terminal=yes captain-relevant=yes at_epoch=1790018200
  paused [at=1790018300] [key=nm-42-ci-wait]: fork-workflow approval => paused=yes
Evidence: Targeted suites batch 1 (8 suites)

Source: Targeted suites batch 1 (8 suites)

FM_TEST_BEGIN 2026-09-21T19:12:45Z tests/fm-brief.test.sh family=pure-contract-unit expected_gate_skip=none
ok - fm-brief: scaffolds leave the worker role scope to the launch boundary and keep the secondmate contract
ok - fm-brief.sh: bash -n succeeds
/tmp/fm-test-run.CSBq3T/w1/tmp/fm-brief.88Jhjw/heredoc-in-substitution.sh:2
ok - fm-brief.sh: no heredoc is nested inside a command substitution (Bash 3.2 parse-safe)
ok - fm-brief.sh: --help renders the complete header
ok - fm-brief.sh: no-mistakes/direct-PR/local-only briefs generate cleanly
ok - fm-brief.sh: ship --mode is required and closed-set validated
ok - fm-brief.sh: the explicit ship mode wins over the registered posture
ok - fm-brief.sh: --yolo and scout/secondmate --mode are refused, never silently dropped
ok - fm-brief.sh: faster paths use configured authority without stacked review
ok - fm-brief.sh: no-mistakes DOD keeps its apostrophe prose and bans --yes outright
ok - fm-brief.sh: no-mistakes ask-user findings use one event plus a verbatim snapshot
ok - fm-brief.sh: ship project-memory wording carries the AGENTS.md authoring bar
ok - fm-brief.sh: --herdr-lab emits the complete hard safety contract
ok - fm-brief.sh: --herdr-lab uses its quoted Firstmate-owned helper path
ok - fm-brief.sh: ship and scout scaffolds make omitted Herdr intent fail-visible
ok - fm-brief.sh: the documented {TASK} and {FIRSTMATE_SPEC} fills cannot corrupt the Herdr safety gate
ok - fm-brief.sh: Herdr lab contract covers scouts and rejects secondmate misuse
ok - fm-brief.sh: --no-projects scaffolds a project-less charter and guards misuse
ok - fm-brief.sh: marked requests avoid generic acknowledgements and preserve material reporting
ok - fm-brief.sh: relative directory inputs ignore CDPATH, render stable absolute charter paths, or fail loudly
ok - fm-brief.sh: custom pause verb renders in every scaffold
ok - fm-brief.sh: ship and scout scaffolds teach validation-round pauses
ok - fm-brief.sh: investigation and visual-review completions load the shared decision policy
ok - fm-brief: scout and secondmate code paths still scaffold well-formed briefs
ok - fm-brief.sh: scout Lavish hosting follows the bootstrap lavish-axi floor
ok - fm-brief.sh: the home brief include lands last on ship and scout, verbatim, and fails closed
FM_TEST_END 2026-09-21T19:12:53Z tests/fm-brief.test.sh exit=0 duration_ms=7880 gate_skip=false
FM_TEST_BEGIN 2026-09-21T19:12:53Z tests/fm-branch-claude-mod.test.sh family=pure-contract-unit expected_gate_skip=none
ok - the mod is one hooks module and one agent, reached only through --plugin-dir, with no command, skill, or classic hook path
ok - agents/fm-branch.md is current with bin/fm-branch-agent-md.sh and names the agent and tools the module spawns
ok - lib/ resolves to the mod's canonical modules and the eligibility wrapper loads
FM_TEST_END 2026-09-21T19:12:53Z tests/fm-branch-claude-mod.test.sh exit=0 duration_ms=208 gate_skip=false
FM_TEST_BEGIN 2026-09-21T19:12:53Z tests/fm-pr-check-security.test.sh family=pr-forge expected_gate_skip=none
ok - raw-byte parser accepts canonical URLs and rejects the complete adversarial matrix
ok - GitLab merge requests are followed on any instance and never wake falsely
ok - validated merged polls notify once and retire before the next watcher cycle
ok - a repeat identical merged poll for an already-notified task is absorbed, never queued as a main-blocking row
ok - a failed upward merge report keeps its poll armed for repair and retry
ok - staged self-merge and poll interleavings are never silent
ok - queued merges retain their away authority after captain return
ok - poll distinguishes attended authorization from external landing
ok - validated PR registrations emit ready spans; rejections, disabled homes, and export failures stay silent
ok - self and poll merge observations share one publication-owned merged span
ok - poll-detected merges carry origin and the persisted or external authority
ok - accepted merge authority refuses rebound task metadata
ok - accepted merge authority persists under the lifecycle lock
ok - teardown cannot race merged-poll authority consumption
ok - poll retirement preserves a replacement authority record
ok - a merge detected by the poll is reported upward from a secondmate home exactly once
ok - a different merged PR for the same task gets its own first notification
ok - merged poll retirement preserves every persistent secondmate lifecycle artifact
ok - queue, receipt, and every fixed-path removal crash point recover without loss or repeated execution
ok - open/red, closed-unmerged, malformed, and forge errors remain armed until an exact merged transition
ok - replacement, nonterminal, tampered, and custom results receive no deletion authority
ok - queue failure and untrusted receipts preserve canonical poll evidence
ok - GitHub and GitLab exact merged results share one retirement path
ok - PR and teardown entrypoints reject invalid arguments before every side effect
ok - valid direct and merge flows record exact metadata and reject multiline head metadata
ok - rejected metacharacter bytes remain inert at generation and watcher time
ok - static poll is silent except for one merged line and remains watcher-bounded
ok - interrupted atomic preparation cleans private temporaries and publishes nothing
ok - concurrent watchers observe only complete private poll publications
ok - poll publication paths refuse symlinks and directories
ok - live poll and custom-check artifacts require private single-link files
ok - a poll armed before a volume renumber is re-recorded under the control lock and keeps detecting merges
ok - a renumbered registration is never re-recorded around a tampered artifact: swapped-check altered-check swapped-sidecar altered-sidecar altered-template-hash wrong-mode hardlinked-check split-device foreign-device, or a pending retirement
ok - direct re-arm publication waits without replacing an armed poll
ok - device re-record publication waits without rewriting its registration
ok - post-rename poll validation faults revoke both names and allow a clean retry
ok - bootstrap does not rewrite unauthenticated checks or emit retired migration diagnostics
ok - watcher signals promptly stop custom checks and clean private state
ok - returned custom check descendants are drained on installed and fallback timeout paths
ok - teardown removes safe poll artifacts and refuses directory-shaped check files without traversal
FM_TEST_END 2026-09-21T19:17:17Z tests/fm-pr-check-security.test.sh exit=0 duration_ms=263886 gate_skip=false
FM_TEST_BEGIN 2026-09-21T19:17:17Z tests/fm-classify-corr-token.test.sh family=standalone expected_gate_skip=none
ok - captain regex overrides preserve timed and legacy relevance and event bytes
ok - malformed event times stay ordinary line bytes without hiding the event
ok - malformed event times never open or close a decision
ok - optional event time preserves parsing and legacy unknown time
ok - a correlation token between the verb and the key breaks neither opening nor closing
ok - the token is read through before the key, after it, doubled, bracketed, and unkeyed
ok - the untokened opener/closer pair behaves exactly as before
ok - prose, malformed, wrong-length and unknown name=value tokens stay non-transitions
ok - a token-first line cannot impersonate any opening or closing verb
ok - untokened captain-relevance, pause, terminal-verb and captain-held verdicts are unchanged
ok - captain-relevance, terminal-verb, pause and captain-held all read through the token
ok - the daemon and crew-state verb case arms read through the token
ok - reading through the token does not weaken the reserved-key namespace rule
ok - the cursor-backed fold and the whole-file fold agree on every correlated transition
ok - a cursor persisted under the previous reading is discarded and refolded
ok - both real correlation-token writers produce lines this classifier reads through
FM_TEST_END 2026-09-21T19:17:48Z tests/fm-classify-corr-token.test.sh exit=0 duration_ms=30644 gate_skip=false
FM_TEST_BEGIN 2026-09-21T19:17:48Z tests/fm-inbox.test.sh family=unclassified expected_gate_skip=none
ok - plain note, li

... [6618 bytes truncated] ...

 records the exact unlanded work it preserved
ok - fm-control relaunch: a secondmate's child work is accounted for and its charter is left alone
ok - fm-control relaunch: a secondmate home that is not this secondmate's is refused
ok - fm-control relaunch: unreadable and untraversable child state fails checkpoint
ok - fm-control relaunch: two control actions on one task serialize instead of interleaving
ok - fm-spawn relaunch: direct entry participates in lifecycle serialization
ok - fm-promote: promotion participates in lifecycle serialization
ok - fm-spawn --relaunch: refuses to launch a second agent into a live endpoint
ok - fm-spawn --relaunch: symlinked records refuse before inspection
ok - fm-spawn --relaunch: keeps its early meta lock continuous
ok - fm-spawn --relaunch: pending closes refuse before replacement begins
ok - fm-spawn --relaunch: every identity axis comes from the record, and a contradicting flag refuses
ok - fm-spawn --relaunch: an unrecorded task is refused
ok - fm-spawn --relaunch: refuses to start a replacement outside the copy holding its work
ok - tmux: a window absent from its session refuses both verbs rather than being assumed gone
ok - tmux: an unfindable session refuses both verbs, so a live agent is never duplicated
ok - tmux: a dead server on this socket refuses both verbs rather than proving absence
ok - reclaim: an unclassifiable endpoint is still refused, so two agents cannot share one
ok - reclaim: a herdr pane that outlived its stopped server is adopted, never orphaned beside a new tab
ok - fm-control exit: a herdr pane that outlived its stopped server is already-stopped, not gone
ok - reclaim: a herdr rebind is created in the session the record names, never the ambient one
ok - reclaim: a herdr agent that came back with its server refuses, so one worktree keeps one agent
ok - reclaim: a herdr reclaim rebinds the endpoint and leaves the whole rest of the task alone
ok - reclaim: a herdr secondmate whose endpoint is gone is sent to its own respawn owner
ok - reclaim: a rebind refused from a plain shell reports the real cause, not a fabricated session mismatch
ok - relaunch re-reads the backlog item instead of blindly re-running the transition
ok - relaunch heals an item that drifted out of In flight while the task stayed live
FM_TEST_END 2026-09-21T19:19:38Z tests/fm-control-relaunch.test.sh exit=0 duration_ms=91761 gate_skip=false
FM_TEST_BEGIN 2026-09-21T19:19:38Z tests/fm-backend-orca.test.sh family=orca expected_gate_skip=optional-binary
ok - fm_backend_orca_capture: parses result.terminal.tail and calls terminal read
ok - fm_backend_orca_capture: falls back to result text fields
ok - fm_backend_orca_capture: fails closed on Orca read error JSON
ok - fm_backend_orca_runtime_check: accepts reachable ready runtime
ok - fm_backend_orca_runtime_check: fails closed when runtime is not ready
ok - fm_backend_orca_send_text_submit: verifies empty composer after Enter with one bounded read
ok - fm_backend_orca_send_text_submit: a borderless claude composer confirms delivery (the missing #2029 shape)
ok - fm_backend_orca_composer_state: a stale startup banner cannot outrank the live composer row
ok - fm_backend_orca_send_text_submit: retries Enter while composer remains pending
ok - fm_backend_orca_composer_state: a slash-command popup's argument-hint placeholder still reads pending
ok - fm_backend_orca_composer_state: a bare dead-shell prompt reads unknown (unsafe-for-injection), never empty
ok - fm_backend_orca_send_text_submit: a slash-command popup's placeholder fill on Enter #1 does not short-circuit as submitted; Enter #2 is retried and lands it
ok - fm_backend_orca_send_literal: sends text without submitting
ok - fm_backend_orca_send_text_submit: reports send-failed when Orca send fails
ok - Orca send helpers: fail closed on ok:false JSON
ok - fm_backend_orca_send_key: Enter maps to empty enter, C-c maps to interrupt
ok - fm_backend_orca_send_key: refuses unsupported keys loudly
ok - fm_backend_orca_send_key: refuses Escape instead of mapping it to interrupt
ok - fm_backend_orca_kill: calls terminal close and stays best-effort
ok - fm_backend_orca_kill: a close its missing CLI never attempted reports the failure instead of a success
ok - fm_backend_orca_remove_worktree: refuses empty worktree ids
ok - fm_backend_orca_remove_worktree: fails closed on ok:false JSON
ok - fm_backend_orca_worktree_path: resolves an Orca worktree id to its path
ok - fm-backend dispatcher: accepts orca and routes capture through bin/backends/orca.sh
ok - fm_backend_orca_json_get: ignores undocumented terminal id shapes
ok - Orca lifecycle helpers: register repo, create worktree, create terminal, parse stable ids
ok - fm_backend_orca_worktree_create: removes created worktree when path is missing
ok - fm-spawn.sh --backend orca: preserves metadata when pathless cleanup fails
ok - fm-spawn.sh --backend orca: reuses implicit terminal, records metadata, launches harness
ok - fm-spawn.sh --backend orca --secondmate: refuses before secondmate-home mutation
ok - fm-spawn.sh --backend orca: refuses before mutation when Orca runtime is not ready
ok - fm-spawn.sh --backend orca: refuses non-isolated worktrees and closes implicit terminals
ok - fm-spawn.sh --backend orca: removes worktree when terminal creation fails
ok - fm-spawn.sh --backend orca: preserves metadata when abort cleanup fails
ok - fm-spawn.sh --backend orca: releases terminal and worktree on later aborts
ok - fm-peek/fm-send/fm-crew-state route through backend=orca metadata and its durable inbox
ok - fm-peek/fm-crew-state: Orca read error JSON fails closed
ok - fm_backend_target_exists: Orca ok:false read JSON is not live
ok - fm-teardown.sh backend=orca: scout report gate then helper-backed worktree removal
ok - fm-teardown.sh backend=orca: scout teardown refuses id/path mismatches
ok - fm-teardown.sh backend=orca: releases terminal/worktree when path is absent
ok - fm-teardown.sh backend=orca: preserves metadata on remove ok:false JSON
ok - fm-teardown.sh backend=orca: scout report gate precedes pathless helper cleanup
ok - fm-teardown.sh backend=orca: ship teardown fails closed when worktree path is missing
ok - fm-teardown.sh backend=orca: ship teardown requires a matching Orca id path
ok - fm-teardown.sh backend=orca: ship teardown fails closed when id resolution fails
ok - fm-teardown.sh backend=orca: ship teardown refuses id/path mismatches
ok - fm-teardown.sh backend=orca: refuses missing worktree ids before cleanup
ok - fm-teardown.sh backend=orca: refuses incomplete worktree-only endpoint metadata before runtime dispatch
ok - fm-teardown.sh --force: removes Orca secondmate children through Orca
ok - fm-teardown.sh --force: refuses Orca child id/path mismatches
ok - fm-teardown.sh --force: refuses partial Orca secondmate children before runtime dispatch
FM_TEST_END 2026-09-21T19:20:07Z tests/fm-backend-orca.test.sh exit=0 duration_ms=28645 gate_skip=false
FM_TEST_SUMMARY total=8 failed=0 skipped_gate=0 duration_ms=442462
FM_TEST_SUMMARY_FAMILY family=afk count=1 duration_ms=11555 failed=0
FM_TEST_SUMMARY_FAMILY family=backend-dispatch count=1 duration_ms=91761 failed=0
FM_TEST_SUMMARY_FAMILY family=orca count=1 duration_ms=28645 failed=0
FM_TEST_SUMMARY_FAMILY family=pr-forge count=1 duration_ms=263886 failed=0
FM_TEST_SUMMARY_FAMILY family=pure-contract-unit count=2 duration_ms=8088 failed=0
FM_TEST_SUMMARY_FAMILY family=standalone count=1 duration_ms=30644 failed=0
FM_TEST_SUMMARY_FAMILY family=unclassified count=1 duration_ms=7423 failed=0
FM_TEST_SLOWEST rank=1 script=tests/fm-pr-check-security.test.sh duration_ms=263886
FM_TEST_SLOWEST rank=2 script=tests/fm-control-relaunch.test.sh duration_ms=91761
FM_TEST_SLOWEST rank=3 script=tests/fm-classify-corr-token.test.sh duration_ms=30644
FM_TEST_SLOWEST rank=4 script=tests/fm-backend-orca.test.sh duration_ms=28645
FM_TEST_SLOWEST rank=5 script=tests/fm-afk-contract.test.sh duration_ms=11555
FM_TEST_SLOWEST rank=6 script=tests/fm-brief.test.sh duration_ms=7880
FM_TEST_SLOWEST rank=7 script=tests/fm-inbox.test.sh duration_ms=7423
FM_TEST_SLOWEST rank=8 script=tests/fm-branch-claude-mod.test.sh duration_ms=208

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

🔧 **Rebase** - 3 issues found → auto-fixed ✅
  • ⚠️ tests/fm-backend-orca.test.sh - merge conflict rebasing onto origin/main
  • ⚠️ tests/fm-spawn-compact-adviser-disable-remote.test.sh - merge conflict rebasing onto origin/main
  • ⚠️ tests/fm-spawn-compact-adviser-disable.test.sh - merge conflict rebasing onto origin/main

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 13 of 13 scenarios driven live against the product
Scenario Result Live Evidence
Spawned ship worker (allowlist absent and enabled) starts with the compact adviser enabled: executed launch shows COMPACT_ADVISER_DISABLE unset ✅ pass live compact-adviser-enabled-probe.log cases ship-open, ship-filtered
Spawned secondmate (both allowlist postures) starts with the compact adviser enabled ✅ pass live compact-adviser-enabled-probe.log cases sm-absent, sm-enabled
fm-control relaunch rebuilds the launch without the compact-adviser switch (both allowlist postures) ✅ pass live compact-adviser-enabled-probe.log cases relaunch absent/enabled
Upstream delete/modify tests stay deleted and no compact-adviser-disable reference exists in the tree ✅ pass live ls tests/fm-spawn-compact-adviser-disable* no such file; grep empty
fm-brief scaffolds Captain's intent / Published intent / Firstmate spec, stamps status templates with [at=<epoch>], and appends the home brief include as the last section ✅ pass live brief-contract-live.txt; tests/fm-brief.test.sh in targeted-suites.log
Adversarial: a brief include carrying a Delivery contract line is refused before anything is written ✅ pass live brief-contract-live.txt (exit=1, only probe-a1 in data/)
Adversarial: spawn refuses a brief lacking ## Published intent, accepts once added ✅ pass live published-intent-refusal.txt
Inbox capture with --request-id is idempotent (replay, one note, one wake) and ready/receipts/reply JSON round-trip ✅ pass live inbox-capture-live.txt; tests/fm-inbox.test.sh in targeted-suites.log
Stamped status lines (needs-decision/resolved/done/paused with [at=<epoch>]) classify correctly through fm-classify-lib ✅ pass live status-stamp-classify.txt
Away-words authority model: AFK contract, return, launch and merged-span trace assertions hold ✅ pass live tests/fm-afk-contract.test.sh, tests/fm-pr-check-security.test.sh (targeted-suites.log); tests/fm-afk-return.test.sh, tests/fm-afk-launch.test.sh, tests/fm-pr-merge.test.sh (targeted-suites-2.log)
Herdr relaunch fixture carries Published intent and the relaunch suite passes ✅ pass live tests/fm-control-relaunch.test.sh in targeted-suites.log
Regenerated fm-branch agent definition matches its generator ✅ pass live bin/fm-branch-agent-md.sh --check exit 0; tests/fm-branch-claude-mod.test.sh
Orca staged-launch extraction keeps the fork's settings JSON needle (rebase-1 resolution) ✅ pass live tests/fm-backend-orca.test.sh in targeted-suites.log
  • bin/fm-test-run.sh tests/fm-brief.test.sh tests/fm-inbox.test.sh tests/fm-afk-contract.test.sh tests/fm-pr-check-security.test.sh tests/fm-control-relaunch.test.sh tests/fm-branch-claude-mod.test.sh tests/fm-backend-orca.test.sh tests/fm-classify-corr-token.test.sh (8/8 pass)
  • bin/fm-test-run.sh tests/fm-afk-return.test.sh tests/fm-afk-launch.test.sh tests/fm-task-delivery.test.sh tests/fm-pr-merge.test.sh tests/fm-spawn-dispatch-profile.test.sh (5/5 pass)
  • bin/fm-branch-agent-md.sh --check exit 0
  • bash compact-adviser-enabled-probe.sh &lt;worktree&gt;: real bin/fm-spawn.sh (ship allowlist absent/enabled, secondmate absent/enabled) and bin/fm-control.sh relaunch (absent/enabled); emitted launch executed with harness replaced by env probe; all six report COMPACT_ADVISER_DISABLE unset and zero mentions in pane/launch
  • ls tests/fm-spawn-compact-adviser-disable* absent; grep -rn COMPACT_ADVISER bin lib tests docs empty
  • FM_HOME=&lt;tmp&gt; bin/fm-brief.sh probe-a1 some-proj --mode no-mistakes with config/brief-include.md; second run with a Delivery contract: mode= include refused exit 1
  • bin/fm-spawn.sh pub-a1 against a brief lacking ## Published intent refused; accepted after adding the section
  • bin/fm-inbox.sh note --request-id req-1 --json twice (created then replay, 1 note, 1 wake), ready, receipts, reply --json, receipts --all-replies
  • sourced bin/fm-classify-lib.sh: status_line_verb/status_line_at_epoch/status_has_open_needs_decision/status_is_terminal_verb/status_is_paused on [at=&lt;epoch&gt;]-stamped lines
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

rovermike and others added 21 commits September 21, 2026 20:03
…enguid#4973)

* fix(bin): treat a live no-mistakes run as current after rebase

A running run on the task's branch is authoritative regardless of head.
Matching only the local head made a rebased in-flight run look failed.

* no-mistakes(review): restrict coarse live-any-head to foreign-branch answers

* no-mistakes(review): reject gate-parked runs from the executing predicate

* no-mistakes(review): hoist gate-marker patterns into single run-lib owner

* no-mistakes(review): require live daemon for head-free run binding

* no-mistakes(review): require answered daemon-down before unbinding live runs

* no-mistakes(review): extend daemon guard to anchored continuation routes

* no-mistakes(review): delete live-any-head; restore dead-daemon verdict

* no-mistakes(review): keep parked gates parked; name dead daemon everywhere

* no-mistakes(review): set dead-daemon verdict instead of emitting early

* no-mistakes(review): align selected route with legacy dead-daemon handling

* no-mistakes(review): drop unproven-record binds; narrow coarse gate reading

* no-mistakes(review): narrow header, drop vestigial guard, retarget tests

* no-mistakes(review): revert coarse gate override; require answered-down probe

* no-mistakes(review): cache one daemon probe; stop duplicating run id

* no-mistakes(review): restrict coarse dead-daemon verdict to moved-off rows

* no-mistakes(review): delete coarse dead-daemon extension and gate note

* no-mistakes(review): delete remaining coarse dead-daemon block and stale docs

* no-mistakes(document): document rebase-safe live-run bind and unverified-record verdict
…4994)

* fix(bin): stage the launch command in a private file and type a short source line

A long launch line typed while the fresh pane shell is still busy waits in the
terminal's canonical line buffer, which drops input past about 1,024 bytes on
macOS, so the pane was left at an unfinished command with no agent running.
fm-spawn now writes the assembled command to the task's own temp root under
umask 077 and types only a short line that sources it.

Refs kunchenguid#4559

* fix(bin): keep the per-task temp root private before staging the launch command

The root lives at a predictable path under /tmp and now holds the whole launch
command. Create it with mode 0700, refuse one that already exists as anything but
a directory owned by this user that nobody else can write, and tighten an owned
one, so no other local user can plant or swap the staged file.

Refs kunchenguid#4559

* fix(bin): enforce private staged launch file mode

* test(spawn): cover long staged Claude launches

* no-mistakes(review): Namespace launch files and prove truncation staging

* no-mistakes(review): Use immutable per-spawn launch filenames

* no-mistakes(document): Document staged launch delivery safeguards

* no-mistakes(ci): Updated eight behavior tests/fakes to execute or inspect immutable staged launch files instead of expecting inline launch commands. This restores Muse, secondmate lifecycle/restart, remote trace/parent binding, compact-adviser, and Orca coverage. All affected tests, dispatch-profile regression, fixture tests, syntax checks, ShellCheck, and git diff checks pass

---------

Co-authored-by: Vytautas Stankus <svycka@gmail.com>
* Add isolated Herdr runbook to test instructions

* no-mistakes(review): Drop substring matching from test.instructions contract

* no-mistakes(review): Assert commands.test key absence in YAML

* Drop unit-first sentence and instructions contract test

Captain-scoped follow-up on the Herdr-lab test.instructions ship:
keep the lab safety runbook only, and leave the no-mistakes contract
test focused on commands.test absence.
…uid#4873) (kunchenguid#5001)

* docs(vision): accept vendor-semantics and 9k contract-ceiling amendments (kunchenguid#4873)

Replace the pixels-of-today's-UI rule with a quarantined, version-pinned
surface-adapter exception recorded as standing debt. Cap the always-loaded
contract at 9,000 words and require prune-or-trigger before a crossing change
lands.

Co-authored-by: Kun Chen <kunchenguid@users.noreply.github.com>

* docs(vision): restore accepted three-sentence vendor-semantics form (kunchenguid#4873)

Replace the compressed paraphrase with the issue's accepted wording:
a named quarantined version-pinned adapter, expected to break, recorded
as standing debt that never hardens into a shared contract.

Co-authored-by: Kun Chen <kunchenguid@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Kun Chen <kunchenguid@users.noreply.github.com>
…or-owed gate (kunchenguid#4974)

* fix(watch): recheck a gate awaiting a human instead of wedge-escalating it

A lane whose validation run is parked at a gate waiting on a human
decision is correctly quiet, but nothing in its status line says so: the
evidence is the pipeline's own gate state rather than anything the worker
wrote. The wedge timer read that silence as a suspected wedge and climbed
the escalation ladder for as long as the wait lasted, and each escalation
cost a supervising turn. The landed declared-wait consult does not reach
it, because a live ordinary crewmate never reports a declared pause, and
raising FM_STALE_ESCALATE_SECS would delay genuine wedge detection for
every lane by the same amount.

The threshold now reads a second, independent record when the status line
accounts for nothing: whether the crew's current state is a gate whose
answer is owed by a human. That is minted only from the gate's own
findings table, by a row whose `action` column is exactly `ask-user`,
located by position out of the table header the way nm_gate_step_row
already reads its row - never searched for over the run payload, where a
finding's free-text description or a branch name satisfies a search just
as well. A gate awaiting the CREWMATE's own answer keeps the unchanged
escalation schedule, reason and demand-deep-inspection wording, because a
crewmate that goes quiet before answering its own gate is exactly the
wedge the ladder exists to catch.

Each kind of wait now carries the human it is on, the action that clears
it, and whether that human is the captain as data alongside the verdict,
rather than as wording chosen per branch where the recheck is written, so
the deferral cannot word one kind of wait as another and a new kind
cannot ship without deciding all of them. A parked gate has no written
record of when its wait began, so its recheck publishes no wait age at
all rather than one read from the quiet window this deferral resets on
every pass, which would report the same small number for a gate of any
age. Like every other captain-facing recheck here it is absorbed in
silence while the away-posture record exists, arming no throttle, so the
recheck is owed in full the moment the record is archived.

The consult runs only in the at-threshold branch that was about to
escalate, beside the worktree walk already there, and only for lanes
whose status line explained nothing.

Closes kunchenguid#3055

* no-mistakes(review): require an unanswered decision before deferring a parked gate

* no-mistakes(review): reset the away-silenced timer, fail-safe findings parse, US-joined wait records

* test(watch): pass the pane hash wedge_timer_check now takes

Upstream gave wedge_timer_check a sixth <pane-hash> argument for its
dead-record probe. The malformed-wait-record rounds drive the real function
directly, so they pass one, and stub fm_backend_agent_state to a live agent so
the probe that runs after a refused deferral keeps the unchanged ladder rather
than reading a backend the child shell has none of.

* no-mistakes(review): Bind parked-gate wait to its run, owe it firstmate

* no-mistakes(document): correct wait-kind count, crew-state reader scope, gate-key coupling

* feat(watch): make the parked-gate wait deferral opt-in

The wedge timer deferring a lane parked at a validation gate is new
supervision behaviour rather than a restored one, and it decides which
lanes give up the escalation ladder, so it now ships as a default-off
per-home option instead of changing every home on upgrade.

config/wedge-defer-parked-gate arms it. The flag is read before the
decision fold, so an unconfigured home spends no fold or current-state
read, writes no record, and keeps the unchanged escalation schedule,
reasons and demand-deep-inspection wording; a test counts the reader
calls in both directions to pin that.

It is not inherited by secondmate homes: each home supervises its own
crew and owns that trade separately, the same reason
config/turnend-churn-absorb is home-local.

The away-posture absorb returns to leaving the idle timer alone, which
it had restarted only because the costly consult could reach it. A
parked-gate wait is owed to the supervisor rather than the captain, so
it never enters that branch, and the recheck owed on return is again
owed in full the moment the record is archived.

* test(watch): pin that the away-silenced hold leaves the idle timer alone

The absorb no longer restarts the timer, so the recheck owed on return is
owed in full rather than a cadence into the return. Nothing asserted
that, so a restart could be reintroduced silently.

* no-mistakes(review): document away-silence rationale, pin captured gate component

* no-mistakes(test): anchor gate row scan to the braced findings header

* no-mistakes(document): pin same-block gate row invariant in crew-state comment
…uid#5007)

* fix(control): let the owning seat reclaim a task whose endpoint is gone

A destroyed pane or workspace made `missing` a terminal state. Relaunch
accepted only `dead` and said to stop the agent first; exit refused
`missing` and said to reconcile the task first; there is no reconcile
verb. Each command named the other as its prerequisite, so a task whose
terminal went away could not be reclaimed by anything, and a no-mistakes
approval it was parked on had no seat left to answer it.

`missing` is agent-free a fortiori: there is no endpoint, so there is no
agent in it. Widen the existing guards rather than add a verb.

- fm-spawn --relaunch accepts a positively proven `missing` and creates
  one fresh endpoint in the recorded worktree; the record it already
  republishes rebinds the task to it. A `dead` endpoint is still adopted
  in place.
- fm-control exit reports `endpoint-gone` instead of dying, so the
  relaunch transaction's stop step no longer dead-ends, and re-resolves
  the endpoint from the record before verifying the replacement.

The duplicate-agent refusal is untouched: both verdicts come from the
same recovery-grade classifier, which claims `missing` only from positive
absence, so `alive`, `ambiguous`, and `unreadable` all still refuse. The
backends' own create paths refuse a live same-labeled endpoint as a
second independent guard. The worktree, its branch, commits, uncommitted
changes, armed poll and registration, record rows, and status log are all
untouched - a reclaim is a recovery, never a teardown.

A secondmate is excluded: its gone-endpoint recovery already has one
owner in the session-start liveness sweep, so relaunch refuses and names
it rather than becoming a second path to the same outcome.

Tests reproduce both halves of the deadlock, the reclaim succeeding,
unlanded work surviving it, and the refusals that still hold.

* no-mistakes(review): prove endpoint absence per backend before reclaim rebinds

* no-mistakes(review): give exit and relaunch one absence proof; pin herdr rebind session

* no-mistakes(review): narrow endpoint reclaim to herdr; tmux refuses honestly

* no-mistakes(review): stop refusals and docs asserting unestablished causes

* no-mistakes(review): stop herdr fixture helper losing tmp-root registration

* no-mistakes(review): document workspace drift and absence-probe server residue

* no-mistakes(review): correct rebind limitation to its one reachable case

* no-mistakes(review): stop claiming reclaim leaves instructions untouched

* no-mistakes(document): scope fm-control-lib purity claim, note reclaim coverage

* no-mistakes(rebase): read the staged launch file in the herdr fixture

Rebasing onto main picked up kunchenguid#4994, which stages a long worker launch
command into a script and delivers the short `. '<path>'` line instead of
the literal command. The tmux fake and tests/fixtures.sh were updated for
that; the herdr fake this branch adds was written before it and still
keyed "an agent now exists on this pane" off the literal
`encode launch-brief` text, so after the rebase it never marked the
rebound pane live and the reclaim's alive-wait read `dead`.

Dereference the staged file first, exactly as the tmux fake above does.
Test-fixture only; no production path changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* no-mistakes(document): note reclaim placement in herdr and scripts inventories

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…3764)

* test(status): reproduce missing event emission time

* wip(status): preserve optional event emission time

* test(status): document indirect clock stub invocation

* no-mistakes(review): Preserve historical status bytes during reply recovery

* no-mistakes(test): Fix timestamped status assertions and remote fixture dependencies

* no-mistakes(review): Preserve captain regex overrides for timestamped status events

* no-mistakes(document): Clarify status event timing and publication contracts

* no-mistakes(lint): Quote literal done to satisfy ShellCheck

* no-mistakes(ci): Captain, updated .github/workflows/ci.yml to expect 19 snapshot tests instead of 18, matching the PR’s added regression. Reproduced the failure before the fix. Stock Bash 3.2.57 verification passed: parse sweep, 19 snapshot tests, 53 Bearings tests, and the public-followup regression. Workflow lint and diff checks passed

* no-mistakes(test): Preserve terminal notifications with malformed timestamp tags

* no-mistakes(test): Stamp Rovo spawn failures with emission time

* no-mistakes(document): Verify status event documentation

* no-mistakes(lint): Fix ShellCheck quoting in status emission-time tests

* no-mistakes(ci): Captain, fixed four lifecycle assertions to accept emission timestamps while preserving publication and retry checks. Reproduced the CI failure before the fix. The lifecycle suite now passes with six Beads capability skips; syntax, targeted ShellCheck, and diff checks passed

* no-mistakes(ci): Captain, fixed malformed timestamp colons hiding actionable events using shared normalization. Original bytes and unknown ages are preserved. Regression reproduced before the fix; classifier and remote-reply suites, targeted lint, syntax, and diff checks passed

* no-mistakes(review): Stamp remote escalations at call sites, drop new flag

* no-mistakes(review): Accept stamped escalation and close lines in test assertions

* no-mistakes(review): Restore reserved-key answered-note guard for stamped closes

* test(status): accept optional emission time in PR-provenance assertions

The kunchenguid#4148 provenance test landed on main with exact unstamped greps.
Parent-channel lines from this branch carry [at=<epoch>], so strip only
that tag before the same exact match. No production change.

* no-mistakes(review): Accept stamped ready signal in PR fallback scrape

* no-mistakes(review): Drop relay flag, stamp parent events at call sites

* no-mistakes(review): Stamp worker terminal-signal instructions, revert fm-on fixture

* no-mistakes(review): Accept optional stamp in live cmux drift guard

* no-mistakes(review): Restore original test invocation order in two suites

* no-mistakes(review): Strip only well-formed numeric status time tags

* no-mistakes(document): Drop stale unstamped PR-ready line spelling from channel doc

* no-mistakes(review): Stamp agy spawn-failure status lines with event time

* fix(bin): normalize status event times in-shell and freeze the budget test clock

Two paths made a status event's emission time cost more than it should.

The captain-relevance fallback piped every line through awk to drop a
well-formed `[at=<epoch>]` tag before matching, so a supervisor sweep paid a
fork per line just to prepare a regex match. Shell parameter expansion does the
same strip with no fork, and the retry-dedup scan now reuses that one helper
instead of carrying a second copy of the rule in awk. The copies had already
drifted: the shell side stripped tags from lines with no colon, which the awk
rule left whole, so a colonless line could be mistaken for one already
recorded. One definition, checked against the awk rule it replaces over the
edge cases and a 4000-line fuzz.

tests/fm-contributions.test.sh froze its fixture clock only in exhaust mode. In
hang mode the poll set DEADLINE to the real now plus a one-second budget, and
when the second ticked before the first forge call the loop broke without ever
calling gh: forge/calls was never written and the assertion failed reading a
missing file. Freezing the clock in both modes removes the dependence on wall
time; the bounded call is still cut by the real timeout, so the observation the
test asserts still starts.

Emission time stays optional on new status records, and legacy or malformed
lines keep an unknown age.

* no-mistakes(review): Stamp ask-user escalation line and fix Kimi status assertion

* no-mistakes(document): Drop stale unstamped done-line spelling from watcher docs

* test: fold emission-time snapshot coverage into the fixture case

Drop the incidental ci.yml 18-to-19 count hunk so the PR no longer
touches workflows. Keep every emission-time assertion by folding it
into test_fixture_snapshot_json.

* no-mistakes(review): replace brief date substitution with epoch placeholder; drop emitted_at_epoch

* no-mistakes(review): align untimed normalizer with epoch parser; tolerate placeholder stamp in PR scrape

* no-mistakes(review): strip undelimited at-tags; correct brief stamp header

* no-mistakes(review): normalize stamps at both captain-regex sites; restore mtime freshness

* no-mistakes(review): strip colon-bearing stamps for relevance; fix headers and test oracles

* no-mistakes(review): narrow escalation match to stamp tolerance; pin note verb

* no-mistakes(review): read note and key past colon-bearing stamps

* test(status): keep inactive reconcile assertions stamp-tolerant

These two oracles were made stamp-tolerant while resolving one of the
branch's merges from main. The rebase drops merge commits, so that
adaptation was lost and both assertions went back to matching an exact
substring that a stamped line no longer contains: the tag lands before
the colon, so "failed [key=k]: ..." is now "failed [key=k] [at=N]: ...".
Strip a well-formed tag before matching, as the branch's other oracles do.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* no-mistakes(review): unstamp fold colon tests; reserve stamp width in cap

* no-mistakes(document): correct stale unstamped status-line spellings in docs

* no-mistakes(document): quote brief-test literals for lint; correct stamp-helper contract comments

* no-mistakes(ci): rename subshell-local epoch in delivery-race stub

The serialization test overrides fm_pending_reply_mark_delivered inside a
(..) subshell. Its `epoch` local collided with the same name in
status_line_at_epoch/status_stamp_line, which this branch added and this
suite now calls at top level, so ShellCheck 0.11.0 reported SC2030 and
failed Lint 2. The stub already prefixes its other locals with `pending_`
for the same reason; `epoch` was the leftover.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: ship clean Lavish host fixes

* no-mistakes(review): Fix Lavish classifications and fail-closed host loading

* no-mistakes(review): Restore Lavish host state across retries and launches

* no-mistakes(review): Preserve destination Lavish host when configuration is absent

* no-mistakes(document): Document Lavish status and host guarantees
…#5076)

* feat(afk): make the captain's away words the whole mandate

Retire the clause fields, verb list, never-set scan, refused records, and
the per-task merge-grant list from the away-posture record. The record is
now version 2: the captain's words verbatim plus expected return, spend
cap, and reach line; a version 1 record still validates, reads, and
archives so a live away window is never broken by the upgrade.

The supervision branch reads the words at the tail of every wake and acts
on them by its own judgment through the guarded scripts under standing
authority, never by analogy, holding for the return on doubt, and opens
each such outcome summary with "per your away instructions:" so the
return brief can render the words beside the session's account. While the
record exists any green merge runs under away authority (ledger tag
"away"); red merges, --allow-red, asynchronous and queued merges, and
local-only landing stay refused. The branch may file a backlog item the
words explicitly call for before dispatching it under the spend cap.

Tests drive fm-afk-contract.sh, fm-afk-launch.sh, fm-afk-return.sh, and
fm-pr-merge.sh as commands: version 2 written, version 1 read, retired
flags and subcommands refused by name, green merges landing under the
record, red and waived-red refused, the record lock still closing the
authority-read window, and the Pi away tail carrying the words.

* no-mistakes(review): carry the away read-back to the session verbatim

* no-mistakes(review): match the exact away-action marker in the return brief

* no-mistakes(review): refuse a words block truncated by a damaged line

* no-mistakes(document): Refresh away-role contract documentation
…unchenguid#5049)

* fix(bin): render the remote charter's steering-inbox path host-local

A freshly provisioned remote secondmate read a parent-home absolute
steering-inbox path in its charter - a location that exists on no route -
and spent its first turn discovering the gap and filing a blocked
decision for what was a render defect. The seed's remote-copy rewrite now
maps the inbox to the route's host-local parent-route inbox, exactly as
it already maps the reply-log path, so every mention - bare path, listing,
and handled/ acknowledgement - lands host-local.

Both rewrites also become plain assignments, because a quoted substitution
nested inside a double-quoted printf argument leaks literal quotes into
the replacement text on stock macOS bash. The lifecycle suite pins the
corrected render both directions against the real seed, provisioning,
and delivery route, sharing one fixture value between the render truth
and the delivery truth.

Closes kunchenguid#5012

* no-mistakes(document): document remote charter's host-local steering inbox
)

* feat(procevent): route worker-owned Lavish rounds

* no-mistakes(review): drop duplicate artifact field from task-owned registration

* no-mistakes(review): post worker reply once, fix ring label, keep re-arm atomic

* no-mistakes(review): keep worker board owned until terminal round acknowledged

* no-mistakes(review): refuse every retirement of an open worker-owned round

* no-mistakes(review): use real lavish reply flag, isolate reply generations

* no-mistakes(review): drop .posted marker for best-effort reply posting

* no-mistakes(review): consume staged reply after listener setup, refuse orphaned captures

* no-mistakes(review): require a reachable owner, redeliver open rounds, roll back failed re-arms

* no-mistakes(review): re-arm only to acknowledge an open round

* no-mistakes(review): conclude only a still-open terminal round

* no-mistakes(review): record the acknowledgement before retiring the board

* no-mistakes(review): retain the registration across a conclude, qualify terminal docs

* no-mistakes(document): Document worker-owned Lavish round lifecycle
…unchenguid#5107)

* fix(bin): reserve contribution observation budget

* no-mistakes(review): Strengthen slow-read regression test to exceed the poll budget
…ness JSON (kunchenguid#5103)

* feat(bin): add idempotent inbox orders, receipts, replies, and readiness

Let a caller supply a request id when publishing a captain inbox note so a
retry returns the original note instead of creating a second one, including
across the crash window between save and wake announcement. Separate saved
from announced so a failed wake is repairable without enqueueing again.
Add bounded receipts JSON with omission disclosure, a durable primary reply
against a note id, and a read-only readiness projection that can say
unknown instead of inferring liveness from a lock file.

* no-mistakes(review): fix(bin): honest inbox announce, reply cursor, and readiness verdict

* fix(bin): resolve ready from lock-holder ancestry; drop lock status --json

Remove the extra JSON surface from fm-lock.sh so its human status still
always exits zero. Have the readiness projection classify the inspected
home from the lock-holder pid via fm-harness.sh ancestry, with an explicit
FM_SUPERVISION_MODEL still winning and an unknown model when there is no
holder. Prove the yes path when that ancestry names a known harness.

* no-mistakes(review): Harden inbox announce, receipts reads, and reply sequence cursor

* no-mistakes(document): Note read-only lock inspection in scripts inventory

* no-mistakes(lint): Pass missing id argument to malformed-reply test printf

---------

Co-authored-by: cliflacata-svg <304148223+cliflacata-svg@users.noreply.github.com>
…ending text (kunchenguid#5118)

* fix(composer): stop a harness footer row from reading as a composer holding text

A harness draws its own furniture below the composer - a user statusLine, a
permission-mode hint - and the cursorless "bottom-most shape wins" rule looks
exactly there. `→` (U+2192) is Cursor's prompt glyph but ordinary text
everywhere else, so a statusLine opening with `→` was selected as a bare
composer, swallowed the hint row beneath it as wrapped input, and answered
`pending` on a visibly empty pane. `fm_task_inbox_ring` defers on exactly that
verdict, and `bin/fm-watch.sh`'s re-ring calls the same function, so the first
doorbell and every retry were skipped and the worker never saw the steer.

Measured live on 2026-09-20: three of five Claude Code 2.1.236 worker panes on
Herdr 0.8.0 had genuinely empty composers and every one of them was refused.

A separator pair that closed over a bare agent-glyph row is a proven composer
container, so the contiguous non-blank rows below its closing rule are that
composer's footer and are no longer composer candidates. The demotion is bounded
by all three of its own preconditions: a blank row ends the zone, a pair that
closed over no glyph row demotes nothing, and a shape with no separator pair at
all (Cursor's half-block rules) is untouched. Real unsubmitted text in that same
composer, including a stray SGR mouse report left by a click in the pane, still
reads `pending`.

Pinned by two portable regressions and by a new cursorless arm on the live
composer-matrix guard, which re-reads each harness's already-proven-idle pane
the way every non-tmux backend reads it and fails naming the harness and
version when that read is `pending`.

* no-mistakes(review): make composer footer-zone demotion shape-independent

* no-mistakes(review): make footer-zone demotion refuse-only and drop rescan

* no-mistakes(lint): quote probe-absent sentinel to clear ShellCheck SC2100

---------

Co-authored-by: Koen Muller <koen@catapult.nl>
…5115)

Co-authored-by: guanchengh-lgtm <271917158+guanchengh-lgtm@users.noreply.github.com>
… an unreadable runs table (kunchenguid#5114)

* fix(bin): stop misreading a no-run branch as an unreadable runs table

Defect: when `no-mistakes axi status`'s overview is truncated (a task's
own branch has zero rows among the shown ones), fm_nm_select_run's
Python fallback derived the repo identity for its direct SQLite query
from a `repo: <path>` line it expected in the overview text. The real
CLI never emits that line, truncated or not (see the genuine capture at
tests/captures/no-mistakes-v1.70.1/overview.toon, which has only
`count:`/`runs[...]:`), so the lookup always failed and reported
"unreadable runs table" for a task that simply has no run on its
branch. On a fleet with many concurrent runs, every idle-branch task
hits the truncated-overview path routinely, so this fired every few
minutes and drowned genuine unreadable/blocked verdicts in noise.

Fix: derive the repo identity from the task worktree path instead,
which is exactly the value `no-mistakes` records as a repo's
`working_path` (confirmed against the existing capped-overview test
fixtures, which already register repos by worktree path). A worktree
path that is not absolute cannot be matched and still reads as
unreadable rather than being guessed at. Also raise the reader's
SQLite busy timeout from 1s to 30s so ordinary lock contention on a
busy fleet cannot masquerade as an unreadable database.

Safety: every other verdict byte-for-byte unchanged - the repo lookup
still requires exactly one matching row (a genuinely corrupt or
mismatched repos table still reports unreadable, per the existing
`repo` failure-mode test), the branch query and row validation are
untouched, and a zero-row result for the branch still flows through
the same recursive re-parse that already turns an empty `runs[0]{...}`
table into `absent`. Added a regression test
(test_capped_overview_without_repo_line_and_no_runs_reports_absent)
that reproduces the real overview shape - capped, zero rows for the
task's branch, no `repo: ` line - and asserts the crew state falls
through to the pane/busy verdict instead of reporting unknown or
"unreadable". Full fm-crew-state.test.sh suite passes unchanged
otherwise.

* fix: recovered same-branch inventory awk misreads empty result as unreadable

fm_nm_select_run's deep SQLite reader rebuilds a `count:`/`runs[...]:`
overview and re-runs it through the same awk selection pass. When that
rebuilt inventory has zero rows for the branch, the row-matching loop never
executes, so its counters (`seen`) stay at awk's uninitialized empty string
while `expected` and `shown` are plain strings parsed from the header text.
Comparing an uninitialized value against a non-numeric string uses string
comparison, so "" != "0" is true, and the END block takes the "unreadable
runs table" branch instead of falling through to the correct "absent"
verdict for a branch with genuinely zero runs.

Coerce the affected END comparisons with `+0` so they are always numeric,
matching seen/expected/shown/total regardless of whether awk classified
them as strings or numeric strings. A truncated or genuinely malformed
inventory still differs numerically and still reports unreadable.

* no-mistakes(review): bound capped-overview inventory reader and canonicalize worktree lookup

* no-mistakes(review): match recorded repo path first, tolerate duplicate spellings

* no-mistakes(review): revert repo lookup to exact working_path match

* no-mistakes(document): note state-db inventory read under crew-state nm timeout
The merged fm-brief contract now stamps every worker-written status
template (paused, resolved, needs-decision, done) with [at=<epoch>]
before its key, matching upstream's stamp convention that the merged
fm-brief test round-trips through fm-classify-lib. The fork's exact-text
asserts follow the stamped forms; the paused/resolved keys, the
never-blocked rule, and the done: PR checks green contract are
unchanged.
The merge changed the AGENTS.md sections the generator reads; the
tracked definition was stale against its generator.
Upstream retired the per-task yolo tag and the per-task grant list at
merge-queue time: a queued merge under the captain's away record
persists authority=away whatever the task's yolo flag, and --grant is
no longer a propose flag. The fork's trace-span assertions keep
checking origin, authority, and the canonical URL, now against the
merged model's away value for both the yolo and words postures.
Upstream's relaunch test scaffolds a ship brief without the fork's
## Published intent subsection, which the fork's spawn refuses as a
pre-contract brief. The fixture now carries the section like every
other ship fixture in this script.
@andrewesweet andrewesweet changed the title Merge upstream main through 43bf6d3d (sixteen commits) into the fork feat(bin): sync upstream firstmate main through 43bf6d3d into the fork Sep 21, 2026
@andrewesweet
andrewesweet merged commit 327b45d into main Sep 21, 2026
19 of 20 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.