Skip to content

fix(bin): trust pooled Treehouse worktrees across clones of the same origin - #2

Merged
yehezkieled merged 5 commits into
mainfrom
fm/fm-pool-trust
Oct 4, 2026
Merged

yehezkieled merged 5 commits into
mainfrom
fm/fm-pool-trust

Conversation

@yehezkieled

@yehezkieled yehezkieled commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

Intent

Work on hive on Sonnet 5.5: hive now has its own second mate home, and its Claude workers must be able to launch from that home.

Observed 2026-10-04: the hive second mate (home /.treehouse/firstmate-7bab20/1/firstmate, its own hive clone under that home's projects/hive) tried to spawn a Claude Sonnet 5.5 worker for hive-cutover. The shared treehouse worktree pool for hive (/.treehouse/hive-4f4202) handed out a worktree of the MAIN home's hive clone (~/firstmate/projects/hive), and Claude's workspace-trust pre-registration (bin/fm-claude-trust.sh, called from bin/fm-spawn.sh) refused it as not belonging to the second mate home's own clone, so the spawn stopped. Nothing launched, no work lost.

What Changed

  • Allow Claude trust registration for Treehouse pooled worktrees from another clone with the same origin, registering trust on the slot’s actual canonical checkout while rejecting unrelated origins and cross-clone worktrees outside a pool.
  • Share origin-identity helpers between trust checks and Treehouse pool recognition and locking; include the new dependency in teardown checks and test fixtures.
  • Add regression coverage for cross-clone pool acceptance and rejection, and update script and Orca documentation.

Risk Assessment

✅ Low: The change narrowly accepts same-origin pooled worktrees while preserving structural refusals and existing import-consent controls.

Testing

Seven focused CLI scenarios passed with product output and persisted configuration evidence. No full suite or lint ran. Authenticated Claude launch was not exercised because of the write boundary.

  • Live validation: ⚠️ inconclusive - 7 of 8 scenarios driven live against the product
Scenario Result Live Evidence
Register another clone's same-origin pooled worktree and trust its canonical checkout ✅ pass live trust-cli.txt: same-origin-pool
Register an ordinary worktree belonging to the launching project ✅ pass live trust-cli.txt: same-clone-existing
Reject another clone's non-pool worktree without changing Claude configuration ✅ pass live trust-cli.txt: no-pool
Reject pooled worktrees when origin identity differs or is absent ✅ pass live trust-cli.txt: unrelated-origin and missing-origin
Reject a primary checkout presented as an isolated worker worktree ✅ pass live trust-cli.txt: primary-checkout
Carry canonical checkout import approval forward and preserve explicit declines ✅ pass live trust-cli.txt: canonical-consent and canonical-decline
Recognize same-origin cross-clone pool slots while rejecting unrelated origins ✅ pass live trust-cli.txt: Pool-slot executable recognition
Launch an authenticated Claude worker from a secondmate home into another clone's pooled slot and reach its brief ⏸️ untested no The workspace boundary prohibits normal Claude user-configuration writes and an external disposable secondmate home. Completing this requires explicit permission for those writes; the earlier decision…
Evidence: Trust CLI output and persisted Claude configuration

Source: Trust CLI output and persisted Claude configuration

same-origin-pool
$ bash bin/fm-claude-trust.sh .trust-live-drivrl35/pool/1/project .trust-live-drivrl35/second
trusted: ~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/pool/1/project
trusted (project root): ~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/main
exit=0
{"projects": {"~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/main": {"hasTrustDialogAccepted": true}, "~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/pool/1/project": {"hasTrustDialogAccepted": true}}}
same-clone-existing
$ bash bin/fm-claude-trust.sh .trust-live-drivrl35/plain .trust-live-drivrl35/main
trusted: ~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/plain
trusted (project root): ~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/main
exit=0
{"projects": {"~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/main": {"hasTrustDialogAccepted": true}, "~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/plain": {"hasTrustDialogAccepted": true}}}
no-pool
$ bash bin/fm-claude-trust.sh .trust-live-drivrl35/plain .trust-live-drivrl35/second
error: refusing to pre-register Claude trust: '~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/plain' is not a worktree of project '~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/second'
exit=1
Claude store unchanged after refusal
unrelated-origin
$ bash bin/fm-claude-trust.sh .trust-live-drivrl35/pool/1/project .trust-live-drivrl35/other
error: refusing to pre-register Claude trust: '~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/pool/1/project' is not a worktree of project '~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/other'
exit=1
Claude store unchanged after refusal
primary-checkout
$ bash bin/fm-claude-trust.sh .trust-live-drivrl35/main .trust-live-drivrl35/second
error: refusing to pre-register Claude trust: '~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/main' is a primary checkout, not an isolated worktree
exit=1
Claude store unchanged after refusal
missing-origin
$ bash bin/fm-claude-trust.sh .trust-live-drivrl35/pool/1/project .trust-live-drivrl35/second
error: refusing to pre-register Claude trust: '~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/pool/1/project' is not a worktree of project '~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/second'
exit=1
Claude store unchanged after refusal
canonical-consent
$ bash bin/fm-claude-trust.sh .trust-live-drivrl35/pool/1/project .trust-live-drivrl35/second
trusted: ~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/pool/1/project
trusted (project root): ~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/main
exit=0
{"projects": {"~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/main": {"hasClaudeMdExternalIncludesApproved": true, "hasClaudeMdExternalIncludesWarningShown": true, "hasTrustDialogAccepted": true}, "~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/pool/1/project": {"hasClaudeMdExternalIncludesApproved": true, "hasClaudeMdExternalIncludesWarningShown": true, "hasTrustDialogAccepted": true}}, "unrelated": "preserve"}
canonical-decline
$ bash bin/fm-claude-trust.sh .trust-live-drivrl35/pool/1/project .trust-live-drivrl35/second
error: project entry for ~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/main in ~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/canonical-decline/.claude.json already declined external CLAUDE.md imports; refusing to override that consent. To recover, remove hasClaudeMdExternalIncludesApproved and hasClaudeMdExternalIncludesWarningShown from that project entry and approve the imports dialog interactively once
error: refusing to pre-register Claude trust: could not record trust for '~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/pool/1/project' and project '~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/main' in '~/.no-mistakes/worktrees/e677c3fe7f2c/01M44FNJB4995EJG555EPD89QP/.trust-live-drivrl35/canonical-decline/.claude.json'
exit=1
Claude store unchanged after refusal
Pool-slot executable recognition: same-origin cross-clone exit=0
Pool-slot executable recognition: unrelated origin exit=1
All behavioral assertions passed; disposable fixtures removed.
- Outcome: ⚠️ 1 warning across 1 run (1m29s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

⚠️ **Test** - 1 warning
  • ⚠️ live validation verdict: inconclusive (7 of 8 scenarios were driven live against the product); untested: Launch an authenticated Claude worker from a secondmate home into another clone's pooled slot and reach its brief
  • Live validation: ⚠️ inconclusive - 7 of 8 scenarios driven live against the product
Scenario Result Live Evidence
Register another clone's same-origin pooled worktree and trust its canonical checkout ✅ pass live trust-cli.txt: same-origin-pool
Register an ordinary worktree belonging to the launching project ✅ pass live trust-cli.txt: same-clone-existing
Reject another clone's non-pool worktree without changing Claude configuration ✅ pass live trust-cli.txt: no-pool
Reject pooled worktrees when origin identity differs or is absent ✅ pass live trust-cli.txt: unrelated-origin and missing-origin
Reject a primary checkout presented as an isolated worker worktree ✅ pass live trust-cli.txt: primary-checkout
Carry canonical checkout import approval forward and preserve explicit declines ✅ pass live trust-cli.txt: canonical-consent and canonical-decline
Recognize same-origin cross-clone pool slots while rejecting unrelated origins ✅ pass live trust-cli.txt: Pool-slot executable recognition
Launch an authenticated Claude worker from a secondmate home into another clone's pooled slot and reach its brief ⏸️ untested no The workspace boundary prohibits normal Claude user-configuration writes and an external disposable secondmate home. Completing this requires explicit permission for those writes; the earlier decision…
  • Executed bash bin/fm-claude-trust.sh <worktree> <project> against disposable real Git clones and linked worktrees with worktree-local Claude stores.
  • Parsed generated .claude.json to verify canonical trust, consent propagation, unrelated-key preservation, and unchanged stores after refusals.
  • Executed fm_treehouse_pool_slot through bash for same-origin and unrelated-origin clones.
  • Ran command -v claude; removed all disposable worktree fixtures.
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

hezki added 3 commits October 4, 2026 23:38
Treehouse shares one pool among every clone of an origin, so a claude spawn
from a secondmate home could be handed a slot of another home's clone and
fm-claude-trust refused it. Accept a pooled same-origin worktree, keep every
existing refusal, and let fm_treehouse_pool_slot recognize such slots too.
… new library, bin/fm-git-origin-lib.sh. Every place that ships the wake lib together with its dependencies (fm-wake-lib.sh plus fm-path-lib.sh) never got the new file. Sourcing therefore failed with "fm-git-origin-lib.sh: No such file or directory", which broke the failing tests in shards 2, 3, 4, 6 and 8. Invariant: any set of files that ships fm-wake-lib.sh must also ship every library it sources. I found every such set by grepping for fm-path-lib.sh, and fixed each one the same way, by adding fm-git-origin-lib.sh next to fm-path-lib.sh: - bin/fm-teardown.sh: its required-source preflight list. - 12 test files, in their fixture copy/link lists: fm-turnend-guard (2 sites), fm-claude-stop-autoarm, fm-session-lock-ancestry, fm-afk-return, fm-mail-check, fm-gotmp (2 sites), fm-remote-transport-lanes, fm-remote-backlog-handoff, fm-pi-branch-extension, fm-cursor-primary, fm-extension-binding. I did not change the trust or wake logic. Verified locally, all passing (exit 0, no "not ok"): fm-turnend-guard, fm-claude-stop-autoarm, fm-afk-return, fm-gotmp, fm-remote-backlog-handoff, fm-remote-transport-lanes, fm-pi-branch-extension, fm-calm-pi-extension, fm-extension-binding, fm-mail-check, fm-cursor-primary, fm-claude-trust and fm-teardown-endpoint-safety. That covers every test file that failed in CI. fm-extension-binding finished in only 5 seconds, and I did not check whether it skipped part of its run. bin/fm-lint.sh also passes with ShellCheck 0.11.0 and actionlint 1.7.12. fm-session-lock-ancestry fails locally with "the pty-host was not reparented to init", but it fails the same way on the unmodified tree, so that is this local environment, not this change. It did not fail in CI
@yehezkieled yehezkieled changed the title fix(bin): trust pooled Treehouse worktrees from another clone of the same origin fix(bin): trust pooled Treehouse worktrees across clones of the same origin Oct 4, 2026
@yehezkieled
yehezkieled merged commit 74f428f into main Oct 4, 2026
20 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.

2 participants