Watch
0
0
Fork
You've already forked hyperhive
0

hive-matrix-mcp: test the retry path and the once-only todo clear

The startup todo wipe runs once in main, before any sync loop, so a
secondary that comes up later cannot clear the todos the running
accounts' sweeps already deduped. Nothing tested that.

main now reads HIVE_AGENT_SOCKET once at startup and hands the path to
wake::clear_all_todos, the only way left to wipe the whole set;
send_todo_clear clears one key only. bring_up_account is split into
restore_account (everything that talks to the network) and the
synchronous account_sync_loop, and the retry path restores with the
former and builds the loop itself. Neither the loop nor the retry path
is given the socket.

The new test runs a late secondary's retry and its sync loop against a
listener standing in for the harness socket, after startup's wipe, and
asserts the harness saw exactly one wipe. It pins that seam, not every
place in restore_account a wipe could be added.
This commit is contained in:
atlas 2026-10-14 05:44:06 +02:00 • committed by mara
commit 739c35757a
4 changed files with 140 additions and 72 deletions

View file

@ -23,7 +23,8 @@ const TODO_SOCKET_RETRY: Retry = Retry::None;
/// go — distinct from the host-served control socket used by `send_wake`.
/// `None` when unset/empty, in which case todo sends are a best-effort
/// no-op (a standalone daemon without the harness socket).
fn agent_socket() -> Option<std::path::PathBuf> {
#[must_use]
pub fn agent_socket() -> Option<std::path::PathBuf> {
std::env::var_os("HIVE_AGENT_SOCKET")
.filter(|v| !v.is_empty())
.map(std::path::PathBuf::from)
@ -52,26 +53,40 @@ pub async fn send_todo_upsert(key: &str, summary: impl AsRef<str>) -> Result<()>
notify(&socket, &payload, TODO_SOCKET_RETRY).await
}
/// Clear matrix-subsystem todos on the harness's in-agent socket. `key =
/// Some(room)` clears one room's todo (it was read); `all = true` wipes the
/// whole matrix set (cancel-and-recreate on daemon restart). Best-effort:
/// a no-op when `HIVE_AGENT_SOCKET` isn't configured.
/// Clear the matrix-subsystem todo `key` on the harness's in-agent socket
/// (its room was read, or its invite resolved). Best-effort: a no-op when
/// `HIVE_AGENT_SOCKET` isn't configured.
///
/// # Errors
///
/// Returns an error on socket connect failure, serialisation failure,
/// or I/O error writing to or reading from the socket.
pub async fn send_todo_clear(key: Option<&str>, all: bool) -> Result<()> {
pub async fn send_todo_clear(key: &str) -> Result<()> {
let Some(socket) = agent_socket() else {
return Ok(());
};
send_clear(&socket, Some(key), false).await
}
/// Wipe the whole matrix todo set on `socket` (cancel-and-recreate on daemon
/// start). Takes the socket instead of reading `HIVE_AGENT_SOCKET`, so only
/// code handed the path can wipe the set.
///
/// # Errors
///
/// As [`send_todo_clear`].
pub async fn clear_all_todos(socket: &std::path::Path) -> Result<()> {
send_clear(socket, None, true).await
}
async fn send_clear(socket: &std::path::Path, key: Option<&str>, all: bool) -> Result<()> {
let payload = serde_json::json!({
"cmd": "clear_todo",
"subsystem": "matrix",
"key": key,
"all": all,
});
notify(&socket, &payload, TODO_SOCKET_RETRY).await
notify(socket, &payload, TODO_SOCKET_RETRY).await
}
/// Format a wake-message body from a list of per-room unread summaries.