Context
Found during the 2026-07-27 concurrency work while auditing PersistenceTask (src/persistence/task.rs); never observed in practice (theoretical, nanosecond-scale), never fixed. Filing so it does not get lost.
The window
wait_for_ops returns when all three are true: queue.len() == 0, analyzer_inner_wt.count() == 0, !analyzer_in_progress.
The engine task's idle transition is:
engine_progress_notify.notify_waiters();
task_analyzer_in_progress.store(false, Ordering::Release);
let res = Some(engine_queue.pop().await); // blocks; pop decrements len BEFORE returning
task_analyzer_in_progress.store(true, Ordering::Release);
Between pop() returning (queue len already decremented to 0, op held in a local variable, not yet in the analyzer) and store(true), all three conditions can be simultaneously true. A wait_for_ops caller checking in exactly that window returns while one operation is still un-applied. If the caller then drops the runtime (test block_on scope ending), the op is lost; if it reads on-disk state, it reads stale state.
Mitigating factors: the window is a few instructions wide; the 0010 queue swap made len increment before enqueue on the push side, which errs conservatively; 100+ measured full-suite runs never hit it. But it is a real hole in the barrier semantics.
Suggested fix
Make the busy flag cover the pop itself — e.g. a Queue::pop_busy(&self, busy: &AtomicBool) that loops:
loop {
busy.store(true, Release);
if let Some(op) = self.immediate_pop() { return op; }
busy.store(false, Release);
self.notify.notified().await;
}
Then there is no instant where an op has left the queue while busy is false. (Registering notified() after the failed pop is the same lost-wakeup-safe pattern the current pop uses; tokio Notify stores a permit.)
Verification hints
Hard to hit natively; a loom-style or targeted test would inject a yield between pop and store. Otherwise verify by review plus the usual suite (all wait_for_ops-based tests, ~430 tests, 4s warm).
Context
Found during the 2026-07-27 concurrency work while auditing
PersistenceTask(src/persistence/task.rs); never observed in practice (theoretical, nanosecond-scale), never fixed. Filing so it does not get lost.The window
wait_for_opsreturns when all three are true:queue.len() == 0,analyzer_inner_wt.count() == 0,!analyzer_in_progress.The engine task's idle transition is:
Between
pop()returning (queue len already decremented to 0, op held in a local variable, not yet in the analyzer) andstore(true), all three conditions can be simultaneously true. Await_for_opscaller checking in exactly that window returns while one operation is still un-applied. If the caller then drops the runtime (testblock_onscope ending), the op is lost; if it reads on-disk state, it reads stale state.Mitigating factors: the window is a few instructions wide; the 0010 queue swap made
lenincrement before enqueue on the push side, which errs conservatively; 100+ measured full-suite runs never hit it. But it is a real hole in the barrier semantics.Suggested fix
Make the busy flag cover the pop itself — e.g. a
Queue::pop_busy(&self, busy: &AtomicBool)that loops:Then there is no instant where an op has left the queue while
busyis false. (Registeringnotified()after the failed pop is the same lost-wakeup-safe pattern the currentpopuses; tokioNotifystores a permit.)Verification hints
Hard to hit natively; a loom-style or targeted test would inject a yield between pop and store. Otherwise verify by review plus the usual suite (all
wait_for_ops-based tests, ~430 tests, 4s warm).