Conversation
load_settings_in and load_projects_in resolve the record file for the read, then re-resolve it through global_dir() for the write-back. TERMIC_DATA_DIR is process-global and tests run in threads, so a with_scratch_data_dir window can flip it between the two resolutions: the migrated write lands in a settings.json/projects.json the load never read from. That clobbers the scratch a neighbouring test just wrote (the intermittent agent_hooks::...status_line failure), and flipped the other way drops test content into the developer's real data dir. Keep the already-resolved path for the write-back; the callers' doc comments already promise the write lands where the records came from. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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.
What this fixes
An intermittent full-suite failure simion saw while verifying #353:
agent_hooks::tests::a_clones_status_line_is_read_from_its_own_config_dirfails ~once percargo testrun, passes alone, pre-existing onmain.The mechanism
with_scratch_data_dirserializes tests that redirectTERMIC_DATA_DIR, butTERMIC_DATA_DIRis process-global: tests that readglobal_dir()-derived paths without the lock can still straddle a neighbour's scratch window.That alone is a known hazard — but it produces writes through one specific path: the migration write-backs.
Both
load_settings_inandload_projects_inresolve the record file once for the read, run their migrations, and then callsave_*_in(id, …)— which re-resolvesglobal_dir()a second time at write time. If a scratch window opens in the gap, the write lands in a directory the load never read from:load_settings_innerresolves env → real/fixture path, reads a legacy-shapedsettings.json, setsmigrated→ write-back re-resolves → a scratch window just opened → the migrated copy lands over that scratch'ssettings.json, wiping the agent the victim test just saved → itsnext-claudelookup falls back to~/.claude→ assert fails.Why not lock the accessor instead
Gating
global_dir()(or the settings accessors) onDATA_DIR_LOCKdeadlocks:PORT_ALLOC_LOCKis held across task-create flows that callload_settings_inner, while scratch closures call task-creation paths that needPORT_ALLOC_LOCK.The fix
Both write-backs now write to the path already resolved for the read (
save_settings_at(&f, …)/save_projects_at(&f, …)), which is what their own comments already claim — "the write has to land in the profile the records came from".save_settings_in/save_projects_inkeep their signatures for explicit saves.Honest caveats
set_var/save_settings_*/global_dirwriter that can inject a foreignsettings.jsoninto a live scratch without an unlocked writer call.TERMIC_DATA_DIRpoints at mid-window (wrong data for their asserts — the "different test each time" signature from the comment intest_support.rs). Closing that needs the accessor gating ruled out above, or dropping the process-global seam entirely.Test plan
cargo test— 1216 pass on this branch