Isolate local harness tests and preserve workspace settings keys
Problem
LocalHarness defaults could make tests read personal MCP settings. Workspace selection also skipped equivalent .claude.json project keys when the configured path, canonical Windows verbatim path, case or separators differed. Stdio failure tests accepted Unsupported without exercising executable lookup.
Design
- Give test_support::local_harness_config an owned temporary settings home and explicit temporary codex_home. Repoint every local test constructor; verify ownership, paths and cleanup without reading the ambient home.
- Preserve the configured workspace for selection and the canonical path for process startup. The shared settings selector compares components across ordinary/verbatim drive and UNC forms, Windows case differences and separator aliases.
- Gate stdio scenarios on mcp-stdio, retain the independent HTTP scenario, and assert actual process not_found causes. Keep both HTTP tool wire payloads above the 1 KiB catalog limit.
Decisions
- Project-key comparison allocates no normalized strings and performs no extra filesystem calls. POSIX case and literal backslashes remain significant; drive-relative, local rooted, UNC and device spellings remain distinct. Character case comparison does not expand one character into several.
- The test-support guard owns its temporary home until settings loading finishes or the config is dropped. It depends only on fixture-owned paths, including when HOME names a nonexistent directory. Production user settings and CODEX_HOME behavior are unchanged.
- The existing HTTP fixture's accidental 3 KiB query reached 28,942 tokens against a 28,672-token ceiling. Its intended 2 KiB query fits while explicit assertions preserve the catalog-versus-tool-I/O regression. Model capacity, accounting, compaction and transport limits are unchanged.
- Merge main only to resolve the reported conflict: use its ToolCall::new event shape, and route its three newly added local fixture constructors through the same isolated settings helper.
- Configuration files remain the source of truth. No new settings store, transport, protocol, synchronization path or public path API. The standalone fuzz workspace includes the production comparator directly and avoids building the SDK for fuzzing.
Deletions
Remove raw LocalHarnessConfig::new calls from every local test fixture; only the shared helper uses it. Replace exact project-path equality and the test's ambient-home canonicalization. Remove the weak generic stdio failure assertion. Overall: 26 files, +578/-64, net +514 lines; this review fix is +374/-8 (includes 89 lockfile lines and fuzz tooling).
Tests run
Same native feature set throughout: filesystem-local,native-execution,terminal,mcp-http,test-support, with defaults (including hooks and stdio).
- bb1: merged-head native settings 17/17, 0.055 s; local MCP 4/4, 0.522 s; isolation property with HOME set to an absent fixture directory 1/1, 0.025 s; admission 2/2, 0.801 s; private task-file follow/reopen 1/1, 0.205 s. Binaries run directly; zero-test filters and suites over 10 s are rejected.
- Windows through lb.ps1: merged-head cargo check -p acyclic-harness --lib --tests passed; focused native_settings suite 16/16, 0.152 s before the merge (the comparator and properties are unchanged). Includes real non-verbatim/case/separator selection and relative-workspace drive/UNC regressions.
- Three shrinking properties cover drive/UNC spelling round trips, separators, verbatim prefixes, Unicode case, equivalence laws and root separation.
- bb1: cargo +nightly-2026-07-01 fuzz run --dev --target x86_64-unknown-linux-gnu --fuzz-dir rust/crates/harness/fuzz-settings workspace_key -- -max_total_time=2 -timeout=1 -max_len=4096: 16,017 executions in 3 s, no failures; four seed files checked in. GNU is explicit because the box's default musl target cannot use ASan.
- Caller search, rustfmt --check, git diff --check, LF/NUL and source/test size checks passed.