feat(bin): make the ship-branch prefix configurable per project - #2648
Conversation
There was a problem hiding this comment.
Pull request overview
Captain, this PR makes the “ship branch” naming prefix configurable per project (via the data/projects.md registry parsed by bin/fm-project-mode.sh), so generated briefs and local-only merge tooling can use a non-fm/ prefix when desired while keeping the default behavior byte-identical (fm/<task-id>).
Changes:
- Adds
branch=<prefix>as an order-independent registry token and exposesbin/fm-project-mode.sh --branch-prefix <project>for mechanical resolution (defaulting tofm/, withbranch=meaning “no prefix”). - Adds
--branch-prefixtobin/fm-brief.shand uses one resolved$BRANCHconsistently across all brief sections that mention the branch. - Updates
bin/fm-merge-local.shto resolve the project’s branch prefix viafm-project-mode.sh --branch-prefixinstead of hardcodingfm/$ID, and extends tests/docs accordingly.
Reviewed changes
Copilot reviewed 4 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
bin/fm-project-mode.sh |
Extends registry parsing to support branch=<prefix> and a --branch-prefix query while preserving legacy <mode> <yolo> output. |
bin/fm-brief.sh |
Adds --branch-prefix and centralizes branch name rendering via a single $BRANCH variable. |
bin/fm-merge-local.sh |
Resolves branch prefix per project before locating the crewmate branch to fast-forward into the default branch. |
tests/fm-task-delivery.test.sh |
Adds coverage for fm-project-mode.sh --branch-prefix defaults, ordering, and empty override behavior. |
tests/fm-brief.test.sh |
Adds coverage that the resolved branch name is consistent across all generated brief sections and modes. |
docs/architecture.md |
Documents the registry/flag contract and intake behavior for branch-prefix resolution. |
AGENTS.md |
Updates the intake contract to resolve and pass --branch-prefix explicitly (default fm/ needs no flag). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…guid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass.
|
Speaking as Kun's firstmate: Diff review: optional project VISION per-rule: One captain/interface — aligns when opt-in. Authority — aligns (config grant). Scripts vs agents — aligns. Restart — aligns (recorded branch). Delegation — aligns. Fleet/vendor — aligns. Scope — aligns. contract-class: opt-in — unconfigured homes keep attestation: MISMATCH (body |
|
Speaking as Kun's firstmate: Re-triage on newer activity HEAD VISION per-rule:
contract-class: opt-in — unconfigured homes keep CI: tip checks still settling / UNSTABLE (CI run next: waiting-author — re-raise through no-mistakes so attestation MATCHES this tip; close the promoted-scout relaunch gap (resolve relaunch instructions from the promoted ship contract / |
|
Thanks for the re-triage. Two responses to the tip `254e7676`: Attestation MISMATCH: pushed the mechanical CI fixes (below) through `no-mistakes` from a fresh origin-pointed clone so the pipeline can re-attest this new tip; the run is currently stalled at the review step because the local pipeline's agent credentials (Claude Code OAuth session, and separately the Codex refresh token) are both expired and need an interactive re-login that I can't do from here. I'll re-push and let it re-attest as soon as one of those is renewed — flagging so this doesn't read as stalled-and-ignored. CI fixes staged and verified locally (rebased clean onto current `main`, ShellCheck passes with the pinned 0.11.0):
Greptile's open merge-local P1: agreed, that's stale vs this tip — the recorded `branch=` in task meta is what `fm-merge-local.sh` consumes now, not a reconstructed `fm/`. The promoted-scout relaunch gap (the PR's own declared High risk, and the one open functional gap you flagged: a non-default-prefix promoted scout still relaunches from the original scout `brief.md`, which has no `Ship branch:` line, so branch agreement refuses relaunch: this is a real, separate behavior fix (select |
|
Speaking as Kun's firstmate: re-triage after author push + comment. HEAD Default ship-branch prefix remains Attestation: MATCH (body binds tip). Fork CI + NM were contract-class: opt-in — unconfigured homes keep VISION.md per-rule
waiting-ci (was waiting-author for attestation; tip now MATCH). Merge-eligible N until tip CI+NM green. No captain card. Security FYI: none new (injection hardening already noted). |
…guid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass.
c79c920 to
1a32158
Compare
|
Autonomous re-gate status (run on the local no-mistakes pipeline, GLM lane via the Z.AI Anthropic endpoint — no OAuth dependency): Attested tip: Fork CI + Require-no-mistakes on Promoted-scout relaunch fix (
In short: |
1a32158 to
b071bc9
Compare
…guid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass.
|
Rebased onto current upstream main (was 33 behind, head
Gates re-run on the new tip: fm-brief.test.sh (31 ok), fm-task-delivery.test.sh (all pass), fm-spawn-batch.test.sh (all pass), fm-spawn-dispatch-profile.test.sh (all pass), bash -n on all touched scripts, shellcheck -x clean (zero warnings/errors; fixed an SC2100 the rebase surfaced and dropped a now-unused BRANCH_Q). Full no-mistakes pipeline re-attestation can run on this tip if required. |
|
Speaking as Kun's firstmate: Overlap: #4384 (JoeyRichter) is CLOSED not merged (author closed 2026-09-14 in favor of this PR). No leftover to close; #2648 remains the live opt-in prefix PR. Tip Diff review on HEAD VISION per-rule:
contract-class: opt-in. |
|
Following up on the triage note — this PR has been re-raised end-to-end through the no-mistakes pipeline (run Current state at head
Could you approve the workflow runs when you get a chance? Happy to re-run or rebase if anything else is needed. |
…guid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass.
236ad0b to
44ea781
Compare
fm-brief.sh hardcoded every generated ship branch to fm/<task-id>, which leaks that firstmate produced the branch/PR - unwanted for a third-party public repo that does not use this tooling. Add an optional --branch-prefix flag to fm-brief.sh (default "fm/", so existing installs are unaffected) and teach fm-project-mode.sh - the registry's single-owner parser - to resolve a project's optional "branch=<prefix>" data/projects.md annotation via a new --branch-prefix query, order-independent with the existing mode/+yolo tokens. Firstmate resolves the override at task intake and passes it explicitly, mirroring how --mode already works; fm-brief.sh itself never reads the registry. An empty override resolves to a bare "<task-id>" branch rather than a leading slash. All five previously hardcoded fm/$ID sites (branch creation, never-push rule text, definition-of-done text, and the status message) now render the resolved prefix consistently.
…erge-local.sh hardcoded fm/ prefix
… in architecture.md
…guid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass.
…snapshot count - Quote the --branch-prefix want_value assignment in fm-brief.sh, fm-promote.sh, and fm-spawn.sh so ShellCheck SC2100 no longer misreads the plain string 'branch-prefix' as arithmetic shorthand. - Bump the Stock macOS Bash snapshot job's hardcoded Bearings test-count assertion from 59 to 60: this PR added a Bearings test, so the count was stale, not the feature.
…ions with regression test
fm-review-diff.sh's header is the owner of its branch-resolution contract; it still described only the legacy local-branch behavior after the change made review-diff honor state/<id>.meta's recorded ship branch. README's feature bullet enumerates the registry's optional flags and was missing the new branch=<prefix> override.
…nvironment-only failure
…x override test The rebase resolution of tests/fm-brief.test.sh kept the branch's pre-merge \`done: ready in branch ...\` assertion while the merged fm-dod-lib.sh (carrying main's epoch-stamped status line) renders \`done [at=<epoch>]: ready in branch ...\`. Align the assertion so the override-consistency test matches the behavior it verifies.
44ea781 to
a7098fd
Compare
|
Speaking as Kun's firstmate: this is merged. Thank you @wesleymatosdev — really appreciate you taking the time on this. |
…henguid#2648) * feat(bin): make the ship-branch prefix configurable per project fm-brief.sh hardcoded every generated ship branch to fm/<task-id>, which leaks that firstmate produced the branch/PR - unwanted for a third-party public repo that does not use this tooling. Add an optional --branch-prefix flag to fm-brief.sh (default "fm/", so existing installs are unaffected) and teach fm-project-mode.sh - the registry's single-owner parser - to resolve a project's optional "branch=<prefix>" data/projects.md annotation via a new --branch-prefix query, order-independent with the existing mode/+yolo tokens. Firstmate resolves the override at task intake and passes it explicitly, mirroring how --mode already works; fm-brief.sh itself never reads the registry. An empty override resolves to a bare "<task-id>" branch rather than a leading slash. All five previously hardcoded fm/$ID sites (branch creation, never-push rule text, definition-of-done text, and the status message) now render the resolved prefix consistently. * no-mistakes(review): Wire branch-prefix intake in AGENTS.md; fix fm-merge-local.sh hardcoded fm/ prefix * no-mistakes(document): docs: document configurable ship-branch prefix in architecture.md * no-mistakes(review): Persist immutable branch contracts * no-mistakes(document): Document configurable ship branch prefixes * no-mistakes(lint): Captain: fix ShellCheck test warnings * fix(bin): map bearings PR rows to their recorded ship branch (kunchenguid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass. * fix(ci): align lint arithmetic-looking assignment and stale Bearings snapshot count - Quote the --branch-prefix want_value assignment in fm-brief.sh, fm-promote.sh, and fm-spawn.sh so ShellCheck SC2100 no longer misreads the plain string 'branch-prefix' as arithmetic shorthand. - Bump the Stock macOS Bash snapshot job's hardcoded Bearings test-count assertion from 59 to 60: this PR added a Bearings test, so the count was stale, not the feature. * no-mistakes(review): fix(bin): honor recorded ship branch in relaunch and review-diff * no-mistakes(document): docs: complete branch-prefix flag in brief and promote headers * fix(lint): quote branch-prefix parser token; drop unused BRANCH_Q after rebase * no-mistakes(review): Restore %q branch escaping in promotion instructions with regression test * no-mistakes(document): document recorded ship branch and prefix flag fm-review-diff.sh's header is the owner of its branch-resolution contract; it still described only the legacy local-branch behavior after the change made review-diff honor state/<id>.meta's recorded ship branch. README's feature bullet enumerates the registry's optional flags and was missing the new branch=<prefix> override. * no-mistakes(lint): Silence SC2016 on intentional single-quoted sed expression * no-mistakes(review): address branch-prefix review findings in DoD and project-mode * no-mistakes(test): branch-prefix suites pass under tasks-axi 0.2.6; environment-only failure * no-mistakes(document): purge stale fm/ branch naming from docs and headers * fix(test): assert the merged epoch status wording in the branch-prefix override test The rebase resolution of tests/fm-brief.test.sh kept the branch's pre-merge \`done: ready in branch ...\` assertion while the merged fm-dod-lib.sh (carrying main's epoch-stamped status line) renders \`done [at=<epoch>]: ready in branch ...\`. Align the assertion so the override-consistency test matches the behavior it verifies. * no-mistakes(review): Address remaining branch-prefix findings in four bin scripts * no-mistakes(test): skip real-tasks-axi tests below the repo's 0.2.6 floor * no-mistakes(document): document spawn's branch-prefix registry deviation notice
…henguid#2648) * feat(bin): make the ship-branch prefix configurable per project fm-brief.sh hardcoded every generated ship branch to fm/<task-id>, which leaks that firstmate produced the branch/PR - unwanted for a third-party public repo that does not use this tooling. Add an optional --branch-prefix flag to fm-brief.sh (default "fm/", so existing installs are unaffected) and teach fm-project-mode.sh - the registry's single-owner parser - to resolve a project's optional "branch=<prefix>" data/projects.md annotation via a new --branch-prefix query, order-independent with the existing mode/+yolo tokens. Firstmate resolves the override at task intake and passes it explicitly, mirroring how --mode already works; fm-brief.sh itself never reads the registry. An empty override resolves to a bare "<task-id>" branch rather than a leading slash. All five previously hardcoded fm/$ID sites (branch creation, never-push rule text, definition-of-done text, and the status message) now render the resolved prefix consistently. * no-mistakes(review): Wire branch-prefix intake in AGENTS.md; fix fm-merge-local.sh hardcoded fm/ prefix * no-mistakes(document): docs: document configurable ship-branch prefix in architecture.md * no-mistakes(review): Persist immutable branch contracts * no-mistakes(document): Document configurable ship branch prefixes * no-mistakes(lint): Captain: fix ShellCheck test warnings * fix(bin): map bearings PR rows to their recorded ship branch (kunchenguid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass. * fix(ci): align lint arithmetic-looking assignment and stale Bearings snapshot count - Quote the --branch-prefix want_value assignment in fm-brief.sh, fm-promote.sh, and fm-spawn.sh so ShellCheck SC2100 no longer misreads the plain string 'branch-prefix' as arithmetic shorthand. - Bump the Stock macOS Bash snapshot job's hardcoded Bearings test-count assertion from 59 to 60: this PR added a Bearings test, so the count was stale, not the feature. * no-mistakes(review): fix(bin): honor recorded ship branch in relaunch and review-diff * no-mistakes(document): docs: complete branch-prefix flag in brief and promote headers * fix(lint): quote branch-prefix parser token; drop unused BRANCH_Q after rebase * no-mistakes(review): Restore %q branch escaping in promotion instructions with regression test * no-mistakes(document): document recorded ship branch and prefix flag fm-review-diff.sh's header is the owner of its branch-resolution contract; it still described only the legacy local-branch behavior after the change made review-diff honor state/<id>.meta's recorded ship branch. README's feature bullet enumerates the registry's optional flags and was missing the new branch=<prefix> override. * no-mistakes(lint): Silence SC2016 on intentional single-quoted sed expression * no-mistakes(review): address branch-prefix review findings in DoD and project-mode * no-mistakes(test): branch-prefix suites pass under tasks-axi 0.2.6; environment-only failure * no-mistakes(document): purge stale fm/ branch naming from docs and headers * fix(test): assert the merged epoch status wording in the branch-prefix override test The rebase resolution of tests/fm-brief.test.sh kept the branch's pre-merge \`done: ready in branch ...\` assertion while the merged fm-dod-lib.sh (carrying main's epoch-stamped status line) renders \`done [at=<epoch>]: ready in branch ...\`. Align the assertion so the override-consistency test matches the behavior it verifies. * no-mistakes(review): Address remaining branch-prefix findings in four bin scripts * no-mistakes(test): skip real-tasks-axi tests below the repo's 0.2.6 floor * no-mistakes(document): document spawn's branch-prefix registry deviation notice
…henguid#2648) * feat(bin): make the ship-branch prefix configurable per project fm-brief.sh hardcoded every generated ship branch to fm/<task-id>, which leaks that firstmate produced the branch/PR - unwanted for a third-party public repo that does not use this tooling. Add an optional --branch-prefix flag to fm-brief.sh (default "fm/", so existing installs are unaffected) and teach fm-project-mode.sh - the registry's single-owner parser - to resolve a project's optional "branch=<prefix>" data/projects.md annotation via a new --branch-prefix query, order-independent with the existing mode/+yolo tokens. Firstmate resolves the override at task intake and passes it explicitly, mirroring how --mode already works; fm-brief.sh itself never reads the registry. An empty override resolves to a bare "<task-id>" branch rather than a leading slash. All five previously hardcoded fm/$ID sites (branch creation, never-push rule text, definition-of-done text, and the status message) now render the resolved prefix consistently. * no-mistakes(review): Wire branch-prefix intake in AGENTS.md; fix fm-merge-local.sh hardcoded fm/ prefix * no-mistakes(document): docs: document configurable ship-branch prefix in architecture.md * no-mistakes(review): Persist immutable branch contracts * no-mistakes(document): Document configurable ship branch prefixes * no-mistakes(lint): Captain: fix ShellCheck test warnings * fix(bin): map bearings PR rows to their recorded ship branch (kunchenguid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass. * fix(ci): align lint arithmetic-looking assignment and stale Bearings snapshot count - Quote the --branch-prefix want_value assignment in fm-brief.sh, fm-promote.sh, and fm-spawn.sh so ShellCheck SC2100 no longer misreads the plain string 'branch-prefix' as arithmetic shorthand. - Bump the Stock macOS Bash snapshot job's hardcoded Bearings test-count assertion from 59 to 60: this PR added a Bearings test, so the count was stale, not the feature. * no-mistakes(review): fix(bin): honor recorded ship branch in relaunch and review-diff * no-mistakes(document): docs: complete branch-prefix flag in brief and promote headers * fix(lint): quote branch-prefix parser token; drop unused BRANCH_Q after rebase * no-mistakes(review): Restore %q branch escaping in promotion instructions with regression test * no-mistakes(document): document recorded ship branch and prefix flag fm-review-diff.sh's header is the owner of its branch-resolution contract; it still described only the legacy local-branch behavior after the change made review-diff honor state/<id>.meta's recorded ship branch. README's feature bullet enumerates the registry's optional flags and was missing the new branch=<prefix> override. * no-mistakes(lint): Silence SC2016 on intentional single-quoted sed expression * no-mistakes(review): address branch-prefix review findings in DoD and project-mode * no-mistakes(test): branch-prefix suites pass under tasks-axi 0.2.6; environment-only failure * no-mistakes(document): purge stale fm/ branch naming from docs and headers * fix(test): assert the merged epoch status wording in the branch-prefix override test The rebase resolution of tests/fm-brief.test.sh kept the branch's pre-merge \`done: ready in branch ...\` assertion while the merged fm-dod-lib.sh (carrying main's epoch-stamped status line) renders \`done [at=<epoch>]: ready in branch ...\`. Align the assertion so the override-consistency test matches the behavior it verifies. * no-mistakes(review): Address remaining branch-prefix findings in four bin scripts * no-mistakes(test): skip real-tasks-axi tests below the repo's 0.2.6 floor * no-mistakes(document): document spawn's branch-prefix registry deviation notice
…the take-in This reverts 697d94d (feat: add Devin CLI crewmate and scout adapter, kunchenguid#5380) and 67130f1 (feat(bin): make the ship-branch prefix configurable per project, kunchenguid#2648) on top of upstream 9284978, so the P2 take-in merge brings in the rest of upstream b6930db..9284978 without them. - Devin: deferred on the captain's word (take-in question 6); it touches the composer and control hotspots and nothing here uses it. It can come in whole at a later take-in by reverting this revert. - Ship-branch prefix: skipped for now (report section 2.4); every repository this fleet ships to accepts the fm/ prefix. Resolution: fm-harness.sh keeps ac2ed3b's later secondmate-harness line and drops devin from ac2ed3b's supervision-branch pin list.
…henguid#2648) * feat(bin): make the ship-branch prefix configurable per project fm-brief.sh hardcoded every generated ship branch to fm/<task-id>, which leaks that firstmate produced the branch/PR - unwanted for a third-party public repo that does not use this tooling. Add an optional --branch-prefix flag to fm-brief.sh (default "fm/", so existing installs are unaffected) and teach fm-project-mode.sh - the registry's single-owner parser - to resolve a project's optional "branch=<prefix>" data/projects.md annotation via a new --branch-prefix query, order-independent with the existing mode/+yolo tokens. Firstmate resolves the override at task intake and passes it explicitly, mirroring how --mode already works; fm-brief.sh itself never reads the registry. An empty override resolves to a bare "<task-id>" branch rather than a leading slash. All five previously hardcoded fm/$ID sites (branch creation, never-push rule text, definition-of-done text, and the status message) now render the resolved prefix consistently. * no-mistakes(review): Wire branch-prefix intake in AGENTS.md; fix fm-merge-local.sh hardcoded fm/ prefix * no-mistakes(document): docs: document configurable ship-branch prefix in architecture.md * no-mistakes(review): Persist immutable branch contracts * no-mistakes(document): Document configurable ship branch prefixes * no-mistakes(lint): Captain: fix ShellCheck test warnings * fix(bin): map bearings PR rows to their recorded ship branch (kunchenguid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass. * fix(ci): align lint arithmetic-looking assignment and stale Bearings snapshot count - Quote the --branch-prefix want_value assignment in fm-brief.sh, fm-promote.sh, and fm-spawn.sh so ShellCheck SC2100 no longer misreads the plain string 'branch-prefix' as arithmetic shorthand. - Bump the Stock macOS Bash snapshot job's hardcoded Bearings test-count assertion from 59 to 60: this PR added a Bearings test, so the count was stale, not the feature. * no-mistakes(review): fix(bin): honor recorded ship branch in relaunch and review-diff * no-mistakes(document): docs: complete branch-prefix flag in brief and promote headers * fix(lint): quote branch-prefix parser token; drop unused BRANCH_Q after rebase * no-mistakes(review): Restore %q branch escaping in promotion instructions with regression test * no-mistakes(document): document recorded ship branch and prefix flag fm-review-diff.sh's header is the owner of its branch-resolution contract; it still described only the legacy local-branch behavior after the change made review-diff honor state/<id>.meta's recorded ship branch. README's feature bullet enumerates the registry's optional flags and was missing the new branch=<prefix> override. * no-mistakes(lint): Silence SC2016 on intentional single-quoted sed expression * no-mistakes(review): address branch-prefix review findings in DoD and project-mode * no-mistakes(test): branch-prefix suites pass under tasks-axi 0.2.6; environment-only failure * no-mistakes(document): purge stale fm/ branch naming from docs and headers * fix(test): assert the merged epoch status wording in the branch-prefix override test The rebase resolution of tests/fm-brief.test.sh kept the branch's pre-merge \`done: ready in branch ...\` assertion while the merged fm-dod-lib.sh (carrying main's epoch-stamped status line) renders \`done [at=<epoch>]: ready in branch ...\`. Align the assertion so the override-consistency test matches the behavior it verifies. * no-mistakes(review): Address remaining branch-prefix findings in four bin scripts * no-mistakes(test): skip real-tasks-axi tests below the repo's 0.2.6 floor * no-mistakes(document): document spawn's branch-prefix registry deviation notice
…henguid#2648) * feat(bin): make the ship-branch prefix configurable per project fm-brief.sh hardcoded every generated ship branch to fm/<task-id>, which leaks that firstmate produced the branch/PR - unwanted for a third-party public repo that does not use this tooling. Add an optional --branch-prefix flag to fm-brief.sh (default "fm/", so existing installs are unaffected) and teach fm-project-mode.sh - the registry's single-owner parser - to resolve a project's optional "branch=<prefix>" data/projects.md annotation via a new --branch-prefix query, order-independent with the existing mode/+yolo tokens. Firstmate resolves the override at task intake and passes it explicitly, mirroring how --mode already works; fm-brief.sh itself never reads the registry. An empty override resolves to a bare "<task-id>" branch rather than a leading slash. All five previously hardcoded fm/$ID sites (branch creation, never-push rule text, definition-of-done text, and the status message) now render the resolved prefix consistently. * no-mistakes(review): Wire branch-prefix intake in AGENTS.md; fix fm-merge-local.sh hardcoded fm/ prefix * no-mistakes(document): docs: document configurable ship-branch prefix in architecture.md * no-mistakes(review): Persist immutable branch contracts * no-mistakes(document): Document configurable ship branch prefixes * no-mistakes(lint): Captain: fix ShellCheck test warnings * fix(bin): map bearings PR rows to their recorded ship branch (kunchenguid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass. * fix(ci): align lint arithmetic-looking assignment and stale Bearings snapshot count - Quote the --branch-prefix want_value assignment in fm-brief.sh, fm-promote.sh, and fm-spawn.sh so ShellCheck SC2100 no longer misreads the plain string 'branch-prefix' as arithmetic shorthand. - Bump the Stock macOS Bash snapshot job's hardcoded Bearings test-count assertion from 59 to 60: this PR added a Bearings test, so the count was stale, not the feature. * no-mistakes(review): fix(bin): honor recorded ship branch in relaunch and review-diff * no-mistakes(document): docs: complete branch-prefix flag in brief and promote headers * fix(lint): quote branch-prefix parser token; drop unused BRANCH_Q after rebase * no-mistakes(review): Restore %q branch escaping in promotion instructions with regression test * no-mistakes(document): document recorded ship branch and prefix flag fm-review-diff.sh's header is the owner of its branch-resolution contract; it still described only the legacy local-branch behavior after the change made review-diff honor state/<id>.meta's recorded ship branch. README's feature bullet enumerates the registry's optional flags and was missing the new branch=<prefix> override. * no-mistakes(lint): Silence SC2016 on intentional single-quoted sed expression * no-mistakes(review): address branch-prefix review findings in DoD and project-mode * no-mistakes(test): branch-prefix suites pass under tasks-axi 0.2.6; environment-only failure * no-mistakes(document): purge stale fm/ branch naming from docs and headers * fix(test): assert the merged epoch status wording in the branch-prefix override test The rebase resolution of tests/fm-brief.test.sh kept the branch's pre-merge \`done: ready in branch ...\` assertion while the merged fm-dod-lib.sh (carrying main's epoch-stamped status line) renders \`done [at=<epoch>]: ready in branch ...\`. Align the assertion so the override-consistency test matches the behavior it verifies. * no-mistakes(review): Address remaining branch-prefix findings in four bin scripts * no-mistakes(test): skip real-tasks-axi tests below the repo's 0.2.6 floor * no-mistakes(document): document spawn's branch-prefix registry deviation notice
…henguid#2648) * feat(bin): make the ship-branch prefix configurable per project fm-brief.sh hardcoded every generated ship branch to fm/<task-id>, which leaks that firstmate produced the branch/PR - unwanted for a third-party public repo that does not use this tooling. Add an optional --branch-prefix flag to fm-brief.sh (default "fm/", so existing installs are unaffected) and teach fm-project-mode.sh - the registry's single-owner parser - to resolve a project's optional "branch=<prefix>" data/projects.md annotation via a new --branch-prefix query, order-independent with the existing mode/+yolo tokens. Firstmate resolves the override at task intake and passes it explicitly, mirroring how --mode already works; fm-brief.sh itself never reads the registry. An empty override resolves to a bare "<task-id>" branch rather than a leading slash. All five previously hardcoded fm/$ID sites (branch creation, never-push rule text, definition-of-done text, and the status message) now render the resolved prefix consistently. * no-mistakes(review): Wire branch-prefix intake in AGENTS.md; fix fm-merge-local.sh hardcoded fm/ prefix * no-mistakes(document): docs: document configurable ship-branch prefix in architecture.md * no-mistakes(review): Persist immutable branch contracts * no-mistakes(document): Document configurable ship branch prefixes * no-mistakes(lint): Captain: fix ShellCheck test warnings * fix(bin): map bearings PR rows to their recorded ship branch (kunchenguid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass. * fix(ci): align lint arithmetic-looking assignment and stale Bearings snapshot count - Quote the --branch-prefix want_value assignment in fm-brief.sh, fm-promote.sh, and fm-spawn.sh so ShellCheck SC2100 no longer misreads the plain string 'branch-prefix' as arithmetic shorthand. - Bump the Stock macOS Bash snapshot job's hardcoded Bearings test-count assertion from 59 to 60: this PR added a Bearings test, so the count was stale, not the feature. * no-mistakes(review): fix(bin): honor recorded ship branch in relaunch and review-diff * no-mistakes(document): docs: complete branch-prefix flag in brief and promote headers * fix(lint): quote branch-prefix parser token; drop unused BRANCH_Q after rebase * no-mistakes(review): Restore %q branch escaping in promotion instructions with regression test * no-mistakes(document): document recorded ship branch and prefix flag fm-review-diff.sh's header is the owner of its branch-resolution contract; it still described only the legacy local-branch behavior after the change made review-diff honor state/<id>.meta's recorded ship branch. README's feature bullet enumerates the registry's optional flags and was missing the new branch=<prefix> override. * no-mistakes(lint): Silence SC2016 on intentional single-quoted sed expression * no-mistakes(review): address branch-prefix review findings in DoD and project-mode * no-mistakes(test): branch-prefix suites pass under tasks-axi 0.2.6; environment-only failure * no-mistakes(document): purge stale fm/ branch naming from docs and headers * fix(test): assert the merged epoch status wording in the branch-prefix override test The rebase resolution of tests/fm-brief.test.sh kept the branch's pre-merge \`done: ready in branch ...\` assertion while the merged fm-dod-lib.sh (carrying main's epoch-stamped status line) renders \`done [at=<epoch>]: ready in branch ...\`. Align the assertion so the override-consistency test matches the behavior it verifies. * no-mistakes(review): Address remaining branch-prefix findings in four bin scripts * no-mistakes(test): skip real-tasks-axi tests below the repo's 0.2.6 floor * no-mistakes(document): document spawn's branch-prefix registry deviation notice
|
Both findings are addressed in the merged code (merge commit
|
…henguid#2648) * feat(bin): make the ship-branch prefix configurable per project fm-brief.sh hardcoded every generated ship branch to fm/<task-id>, which leaks that firstmate produced the branch/PR - unwanted for a third-party public repo that does not use this tooling. Add an optional --branch-prefix flag to fm-brief.sh (default "fm/", so existing installs are unaffected) and teach fm-project-mode.sh - the registry's single-owner parser - to resolve a project's optional "branch=<prefix>" data/projects.md annotation via a new --branch-prefix query, order-independent with the existing mode/+yolo tokens. Firstmate resolves the override at task intake and passes it explicitly, mirroring how --mode already works; fm-brief.sh itself never reads the registry. An empty override resolves to a bare "<task-id>" branch rather than a leading slash. All five previously hardcoded fm/$ID sites (branch creation, never-push rule text, definition-of-done text, and the status message) now render the resolved prefix consistently. * no-mistakes(review): Wire branch-prefix intake in AGENTS.md; fix fm-merge-local.sh hardcoded fm/ prefix * no-mistakes(document): docs: document configurable ship-branch prefix in architecture.md * no-mistakes(review): Persist immutable branch contracts * no-mistakes(document): Document configurable ship branch prefixes * no-mistakes(lint): Captain: fix ShellCheck test warnings * fix(bin): map bearings PR rows to their recorded ship branch (kunchenguid#1887) fm-bearings-snapshot.sh keyed a PR back to its task by string-matching the headRefName against the fm/ prefix, so any project whose branch prefix was overridden (e.g. via kunchenguid#2648's branch=<prefix> registry annotation) had its PRs silently drop to task "-" in the bearings view, exactly the third fm/-assumption issue kunchenguid#1887 named alongside fm-merge-local.sh and fm-bearings-snapshot.sh itself. fm-fleet-snapshot.sh now surfaces each task's recorded branch= metadata field in its JSON task rows, and fm-bearings-snapshot.sh cross-references a PR's headRefName against those recorded branches before falling back to the legacy fm/ prefix heuristic, so a custom branch prefix maps a PR back to its real task. Adds a regression test proving a PR opened against a fix/<task-id> branch resolves to that task instead of "-"; confirmed it fails on the prior startswith("fm/") logic and passes with this change. ShellCheck clean; full fm-bearings-snapshot.test.sh and fm-fleet-snapshot-view.test.sh suites pass. * fix(ci): align lint arithmetic-looking assignment and stale Bearings snapshot count - Quote the --branch-prefix want_value assignment in fm-brief.sh, fm-promote.sh, and fm-spawn.sh so ShellCheck SC2100 no longer misreads the plain string 'branch-prefix' as arithmetic shorthand. - Bump the Stock macOS Bash snapshot job's hardcoded Bearings test-count assertion from 59 to 60: this PR added a Bearings test, so the count was stale, not the feature. * no-mistakes(review): fix(bin): honor recorded ship branch in relaunch and review-diff * no-mistakes(document): docs: complete branch-prefix flag in brief and promote headers * fix(lint): quote branch-prefix parser token; drop unused BRANCH_Q after rebase * no-mistakes(review): Restore %q branch escaping in promotion instructions with regression test * no-mistakes(document): document recorded ship branch and prefix flag fm-review-diff.sh's header is the owner of its branch-resolution contract; it still described only the legacy local-branch behavior after the change made review-diff honor state/<id>.meta's recorded ship branch. README's feature bullet enumerates the registry's optional flags and was missing the new branch=<prefix> override. * no-mistakes(lint): Silence SC2016 on intentional single-quoted sed expression * no-mistakes(review): address branch-prefix review findings in DoD and project-mode * no-mistakes(test): branch-prefix suites pass under tasks-axi 0.2.6; environment-only failure * no-mistakes(document): purge stale fm/ branch naming from docs and headers * fix(test): assert the merged epoch status wording in the branch-prefix override test The rebase resolution of tests/fm-brief.test.sh kept the branch's pre-merge \`done: ready in branch ...\` assertion while the merged fm-dod-lib.sh (carrying main's epoch-stamped status line) renders \`done [at=<epoch>]: ready in branch ...\`. Align the assertion so the override-consistency test matches the behavior it verifies. * no-mistakes(review): Address remaining branch-prefix findings in four bin scripts * no-mistakes(test): skip real-tasks-axi tests below the repo's 0.2.6 floor * no-mistakes(document): document spawn's branch-prefix registry deviation notice
What Changed
branch=<prefix>annotation to thedata/projects.mdregistry with a--branch-prefixquery inbin/fm-project-mode.sh(defaulting tofm/), and thread a--branch-prefixflag throughfm-brief.sh,fm-spawn.sh, andfm-promote.shso ship tasks create and record<prefix><task-id>branches;fm-dod-lib.shrenders the resolved branch in delivery contracts under a machine-readableShip branch:line, and spawn refuses a brief/spawn branch mismatch while persistingbranch=in task meta for relaunches.fm-merge-local.shandfm-review-diff.shread it from task meta (falling back tofm/<id>for old records and refusing invalid names),fm-fleet-snapshot.shexposes it in task JSON, andfm-bearings-snapshot.shmaps PR head refs to task IDs via recorded branches instead of stripping thefm/prefix (task list moved to a temp file to avoid E2BIG on large fleets).Risk Assessment
✅ Low: Every prior finding verifies as genuinely fixed with exact merge-local parity on the refusal, a mechanically correct slurpfile temp-file path, a header-consistent unknown-mode fallback, and real behavior-level regression tests; the sole residual is a direction-dependent wording inaccuracy in one advisory notice.
Testing
Round 1's only finding is resolved: commit 2df387e (added by the fix phase) skips the two real-tasks-axi tests when the installed tasks-axi predates 0.2.6, so fm-control-relaunch and fm-bearings-snapshot now exit 0 — the bearings suite runs to completion for the first time in this environment (it previously aborted), with the skips printing an explicit reason and the branch-prefix-specific tests in both suites passing. All focused suites for the branch's touched scripts pass (fm-brief, fm-task-delivery, fm-review-diff, fm-dod-lib, fm-fleet-snapshot-view), and a manual end-to-end CLI demo over a real generated brief and registry — captured in the transcript artifact — shows the configurable prefix resolving at intake, rendering consistently across all brief sections, keeping legacy fm/ and default posture output unchanged, and refusing misuse. Visual evidence is not applicable: the change is CLI/library shell surface, so the end-user experience is command output, captured verbatim in the artifacts.
Evidence: End-to-end CLI transcript: registry annotation -> intake resolution -> generated brief -> refusals
Source: End-to-end CLI transcript: registry annotation -> intake resolution -> generated brief -> refusals
Evidence: Full fm-bearings-snapshot suite run (previously aborted; now completes with clean tasks-axi floor skips; custom-prefix PR mapping passes)
Source: Full fm-bearings-snapshot suite run (previously aborted; now completes with clean tasks-axi floor skips; custom-prefix PR mapping passes)
Evidence: Full fm-control-relaunch suite run (exit 0; two tasks-axi floor skips; custom-branch relaunch passes)
Source: Full fm-control-relaunch suite run (exit 0; two tasks-axi floor skips; custom-branch relaunch passes)
Pipeline
Updates from git push no-mistakes
⏭️ **intent** - skipped
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
bin/fm-project-mode.sh:202- The header (bin/fm-project-mode.sh:78-79) promises that an unknown mode under --branch-prefix falls back to "fm/", but the code prints the registered branch token instead: for a registry entry like- proj [no-mistake branch=fix/],fm-project-mode.sh --branch-prefix projemitsfix/(exit 0) while the default output refuses-and-defaults the mode. The mode-typo warning fires, but the branch contract the header documents is not what runs; either the header must drop the claim or the unknown-mode fallback must also reset branch to "fm/". Which side is intended is an author decision.bin/fm-bearings-snapshot.sh:299- The new jq mapping passes the entire fleet snapshot as one argv element (--argjson tasks "$SNAP"). Linux caps a single exec argument at ~128KB (MAX_ARG_STRLEN), and the snapshot's default bounds make that reachable on a normal fleet: secondmate_current alone allows 256KB (FM_SNAPSHOT_SECONDMATE_MAX_BYTES) plus per-record 64KB parent-activity and 64KB registry sections; the bearings default path (line 241) includes secondmates. When exec fails with E2BIG, the|| { nwarn++; continue; }at line 317 swallows it, so that repo's PR rows disappear from the bearings table entirely (not just unmapped task labels) with only a warning count - precisely on the largest fleets. Every neighboring jq call pipes SNAP via stdin; fix mechanically by piping instead of argv (e.g. write.tasksto a temp file once before the repo loop and pass--slurpfile).bin/fm-review-diff.sh:76- Unlike the other new readers of the metabranch=record (fm-merge-local.sh:99 and fm-spawn.sh:1731 both refuse an invalid recorded branch via check-ref-format), fm-review-diff.sh trusts it unvalidated: a hand-edited/corruptbranch=value fails the refs/heads lookup at line 78 and silently falls back to reviewing the worktree's moved HEAD with no warning - the exact wrong-content-diff outcome the feature's own test says must not happen. One mechanical refusal mirroring merge-local closes it.bin/fm-spawn.sh:2902- Spawn validates brief-vs-spawn branch agreement mechanically and reads the registry for forge (hard refusal) and mode (advisory deviation notice at line 2957), but performs no cross-check of the selected prefix against the registry'sbranch=token - not even an advisory notice. The only backstop is the agent following AGENTS.md section 7 at intake, so the feature's own stated purpose (a third-party project's branches/PRs not reading as fm/-authored) can silently fail for a task whose brief was scaffolded without the flag, discovered only at PR time. Cosmetic and consistent with pre-forge mode handling, but the asymmetry deserves a deliberate owner decision.bin/fm-project-mode.sh:167- Dead defensive code:forgeis initialized to "none" (line 142) and only ever reassigned from a token matching /^forge=/ (line 156), so it can never be the empty string and this guard is unreachable. Removing it (or repurposing it for a reachable case) saves readers a hunt for the path where forge is empty.🔧 Fix: Address remaining branch-prefix findings in four bin scripts
1 info still open:
bin/fm-spawn.sh:2968- The new deviation notice's consequence clause "the task's branch and PR will read as firstmate-authored" is emitted unconditionally, but it is only true when the shipped branch carries the fm/ prefix. In the reverse deviation - e.g.fm-spawn --branch-prefix fix/on an unregistered project (standing prefix resolves to the fm/ default) or a relaunch after the captain registered an override in the other direction - the notice correctly fires about the deviation but states a false consequence (fix/<id> does not read as firstmate-authored), which could mislead the operator's proceed/skip judgment. The clause also says the project "registers" the prefix even when it is the unregistered default (the sibling mode notice explicitly acknowledges that nuance in its comment). Condition the clause on the shipped branch actually starting with fm/, or phrase it neutrally (e.g. "differs from the registered prefix").🔧 **Test** - 1 issue found → auto-fixed ✅
bin/fm-test-run.sh tests/fm-brief.test.sh — all pass, incl. the five added --branch-prefix behaviors (legacy default, cross-section override, empty override, scout/secondmate refusal, value validation, shell-safe embedding)bin/fm-test-run.sh tests/fm-task-delivery.test.sh — all pass, incl. fm-project-mode --branch-prefix order-independent resolution, brief/spawn branch agreement refusal, promote recording branch=fix/<id>, prefix-deviation advisory, merge-local registry immutabilitybin/fm-test-run.sh tests/fm-review-diff.test.sh — all pass, incl. reviewing the meta-recorded custom ship branch and refusing a corrupt recorded branchbin/fm-test-run.sh tests/fm-control-relaunch.test.sh — the added test 'a promoted scout with a recorded custom branch relaunches on it' passes; one unrelated pre-existing test fails on the tasks-axi 0.2.5 environment gapbin/fm-test-run.sh tests/fm-bearings-snapshot.test.sh — aborts at a pre-existing tasks-axi-dependent test before reaching the new prefix testisolated run of test_include_prs_is_the_only_fetch_path + test_include_prs_maps_custom_branch_prefix_to_task via a temporarily stripped copy of the bearings suite (copy deleted after) — 'a PR on a custom (non-fm/) branch prefix maps to its recorded task' passesmanual end-to-end captain-flow demo in a throwaway FM_HOME: registry annotation branch=contrib/ -> fm-project-mode.sh --branch-prefix resolves contrib/ (default fm/, empty -> bare id) -> fm-brief.sh scaffolds with contrib/<task-id> in branch creation, Ship branch line, never-push rule, DoD, and status message, zero fm/ leakage; stock project keeps fm/<task-id>; scout/space-prefix misuse refused with nothing scaffolded (transcript captured)🔧 Fix: Skip real-tasks-axi tests below the repo's 0.2.6 floor
✅ Re-checked - no issues remain.
tests/fm-brief.test.sh— full suite, includes the new branch-prefix tests (legacy default, cross-mode override consistency, bare empty prefix, scout/secondmate refusal, space/dash validation, shell-metacharacter safety)tests/fm-task-delivery.test.sh— full suite, covers fm-project-mode --branch-prefix order-independent resolution, fm-spawn prefix selection/deviation notice, fm-promote prefix propagation, fm-merge-localtests/fm-review-diff.test.sh— full suite, covers meta-recorded custom-prefix branch review after worktree HEAD moves and corrupt-branch refusalbash tests/fm-control-relaunch.test.sh— full suite (exit 0, 72 ok); verifies the 2df387e skip for tasks-axi < 0.2.6 and the custom-branch relaunch testbash tests/fm-bearings-snapshot.test.sh— full suite (exit 0, 58 ok, 2 clean skips); verifies the suite no longer aborts and--include-prs maps a custom branch-prefix PR back to its recorded taskbash tests/fm-dod-lib.test.sh— full suite (script changed by the branch)bash tests/fm-fleet-snapshot-view.test.sh— regression for the touched fm-fleet-snapshot.shManual end-to-end demo: wrote a data/projects.md registry withbranch=contrib/,branch=, and no annotation; ranbin/fm-project-mode.sh --branch-prefix <project>for each and the default two-word query; generated three briefs viabin/fm-brief.sh --mode local-only(overridecontrib/, no flag, empty prefix) and grepped the generated briefs to confirm every generated section renders the resolved branch and no fm/ leakage; exercised the scout and space-in-prefix refusals (exit 1 with named errors)✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.