Skip to content

fix(bin): settle cmux's stale post-create workspace snapshot - #5124

Closed
nickxyris wants to merge 9 commits into
kunchenguid:mainfrom
Xyritics-New:fm/fm-cmux-resolve
Closed

nickxyris wants to merge 9 commits into
kunchenguid:mainfrom
Xyritics-New:fm/fm-cmux-resolve

Conversation

@nickxyris

Copy link
Copy Markdown

Intent

Launching a worker through the cmux backend fails every time, so nothing can be dispatched on
cmux in this home. Fix it, and get the fix reviewed and merged before anything else runs.

The failure, reproduced four times from bin/fm-spawn.sh:

error: could not resolve a cmux workspace id for
'fm-firstmate-e2cba94a-wf-wfsmoke-orient' after creation

It was traced to bin/backends/cmux.sh, fm_backend_cmux_create_task. That function makes
three cmux calls in order: a duplicate-check workspace list, then new-workspace, then a
second workspace list to resolve the new workspace's id. The third call is served a stale
snapshot that does not yet contain the workspace just created, so the function aborts.
Reproduced outside firstmate:

query -> EMPTY (the duplicate check)
create -> OK
query -> EMPTY (stale; this is the read that aborts the spawn)
sleep 1; query -> 7E517926-4039-48D3-BAA5-7EFF5B2ECE73 (correct)

Dropping the leading duplicate-check query makes the immediate post-create resolve return the
right id, which is why the same two calls pass in a standalone test and fail inside the adapter.

Two knock-on effects were observed and should not be made worse. Each failed attempt left an
orphan cmux workspace carrying the crewmate's title, and the next attempt's duplicate check then
refused with already exists. An earlier interrupted spawn had left such a workspace behind and
a later agent session ended up running inside it, so the duplicate check named a workspace that
was in fact a live session.

Boundary stated: fix the cmux launch fault. Nothing else about cmux is being asked for.

What Changed

  • fm_backend_cmux_create_task now resolves a freshly created workspace's id through a new fm_backend_cmux_workspace_id_settled helper, which re-reads workspace list over a bounded retry window (FM_BACKEND_CMUX_SETTLE_TRIES, default 40; FM_BACKEND_CMUX_SETTLE_DELAY, default 0.25s, clamped by fm_backend_cmux_settle_tries) instead of trusting a single post-create read that cmux can serve from a snapshot predating the create. An exhausted bound keeps the original loud refusal, now naming the attempt count it spent; the pre-create duplicate check and the un-retried list-panes surface read are unchanged.
  • Added two portable regressions in tests/fm-backend-cmux.test.sh driving the fake CLI through a stale post-create list (asserting the retry resolves and that no second workspace is created) and through a never-resolving list (asserting the refusal and the retry bound), plus a live guard tests/fm-cmux-workspace-settle-live-e2e.test.sh that runs real create_task over the duplicate-check-then-create sequence, gated via fm_live_gate/FM_CMUX_WORKSPACE_SETTLE_LIVE and closing only the fm-test- workspaces it creates; the new live test is registered in bin/fm-test-run.sh's live-e2e family.
  • Documented the non-read-your-writes behavior in docs/cmux-backend.md as adapter finding feat: add scout task lifecycle #7 and in docs/verification/runtime-backends.md with the dated cmux 0.64.25 / macOS aarch64 evidence, the observed query/create/query trace, and the command that refreshes the entry.

Risk Assessment

✅ Low: The bounded lookup retry addresses the reported stale-read sequence while preserving duplicate refusal, single creation, and existing identity checks; no new material issues were substantiated.

Testing

Drove the cmux launch path against the real cmux 0.64.25 app on this host. The reported fault reproduced 4/4 times on the base-commit adapter with the intent's exact error message and left the described orphan workspace each time; the fixed adapter passed the identical sequence 4/4, and the repo's new default-on live guard passed all five rounds through bin/fm-test-run.sh. The end-user entrypoint bin/fm-spawn.sh --backend cmux launched a worker in an isolated firstmate home, its workspace was live in the cmux app under its home-scoped title, its launch output was capturable from the surface, and bin/fm-teardown.sh removed it cleanly. Adversarially, reducing the settle window to one attempt reproduced the original failure at the real entrypoint with the bounded, loud refusal preserved, and the duplicate check still refused a repeat launch of a live label. The portable regression added in this change was exercised only against the suite's fake CLI — it fails on the pre-fix adapter and passes on the fixed one there, but that is not a drive of the real cmux app, so it is reported as untested rather than a live pass. No visual artifact is attached because the change alters a shell adapter's CLI call sequence rather than any rendered surface; the reviewer-visible surfaces here are the fm-spawn transcript and cmux's own workspace listing, both captured as text, and a full-screen macOS capture would have published unrelated operator screen content. Every workspace created during testing was closed through tests/cmux-test-safety.sh's guarded close and the app ended in exactly its starting state.

  • Live validation: ✅ go - 6 of 7 scenarios driven live against the product
Scenario Result Live Evidence
An operator launches a worker on cmux with bin/fm-spawn.sh and the worker's workspace comes up live ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/03-fm-spawn-cmux-live.txt - spawn printed spawned ... window=<ws>:<surface>, the workspace appears in the live cmux list under…
The reported failure genuinely reproduces before the fix: the pre-fix adapter refuses to resolve the workspace it just created ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/01-prefix-adapter-repro.txt - base-commit adapter, 4/4 rounds refused with `could not resolve a cmux workspace id ... after creat…
The settle window absorbs cmux's stale post-create snapshot repeatably, not just once ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/02-fixed-adapter-repro.txt (4/4 rounds) and 06-live-guard.txt (the repo's guard, 5/5 rounds, via bin/fm-test-run.sh against cmux…
Adversarial: with the settle window removed the launch still fails loudly and stops at its bound rather than hanging or silently succeeding ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/04-fm-spawn-cmux-settle-disabled.txt - fm-spawn with FM_BACKEND_CMUX_SETTLE_TRIES=1 exits 1 with `... after creation (gave up aft…
Knock-on guard: the duplicate check still refuses a second launch of a label that is live in the app ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/03-fm-spawn-cmux-live.txt - create_task('fm-test-cmuxspawn-7515') -> rc=1 error: cmux workspace '...' already exists
Knock-on guard: a successful launch leaves no orphan workspace after the operator's own teardown, and the app ends where it started ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/03-fm-spawn-cmux-live.txt (no workspace with the task title after bin/fm-teardown.sh) and 05-orphan-cleanup-and-final-workspace-s…
The shipped portable regression actually catches this bug (fails on the pre-fix adapter, passes on the fixed one) ⏸️ untested no This scenario was only exercised through the fake-CLI unit suite (tests/fm-backend-cmux.test.sh against a temp root carrying the base-commit adapter), which stubs the cmux CLI and pins the retry count…
Evidence: Pre-fix adapter reproduces the spawn refusal 4/4 against real cmux

Source: Pre-fix adapter reproduces the spawn refusal 4/4 against real cmux

round 1: FAIL error: could not resolve a cmux workspace id for 'fm-firstmate-85fb1818-test-prefix-3432-1' after creation round 2: FAIL ... round 3: FAIL ... round 4: FAIL summary: 4/4 rounds failed

round 1: FAIL  error: could not resolve a cmux workspace id for 'fm-firstmate-85fb1818-test-prefix-3432-1' after creation
        teardown: closed 6873BE8E-09E6-41F5-8C72-16C181F68442 (fm-firstmate-85fb1818-test-prefix-3432-1)
round 2: FAIL  error: could not resolve a cmux workspace id for 'fm-firstmate-85fb1818-test-prefix-3432-2' after creation
        teardown: closed 71987E99-23A8-4266-A807-EA15BB674B2A (fm-firstmate-85fb1818-test-prefix-3432-2)
round 3: FAIL  error: could not resolve a cmux workspace id for 'fm-firstmate-85fb1818-test-prefix-3432-3' after creation
        teardown: closed 3C62076D-616C-4508-8A00-94051F67AE70 (fm-firstmate-85fb1818-test-prefix-3432-3)
round 4: FAIL  error: could not resolve a cmux workspace id for 'fm-firstmate-85fb1818-test-prefix-3432-4' after creation
        teardown: closed 376A100D-E219-4794-AA35-8ED7A42A9A3A (fm-firstmate-85fb1818-test-prefix-3432-4)
summary: 4/4 rounds failed
Evidence: Fixed adapter: same sequence, 4/4 resolve the new workspace/surface

Source: Fixed adapter: same sequence, 4/4 resolve the new workspace/surface

round 1: PASS create_task -> 5DAC0CE0-... 03C6B3F5-... round 2..4: PASS summary: 0/4 rounds failed

round 1: PASS  create_task -> 5DAC0CE0-177E-40DA-A9B4-BC18E9E2B91B 03C6B3F5-AC38-44E2-B10A-50ACAE63CCD5
        teardown: closed 5DAC0CE0-177E-40DA-A9B4-BC18E9E2B91B (fm-firstmate-f234c421-test-fixed-4644-1)
round 2: PASS  create_task -> A86236EC-FE6A-4C3F-B336-829C706E9936 611C943E-0505-4AA5-9F53-5F425139C741
        teardown: closed A86236EC-FE6A-4C3F-B336-829C706E9936 (fm-firstmate-f234c421-test-fixed-4644-2)
round 3: PASS  create_task -> E2C636DA-495E-4C77-AA4F-66A182B6C872 902F4DDE-4DE2-4766-9D67-BEEAB8B49A6F
        teardown: closed E2C636DA-495E-4C77-AA4F-66A182B6C872 (fm-firstmate-f234c421-test-fixed-4644-3)
round 4: PASS  create_task -> 917A1BE0-7BAF-453E-99EA-7EEEEC02073E E653F326-1D6B-456B-90D3-3271969F808C
        teardown: closed 917A1BE0-7BAF-453E-99EA-7EEEEC02073E (fm-firstmate-f234c421-test-fixed-4644-4)
summary: 0/4 rounds failed
Evidence: End-user launch: bin/fm-spawn.sh --backend cmux, live workspace, duplicate refusal, clean teardown

Source: End-user launch: bin/fm-spawn.sh --backend cmux, live workspace, duplicate refusal, clean teardown

spawned test-cmuxspawn-7515 harness=sh kind=ship mode=no-mistakes yolo=off window=8C5A52E5-...:F8F4473E-... worktree=~/.treehouse/scratch-project-c3223c/1/scratch-project workspace 8C5A52E5-... title fm-firstmate-f234c421-test-cmuxspawn-7515 <capture of the worker surface> cmux-spawn-live-ok create_task('fm-test-cmuxspawn-7515') -> rc=1 error: cmux workspace 'fm-firstmate-f234c421-test-cmuxspawn-7515' already exists teardown test-cmuxspawn-7515 complete ... --- workspaces carrying this task's title after teardown --- <none>

=== bin/fm-spawn.sh test-cmuxspawn-7515 <project> --backend cmux ===
--- stdout ---
spawned test-cmuxspawn-7515 harness=sh kind=ship mode=no-mistakes yolo=off window=8C5A52E5-0317-4C67-9DCC-9E5A06779ACF:F8F4473E-9B03-4BBF-9C5D-AF7D99F7D01E worktree=~/.treehouse/scratch-project-c3223c/1/scratch-project
--- stderr ---
warning: /private/var/folders/38/r1d9kgsd0_x2bvbkglvjml200000gn/T/fm-cmux-spawn-live.tYtAXg/data/test-cmuxspawn-7515/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
--- exit: 0 ---

=== recorded task state (state/test-cmuxspawn-7515.meta) ===
window=8C5A52E5-0317-4C67-9DCC-9E5A06779ACF:F8F4473E-9B03-4BBF-9C5D-AF7D99F7D01E
endpoint_task_id=test-cmuxspawn-7515
worktree=~/.treehouse/scratch-project-c3223c/1/scratch-project
project=/private/var/folders/38/r1d9kgsd0_x2bvbkglvjml200000gn/T/fm-cmux-spawn-live.tYtAXg/scratch-project
harness=sh
kind=ship
mode=no-mistakes
yolo=off
tasktmp=/tmp/fm-test-cmuxspawn-7515
model=default
effort=default
spawn_gen=s1789987424.7531.24510
backend=cmux
cmux_workspace_id=8C5A52E5-0317-4C67-9DCC-9E5A06779ACF
cmux_surface_id=F8F4473E-9B03-4BBF-9C5D-AF7D99F7D01E

=== the worker's workspace as the live cmux app reports it ===
workspace 8C5A52E5-0317-4C67-9DCC-9E5A06779ACF  title fm-firstmate-f234c421-test-cmuxspawn-7515
recorded endpoint: 8C5A52E5-0317-4C67-9DCC-9E5A06779ACF:F8F4473E-9B03-4BBF-9C5D-AF7D99F7D01E
--- fm_backend_cmux_capture of the worker surface ---
quote> ' '__FM_CMUX_CWD_END__'
__FM_CMUX_CWD_BEGIN__
~/.treehouse/scratch-project-c3223c/1/scratch-project
__FM_CMUX_CWD_END__
nicholasmartin@Mac scratch-project % printf '%s
quote> ' '__FM_CMUX_CWD_BEGIN__'; pwd; printf '%s
quote> ' '__FM_CMUX_CWD_END__'
__FM_CMUX_CWD_BEGIN__
~/.treehouse/scratch-project-c3223c/1/scratch-project
__FM_CMUX_CWD_END__
nicholasmartin@Mac scratch-project % export GOTMPDIR=/tmp/fm-test-cmuxspawn-7515/gotmp
nicholasmartin@Mac scratch-project % export COMPACT_ADVISER_DISABLE=1
nicholasmartin@Mac scratch-project % export FM_TASK_ID=test-cmuxspawn-7515
nicholasmartin@Mac scratch-project % . '/tmp/fm-test-cmuxspawn-7515+e2cba94ad6e1719fb91b58b1642185943a631dc67a57d03dfb12b454c8df7fb4/launch.s1789987424.7531.24510.sh'
cmux-spawn-live-ok
=== knock-on: duplicate check still refuses a second launch of the same label ===
create_task('fm-test-cmuxspawn-7515') -> rc=1  error: cmux workspace 'fm-firstmate-f234c421-test-cmuxspawn-7515' already exists

=== bin/fm-teardown.sh test-cmuxspawn-7515 (the operator's own cleanup path) ===
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  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 guarded operation WILL still run.
●  watcher supervision needs Stop-owned automatic recovery; inspect the hook registration and startup status before ending the turn.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
teardown: reaping leaked worktree process(es) for test-cmuxspawn-7515: 8348 9874
teardown: force-killing leaked worktree process(es) for test-cmuxspawn-7515: 8348
🌳 Worktree returned to pool.
/private/var/folders/38/r1d9kgsd0_x2bvbkglvjml200000gn/T/fm-cmux-spawn-live.tYtAXg/scratch-project: already current
teardown test-cmuxspawn-7515 complete (window 8C5A52E5-0317-4C67-9DCC-9E5A06779ACF:F8F4473E-9B03-4BBF-9C5D-AF7D99F7D01E, worktree ~/.treehouse/scratch-project-c3223c/1/scratch-project)
Backlog: test-cmuxspawn-7515 just finished (this home keeps no markdown backlog at /private/var/folders/38/r1d9kgsd0_x2bvbkglvjml200000gn/T/fm-cmux-spawn-live.tYtAXg/data/backlog.md). Update /private/var/folders/38/r1d9kgsd0_x2bvbkglvjml200000gn/T/fm-cmux-spawn-live.tYtAXg/data/backlog.md - move test-cmuxspawn-7515 to Done, keep Done to the 10 most recent, then re-scan Queued and dispatch only work whose blockers are gone and date is due.
--- workspaces carrying this task's title after teardown ---
<none>
Evidence: Adversarial: settle window collapsed to one attempt reproduces the fault at the real entrypoint

Source: Adversarial: settle window collapsed to one attempt reproduces the fault at the real entrypoint

error: could not resolve a cmux workspace id for 'fm-firstmate-f234c421-test-cmuxspawn-tries1-12371' after creation (gave up after 1 attempts) --- exit: 1 --- workspace 0BBC1E75-... title fm-firstmate-f234c421-test-cmuxspawn-tries1-12371 (the orphan the intent describes)

=== bin/fm-spawn.sh test-cmuxspawn-tries1-12371 <project> --backend cmux ===
--- stdout ---
--- stderr ---
warning: /private/var/folders/38/r1d9kgsd0_x2bvbkglvjml200000gn/T/fm-cmux-spawn-live.PBPB5z/data/test-cmuxspawn-tries1-12371/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: could not resolve a cmux workspace id for 'fm-firstmate-f234c421-test-cmuxspawn-tries1-12371' after creation (gave up after 1 attempts)
--- exit: 1 ---

=== recorded task state (state/test-cmuxspawn-tries1-12371.meta) ===
(no meta written)

=== the worker's workspace as the live cmux app reports it ===
workspace 0BBC1E75-CEE3-4CAE-AE7D-497E021F7724  title fm-firstmate-f234c421-test-cmuxspawn-tries1-12371
Evidence: Orphan from the failed launch closed; cmux app back to its starting state

Source: Orphan from the failed launch closed; cmux app back to its starting state

orphan left by the failed spawn: 0BBC1E75-... (fm-firstmate-f234c421-test-cmuxspawn-tries1-12371) guarded close: done --- workspaces now --- 638CC0CB-44C2-4A89-ABC6-FA7583837ADF wayfinder · wayfinder-smoke

orphan left by the failed spawn: 0BBC1E75-CEE3-4CAE-AE7D-497E021F7724 (fm-firstmate-f234c421-test-cmuxspawn-tries1-12371)
guarded close: done
--- workspaces now ---
638CC0CB-44C2-4A89-ABC6-FA7583837ADF  wayfinder · wayfinder-smoke
Evidence: Live settle guard through the real runner (5 rounds, real cmux)

Source: Live settle guard through the real runner (5 rounds, real cmux)

ok - real cmux (cmux 0.64.25 (106) [b685a275c]): create_task resolved its new workspace and surface on all 5 rounds FM_TEST_END ... exit=0 duration_ms=76447 gate_skip=false

FM_TEST_BEGIN 2026-09-21T10:46:54Z tests/fm-cmux-workspace-settle-live-e2e.test.sh family=live-harness-optin expected_gate_skip=live-capability
ok - real cmux (cmux 0.64.25 (106) [b685a275c]): create_task resolved its new workspace and surface on all 5 rounds
FM_TEST_END 2026-09-21T10:48:11Z tests/fm-cmux-workspace-settle-live-e2e.test.sh exit=0 duration_ms=76447 gate_skip=false
FM_TEST_SUMMARY total=1 failed=0 skipped_gate=0 duration_ms=76512
FM_TEST_SUMMARY_FAMILY family=live-harness-optin count=1 duration_ms=76447 failed=0
FM_TEST_SLOWEST rank=1 script=tests/fm-cmux-workspace-settle-live-e2e.test.sh duration_ms=76447
Evidence: New portable regression fails against the pre-fix adapter (fake-CLI suite, red before / green after)

Source: New portable regression fails against the pre-fix adapter (fake-CLI suite, red before / green after)

not ok - create_task should retry a stale post-create workspace list, got '' (pre-fix adapter; passes on the fixed adapter)

ok - fm_backend_cmux_version_check: accepts the verified minimum (0.64.17)
ok - fm_backend_cmux_version_check: accepts a newer version (0.70.0)
ok - fm_backend_cmux_version_check: refuses an old version loudly
ok - fm_backend_cmux_version_check: refuses loudly when cmux is not found on PATH or at the bundle path
ok - fm_backend_cmux_password: reads the first non-empty line of config/cmux-socket-password
ok - fm_backend_cmux_password: preserves spaces and tabs in config/cmux-socket-password
ok - fm_backend_cmux_password: respects FM_CONFIG_OVERRIDE
ok - fm_backend_cmux_password: empty when config/cmux-socket-password is absent
ok - fm_backend_cmux_cli: exports CMUX_SOCKET_PASSWORD when config/cmux-socket-password is set
ok - fm_backend_cmux_parse_target: splits '<workspace_uuid>:<surface_uuid>' on the first colon
ok - fm_backend_cmux_normalize_key: Enter/Escape/C-c map to cmux's verified enter/escape/ctrl-c
ok - fm_backend_cmux_scoped_title: scopes a primary task title with firstmate plus root hash
ok - fm_backend_cmux_scoped_title: scopes a secondmate task title with the home marker plus root hash
ok - fm_backend_cmux_scoped_title: includes the resolved FM_ROOT hash in the home label
ok - fm_backend_validate: cmux is a known backend
ok - fm_backend_busy_state: cmux (no native primitive) always reports unknown, same as tmux/zellij/orca
ok - fm_backend_composer_state: routes cmux to the cmux composer classifier
ok - fm_backend_cmux_ping_state: reports 'ok' on PONG
ok - fm_backend_cmux_ping_state: reports 'denied' when socketControlMode=cmuxOnly rejects the connection
ok - fm_backend_cmux_ping_state: reports 'unauth' when password mode rejects a missing/wrong password
ok - fm_backend_cmux_ping_state: reports 'unauth' when password mode rejects a wrong password (Invalid password)
ok - fm_backend_cmux_ping_state: reports 'down' when the app is not running yet
ok - fm_backend_cmux_ensure_running: returns immediately when cmux is already reachable
ok - fm_backend_cmux_ensure_running: fails fast on a denied socket without attempting to launch, naming every viable mode
ok - fm_backend_cmux_ensure_running: fails fast on an unauthenticated socket, naming the password config and the Automation mode alternative
ok - fm_backend_cmux_create_task: refuses a duplicate workspace title (cmux's own new-workspace has no uniqueness check)
ok - fm_backend_cmux_create_task: creates a workspace and parses workspace_id/surface_id from list responses
error: could not resolve a cmux workspace id for 'fm-firstmate-2eec80d3-stalelist' after creation
not ok - create_task should retry a stale post-create workspace list, got ''

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 - 6 of 7 scenarios driven live against the product
Scenario Result Live Evidence
An operator launches a worker on cmux with bin/fm-spawn.sh and the worker's workspace comes up live ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/03-fm-spawn-cmux-live.txt - spawn printed spawned ... window=&lt;ws&gt;:&lt;surface&gt;, the workspace appears in the live cmux list under…
The reported failure genuinely reproduces before the fix: the pre-fix adapter refuses to resolve the workspace it just created ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/01-prefix-adapter-repro.txt - base-commit adapter, 4/4 rounds refused with `could not resolve a cmux workspace id ... after creat…
The settle window absorbs cmux's stale post-create snapshot repeatably, not just once ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/02-fixed-adapter-repro.txt (4/4 rounds) and 06-live-guard.txt (the repo's guard, 5/5 rounds, via bin/fm-test-run.sh against cmux…
Adversarial: with the settle window removed the launch still fails loudly and stops at its bound rather than hanging or silently succeeding ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/04-fm-spawn-cmux-settle-disabled.txt - fm-spawn with FM_BACKEND_CMUX_SETTLE_TRIES=1 exits 1 with `... after creation (gave up aft…
Knock-on guard: the duplicate check still refuses a second launch of a label that is live in the app ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/03-fm-spawn-cmux-live.txt - create_task(&#39;fm-test-cmuxspawn-7515&#39;) -&gt; rc=1 error: cmux workspace &#39;...&#39; already exists
Knock-on guard: a successful launch leaves no orphan workspace after the operator's own teardown, and the app ends where it started ✅ pass live ~/.no-mistakes/evidence/01M31RPYCPXFE3WNH8DHBV3SKV/03-fm-spawn-cmux-live.txt (no workspace with the task title after bin/fm-teardown.sh) and 05-orphan-cleanup-and-final-workspace-s…
The shipped portable regression actually catches this bug (fails on the pre-fix adapter, passes on the fixed one) ⏸️ untested no This scenario was only exercised through the fake-CLI unit suite (tests/fm-backend-cmux.test.sh against a temp root carrying the base-commit adapter), which stubs the cmux CLI and pins the retry count…
  • bash tests/fm-backend-cmux.test.sh (portable cmux suite incl. the two new settle regressions) — 63 ok, 0 not ok
  • Same suite run against a temp root whose bin/backends/cmux.sh is the base-commit (pre-fix) adapter — not ok - create_task should retry a stale post-create workspace list (red-before/green-after)
  • bin/fm-test-run.sh tests/fm-cmux-workspace-settle-live-e2e.test.sh — default-on live guard, 5 real create_task rounds against cmux 0.64.25, exit=0
  • Manual live repro: pre-fix fm_backend_cmux_create_task x4 rounds against the real cmux app (duplicate-check-then-create shape)
  • Manual live control: fixed fm_backend_cmux_create_task x4 rounds, same lab FM_HOME, same app
  • bin/fm-spawn.sh test-cmuxspawn-&lt;pid&gt; &lt;scratch-project&gt; &#34;sh -c &#39;echo cmux-spawn-live-ok; exec sleep 600&#39;&#34; --mode no-mistakes --yolo off --backend cmux in an isolated FM_*_OVERRIDE home, then fm_backend_cmux_capture of the worker surface and bin/fm-teardown.sh &lt;id&gt;
  • Same live spawn with FM_BACKEND_CMUX_SETTLE_TRIES=1 (adversarial: settle window removed)
  • Live duplicate-check probe: fm_backend_cmux_create_task on a label already live in the app
  • cmux workspace list --json before and after the whole session to confirm no orphan fm-titled workspaces
  • bin/fm-test-run.sh --list --lane portable-serial and --check-coverage to confirm the new guard is scheduled, not orphaned
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

cmux's `workspace list` is not read-your-writes against `new-workspace`:
a list issued right after a successful create can be served a snapshot
taken before the new workspace was published, so the adapter's
duplicate-check-then-create-then-resolve sequence aborted every spawn with
"could not resolve a cmux workspace id ... after creation".

Give both post-creation reads a bounded retry window through a new
fm_backend_cmux_settle helper. The bound is explicit, and an exhausted
bound keeps the existing loud refusal rather than becoming a silent
success or an unbounded wait. The duplicate check stays, because cmux
enforces no title uniqueness of its own.

Covered by a portable regression over the fake CLI and a live guard that
drives the real app and names cmux and its version on failure.
@nickxyris nickxyris closed this Sep 21, 2026
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