Skip to content

fix(bin): select empty worktree-pool slots and attribute live occupancy (land of upstream #1923) - #66

Merged
sbracewell64 merged 4 commits into
mainfrom
fm/land-worktree-pool-onto-fork
Aug 9, 2026
Merged

sbracewell64 merged 4 commits into
mainfrom
fm/land-worktree-pool-onto-fork

Conversation

@sbracewell64

Copy link
Copy Markdown
Owner

Lands upstream PR kunchenguid#1923 (pushed head c9c5aaf4, "fix(bin): select empty worktree-pool slots and attribute live occupancy") onto this fork's trunk so the running fleet actually gets it.

Nothing was redesigned and nothing was re-reviewed. The change was already reviewed upstream, the upstream contribution stays open and untouched on the maintainer's schedule, and only that contribution's own changes are carried here.

What it fixes

A spawn was refused when the worktree pool offered a slot that a live worker still occupied, instead of selecting an empty slot. The allocation now picks an empty slot and attributes live occupancy to its apparent owner, so a refusal names a real conflict rather than an artefact of which slot the pool happened to hand out.

What is carried, and how it was cut

The upstream head c9c5aaf4 is a merge of upstream main 833a9a2 into the lane, so it is not the contribution alone. The lane's own three commits sit directly on this fork's trunk at ed376cf:

  • 6c5e9b4 fix(bin): allocate an empty pool slot instead of blockading on an occupied one
  • dfeb9d8 no-mistakes(review): serialize slot selection cross-home, record enter evidence, fix label
  • 7425e9b no-mistakes(document): document slot-selecting pool allocation in remaining owner docs

Those three were rebased onto the current trunk c1141a5. The upstream-main merge commit was deliberately left behind, so this branch carries the contribution and nothing else.

Evidence

The rebase was clean - no conflicts at any of the three commits. The resulting change-set is identical, file for file, to the contribution's own change-set at its original base:

$ diff <(git diff --name-only ed376cf..7425e9b | sort) \
       <(git diff --name-only fork/main..HEAD | sort)
(no output)

Eleven files: AGENTS.md, bin/fm-spawn.sh, bin/fm-worktree-guard.sh, docs/architecture.md, docs/cmux-backend.md, docs/configuration.md, docs/scripts.md, docs/verification/worktree-allocation.md, docs/zellij-backend.md, tests/fm-spawn-worktree-settle.test.sh, tests/fm-worktree-guard.test.sh.

Known structural red

PR must be raised via no-mistakes fails on this pull request by construction: it was opened by hand, so its head carries no refs/notes/no-mistakes attestation. That is the expected state for every hand-opened landing here until the pipeline push-step fix lands, and it is not a defect in this change.

…upied one

`treehouse get` hands out the first available slot and takes no slot
argument, so the pre-allocation guard could only refuse. One parked slot
therefore blockaded every spawn even when later slots were genuinely
empty, and the only way through was authorizing the parked slots by hand.

The guard now chooses as well as refuses: it names a demonstrably empty
slot that is parked at a detached HEAD or the default branch, and
fm-spawn acquires that slot by name with `treehouse enter`, which does
not reset it. An occupied slot is skipped untouched. The refusal is
preserved exactly where it still matters - with no empty slot to steer
to, the allocation falls back to `treehouse get`, so every available slot
must still be empty or explicitly authorized, and the refusal still names
each slot, its evidence and its apparent owner.

Liveness attribution no longer calls a worker gone on a stale recorded
pid alone. That pid is one process sampled when the slot was accepted, so
it stops matching for reasons that say nothing about the task. Stronger
bindings are read first and any one of them carries the live verdict:
HERDR_PANE_ID in a live process's environment matching the task's
recorded herdr_pane_id, GOTMPDIR matching its recorded tasktmp, or a live
process whose cwd is inside the slot.

Between choosing a slot and the pane's shell arriving in it, fm-spawn
holds the slot with one short-lived process of its own, because treehouse
reports a slot in-use while any process's cwd is inside it; the abort
path releases it.

tests/fm-worktree-guard.test.sh cases (s1) through (s4) and the rewritten
(o5) pin the skip, the preserved all-occupied refusal, both liveness
bindings with a negative control each, and the path-scoped reclaim
authority. docs/verification/worktree-allocation.md records the treehouse
behavior measured against v2.1.0.
…quires

Trunk began requiring --reason-code on every ship and scout spawn after this
branch was cut. The pre-existing spawn helper in this suite was updated on
trunk, but the pool-lock helper this branch adds was not, so its directed spawn
was refused before it could enter a slot. It now passes NL_RULE_CLASSIFICATION,
matching the helper beside it.
@sbracewell64
sbracewell64 force-pushed the fm/land-worktree-pool-onto-fork branch from 424a80d to 28db6fc Compare August 9, 2026 19:41
@sbracewell64

Copy link
Copy Markdown
Owner Author

Rebased onto the current fork trunk

Rebased onto 825e965 (fork main, after #60, #62, #63 and #65 merged). Pre-rewrite head 424a80d is preserved at archive/prerebase-2026-08-09/land-worktree-pool-onto-fork; the head branch is fork-only and is not shared with any open upstream PR - the upstream contribution rides fm/worktree-pool-offers-a-slot-owned-by-a-live-worker and was not touched. All three commits survived, including both pipeline-fix commits.

Conflict and how it was resolved

One conflict, in AGENTS.md section 7. This branch replaces the sentence describing the old behavior - a spawn refusing when the pool would hand out an occupied slot - with the new one, where a spawn selects a demonstrably empty slot and refuses only when the pool offers none. The trunk had appended an unrelated sentence about the required dispatch reason code immediately after it. Took this branch's replacement sentence and kept the trunk's added sentence beside it, so the behavior change lands and the reason-code rule is not dropped.

One integration fix the rebase exposed

Trunk began requiring --reason-code on every ship and scout spawn after this branch was cut. The suite's pre-existing spawn helper was updated on trunk, but the pool-lock helper this branch adds was not, so its directed spawn was refused before it could enter a slot. It now passes NL_RULE_CLASSIFICATION, matching the helper beside it. A scan of every test this branch touches found no other spawn missing one.

Test results, disclosed in full

bin/fm-test-run.sh --changed --base fork/main selected 84 suites; 9 failed on the first pass.

  • tests/fm-spawn-worktree-settle.test.sh - failed for the missing reason code above. It passes on bare trunk and failed only here, which is what distinguished it from the environmental failures and made it worth chasing rather than dismissing; it passes after the fix.
  • The other eight - fm-calm-pi-extension, fm-backend-tmux-smoke, fm-launch, fm-tmux-agent-liveness, fm-secondmate-harness, fm-secondmate-sync, fm-startup-memory-budget, fm-busy-adapter-wiring - are pre-existing and unrelated, all reproduced on unmodified fork/main in a separate clean checkout. They are local-environment failures: a Node ESM loader error, the local tmux harness, an absent no-mistakes daemon root, and the worktree-tangle warning that fires because the rebase worktree sits on a task branch.

bin/fm-lint.sh is clean.

The reporting was not trusted on absence: the runner produced real not ok lines and a non-zero exit, the fixed suite was watched failing and then passing on the same command, and every unrelated failure was reproduced against a bare-trunk control rather than assumed.

@sbracewell64
sbracewell64 merged commit 095cf63 into main Aug 9, 2026
13 of 14 checks passed
sbracewell64 added a commit that referenced this pull request Aug 9, 2026
…cy (land of upstream kunchenguid#1923) (#66)

* fix(bin): allocate an empty pool slot instead of blockading on an occupied one

`treehouse get` hands out the first available slot and takes no slot
argument, so the pre-allocation guard could only refuse. One parked slot
therefore blockaded every spawn even when later slots were genuinely
empty, and the only way through was authorizing the parked slots by hand.

The guard now chooses as well as refuses: it names a demonstrably empty
slot that is parked at a detached HEAD or the default branch, and
fm-spawn acquires that slot by name with `treehouse enter`, which does
not reset it. An occupied slot is skipped untouched. The refusal is
preserved exactly where it still matters - with no empty slot to steer
to, the allocation falls back to `treehouse get`, so every available slot
must still be empty or explicitly authorized, and the refusal still names
each slot, its evidence and its apparent owner.

Liveness attribution no longer calls a worker gone on a stale recorded
pid alone. That pid is one process sampled when the slot was accepted, so
it stops matching for reasons that say nothing about the task. Stronger
bindings are read first and any one of them carries the live verdict:
HERDR_PANE_ID in a live process's environment matching the task's
recorded herdr_pane_id, GOTMPDIR matching its recorded tasktmp, or a live
process whose cwd is inside the slot.

Between choosing a slot and the pane's shell arriving in it, fm-spawn
holds the slot with one short-lived process of its own, because treehouse
reports a slot in-use while any process's cwd is inside it; the abort
path releases it.

tests/fm-worktree-guard.test.sh cases (s1) through (s4) and the rewritten
(o5) pin the skip, the preserved all-occupied refusal, both liveness
bindings with a negative control each, and the path-scoped reclaim
authority. docs/verification/worktree-allocation.md records the treehouse
behavior measured against v2.1.0.

* no-mistakes(review): serialize slot selection cross-home, record enter evidence, fix label

* no-mistakes(document): document slot-selecting pool allocation in remaining owner docs

* test(pool): give the directed-spawn case the reason code trunk now requires

Trunk began requiring --reason-code on every ship and scout spawn after this
branch was cut. The pre-existing spawn helper in this suite was updated on
trunk, but the pool-lock helper this branch adds was not, so its directed spawn
was refused before it could enter a slot. It now passes NL_RULE_CLASSIFICATION,
matching the helper beside it.
sbracewell64 added a commit that referenced this pull request Aug 10, 2026
…cy (land of upstream kunchenguid#1923) (#66)

* fix(bin): allocate an empty pool slot instead of blockading on an occupied one

`treehouse get` hands out the first available slot and takes no slot
argument, so the pre-allocation guard could only refuse. One parked slot
therefore blockaded every spawn even when later slots were genuinely
empty, and the only way through was authorizing the parked slots by hand.

The guard now chooses as well as refuses: it names a demonstrably empty
slot that is parked at a detached HEAD or the default branch, and
fm-spawn acquires that slot by name with `treehouse enter`, which does
not reset it. An occupied slot is skipped untouched. The refusal is
preserved exactly where it still matters - with no empty slot to steer
to, the allocation falls back to `treehouse get`, so every available slot
must still be empty or explicitly authorized, and the refusal still names
each slot, its evidence and its apparent owner.

Liveness attribution no longer calls a worker gone on a stale recorded
pid alone. That pid is one process sampled when the slot was accepted, so
it stops matching for reasons that say nothing about the task. Stronger
bindings are read first and any one of them carries the live verdict:
HERDR_PANE_ID in a live process's environment matching the task's
recorded herdr_pane_id, GOTMPDIR matching its recorded tasktmp, or a live
process whose cwd is inside the slot.

Between choosing a slot and the pane's shell arriving in it, fm-spawn
holds the slot with one short-lived process of its own, because treehouse
reports a slot in-use while any process's cwd is inside it; the abort
path releases it.

tests/fm-worktree-guard.test.sh cases (s1) through (s4) and the rewritten
(o5) pin the skip, the preserved all-occupied refusal, both liveness
bindings with a negative control each, and the path-scoped reclaim
authority. docs/verification/worktree-allocation.md records the treehouse
behavior measured against v2.1.0.

* no-mistakes(review): serialize slot selection cross-home, record enter evidence, fix label

* no-mistakes(document): document slot-selecting pool allocation in remaining owner docs

* test(pool): give the directed-spawn case the reason code trunk now requires

Trunk began requiring --reason-code on every ship and scout spawn after this
branch was cut. The pre-existing spawn helper in this suite was updated on
trunk, but the pool-lock helper this branch adds was not, so its directed spawn
was refused before it could enter a slot. It now passes NL_RULE_CLASSIFICATION,
matching the helper beside it.
sbracewell64 added a commit that referenced this pull request Aug 11, 2026
…cy (land of upstream kunchenguid#1923) (#66)

* fix(bin): allocate an empty pool slot instead of blockading on an occupied one

`treehouse get` hands out the first available slot and takes no slot
argument, so the pre-allocation guard could only refuse. One parked slot
therefore blockaded every spawn even when later slots were genuinely
empty, and the only way through was authorizing the parked slots by hand.

The guard now chooses as well as refuses: it names a demonstrably empty
slot that is parked at a detached HEAD or the default branch, and
fm-spawn acquires that slot by name with `treehouse enter`, which does
not reset it. An occupied slot is skipped untouched. The refusal is
preserved exactly where it still matters - with no empty slot to steer
to, the allocation falls back to `treehouse get`, so every available slot
must still be empty or explicitly authorized, and the refusal still names
each slot, its evidence and its apparent owner.

Liveness attribution no longer calls a worker gone on a stale recorded
pid alone. That pid is one process sampled when the slot was accepted, so
it stops matching for reasons that say nothing about the task. Stronger
bindings are read first and any one of them carries the live verdict:
HERDR_PANE_ID in a live process's environment matching the task's
recorded herdr_pane_id, GOTMPDIR matching its recorded tasktmp, or a live
process whose cwd is inside the slot.

Between choosing a slot and the pane's shell arriving in it, fm-spawn
holds the slot with one short-lived process of its own, because treehouse
reports a slot in-use while any process's cwd is inside it; the abort
path releases it.

tests/fm-worktree-guard.test.sh cases (s1) through (s4) and the rewritten
(o5) pin the skip, the preserved all-occupied refusal, both liveness
bindings with a negative control each, and the path-scoped reclaim
authority. docs/verification/worktree-allocation.md records the treehouse
behavior measured against v2.1.0.

* no-mistakes(review): serialize slot selection cross-home, record enter evidence, fix label

* no-mistakes(document): document slot-selecting pool allocation in remaining owner docs

* test(pool): give the directed-spawn case the reason code trunk now requires

Trunk began requiring --reason-code on every ship and scout spawn after this
branch was cut. The pre-existing spawn helper in this suite was updated on
trunk, but the pool-lock helper this branch adds was not, so its directed spawn
was refused before it could enter a slot. It now passes NL_RULE_CLASSIFICATION,
matching the helper beside it.
sbracewell64 added a commit that referenced this pull request Aug 11, 2026
…cy (land of upstream kunchenguid#1923) (#66)

* fix(bin): allocate an empty pool slot instead of blockading on an occupied one

`treehouse get` hands out the first available slot and takes no slot
argument, so the pre-allocation guard could only refuse. One parked slot
therefore blockaded every spawn even when later slots were genuinely
empty, and the only way through was authorizing the parked slots by hand.

The guard now chooses as well as refuses: it names a demonstrably empty
slot that is parked at a detached HEAD or the default branch, and
fm-spawn acquires that slot by name with `treehouse enter`, which does
not reset it. An occupied slot is skipped untouched. The refusal is
preserved exactly where it still matters - with no empty slot to steer
to, the allocation falls back to `treehouse get`, so every available slot
must still be empty or explicitly authorized, and the refusal still names
each slot, its evidence and its apparent owner.

Liveness attribution no longer calls a worker gone on a stale recorded
pid alone. That pid is one process sampled when the slot was accepted, so
it stops matching for reasons that say nothing about the task. Stronger
bindings are read first and any one of them carries the live verdict:
HERDR_PANE_ID in a live process's environment matching the task's
recorded herdr_pane_id, GOTMPDIR matching its recorded tasktmp, or a live
process whose cwd is inside the slot.

Between choosing a slot and the pane's shell arriving in it, fm-spawn
holds the slot with one short-lived process of its own, because treehouse
reports a slot in-use while any process's cwd is inside it; the abort
path releases it.

tests/fm-worktree-guard.test.sh cases (s1) through (s4) and the rewritten
(o5) pin the skip, the preserved all-occupied refusal, both liveness
bindings with a negative control each, and the path-scoped reclaim
authority. docs/verification/worktree-allocation.md records the treehouse
behavior measured against v2.1.0.

* no-mistakes(review): serialize slot selection cross-home, record enter evidence, fix label

* no-mistakes(document): document slot-selecting pool allocation in remaining owner docs

* test(pool): give the directed-spawn case the reason code trunk now requires

Trunk began requiring --reason-code on every ship and scout spawn after this
branch was cut. The pre-existing spawn helper in this suite was updated on
trunk, but the pool-lock helper this branch adds was not, so its directed spawn
was refused before it could enter a slot. It now passes NL_RULE_CLASSIFICATION,
matching the helper beside it.
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