gate stale todo wakes on an emptiness check (#2678)

This commit is contained in:
damocles 2026-07-25 20:44:27 +02:00 committed by mara
commit 001ea38ea4
2 changed files with 65 additions and 3 deletions

View file

@ -223,6 +223,27 @@ impl Todos {
.collect::<rusqlite::Result<Vec<_>>>()?;
Ok(rows)
}
/// Cheap existence check — `true` when at least one todo row exists
/// (across every subsystem). Used to gate a `todo_wake` notification
/// against being turned into a turn when its payload has already been
/// drained by an earlier turn (see the serve loop's `LocalTodo` arm):
/// an `EXISTS` probe, not a full `list` + row materialization, since
/// this runs on every wake.
///
/// # Errors
///
/// Propagates the sqlite query failure.
///
/// # Panics
///
/// Panics if the connection mutex is poisoned.
pub fn has_any(&self) -> Result<bool> {
let conn = self.conn.lock().unwrap();
let any: bool =
conn.query_row("SELECT EXISTS(SELECT 1 FROM todos)", [], |row| row.get(0))?;
Ok(any)
}
}
#[cfg(test)]
@ -279,6 +300,19 @@ mod tests {
assert!(s.list(None).unwrap().is_empty());
}
#[test]
fn has_any_reflects_emptiness() {
let (_dir, s) = store();
assert!(!s.has_any().unwrap(), "fresh store has no todos");
let (id, _) = s.upsert("bash", None, "task done", None).unwrap();
assert!(s.has_any().unwrap());
s.mark_done(id).unwrap();
assert!(
!s.has_any().unwrap(),
"empty again after draining the only row"
);
}
#[test]
fn clear_subsystem_wipes_only_its_own() {
let (_dir, s) = store();