Skip to content

fix: allow missing tmux endpoint recovery despite unrelated servers - #46

Merged
MrGTV-love merged 5 commits into
mainfrom
fm/fm-control-reclaim-missing-endpoint-s2
Oct 8, 2026
Merged

MrGTV-love merged 5 commits into
mainfrom
fm/fm-control-reclaim-missing-endpoint-s2

Conversation

@MrGTV-love

Copy link
Copy Markdown
Owner

Intent

Vernant lane workers whose recorded endpoint has disappeared cannot be restarted through the supported control path, which blocks S5 continuations in lanes d2 and d7 (Vernant GRE-1774).
Observed in lane d2 (key main719-hosted-exited-owner-proof): fm-control.sh <task> relaunch --harness claude --reconcile-only refused before launch with "proven exited owner missing", because the process table does not show zero current-user tmux processes and another socket may hold the endpoint.
Any live tmux server for the same user (there are always several on this machine) therefore makes every missing-endpoint relaunch impossible, even when the recorded worker is gone.
The need is a supported way for relaunch to prove that the recorded task's own endpoint and owner are gone, scoped to that recorded endpoint, so a missing-endpoint task can be restored without a forced stop, a socket sweep or discarding work.

What Changed

  • Replace the machine-wide no-tmux-process requirement with two recorded-session inventory reads bracketing a worktree-holder scan, allowing unrelated tmux servers while refusing live agents or inconclusive evidence.
  • Pass the recorded worktree through exit, reconciliation-only relaunch, and direct spawn recovery so they share the endpoint-scoped proof; retain configured-Herdr-only replacement without recreating tmux endpoints.
  • Update recovery documentation and coverage for escaped and symlinked worktree paths, live or unattributed holders, changing inventory reads, and real-lsof recovery from worktree roots and descendants.

Risk Assessment

✅ Low: The change is bounded to the shared missing-endpoint proof and its existing callers, preserves fail-closed handling of inconclusive evidence, and contains no substantiated material defects or unnecessary scope additions.

Testing

Focused regressions passed after correcting the empty-scan fixture, and isolated live checks demonstrated worktree-local recovery, real Claude process restoration, preserved work and holds, and conservative ownership and inventory guards. CLI, state, and rendered-terminal evidence was captured, and all owned labs were removed. Authenticated prompt handling was not exercised; no full suite, linters, or static analysis ran.

  • Live validation: ✅ go - 8 of 9 scenarios driven live against the product
Scenario Result Live Evidence
Inspect a missing recorded endpoint from its worktree despite unrelated tmux servers and idle shells ✅ pass live round2-live-absence-shapes.log
Reconcile-only relaunch from a descendant restores a real Claude process without discarding work or its hold ✅ pass live round2-live-reclaim-unicode.log; round2-preserved-recovery-state.json
Direct replacement from the worktree root restores a second endpoint without disturbing the first ✅ pass live round2-live-direct-replacement.log
Attempt recovery while a real Claude owner survives on another tmux socket ✅ pass live round2-real-other-tmux-owner.log
Attempt recovery with an unattributed holder under a Unicode and literal-backslash worktree path ✅ pass live round2-real-unknown-holder.log
Inspect an answering recorded window without claiming that its endpoint is gone ✅ pass live round2-live-answering-window.log
Attempt replacement when the recorded window appears between the two inventory reads ✅ pass live round2-live-inventory-race.log
Attempt to replace a proven-gone tmux endpoint when the configured backend is still tmux ✅ pass live round2-live-absence-shapes.log
Have the restored Claude owner interpret reconciliation instructions through an authenticated session ⏸️ untested no The normal Claude login exists, but the workspace-isolated HOME reported no login and the actual replacement reached Select login method. Normal and isolated auth checks and the real replacement were…
Evidence: Live absence shapes and configured-backend refusal

Source: Live absence shapes and configured-backend refusal

$ tasks-axi add absent 'Missing endpoint task' --kind ship --file ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/home/data/backlog.md
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
ok: added absent (ship) -> Queued
task:
  id: absent
  title: Missing endpoint task
  state: queued
  blocked: no
  blocked_by: none
  held: no
  hold_reason: "-"
  hold_kind: "-"
  hold_until: "-"
  kind: ship
  repo: "-"
  priority: "-"
  created: 2026-10-08
  closed: "-"
  deps: none
  links: none
  body: ""
help[2]:
  - Run `tasks-axi start absent --file=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/home/data/backlog.md` to move it to in flight
  - Run `tasks-axi block absent --by <other> --file=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/home/data/backlog.md` to record a dependency
exit=0

$ tasks-axi start absent --file ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/home/data/backlog.md
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
ok: start absent -> In flight
help[1]:
  - Run `tasks-axi done absent --pr <url> --file=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/home/data/backlog.md` when it ships
exit=0

$ tmux -S ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.b new-window -t fm-lab-unrelated -n idle-shell -c '~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane/deep' '/bin/bash --noprofile --norc'
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
exit=0

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-control.sh absent exit
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane
endpoint-gone absent harness=claude backend=tmux endpoint=recorded:fm-absent worktree=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane
exit=0

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-control.sh absent exit
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane/deep
endpoint-gone absent harness=claude backend=tmux endpoint=recorded:fm-absent worktree=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane
exit=0

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-control.sh absent exit
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane/deep
endpoint-gone absent harness=claude backend=tmux endpoint=absent-session:fm-absent worktree=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane
exit=0

$ tmux -S ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.a kill-server
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
exit=0

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-control.sh absent exit
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane
endpoint-gone absent harness=claude backend=tmux endpoint=recorded:fm-absent worktree=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane
exit=0

$ tmux -S ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.a new-session -d -s recorded -n scratch -x 120 -y 40 -c ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7 '/bin/bash --noprofile --norc'
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
exit=0

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-spawn.sh absent --relaunch --harness claude --reconcile-only
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane
error: configured backend 'tmux' is not herdr; refusing to replace task absent's proven-gone tmux endpoint
exit=1

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-spawn.sh absent --relaunch --harness claude --reconcile-only
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane/deep
error: configured backend 'tmux' is not herdr; refusing to replace task absent's proven-gone tmux endpoint
exit=1
Evidence: Successful descendant-directory reconciliation-only relaunch

Source: Successful descendant-directory reconciliation-only relaunch

$ bin/fm-control.sh recover relaunch --harness claude --reconcile-only --note "Restore instruction owner only"
warning: ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/home/data/recover/launch-brief.md records no ship branch; defaulting to legacy branch fm/recover
warning: ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/home/data/recover/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 recover harness=claude from=claude model=default effort=default backend=herdr endpoint=fm-lab-r2-19846:w1:p3 worktree=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café

exit=0
Evidence: Preserved recovery metadata, HEAD, branch, work, status, and hold

Source: Preserved recovery metadata, HEAD, branch, work, status, and hold

{
  "meta": "window=fm-lab-r2-19846:w1:p3\nendpoint_task_id=recover\nworktree=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-caf\u00e9\nproject=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/project\nharness=claude\nkind=ship\nrecovery=reconcile-only\nmode=no-mistakes\nyolo=off\nbranch=fm/recover\ntasktmp=/tmp/fm-recover\nmodel=default\neffort=default\nbusy_gen=g1791443443.98513.2666\nspawn_gen=s1791443444.79989.13654\nbackend=herdr\nherdr_session=fm-lab-r2-19846\nherdr_workspace_id=w1\nherdr_tab_id=w1:t3\nherdr_pane_id=w1:p3\ncontrol_relaunch_tx=70906.20261008T071032Z.12255\n",
  "head_before": "1719ac3ea588cd3263e4c9daab66c08f5fe75721",
  "head_after": "1719ac3ea588cd3263e4c9daab66c08f5fe75721",
  "branch_after": "task-recover",
  "dirty_file": "recover uncommitted work must survive\n",
  "status": "working: preserve this recovery status history\n",
  "backlog": "$ tasks-axi show recover --file ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/home/data/backlog.md\ncwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7\ntask:\n  id: recover\n  title: Recover real Claude instruction owner\n  state: in_flight\n  blocked: no\n  blocked_by: none\n  held: yes\n  hold_reason: Wait for explicit continuation\n  hold_kind: captain\n  hold_until: \"-\"\n  kind: ship\n  repo: \"-\"\n  priority: \"-\"\n  created: 2026-10-08\n  closed: \"-\"\n  deps: none\n  links: none\n  body: \"\"\nexit=0\n"
}
Evidence: Successful root-directory direct replacement

Source: Successful root-directory direct replacement

$ bin/fm-spawn.sh direct --relaunch --harness claude --reconcile-only
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-direct-café
warning: ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/home/data/direct/launch-brief.md records no ship branch; defaulting to legacy branch fm/direct
warning: ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/home/data/direct/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
spawned direct harness=claude kind=ship mode=no-mistakes yolo=off window=fm-lab-r2-19846:w1:p4 worktree=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-direct-café

exit=0
Published task record:
window=fm-lab-r2-19846:w1:p4
endpoint_task_id=direct
worktree=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-direct-café
project=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/project
harness=claude
kind=ship
recovery=reconcile-only
mode=no-mistakes
yolo=off
branch=fm/direct
tasktmp=/tmp/fm-direct
model=default
effort=default
busy_gen=g1791443832.28784.23880
spawn_gen=s1791443832.19780.8194
backend=herdr
herdr_session=fm-lab-r2-19846
herdr_workspace_id=w1
herdr_tab_id=w1:t4
herdr_pane_id=w1:p4

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-herdr-lab.sh run fm-lab-r2-19846 agent list
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
{"id":"cli:agent:list","result":{"agents":[{"agent":"claude","agent_status":"idle","cwd":"~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café","focused":false,"foreground_cwd":"~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café","pane_id":"w1:p3","revision":0,"state_change_seq":3,"tab_id":"w1:t3","terminal_id":"term_65d4eedfda5e53","workspace_id":"w1"},{"agent":"claude","agent_status":"unknown","cwd":"~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-direct-café","focused":false,"foreground_cwd":"~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-direct-café","pane_id":"w1:p4","revision":0,"state_change_seq":0,"tab_id":"w1:t4","terminal_id":"term_65d4f0539ca784","workspace_id":"w1"}],"type":"agent_list"}}
exit=0

First recovered endpoint unchanged; direct replacement preserved dirty file.
Evidence: Real Claude owner on another tmux socket blocks every entrypoint

Source: Real Claude owner on another tmux socket blocks every entrypoint

Owned other-socket real Claude pane: 2.1.294 0 120x40
$ tmux -S ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.b capture-pane -p -t fm-lab-unrelated:actual-claude
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
Welcome to Claude Code v2.1.294
..........................................................

     *                                       █████▓▓░
                                 *         ███▓░     ░░
            ░░░░░░                        ███▓░
    ░░░   ░░░░░░░░░░                      ███▓░
   ░░░░░░░░░░░░░░░░░░░    *                ██▓░░      ▓
                                             ░▓▓███▓▓░
 *                                 ░░░░
                                 ░░░░░░░░
                               ░░░░░░░░░░░░░░░░
       █████████                                        *
      ██▄█████▄██                        *
       █████████      *
.......█ █   █ █..........................................

 Let's get started.

 Choose the text style that looks best with your terminal
 To change this later, run /theme

     Auto (match terminal)
 ❯ ✔ Dark mode
     Light mode
     Dark mode (colorblind-friendly)
     Light mode (colorblind-friendly)
     Dark mode (ANSI colors only)
     Light mode (ANSI colors only)

 ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
  1  function greet() {
  2 -  console.log("Hello, World!");
  2 +  console.log("Hello, Claude!");
  3  }
 ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
  Syntax theme: Monokai Extended (ctrl+t to disable)



exit=0

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-control.sh owner exit
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-owner-café/deep
error: task owner's endpoint recorded:fm-owner reads 'missing', but an agent process still holds the recorded worktree, so its endpoint may live on a server this process does not address; exit will not claim an agent stopped at an address it cannot trust, nor send lifecycle input to one
exit=1

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-control.sh owner relaunch --harness claude --reconcile-only --note 'Never replace other-socket owner'
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-owner-café/deep
error: reconciliation-only recovery requires a proven exited owner (endpoint reads unproven	an agent process still holds the recorded worktree, so its endpoint may live on a server this process does not address)
exit=1

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-spawn.sh owner --relaunch --harness claude --reconcile-only
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-owner-café/deep
error: task owner's recorded endpoint recorded:fm-owner reads 'missing', but an agent process still holds the recorded worktree, so its endpoint may live on a server this process does not address. An endpoint that cannot be proven absent may still hold a live agent on this task's worktree; refusing rather than launching a second agent into it
exit=1

Original task metadata unchanged.
Evidence: Unattributed holder under an escaped worktree path blocks recovery

Source: Unattributed holder under an escaped worktree path blocks recovery

Real unattributed holder: python3 PID 2324, CWD ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane/deep
$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-control.sh unknown exit
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane/deep
error: task unknown's endpoint recorded:fm-unknown reads 'missing', but the processes holding the recorded worktree could not be read; exit will not claim an agent stopped at an address it cannot trust, nor send lifecycle input to one
exit=1

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-control.sh unknown relaunch --harness claude --reconcile-only --note 'Never replace unresolved holder'
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane/deep
error: reconciliation-only recovery requires a proven exited owner (endpoint reads unproven	the processes holding the recorded worktree could not be read)
exit=1

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-spawn.sh unknown --relaunch --harness claude --reconcile-only
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane/deep
error: task unknown's recorded endpoint recorded:fm-unknown reads 'missing', but the processes holding the recorded worktree could not be read. An endpoint that cannot be proven absent may still hold a live agent on this task's worktree; refusing rather than launching a second agent into it
exit=1

Original metadata unchanged; holder terminated after checks.
Evidence: Answering endpoint is not classified gone

Source: Answering endpoint is not classified gone

$ tmux -S ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.a new-window -t recorded -n fm-absent -c '~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane/deep' '/bin/bash --noprofile --norc'
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
exit=0

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-control.sh absent exit
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane/deep
already-stopped absent harness=claude backend=tmux endpoint=recorded:fm-absent worktree=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane
exit=0

$ bash -c 'source bin/fm-control-lib.sh; fm_control_endpoint_absence_verdict tmux recorded:fm-absent "$1"' bash '~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane'
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
unproven	backend 'tmux' could not be loaded to prove anything about that endpointbin/fm-control-lib.sh: line 434: fm_backend_source: command not found
exit=0

$ bash -c 'source bin/fm-backend.sh; source bin/fm-control-lib.sh; fm_control_endpoint_absence_verdict tmux recorded:fm-absent "$1"' bash '~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane'
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
unproven	the recorded tmux window answers on the addressed serverexit=0
Evidence: Actual window appearing between inventory reads prevents replacement

Source: Actual window appearing between inventory reads prevents replacement

Timing hook ran the real /usr/sbin/lsof and emitted its output unchanged; it then created the actual recorded window before the second inventory read.
$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-spawn.sh absent --relaunch --harness claude --reconcile-only
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café\lane/deep
error: task absent's recorded endpoint recorded:fm-absent reads 'missing', but the recorded tmux window answers on the addressed server. An endpoint that cannot be proven absent may still hold a live agent on this task's worktree; refusing rather than launching a second agent into it
exit=1

$ tmux -S ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.a list-windows -t =recorded -F '#{window_name}'
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
scratch
fm-absent
exit=0

Metadata unchanged, no replacement launched.
Evidence: Rendered actual replacement terminal showing the isolated login boundary

Source: Rendered actual replacement terminal showing the isolated login boundary

<!doctype html><meta charset="utf-8"><title>Real Claude replacement terminal</title><style>body{background:#111;color:#eee;padding:24px}pre{font:14px/1.4 ui-monospace,monospace;white-space:pre-wrap}</style><h1>Real replacement terminal — isolated login boundary</h1><pre>$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-herdr-lab.sh run fm-lab-r2-19846 pane read w1:p3 --source recent-unwrapped --lines 100
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
charlesabrooker@Mac-Studio wt-café % cd -- &#x27;~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.live-round2/wt-café&#x27;
charlesabrooker@Mac-Studio wt-café % export GOTMPDIR=/tmp/fm-recover/gotmp
charlesabrooker@Mac-Studio wt-café % export COMPACT_ADVISER_DISABLE=1
charlesabrooker@Mac-Studio wt-café % export FM_TASK_ID=recover
charlesabrooker@Mac-Studio wt-café % . &#x27;/tmp/fm-recover+2a0789364a691bc0919970569a16263c7dafe4468ca17a4c9b1f7bbf0b934f05/launch.s1791443444.79989.13654.sh&#x27;
Welcome to Claude Code v2.1.294
..........................................................

     *                                       █████▓▓░
                                 *         ███▓░     ░░
            ░░░░░░                        ███▓░
    ░░░   ░░░░░░░░░░                      ███▓░
   ░░░░░░░░░░░░░░░░░░░    *                ██▓░░      ▓
                                             ░▓▓███▓▓░
 *                                 ░░░░
                                 ░░░░░░░░
                               ░░░░░░░░░░░░░░░░
       █████████                                        *
      ██▄█████▄██                        *
       █████████      *
.......█ █   █ █..........................................

 Claude Code can be used with your Claude subscription or billed based on API usage through your Console account.

 Select login method:

 ❯ 1. Claude account with subscription · Pro, Max, Team, or Enterprise
   2. Anthropic Console account · API usage billing
   3. 3rd-party platform · Amazon Bedrock, Microsoft Foundry, Google Vertex AIexit=0
</pre>
Evidence: Authentication boundary and unexercised prompt handling

Source: Authentication boundary and unexercised prompt handling

Normal `claude auth status`: loggedIn=true, authMethod=claude.ai.
With the workspace-isolated HOME used by the real relaunch: loggedIn=false, authMethod=none.
The actual replacement launched, was detected as Claude by Herdr, and after theme selection displayed Select login method. No sign-in was attempted, no production credentials were copied, and no operator trust store was modified. Authenticated prompt interpretation was not exercised.
Evidence: Owned-runtime teardown and unchanged-default-session tripwire

Source: Owned-runtime teardown and unchanged-default-session tripwire

$ tmux -S ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.a kill-server
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
exit=0

$ tmux -S ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/.b kill-server
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
exit=0

$ ~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7/bin/fm-herdr-lab.sh teardown fm-lab-r2-19846
cwd=~/.no-mistakes/worktrees/32d18ed9638d/01M4D1RDBMZB23Z36H5S5Y4VK7
exit=0

Named lab teardown passed its unchanged-default-session tripwire.
Remaining fixture processes: []

Read-only fixture hook directories required chmod u+w before removal. All disposable worktree homes, sockets, tool routers, generated Herdr release-note cache, and focused driver were then removed; explicit absence checks succeeded. The only intentional test-source edit corrects the empty-lsof fixture.
- Outcome: 🔧 2 issues found → auto-fixed ✅ across 2 runs (49m56s)

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-lib.sh:338 - The holder scan compares escaped lsof NAME fields against raw worktree paths. For a live worker in ~/projets/café/task, LC_ALL=C lsof -F pn emits the UTF-8 bytes as caf\xc3\xa9; literal backslashes are escaped too. Apple's field serializer calls printname, which uses safestrprt (https://github.com/apple-oss-distributions/lsof/blob/main/lsof/proc.c#L1373-L1376; https://github.com/apple-oss-distributions/lsof/blob/main/lsof/print.c#L2001-L2024; https://github.com/apple-oss-distributions/lsof/blob/main/lsof/misc.c#L1310-L1478). The absolute-path check succeeds, but neither raw root matches, so the live worker is omitted and the helper returns none. If its endpoint survives on another socket, both addressed-server reads can omit it and line 445 returns gone, permitting a duplicate owner. The uncertified Round 2 fix rejects error-valued NAME records but leaves this representation sibling unresolved; the selected normalization fix is absent from this target. Normalize NAME fields and both logical/physical roots to one representation at the shared holder boundary, retaining uncertainty when comparison cannot be established. Affected consumers: bin/fm-control.sh:661 (exit), bin/fm-control.sh:1141 (reconciliation admission), and bin/fm-spawn.sh:1918 (replacement). Update the raw-path fixtures at tests/fm-control-relaunch.test.sh:92 and tests/fm-control.test.sh:207 to exercise escaped paths, and the affected guarantee at docs/agent-control.md:136–141.
  • ⚠️ bin/fm-control-lib.sh:321 - Recovery invoked from the recorded worktree or a descendant includes the lsof probe itself as a holder. Darwin enumerates all PIDs and applies explicit selection/exclusion rules without automatically excluding lsof (https://github.com/apple-oss-distributions/lsof/blob/main/lsof/dialects/darwin/libproc/dproc.c#L330-L518; https://github.com/apple-oss-distributions/lsof/blob/main/lsof/proc.c#L665-L820). Here the probe inherits that CWD, and the command substitution finishes only after it exits. Its subsequent identity read at bin/fm-control-lib.sh:349 therefore fails and returns unknown, refusing recovery even when the previous owner and endpoint are genuinely gone. The uncertified Round 2 fix introduced this deterministic refusal by making failed identity reads unconditional uncertainty; the subsequently selected probe-exclusion fix is absent from this target. Run the scan from a worktree-neutral directory or explicitly exclude the scanner's PID without weakening refusal for actual unreadable holders. The same failure reaches bin/fm-control.sh:661 (exit), bin/fm-control.sh:1141 (reconciliation admission), and bin/fm-spawn.sh:1918 (replacement). The canned scans at tests/fm-control-relaunch.test.sh:84–96 and tests/fm-control.test.sh:203–208 omit the probe and consequently hide this refusal.

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

🔧 **Test** - 2 issues found → auto-fixed ✅
  • 🚨 bin/fm-control-lib.sh:344 - Live recovery from the recorded worktree or a descendant still manufactures an unreadable holder. The scan excludes the exec'd lsof PID, but includes a transient Bash command-substitution process sharing the caller's CWD. That process exits before the subsequent ps identity read at line 372, causing unknown. With no worker holding the disposable task, exit, reconciliation-only relaunch, and direct replacement refused; the same endpoint was proven gone when invoked from a neutral directory. This leaves the selected probe-exclusion fix incomplete. Run the scan from a worktree-neutral directory without weakening refusal for genuine unreadable holders, and cover this with a real-lsof regression rather than only the canned scan fixture.
  • 🚨 live validation verdict: no-go (8 of 9 scenarios were driven live against the product); failed: Restore an exited instruction owner from inside its recorded worktree without the probe blocking recovery
  • Live validation: ❌ no-go - 8 of 9 scenarios driven live against the product
Scenario Result Live Evidence
Prove a missing recorded window gone while an unrelated tmux server remains live ✅ pass live live-recovery-and-backend-policy.log: missing-window
Prove an absent recorded session gone without requiring all user tmux servers to stop ✅ pass live live-recovery-and-backend-policy.log: missing-session
Prove a missing addressed server gone while another private server survives ✅ pass live live-recovery-and-backend-policy.log: missing-server
Restore an exited instruction owner from inside its recorded worktree without the probe blocking recovery ❌ fail live live-recovery-and-backend-policy.log, holder-refusal-diagnosis.log, and transient-probe-identification.json
Refuse replacement while a real worker survives on another socket in an escaped-path worktree ✅ pass live live-owner-guards.log: real-codex-owner
Treat readable but unattributed ownership as uncertainty rather than absence ✅ pass live live-owner-guards.log: unattributed-node-holder
Allow absence proof when only an idle shell holds the recorded worktree ✅ pass live live-owner-guards.log: idle-shell-holder
Refuse to recreate a proven-gone tmux endpoint when the home still selects tmux ✅ pass live live-recovery-and-backend-policy.log: backend-policy
Complete an authenticated Claude replacement on Herdr while preserving work and reconciliation-only restrictions ⏸️ untested no The ordinary machine login was confirmed available. Attempts to retain isolation through workspace-local CLAUDE_CONFIG_DIR and workspace-local HOME both returned loggedIn=false. Using the ordinary aut…
  • Ran existing targeted cases test_tmux_gone_endpoint_is_proven_despite_unrelated_servers, test_tmux_refuses_while_the_recorded_endpoint_may_be_live, test_tmux_unreadable_evidence_refuses, and test_tmux_reclaim_refuses_other_configured_backends through a temporary Bash runner; all passed.
  • Ran python3 .live-validation/drive.py against a marked disposable FM_HOME, an independent git project/worktree, and private tmux sockets $PWD/.a and $PWD/.b; corrected fixture setup issues before completing the ownership checks.
  • Drove bin/fm-control.sh proof exit with missing-window, missing-session, and missing-server endpoints while another private tmux server remained live.
  • Drove bin/fm-control.sh proof relaunch --harness claude --reconcile-only --note &#39;Restore only to reconcile instructions&#39; from the recorded worktree's descendant; it refused before launch.
  • Drove bin/fm-spawn.sh proof --relaunch --harness claude --reconcile-only with the configured backend set to tmux; it refused recreation after proving absence.
  • Executed exit, reconciliation-only relaunch, and direct replacement against a real Codex process and an unattributed Node process holding a descendant of a worktree containing both café and a literal backslash; all refused without changing metadata or instructions.
  • Ran the idle-shell holder scenario through bin/fm-control.sh proof exit; it reported endpoint-gone.
  • Compared the base and target fm_control_endpoint_absence_verdict implementations against real tmux/lsof state: base returned unproven because tmux processes existed; target returned gone from a neutral directory.
  • Diagnosed the failed scan with Bash tracing and real lsof -F pcn output; observed a transient Bash holder whose subsequent identity read failed.
  • Checked ordinary Claude authentication and attempted isolation with workspace-local CLAUDE_CONFIG_DIR and HOME; the ordinary login was available, but both isolated stores were unauthenticated.
  • Prepared and retired a named Herdr lab through bin/fm-herdr-lab.sh; stopped only owned tmux servers and harness descendants, confirmed no fixture CWD holders remained, and removed disposable workspace fixtures.

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

  • Live validation: ✅ go - 8 of 9 scenarios driven live against the product
Scenario Result Live Evidence
Inspect a missing recorded endpoint from its worktree despite unrelated tmux servers and idle shells ✅ pass live round2-live-absence-shapes.log
Reconcile-only relaunch from a descendant restores a real Claude process without discarding work or its hold ✅ pass live round2-live-reclaim-unicode.log; round2-preserved-recovery-state.json
Direct replacement from the worktree root restores a second endpoint without disturbing the first ✅ pass live round2-live-direct-replacement.log
Attempt recovery while a real Claude owner survives on another tmux socket ✅ pass live round2-real-other-tmux-owner.log
Attempt recovery with an unattributed holder under a Unicode and literal-backslash worktree path ✅ pass live round2-real-unknown-holder.log
Inspect an answering recorded window without claiming that its endpoint is gone ✅ pass live round2-live-answering-window.log
Attempt replacement when the recorded window appears between the two inventory reads ✅ pass live round2-live-inventory-race.log
Attempt to replace a proven-gone tmux endpoint when the configured backend is still tmux ✅ pass live round2-live-absence-shapes.log
Have the restored Claude owner interpret reconciliation instructions through an authenticated session ⏸️ untested no The normal Claude login exists, but the workspace-isolated HOME reported no login and the actual replacement reached Select login method. Normal and isolated auth checks and the real replacement were…
  • bash tests/.phase-recovery-regression.sh: temporary driver selecting only the scoped-absence, real-lsof worktree-local recovery, live-owner, unreadable-evidence, sequential-reclaim, and backend-policy regressions. An initial bounded attempt timed out; the completed run exposed the empty-scan fixture error. After correcting that fixture, the affected and remaining selected cases passed.
  • bin/fm-control.sh absent exit from the recorded worktree and its descendant, using real tmux and lsof, with missing-window, missing-session, and stopped-addressed-server configurations while another private tmux server remained running.
  • bin/fm-control.sh recover relaunch --harness claude --reconcile-only --note &#39;Restore instruction owner only&#39; from a descendant directory; inspected the published record, actual Herdr agent, terminal, HEAD, branch, dirty file, status history, and retained backlog hold.
  • bin/fm-spawn.sh direct --relaunch --harness claude --reconcile-only from the recorded worktree root; inspected the real replacement and verified that the first recovered endpoint and uncommitted work remained unchanged.
  • Drove exit, reconciliation-only relaunch, and direct replacement against a real Claude process on another private tmux socket and against a real unattributed Python holder; verified refusal and unchanged task metadata.
  • Inspected an answering tmux window through fm-control.sh exit and the executable absence-verdict interface; it remained already-stopped/unproven, never gone.
  • Ran direct replacement with an unmodified real-lsof scan followed by creation of the actual recorded tmux window before the second inventory read; replacement refused.
  • Verified configured-tmux replacement refusal from both the worktree root and descendant.
  • Used bin/fm-herdr-lab.sh preparation, provisioning, run, and teardown on named session fm-lab-r2-19846; stopped only owned tmux servers, confirmed the unchanged-default-session tripwire, and removed disposable workspace resources.
  • Checked normal and isolated claude auth status, inspected the replacement login screen without signing in, and saved CLI transcripts, persisted-state evidence, and a rendered terminal HTML artifact.
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

A missing tmux endpoint could never be proven gone while any tmux process of the
same user existed, so relaunch --reconcile-only refused with "proven exited owner
missing".
The proof now reads the recorded session on the addressed server twice, and scans
for a live agent holding the recorded worktree between the reads.
It refuses while the endpoint may be live or any evidence is unreadable.
It never tears down, forces or discards, and it sweeps no sockets.
@MrGTV-love
MrGTV-love merged commit 518d93e into main Oct 8, 2026
21 checks passed
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