Problem
Pointing CARGO_TARGET_DIR at a shared directory from two different worktrees
of this repository produces compile errors that name symbols the source does
not contain. A build in worktree A can link against worktree B's build of a
workspace crate, so rustc reports a real-looking error against B's source
while citing line numbers in A's files.
This is a trap for the workflow AGENTS.md already documents: parallel worktrees
under .claude/worktrees/, plus a make gate that is slow from cold, makes
"reuse the warm cache" an obvious-looking optimisation. It is not safe.
Observed
While unbreaking main (PR #2000), make gate was run in a worktree with
CARGO_TARGET_DIR=/path/to/main-checkout/target to reuse a warm cache. It
failed:
error[E0004]: non-exhaustive patterns: `&stella_protocol::AgentEvent::TurnParked { .. }`
and `&stella_protocol::AgentEvent::TurnWoken { .. }` not covered
--> crates/stella-pipeline/src/replay.rs:648:11
note: `stella_protocol::AgentEvent` defined here
--> crates/stella-protocol/src/event.rs:396:4
AgentEvent::TurnParked and AgentEvent::TurnWoken exist in neither that
worktree nor the main checkout:
$ rg -uu -c 'TurnParked' crates/stella-protocol/src/ # no matches, exit 1
$ rg -uu -n 'TurnParked' /path/to/main-checkout/crates/stella-protocol/src/event.rs
# no matches
Another parallel job (four concurrent cargo/rustc processes at the time) was
building its own worktree — one that does carry those variants, plausibly the
parked-waits work — into the same target directory.
Re-running with a private target dir (unset CARGO_TARGET_DIR) compiled every
workspace crate with no such error, which is what confirms the diagnosis.
Why it is worth guarding rather than just knowing
The failure is plausible. replay.rs does match exhaustively on
AgentEvent, and adding arms for two variants is exactly what a reader would do
next. Acting on it writes arms for variants that do not exist, which then fails
to compile for a second, unrelated reason. The only tell is that the cited
symbol cannot be found in the cited file — a check nobody performs by default.
Definition of done
Any of, in preference order:
- A sentence in
AGENTS.md (near the make gate / worktree material) stating
that CARGO_TARGET_DIR must not be shared between worktrees, and that a
compile error naming an absent symbol means exactly this.
- A guard in the
Makefile's gate entrypoint that refuses to run when
CARGO_TARGET_DIR resolves outside the current worktree, with that message.
- Root-cause it properly: determine whether this is a cargo fingerprinting bug
worth reporting upstream (two workspace members sharing name+version across
source roots), and if so, file it and link back here.
Option 2 is the one that actually stops a future session losing an hour, since
the guidance in option 1 only helps someone who already reads it.
Constraints
scripts/impacted-crates.sh and the pre-push hook already reason about
scoping; a target-dir guard belongs beside them, not inside a crate.
- Do not "fix" this by making worktrees share a lockfile or a target dir on
purpose. Isolation is the property that makes parallel jobs safe here.
Verify
Two worktrees of this repo, both with CARGO_TARGET_DIR set to the same path,
building concurrently, where one carries a workspace-crate enum the other lacks.
With the guard in place, the run must refuse to start rather than emit E0004.
Problem
Pointing
CARGO_TARGET_DIRat a shared directory from two different worktreesof this repository produces compile errors that name symbols the source does
not contain. A build in worktree A can link against worktree B's build of a
workspace crate, so
rustcreports a real-looking error against B's sourcewhile citing line numbers in A's files.
This is a trap for the workflow AGENTS.md already documents: parallel worktrees
under
.claude/worktrees/, plus amake gatethat is slow from cold, makes"reuse the warm cache" an obvious-looking optimisation. It is not safe.
Observed
While unbreaking
main(PR #2000),make gatewas run in a worktree withCARGO_TARGET_DIR=/path/to/main-checkout/targetto reuse a warm cache. Itfailed:
AgentEvent::TurnParkedandAgentEvent::TurnWokenexist in neither thatworktree nor the main checkout:
Another parallel job (four concurrent
cargo/rustcprocesses at the time) wasbuilding its own worktree — one that does carry those variants, plausibly the
parked-waits work — into the same target directory.
Re-running with a private target dir (
unset CARGO_TARGET_DIR) compiled everyworkspace crate with no such error, which is what confirms the diagnosis.
Why it is worth guarding rather than just knowing
The failure is plausible.
replay.rsdoes match exhaustively onAgentEvent, and adding arms for two variants is exactly what a reader would donext. Acting on it writes arms for variants that do not exist, which then fails
to compile for a second, unrelated reason. The only tell is that the cited
symbol cannot be found in the cited file — a check nobody performs by default.
Definition of done
Any of, in preference order:
AGENTS.md(near themake gate/ worktree material) statingthat
CARGO_TARGET_DIRmust not be shared between worktrees, and that acompile error naming an absent symbol means exactly this.
Makefile's gate entrypoint that refuses to run whenCARGO_TARGET_DIRresolves outside the current worktree, with that message.worth reporting upstream (two workspace members sharing name+version across
source roots), and if so, file it and link back here.
Option 2 is the one that actually stops a future session losing an hour, since
the guidance in option 1 only helps someone who already reads it.
Constraints
scripts/impacted-crates.shand the pre-push hook already reason aboutscoping; a target-dir guard belongs beside them, not inside a crate.
purpose. Isolation is the property that makes parallel jobs safe here.
Verify
Two worktrees of this repo, both with
CARGO_TARGET_DIRset to the same path,building concurrently, where one carries a workspace-crate enum the other lacks.
With the guard in place, the run must refuse to start rather than emit E0004.