Measured while working #11907 (PR #12076), which needed the cache's location established to control for cache warmth. Recorded because it is the distribution vector that turns a one-worktree incident into everyone's, and because it contradicts an isolation claim agents rely on.
Measured (2026-08-25)
turbo resolves the repo root through the git common directory, not the worktree:
$ head -c 80 .git
gitdir: /home/user/objectstack/.git/worktrees/objectstack-issue-11907
$ git rev-parse --git-common-dir
/home/user/objectstack/.git
$ git rev-parse --show-toplevel
/home/user/objectstack-issue-11907 <- the worktree
So a linked worktree's cache directory resolves to the primary checkout:
$ ls -d /home/user/objectstack-issue-11907/.turbo # absent
$ ls /home/user/objectstack/.turbo/cache/*.tar.zst | wc -l
53
At the time of measurement five worktrees were live in the container (objectstack, plus -issue-11671, -issue-11907, -issue-11935, -issue-11998). All five share that one cache directory. Entries written from one worktree were confirmed being replayed into another (cache hit, replaying logs <hash> for tasks this worktree never executed).
Why it is worth a record
Not proposing a fix here
Sharing the cache is plausibly deliberate (it is most of the speed-up). The gap is that nothing says so, and the isolation the worktree rules promise is read as covering it. Candidates, for triage rather than as a recommendation: document it beside the stash rule; or give each worktree its own cacheDir, trading the cross-worktree hit rate for isolation.
A manifest scan of the shared cache for the "has a dist/ with JS but zero declaration files" shape is what surfaced the poisoned entry, and is cheap enough to be worth having somewhere:
for m in $CACHE/*-manifest.json: files with '/dist/'; any .js/.mjs and no .d.ts/.d.mts => suspect
Generated by Claude Code
Measured while working #11907 (PR #12076), which needed the cache's location established to control for cache warmth. Recorded because it is the distribution vector that turns a one-worktree incident into everyone's, and because it contradicts an isolation claim agents rely on.
Measured (2026-08-25)
turbo resolves the repo root through the git common directory, not the worktree:
So a linked worktree's cache directory resolves to the primary checkout:
At the time of measurement five worktrees were live in the container (
objectstack, plus-issue-11671,-issue-11907,-issue-11935,-issue-11998). All five share that one cache directory. Entries written from one worktree were confirmed being replayed into another (cache hit, replaying logs <hash>for tasks this worktree never executed).Why it is worth a record
.git-adjacent shared state with no note anywhere.@objectstack/plugin-authbuild in a fresh worktree withOS_SKIP_DTSunset — its own typecheck then reds on a diff that never touched it #11907 travel. A worktree that hits memory pressure can cache a JS-only, declaration-lessdist/**under the hash of an ordinary full build; every other worktree at the same commit then gets that artifact on its first, clean run. That is how "a fresh worktree with a cleanpnpm install" can start out broken — the observation that made Local turbo cache served a DTS-less@objectstack/plugin-authbuild in a fresh worktree withOS_SKIP_DTSunset — its own typecheck then reds on a diff that never touched it #11907's mechanism hard to place.--forcea wider blast radius than it reads:turbo run build --filter PKG --forcere-executes the whole dependency graph and rewrites a cache entry for every task in it, in the shared directory. While reproducing Local turbo cache served a DTS-less@objectstack/plugin-authbuild in a fresh worktree withOS_SKIP_DTSunset — its own typecheck then reds on a diff that never touched it #11907 with a deliberately broken tsup DTS worker, a--forcerun intended to touch onlyplugin-authalso wrote a declaration-lesspackages/specentry (1713 files, 0 declarations) that every other worktree could then have hit. It was detected and evicted, but nothing except a hand-written manifest scan would have surfaced it.Not proposing a fix here
Sharing the cache is plausibly deliberate (it is most of the speed-up). The gap is that nothing says so, and the isolation the worktree rules promise is read as covering it. Candidates, for triage rather than as a recommendation: document it beside the stash rule; or give each worktree its own
cacheDir, trading the cross-worktree hit rate for isolation.A manifest scan of the shared cache for the "has a
dist/with JS but zero declaration files" shape is what surfaced the poisoned entry, and is cheap enough to be worth having somewhere:Generated by Claude Code