Skip to content

fix: pin remote secondmate relaunches to Herdr - #210

Merged
dnth merged 2 commits into
mainfrom
fm/fm-boat-relaunch-backend-pin
Oct 5, 2026
Merged

dnth merged 2 commits into
mainfrom
fm/fm-boat-relaunch-backend-pin

Conversation

@dnth

@dnth dnth commented Oct 5, 2026

Copy link
Copy Markdown
Owner

Intent

Fix Boat F2: bin/fm-remote-secondmate-control.sh relaunch did not pin --backend herdr. cmd_relaunch omitted the --backend herdr that cmd_launch passes. In the live Boat proof, a remote relaunch therefore resolved the remote home's default backend (tmux), failed OMP session-lock binding, and left the endpoint meta window=firstmate: with the route unverified and no migrate verb. Requirements: pin --backend herdr in cmd_relaunch exactly as cmd_launch does. Also make remote relaunch refuse, with a clear message, when the recorded endpoint backend is not herdr, rather than silently relaunching on another backend.

Accepted design decisions (deliberate, not mistakes): to let the remote control pass the pin through the ordinary host-local control plane, bin/fm-control.sh relaunch gains a --backend <name> option that is forwarded to the launch owner (fm-spawn --relaunch); when the pinned backend differs from the task's recorded endpoint backend, fm-control refuses before any journal write, agent touch, or spawn, so a mismatched pin can never migrate a task onto another backend. --backend is relaunch-only (other verbs refuse it like --harness/--model). The remote-side refusal for a recorded non-herdr endpoint is enforced by the existing remote_endpoint_require check (message names the recorded backend and 'expected herdr') before fm-control runs, with fm-control's pin check as defense in depth.

Acceptance criteria:

  • AC1: a regression test proves relaunch passes --backend herdr (fails on the parent commit, passes after the fix). Implemented as an e2e case in tests/fm-remote-secondmate-lifecycle-e2e.test.sh where the remote home config names tmux and the remote OMP mate is relaunched from a dead endpoint; plus fm-control pin-forwarding tests in tests/fm-spawn-relaunch-dead-endpoint.test.sh.
  • AC2: a test proves remote relaunch refuses when the recorded backend is not herdr, and leaves the route and metadata unchanged.
  • AC3: changed tests (bin/fm-test-run.sh --changed) green and bin/fm-lint.sh clean; the PR's full GitHub CI suite is the broad-regression gate.

PR description requirement: local bin/fm-test-run.sh --changed (72 scripts) had 3 failures that must be listed in the PR description with this triage, not presented as green: tests/fm-spawn-pool-base-freshen.test.sh and tests/fm-secondmate-sync.test.sh fail identically on the parent commit 44f9fe3 (pre-existing); tests/fm-secondmate-harness.test.sh fails only because the worktree-tangle detector fires when running inside a feature-branch worktree and passes on a detached HEAD of the parent. tests/fm-remote-reply.test.sh was observed flaky (fails on both parent and branch intermittently, passed in the clean full run). GitHub CI is the deciding gate for these.

Firstmate-Validation-Generation: c9458f578878030dbfa38610bbb75c0a

What Changed

  • Pin remote secondmate relaunches to --backend herdr, preserving Herdr even when the remote home defaults to tmux. Document the pin and refusal of recorded non-Herdr endpoints.
  • Add relaunch-only --backend forwarding in fm-control.sh; reject mismatched pins before journal writes, agent interaction, or spawning. Add regression coverage for forwarding, refusal without metadata or route changes, and remote OMP relaunch from a dead endpoint.
  • Reported local bin/fm-test-run.sh --changed run (72 scripts) had three failures: tests/fm-spawn-pool-base-freshen.test.sh and tests/fm-secondmate-sync.test.sh fail identically on parent 44f9fe3b; tests/fm-secondmate-harness.test.sh hits the feature-worktree tangle detector and passes on a detached parent HEAD. tests/fm-remote-reply.test.sh intermittently fails on both parent and branch but passed in the clean full run. GitHub CI is the deciding gate.

Risk Assessment

✅ Low: Captain, this bounded fix pins remote relaunch to Herdr, rejects mismatched recorded backends before relaunch mutations, and adds behavioral regression coverage.

Testing

Both targeted scripts and all four live CLI scenarios passed; base checks reproduced the regression. Setup issues were resolved, evidence retained, and disposable resources removed. Lint, broad-suite validation, PR, and CI remain with the outer executor.

  • Live validation: ✅ go - 4 of 4 scenarios driven live against the product
Scenario Result Live Evidence
On the remote host, relaunch a dead OMP endpoint with tmux configured as the home default; the replacement remains on fm-remote Herdr, reports alive, and binds its integration marker to the live sessi… ✅ pass live live-relaunch.log; parent-remote-relaunch.log; remote-lifecycle-tests.log
Relaunch an endpoint recorded on tmux through remote control; it refuses with the recorded and expected backends named, preserves endpoint metadata, and creates no relaunch journal. ✅ pass live live-refusals.log; tests/fm-remote-secondmate-lifecycle-e2e.test.sh additionally verifies parent route preservation through simulated SSH
Pin a running Herdr OMP task to tmux through host-local control; it refuses before changing metadata or the previous journal, and the original process remains alive. ✅ pass live live-active-mismatch.log
Pass --backend to interrupt or exit, or supply an empty or missing relaunch pin; control rejects the option and preserves task metadata. ✅ pass live live-refusals.log
Evidence: Live OMP relaunch preserves Herdr and verifies session-lock binding
Closing owned pane w2:p2 to simulate endpoint death.
{"id":"cli:pane:close","result":{"type":"ok"}}
Home default backend: tmux
WARNING: watcher still down (same stale episode; last beat: never, grace 300s) - full banner already printed this episode.
relaunched boat-test harness=omp from=omp model=default effort=default backend=herdr endpoint=fm-remote:w3:p2 worktree=~/.no-mistakes/worktrees/dd71c22cc6d7/01M465WH41SFT455WGMD35CTPJ/.no-mistakes/test-phase/mate
relaunch exit=0
window=fm-remote:w3:p2
endpoint_task_id=boat-test
worktree=~/.no-mistakes/worktrees/dd71c22cc6d7/01M465WH41SFT455WGMD35CTPJ/.no-mistakes/test-phase/mate
project=~/.no-mistakes/worktrees/dd71c22cc6d7/01M465WH41SFT455WGMD35CTPJ/.no-mistakes/test-phase/mate
harness=omp
kind=secondmate
mode=secondmate
yolo=off
tasktmp=/tmp/fm-boat-test
model=default
effort=default
spawn_gen=s1791209560.2987997.12223
control_relaunch_tx=2983315.20261005T141238Z.7034
omp_bin=~/.bun/bin/omp
omp_bun=~/.bun/bin/omp
backend=herdr
herdr_session=fm-remote
herdr_workspace_id=w3
herdr_tab_id=w3:t2
herdr_pane_id=w3:p2
home=~/.no-mistakes/worktrees/dd71c22cc6d7/01M465WH41SFT455WGMD35CTPJ/.no-mistakes/test-phase/mate
projects=
PUBLIC STATE
alivePUBLIC ROUTE
schema=fm-remote-secondmate-control.v1
backend=herdr
target=fm-remote:w3:p2
herdr_session=fm-remote
harness=omp
model=default
effort=default
omp_bun=~/.bun/bin/omp
omp_bin=~/.bun/bin/omp
LOCK BINDING
3015816
sha256:9520240d8e6a003c64636000ed93ca15d85bef251214f1887febba4b4a49eb52
3015816
~/.bun/bin/omp
~/.bun/bin/omp
backend=herdr
herdr_session=fm-remote
Real OMP relaunched on Herdr and bound to its live session lock despite tmux default.
Evidence: Remote refusal and relaunch-only option guards
REMOTE NON-HERDR REFUSAL
error: remote secondmate boat-test endpoint is recorded on backend 'tmux', expected 'herdr'; refusing access until it is explicitly migrated
exit=1
Persisted endpoint metadata unchanged; no relaunch journal created.
LOCAL MISMATCH REFUSAL
error: task boat-test's endpoint is recorded on backend 'tmux', not the pinned 'herdr'; refusing to relaunch it onto another backend
exit=1
Persisted endpoint metadata unchanged; no relaunch journal created.
RELAUNCH-ONLY PIN: interrupt
error: --harness, --model, --effort, --backend, --note, --lock-preheld, and --stall-record apply to 'relaunch' only
exit=1
Persisted endpoint metadata unchanged; no relaunch journal created.
RELAUNCH-ONLY PIN: exit
error: --harness, --model, --effort, --backend, --note, --lock-preheld, and --stall-record apply to 'relaunch' only
exit=1
Persisted endpoint metadata unchanged; no relaunch journal created.
EMPTY OR MISSING PIN: --backend=
error: --backend requires a non-empty value
exit=1
Persisted endpoint metadata unchanged; no relaunch journal created.
EMPTY OR MISSING PIN: --backend
error: --backend requires a value
exit=1
Persisted endpoint metadata unchanged; no relaunch journal created.
Evidence: Conflicting pin leaves the running OMP process and journal untouched
error: task boat-test's endpoint is recorded on backend 'herdr', not the pinned 'tmux'; refusing to relaunch it onto another backend
exit=1
Metadata and previous journal unchanged; original OMP pid 3015816 remains alive.
alive
Evidence: Base-commit replay reproduces tmux endpoint drift
{"id":"cli:pane:close","result":{"type":"ok"}}
WARNING: watcher still down (same stale episode; last beat: never, grace 300s) - full banner already printed this episode.
error: OMP secondmate primary integration and durable session did not bind to its live session lock; OMP_SKIP_SETUP=1 may not have been honored and an interactive setup wizard may be blocking; stopping only the owned endpoint and preserving the persistent home
warning: OMP secondmate launch failed after endpoint creation; stopped only its owned endpoint, retired its launch-generation artifacts, and preserved its persistent home, metadata, and sessions
error: the replacement agent for boat-test could not be launched on omp
error: boat-test was relaunched on omp but no running agent could be confirmed; its work is preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M465WH41SFT455WGMD35CTPJ/.no-mistakes/test-phase/mate
Parent remote relaunch exit=1
window=firstmate:fm-boat-test
endpoint_task_id=boat-test
worktree=~/.no-mistakes/worktrees/dd71c22cc6d7/01M465WH41SFT455WGMD35CTPJ/.no-mistakes/test-phase/mate
project=~/.no-mistakes/worktrees/dd71c22cc6d7/01M465WH41SFT455WGMD35CTPJ/.no-mistakes/test-phase/mate
harness=omp
kind=secondmate
mode=secondmate
yolo=off
tasktmp=/tmp/fm-boat-test
model=default
effort=default
spawn_gen=s1791209688.3361886.4383
control_relaunch_tx=3358626.20261005T141447Z.8738
omp_bin=~/.bun/bin/omp
omp_bun=~/.bun/bin/omp
home=~/.no-mistakes/worktrees/dd71c22cc6d7/01M465WH41SFT455WGMD35CTPJ/.no-mistakes/test-phase/mate
projects=

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 - 4 of 4 scenarios driven live against the product
Scenario Result Live Evidence
On the remote host, relaunch a dead OMP endpoint with tmux configured as the home default; the replacement remains on fm-remote Herdr, reports alive, and binds its integration marker to the live sessi… ✅ pass live live-relaunch.log; parent-remote-relaunch.log; remote-lifecycle-tests.log
Relaunch an endpoint recorded on tmux through remote control; it refuses with the recorded and expected backends named, preserves endpoint metadata, and creates no relaunch journal. ✅ pass live live-refusals.log; tests/fm-remote-secondmate-lifecycle-e2e.test.sh additionally verifies parent route preservation through simulated SSH
Pin a running Herdr OMP task to tmux through host-local control; it refuses before changing metadata or the previous journal, and the original process remains alive. ✅ pass live live-active-mismatch.log
Pass --backend to interrupt or exit, or supply an empty or missing relaunch pin; control rejects the option and preserves task metadata. ✅ pass live live-refusals.log
  • TMPDIR=&#34;$PWD/.test-phase/tmp&#34; bash tests/fm-spawn-relaunch-dead-endpoint.test.sh — passed.
  • TMPDIR=&#34;$PWD/.no-mistakes/test-phase/tmp&#34; bash tests/fm-remote-secondmate-lifecycle-e2e.test.sh — passed after correcting the initial scratch-directory copy recursion.
  • Started real Herdr 0.9.0 in isolated XDG directories; used a relative XDG path to resolve Linux's Unix-socket path limit.
  • Ran real remote OMP relaunch using a disposable saved session; acquired the lock through OMP's interactive bash command !bin/fm-lock.sh, then checked public state, route, metadata, and process binding.
  • Executed remote and host-local backend mismatch refusals, interrupt/exit option guards, and empty/missing pin guards through the real CLI.
  • Executed the pin-forwarding regression against base commit 7bfe32ac35c64923ed521625b562467183566a24; it failed because --backend was unsupported.
  • Replayed base-commit remote relaunch against isolated real Herdr and tmux; it published window=firstmate:fm-boat-test.
  • Stopped and deleted disposable servers, ran product teardown, removed scratch files, and confirmed no source changes remained.
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

dnth added 2 commits October 5, 2026 22:01
cmd_relaunch omitted the --backend herdr that cmd_launch passes, so a remote
relaunch resolved the remote home's configured backend (tmux), failed OMP
session-lock binding, and stranded the route. fm-control relaunch now accepts
--backend, forwards it to the launch owner, and refuses before touching
anything when the recorded endpoint lives on a different backend.
@dnth
dnth merged commit dad3e4a into main Oct 5, 2026
17 checks passed
@dnth
dnth deleted the fm/fm-boat-relaunch-backend-pin branch October 5, 2026 15:13
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.

1 participant