diff --git a/hive-agent/src/todo_server.rs b/hive-agent/src/todo_server.rs index a45e4784..1336f1fb 100644 --- a/hive-agent/src/todo_server.rs +++ b/hive-agent/src/todo_server.rs @@ -165,10 +165,26 @@ fn dispatch( bus: &Bus, ) -> Response { match req { - Request::UpsertTodo { .. } - | Request::ClearTodo { .. } - | Request::ListTodos { .. } - | Request::MarkTodoDone { .. } => dispatch_todo(req, store, wake), + Request::UpsertTodo { + subsystem, + key, + summary, + source, + } => upsert_todo( + store, + wake, + &subsystem, + key.as_deref(), + &summary, + source.as_deref(), + ), + Request::ClearTodo { + subsystem, + key, + all, + } => clear_todo(store, &subsystem, key.as_deref(), all), + Request::ListTodos { subsystem } => list_todos(store, subsystem.as_deref()), + Request::MarkTodoDone { id } => mark_todo_done(store, id), Request::StoreReminder { message, timing, @@ -221,61 +237,68 @@ fn dispatch( } } -/// Todo-family requests (loose-ends v2). `req` is guaranteed by [`dispatch`] -/// to be one of the four todo variants; any other variant is a caller bug. -fn dispatch_todo(req: Request, store: &Todos, wake: &Notify) -> Response { - match req { - Request::UpsertTodo { - subsystem, - key, - summary, - source, - } => match store.upsert(&subsystem, key.as_deref(), &summary, source.as_deref()) { - Ok((id, changed)) => { - tracing::debug!(subsystem = %subsystem, key = ?key, id, changed, "todo upsert"); - if changed { - wake.notify_one(); - } - Response::Ok +/// `UpsertTodo` handler: writes/refreshes a todo row, logs the outcome, and +/// fires `wake` on a new-or-changed upsert so the serve loop runs a turn. +fn upsert_todo( + store: &Todos, + wake: &Notify, + subsystem: &str, + key: Option<&str>, + summary: &str, + source: Option<&str>, +) -> Response { + match store.upsert(subsystem, key, summary, source) { + Ok((id, changed)) => { + tracing::debug!(%subsystem, ?key, id, changed, "todo upsert"); + if changed { + wake.notify_one(); } - Err(e) => err(&e), - }, - Request::ClearTodo { - subsystem, - key, - all, - } => { - let result = if all { - store.clear_subsystem(&subsystem) - } else { - store.clear(&subsystem, key.as_deref()) - }; - match result { - Ok(count) => { - tracing::debug!(subsystem = %subsystem, key = ?key, all, count, "todo clear"); - Response::Acked { - count: u64::try_from(count).unwrap_or(0), - } - } - Err(e) => err(&e), + Response::Ok + } + Err(e) => err(&e), + } +} + +/// `ClearTodo` handler: drops one keyed todo, or every todo in `subsystem` +/// when `all` is set. +fn clear_todo(store: &Todos, subsystem: &str, key: Option<&str>, all: bool) -> Response { + let result = if all { + store.clear_subsystem(subsystem) + } else { + store.clear(subsystem, key) + }; + match result { + Ok(count) => { + tracing::debug!(%subsystem, ?key, all, count, "todo clear"); + Response::Acked { + count: u64::try_from(count).unwrap_or(0), } } - Request::ListTodos { subsystem } => match store.list(subsystem.as_deref()) { - Ok(todos) => Response::LooseEnds { - loose_ends: todos.into_iter().map(to_loose_end).collect(), - }, - Err(e) => err(&e), + Err(e) => err(&e), + } +} + +/// `ListTodos` handler: read-only, so no debug logging — not relevant to +/// diagnosing wake behaviour. +fn list_todos(store: &Todos, subsystem: Option<&str>) -> Response { + match store.list(subsystem) { + Ok(todos) => Response::LooseEnds { + loose_ends: todos.into_iter().map(to_loose_end).collect(), }, - Request::MarkTodoDone { id } => match store.mark_done(id) { - Ok(count) => { - tracing::debug!(id, count, "todo mark-done"); - Response::Acked { - count: u64::try_from(count).unwrap_or(0), - } + Err(e) => err(&e), + } +} + +/// `MarkTodoDone` handler: marks a single todo done by id. +fn mark_todo_done(store: &Todos, id: i64) -> Response { + match store.mark_done(id) { + Ok(count) => { + tracing::debug!(id, count, "todo mark-done"); + Response::Acked { + count: u64::try_from(count).unwrap_or(0), } - Err(e) => err(&e), - }, - _ => unreachable!("dispatch only routes todo variants here"), + } + Err(e) => err(&e), } }