Skip to content

fix(bin): lease ship and scout worktrees until teardown - #10

Merged
sparkus merged 9 commits into
mainfrom
fm/fix-lease-ship-worktrees-minimal
Aug 4, 2026
Merged

fix(bin): lease ship and scout worktrees until teardown#10
sparkus merged 9 commits into
mainfrom
fm/fix-lease-ship-worktrees-minimal

Conversation

@sparkus

@sparkus sparkus commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Intent

Lease ship/scout worktrees at spawn and release them at successful teardown only. MINIMAL CHANGE WITH A HARD SCOPE FENCE for firstmate shared tracked material.

Defect: bin/fm-spawn.sh sent plain treehouse get into the worker terminal. Plain get takes an AVAILABLE pool slot and does NOT lease it, so a slot still holding a parked task's worktree (with unpushed commits) counts as available and can be handed to the next spawn. That destroyed unrecoverable work on ampos-o9o.31 (kunchenguid#1441).

Naive flag swap fails: treehouse get --lease prints the path and exits without opening a subshell, so spawn's landing wait (pane cwd change) breaks. Correct shape matches bin/fm-home-seed.sh: lease with --lease --lease-holder <task-id>, then send the worker into the leased path (cd), keeping isolation assertion and landing confirmation adapted to a known-in-advance path.

IN SCOPE only: bin/fm-spawn.sh (lease then enter path), bin/fm-teardown.sh (release lease only when treehouse return succeeds), and tests. OUT OF SCOPE: home lock, retirement boundary, spawn concurrency locks, any backend adapter, install/bootstrap/CI/skills/AGENTS.md, recovery/relaunch lease semantics, pre-existing unleased worktrees.

Non-negotiable: REFUSED teardown must NOT release the lease (uncommitted/unlanded work is exactly what the lease protects). Concurrent distinct-task spawns must both succeed without serializing setup under a firstmate lock.

Acceptance: leased slot not returned by subsequent plain treehouse get; successful teardown releases; refused teardown keeps lease; concurrent distinct spawns work; existing spawn isolation and teardown tests stay green. Soft file-count fence ~5 files (landed at 7 with required test-adapter updates only).

What Changed

  • Lease Treehouse-backed ship and scout worktrees under the task ID, enter the exact leased path, and confirm landing and isolation before launch.
  • Preserve leases through refused teardowns and failed returns; limit pre-metadata spawn cleanup to leases still held by the spawning task.
  • Add lease lifecycle and concurrent-spawn regression coverage, update backend test fixtures, and document the durable lease behavior.

Risk Assessment

✅ Low: The change is narrowly scoped and the holder-guarded abort cleanup closes the prior issue without weakening refused-teardown lease retention.

Testing

The clean assigned target was checked against its base; focused lease, landing, cleanup-safety, backend, and isolation regressions passed without skips. A CLI transcript demonstrated the complete slot lifecycle, and the installed Treehouse CLI confirmed the lease-holder and guarded-return flags. The broad suite, lint, formatters, and static analysis were not run per the targeted test-phase boundary.

Evidence: Lease lifecycle CLI transcript

Spawn reserved slot-1; a later plain allocation received slot-2. Successful cleanup released slot-1, refused cleanup retained its holder without calling return, and two distinct tasks spawned concurrently with separate leases.

FIRSTMATE LEASE LIFECYCLE — END-TO-END CLI EVIDENCE
actual scripts: /Users/agwerschky/.no-mistakes/worktrees/e661563b090a/01KZ4WKJM3KWZPF6ZF8GFV8PVR/bin/fm-spawn.sh and /Users/agwerschky/.no-mistakes/worktrees/e661563b090a/01KZ4WKJM3KWZPF6ZF8GFV8PVR/bin/fm-teardown.sh

[1] SPAWN RESERVES A SLOT; LATER PLAIN GET SKIPS IT
spawn output: warn: no registry at /var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/evidence-held/home/data/projects.md; defaulting project to no-mistakes off
spawned evidence-hold-a1 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate:fm-evidence-hold-a1 worktree=/var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/evidence-held/pool/slot-1
recorded isolated copy: /var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/evidence-held/pool/slot-1
durable lease holder: evidence-hold-a1
subsequent plain treehouse get returned: /var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/evidence-held/pool/slot-2
leased slot was skipped: yes

[2] SUCCESSFUL CLEANUP RETURNS THE SLOT AND RELEASES THE LEASE
cleanup output: teardown evidence-hold-a1 complete (window firstmate:fm-evidence-hold-a1, worktree /var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/evidence-held/pool/slot-1)
Backlog: evidence-hold-a1 just finished. Run tasks-axi done evidence-hold-a1 --note "local main", then run tasks-axi ready for dependency-cleared candidates, check date gates, and dispatch only work whose blockers are gone and date is due.
lease after successful cleanup: released
treehouse return call: treehouse return --force /var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/evidence-held/pool/slot-1

[3] REFUSED CLEANUP PRESERVES UNLANDED WORK AND ITS LEASE
spawn output: warn: no registry at /var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/evidence-refused/home/data/projects.md; defaulting project to no-mistakes off
spawned evidence-refuse-b2 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate:fm-evidence-refuse-b2 worktree=/var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/evidence-refused/pool/slot-1
cleanup exit: 1
cleanup refusal: REFUSED: worktree /var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/evidence-refused/pool/slot-1 has work not on any remote and not landed.
durable lease holder after refusal: evidence-refuse-b2
treehouse return attempted after refusal: no

[4] TWO DISTINCT TASKS SPAWN CONCURRENTLY IN THE SAME HOME
ok - concurrent distinct-task spawns both succeed with distinct leased slots
task A output: warn: no registry at /var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/concurrent-mapped/home/data/projects.md; defaulting project to no-mistakes off
spawned conc-map-a6 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate:fm-conc-map-a6 worktree=/var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/concurrent-mapped/pool/slot-1
task B output: warn: no registry at /var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/concurrent-mapped/home/data/projects.md; defaulting project to no-mistakes off
spawned conc-map-b7 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate:fm-conc-map-b7 worktree=/var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T//fm-spawn-worktree-lease.GrB3Ft/concurrent-mapped/pool/slot-2
task A lease holder: conc-map-a6
task B lease holder: conc-map-b7
concurrent wall time: 2666ms
both task records exist: yes

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed ✅
  • 🚨 bin/fm-spawn.sh:347 - Intent requires “release them at successful teardown only,” but this new EXIT path runs treehouse return --force &#34;$WT&#34; after any pre-metadata spawn failure, including landing timeout or isolation refusal. This releases the lease outside teardown and before validate_spawn_worktree runs at line 1370. Decide whether failed-spawn rollback is an authorized exception; otherwise remove this return and retain the lease. If it is authorized, document the exception and validate both the path and --if-lease-holder &#34;$ID&#34; before force-returning it.

🔧 Fix: Scope failed-spawn lease cleanup to task holder
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • git status --short --branch; git rev-parse HEAD; diff stat and name-status for 2ef842cb530967264ba0f4835249f247b2c2fa40..ff8d151f6a8aa8adf0eba8ff6f08fdae20e5ae71
  • bin/fm-test-run.sh tests/fm-spawn-worktree-lease.test.sh tests/fm-spawn-worktree-settle.test.sh tests/fm-teardown.test.sh tests/fm-backend.test.sh tests/fm-tangle-guard.test.sh
  • Deterministic two-slot Treehouse evidence harness invoking the actual bin/fm-spawn.sh and bin/fm-teardown.sh
  • treehouse get --help; treehouse return --help
  • Post-test git status --short --branch
⚠️ **Document** - 1 warning
  • ⚠️ bin/backends/tmux.sh:82 - Backend adapter comments in tmux, Herdr, Zellij, and cmux still describe plain treehouse-get subshell discovery. The hard scope fence forbids editing backend adapters; a separately authorized comment-only cleanup should describe leased-worktree landing confirmation while preserving the empirical subshell limitations.
✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

sparkus added 9 commits August 3, 2026 16:39
Plain treehouse get only marks a pool slot in-use while a process holds
it, so a parked task with unpushed commits could be handed to the next
spawn and destroyed (kunchenguid#1441).

Lease the slot with get --lease --lease-holder <task-id> (same shape as
secondmate home seeding), then cd the worker into the known path and
keep the landing confirmation. Teardown still releases only via a
successful treehouse return; a refused teardown never reaches return.
Restore cmux/zellij/verification backend pages unchanged. Keep only the
architecture worktree-lease contract lines that describe durable ship/scout
leasing, refused-teardown retention, and holder-scoped abort release.
Post-create abort still needs isolation to refuse after the endpoint exists.
With host-side get --lease, the fixture must hand out the armed non-worktree
path so landing can match the poisoned pane cwd and validation still fails.
Focus-safe emptying close may remove the projected last pane without a
pane.close audit row. Concurrent abort still serializes under the
presentation lock; accept create-only sequences and keep pane-gone and
focus checks as the proof.
No-op treehouse return on the synthetic abort path so real treehouse never
touches the lab pool for it, and re-pin captain focus before projected shape
teardown after pane-death abort cleanup.
Leased ship/scout workers have their shell cwd in the worktree. Returning
the slot first kills that shell via pane-death and steals captain focus
without the focus-preserving close path. Close under the presentation
lock first, confirm the pane is gone, then release the lease.
Ship/scout spawns now call treehouse get --lease in-process. The crew path in
fm-secondmate-harness only faked tmux, so crew-unaffected failed before meta was
written. Match the shared lib stub for get --lease / return.
@sparkus
sparkus merged commit 2c0a001 into main Aug 4, 2026
10 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