use super::Harness;
use crate::nav::ws_key;
use crate::ui_state::SeenKind;
use crate::watch::Mark;
use std::time::Duration;
fn build_named(h: &Harness, id: &str, name: &str) {
h.build_more(id, "fix the gate");
h.fx.name_agent(id, name);
}
#[test]
fn a_fired_start_focuses_the_conversation_it_started() {
let h = Harness::new();
let (clock, mut model) = h.model();
model.focus_workspace(&crate::naming::leaf(&h.ws));
assert!(model.focus().agent.is_none(), "the placeholder's state");
model.await_conversation(&h.ws, "stench-pug", "fix the gate");
assert_eq!(
model.focus().agent.as_deref(),
Some("stench-pug"),
"the start selects what it started, by the name it minted"
);
build_named(&h, "c-2", "stench-pug");
model.dirty_handle().mark_all([(h.ws.clone(), Mark::Watch)]);
model.tick(); clock.advance(Duration::from_millis(150));
assert!(model.tick(), "the roster now carries the started root");
assert_eq!(
model.focus().agent.as_deref(),
Some("c-2"),
"the start's own conversation is what renders — no ↓, no click"
);
let tip = model
.tree(&h.ws)
.and_then(|t| t.agents.iter().find(|a| a.agent_id == "c-2").cloned())
.map(|a| a.tip_oid)
.expect("the started root is in the tree");
assert!(
model.is_seen(SeenKind::Stopped, &ws_key(&h.ws), "c-2", &tip),
"arriving on it recorded its watermark"
);
}
#[test]
fn the_claim_is_spent_once_and_leaves_later_focus_alone() {
let h = Harness::new();
let (clock, mut model) = h.model();
build_named(&h, "c-2", "stench-pug");
model.dirty_handle().mark_all([(h.ws.clone(), Mark::Watch)]);
model.tick();
clock.advance(Duration::from_millis(150));
model.tick();
model.await_conversation(&h.ws, "stench-pug", "fix the gate");
model.refresh();
assert_eq!(model.focus().agent.as_deref(), Some("c-2"), "claimed");
model.focus_agent(&h.ws, "c-1");
model.refresh();
assert_eq!(
model.focus().agent.as_deref(),
Some("c-1"),
"the claim was spent on its arrival, not held"
);
}
#[test]
fn navigation_during_the_window_outranks_the_arriving_claim() {
let h = Harness::new();
let (clock, mut model) = h.model();
model.await_conversation(&h.ws, "stench-pug", "fix the gate");
assert_eq!(
model.focus().agent.as_deref(),
Some("stench-pug"),
"the fire's own selection, made at once (bl-2e8f)"
);
model.focus_agent(&h.ws, "c-1");
build_named(&h, "c-2", "stench-pug");
model.dirty_handle().mark_all([(h.ws.clone(), Mark::Watch)]);
model.tick();
clock.advance(Duration::from_millis(150));
assert!(model.tick(), "the roster now carries the started root");
assert_eq!(
model.focus().agent.as_deref(),
Some("c-1"),
"where they went is where they are"
);
model.focus_workspace(&crate::naming::leaf(&h.ws));
model.refresh();
assert!(
model.focus().agent.is_none(),
"a spent claim has no name left to match"
);
}
#[test]
fn a_claim_whose_root_never_appears_stays_on_the_name_it_minted() {
let h = Harness::new();
let (_c, mut model) = h.model();
model.focus_agent(&h.ws, "c-1");
model.await_conversation(&h.ws, "never-written", "fix the gate");
model.refresh();
assert_eq!(
model.focus().agent.as_deref(),
Some("never-written"),
"the claim's own selection stands: a root that never lands is a faded \
row (§7.2), not a focus that snaps back to the conversation before it"
);
model.await_conversation(
std::path::Path::new("/no/such/ws"),
"stench-pug",
"fix the gate",
);
model.refresh();
assert_eq!(
model.focus().agent.as_deref(),
Some("stench-pug"),
"an unresolvable claim is inert — nothing spends it, and nothing \
re-aims the focus it made"
);
}