#3319 — ork shipped the worktree idiom its own docs call broken

Filed as one line in session-registrar. It was fourteen recommendation sites across seven files, and the two worst reach the model rather than the operator.

The mechanism

  git worktree add ../myrepo-task -b feat/x origin/main   ← succeeds
  cd ../myrepo-task                                       ← reports success

  Shell cwd was reset to /path/to/myrepo                  ← silent

  ...every later command now runs in the PRIMARY tree.

  A sibling path sits OUTSIDE the session's project directory, and the harness
  bounces any cd that leaves it. Nothing errors. Nothing warns.
This is the failure behind platform#9870: work was committed onto another agent's branch, with that agent's uncommitted files sitting in the tree. The repo has documented the idiom as broken since 2026-08-06 while still shipping it in seven files.

Before / after

BEFORE
git worktree add ../myrepo-task \
    -b feat/x origin/main
cd ../myrepo-task

# sibling → outside the project dir
# cd is silently reverted
AFTER
WT=$(~/.claude/hooks/worktree-new.sh \
       task feat/x) && cd "$WT"
pwd   # confirm — the reset is silent

# .worktrees/task → inside the repo
# helper refuses an existing path

Every site, and who it taught

FileReachesWhat it said
lib/tool-invocation-rules.ts:95 MODEL Fired on Agent(isolation:'worktree') and told the model to pre-create a sibling, then prefix the prompt FIRST: cd <path>. It fires exactly when a session is about to spawn parallel work.
skills/implement/references/worktree-workflow.md MODEL 7 occurrences, including cd ../myapp-auth in three separate flows.
skills/implement/references/team-worktree-setup.md MODEL 3 worktree-adds plus a directory diagram drawn around the sibling layout.
skills/implement/references/agent-teams-phases.md MODEL Told the lead to hand each teammate a sibling path over SendMessage.
skills/implement/references/agent-teams-full-stack.md MODEL 3 worktree-adds plus the per-teammate assignment table.
lifecycle/session-registrar.ts:246 OPERATOR The peer-collision warning — printed at the moment a session learns a peer exists, i.e. precisely when someone is about to act on it.
lifecycle/sweep-stale-worktrees.ts:10 HISTORY Kept. Describes the #1884 symptom this sweeper cleans up after. Now annotated "do not copy". Rewriting it would misrepresent the history.

The test asserted the bug

BEFORE
expect(warning)
  .toContain('git worktree add')

Locked the defect in as a contract. It passed, always, and could never have caught this.

AFTER
expect(warning)
  .toContain('worktree-new.sh')
expect(warning)
  .not.toMatch(/cd \.\.\//)
expect(warning)
  .not.toMatch(/git worktree add \.\.\//)

Both negatives fail against origin/main, which emits exactly those strings.

Verified

 origin/main emits `git worktree add ../${repoName}-task` and `cd ../${repoName}-task`
 HEAD emits neither — only the helper
 session-registrar tests    9 passed / 9
 npm run typecheck          rc=0
 npm run build              rc=0
 residual sweep             only the 2 annotated historical lines remain

While this change was being written, the un-rebuilt rule fired on a live Agent(isolation:'worktree') call and printed the sibling idiom verbatim — the bug demonstrating itself at the exact moment the issue says it is most expensive.