use super::fixture::{MINTED_FIRST, World, fake_lernie, seed_world, world};
use super::screen::{Screen, press};
use crate::test_support::spawn_guard;
use tempfile::tempdir;
const SAID: &str = "unbar the postern";
fn say(screen: &Screen, world: &mut World) {
screen.frame(world, vec![egui::Event::Text(SAID.to_owned())]);
screen.frame(world, vec![press(egui::Key::Enter, egui::Modifiers::NONE)]);
world.model.refresh();
}
fn rows_named(world: &World, name: &str) -> Vec<crate::nav::convs::ConvRow> {
world
.model
.conversations(0)
.into_iter()
.filter(|r| r.display_name() == name)
.collect()
}
fn quick(mut world: World) -> World {
std::fs::write(
world.model.state_root().join("cadence.yaml"),
"cadence:\n watcher:\n debounce_ms: 0\n",
)
.unwrap();
world.model.after_lernie_verb();
world.converge();
world
}
fn converge_ws(world: &mut World) {
let ws = world.ws.clone();
world.model.mark_dirty([ws]);
world.converge();
}
fn branches(world: &World) -> usize {
std::fs::read_dir(world.ws.join("agents")).map_or(0, |d| d.flatten().count())
}
fn shot(screen: &Screen, world: &mut World) -> egui::FullOutput {
for _ in 0..3 {
screen.output(world, Vec::new());
}
screen.output(world, Vec::new())
}
fn fills(out: &egui::FullOutput) -> Vec<egui::Color32> {
let mut all = Vec::new();
for clipped in &out.shapes {
crate::paint_probe::collect_fills(&clipped.shape, &mut all);
}
all
}
fn faded_user() -> egui::Color32 {
let (hue, _) = crate::theme::role_badge(crate::theme::Role::User);
hue.gamma_multiply(crate::theme::tone_solidity(crate::transcript::Tone::Weak))
}
#[test]
fn a_start_is_a_row_in_the_operators_own_words_on_the_next_frame() {
let bin = tempdir().unwrap();
let mut world = quick(world());
seed_world(&world);
let _g = spawn_guard();
let screen = Screen::with_lernie(fake_lernie(bin.path()));
assert!(screen.idle(&mut world), "the cursor starts in the composer");
let worktrees = branches(&world);
let before = screen.text(&mut world);
assert!(
!before.contains(SAID),
"nothing says it before the operator does:\n{before}"
);
say(&screen, &mut world);
assert_eq!(
branches(&world),
worktrees,
"the driver has written nothing: no branch for a derivation to carry"
);
let painted = screen.text(&mut world);
assert!(
painted.contains(SAID),
"the frame immediately after Enter carries what was typed:\n{painted}"
);
let pending = rows_named(&world, MINTED_FIRST);
assert_eq!(
pending.len(),
1,
"exactly one row for the started conversation"
);
assert_eq!(
pending[0].root_id, MINTED_FIRST,
"keyed by the minted §3.3 name — the only identity a start has yet"
);
assert_eq!(
pending[0].subtitle(),
SAID,
"and its preview is the operator's text verbatim"
);
assert_eq!(
pending[0].tone,
crate::transcript::Tone::Weak,
"faded: yog's own word for it, not yet a statement (§11)"
);
world.add_root("c-2", MINTED_FIRST);
let messages = world.ws.join("agents/c-2/messages");
std::fs::create_dir_all(&messages).unwrap();
std::fs::write(messages.join("001-user.md"), SAID).unwrap();
converge_ws(&mut world);
let landed = rows_named(&world, MINTED_FIRST);
assert_eq!(
landed.len(),
1,
"still one row — the echo gave its seat up rather than doubling it"
);
assert_eq!(
landed[0].tone,
crate::transcript::Tone::Plain,
"and it brightened: the derivation made it a statement"
);
assert_eq!(
landed[0].root_id, "c-2",
"the row is now the real branch, keyed by its agent id"
);
}
#[test]
fn a_message_joins_the_inbox_queue_faded_and_brightens_when_it_lands() {
let bin = tempdir().unwrap();
let mut world = quick(world());
seed_world(&world);
let _g = spawn_guard();
let screen = Screen::with_lernie(fake_lernie(bin.path()));
let ws = world.ws.clone();
world.model.focus_agent(&ws, "c-1");
world
.model
.select_tab(crate::keymap::InspectorTab::Transcript);
screen.text(&mut world);
let before = world
.model
.tree(&ws)
.and_then(|t| t.agents.iter().find(|a| a.agent_id == "c-1").cloned())
.expect("the fixture's conversation");
assert_eq!(before.pending.len(), 1, "the fixture's one landed deposit");
let landed_messages = before.messages;
say(&screen, &mut world);
assert_eq!(
std::fs::read_dir(world.ws.join("agents/c-1/messages")).map_or(0, |d| d.flatten().count()),
landed_messages,
"no message has landed: the transcript directory is exactly where it was"
);
let out = shot(&screen, &mut world);
let text = crate::paint_probe::text_of(&out);
assert!(
text.contains(SAID),
"the frame immediately after Enter carries what was typed:\n{text}"
);
assert!(
fills(&out).contains(&faded_user()),
"and it is faded — yog's own word for it, not yet a statement (§11)"
);
let messages = world.ws.join("agents/c-1/messages");
std::fs::write(messages.join("003-user.md"), SAID).unwrap();
converge_ws(&mut world);
let after = shot(&screen, &mut world);
assert!(
!fills(&after).contains(&faded_user()),
"the faded row is gone: the echo retired onto the landed message"
);
assert!(
crate::paint_probe::text_of(&after).contains(SAID),
"and the words are still on screen — now the derivation's, not yog's:\n{}",
crate::paint_probe::text_of(&after)
);
}