persona: a reply that cannot be placed is a text-free pointer in the public session

A reply that answers no brief, or briefs of two conversations, was read by nothing and re-paged on every Persona read. It is now a route in the public conversation marked as a pointer: the line carries the reply id and a fixed note, never its text, and the Persona reads the reply by id. Heard, it is resolved like any reply.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-11-07 03:16:27 +01:00
commit a1370cf424
2 changed files with 54 additions and 14 deletions

View file

@ -962,8 +962,8 @@ impl Conversation {
}
/// The conversation a reply is told in: the one conversation its briefs' origins name, or none when they name two or
/// it answers no brief (a result the Self could not attribute). Such a reply is told in no session, so no member's words
/// reach another's room, and it stays in force.
/// it answers no brief (a result the Self could not attribute). Such a reply has no conversation: the public session is told a
/// pointer to it without its text, so no member's words reach another's room.
fn reply_conversation(answers: &[Option<MemoryOrigin>]) -> Option<Conversation> {
let mut conversations = answers.iter().map(|origin| Conversation::of_origin(origin.as_ref()));
let first = conversations.next()?;
@ -979,10 +979,12 @@ struct Route {
conversation: Conversation,
/// The origin of the first brief the reply answers that has one: what a session opened for the reply alone records.
origin: Option<MemoryOrigin>,
/// The reply could not be placed in one conversation (it answers none, or briefs of two): the public session is told a pointer to it, never its text.
pointer: bool,
}
/// Her in-force replies this process has not told, oldest first, each with its conversation: one selection of the replies and
/// one keyed selection of the briefs they answer. A reply whose briefs name two conversations is left out: no session tells it.
/// one keyed selection of the briefs they answer. A reply with no one conversation is a pointer route in the public one.
fn reply_routes(mind: &dyn MindPort, told: &BTreeSet<String>) -> Result<Vec<Route>> {
let replies: Vec<_> = headers(mind, &in_force(any_of(of_kind(PipelineKind::Reply), "root", &[&mind.instance().0])))?.into_iter().filter(|header| !told.contains(&header.id.id.0)).collect();
let mut keys: Vec<String> = replies
@ -1006,12 +1008,13 @@ fn reply_routes(mind: &dyn MindPort, told: &BTreeSet<String>) -> Result<Vec<Rout
for header in replies {
let PipelineFacts::Reply { answers, .. } = &header.facts else { continue };
let of_answers: Vec<Option<MemoryOrigin>> = answers.iter().map(|brief| origins.get(&brief.id.0).cloned().flatten()).collect();
let Some(conversation) = reply_conversation(&of_answers) else { continue };
let placed = reply_conversation(&of_answers);
routes.push(Route {
id: header.id.id.0.clone(),
ordinal: header.admission.ordinal,
at_unix_ms: instant_ms(&header.admission.admitted_at).unwrap_or(0),
conversation,
pointer: placed.is_none(),
conversation: placed.unwrap_or(Conversation::Public),
origin: of_answers.into_iter().flatten().next(),
});
}
@ -1123,11 +1126,19 @@ struct HeardReply {
/// The briefs it answers, each with its repo (empty when the brief's repo could not be read).
answers: Vec<(String, String)>,
text: String,
/// A pointer to a reply that could not be placed: it holds no answers and no text, only the id.
pointer: bool,
}
/// What a pointer line says, in the organ's own words: the reply is in the mind under its id, and nothing of it is in this line.
const UNPLACED_NOTE: &str = "Your Self finished something it could not place in any one conversation. Its words are not here: read the reply by this id, privately, and decide where it belongs.";
/// A reply as one line: `role=self` is the organ's word that it is her Self's, and every field a Self wrote is quoted, so nothing in
/// it can end the line or pass for a message, a notice or a field.
fn reply_line(reply: &HeardReply) -> String {
if reply.pointer {
return format!("reply role=self at={} id={} unplaced=true note={}\n", at_text(reply.at_unix_ms), quoted(&reply.id), quoted(UNPLACED_NOTE));
}
let answers = reply
.answers
.iter()
@ -1951,8 +1962,12 @@ fn decode_reply(text: &str, rooms: &[String], people: &[String], open: &[String]
/// document cannot be read is left for the next read. Only the routes of the session's own conversation are given.
fn unheard_replies(mind: &dyn MindPort, routes: &[Route]) -> Result<Vec<HeardReply>> {
let mut found = Vec::new();
for Route { id, ordinal, .. } in routes {
for Route { id, ordinal, at_unix_ms, pointer, .. } in routes {
let (id, ordinal) = (id.clone(), *ordinal);
if *pointer {
found.push(HeardReply { id, ordinal, at_unix_ms: *at_unix_ms, answers: Vec::new(), text: String::new(), pointer: true });
continue;
}
let one = Selection { keys: Some(vec![id.clone()]), projection: "document".into(), ..Selection::default() };
let PipelinePageItems::Documents(views) = mind.query(&one)?.items else { bail!("the mind answered headers to a document selection") };
let Some(view) = views.into_iter().next() else { continue };
@ -1967,7 +1982,7 @@ fn unheard_replies(mind: &dyn MindPort, routes: &[Route]) -> Result<Vec<HeardRep
});
answers.push((brief.id.0.clone(), repo.unwrap_or_default()));
}
found.push(HeardReply { id, ordinal, at_unix_ms, answers, text: reply.text.0 });
found.push(HeardReply { id, ordinal, at_unix_ms, answers, text: reply.text.0, pointer: false });
}
Ok(found)
}

View file

@ -6481,7 +6481,7 @@ fn a_start_opens_a_conversation_for_a_reply_alone_at_most_once() {
}
fn route(id: &str, at_unix_ms: u64, conversation: Conversation) -> Route {
Route { id: id.into(), ordinal: at_unix_ms, at_unix_ms, conversation, origin: None }
Route { id: id.into(), ordinal: at_unix_ms, at_unix_ms, conversation, origin: None, pointer: false }
}
fn at_ms(delivery: ChatDelivery, at_unix_ms: u64) -> ChatDelivery {
@ -6542,22 +6542,47 @@ fn a_reply_to_a_public_brief_or_a_brief_with_no_origin_is_told_in_the_public_ses
for words in ["old-brief words", "public-brief words"] {
assert_eq!(all.contains(words), public, "{words} is told in the public session only: {all}");
}
assert!(!all.contains("no-brief words"), "a reply the Self could not attribute is told in no session: {all}");
assert!(!all.contains("no-brief words"), "a reply the Self could not attribute puts no text in any session: {all}");
}
}
/// The inputs of the sessions that were told a pointer, and every input the model was given.
fn pointed_inputs(rig: &Rig) -> (Vec<String>, Vec<String>) {
let all: Vec<String> = rig.model.requests.borrow().iter().map(|told| told.input.clone()).collect();
(all.iter().filter(|input| input.contains("unplaced=true")).cloned().collect(), all)
}
#[test]
fn a_reply_whose_briefs_name_two_conversations_is_told_in_no_session_and_stays_in_force() {
fn a_reply_whose_briefs_name_two_conversations_is_a_text_free_pointer_in_the_public_session_only() {
assert_eq!(reply_conversation(&[Some(dm_origin(AQUA_DM, "@a:chat")), Some(dm_origin(LIBBY_DM, "@l:chat"))]), None);
assert_eq!(reply_conversation(&[Some(dm_origin(AQUA_DM, "@a:chat")), None]), None);
let pending = vec![direct(1, AQUA_DM, "@aqua:chat", AQUA_ASK), direct(2, LIBBY_DM, "@libby:chat", "libby asks about cedar"), delivery(3, "swarm", "@m:chat", "public asks about oak")];
let rig = Rig::new(pending, &[says(&[]), says(&[]), says(&[])]);
let rig = Rig::new(pending, &[says(&[]), says(&[]), says(&[]), says(&[])]);
rig.mind.committed(briefs_in_every_room());
rig.mind.committed(vec![self_reply_to("r-both", &["ask-aqua", "ask-libby"], "both-rooms words")]);
assert_eq!(failure_of(rig.go()), None);
assert_eq!(rig.model.spawns.borrow().len(), 3, "only the deliveries' sessions");
assert!(!rig.model.requests.borrow().iter().any(|told| told.input.contains("both-rooms words")));
assert!(reply_in_force(&rig.mind, &reply_id("r-both")).unwrap());
let (pointed, all) = pointed_inputs(&rig);
assert_eq!(pointed.len(), 1, "one pointer, in one session: {all:?}");
assert!(pointed[0].contains(&reply_id("r-both")), "{}", pointed[0]);
assert!(!pointed[0].contains(AQUA_ASK) && !pointed[0].contains("libby asks about cedar"), "no direct message in the pointer's session: {}", pointed[0]);
assert!(!all.iter().any(|input| input.contains("both-rooms words")), "no reply text reaches any line");
// The Persona reads it by id: the reply document holds the words the line does not.
let PipelineDocument::Reply(reply) = rig.mind.view(K::Reply, &reply_id("r-both")).unwrap().document else { panic!("a reply") };
assert_eq!(reply.text.0, "both-rooms words");
assert!(!reply_in_force(&rig.mind, &reply_id("r-both")).unwrap(), "heard once, it no longer re-pages on every read");
}
#[test]
fn a_reply_that_answers_no_brief_is_a_text_free_pointer_with_its_id() {
let rig = Rig::new(vec![delivery(1, "swarm", "@m:chat", "public asks about oak")], &[says(&[]), says(&[])]);
rig.mind.committed(briefs_in_every_room());
rig.mind.committed(vec![self_reply_to("r-none", &[], "stranded words")]);
assert_eq!(failure_of(rig.go()), None);
let (pointed, all) = pointed_inputs(&rig);
assert_eq!(pointed.len(), 1, "{all:?}");
assert!(pointed[0].contains(&reply_id("r-none")) && pointed[0].contains("could not place"), "{}", pointed[0]);
assert!(!all.iter().any(|input| input.contains("stranded words")));
assert!(!reply_in_force(&rig.mind, &reply_id("r-none")).unwrap());
}
#[test]