feat(bin): support design tasks in fm-control relaunch - #273
Open
HelloWorldSungin wants to merge 6 commits into
Open
feat(bin): support design tasks in fm-control relaunch#273HelloWorldSungin wants to merge 6 commits into
HelloWorldSungin wants to merge 6 commits into
Conversation
A live ADR task kept the same endpoint, worktree, inbox, and dispatch-pinned skills instead of being refused or rebound to a later plugin release. Co-authored-by: Cursor <cursoragent@cursor.com>
…ify binding serialization
…al 6 (tests/fm-control-relaunch.test.sh): the pi design relaunch case failed because no `pi` binary is on PATH in CI. Added an executable `pi` stub to the per-case fakebin in make_tmux_stub (PATH already prefers fakebin), next to the existing tmux/sleep stubs. fm-spawn resolves pi via `type -P` and probes `--help` for `--tui-mode`; the stub exits 0 so the probe simply omits the flag. Supported-runtime coverage (claude, codex, pi) is unchanged. 2) Lint SC1091 (bin/fm-control.sh:768, bin/fm-spawn.sh:1995): added `# shellcheck source=bin/fm-design-skills-lib.sh` immediately before each `. "$SCRIPT_DIR/fm-design-skills-lib.sh"`, matching the directive used for other bin libs. Verification: - Reproduced failure 1 with a PATH mirror containing no `pi`: pre-fix run gave `not ok - a pi design relaunch should succeed` / `error: pi executable not found on PATH`, exit 1. With the stub the same run passes, exit 0. - Full suite also passes with a normal PATH. - `CI=true bin/fm-lint.sh` (full extended analysis with source following, matching CI) exits 0 with no SC1091. Note: while reproducing failure 1 under a deliberately minimal PATH that lacked `mktemp`, the test harness deleted its own working directory, wiping this worktree checkout. I restored the worktree from the gate repo (worktree metadata was intact) and reapplied the changes; the final diff is exactly the 10 added lines described above. The suite appears to run an unguarded `rm` against a temp root it failed to create, but that is outside the two reported checks so I left it alone
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Add design-task support to the existing restart command, as the captain explicitly approved, so the preserved PMCC ADR worker can restart with the smaller Codex context. Preserve its work, decisions and ADR-only scope.
What Changed
bin/fm-control.sh relaunchnow acceptskind=designtasks the same way it handles ship and scout tasks: it requires--note, appends that note to the brief the replacement worker reads, and keeps the harness recorded for the task instead of reading it again from config.design_skills_plugin/version/updatedplus the skill paths in the dispatch brief under the task tmp dir) and never callsfm-design-skills.sh resolveagain. If the pin is missing, doesn't match, or can't be read, the relaunch refuses before the old agent is stopped. The shared parsing and validation helpers moved out ofbin/fm-spawn.shinto a newbin/fm-design-skills-lib.sh, andfm-spawn.sh --relaunchuses the same adopt path.preserve_relaunch_metanow also carries thebranchmeta key, so it is no longer written twice.docs/agent-control.md,docs/fleet-data-contracts.md,docs/verification/runtime-backends.mdand the design-profile skill to describe design relaunch.tests/fm-control-relaunch.test.shadds tests for:--noterequirement--designonfm-spawn.sh --relaunch🤖 Generated with Claude Code
Risk Assessment
✅ Low: The fix round moves the full design-pin validation into a shared helper that fm-control now calls before it checkpoints or stops the worker. The helper checks the binding schema, that the binding matches the recorded release, that the paths are safe, and that the pinned skill files are readable, and fm-spawn reuses the same helper. The dispatch binding is now built in one place, and the new test runs both entry points against nine binding and skill-file defects and confirms that nothing is stopped or changed.
Testing
I ran the targeted relaunch test file (all passed) and re-drove the manual CLI scenarios against the current code with a stub multiplexer: the codex ADR restart on a smaller model, the refusal when a pinned skill is removed, and repeated relaunches. All the live-driven scenarios passed and the worktree stayed clean. The other refusal cases (missing note, invalid pin, --design flag, unknown kind) are covered only by the hermetic test file and were not driven live. There is no UI in this change, so the evidence is CLI transcripts and the persisted task records.
?? wip.mdpresent, the note appears in the brief, and the dispatch binding keeps version 1.2.0Evidence: Manual CLI transcript: codex ADR design relaunch and pinned-skill-removed refusal
Evidence: Branch line count across three design relaunches
relaunch 1 rc=0 branch_lines=1 relaunch 2 rc=0 branch_lines=1 relaunch 3 rc=0 branch_lines=1Evidence: fm-control-relaunch test log
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 2 issues found → auto-fixed ✅
bin/fm-control.sh:74- require_recorded_design_skill_pin checks only a few things before the old agent is stopped: the three meta keys are present, and $tasktmp/brief.md exists and is not a symlink. The checks that can actually refuse run in fm-spawn --relaunch, after do_exit has already stopped the worker. Those are adopt_relaunch_design_skills (binding schema, binding matches meta, safe paths) and the pinned-file readability check at fm-spawn.sh:3188. This failure is reachable in intended use. The mattpocock plugin auto-updates and can remove the old version's skill directory while a design worker stays live, which is the preserved-worker case this change targets. Relaunching then stops the ADR worker, spawn exits 1 at line 3188, and rollback ends as 'prior-record-kept-agent-dead'. The worker is gone and the replacement never launched, even though fm-control's own comment promises a missing pin 'refuses with nothing changed'. Fix: run the full check before safe_checkpoint and do_exit. That means parsing the binding, confirming plugin, version and last_updated match meta, and checking that both pinned paths are regular, readable, non-symlink files. Put this in one shared helper that fm-control and fm-spawn both call, so the two partial copies of the rule stop drifting apart.bin/fm-spawn.sh:2091- The relaunch branch (adopt_relaunch_design_skills) and the fresh-dispatch branch each build the same fm-design-skills.dispatch.v1 jq object from the DESIGN_SKILLS_* variables. Build the binding once after the if/else so the dispatch schema has a single definition. This is a non-functional refactor.🔧 Fix applied.
✅ Re-checked - no issues remain.
🔧 **Test** - 1 issue found → auto-fixed ✅
bin/fm-spawn.sh:3703- This is an older bug that the change did not introduce, but it shows up on every design relaunch.preserve_relaunch_metahas nobranchin its owned-key list, so the oldbranch=line is carried over and the newly written one is added next to it. The meta file gains one extrabranch=line per relaunch: 2, 3, then 4 after three design relaunches (see branch-duplication.txt). Ship tasks with a branch marker behave the same way. The values are identical today, so readers still get the right answer, but the meta file keeps growing and would become ambiguous if the branch ever changed. Fix: addbranchto the owned keys inpreserve_relaunch_meta.fm-control relaunch; it comes back as kind=design on the same endpoint, worktree and branch, with the recorded skill releas…fm-spawn --relaunch --designis refused as a kind overridebin/fm-test-run.sh tests/fm-control-relaunch.test.sh(whole relaunch file, including the six new design and kind tests and the--designcontradicting-flag case)Manual transcriptdrive.sh:fm-control.sh adr1 relaunch --model gpt-5.4-mini --note ...on a live codex design worker, then checked meta, inbox, worktree status, replacement brief, pinned binding and the codex launch lineManual transcriptdrive.sh: removed the pinned grilling skill directory (as a plugin auto-update would) on a live design worker, then ranfm-control.sh adr2 relaunch; checked the refusal, that the pane is still codex, that no keys were sent, that meta is byte-identical and that no relaunch journal existsdrive-branch.sh/drive-branch-repeat.sh: compared metabranch=line counts across ship and design relaunches, and across three repeated design relaunches🔧 Fix applied.
✅ Re-checked - no issues remain.
?? wip.mdpresent, the note appears in the brief, and the dispatch binding keeps version 1.2.0bash tests/fm-control-relaunch.test.sh(full relaunch file, including the design restarts on claude, codex and pi, the missing-note, crew-harness-config, unknown-kind and missing-pin refusals, the invalid-pin checks for both fm-control and direct fm-spawn --relaunch, and the --design flag refusal)bash $EVIDENCE/drive.sh- manual CLI drive:fm-control.sh adr1 relaunch --model gpt-5.4-mini --note ...on a codex design worker, then a relaunch after removing the pinned grilling skill directorybash $EVIDENCE/drive-branch-repeat.sh- three design relaunches in a row, countingbranch=lines in the task record each time✅ **Document** - passed
✅ No issues found.
🔧 **Lint** - 1 issue found → auto-fixed ✅
🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Push** - passed
✅ No issues found.