Watch
0
0
Fork
You've already forked hyperhive
0

hive-agent: key the boot-announce todo so it dedups across boots

This commit is contained in:
damocles 2026-10-04 18:02:18 +02:00 • committed by mara
commit f33a1ed660

View file

@ -18,11 +18,16 @@
//! (the old first-spawn message didn't reliably fire anyway, so unifying
//! the two loses nothing).
//!
//! Keyless on purpose: each boot is a genuinely new occurrence, not a
//! reconciled condition like `disk_watch`'s, so there's nothing to dedup
//! *against* within one store — `Todos::upsert`'s keyless path always
//! inserts a fresh row and always reports `changed`, which is exactly
//! "wake me, this happened" with no extra bookkeeping.
//! Keyed on a constant `"boot"` key, not keyless: the store (`Todos`,
//! backed by `paths::state_db()`, a sqlite file) outlives the process, so
//! a keyless insert would never dedup across boots — N harness starts
//! while the agent hasn't acked the previous row would leave N identical
//! rows, exactly the restart-storm this module replaces. With a constant
//! key and the summary text constant too, `Todos::upsert`'s content-
//! unchanged path makes a boot while the previous notice is still pending
//! a no-op (no second wake), and `reopen_if_acked = true` makes a boot
//! after the agent acked it re-open the same row and wake again. One row,
//! ever.
use tokio::sync::Notify;
@ -31,6 +36,10 @@ use crate::todos::Todos;
/// Producing subsystem marker for the boot-announce todo row.
const SUBSYSTEM: &str = "harness";
/// Dedup key for the boot-announce row — constant, so every boot targets
/// the same row instead of inserting a fresh one. See module doc.
const KEY: &str = "boot";
/// Push the "you were just (re)started" todo and wake the turn loop.
/// Best-effort: a store error is logged, never fatal to boot.
pub fn announce(label: &str, todos: &Todos, wake: &Notify) {
@ -40,8 +49,42 @@ pub fn announce(label: &str, todos: &Todos, wake: &Notify) {
off — claude's `--continue` session is intact, so prior context is \
still in your window."
);
match todos.upsert(SUBSYSTEM, None, &summary, None, false) {
match todos.upsert(SUBSYSTEM, Some(KEY), &summary, None, true) {
Ok(_) => wake.notify_one(),
Err(e) => tracing::warn!(error = ?e, "boot_announce: todo upsert failed"),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn two_boots_without_an_ack_leave_one_row() {
let dir = tempfile::tempdir().expect("tempdir");
let todos = Todos::open(&dir.path().join("state.sqlite")).expect("open");
let wake = Notify::new();
announce("a", &todos, &wake);
let rows = todos.list(Some(SUBSYSTEM)).expect("list");
assert_eq!(rows.len(), 1);
let id = rows[0].id;
// A second boot before the first notice is acked: same row, no
// duplicate.
announce("a", &todos, &wake);
let rows = todos.list(Some(SUBSYSTEM)).expect("list");
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].id, id);
// Ack it, then boot again: the row re-opens (still the same row,
// un-acked again), not a second insert.
todos.mark_done(id).expect("mark_done");
assert!(todos.list(Some(SUBSYSTEM)).expect("list").is_empty());
announce("a", &todos, &wake);
let rows = todos.list(Some(SUBSYSTEM)).expect("list");
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].id, id);
}
}