Skip to content

feat: integrate Matt Pocock engineering skills into worker brief contract - #1

Merged
mattleus merged 8 commits into
mainfrom
ml/matt-skills-integration
Oct 5, 2026
Merged

mattleus merged 8 commits into
mainfrom
ml/matt-skills-integration

Conversation

@mattleus

@mattleus mattleus commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Intent

Integrate Matt Pocock's installed skill pack into FirstMate so planning and workers use stronger engineering methods while FirstMate retains orchestration, isolation, supervision, communication, delivery, and merge authority. Add an internal integration skill and routing rules, generate and validate task-specific required engineering skills and agreed public testing seams for ship and scout workers, preserve older saved instructions for recovery, carry the contract through scout promotion, document installation and architecture, and add behavioral tests. Prevent workers from launching nested orchestration or duplicate delivery and review flows: no-mistakes remains the sole final review flow when selected, while project issues hold planning artifacts and FirstMate's backlog tracks execution. Do not configure individual projects yet. Follow FirstMate's standing validation policy: keep the Test step intent-targeted, use bin/fm-test-run.sh for selected suites, and do not configure or run an unrelated full-suite test command.

What Changed

  • Added the internal matt-pocock-integration skill that routes upstream Matt Pocock workflows (grill-me, wayfinder, research, implement, code-review, etc.) into FirstMate scouts, ships, and planning artifacts while keeping orchestration, isolation, supervision, delivery, and merge authority with FirstMate and blocking nested orchestration or duplicate final-review paths.
  • bin/fm-brief.sh now scaffolds a # Engineering method section with task-specific ## Required skills and ## Agreed testing seams subsections in ship and scout briefs; new bin/fm-dod-lib.sh helpers let bin/fm-spawn.sh and bin/fm-promote.sh reject leftover {REQUIRED_SKILLS} / {TESTING_SEAMS} placeholders or empty subsections, while briefs predating the section remain launchable for recovery and promotion carries the validated method to the live worker and replacement instructions.
  • Documented installation and operator behavior in docs/matt-pocock-skills.md plus docs/architecture.md, AGENTS.md, and README.md updates, and added behavioral test coverage for the new brief contract, spawn/promotion validation, and fixtures.

Risk Assessment

✅ Low: The change adds a well-bounded scaffold section and validation gate that reuse the existing exact-match heading-parser contract, refuse before any state mutation, preserve legacy-brief launchability, and are covered by behavioral spawn/promote tests, with documentation and intent conformance all verified against source.

Testing

Ran the intent-targeted suites through bin/fm-test-run.sh (fm-brief, fm-task-delivery, fm-documentation-audiences — all exit 0, zero gate skips) and drove five manual scenarios against the real fm-brief.sh/fm-spawn.sh/fm-promote.sh CLIs in isolated FM_HOME fixtures: 19/19 checks passed covering the new Engineering method contract in scaffolds, adversarial refusal of unfilled and emptied skill/seam subsections at both spawn and promotion with no state written, carry-through of the filled contract into promoted worker instructions, and recovery compatibility for pre-contract briefs. The only untested aspect is live-LLM compliance with the prompt-level orchestration guard, which the repo's own test policy assigns to development-only evaluation.

  • Live validation: ✅ go - 9 of 10 scenarios driven live against the product
Scenario Result Live Evidence
Firstmate scaffolds a ship or scout brief and the worker contract includes the task-specific engineering method (required skills, agreed testing seams) plus the sole-final-review and no-nested-orchest… ✅ pass live Manual drive S1 (s1-ship-brief.md, s1-scout-brief.md) and bin/fm-test-run.sh tests/fm-brief.test.sh (test_ship_modes_generate_clean_briefs, test_scout_and_secondmate_scaffold), exit 0
Secondmate charters are unaffected by the task engineering contract ✅ pass live Manual drive S1 secondmate check and fm-brief.test.sh assert_no_grep on # Engineering method
Adversarial: spawning a current brief with leftover {REQUIRED_SKILLS}/{TESTING_SEAMS} placeholders is refused, names the subsections to fill, and writes no task metadata; a filled brief that mentions… ✅ pass live fm-task-delivery.test.sh test_spawn_requires_filled_engineering_method, exit 0
Adversarial: spawning a brief whose Required skills / Agreed testing seams bodies were emptied is refused with the nonempty-subsection error and writes no task metadata ✅ pass live Manual drive S4 (s4-spawn-empty-refusal.txt, exit non-zero, no state/*.meta)
Recovery compatibility: a saved ship brief predating the Engineering method section still passes spawn validation and proceeds through the normal launch flow ✅ pass live Manual drive S2 (s2-legacy-spawn-output.txt): reached the post-validation rigor notice at bin/fm-spawn.sh:2634, which runs strictly after the engineering validation at bin/fm-spawn.sh:2554, with no er…
Scout promotion carries the filled engineering contract (required skills and testing seams) into the instructions the promoted worker receives, alongside the same mode-specific Definition of done a br… ✅ pass live fm-task-delivery.test.sh test_promotion_delivers_the_real_definition_of_done, exit 0 (asserts the delivered payload for all three modes)
Adversarial: promoting a scout brief with leftover engineering placeholders is refused with a named error and publishes no ship instructions ✅ pass live Manual drive S3 (s3-promote-refusal.txt): exit non-zero, refusal names placeholders and subsections, no ship-instructions.md
Recovery compatibility: promoting a legacy scout brief with no Engineering method section still publishes ship instructions carrying the selected delivery contract ✅ pass live Manual drive S5 (s5-legacy-ship-instructions.md with 'Delivery contract: mode=direct-PR')
Operator and maintainer docs for the skills integration are classified, linked, and reachable through the documentation-audiences inventory ✅ pass live bin/fm-test-run.sh tests/fm-documentation-audiences.test.sh, exit 0 (real consumer of docs/documentation-audiences.json validates the new entries and links)
A live worker actually obeys the prompt-level guard (no nested code-review/implement/research/wayfinder flows) when a real model executes a filled brief ⏸️ untested no This requires executing a real LLM worker session; the gate has no live-LLM credential or harness session authority, and the repository's own test-quality policy assigns model-prompt interpretation to…
Evidence: Manual drive script and its 19-check pass transcript source

Source: Manual drive script and its 19-check pass transcript source

#!/usr/bin/env bash
# Manual live drives for the Matt Pocock skills integration, against the real
# bin/fm-brief.sh, bin/fm-spawn.sh, and bin/fm-promote.sh in the worktree.
set -u
ROOT=~/.no-mistakes/worktrees/e1a436203903/01M45BVVZ7BDQHBZZ36AFF6QTX
EVIDENCE=~/.no-mistakes/evidence/01M45BVVZ7BDQHBZZ36AFF6QTX
WORK=$(mktemp -d "${TMPDIR:-/tmp}/fm-mp-drive.XXXXXX")
trap 'rm -rf "$WORK"' EXIT
FAILED=0
note() { printf '%s\n' "$*"; }
check() { # <label> <condition-status> <detail>
  if [ "$2" -eq 0 ]; then note "PASS: $1"; else note "FAIL: $1 - $3"; FAILED=1; fi
}

SPAWN="$ROOT/bin/fm-spawn.sh"
BRIEF="$ROOT/bin/fm-brief.sh"
PROMOTE="$ROOT/bin/fm-promote.sh"

make_home() { # <name>
  local name=$1 home=$WORK/$1
  mkdir -p "$home/home/data" "$home/home/state" "$home/home/config" "$home/projects/proj" "$home/bin"
  git -C "$home/projects/proj" init -q
  printf '#!/bin/sh\nexit 1\n' > "$home/bin/tmux"
  chmod +x "$home/bin/tmux"
  printf '%s\n' "$home/home"
}

run_spawn() { # <home> <bin> <args...>
  local home=$1 bin=$2; shift 2
  env -u NO_MISTAKES_GATE FM_GATE_REFUSE_BYPASS=1 \
    FM_ROOT_OVERRIDE='' FM_HOME="$home" \
    FM_STATE_OVERRIDE="$home/state" FM_DATA_OVERRIDE="$home/data" \
    FM_PROJECTS_OVERRIDE="$WORK/projects-unused" FM_CONFIG_OVERRIDE="$home/config" \
    FM_SPAWN_NO_GUARD=1 FM_BACKEND=tmux PATH="$bin:$PATH" \
    "$SPAWN" "$@" 2>&1
}

fill() { # <file> <intent> <spec> [<skills> <seams>]
  local file=$1 content
  content=$(cat "$file")
  content=${content//'{TASK}'/$2}
  content=${content//'{FIRSTMATE_SPEC}'/$3}
  if [ $# -ge 5 ]; then
    content=${content//'{REQUIRED_SKILLS}'/$4}
    content=${content//'{TESTING_SEAMS}'/$5}
  fi
  printf '%s\n' "$content" > "$file"
}

note '=== S1: fm-brief scaffolds ship and scout briefs carrying the Engineering method contract ==='
HOME1=$(make_home s1)
cd "$WORK/s1"
FM_HOME="$HOME1" "$BRIEF" mp-ship proj --mode direct-PR >"$WORK/s1/ship.out" 2>&1
check "ship scaffold exits zero" $? "$(cat "$WORK/s1/ship.out")"
cp "$HOME1/data/mp-ship/brief.md" "$EVIDENCE/s1-ship-brief.md"
FM_HOME="$HOME1" "$BRIEF" mp-scout proj --scout >"$WORK/s1/scout.out" 2>&1
check "scout scaffold exits zero" $? "$(cat "$WORK/s1/scout.out")"
cp "$HOME1/data/mp-scout/brief.md" "$EVIDENCE/s1-scout-brief.md"
grep -q '# Engineering method' "$HOME1/data/mp-ship/brief.md"; check "ship brief has # Engineering method" $? ''
grep -q '{REQUIRED_SKILLS}' "$HOME1/data/mp-ship/brief.md"; check "ship brief has {REQUIRED_SKILLS}" $? ''
grep -q '{TESTING_SEAMS}' "$HOME1/data/mp-ship/brief.md"; check "ship brief has {TESTING_SEAMS}" $? ''
grep -q "Do not invoke \`code-review\`, \`implement\`, \`research\`, \`wayfinder\`" "$HOME1/data/mp-ship/brief.md"
check "ship brief forbids nested orchestration/duplicate delivery flows" $? ''
grep -q "FirstMate's selected delivery path is the only final review owner." "$HOME1/data/mp-ship/brief.md"
check "ship brief keeps final review with FirstMate's delivery path" $? ''
grep -q '# Engineering method' "$HOME1/data/mp-scout/brief.md"; check "scout brief has # Engineering method" $? ''
grep -q '{REQUIRED_SKILLS}' "$HOME1/data/mp-scout/brief.md"; check "scout brief has {REQUIRED_SKILLS}" $? ''
FM_SECONDMATE_CHARTER='Supervise the alpha domain.' FM_HOME="$HOME1" "$BRIEF" mp-sm --secondmate alpha >"$WORK/s1/sm.out" 2>&1
check "secondmate charter scaffolds" $? "$(cat "$WORK/s1/sm.out")"
grep -q '# Engineering method' "$HOME1/data/mp-sm/brief.md"
check "secondmate charter carries NO engineering method section" $((1-$?)) ''

note '=== S2: legacy brief with no Engineering method section still passes spawn validation (recovery compatibility) ==='
D2=$WORK/s2; HOME2=$(make_home s2); PROJ2="$WORK/s2/projects/proj"; BIN2="$WORK/s2/bin"
mkdir -p "$HOME2/data/legacy-ship"
cat > "$HOME2/data/legacy-ship/brief.md" <<'EOF'
You are a crewmate.

# Task
## Captain's intent
Recover the saved instructions.

## Firstmate spec
Launch with the recorded contract.

# Definition of done
Delivery contract: mode=direct-PR
EOF
out=$(run_spawn "$HOME2" "$BIN2" legacy-ship "$PROJ2" claude --mode direct-PR --yolo off)
printf '%s\n' "$out" > "$EVIDENCE/s2-legacy-spawn-output.txt"
printf '%s\n' "$out" | grep -qi 'engineering method'
check "legacy brief is NOT refused for a missing engineering method" $((1-$?)) "$out"
printf '%s\n' "$out" | grep -q '^error:'
check "legacy brief produced NO validation error" $((1-$?)) "$out"
# Engineering validation (bin/fm-spawn.sh:2554) runs strictly before the rigor
# notice (bin/fm-spawn.sh:2634), so reaching the notice proves validation passed;
# the fake tmux then stops the run before any window, worktree, or meta exists.
printf '%s\n' "$out" | grep -q 'less rigor than the captain'
check "legacy brief passed validation and reached the post-validation flow" $? "$out"
[ ! -e "$HOME2/state/legacy-ship.meta" ]
check "fake-tmux stop left no task metadata behind" $? ''

note '=== S3: fm-promote refuses a scout brief with unfilled engineering placeholders (adversarial) ==='
HOME3=$(make_home s3)
printf 'window=fm-promote-unfilled\nkind=scout\nworktree=/tmp/wt\n' > "$HOME3/state/promote-unfilled.meta"
FM_HOME="$HOME3" "$BRIEF" promote-unfilled proj --scout >/dev/null 2>&1
fill "$HOME3/data/promote-unfilled/brief.md" "Ship the promoted work." "Keep the selected delivery mode."
out=$(env -u NO_MISTAKES_GATE FM_GATE_REFUSE_BYPASS=1 FM_HOME="$HOME3" FM_STATE_OVERRIDE="$HOME3/state" "$PROMOTE" promote-unfilled --mode direct-PR --yolo off 2>&1)
status=$?
printf 'exit=%s\n%s\n' "$status" "$out" > "$EVIDENCE/s3-promote-refusal.txt"
[ "$status" -ne 0 ]; check "promotion with unfilled engineering placeholders exits non-zero" $? 'promoted anyway'
printf '%s\n' "$out" | grep -q 'still contains {REQUIRED_SKILLS} or {TESTING_SEAMS}'
check "promotion refusal names the unfilled engineering placeholders" $? "$out"
printf '%s\n' "$out" | grep -q 'fill ## Required skills and ## Agreed testing seams before promotion'
check "promotion refusal names the subsections to fill" $? "$out"
[ ! -f "$HOME3/data/promote-unfilled/ship-instructions.md" ]
check "refused promotion publishes no ship instructions" $? ''

note '=== S4: spawn refuses a brief whose engineering subsection bodies were emptied (adversarial) ==='
D4=$WORK/s4; HOME4=$(make_home s4); PROJ4="$WORK/s4/projects/proj"; BIN4="$WORK/s4/bin"
FM_HOME="$HOME4" "$BRIEF" empty-skills proj --mode direct-PR >/dev/null 2>&1
fill "$HOME4/data/empty-skills/brief.md" "Ship something." "Keep the delivery contract." '' ''
out=$(run_spawn "$HOME4" "$BIN4" empty-skills "$PROJ4" claude --mode direct-PR --yolo off)
status=$?
printf 'exit=%s\n%s\n' "$status" "$out" > "$EVIDENCE/s4-spawn-empty-refusal.txt"
[ "$status" -ne 0 ]; check "spawn with empty engineering bodies exits non-zero" $? 'spawned anyway'
printf '%s\n' "$out" | grep -q 'must contain nonempty ## Required skills and ## Agreed testing seams'
check "spawn refuses with the nonempty-subsection error" $? "$out"
[ ! -f "$HOME4/state/empty-skills.meta" ]
check "refused spawn wrote no task metadata" $? ''

note '=== S5: legacy scout brief with no Engineering method section still promotes (recovery compatibility) ==='
HOME5=$(make_home s5)
printf 'window=fm-promote-legacy\nkind=scout\nworktree=/tmp/wt\n' > "$HOME5/state/promote-legacy.meta"
mkdir -p "$HOME5/data/promote-legacy"
cat > "$HOME5/data/promote-legacy/brief.md" <<'EOF'
You are a crewmate.

# Task
## Captain's intent
Ship the recovered scout work.

## Firstmate spec
Deliver through the recorded mode.
EOF
out=$(env -u NO_MISTAKES_GATE FM_GATE_REFUSE_BYPASS=1 FM_HOME="$HOME5" FM_STATE_OVERRIDE="$HOME5/state" "$PROMOTE" promote-legacy --mode direct-PR --yolo off 2>&1)
status=$?
printf 'exit=%s\n%s\n' "$status" "$out" > "$EVIDENCE/s5-legacy-promote.txt"
printf '%s\n' "$out" | grep -qi 'engineering method'
check "legacy scout promotion is NOT refused for a missing engineering method" $((1-$?)) "$out"
[ -f "$HOME5/data/promote-legacy/ship-instructions.md" ]
check "legacy scout promotion publishes ship instructions" $? "$out"
grep -q '^Delivery contract: mode=direct-PR' "$HOME5/data/promote-legacy/ship-instructions.md" \
  || grep -q 'Delivery contract: mode=direct-PR' "$HOME5/data/promote-legacy/ship-instructions.md"
check "legacy promoted instructions carry the delivery contract" $? ''
if [ -f "$HOME5/data/promote-legacy/ship-instructions.md" ]; then
  cp "$HOME5/data/promote-legacy/ship-instructions.md" "$EVIDENCE/s5-legacy-ship-instructions.md"
fi

note "=== overall: $([ "$FAILED" -eq 0 ] && echo ALL-PASS || echo HAS-FAILURES) ==="
exit "$FAILED"
Evidence: Generated ship brief carrying the Engineering method contract (real fm-brief.sh output)

Source: Generated ship brief carrying the Engineering method contract (real fm-brief.sh output)

You are a crewmate: an autonomous worker agent managed by firstmate. Work on your own; do not wait for a human.

# Task
## Captain's intent
{TASK}

## Firstmate spec
{FIRSTMATE_SPEC}

# Engineering method
Fill each task-specific subsection with one bullet per item, or write `None - <reason>.`

## Required skills
{REQUIRED_SKILLS}

## Agreed testing seams
{TESTING_SEAMS}

## Execution
Each required-skill bullet is an exact skill ID unless the subsection contains only `None - <reason>.`
Load every named skill before using its method.
If a named skill is unavailable, report the missing skill as a blocker and stop.
Testing seams are the agreed public interfaces where behavior will be tested.
Write tests only at these seams.
For a bug, reproduce the end-user path first and observe the regression test fail before the fix.
When tests apply, work in vertical red-green slices rather than writing every test or every implementation change in one horizontal batch.

## Ownership
FirstMate's selected delivery path is the only final review owner.
Use the required skills for engineering method while keeping orchestration, worker allocation, tracker mutation, review, PR, CI, and merge authority with FirstMate and this brief's Definition of done.
Do not invoke `code-review`, `implement`, `research`, `wayfinder`, or another workflow that delegates work or starts a second delivery path.

# Herdr lifecycle declaration - NOT ENABLED
**HARD SAFETY GATE:** this scaffold cannot inspect the task text filled in above.
If the task will start, stop, delete, restart, profile, or otherwise drive Herdr lifecycle behavior, stop and regenerate the brief with `--herdr-lab` before dispatch.
Do not add Herdr lifecycle commands to this unguarded brief by hand.

# Setup
You are in a disposable git worktree of proj, at a detached HEAD on a clean default branch.

**Verify isolation before anything else.** Run `pwd -P` and `git rev-parse --show-toplevel`; both must resolve to the disposable task worktree you were launched in, such as a treehouse pool path or an Orca-managed worktree, not the primary checkout firstmate operates from.
The path check is authoritative: `git rev-parse --git-dir` and `git rev-parse --git-common-dir` can help inspect the repo, but they do not prove you are outside the primary checkout.
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: launched in primary checkout, not an isolated worktree` to the status file and stop.

1. First action: create your branch: `git checkout -b ml/mp-ship`

# Rules
1. Never push to the default branch (push only your `ml/mp-ship` branch). Never merge a PR.
2. Stay inside this worktree; modify nothing outside it.
3. Use gh-axi for GitHub operations and chrome-devtools-axi for browser operations.
4. Report status by appending one line:
   `echo "{state}: {one short line}" >> '/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s1/home/state/mp-ship.status'`
   States: working, needs-decision, blocked, paused, done, failed.
   Each append wakes firstmate, so report sparingly: only phase changes a supervisor
   would act on (setup done, bug reproduced, fix implemented, validation passed) and the
   needs-decision/blocked/paused/done/failed states. No step-by-step FYI progress lines;
   firstmate reads your pane for that.
   Whenever you mention a PR anywhere - a status line, your terminal, a summary - write its full
   https:// URL exactly as the forge printed it, never a bare number such as "PR 108"; firstmate
   copies that URL from your line rather than assembling one.
   A mid-task `working:` line (including setup complete) is nonterminal: do not end the
   turn after it; continue the same stage until a defined `done:` gate under Definition of done.
   Use `paused: {why}` - distinct from `blocked:` - ONLY when you are deliberately idling on a
   known external wait you expect to clear on its own (an upstream release, a rate-limit reset, a scheduled window, or your own validation round):
   firstmate then leaves your idle pane alone and rechecks it on a long
   cadence instead of treating it as a possible wedge. Use `blocked:` when you are stuck and need help.
5. If you hit the same obstacle twice, append `blocked: {why}` and stop; firstmate will help.
6. If a decision belongs above the implementation worker (product choices, destructive actions),
   append `needs-decision: {summary of options}` and stop. Firstmate will reply with the decision.

   A decision or blocker you opened stays open until a `resolved` line carrying its exact key lands; a later `done:` or `working:` line never closes it, even when the answer is what started that work.
   Firstmate's reply normally writes that closing line at answer time; when a blocker or wait clears WITHOUT a firstmate reply, append `resolved: {how it cleared}` yourself (same `[key=<slug>]` if you opened it with one) as you resume.
7. Never stop, restart, or update the shared `no-mistakes` daemon - it is one instance serving
   every lane/home, so restarting it kills other lanes' in-flight pipeline runs; only firstmate
   manages the daemon.
   Before you append `blocked:` about the pipeline, run `no-mistakes daemon status` and
   `no-mistakes axi status`. If the daemon socket refuses connections or is missing, append
   `blocked: {the daemon error}` and stop even when the local run record still says running or
   fixing, because that record can be stale after the daemon exits. A run record failed with a
   daemon error is also a real block.
   Only after ruling out socket refusal, if the run is still running or fixing, reattach and keep
   going. A drive-call error, timeout, slow read, or generic unreachability is NOT a daemon error:
   the daemon accepts `respond` immediately and runs the round in the background, so a killed or
   timed-out call was only waiting for a read while the run kept working.

# Firstmate instruction inbox
Firstmate steers you through durable message files in '/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s1/home/state/mp-ship.inbox'.
When a terminal message says an instruction is waiting there - and at any natural checkpoint when you are unsure - list '/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s1/home/state/mp-ship.inbox'/*.msg, read and act on each message in numeric order, then acknowledge each handled message by moving it: `mv '/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s1/home/state/mp-ship.inbox'/NNN.msg '/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s1/home/state/mp-ship.inbox'/handled/`.
The move IS the acknowledgement: without it firstmate rings again and eventually treats you as stuck. An empty or absent inbox needs no action.

# Project memory
If `AGENTS.md` or `CLAUDE.md` already exists, or if this task produced durable project-intrinsic knowledge, run `~/.no-mistakes/worktrees/e1a436203903/01M45BVVZ7BDQHBZZ36AFF6QTX/bin/fm-ensure-agents-md.sh .` in the worktree.
Record only project knowledge useful to almost every future session.
For anything the codebase already shows, prefer a pointer to the authoritative file, command, or doc over copying the detail.
If you touch a project `AGENTS.md`, follow `~/.no-mistakes/worktrees/e1a436203903/01M45BVVZ7BDQHBZZ36AFF6QTX/bin/fm-ensure-agents-md.sh`'s self-governance contract in the same pass.
Keep it proportionate: skip `AGENTS.md` edits for trivial tasks that produced no durable project knowledge.

# Definition of done
Delivery contract: mode=direct-PR
This task ships **direct-PR**: you raise the PR yourself, without the no-mistakes pipeline.
The task is complete only when committed on your branch.
When it is implemented and committed, push your branch and open a PR with `gh-axi`, then append `done: PR {url}` to the status file and stop.
Do NOT run /no-mistakes. The configured merge authority decides whether to merge the PR; firstmate relays the outcome.
Evidence: Generated scout brief carrying the Engineering method contract (real fm-brief.sh output)

Source: Generated scout brief carrying the Engineering method contract (real fm-brief.sh output)

You are a crewmate: an autonomous worker agent managed by firstmate. Work on your own; do not wait for a human.

# Task
## Captain's intent
{TASK}

## Firstmate spec
{FIRSTMATE_SPEC}

# Engineering method
Fill each task-specific subsection with one bullet per item, or write `None - <reason>.`

## Required skills
{REQUIRED_SKILLS}

## Agreed testing seams
{TESTING_SEAMS}

## Execution
Each required-skill bullet is an exact skill ID unless the subsection contains only `None - <reason>.`
Load every named skill before using its method.
If a named skill is unavailable, report the missing skill as a blocker and stop.
Testing seams are the agreed public interfaces where behavior will be tested.
Write tests only at these seams.
For a bug, reproduce the end-user path first and observe the regression test fail before the fix.
When tests apply, work in vertical red-green slices rather than writing every test or every implementation change in one horizontal batch.

## Ownership
FirstMate's selected delivery path is the only final review owner.
Use the required skills for engineering method while keeping orchestration, worker allocation, tracker mutation, review, PR, CI, and merge authority with FirstMate and this brief's Definition of done.
Do not invoke `code-review`, `implement`, `research`, `wayfinder`, or another workflow that delegates work or starts a second delivery path.

# Herdr lifecycle declaration - NOT ENABLED
**HARD SAFETY GATE:** this scaffold cannot inspect the task text filled in above.
If the task will start, stop, delete, restart, profile, or otherwise drive Herdr lifecycle behavior, stop and regenerate the brief with `--herdr-lab` before dispatch.
Do not add Herdr lifecycle commands to this unguarded brief by hand.

# Setup
You are in a disposable git worktree of proj, at a detached HEAD on a clean default branch.
This is a SCOUT task: the deliverable is a written report, not a PR.
The worktree is your laboratory - install, run, edit, and make scratch commits freely; all of it is discarded at teardown.
The report is the only thing that survives, so anything worth keeping must be in it.

# Rules
1. Never push to any remote and never open a PR.
2. Stay inside this worktree; the only files you may write outside it are the report and the status file below.
3. Use gh-axi for GitHub operations and chrome-devtools-axi for browser operations.
4. Report status by appending one line:
   `echo "{state}: {one short line}" >> '/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s1/home/state/mp-scout.status'`
   States: working, needs-decision, blocked, paused, done, failed.
   Each append wakes firstmate, so report sparingly: only phase changes a supervisor
   would act on and the needs-decision/blocked/paused/done/failed states. No step-by-step
   FYI progress lines; firstmate reads your pane for that.
   Whenever you mention a PR anywhere - a status line, your terminal, a summary - write its full
   https:// URL exactly as the forge printed it, never a bare number such as "PR 108"; firstmate
   copies that URL from your line rather than assembling one.
   Use `paused: {why}` - distinct from `blocked:` - ONLY when you are deliberately idling on a
   known external wait you expect to clear on its own (an upstream release, a rate-limit reset, a scheduled window, or your own validation round):
   firstmate then leaves your idle pane alone and rechecks it on a long cadence instead of
   treating it as a possible wedge. When you know when the wait clears, say so in the line with
   `until <YYYY-MM-DDTHH:MMZ>` (UTC) and firstmate rechecks at that time instead.
   Use `blocked:` when you are stuck and need help.
5. If you hit the same obstacle twice, append `blocked: {why}` and stop; firstmate will help.
6. If a decision belongs to a human (product choices, destructive actions),
   append `needs-decision: {summary of options}` and stop. Firstmate will reply with the decision.
   A decision or blocker you opened stays open until a `resolved` line carrying its exact key lands; a later `done:` or `working:` line never closes it, even when the answer is what started that work.
   Firstmate's reply normally writes that closing line at answer time; when a blocker or wait clears WITHOUT a firstmate reply, append `resolved: {how it cleared}` yourself (same `[key=<slug>]` if you opened it with one) as you resume.
7. Never stop, restart, or update the shared `no-mistakes` daemon - it is one instance serving
   every lane/home, so restarting it kills other lanes' in-flight pipeline runs; only firstmate
   manages the daemon.
   Before you append `blocked:` about the pipeline, run `no-mistakes daemon status` and
   `no-mistakes axi status`. If the daemon socket refuses connections or is missing, append
   `blocked: {the daemon error}` and stop even when the local run record still says running or
   fixing, because that record can be stale after the daemon exits. A run record failed with a
   daemon error is also a real block.
   Only after ruling out socket refusal, if the run is still running or fixing, reattach and keep
   going. A drive-call error, timeout, slow read, or generic unreachability is NOT a daemon error:
   the daemon accepts `respond` immediately and runs the round in the background, so a killed or
   timed-out call was only waiting for a read while the run kept working.

# Firstmate instruction inbox
Firstmate steers you through durable message files in '/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s1/home/state/mp-scout.inbox'.
When a terminal message says an instruction is waiting there - and at any natural checkpoint when you are unsure - list '/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s1/home/state/mp-scout.inbox'/*.msg, read and act on each message in numeric order, then acknowledge each handled message by moving it: `mv '/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s1/home/state/mp-scout.inbox'/NNN.msg '/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s1/home/state/mp-scout.inbox'/handled/`.
The move IS the acknowledgement: without it firstmate rings again and eventually treats you as stuck. An empty or absent inbox needs no action.

# Definition of done
Write your findings to `/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s1/home/data/mp-scout/report.md`.
The report must stand alone: what you did, what you found, the evidence (commands run, output, file:line references), and what you recommend.
If your deliverable is a visual artifact the captain will review and iterate on, you may host the Lavish review loop yourself (poll, revise, re-serve, staying alive) instead of handing it back to firstmate.
Before reporting done, read and follow `~/.no-mistakes/worktrees/e1a436203903/01M45BVVZ7BDQHBZZ36AFF6QTX/.agents/skills/captain-hold-lifecycle/SKILL.md` and pass its shared completion gate for the report and any visual review.
When the report is complete, append `done: {one-line conclusion}` to the status file and stop.
If your findings reveal work that should ship (e.g. you reproduced a bug and the fix is clear), say so in the report; firstmate may promote this task in place, and you would then receive mode-specific ship instructions as a follow-up message.
Evidence: Legacy-brief spawn output proving validation passed with no engineering refusal

Source: Legacy-brief spawn output proving validation passed with no engineering refusal

notice: legacy-ship ships mode=direct-PR while the standing posture for proj is no-mistakes - less rigor than the captain's standing posture; proceed only on a current explicit captain instruction or an intake judgment you can state
Evidence: fm-promote refusal transcript naming the unfilled engineering placeholders and subsections

Source: fm-promote refusal transcript naming the unfilled engineering placeholders and subsections

exit=1
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  WATCHER DOWN - SUPERVISION IS OFF
●  1 task(s) in flight, but no watcher has a fresh beacon (last beat: never, grace 300s).
●  Trust the emitted supervision protocol for this harness; do not use shell & for watcher repair.
●  This is a supervision warning only; the guarded operation WILL still run.
●  repair a missing or failed watcher cycle with the Pi tool fm_watch_arm_pi, or restart Pi with -e ~/.no-mistakes/worktrees/e1a436203903/01M45BVVZ7BDQHBZZ36AFF6QTX/.pi/extensions/fm-primary-turnend-guard.ts -e ~/.no-mistakes/worktrees/e1a436203903/01M45BVVZ7BDQHBZZ36AFF6QTX/.pi/extensions/fm-primary-pi-watch.ts if the extensions are not loaded.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
error: /var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s3/home/data/promote-unfilled/brief.md still contains {REQUIRED_SKILLS} or {TESTING_SEAMS}; fill ## Required skills and ## Agreed testing seams before promotion
Evidence: fm-spawn refusal transcript for emptied engineering subsection bodies

Source: fm-spawn refusal transcript for emptied engineering subsection bodies

exit=1
error: /var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s4/home/data/empty-skills/brief.md must contain nonempty ## Required skills and ## Agreed testing seams under # Engineering method before spawn
Evidence: Ship instructions published by promoting a legacy (pre-contract) scout brief

Source: Ship instructions published by promoting a legacy (pre-contract) scout brief

Your scout task has been promoted to a ship task, mode=direct-PR. Your window, worktree, and context stay as they are; only the contract below changes.

# Task
## Captain's intent
Ship the recovered scout work.

## Firstmate spec
If these promotion steps were already completed before a relaunch, preserve the existing worker branch and continue from its current state; do not repeat them destructively. That branch is normally `ml/promote-legacy`; a pre-cutover promoted task instead has `fm/promote-legacy`, which must be preserved as-is - never create a fresh `ml/promote-legacy` while prior `fm/promote-legacy` work exists.
1. **Verify isolation before anything else.** Run `pwd -P` and `git rev-parse --show-toplevel`; both must resolve to the disposable task worktree you were launched in, such as a treehouse pool path or an Orca-managed worktree, not the primary checkout firstmate operates from. If either does not resolve to the worktree you were launched in, stop and escalate to firstmate.
2. Inventory this worktree's scratch state with `git status` and `git log` before changing anything.
3. Return to a clean default-branch base, then create your branch: `git checkout -b ml/promote-legacy`.
4. Carry over only the intended fix changes. Leave scratch commits, debug edits, and experiment files behind.
5. If you reproduced a bug, turn that reproduction into a regression test.
6. Treat the scout-time Firstmate spec and any unmarked legacy `# Task` text as investigation context, not captain intent or current ship-time instructions.
7. Everything else in your original instructions carries over unchanged: the status protocol; the instruction inbox and its acknowledgement; the escalation rules, including ask-user; and every safety rule, except where the current delivery contract below explicitly replaces scout-only delivery rules.



# Current delivery mode contract
This task is now kind=ship with mode=direct-PR.
This section supersedes every earlier brief instruction about delivery mode.
These current ship instructions supersede the scout delivery rules and report-based Definition of done.
Any earlier "Never push" or scout-only delivery language in this file is superseded.
The mode-specific Definition of done below is the current delivery contract.

# Current ship safety rule
1. Never push to the default branch (push only your `ml/promote-legacy` branch). Never merge a PR.

# Definition of done
Delivery contract: mode=direct-PR
This task ships **direct-PR**: you raise the PR yourself, without the no-mistakes pipeline.
The task is complete only when committed on your branch.
When it is implemented and committed, push your branch and open a PR with `gh-axi`, then append `done: PR {url}` to the status file and stop.
Do NOT run /no-mistakes. The configured merge authority decides whether to merge the PR; firstmate relays the outcome.
Evidence: Legacy scout promotion transcript

Source: Legacy scout promotion transcript

exit=0
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  WATCHER DOWN - SUPERVISION IS OFF
●  1 task(s) in flight, but no watcher has a fresh beacon (last beat: never, grace 300s).
●  Trust the emitted supervision protocol for this harness; do not use shell & for watcher repair.
●  This is a supervision warning only; the guarded operation WILL still run.
●  repair a missing or failed watcher cycle with the Pi tool fm_watch_arm_pi, or restart Pi with -e ~/.no-mistakes/worktrees/e1a436203903/01M45BVVZ7BDQHBZZ36AFF6QTX/.pi/extensions/fm-primary-turnend-guard.ts -e ~/.no-mistakes/worktrees/e1a436203903/01M45BVVZ7BDQHBZZ36AFF6QTX/.pi/extensions/fm-primary-pi-watch.ts if the extensions are not loaded.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
promoted promote-legacy to ship mode=direct-PR yolo=off (teardown protection restored)
wrote ship instructions for mode=direct-PR: /var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s5/home/data/promote-legacy/ship-instructions.md
next: FM_HOME=/var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s5/home bin/fm-send.sh fm-promote-legacy "$(cat /var/folders/g1/q67qx6cx44n6v9v0fdr3l_xw0000gn/T//fm-mp-drive.aaTXwO/s5/home/data/promote-legacy/ship-instructions.md)"
Evidence: Targeted suite result via bin/fm-test-run.sh
FM_TEST_END tests/fm-brief.test.sh exit=0 / tests/fm-documentation-audiences.test.sh exit=0 / tests/fm-task-delivery.test.sh exit=0
FM_TEST_SUMMARY total=3 failed=0 skipped_gate=0

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 9 of 10 scenarios driven live against the product
Scenario Result Live Evidence
Firstmate scaffolds a ship or scout brief and the worker contract includes the task-specific engineering method (required skills, agreed testing seams) plus the sole-final-review and no-nested-orchest… ✅ pass live Manual drive S1 (s1-ship-brief.md, s1-scout-brief.md) and bin/fm-test-run.sh tests/fm-brief.test.sh (test_ship_modes_generate_clean_briefs, test_scout_and_secondmate_scaffold), exit 0
Secondmate charters are unaffected by the task engineering contract ✅ pass live Manual drive S1 secondmate check and fm-brief.test.sh assert_no_grep on # Engineering method
Adversarial: spawning a current brief with leftover {REQUIRED_SKILLS}/{TESTING_SEAMS} placeholders is refused, names the subsections to fill, and writes no task metadata; a filled brief that mentions… ✅ pass live fm-task-delivery.test.sh test_spawn_requires_filled_engineering_method, exit 0
Adversarial: spawning a brief whose Required skills / Agreed testing seams bodies were emptied is refused with the nonempty-subsection error and writes no task metadata ✅ pass live Manual drive S4 (s4-spawn-empty-refusal.txt, exit non-zero, no state/*.meta)
Recovery compatibility: a saved ship brief predating the Engineering method section still passes spawn validation and proceeds through the normal launch flow ✅ pass live Manual drive S2 (s2-legacy-spawn-output.txt): reached the post-validation rigor notice at bin/fm-spawn.sh:2634, which runs strictly after the engineering validation at bin/fm-spawn.sh:2554, with no er…
Scout promotion carries the filled engineering contract (required skills and testing seams) into the instructions the promoted worker receives, alongside the same mode-specific Definition of done a br… ✅ pass live fm-task-delivery.test.sh test_promotion_delivers_the_real_definition_of_done, exit 0 (asserts the delivered payload for all three modes)
Adversarial: promoting a scout brief with leftover engineering placeholders is refused with a named error and publishes no ship instructions ✅ pass live Manual drive S3 (s3-promote-refusal.txt): exit non-zero, refusal names placeholders and subsections, no ship-instructions.md
Recovery compatibility: promoting a legacy scout brief with no Engineering method section still publishes ship instructions carrying the selected delivery contract ✅ pass live Manual drive S5 (s5-legacy-ship-instructions.md with 'Delivery contract: mode=direct-PR')
Operator and maintainer docs for the skills integration are classified, linked, and reachable through the documentation-audiences inventory ✅ pass live bin/fm-test-run.sh tests/fm-documentation-audiences.test.sh, exit 0 (real consumer of docs/documentation-audiences.json validates the new entries and links)
A live worker actually obeys the prompt-level guard (no nested code-review/implement/research/wayfinder flows) when a real model executes a filled brief ⏸️ untested no This requires executing a real LLM worker session; the gate has no live-LLM credential or harness session authority, and the repository's own test-quality policy assigns model-prompt interpretation to…
  • bash bin/fm-test-run.sh tests/fm-brief.test.sh tests/fm-task-delivery.test.sh tests/fm-documentation-audiences.test.sh (selected suites per the intent's validation policy; FM_TEST_SUMMARY total=3 failed=0)
  • Manual drive bash manual-drive.sh S1: real fm-brief.sh scaffolded ship, scout, and secondmate-charter briefs in an isolated FM_HOME and the generated files were asserted for the Engineering method contract and guard wording
  • Manual drive S2: real fm-spawn.sh against a legacy brief with no # Engineering method section confirmed recovery compatibility (reached post-validation flow, no error, no refusal)
  • Manual drive S3 (adversarial): real fm-promote.sh against a filled scout brief with leftover {REQUIRED_SKILLS}/{TESTING_SEAMS} placeholders confirmed refusal, named subsections, and no published ship instructions
  • Manual drive S4 (adversarial): real fm-spawn.sh against a brief with emptied engineering subsection bodies confirmed refusal with the nonempty-subsection error and no task metadata written
  • Manual drive S5: real fm-promote.sh against a legacy scout brief with no Engineering method section confirmed ship instructions are published with the selected delivery contract
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@mattleus mattleus closed this Oct 5, 2026
@mattleus mattleus reopened this Oct 5, 2026
@mattleus mattleus closed this Oct 5, 2026
@mattleus mattleus reopened this Oct 5, 2026
@mattleus mattleus changed the title feat(bin): integrate Matt Pocock engineering skills into worker briefs feat: integrate Matt Pocock engineering skills into worker brief contract Oct 5, 2026
…serial 3': tests/fm-pi-branch-extension.test.sh case 'Pi outcomes rendering consumers must preserve stock behavior' (Calm-off ToolExecutionComponent rendering differs from Pi stock). Root cause: upstream version drift, not this PR's diff — CI does npm install -g @earendil-works/pi-coding-agent (latest), which now resolves to 1.0.2, and since Pi 0.99.0 the stock call-fallback renders the tool's args beside the bold title (collapsed muted preview, e.g. 'fm_branch_outcomes recent=2') or as an indented per-arg block when expanded. The tracked extension renderers (fm_branch_outcomes, fm_branch_processed) in .pi/extensions/fm-branch-supervision.ts still emitted only the bare bold title, so calm-off rendering diverged from stock and the stock-comparison case failed. Reproduced locally with an isolated npm prefix of pi-coding-agent@1.0.2 (FM_PI_PACKAGE_DIR): the case failed before the fix with the exact CI error. Fix (smallest root-cause change, matching the file's existing version-floor precedent): (1) added a stockToolCallComponent helper in the extension that byte-mirrors Pi 0.99.0+'s formatToolCallWithArgs fallback and made both tools' renderCall use it; (2) raised the test's PI_STOCK_RENDER_FLOOR from 0.84.4 to 0.99.0 so the comparison skips (named version skip) on hosts with a Pi that predates the args-in-call contract, per the existing version-skew pattern. Verified: bin/fm-test-run.sh tests/fm-pi-branch-extension.test.sh now exits 0 against Pi 1.0.2 with the previously failing case passing; bin/fm-test-run.sh tests/fm-pi-primary-types.test.sh passes strict no-emit typecheck against Pi 1.0.2; bin/fm-lint.sh passes with the pinned ShellCheck 0.11.0 and actionlint 1.7.12. Intentionally not attempted: pinning the Pi version in CI — the repo's established contract is that the extension tracks Pi's current stock rendering (runtime probes + named version floors), so updating the renderers and the floor is the root-cause fix consistent with existing behavior
…table serial 1': tests/fm-calm-pi-extension.test.sh 'Pi calm renderer and lifecycle contract' ('grep disappeared from /export calm.html HTML while calm mode was on'). Root cause: upstream Pi version drift, not this PR's diff — CI installs @earendil-works/pi-coding-agent latest (1.0.2), and Pi 1.0.1 renamed the createToolHtmlRenderer lookup dependency from getToolDefinition to getToolRenderers (agent-session's exportToHtml now resolves renderers via the extension runner). The fixtures still passed getToolDefinition, so on Pi >= 1.0.1 the renderer resolved no definition and renderCall returned undefined. Reproduced locally with an isolated npm prefix of pi-coding-agent@1.0.2 (FM_PI_PACKAGE_DIR): the case failed before the fix with the exact CI error. Fix (smallest root-cause change): pass both lookup spellings in the affected fixtures — older Pi destructures getToolDefinition and ignores the extra key, newer Pi uses getToolRenderers, with identical lookup semantics, so no version check is needed. Two files: tests/fm-calm-pi-extension.test.sh (new exportToolHtmlDeps helper used by both createToolHtmlRenderer sites in the renderer/lifecycle case) and tests/fm-pi-branch-extension.test.sh (the structured-fallback export assertion, which under Pi >= 1.0.1 was passing only vacuously from the unrecognized key — adding getToolRenderers restores real exercise of the tool's throw-to-fallback contract). Verified: bin/fm-test-run.sh tests/fm-calm-pi-extension.test.sh exits 0 on both Pi 1.0.2 and the locally installed Pi 0.85.1; bin/fm-test-run.sh tests/fm-pi-branch-extension.test.sh exits 0 on Pi 1.0.2; bin/fm-lint.sh passes with pinned ShellCheck 0.11.0 and actionlint 1.7.12. Only test fixtures changed; no production code consumes createToolHtmlRenderer
…isible

Since Pi 1.0's fullscreen TUI, restored transcript rows live in Pi's
virtualized scrollback, so a 44-row tmux capture no longer sees the
E2E-appended rows (CI failure: missing CALM_E2E_OUTPUT on Pi 1.0.2).
Raise the session/resize height to 400 at the three affected sites so
the viewport holds the whole restored transcript plus appended rows.
…hook rows

CI Pi 1.0.3 failed the 'rendered export DOM violated the Calm conversation
boundary' assertion because newer Pi exports display:false custom messages as
provenance rows with class 'hook-message hook-message-hidden', kept out of the
rendered conversation by the export's stock CSS unless the body carries
show-hidden-messages; Pi <= 1.0.2 omits those rows entirely. The old flat
includes() assertions matched the hidden provenance row's label text in the
messages region and failed.

Scope the assertions to the visible conversation: every hook row must carry
hook-message-hidden, the body must not activate show-hidden-messages, and the
[firstmate-synthetic-input] label must not survive once hidden hook rows are
stripped. Genuine user/assistant entries, the five current operational
user-role inputs, and tree provenance assertions are unchanged, so the Calm
boundary semantics are preserved and older Pi (no hidden rows emitted) still
passes.

Verified headlessly against the prior worker's existing /tmp/fm-dom-repro
Pi 1.0.3 rendered DOM (now passes; it previously failed exactly on the
synthetic-label predicate), plus fixtures: old-Pi markup without hidden rows
passes, a visible hook row fails, and an active show-hidden-messages body
fails. bash -n and bin/fm-lint.sh (pinned ShellCheck 0.11.0, actionlint
1.7.12) pass. The tmux/Chrome E2E verdict belongs to GitHub's exact check.
…rdr calls and daemon join

tests/fm-remote-job.test.sh's 'worker shutdown terminates the active command
tree' case polled worker exit with a fixed 100x0.05 fork-count loop; on a
contended CI serial shard the supervisor-mediated shutdown (quarantine, KILL
escalation, owner reap) outlasted that budget and the case failed with 'the
worker did not finish its TERM shutdown'. Poll on a wall-clock 30s deadline
instead - the same bound this file already uses for the repeatedly signalled
worker - while keeping the exact assertion: a TERM'd worker must finish its
shutdown.

The Behavior tests (Herdr) lane timed out blind after 20 minutes inside
tests/fm-afk-inject-herdr-e2e.test.sh (CI run 37309436481). The failed
assertion was never printed: every herdr CLI call made by the test, its lab
provisioning/teardown, and the supervise daemon was unbounded, so a wedged
herdr server socket (or the daemon blocked inside such a call, outliving
TERM) hung the script with no per-command evidence. Fix within the affected
test: (1) the existing herdr shim now wraps every call in
bin/fm-timeout-lib.sh's fm_run_timed at a 30s bound, naming the exceeded
bound on stderr and returning the shared 124 contract; the long-lived
`server` launch is exempt since bounding it would kill the lab server under
test; the shim is created up front and put first on PATH, so lab
provisioning, backend adapter operations, the daemon's env, the supervisor
pane's own herdr calls, and teardown all sit under the same bound; (2) the
daemon join in stop_daemon and cleanup escalates TERM -> 30s -> KILL and
stop_daemon fails with a named timeout instead of waiting without bound.
The previously proposed ci.yml per-script flag is replaced by this in-test
bounded behavior (the workflow credential cannot push workflow edits).

Verified: bin/fm-test-run.sh tests/fm-afk-inject-herdr-e2e.test.sh exits 0
against real herdr 0.8.0 with all four scenarios passing (68s); the rendered
shim against a never-answering fake herdr exits 124 in 2s with the named
bound message; bin/fm-test-run.sh tests/fm-remote-job.test.sh and
tests/fm-ci-workflow.test.sh exit 0; bash -n passes; bin/fm-lint.sh passes
with pinned ShellCheck 0.11.0 and actionlint 1.7.12.
@mattleus
mattleus merged commit a47e0ff into main Oct 5, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants