minds-wake-each-other: a message from another Mind that names her launches a Mind off the beat, once per message; a Mind naming herself does not
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e022e533e0
commit
c33884fe7a
2 changed files with 34 additions and 2 deletions
|
|
@ -426,6 +426,14 @@ fn addresses(who: &PersonaId, delivery: &ChatDelivery) -> Option<&'static str> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether a delivery wakes `who` off the beat: the operator or another Mind of
|
||||
/// the roster addresses her. A Mind naming herself does not; a member does not.
|
||||
fn wakes(config: &Config, who: &PersonaId, delivery: &ChatDelivery) -> bool {
|
||||
let from_operator = config.operators.contains(&delivery.sender);
|
||||
let from_other_mind = delivery.sender != who.matrix_id && config.personas.iter().any(|mind| mind.matrix_id == delivery.sender);
|
||||
(from_operator || from_other_mind) && addresses(who, delivery).is_some()
|
||||
}
|
||||
|
||||
/// The mouth pages a pending answer, so fewer deliveries may come than wait.
|
||||
/// The heartbeat acks nothing: it asks again after the highest seq it has until
|
||||
/// the answer is empty. A mouth that never empties is cut off at `PENDING_PAGES`.
|
||||
|
|
@ -593,7 +601,7 @@ pub fn poll(organs: &Organs, config: &Config) -> Result<Outcome> {
|
|||
let mut launches: Vec<String> = Vec::new();
|
||||
let mut launched: Vec<Slug> = Vec::new();
|
||||
|
||||
// Off the beat: the operator naming her, once per message, and her Self run
|
||||
// Off the beat: the operator or another Mind of the roster naming her, once per message, and her Self run
|
||||
// having ended since her last turn. Neither waits for the beat; both need her
|
||||
// idle and released.
|
||||
for row in &mut rows {
|
||||
|
|
@ -606,7 +614,7 @@ pub fn poll(organs: &Organs, config: &Config) -> Result<Outcome> {
|
|||
pending.sort_by_key(|delivery| delivery.seq);
|
||||
pending
|
||||
.into_iter()
|
||||
.filter(|delivery| config.operators.contains(&delivery.sender) && addresses(&row.seat.who, delivery).is_some())
|
||||
.filter(|delivery| wakes(config, &row.seat.who, delivery))
|
||||
.map(|delivery| format!("{}:{}", slug.0, delivery.event_id))
|
||||
.find(|key| !state.handled_mentions.contains(key))
|
||||
};
|
||||
|
|
|
|||
|
|
@ -462,6 +462,30 @@ fn the_operator_naming_a_persona_launches_her_at_once_off_the_beat_and_once_per_
|
|||
assert_eq!(rig.poll(), Outcome::Polled { launched: vec![Slug("ann".into())] });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn another_mind_naming_a_persona_wakes_her_once_off_the_beat() {
|
||||
let rig = Rig::new();
|
||||
rig.turn(ANN, 10);
|
||||
rig.turn(BOB, 10);
|
||||
rig.store.save(&HeartbeatState { last_beat_at: rig.now(), handled_mentions: vec![] }).unwrap();
|
||||
rig.say(BOB, delivery(1, "@ann:chat", "Bob, a word", &[]));
|
||||
assert_eq!(rig.poll(), Outcome::Polled { launched: vec![Slug("bob".into())] }, "a Mind of the roster wakes her at once");
|
||||
rig.end_run(BOB);
|
||||
assert_eq!(rig.poll(), Outcome::Polled { launched: vec![] }, "the same message polled again wakes nobody");
|
||||
assert_eq!(rig.runs(BOB), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_mind_naming_no_one_or_herself_wakes_nobody() {
|
||||
let rig = Rig::new();
|
||||
rig.turn(ANN, 10);
|
||||
rig.turn(BOB, 10);
|
||||
rig.store.save(&HeartbeatState { last_beat_at: rig.now(), handled_mentions: vec![] }).unwrap();
|
||||
rig.say(BOB, delivery(1, "@ann:chat", "nothing to anyone", &[]));
|
||||
rig.say(BOB, delivery(2, "@bob:chat", "Bob reminds Bob", &["@bob:chat"]));
|
||||
assert_eq!(rig.poll(), Outcome::Polled { launched: vec![] });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_member_naming_a_persona_launches_nobody_off_the_beat_but_counts_as_full_urgency_on_it() {
|
||||
let rig = Rig::new();
|
||||
|
|
|
|||
Loading…
Reference in a new issue