use std::path::Path;
use super::*;
use crate::boundary::tests::{agent as agent_row, snapshot};
use crate::control::hold::Held;
use crate::git_tree::AgentState;
use crate::ui_state::UiState;
fn ui() -> UiState {
UiState::open(std::path::PathBuf::from("/nonexistent/ui.json"))
}
const ROOT: &str = "20260801T000000Z-r0";
const CHILD: &str = "20260801T000000Z-r0-20260801T000100Z-c0";
#[test]
fn a_member_reads_its_own_state_and_its_conversations_name() {
let ws = Path::new("/w");
let mut root = agent_row(ROOT, AgentState::Quiescent, 1);
root.name = Some("pennant".to_owned());
let mut child = agent_row(CHILD, AgentState::InFlight, 2);
child.tip_oid = "b".repeat(40);
let snap = snapshot(ws, "alba", vec![root, child], vec![]);
let view = agent(&snap, &ui(), ws, CHILD, 0);
assert_eq!(view.agent_id, CHILD);
assert_eq!(view.root, ROOT);
assert_eq!(view.ancestors, vec![ROOT.to_owned()]);
assert_eq!(view.name, "pennant");
assert!(!view.display_only);
assert_eq!(view.tip, "b".repeat(40));
assert_eq!(view.state, AgentState::InFlight);
assert_eq!(view.flight, Some(crate::nav::convs::Flight::Inference));
assert!(view.stoppable);
assert!(!view.stop_children);
let at_root = agent(&snap, &ui(), ws, ROOT, 0);
assert_eq!(at_root.state, AgentState::Quiescent);
assert!(at_root.ancestors.is_empty(), "a root opens nothing");
assert!(at_root.present && at_root.nudgeable && at_root.held.is_none());
assert!(!at_root.stoppable);
assert!(at_root.stop_children);
assert_eq!(at_root.flight, view.flight, "one conversation, one class");
}
#[test]
fn the_marks_and_the_legacy_naming_rung_are_stated() {
let ws = Path::new("/w");
let mut root = agent_row(ROOT, AgentState::Stopped, 1);
root.goal_name = Some("relic".to_owned());
root.notify_oid = Some("c".repeat(40));
root.held = Some(Held {
tool_use_id: "toolu_1".to_owned(),
tool: "Bash".to_owned(),
reason: "unconfined".to_owned(),
});
let snap = snapshot(ws, "alba", vec![root], vec![]);
let view = agent(&snap, &ui(), ws, ROOT, 0);
assert_eq!(view.name, "relic");
assert!(view.display_only);
assert_eq!(view.marks, vec![AgentMark::Notified, AgentMark::Held]);
assert_eq!(view.held.map(|h| h.tool), Some("Bash".to_owned()));
}
#[test]
fn the_forest_answers_every_fact_the_seat_reads_off_the_selection() {
let ws = Path::new("/w");
let mut root = agent_row(ROOT, AgentState::Quiescent, 1);
root.name = Some("pennant".to_owned());
let child = agent_row(CHILD, AgentState::InFlight, 2);
let snap = snapshot(ws, "alba", vec![root, child], vec![]);
let rows = crate::boundary::answer::conversations(
&snap,
&crate::ui_state::UiState::open("/nonexistent/ui.json".into()),
ws,
100,
);
for id in [ROOT, CHILD, "20260801T000000Z-gh0"] {
let view = agent(&snap, &ui(), ws, id, 0);
let seat = crate::nav::convs::selection(&rows, id);
assert_eq!(seat.agent_id, view.agent_id, "{id}");
assert_eq!(seat.root, view.root, "{id}");
assert_eq!(seat.ancestors, view.ancestors, "{id}");
assert_eq!(seat.name, view.name, "{id}");
assert_eq!(seat.display_only, view.display_only, "{id}");
assert_eq!(seat.flight, view.flight, "{id}");
assert_eq!(seat.present, view.present, "{id}");
assert_eq!(seat.stoppable, view.stoppable, "{id}");
assert_eq!(seat.stop_children, view.stop_children, "{id}");
}
}
#[test]
fn an_agent_the_snapshot_does_not_carry_is_answered_not_refused() {
let ws = Path::new("/w");
let snap = snapshot(
ws,
"alba",
vec![agent_row(ROOT, AgentState::Live, 1)],
vec![],
);
for (at, id) in [(ws, "who"), (Path::new("/elsewhere"), ROOT)] {
let view = agent(&snap, &ui(), at, id, 0);
assert_eq!(view.root, id);
assert_eq!(view.name, crate::nav::convs::id_floor(id));
assert_eq!(view.tip, "");
assert_eq!(view.state, AgentState::Stopped);
assert!(view.marks.is_empty());
assert_eq!(view.flight, None);
assert!(view.ancestors.is_empty());
assert!(!view.present && !view.nudgeable && !view.stoppable);
assert!(!view.stop_children && view.held.is_none());
}
}
fn bill(conv: &str, tokens: u64) -> crate::budgets::StepBill {
let spend = crate::budgets::BudgetSpend {
input_tokens: tokens,
output_tokens: 0,
cache_read_tokens: 0,
cache_write_tokens: 0,
};
crate::budgets::StepBill {
conv: conv.to_owned(),
seq: "001".to_owned(),
model: Some("m".to_owned()),
spend,
last_usage: spend,
wall_secs: 0,
}
}
#[test]
fn a_child_answers_its_own_spend_and_its_own_context() {
let ws = Path::new("/w");
let mut snap = snapshot(
ws,
"alba",
vec![
agent_row(ROOT, AgentState::Quiescent, 1),
agent_row(CHILD, AgentState::InFlight, 2),
],
vec![],
);
snap.bills
.insert(ws.to_path_buf(), vec![bill(ROOT, 70), bill(CHILD, 30)]);
snap.windows.insert("m".to_owned(), 100);
let at_child = agent(&snap, &ui(), ws, CHILD, 0);
assert_eq!(at_child.spend.tokens.input_tokens, 30, "the child's own");
assert_eq!(
at_child.spend.attribution,
crate::spend::Attribution::Conversations(1),
"one subject, and now it is the selected one"
);
assert_eq!(at_child.context.map(|f| f.percent()), Some(30));
let at_root = agent(&snap, &ui(), ws, ROOT, 0);
assert_eq!(at_root.spend.tokens.input_tokens, 100, "root and descent");
assert_eq!(at_root.context.map(|f| f.percent()), Some(70));
}