use super::{agent, nothing, tips_acked};
use crate::attention::*;
use crate::git_tree::{Agent, AgentState};
use crate::inboxview::{Deposit, InboxEntry};
const ROOT: &str = "20260906T090000Z-r001";
const CHILD: &str = "20260906T090000Z-r001-20260906T091000Z-c001";
fn resting(id: &str) -> Agent {
let mut a = agent(id);
a.state = AgentState::Quiescent;
a
}
#[test]
fn a_dispatched_conversation_s_rest_is_not_the_operator_s_turn() {
let agents = vec![resting(ROOT), resting(CHILD)];
let child = attention(&agents[1], &agents, "ws", ¬hing);
assert!(
!child.stopped,
"the parent takes this rest, not the operator"
);
assert!(!child.any(), "so the child is not on the queue at all");
let root = attention(&agents[0], &agents, "ws", ¬hing);
assert!(root.stopped, "and the conversation the operator started is");
}
#[test]
fn a_deposit_nobody_drives_raises_the_same_turn_on_the_parent() {
let mut root = resting(ROOT);
root.pending = vec![InboxEntry {
name: "c001-001.md".into(),
raw: Vec::new(),
deposit: Deposit::default(),
}];
let agents = vec![root, resting(CHILD)];
let seen = tips_acked(&[ROOT]);
let parent = attention(&agents[0], &agents, "ws", &seen);
assert!(!parent.stopped, "the rest itself is old news");
assert!(parent.mail, "but the undriven result is the turn");
assert_eq!(parent.kinds(), vec![AttentionKind::Mail]);
}
#[test]
fn every_other_signal_still_fires_on_a_dispatched_conversation() {
type Case = (fn(&mut Agent), AttentionKind);
let cases: &[Case] = &[
(|a| a.notify_oid = Some("n".into()), AttentionKind::Notify),
(|a| a.budget_oid = Some("b".into()), AttentionKind::Budget),
(
|a| a.conflicted_oid = Some("c".into()),
AttentionKind::Conflicted,
),
(
|a| {
a.held = Some(crate::control::hold::Held {
tool_use_id: "toolu_1".into(),
tool: "Bash".into(),
reason: "destructive".into(),
});
},
AttentionKind::Held,
),
];
for (mutate, kind) in cases {
let mut child = resting(CHILD);
mutate(&mut child);
let agents = vec![resting(ROOT), child];
let att = attention(&agents[1], &agents, "ws", ¬hing);
assert!(att.any(), "{kind:?} is nobody's to take but the operator's");
assert_eq!(att.kinds(), vec![*kind], "and rule 2 stays silent");
}
}
#[test]
fn a_conversation_whose_dispatcher_is_gone_is_the_operator_s_again() {
let orphan = vec![resting(CHILD)];
assert!(
attention(&orphan[0], &orphan, "ws", ¬hing).stopped,
"its dispatcher holds no ref, so nobody is coming for this rest"
);
let outside = vec![resting(&format!("{ROOT}-c0ffee"))];
assert!(
attention(&outside[0], &outside, "ws", ¬hing).stopped,
"an id litany would never mint is nobody's child here either"
);
}