Skip to content

fix: prevent false-success Herdr agent relaunches - #6807

Open
Diabl0570 wants to merge 6 commits into
kunchenguid:mainfrom
Diabl0570:fm/fm-control-relaunch-false-success
Open

Diabl0570 wants to merge 6 commits into
kunchenguid:mainfrom
Diabl0570:fm/fm-control-relaunch-false-success

Conversation

@Diabl0570

@Diabl0570 Diabl0570 commented Oct 7, 2026 •

Copy link
Copy Markdown

Intent

Fix the reported Firstmate relaunch false-success defect: a live original worker was reported exited by delivery, then supported relaunch returned success while the same original process survived and launch shell text entered its live TUI. Delivery and lifecycle must agree on actual liveness, relaunch must verify a real stop/replacement, and no launch command may be typed into a live agent.

Main337 converges the concrete missing-registration acceptance from the desktop memory diagnosis: Herdr agent_not_found must not yield no-agent/dead before consulting recognised live pane-process evidence. For both Claude and Pi, missing registration plus a verified live recognised process stays alive; verified shell-only may be agent-free; unreadable/foreign/contradictory process evidence refuses. Exit/relaunch must never report already-stopped or replacement success while the original PID/start incarnation survives. Classifier fixtures first; live lifecycle reproduction only in the named isolated Herdr lab, never protected original owners. This repair enables a later separately authorised waiting-worker memory policy; it is not authority to exit them now.

Proceed without the live-lab acceptance: run the full normal validation on 68b36e6 with the 16 fixture cases as the proof, and state plainly in the PR that the named live-lab acceptance did not run because of that helper prerequisite.

What Changed

  • Reconcile Herdr missing registration with verified pane-process evidence: recognized live Claude/Pi processes remain alive, only proven shell-only panes are agent-free, and foreign, unreadable, or contradictory evidence refuses recovery.
  • Checkpoint original PID/start incarnations and require their disappearance before reporting a stop or replacement. Recheck shell-only evidence before relaunch shell writes and confirm a recognized replacement process, including standalone relaunches.
  • Add classifier and lifecycle regression fixtures, update recovery/remote fixtures and cleanup, and clarify documentation’s fixture-only verification limits. The named live-lab acceptance did not run because its helper prerequisite was unmet.

Risk Assessment

⚠️ Medium: No material source defect was substantiated, but these safety-critical lifecycle changes depend on OS/process evidence whose actual Claude/Pi live-lab acceptance was explicitly deferred, with conservative refusal checks limiting the risk.

Testing

The six targeted executable suites ultimately passed after correcting an initial temporary-fixture location error; baseline/target classifier comparisons and instrumented lifecycle fixtures retained direct output and process-transition evidence. These are non-live fixture observations, so all six product scenarios remain untested under the live-validation contract. The authorized 0/8 actual Claude/Pi acceptance limitation remains unchanged, and no screenshots were captured because real agent TUIs were not authorized to launch.

  • Live validation: ⚠️ inconclusive - 0 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Deliver an instruction to an unregistered Claude/Pi worker without falsely reporting it exited ⏸️ untested no The prior payload did not establish a live result: it exercised real Firstmate entrypoints with fixture-owned renamed Bash processes and fake Herdr transport, not actual Claude/Pi workers. Its fixture…
Permit agent-free recovery only with verified shell-only evidence and refuse ambiguous process evidence ⏸️ untested no The prior payload did not establish a live result: executable classifier fixtures covered shell-only, foreign, unreadable, contradictory, malformed, and changing-subtree evidence, and crew-state and a…
Refuse exit or relaunch success while the original PID/start incarnation survives ⏸️ untested no The prior payload did not establish a live result: original survival was independently observed in the OS process table, but the worker processes and Herdr responses were fixtures. The fixture transcr…
Complete relaunch only after the original stops and a recognized replacement process exists ⏸️ untested no The prior payload did not establish a live result: control and standalone relaunch interfaces were exercised against fixture-owned processes and fake Herdr transport, not installed Claude/Pi runtimes.…
Reject launch shell text when an agent appears after the initial shell-only check ⏸️ untested no The prior payload did not establish a live result: the adversarial fixture created a real owned process during preparation, but its Herdr transport remained simulated. The late-process fixture transcr…
Reproduce and verify the repair with actual Claude/Pi workers in a named isolated Herdr lab ⏸️ untested no The recorded helper provisioning refusal requires a literal live default session that was absent. The explicit decision prohibits retrying provisioning, starting or reconfiguring default/shared Herdr,…
Evidence: Firstmate lifecycle fixture transcripts, delivery records, and PID/start transitions

Source: Firstmate lifecycle fixture transcripts, delivery records, and PID/start transitions

Evidence scope: real Firstmate entrypoints and fixture-owned Bash PID/start transitions, with fake Herdr transport. No real Herdr session or Claude/Pi runtime launched.

$ bin/fm-send.sh missing-live-claude "read the preserved instruction"
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  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 requested message WILL still be sent.
●  repair a missing or failed watcher cycle with the Pi tool fm_watch_arm_pi, or restart Pi with -e ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.pi/extensions/fm-primary-turnend-guard.ts -e ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.pi/extensions/fm-primary-pi-watch.ts if the extensions are not loaded.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Fake transport payloads from ordinary delivery:
: Firstmate instruction waiting: list "$FM_TASK_INBOX"/*.msg in your 'missing-live-claude.inbox' steering inbox, read and act on each in numeric order, then mv each into its handled/.

Persisted inbox:


$ bin/fm-spawn.sh missing-live-claude --relaunch --harness claude
Before:
fixture-owned agent PID/start: 1823334 proc:47591257
1823334 1823220 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-claude-2126/fake/agent-input
error: task missing-live-claude's endpoint reads 'alive'; a relaunch requires a positively agent-free endpoint (stop the agent first with bin/fm-control.sh missing-live-claude exit)
exit=1
After:
fixture-owned agent PID/start: 1823334 proc:47591257
1823334 1823220 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-claude-2126/fake/agent-input
Independent original PID re-read (1823334):
1823334 1823220 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-claude-2126/fake/agent-input
Transport payloads (fake Herdr, not a vendor TUI):


$ bin/fm-control.sh missing-live-claude exit
Before:
fixture-owned agent PID/start: 1823334 proc:47591257
1823334 1823220 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-claude-2126/fake/agent-input
error: exit-delivered missing-live-claude interrupt=not-needed exit-command=delivered agent-state=alive exit=unconfirmed; the agent did not stop within 0.05s
exit=1
After:
fixture-owned agent PID/start: 1823334 proc:47591257
1823334 1823220 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-claude-2126/fake/agent-input
Independent original PID re-read (1823334):
1823334 1823220 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-claude-2126/fake/agent-input
Transport payloads (fake Herdr, not a vendor TUI):
/exit


$ bin/fm-control.sh missing-live-claude relaunch --note preserve this original
Before:
fixture-owned agent PID/start: 1823334 proc:47591257
1823334 1823220 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-claude-2126/fake/agent-input
error: exit-delivered missing-live-claude interrupt=not-needed exit-command=delivered agent-state=alive exit=unconfirmed; the agent did not stop within 0.05s
error: relaunch of missing-live-claude failed while stopping the old agent, which is still running; its original instructions were restored
exit=1
After:
fixture-owned agent PID/start: 1823334 proc:47591257
1823334 1823220 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-claude-2126/fake/agent-input
phase=failed:stopping
rollback=instructions-restored-agent-alive
Independent original PID re-read (1823334):
1823334 1823220 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-claude-2126/fake/agent-input
Transport payloads (fake Herdr, not a vendor TUI):
/exit
/exit


$ bin/fm-send.sh missing-live-pi "read the preserved instruction"
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  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 requested message WILL still be sent.
●  repair a missing or failed watcher cycle with the Pi tool fm_watch_arm_pi, or restart Pi with -e ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.pi/extensions/fm-primary-turnend-guard.ts -e ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.pi/extensions/fm-primary-pi-watch.ts if the extensions are not loaded.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Fake transport payloads from ordinary delivery:
: Firstmate instruction waiting: list "$FM_TASK_INBOX"/*.msg in your 'missing-live-pi.inbox' steering inbox, read and act on each in numeric order, then mv each into its handled/.

Persisted inbox:


$ bin/fm-spawn.sh missing-live-pi --relaunch --harness pi
Before:
fixture-owned agent PID/start: 1836777 proc:47592078
1836777 1836723 bash            pi --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-pi-2637/fake/agent-input
error: task missing-live-pi's endpoint reads 'alive'; a relaunch requires a positively agent-free endpoint (stop the agent first with bin/fm-control.sh missing-live-pi exit)
exit=1
After:
fixture-owned agent PID/start: 1836777 proc:47592078
1836777 1836723 bash            pi --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-pi-2637/fake/agent-input
Independent original PID re-read (1836777):
1836777 1836723 bash            pi --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/missing-live-pi-2637/fake/agent-input
Transport payloads (fake Herdr, not a vendor TUI):


$ bin/fm-control.sh missing-live-pi exit
Before:
fixture-owned agent PID/start: 1836777 proc:47592078
1836777 1836723 bash            pi --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8c

... [3902 bytes truncated] ...

2/fake/agent-input
phase=complete
original_pid_start=1841133	proc:47592882
exit_result=stopped
Independent original PID re-read (1841133):
original PID absent from OS process table
Transport payloads (fake Herdr, not a vendor TUI):
/exit
. '/tmp/fm-new-incarnation-claude+d8cc78498d236cd0454865ac0cb82b590ad960911600a317b0789bc608b1f7e5/launch.s1791439252.1842079.23260.sh'


$ bin/fm-control.sh new-incarnation-pi relaunch --note continue the preserved work
Before:
fixture-owned agent PID/start: 1844052 proc:47593437
1844052 1844036 bash            pi --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/new-incarnation-pi-31611/fake/agent-input
warning: ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/new-incarnation-pi-31611/home/data/new-incarnation-pi/launch-brief.md records no ship branch; defaulting to legacy branch fm/new-incarnation-pi
warning: ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/new-incarnation-pi-31611/home/data/new-incarnation-pi/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
relaunched new-incarnation-pi harness=pi from=pi model=default effort=default backend=herdr endpoint=fmlab:%7 worktree=~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/new-incarnation-pi-31611/wt
exit=0
After:
fixture-owned agent PID/start: 1849243 proc:47593956
1849243 1844036 bash            pi --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/new-incarnation-pi-31611/fake/agent-input
phase=complete
original_pid_start=1844052	proc:47593437
exit_result=stopped
Independent original PID re-read (1844052):
original PID absent from OS process table
Transport payloads (fake Herdr, not a vendor TUI):
/quit
. '/tmp/fm-new-incarnation-pi+d47ff2b395c3e7956e3633c46da769d738f51596adc0c891c36ae0885c899883/launch.s1791439258.1845644.31979.sh'


$ bin/fm-control.sh registration-only relaunch --note do not borrow registration as process proof
Before:
fixture-owned agent: absent
warning: ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/registration-only-29746/home/data/registration-only/launch-brief.md records no ship branch; defaulting to legacy branch fm/registration-only
warning: ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/registration-only-29746/home/data/registration-only/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
error: task registration-only's replacement launch was delivered but no recognized OS process incarnation was confirmed (process evidence 'shell'); relaunch is unconfirmed
error: the replacement agent for registration-only could not be launched on claude
error: registration-only was relaunched on claude but no running agent could be confirmed; its work is preserved at ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/registration-only-29746/wt
exit=1
After:
fixture-owned agent: absent
phase=failed:launching
rollback=none-new-record-kept
Transport payloads (fake Herdr, not a vendor TUI):
. '/tmp/fm-registration-only+379038283f067d8eb838151ff2c37c1fc03b83cb6c8e7eca94ae3a94da51eabb/launch.s1791439262.1850149.3493.sh'


$ bin/fm-spawn.sh registration-only --relaunch --harness claude
Before:
fixture-owned agent: absent
phase=failed:launching
rollback=none-new-record-kept
warning: ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/registration-only-29746/home/data/registration-only/launch-brief.md records no ship branch; defaulting to legacy branch fm/registration-only
warning: ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/registration-only-29746/home/data/registration-only/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
error: task registration-only's replacement launch was delivered but no recognized OS process incarnation was confirmed (process evidence 'shell'); relaunch is unconfirmed
exit=1
After:
fixture-owned agent: absent
phase=failed:launching
rollback=none-new-record-kept
Transport payloads (fake Herdr, not a vendor TUI):
. '/tmp/fm-registration-only+379038283f067d8eb838151ff2c37c1fc03b83cb6c8e7eca94ae3a94da51eabb/launch.s1791439262.1850149.3493.sh'
. '/tmp/fm-registration-only+379038283f067d8eb838151ff2c37c1fc03b83cb6c8e7eca94ae3a94da51eabb/launch.s1791439265.1851839.972.sh'


$ bin/fm-spawn.sh late-process --relaunch --harness claude
Before:
fixture-owned agent: absent
warning: ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/late-process-24589/home/data/late-process/launch-brief.md records no ship branch; defaulting to legacy branch fm/late-process
warning: ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/late-process-24589/home/data/late-process/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
error: task late-process's Herdr pane is 'agent', not positively shell-only; refusing to type a relaunch shell command into it
error: task late-process's endpoint could not be moved into its recorded worktree '~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/late-process-24589/wt'; refusing to launch outside the copy holding its work
exit=1
After:
fixture-owned agent PID/start: 1854070 proc:47594810
1854070 1853532 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/late-process-24589/fake/agent-input
Transport payloads (fake Herdr, not a vendor TUI):


$ bin/fm-control.sh masked-original relaunch --note do not borrow pane death
Before:
fixture-owned agent PID/start: 1854329 proc:47594837
1854329 1854273 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/masked-original-27508/fake/agent-input
error: task masked-original's original PID/start incarnation survives or cannot be read; relaunch cannot claim a stop or replacement
error: relaunch of masked-original failed while stopping the old agent and its state is 'unreadable-original-process', so it was not proven stopped; its original instructions were restored and the durable record was retained for recovery
exit=1
After:
fixture-owned agent PID/start: 1854329 proc:47594837
1854329 1854273 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/masked-original-27508/fake/agent-input
phase=failed:stopping
rollback=instructions-restored-agent-state-unreadable-original-process
Independent original PID re-read (1854329):
1854329 1854273 bash            claude --noprofile --norc -c read -r _ < "$1" -- ~/.no-mistakes/worktrees/54ec8cc673b9/01M4CPXBSKQ9HYZA4V3XC0CNHD/.test-phase-tmp/fm-control-relaunch.V0LBCT/masked-original-27508/fake/agent-input
Transport payloads (fake Herdr, not a vendor TUI):
/exit
Evidence: Baseline defect and corrected registration/process classifier results

Source: Baseline defect and corrected registration/process classifier results

Deterministic classifier counterfactual; process evidence is supplied by fixtures, not a running vendor agent.
Base: 3c58ec8e0123b0047f9bf319e0edd5788eec988d
Target: ea2e3e0969ba4b109a458bce471e13d1e2ee2e65
baseline claude missing registration + agent => pane=no-agent recovery=dead husk=permitted
baseline claude missing registration + shell => pane=no-agent recovery=dead husk=permitted
baseline claude missing registration + other => pane=no-agent recovery=dead husk=permitted
baseline claude missing registration + unreadable => pane=no-agent recovery=dead husk=permitted
baseline pi missing registration + agent => pane=no-agent recovery=dead husk=permitted
baseline pi missing registration + shell => pane=no-agent recovery=dead husk=permitted
baseline pi missing registration + other => pane=no-agent recovery=dead husk=permitted
baseline pi missing registration + unreadable => pane=no-agent recovery=dead husk=permitted
current claude missing registration + agent => pane=live recovery=alive husk=refused
current claude missing registration + shell => pane=no-agent recovery=dead husk=permitted
current claude missing registration + other => pane=unknown recovery=unreadable husk=refused
current claude missing registration + unreadable => pane=unknown recovery=unreadable husk=refused
current pi missing registration + agent => pane=live recovery=alive husk=refused
current pi missing registration + shell => pane=no-agent recovery=dead husk=permitted
current pi missing registration + other => pane=unknown recovery=unreadable husk=refused
current pi missing registration + unreadable => pane=unknown recovery=unreadable husk=refused
Evidence: Successful unchanged relaunch-suite rerun with corrected fixture location

Source: Successful unchanged relaunch-suite rerun with corrected fixture location

FM_TEST_BEGIN 2026-10-08T05:55:57Z tests/fm-control-relaunch.test.sh family=backend-dispatch expected_gate_skip=none
ok - fm-control removes the dialog file after exit and after relaunch
ok - fm-control exit removes the dialog file before it releases the control lock
ok - fm-control relaunch: a same-harness relaunch replaces the agent in the same endpoint and worktree
ok - fm-control relaunch: pending composer text refuses before the exit command is typed
ok - fm-control relaunch: an unreadable composer fails safe before the exit command is typed
# evidence begin: linked-home relaunch
$ bin/fm-control.sh rl42 relaunch --note "continue from linked home"
warning: /tmp/fm-control-relaunch.jJDFHf/linked-home-22731/home/data/rl42/launch-brief.md records no ship branch; defaulting to legacy branch fm/rl42
warning: /tmp/fm-control-relaunch.jJDFHf/linked-home-22731/home/data/rl42/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
relaunched rl42 harness=claude from=claude model=default effort=default backend=tmux endpoint=fmses:fm-rl42 worktree=/tmp/fm-control-relaunch.jJDFHf/linked-home-22731/wt
exit=0
worker HEAD before=9c778e19ca986a946d078c5011bf7e89958babf0 after=9c778e19ca986a946d078c5011bf7e89958babf0
saved task metadata:
window=fmses:fm-rl42
endpoint_task_id=rl42
worktree=/tmp/fm-control-relaunch.jJDFHf/linked-home-22731/wt
project=/tmp/fm-control-relaunch.jJDFHf/linked-home-22731/secondmate
harness=claude
kind=ship
mode=no-mistakes
yolo=off
branch=fm/rl42
tasktmp=/tmp/fm-rl42
model=default
effort=default
busy_gen=g1791438964.1592045.5769
spawn_gen=s1791438965.1591690.18703
control_relaunch_tx=1591314.20261008T055604Z.10463
worker status:
 M task.txt
preserved task.txt:
committed task work
unfinished task work
worker FETCH_HEAD absent
# evidence end
ok - fm-control relaunch: a linked spawning home preserves committed and unfinished work in the recorded copy
ok - fm-control relaunch: durable task metadata survives replacement launch publication
ok - fm-control relaunch: delivery and concurrent task metadata publication serialize
ok - fm-control relaunch: disabling tracing clears metadata and pane context
ok - fm-control relaunch: progress and the Firstmate-worktree worker identity reach the replacement
ok - fm-control relaunch: a ship task refuses without the progress note its replacement needs
ok - fm-control relaunch: switching harness is one ordinary relaunch, and the old wiring goes with the old agent
ok - fm-control relaunch: a harness switch resets model and effort unless they are named too
ok - fm-control relaunch: a prefixed recorded harness can switch adapters transactionally
ok - fm-control relaunch: a prefixed command requires an explicit replacement harness
ok - fm-control relaunch: a same-harness relaunch keeps the profile axes it was running with
ok - native Ultra relaunch preserves its profile and rejects an unsupported model before stopping
ok - fm-control relaunch: a signed-out worker account pin refuses before the old agent stops
ok - fm-control relaunch: the replacement follows the home's current worker account pin
ok - fm-control relaunch: a Pi replacement keeps the home's tool exclusions
ok - fm-control relaunch: exclusion-list refusals happen before the running agent stops
ok - fm-control relaunch: explicit model and effort win over the recorded ones
ok - fm-control relaunch: refuses to relaunch onto an adapter with no verified mechanics
ok - fm-control relaunch: the retired incarnation's global turn-end token is revoked
ok - fm-control relaunch: wiring cleanup failure refuses replacement arming
ok - fm-control-lib: one owner resolves each harness's turn-end registry entry, and refuses a malformed token
ok - fm-control relaunch: a secondmate relaunch re-resolves its durable configured harness pin
ok - fm-control relaunch: invalid configured effort is ignored before stop
ok - fm-control relaunch: an adapter unverified for this task kind refuses before the agent is stopped
ok - fm-control relaunch: explicit secondmate harness resets unnamed profile axes
ok - fm-control relaunch: a ship task keeps its recorded harness instead of re-reading crew config
ok - fm-spawn --relaunch: with no explicit harness it reuses the task's recorded one, never the crew default
ok - fm-spawn --relaunch: a promoted scout with a recorded custom branch relaunches on it instead of being refused
ok - fm-promote/fm-spawn --relaunch: the current ship contract supersedes stale scout delivery text
ok - fm-spawn --relaunch: wiring armed under a prefixed harness name is still retired
ok - fm-spawn --relaunch: switching away from muse retires its session binding
ok - fm-spawn --relaunch: switching away from cursor retires its session binding
ok - fm-control relaunch: an unaccountable local copy refuses before the agent is touched
ok - fm-control relaunch: a worker with nothing to work from is never launched
ok - fm-control relaunch: a refusal before the agent is stopped leaves the durable record untouched
ok - fm-control relaunch: checkpoint inspection failures refuse before stopping
ok - fm-control relaunch: a launch failure after the stop keeps the prior record and reports the real state
ok - fm-control relaunch: unpublished rollback keeps concurrent durable metadata
ok - fm-control relaunch: post-publication failure keeps the new durable record
ok - fm-control relaunch: partial stop reconciles actual agent state
ok - fm-control relaunch: failed journal replacement preserves durable phase
ok - fm-spawn relaunch: prepublication abort removes replacement state
ok - fm-control relaunch: the checkpoint records the exact unlanded work it preserved
ok - fm-control relaunch: a secondmate's child work is accounted for and its charter is left alone
ok - fm-control relaunch: a secondmate home that is not this secondmate's is refused
ok - fm-control relaunch: unreadable child records fail checkpoint
ok - fm-control relaunch: unlistable state fails checkpoint
ok - fm-control relaunch: a vanished watcher scratch file does not fail the child-record checkpoint
ok - fm-control relaunch: two control actions on one task serialize instead of interleaving
ok - fm-spawn relaunch: direct entry participates in lifecycle serialization
ok - fm-promote: promotion participates in lifecycle serialization
ok - fm-spawn --relaunch: refuses to launch a second agent into a live endpoint
ok - fm-spawn --relaunch: symlinked records refuse before inspection
ok - fm-spawn --relaunch: keeps its early meta lock continuous
ok - fm-spawn --relaunch: pending closes refuse before replacement begins
ok - fm-spawn --relaunch: every identity axis comes from the record, and a contradicting flag refuses
ok - fm-spawn --relaunch: an unrecorded task is refused
ok - fm-spawn --relaunch: refuses to start a replacement outside the copy holding its work
ok - tmux: a window absent from its session refuses both verbs rather than being assumed gone
ok - tmux: an unfindable session refuses both verbs, so a live agent is never duplicated
ok - tmux: a dead server on this socket refuses both verbs rather than proving absence
ok - reclaim: an unclassifiable endpoint is still refused, so two agents cannot share one
ok - Herdr Claude/Pi missing registration: delivery stays live, original survival refuses exit/relaunch, and no launch command reaches the TUI
ok - Herdr relaunch: real stop/new incarnation succeeds; registration-only replacement never reports success
ok - Herdr relaunch: a late process cannot borrow the earlier shell-only read to receive launch text
ok - Herdr stop postcondition: a dead pane read cannot override a surviving exact original incarnation
ok - fm-spawn --relaunch: resumes the bound Pi session only for a Pi registration
ok - reclaim: a herdr pane that outlived its stopped server is adopted, never orphaned beside a new tab
ok - fm-control exit: a herdr pane that outlived its stopped server is already-stopped, not gone
ok - reclaim: a herdr rebind is created in the session the record names, never the ambient one
ok - reclaim: a herdr agent that came back with its server refuses, so one worktree keeps one agent
ok - reclaim: a herdr reclaim rebinds the endpoint and leaves the whole rest of the task alone
ok - reclaim: a herdr secondmate whose endpoint is gone is sent to its own respawn owner
ok - reclaim: a rebind refused from a plain shell reports the real cause, not a fabricated session mismatch
ok - relaunch re-reads the backlog item instead of blindly re-running the transition
ok - relaunch heals an item that drifted out of In flight while the task stayed live
FM_TEST_END 2026-10-08T05:58:32Z tests/fm-control-relaunch.test.sh exit=0 duration_ms=154723 gate_skip=false
FM_TEST_SUMMARY total=1 failed=0 skipped_gate=0 duration_ms=154774
FM_TEST_SUMMARY_FAMILY family=backend-dispatch count=1 duration_ms=154723 failed=0
FM_TEST_SLOWEST rank=1 script=tests/fm-control-relaunch.test.sh duration_ms=154723
fm-test-run: wrote timing artifact: ~/.no-mistakes/evidence/01M4CPXBSKQ9HYZA4V3XC0CNHD/relaunch-rerun-timing.json
Evidence: Commands, setup correction, evidence scope, and explicit live-acceptance limitation

Source: Commands, setup correction, evidence scope, and explicit live-acceptance limitation

# Relaunch safety test evidence

Target: `ea2e3e0969ba4b109a458bce471e13d1e2ee2e65`.
Baseline: `3c58ec8e0123b0047f9bf319e0edd5788eec988d`.

## Executed checks

- `env TMPDIR="$PWD/.test-phase-tmp" FM_TEST_EVIDENCE=1 bash bin/fm-test-run.sh --jobs 1 --json <evidence>/focused-timing.json tests/fm-backend-herdr.test.sh tests/fm-control-relaunch.test.sh tests/fm-control.test.sh tests/fm-crew-state.test.sh tests/fm-herdr-session-cleanup.test.sh tests/fm-agy-harness.test.sh`
- `env TMPDIR=/tmp FM_TEST_EVIDENCE=1 bash bin/fm-test-run.sh --jobs 1 --json <evidence>/relaunch-rerun-timing.json tests/fm-control-relaunch.test.sh`
- An instrumented temporary driver re-executed the existing `test_herdr_missing_registration_never_relaunches_a_surviving_original`, `test_herdr_relaunch_requires_real_stop_and_replacement_incarnation`, `test_herdr_relaunch_rechecks_the_shell_at_the_typing_boundary`, and `test_herdr_stop_postcondition_cannot_borrow_a_false_dead_read` functions.
  The driver preserved their assertions and logged actual Firstmate CLI output, fixture-owned PID/start values, independent original-PID re-reads, journals, delivery inboxes, and fake transport payloads.
  Its final output is `lifecycle-fixture-transcript.txt`; all four functions passed again.
- The baseline adapter was extracted with `git archive <baseline> bin` into a disposable directory inside the worktree.
  A deterministic registration/process counterfactual executed both baseline and target classifiers with the same supplied evidence and independently asserted expected results.
  `registration-before-after.txt` shows the baseline wrongly permitting recovery for missing registration plus live/foreign/unreadable process evidence, and the target preserving liveness or refusing.

## Setup correction

The first suite invocation placed temporary fixtures under the repository.
Five suites passed, but the relaunch suite stopped at its secondmate-home test because the product correctly forbids secondmate homes inside the Firstmate repository.
The unchanged relaunch suite was rerun using the toolchain's ordinary temporary location, and completed successfully including all new Herdr lifecycle fixtures.
This was a test-location error, not a production regression; both receipts are retained.
No source or permanent test changes were made.

## Acceptance limit

All liveness and lifecycle evidence here is portable fixture evidence, not real-harness acceptance.
The process fixtures are renamed Bash processes; Herdr transport and registration reads are faked.
The named live Claude/Pi Herdr lab acceptance did NOT run because the recorded helper prerequisite requires a literal live default session that was absent in the earlier refusal.
The author explicitly accepted proceeding without that acceptance and prohibited retrying provisioning, starting/reconfiguring the default session, or bypassing the helper/tripwire.
This turn did not retry that refusal or launch any real Herdr session or Claude/Pi runtime.
The accepted 0/8 actual Claude/Pi acceptance limitation remains unchanged.
No protected original worker was inspected, stopped, relaunched, or certified repaired.
There is no screenshot because no real agent TUI was launched under that restriction; the change is lifecycle/CLI safety rather than visual layout or copy placement.

Only targeted executable checks were run; no full repository suite, lint, formatting, static analysis, publication, PR, or CI action was performed.
Temporary drivers, the extracted baseline, and test residue inside the worktree were removed after collecting these receipts.
- Outcome: ⚠️ 1 warning across 1 run (14m3s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

🔧 **Rebase** - 2 issues found → auto-fixed ✅
  • ⚠️ docs/verification/runtime-backends.md - merge conflict rebasing onto origin/main
  • ⚠️ tests/fm-backend-herdr.test.sh - merge conflict rebasing onto origin/main

🔧 Fix applied.
✅ Re-checked - no issues remain.

⚠️ **Review** - medium risk

✅ No issues found.

⚠️ **Test** - 1 warning
  • ⚠️ live validation verdict: inconclusive (0 of 6 scenarios were driven live against the product); untested: Deliver an instruction to an unregistered Claude/Pi worker without falsely reporting it exited, Permit agent-free recovery only with verified shell-only evidence and refuse ambiguous process evidence, Refuse exit or relaunch success while the original PID/start incarnation survives, Complete relaunch only after the original stops and a recognized replacement process exists, Reject launch shell text when an agent appears after the initial shell-only check, Reproduce and verify the repair with actual Claude/Pi workers in a named isolated Herdr lab
  • Live validation: ⚠️ inconclusive - 0 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Deliver an instruction to an unregistered Claude/Pi worker without falsely reporting it exited ⏸️ untested no The prior payload did not establish a live result: it exercised real Firstmate entrypoints with fixture-owned renamed Bash processes and fake Herdr transport, not actual Claude/Pi workers. Its fixture…
Permit agent-free recovery only with verified shell-only evidence and refuse ambiguous process evidence ⏸️ untested no The prior payload did not establish a live result: executable classifier fixtures covered shell-only, foreign, unreadable, contradictory, malformed, and changing-subtree evidence, and crew-state and a…
Refuse exit or relaunch success while the original PID/start incarnation survives ⏸️ untested no The prior payload did not establish a live result: original survival was independently observed in the OS process table, but the worker processes and Herdr responses were fixtures. The fixture transcr…
Complete relaunch only after the original stops and a recognized replacement process exists ⏸️ untested no The prior payload did not establish a live result: control and standalone relaunch interfaces were exercised against fixture-owned processes and fake Herdr transport, not installed Claude/Pi runtimes.…
Reject launch shell text when an agent appears after the initial shell-only check ⏸️ untested no The prior payload did not establish a live result: the adversarial fixture created a real owned process during preparation, but its Herdr transport remained simulated. The late-process fixture transcr…
Reproduce and verify the repair with actual Claude/Pi workers in a named isolated Herdr lab ⏸️ untested no The recorded helper provisioning refusal requires a literal live default session that was absent. The explicit decision prohibits retrying provisioning, starting or reconfiguring default/shared Herdr,…
  • env TMPDIR="$PWD/.test-phase-tmp" FM_TEST_EVIDENCE=1 bash bin/fm-test-run.sh --jobs 1 --json ~/.no-mistakes/evidence/01M4CPXBSKQ9HYZA4V3XC0CNHD/focused-timing.json tests/fm-backend-herdr.test.sh tests/fm-control-relaunch.test.sh tests/fm-control.test.sh tests/fm-crew-state.test.sh tests/fm-herdr-session-cleanup.test.sh tests/fm-agy-harness.test.sh
  • env TMPDIR=/tmp FM_TEST_EVIDENCE=1 bash bin/fm-test-run.sh --jobs 1 --json ~/.no-mistakes/evidence/01M4CPXBSKQ9HYZA4V3XC0CNHD/relaunch-rerun-timing.json tests/fm-control-relaunch.test.sh — corrected the initial fixture-location error; the unchanged suite completed successfully.
  • Re-executed test_herdr_missing_registration_never_relaunches_a_surviving_original, test_herdr_relaunch_requires_real_stop_and_replacement_incarnation, test_herdr_relaunch_rechecks_the_shell_at_the_typing_boundary, and test_herdr_stop_postcondition_cannot_borrow_a_false_dead_read through a temporary instrumented driver, retaining CLI output, delivery records, PID/start evidence, journals, and fake transport payloads.
  • Extracted baseline bin/ with git archive 3c58ec8e0123b0047f9bf319e0edd5788eec988d bin and executed baseline/target registration-process counterfactuals with identical fixture inputs and independent expected-result assertions.
  • Checked available tools and RAM/load before sequential test work; reviewed the Herdr helper contract without retrying provisioning or starting sessions.
  • Removed temporary drivers, extracted baseline, and worktree test residue; confirmed unchanged HEAD and a clean working tree.
✅ **Document** - passed

✅ No issues found.

⚠️ **Lint** - 1 warning
  • ⚠️ linter found issues (exit code 1)

🔧 Fix applied.
1 warning still open:

  • ⚠️ linter found issues (exit code 1)
✅ **Push** - passed

✅ No issues found.

@kunchenguid

Copy link
Copy Markdown
Owner

Speaking as Kun's firstmate: thank you, @Diabl0570. I read head 2f04b0df against main 2ce57d00. That covers the bin/ changes (backends/herdr.sh, fm-control.sh, fm-spawn.sh, fm-agent-process-lib.sh, fm-crew-state.sh), the docs, and the test fixtures.

Security review before approving fork CI: no .github/workflows or CI-script edits, no credential handling, no network calls added. The committed CI logs contain only GitHub's own masked runner output (***). I approved this head's fork runs 37715604739 (CI) and 37715604734 (Require no-mistakes).

Blocking now (on you): remove the committed CI logs. The head adds 14 downloaded GitHub Actions logs at the repo root, about 4,750 of the 5,027 added lines: .ci-herdr.log, .ci-serial4.log, .ci-serial5.log, .ci-serial7.log, and .ci-runtime/*.log. They're run artifacts, not source, and can't land in the shared distro. Please drop them from the branch and re-raise through git push no-mistakes so the attestation binds the cleaned head.

What the real change does: on Herdr only, a herdr agent get → agent_not_found no longer reads as no-agent/dead by itself. It now has to be backed by OS process evidence: a recognized live harness process stays alive, a verified shell-only pane may be agent-free, and unreadable, foreign, or contradictory evidence refuses. fm-control.sh exit and relaunch now checkpoint the original PID/start incarnations and refuse success while one survives. fm-spawn.sh rechecks shell-only evidence before every relaunch shell write, and standalone --relaunch waits up to FM_CONTROL_LAUNCH_WAIT for a recognized replacement process.

Contract-class: new-default. Herdr is a selected backend, but for every Herdr home this replaces the specified classification on the default lifecycle path, where registration absence (agent_not_found, issue #4115) was death evidence, with a stricter process proof and new refusal paths. A safety motive doesn't make a replaced default path a restore. It won't auto-merge. Once it's otherwise ready (logs removed, attested, CI green), it goes to Kun for merge-or-leave. Your own risk note says the live Claude/Pi Herdr acceptance didn't run and the evidence is fixtures only. That gap will be part of what Kun weighs.

VISION.md, rule by rule

  • One captain, one interface: aligns. It stops false "stopped/relaunched" reports, which are a hidden failure.
  • Authority is explicit and never inferred: aligns. Uncertain evidence refuses rather than acting.
  • Scripts own the mechanics, agents own the judgment: aligns. Deterministic PID/start checks.
  • A restart is a non-event: aligns. The original incarnations are journaled in the relaunch checkpoint.
  • Delegation with a spine: aligns in intent. The refusal paths are stronger, but live verification is still missing.
  • The fleet outlives any vendor: cannot tell. The stricter proof is Herdr-only and its live acceptance on real Claude/Pi didn't run.
  • Scope: does not align as pushed, because of the committed CI logs. The code itself is command-layer.

Next step: on you. Remove the log files and re-raise. After that it waits on CI, then on Kun's decision.

…tor continuity/revalidation. Confirmed HEAD 40a5d1a and exact diff SHA256 8ee31a003fba5fcc6059df311791835b5b9895c81116efcaa037b71b41ab5f3a: nine test files, 105 insertions/29 deletions, no tracked production change. No additional edits were made. The repair supplies stable suite-owned process evidence, preserves cleanup ownership, and fixes the portable-PATH case without weakening production liveness/refusal checks or removing assertions. Reviewed all nine final retained receipts under .no-mistakes/ci-finish/receipts; each records exit=0, including fm-herdr-session-cleanup-real-process.log and fm-remote-secondmate-lifecycle-e2e-portable-path.log. These support the unchanged candidate as bounded fixture evidence, not published CI success. Locally ran bash -n on all nine changed files and git diff --check; both passed, and HEAD/diff identity remained exact. ci-second-timeout-handoff.md was not found in the worktree or the explicitly allowed evidence directory, so its contents could not be confirmed. The known Herdr helper/tripwire refusal remains unchanged; no native lifecycle actions were run. Isolated GitHub Herdr smoke, new-head validation, and all four still-red published checks remain for the outer pipeline. Retained the accepted 0/8 actual Claude/Pi live-acceptance limitation; no protected original worker is certified repaired. No pipeline control, commit, push, approval, skip, waiver, or merge was performed
@Diabl0570
Diabl0570 force-pushed the fm/fm-control-relaunch-false-success branch from 2f04b0d to 847f69f Compare October 8, 2026 06:24
@Diabl0570 Diabl0570 changed the title fix(herdr): prevent false-success worker relaunches fix: prevent false-success Herdr agent relaunches Oct 8, 2026
@kunchenguid

Copy link
Copy Markdown
Owner

Speaking as Kun's firstmate: thanks for cleaning this up, @Diabl0570. I re-read the thread and the new head 847f69f7 (base 3c58ec8e).

What changed since 2f04b0df: the committed CI logs are gone, which was the blocker last pass. I compared the bin/ delta of the old head against this one, and it's line-for-line identical, so the production change I reviewed before is unchanged. The new commits are doc wording, a lint note in tests/remote-herdr-fixture.sh, and a .gitignore block. No workflow edits, no secrets, no network. The attestation matches 847f69f7. I approved this head's fork runs 37737465177 (CI) plus 37737465249 and 37737522125 (Require no-mistakes).

Blocking now (on you): merge conflict. The PR is CONFLICTING with main b062eb94 in tests/fm-control-herdr-smoke.test.sh, after #6818 ("accept safe exit refusals and clean lab once") landed. This is a new-default change, so I won't rebase it on your behalf. Please rebase onto current main and re-raise through git push no-mistakes so the attestation binds the rebased head.

Small ask while you're there: please drop the 16-line .gitignore block. It lists your local .ci-*.log / .ci-runtime/*.log transcript paths, and the shared distro shouldn't carry one contributor's scratch paths. A global or .git/info/exclude entry on your side does the same job.

Contract-class: new-default (unchanged). For every Herdr home, agent_not_found stops counting as death evidence on its own and needs OS process proof. exit/relaunch get new refusal paths. That replaces the specified classification on the default lifecycle path, so it won't auto-merge. Once it's otherwise ready, Kun decides.

VISION.md, rule by rule

  • One captain, one interface: aligns. It stops false "stopped/relaunched" reports.
  • Authority is explicit and never inferred: aligns. Uncertain evidence refuses.
  • Scripts own the mechanics, agents own the judgment: aligns. The PID/start checks are deterministic.
  • A restart is a non-event: aligns. The original incarnations are journaled in the relaunch checkpoint.
  • Delegation with a spine: aligns in intent. Live Claude/Pi Herdr acceptance is still fixture-only by your own note.
  • The fleet outlives any vendor: cannot tell, for the same live-verification gap.
  • Scope: aligns now that the logs are gone. The .gitignore scratch paths are the only leftover noise.

Next step: on you. Rebase, re-raise and drop the .gitignore block. After that it waits on CI, then on Kun's merge-or-leave decision.

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