Conversation
added 3 commits
September 30, 2026 18:17
…rned A "-" home seed durably leases a Treehouse pool slot but never published Firstmate's slot-owner claim, so completed tasks that used the slot before still name what is now the secondmate's home. Once only one stale record remained and its old claim read as its own, or the claim was absent, its teardown returned the seeded home to the pool. The reassigned-slot shortcut also let any different claim skip the duplicate-record scan on such a home, even when its ownership could not be proved or the old endpoint was live. - fm-wake-lib: read a slot's durable lease from the pool state, recognize persistent-home evidence, positively prove a committed local secondmate home (pool identity, lease holder, identity marker, local parent binding, exact registry route), and transfer a claim atomically while keeping the replaced one at .fm-slot-owner.prior. - fm-home-seed: publish the claim under the Treehouse project lock when a seed leases its home, drop only that claim on rollback, and add claim-slot to re-publish it for an already-seeded home after re-proving ownership. - fm-teardown: never return, reset, or reap a slot showing a persistent home while the claim still makes the ordinary task its owner, even with --force; once the claim names the proved owner, a completed scout whose exact endpoint is dead or missing may take the existing no-slot-touch cleanup while other stale records or the owner's own record name the home, and any other secondmate record still refuses. Forced parent teardown refuses a child slot that is a persistent home. - Tests cover the diagnostic cases, proof mismatches, live and unreadable endpoints, completion gates, interrupted reconciliation, seed claim and rollback, and real Herdr endpoint classification in an isolated lab.
The real-Herdr persistent-slot cleanup test relied on Herdr's own screen detection leaving an unreported claude-named pane at the undetermined `unknown` status. Herdr settles that pane on `idle` about 4 seconds after detection, so a slow run classified it `alive` instead of `unreadable` and failed; a 6-second delay before classification reproduced it every time. Report that pane's status as `unknown` explicitly, which makes the reporter the status authority, and wait for that status before classifying. The classifier path under test and every assertion are unchanged; the fixed test passes with 6- and 15-second delays and in 10 of 10 sequential runs.
…ool records unleased
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Problem. A persistent secondmate home seeded into a reused Treehouse pool slot could still be named by an older finished task's record, or carry an old task's
.fm-slot-ownerclaim. Ordinary or forced teardown of that stale task could then return, reset, or reap the live secondmate home. #6213 lets a stale record retire records-only only when a different owner claim is already present, so a seed that never published its own claim, or a home seeded before claims existed, stayed exposed.Fix. A fresh leased-home seed publishes the secondmate's slot-owner claim under the Treehouse project lock, and seed rollback drops only its own claim. A new
fm-home-seed.sh claim-slot <id>recovers already-seeded homes with an atomic, recoverable claim transfer, gated on positive pool, lease, identity, parent and registry proof of persistent-home ownership. Ordinary teardown refuses to return a durable secondmate home whose claim is its own or absent; the duplicate-record allowance is narrowed to a completed scout with a proved persistent owner and a dead or missing endpoint, still refusing contradictory secondmate records; and forced parent teardown never returns a child slot that is a persistent home. A slot the pool records as unleased stays ordinary, whatever markers a retired secondmate left behind.Tests. Behavioural regressions in
tests/fm-secondmate-safety.test.shandtests/fm-teardown-endpoint-safety.test.sh, a new real-Herdr testtests/fm-teardown-persistent-slot-herdr-e2e.test.sh, and a live lab run with real Treehouse and Herdr (results below).What Changed
-seed leases a Treehouse pool slot,bin/fm-home-seed.shnow holds the firstmate repo's Treehouse project lock from before the lease until the slot-owner claim naming the secondmate and its home is published. A contended lock refuses before anything is leased. Rollback re-takes the lock and drops the claim only while it still names this secondmate. A newfm-home-seed.sh claim-slot <id>command re-publishes the claim for homes that were seeded before seeding wrote one. It takes the registry lock and then the project lock, and writes only after the newfm_treehouse_secondmate_slot_proofinbin/fm-wake-lib.shproves five things: the slot is in this repo's pool, the pool state records a durable lease to that id,.fm-secondmate-homenames the holder,.fm-secondmate-parentis a valid local binding, and the registering home's registry routes the id to this slot. The newfm_treehouse_slot_owner_transferhandles the swap: it keeps the replaced claim's bytes at.fm-slot-owner.priorand converges when retried.bin/fm-teardown.shtreats a slot as a persistent secondmate home when it has a durable lease, or when its pool state can't be read and it carries a secondmate marker or parent binding. If the claim on such a slot is the task's own or missing, teardown refuses, even with--force, and points toclaim-slot. A forced parent teardown refuses a child slot that is a persistent home in the same way. Once the claim names the proved owner, a completed scout (no--force) can finish its own records-only cleanup while other stale records still name the slot, but only if the backend reads its exact recorded endpoint as dead or missing. A live or unreadable endpoint, or a contradictory secondmate record, still refuses. A slot the pool state records as unleased stays an ordinary slot, whatever markers a retired secondmate left behind.claim-slotin the secondmate-provisioning skill,docs/architecture.md,docs/configuration.md,docs/herdr-backend.mdanddocs/verification/runtime-backends.md(measured Herdr 0.9.1 endpoint states). Added regressions totests/fm-secondmate-safety.test.shandtests/fm-teardown-endpoint-safety.test.sh. Added a new real-Herdr test,tests/fm-teardown-persistent-slot-herdr-e2e.test.sh, which is registered in the Herdr family inbin/fm-test-run.shand excluded inbin/fm-test-isolation-proof.sh.🤖 Generated with Claude Code
Risk Assessment
✅ Low: The fix round applies the user-chosen option (b) narrowly. Every refusal path still fails closed, the round-1 retire-then-reuse regression is fixed and covered by behavioural tests in both directions, and the full change meets every required item of the stated intent with no remaining defect found.
Testing
I ran the change's own real-Herdr e2e test, then a new live driver: the target tree's real scripts in a disposable marked lab home, with a real Treehouse pool kept inside the lab and a named fm-lab-* Herdr session. The driver covered fresh seed, rollback, stale-scout cleanup, legacy-claim refusal (with and without --force, and with no claim), claim-slot refusal, reconcile and repeat, contradictory secondmate record, forced parent teardown, and real retirement followed by crewmate reuse. It also swapped in the pre-fix wake library to show the review-round-1 regression reproduces before the fix and is gone after it. All 78 live checks passed, and both targeted suites passed. Scout and secondmate records were written in fm-spawn's format rather than created by spawning agents (no harness was launched or spent tokens). The pre-change seed state (claim still naming the old scout) was created with the product's own claim writer. Lab session, lab root and temp files were all removed, and the worktree is unchanged. One process note: my first probe found that Treehouse 2.0.1 ignores TREEHOUSE_ROOT, so it created one throwaway pool (repo-9965f2) in ~/.treehouse. I returned and destroyed that pool, removed its directory, and confirmed ~/.treehouse matches its original listing. After that, every run used a repo-local treehouse.toml root. This is a CLI and shell change, so the evidence is command transcripts, not screenshots.
fm-home-seed.sh mate - --no-projects) into a slot two scouts used: the slot's .fm-slot-owner then names task=mate and the registering home, and the pool reco…claim-slot mate, and changes nothingEvidence: Real-Herdr persistent-slot e2e output
Source: Real-Herdr persistent-slot e2e output
evidence: herdr 0.9.1 endpoint states: shell-only=dead closed=missing registered-claude=alive unknown-status-claude=unreadable ok - real Herdr: a live or unreadable old endpoint keeps the duplicate-record refusal on a reconciled persistent home ok - real Herdr: completed scouts whose endpoints are dead or missing finish without touching the reconciled persistent homeEvidence: Retire-then-reuse: pre-fix refusal vs target teardown (excerpt)
Evidence: Legacy-claim refusal naming the recovery command (excerpt)
Evidence: Targeted suite: fm-teardown-endpoint-safety
Source: Targeted suite: fm-teardown-endpoint-safety
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-wake-lib.sh:1635-fm_treehouse_slot_persistent_evidencetreats a.fm-secondmate-homeor.fm-secondmate-parentmarker as proof of a persistent home "whatever its lease reads". Nothing removes those markers when a secondmate retires.remove_firstmate_home(bin/fm-teardown.sh ~2749) only runstreehouse return --forceon a leased home. Both markers are gitignored, and Treehouse keeps gitignored files across a return: its README says so, and returned pool slots still hold gitignored state. fm-spawn does not reject such a slot either.Failing sequence:
materetires. Its slot S goes back to the pool unleased, but both markers stay in S.treehouse get, and spawn writes the claim task=T.fm-teardown.sh Trunsteardown_persistent_slot_gate. The evidence check is true from the markers alone, the claim readsmine, and the proof fails with "no readable durable Treehouse lease". Teardown exits at bin/fm-teardown.sh:2488 with "REFUSED ... not even with --force".The forced-parent preflight (bin/fm-teardown.sh ~3088) refuses the same way. Before this change, T would have been torn down and its slot returned normally. Now every later firstmate-project crewmate in that slot is stuck.
claim-slotcannot help because the home is no longer registered, and the only advice printed is to "reconcile the home's lease, identity marker, parent binding, and registry route". The new seed claim (task=<secondmate>) is also never released on retirement, so it stays on the returned slot as well.The defect is a correctness regression, but choosing the fix touches deliberate design, so it needs your decision. Option (a): have secondmate retirement drop its markers and its own slot claim once
treehouse returnsucceeds. Option (b): count marker-only evidence only when the pool state cannot answer (exit 2), not when it positively records no lease (exit 1). Either way, add a regression for retire-then-reuse.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
fm-home-seed.sh mate - --no-projects) into a slot two scouts used: the slot's .fm-slot-owner then names task=mate and the registering home, and the pool reco…claim-slot mate, and changes nothingtests/fm-teardown-persistent-slot-herdr-e2e.test.sh(real Herdr, isolated fm-lab-* session via bin/fm-herdr-lab.sh)~/.no-mistakes/evidence/01M3TD5RAXF1M89YXYS6R1JSE3/live-driver.sh: a marked lab home made bybin/fm-lab-home.sh create(a primary checkout of the 1e71c99 tree); a real Treehouse pool rooted inside the lab through a repo-local treehouse.toml; a real Herdr lab session; realfm-brief.sh,fm-home-seed.shandfm-teardown.shLive: scouts take pool slot 1 through interactivetreehouse getin their own Herdr panes, thenfm-home-seed.sh mate - --no-projectswith a placeholder charter (rollback), then a valid seed (claim published, durable lease)Live:fm-teardown.sh old-scout-aandold-scout-bon the freshly seeded home (records-only; notreehousecall; pool fingerprint byte-identical)Live: legacy claim shape, thenfm-teardown.sh old-scout-c,--force, and--forcewith no claim (all refused; the refusal namesclaim-slot mate)Live:fm-home-seed.sh claim-slot matewith a mismatched identity marker, andclaim-slot ghost(both refused, claim unchanged), thenclaim-slot mate(replaced,.priorkept) and a repeat (unchanged), thenfm-teardown.sh old-scout-cfinishesLive: a contradictoryother-matesecondmate record makesfm-teardown.sh old-scout-drefuse; once that record is removed, old-scout-d finishesLive:fm-home-seed.sh domain <path> --no-projects, thenfm-teardown.sh domain --forcewith a stale child record naming mate's leased home (refused, no pane closed, no pool op); afterclaim-slot mateit finishes, and mate's home is never returnedLive:fm-teardown.sh materetirement (realtreehouse return, slot unleased, markers left behind), then next-crew takes the slot through realtreehouse get. Teardown is refused with 727f692'sbin/fm-wake-lib.shand finishes at the target tree (realtreehouse return, claim released)tests/fm-teardown-endpoint-safety.test.sh(targeted; includes the new persistent-home and retired-marker cases)tests/fm-secondmate-safety.test.sh(targeted; includes the seed-claim, rollback, and forced-parent persistent-home cases)✅ **Document** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.