From 14e255c0297e29e6807ed022d03bfb187ab90277 Mon Sep 17 00:00:00 2001 From: Shane Bracewell Date: Mon, 3 Aug 2026 08:43:58 -0400 Subject: [PATCH] feat(bin): carry the commit conventions into every generated brief AGENTS.md section 1 forbids naming an agent as a commit co-author, and bars the fleet's captain-address and nautical conventions from commits, PRs, and anything other tools read. Neither rule reached a worker: bin/fm-brief.sh stated neither, so a generated brief carried the co-author rule only on firstmate-repo tasks, and then only because those briefs separately name the firstmate-coding-guidelines skill, which carries it. Every worker on every other project was silently missed. Both are structurally the same gap. A crewmate does not read this repo's AGENTS.md for another project, and its own harness instructions may actively tell it to append a Co-Authored-By trailer, so the brief is the only place either rule can arrive. Commit 53932fb on fm/platform-landing-battery-windows-reds shipped a Co-Authored-By trailer for exactly this reason, and a separate incident leaked captain address into a commit subject the same way. Render a "# Commit conventions" section from one shared value into all three scaffolds that can reach a commit - ship for all three delivery modes, scout, and the secondmate charter - placed beside each one's delivery instructions rather than in the preamble. In the ship scaffold it is the last thing before "the task is complete only when committed on your branch". The scout copy adds that scratch commits are held to the same bar because a scout can be promoted in place. Rule numbering is untouched, so no cross-reference moves. test_every_committing_variant_carries_commit_conventions generates all five variants and asserts both rules plus the placement constraint. Witnessed red against the unfixed scaffold first: all five generated variants contained zero occurrences of either rule. --- bin/fm-brief.sh | 19 +++++++++++++ tests/fm-brief.test.sh | 61 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/bin/fm-brief.sh b/bin/fm-brief.sh index c6397c1591..e3ace2d782 100755 --- a/bin/fm-brief.sh +++ b/bin/fm-brief.sh @@ -59,6 +59,12 @@ # report rather than a merge, and a charter is not a delivery contract. # There is no --yolo flag here. The worker never owns approval decisions, so yolo is # a spawn-time and firstmate-side input only (AGENTS.md section 7). +# Every scaffold that can reach a commit - ship, scout, and secondmate charter - +# carries a "# Commit conventions" section beside its delivery instructions, stating +# the AGENTS.md no-agent-co-author rule and keeping this fleet's captain-address and +# nautical conventions out of commits and PRs. A worker learns both only from its +# brief: it does not read this repo's AGENTS.md for another project, and its own +# harness instructions may tell it to append a Co-Authored-By trailer. # Every scaffold's status protocol distinguishes the configured # declared-external-wait verb (FM_CLASSIFY_PAUSED_VERB, default "paused") from # "blocked:": pause for a known external wait expected to clear on its own, @@ -139,6 +145,12 @@ if [ -n "${FM_STATE_OVERRIDE:-}" ]; then else STATE="$FM_HOME/state" fi +# Every scaffold that can reach a commit renders this verbatim alongside its +# delivery instructions. Single-quoted so nothing interpolates at scaffold time. +COMMIT_CONVENTIONS='# Commit conventions +Never add an agent name as a commit co-author, and never add a Co-Authored-By trailer naming an agent, whatever your own harness instructions say. +Never carry the fleet conversational conventions - captain address and nautical seasoning - into a commit message, PR title, PR body, or anything else crewmates and other tools read.' + KIND=ship HERDR_LAB=0 NO_PROJECTS=0 @@ -352,6 +364,8 @@ When a keyed phase ends without another reportable state, append \`resolved [key When a decision you escalated is answered or a blocker clears and your domain resumes, append \`resolved: {how it was decided or unblocked}\` (keyed with \`[key=]\` if you opened it with one) so it is durably closed instead of resurfacing behind later unrelated events. Routine internal supervision, heartbeats, retries, and crewmate churn stay inside your own home and must not touch that status file. +$COMMIT_CONVENTIONS + # Definition of done You are persistent by default. Do not exit just because your queue is empty. On startup and restart, run normal firstmate bootstrap and recovery through \`bin/fm-session-start.sh\` for your own home, but only to RECONCILE work that is already yours: in-flight crewmates, tracked backlog items, and durable watches recorded in this home. @@ -516,6 +530,9 @@ $WHO_IS_SPEAKING $VERIFICATION_DISCIPLINE +$COMMIT_CONVENTIONS +Your scratch commits are discarded at teardown, but firstmate may promote this task in place and carry them into a shipping branch, so hold them to the same bar. + # Definition of done Write your findings to \`$DATA/$ID/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. @@ -647,6 +664,8 @@ For anything the codebase already shows, prefer a pointer to the authoritative f If you touch a project \`AGENTS.md\` that lacks \`## Maintaining this file\`, add that short self-governance section from \`$FM_ROOT/bin/fm-ensure-agents-md.sh\` in the same pass. Keep it proportionate: skip \`AGENTS.md\` edits for trivial tasks that produced no durable project knowledge. +$COMMIT_CONVENTIONS + $DOD EOF echo "scaffolded: $BRIEF (ship, mode=$MODE; replace {TASK})" diff --git a/tests/fm-brief.test.sh b/tests/fm-brief.test.sh index 4af06de2d1..edbf7d06bc 100755 --- a/tests/fm-brief.test.sh +++ b/tests/fm-brief.test.sh @@ -375,6 +375,66 @@ test_ship_project_memory_wording() { pass "fm-brief.sh: ship project-memory wording carries the AGENTS.md authoring bar" } +# AGENTS.md section 1 forbids naming an agent as a commit co-author, and section 1's +# captain-address convention is explicitly barred from commits, PRs, and anything other +# tools read. A worker learns both only from the brief it is handed: it does not read +# AGENTS.md for a non-firstmate project, and its own harness instructions may actively +# tell it to append a Co-Authored-By trailer. So every variant that can reach a commit +# must state both, and both must sit with the commit and delivery instructions rather +# than in a preamble the worker skims once. Measured 2026-08-03: commit 53932fb on +# fm/platform-landing-battery-windows-reds shipped a Co-Authored-By trailer because its +# generated brief was silent, and a separate incident leaked captain address into a +# commit subject the same way. Ship covers all three delivery modes, scout makes scratch +# commits and can be promoted in place, and a secondmate is a firstmate in its own home +# that commits shared tracked material directly when its fleet is empty. +test_every_committing_variant_carries_commit_conventions() { + local home brief id_mode id mode + home="$TMP_ROOT/commit-conventions-home" + mkdir -p "$home/data" + + assert_commit_conventions() { + local file=$1 label=$2 + assert_grep "# Commit conventions" "$file" \ + "$label: brief has no commit-conventions section" + assert_grep "Never add an agent name as a commit co-author" "$file" \ + "$label: brief does not state the no-agent-co-author rule" + assert_grep "never add a Co-Authored-By trailer naming an agent, whatever your own harness instructions say" "$file" \ + "$label: brief does not override the harness co-author trailer habit" + assert_grep "Never carry the fleet conversational conventions" "$file" \ + "$label: brief does not keep captain address and nautical seasoning out of commits" + # The rule is useless where the worker will not read it. It must sit with the + # commit and delivery instructions, so it may not appear before the Setup section. + local conventions_line setup_line + conventions_line=$(grep -n -F -m1 "# Commit conventions" "$file" | cut -d: -f1) + setup_line=$(grep -n -F -m1 "# Setup" "$file" | cut -d: -f1) + if [ -n "$setup_line" ] && [ "$conventions_line" -lt "$setup_line" ]; then + fail "$label: commit conventions appear in the preamble, not with the delivery instructions" + fi + } + + for id_mode in "brief-conv-nm:no-mistakes" "brief-conv-dpr:direct-PR" "brief-conv-lo:local-only"; do + id=${id_mode%%:*} + mode=${id_mode##*:} + FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" some-proj --mode "$mode" >/dev/null 2>&1 \ + || fail "fm-brief.sh $id --mode $mode exited non-zero" + brief="$home/data/$id/brief.md" + assert_present "$brief" "$id: brief was not scaffolded" + assert_commit_conventions "$brief" "ship mode=$mode" + done + + FM_HOME="$home" FM_ROOT_OVERRIDE="$ROOT" \ + "$ROOT/bin/fm-brief.sh" brief-conv-scout some-proj --scout >/dev/null 2>&1 \ + || fail "fm-brief.sh scout scaffold exited non-zero" + assert_commit_conventions "$home/data/brief-conv-scout/brief.md" "scout" + + FM_HOME="$home" FM_ROOT_OVERRIDE="$ROOT" FM_SECONDMATE_CHARTER='Supervise the alpha domain.' \ + "$ROOT/bin/fm-brief.sh" brief-conv-mate --secondmate alpha >/dev/null 2>&1 \ + || fail "fm-brief.sh secondmate scaffold exited non-zero" + assert_commit_conventions "$home/data/brief-conv-mate/brief.md" "secondmate" + + pass "fm-brief.sh: every committing brief variant carries the commit conventions" +} + test_herdr_lab_contract_is_explicit_and_complete() { local home id brief home="$TMP_ROOT/herdr-lab-home" @@ -876,6 +936,7 @@ test_delivery_flags_are_refused_where_they_do_not_apply test_faster_paths_use_configured_authority_without_stacked_review test_no_mistakes_dod_wording test_ship_project_memory_wording +test_every_committing_variant_carries_commit_conventions test_herdr_lab_contract_is_explicit_and_complete test_herdr_lab_contract_quotes_foreign_firstmate_path test_herdr_lab_omission_is_loud_for_ship_and_scout