151 lines
5.0 KiB
Rust
151 lines
5.0 KiB
Rust
//! Which Honcho session a turn goes to (M5c spec, section 3): the Boxmaker session's id, then
|
|
//! `<id>-2`, `<id>-3` for each new speaker, holding every speaker so far; numbered from the
|
|
//! ledger's decisions alone, so a restart numbers the same. Do not edit.
|
|
|
|
#[path = "support/tmp.rs"]
|
|
mod tmp;
|
|
|
|
use bxcore::{SessionId, Timestamp};
|
|
use memoryd::honcho::ledger::{Action, Item, Ledger, Record, Workspace};
|
|
use memoryd::honcho::naming::{HonchoSession, honcho_session, session_name};
|
|
use tmp::TempDir;
|
|
|
|
fn sid(s: &str) -> SessionId {
|
|
SessionId::new(s).unwrap()
|
|
}
|
|
|
|
fn turn(session: &str, turn: u64) -> Item {
|
|
Item::Turn {
|
|
session: sid(session),
|
|
turn,
|
|
}
|
|
}
|
|
|
|
fn spoke(workspace: Workspace, speaker: &str) -> Action {
|
|
Action::Turn {
|
|
workspace,
|
|
speaker: speaker.to_string(),
|
|
}
|
|
}
|
|
|
|
fn skip() -> Action {
|
|
Action::Skip {
|
|
why: "the turn has no single speaker".to_string(),
|
|
}
|
|
}
|
|
|
|
fn hs(name: &str, speakers: &[&str]) -> Option<HonchoSession> {
|
|
Some(HonchoSession {
|
|
name: name.to_string(),
|
|
speakers: speakers.iter().map(|s| s.to_string()).collect(),
|
|
})
|
|
}
|
|
|
|
/// A ledger with these decisions, in this order.
|
|
fn ledger(dir: &TempDir, decisions: &[(Item, Action)]) -> Ledger {
|
|
let path = dir.path().join("honcho.jsonl");
|
|
let mut ledger = Ledger::open(&path).unwrap();
|
|
for (item, action) in decisions {
|
|
ledger
|
|
.append(Record::Decided {
|
|
time: Timestamp::parse("2026-09-28T10:00:00.000Z").unwrap(),
|
|
item: item.clone(),
|
|
action: action.clone(),
|
|
})
|
|
.unwrap();
|
|
}
|
|
ledger
|
|
}
|
|
|
|
#[test]
|
|
fn session_names() {
|
|
assert_eq!(session_name(&sid("chat-1"), 0), "chat-1");
|
|
assert_eq!(session_name(&sid("chat-1"), 1), "chat-1");
|
|
assert_eq!(session_name(&sid("chat-1"), 2), "chat-1-2");
|
|
assert_eq!(session_name(&sid("chat-1"), 12), "chat-1-12");
|
|
}
|
|
|
|
#[test]
|
|
fn each_new_speaker_starts_the_next_session() {
|
|
let dir = TempDir::new("naming-order");
|
|
let decisions = [
|
|
(turn("chat-1", 1), spoke(Workspace::Trusted, "kyle")),
|
|
(turn("chat-2", 1), spoke(Workspace::Trusted, "zed")),
|
|
(turn("chat-1", 2), spoke(Workspace::Trusted, "kyle")),
|
|
(turn("chat-1", 3), spoke(Workspace::Untrusted, "ana_b")),
|
|
(turn("chat-1", 4), skip()),
|
|
(turn("chat-1", 5), spoke(Workspace::Trusted, "kyle")),
|
|
(turn("chat-1", 6), spoke(Workspace::Untrusted, "bob")),
|
|
(turn("chat-1", 7), spoke(Workspace::Trusted, "ana_b")),
|
|
];
|
|
let l = ledger(&dir, &decisions);
|
|
let at = |t: u64| honcho_session(l.decisions(), &sid("chat-1"), t);
|
|
assert_eq!(at(1), hs("chat-1", &["kyle"]));
|
|
assert_eq!(at(2), hs("chat-1", &["kyle"]));
|
|
// A new speaker in any workspace counts.
|
|
assert_eq!(at(3), hs("chat-1-2", &["kyle", "ana_b"]));
|
|
assert_eq!(at(4), None, "a skipped turn goes nowhere");
|
|
assert_eq!(at(5), hs("chat-1-2", &["kyle", "ana_b"]));
|
|
assert_eq!(at(6), hs("chat-1-3", &["kyle", "ana_b", "bob"]));
|
|
assert_eq!(at(7), hs("chat-1-3", &["kyle", "ana_b", "bob"]));
|
|
assert_eq!(at(8), None, "an undecided turn");
|
|
// Another session's speakers do not count.
|
|
assert_eq!(
|
|
honcho_session(l.decisions(), &sid("chat-2"), 1),
|
|
hs("chat-2", &["zed"])
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn the_order_is_the_order_of_decision() {
|
|
let dir = TempDir::new("naming-decided");
|
|
// Turn 2 was decided first (turn 1 waited for brokerd): its speaker is the first.
|
|
let decisions = [
|
|
(turn("chat-1", 2), spoke(Workspace::Trusted, "ana_b")),
|
|
(turn("chat-1", 1), spoke(Workspace::Trusted, "kyle")),
|
|
];
|
|
let l = ledger(&dir, &decisions);
|
|
assert_eq!(
|
|
honcho_session(l.decisions(), &sid("chat-1"), 2),
|
|
hs("chat-1", &["ana_b"])
|
|
);
|
|
assert_eq!(
|
|
honcho_session(l.decisions(), &sid("chat-1"), 1),
|
|
hs("chat-1-2", &["ana_b", "kyle"])
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn a_restart_numbers_the_same() {
|
|
let dir = TempDir::new("naming-restart");
|
|
let decisions = [
|
|
(turn("chat-1", 1), spoke(Workspace::Trusted, "kyle")),
|
|
(turn("chat-1", 2), skip()),
|
|
(turn("chat-1", 3), spoke(Workspace::Trusted, "ana_b")),
|
|
];
|
|
let before: Vec<Option<HonchoSession>> = {
|
|
let l = ledger(&dir, &decisions);
|
|
(1..=3)
|
|
.map(|t| honcho_session(l.decisions(), &sid("chat-1"), t))
|
|
.collect()
|
|
};
|
|
let l = Ledger::open(&dir.path().join("honcho.jsonl")).unwrap();
|
|
let after: Vec<Option<HonchoSession>> = (1..=3)
|
|
.map(|t| honcho_session(l.decisions(), &sid("chat-1"), t))
|
|
.collect();
|
|
assert_eq!(before, after);
|
|
assert_eq!(after[2], hs("chat-1-2", &["kyle", "ana_b"]));
|
|
}
|
|
|
|
#[test]
|
|
fn decisions_are_every_decided_item_in_order() {
|
|
let dir = TempDir::new("naming-decisions");
|
|
let decisions = [
|
|
(turn("chat-1", 2), skip()),
|
|
(turn("chat-1", 1), spoke(Workspace::Trusted, "kyle")),
|
|
];
|
|
let l = ledger(&dir, &decisions);
|
|
let got: Vec<(Item, Action)> = l.decisions().map(|(i, a)| (i.clone(), a.clone())).collect();
|
|
assert_eq!(got, decisions.to_vec());
|
|
}
|