load_tool_traces_for_plan (orchestrator.rs:4164) and write_run_manifest_with_summary (orchestrator.rs:4200) take the Arc<Mutex<ExecutionPersistence>> guard and hold it across a loop that does one or more filesystem reads per task in the plan. Any concurrent persistence user queues behind manifest assembly for the duration. Today that contention is theoretical (both run at end-of-run, after the drain), but on network-backed memory_dir each read is a round trip and the hold time scales with plan size.
The mutex mostly guards current_iteration; the read methods take &self. Dissolving the Mutex (Arc + AtomicUsize for the mutable bit) touches ~21 lock sites.
Follow-up to #421, which made the I/O inside those loops async; this is the remaining lock-shape work. #244 tracks the broader perf cleanup this belongs to.
load_tool_traces_for_plan(orchestrator.rs:4164) andwrite_run_manifest_with_summary(orchestrator.rs:4200) take theArc<Mutex<ExecutionPersistence>>guard and hold it across a loop that does one or more filesystem reads per task in the plan. Any concurrent persistence user queues behind manifest assembly for the duration. Today that contention is theoretical (both run at end-of-run, after the drain), but on network-backed memory_dir each read is a round trip and the hold time scales with plan size.The mutex mostly guards
current_iteration; the read methods take&self. Dissolving the Mutex (Arc + AtomicUsize for the mutable bit) touches ~21 lock sites.Follow-up to #421, which made the I/O inside those loops async; this is the remaining lock-shape work. #244 tracks the broader perf cleanup this belongs to.