fix(agent-core): lock ORGII_HOME while the workspace test reads it - #1181
Merged
Conversation
`resolved_workspace_falls_back_to_personal_workspace` reads process-global `ORGII_HOME` twice — once inside `ResolvedAgent::resolve` and once via `app_paths::personal_workspace()` — and compares the results. It mutates no environment, so it took no lock; a sandboxed test repointing `ORGII_HOME` between the two reads makes them disagree and the assertion fails. The reported left/right flip direction run to run, which is the tell. Takes `test_helpers::test_env::lock_home()`, which `test_env`'s own docs designate for exactly this case: a test that needs the serialization but manages no env of its own.
This was referenced Sep 1, 2026
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.
Problem
core::definitions::resolved::tests_extended::resolved_workspace_falls_back_to_personal_workspacefails intermittently:
The two sides are the same function evaluated at two different moments:
ORGII_HOMEis process-global.test_helpers::test_envalready exists toserialize access to it, and every test that mutates it goes through
test_env::sandbox(). This test mutates nothing — it observes whateverORGII_HOMEhappens to be — so it takes no lock, and a sandboxed test runningin parallel can repoint the variable between the two reads. Whichever read lands
first sees the old value and the assertion fails. The error message flips
direction depending on which side won the race, which is the signature of this
being a timing artifact rather than a logic bug.
test_env's own docs already anticipate this case:That is exactly this test: a reader of the ambient value.
Solution
Take
test_helpers::test_env::lock_home()at the top of the test, with acomment explaining why a test that sets no environment still needs the lock.
agent_corealready dev-depends ontest_helpers, and the guard ispoison-tolerant, so a panicking sandbox test cannot cascade into this one.
Six added lines in one
#[cfg(test)]block; no production code is touched, andno other test's behavior changes.
Resulting invariant: the test's two reads of
ORGII_HOMEobserve the samevalue, so its assertion depends only on
ResolvedAgent's fallback logic — thething it is actually testing.
Potential risks
holding
lock_home(). It does no I/O and the suite time is unchanged withinnoise (14.5s → 14.9s for
agent_core --lib, inside run-to-run variance).lock_home()is not reentrant. If this test later grows atest_env::sandbox()call it would deadlock against itself. It has no reasonto — it deliberately observes the ambient value — but the added comment says
so.
a sweep for every test that reads
ORGII_HOME-derived paths without the lockis a larger audit and is not attempted here. Scoping it this way keeps the
change reviewable against a reproduction.
reader-side race.
test_env's invariant ("every test that mutatesORGII_HOMEorHOMEMUST go throughsandbox()") is still what holds therest together.
Verification
The race was reproduced deterministically before fixing it. On unmodified
develop, inserting a 400ms sleep between the two reads — widening theexisting window, changing no logic — makes it fail every run with the CI
assertion:
The same widened window passes with this fix applied:
test result: ok. 3189 passed; 0 failed; 2 ignored. That is what shows thelock closes the race rather than the sleep reshuffling the schedule. The
experimental sleep is not in this diff (
grep -c EXPERIMENT→ 0).cargo test -p agent_core --lib— 3,189 passed, 0 failed, 2 ignored.cargo clippy -p agent_core --all-targets -- -D warnings— exit 0.Run with a private
CARGO_TARGET_DIR: two ORGII worktrees resolve thisworkspace to the same build-script
OUT_DIR, so a shared target dir canverify the wrong worktree.
Not run: no TypeScript changes, so no
pnpm typecheck/vitest. No UIchange, so no screenshots. Full-workspace
cargo testwas not re-run — thisdiff is
#[cfg(test)]-only inside one test function.Pre-commit hook trailer is absent. Committed from a
git worktree, where.husky/_/husky.shis gitignored and therefore never created bygit worktree add. That trailer is structurally always missing in a worktreeand carries no signal; the check it would have run for a Rust diff is
cargo clippy, run manually above.