mind-body: the committed surface follows HeartbeatView and Addressing; the responsibilities list says which chat names are exact; a test's direct message does not name a Mind

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-11-07 01:03:46 +01:00
commit 6aedd54155
3 changed files with 20 additions and 11 deletions

View file

@ -2169,9 +2169,14 @@ fn render_responsibilities(mind: &dyn MindPort, instance: &Slug, names: &BTreeMa
for steward in &stewards {
if let PipelineFacts::Stewardship { repo, note, names: listed, .. } = &steward.facts {
let chat = project_names(repo, listed);
let words = chat.iter().map(|name| name.text.as_str()).collect::<Vec<_>>().join(", ");
let how = if listed.is_empty() { "any case" } else { "exactly as written" };
out.push_str(&format!("- steward of {} (chat names, {how}: {words}): {}\n", repo.0, note.0));
let how: Vec<String> = [(true, "exactly as written"), (false, "any case")]
.into_iter()
.filter_map(|(exact, how)| {
let words = chat.iter().filter(|name| name.exact == exact).map(|name| name.text.as_str()).collect::<Vec<_>>().join(", ");
(!words.is_empty()).then(|| format!("{how}: {words}"))
})
.collect();
out.push_str(&format!("- steward of {} (chat names, {}): {}\n", repo.0, how.join("; "), note.0));
chat_names.extend(chat);
if !repos.contains(repo) {
repos.push(repo.clone());

View file

@ -1187,7 +1187,7 @@ fn a_turn_shows_her_stewardships_follow_ups_and_the_rulings_they_cite() {
let input = first_input(&rig);
assert!(input.contains("What you are responsible for"), "{input}");
assert!(input.contains("Open follow-ups, newest first:"), "{input}");
assert!(input.contains("- steward of GameCult/cinny (chat names, any case: cinny): the chat client; design law in eureka-body:ruling:client-first."), "{input}");
assert!(input.contains("- steward of GameCult/cinny (chat names, exactly as written: cinny): the chat client; design law in eureka-body:ruling:client-first."), "{input}");
let (newer, older) = (input.find("eureka-body/newer").unwrap(), input.find("eureka-body/older").unwrap());
assert!(newer < older, "{input}");
assert!(input.contains("Ship the other thing.") && !input.contains("Second line."), "{input}");
@ -1212,7 +1212,7 @@ fn her_responsibilities_show_each_stewardships_chat_names_and_the_line_on_changi
let rig = Rig::new(vec![], &[]);
rig.mind.committed(vec![steward_naming("GameCult/BadDaySimulator", &[]), steward_naming("GameCult/Thing", &["Thing"])]);
let text = render_responsibilities(&rig.mind, &Slug(INSTANCE.into()), &BTreeMap::new()).unwrap().text;
assert!(text.contains("- steward of GameCult/BadDaySimulator (chat names, any case: baddaysimulator, bad day simulator): the project"), "{text}");
assert!(text.contains("- steward of GameCult/BadDaySimulator (chat names, exactly as written: BadDaySimulator; any case: bad day simulator): the project"), "{text}");
assert!(text.contains("- steward of GameCult/Thing (chat names, exactly as written: Thing): the project"), "{text}");
assert_eq!(text.matches("These names address you in chat as a tag does. To change a project's names, admit its stewardship's next sequence with `names`").count(), 1, "{text}");
let last_steward = text.rfind("- steward of").unwrap();
@ -2229,7 +2229,8 @@ fn a_dm_memory_names_its_confidant_not_its_subject() {
fn about_can_name_an_absent_mind() {
let (libby, op) = ("@libby:chat", "@op:chat");
let decided = reply(&[("!dm-op:chat", "ok")], json!([keeps("Decided", "Libby does the shaders for the Cinny fork", &[libby])]), json!([]), json!(null));
let rig = Rig::new(vec![direct(1, "!dm-op:chat", op, "Libby will do the shaders for the Cinny fork")], &[decided, says(&[("swarm", "go")])]);
let dm = ChatDelivery { is_direct: true, ..delivery_of(1, "!dm-op:chat", op, "Libby will do the shaders for the Cinny fork", "$dm-libby") };
let rig = Rig::new(vec![dm], &[decided, says(&[("swarm", "go")])]);
assert_eq!(failure_of(rig.go()), None);
assert_eq!(rig.sent_texts().len(), 1);
assert_eq!(rig.chat.acked.borrow().len(), 1);
@ -3789,7 +3790,7 @@ fn a_small_machine() -> Rig {
/// What project-name-addresses-steward made of the base: the stewardship lines show their chat names and one line says what they do.
fn with_chat_names(base: &str) -> String {
let mut lines: Vec<String> = base.lines().map(|line| line.replace("- steward of GameCult/Huginn: ", "- steward of GameCult/Huginn (chat names, any case: huginn): ").replace("- steward of GameCult/cinny: ", "- steward of GameCult/cinny (chat names, any case: cinny): ")).collect();
let mut lines: Vec<String> = base.lines().map(|line| line.replace("- steward of GameCult/Huginn: ", "- steward of GameCult/Huginn (chat names, exactly as written: Huginn): ").replace("- steward of GameCult/cinny: ", "- steward of GameCult/cinny (chat names, exactly as written: cinny): ")).collect();
let last = lines.iter().rposition(|line| line.starts_with("- steward of")).unwrap();
lines.insert(last + 1, "These names address you in chat as a tag does. To change a project's names, admit its stewardship's next sequence with `names` and a resolution superseding the previous record; names you list replace the derived ones and match exactly as you write them, so list each casing you want.".into());
lines.join("\n") + "\n"

View file

@ -11,6 +11,8 @@ mind_body: mod queue
mind_body: mod self_run
mind_body: mod tempo
mind_body::address: impl Addressee
mind_body::address: struct Addressee # [derive (Clone , Debug , PartialEq , Eq , serde :: Serialize , serde :: Deserialize)] pub-fields[]
mind_body::address: struct Name # [derive (Clone , Debug , PartialEq , Eq , serde :: Serialize , serde :: Deserialize)] pub-fields[]
mind_body::chat_client: # [derive (Clone , Copy , Debug , PartialEq , Eq)] pub enum Refusal { Brake , PersonaMismatch , UnknownRoom , EmptyText , SendFailed , UnknownPersona , RoomMoved , }
mind_body::chat_client: const ACK : & str
mind_body::chat_client: const PENDING : & str
@ -89,16 +91,17 @@ mind_body::heartbeat: impl Control for FileControl
mind_body::heartbeat: impl FileStore
mind_body::heartbeat: impl FileStore: fn check (& self) -> Result < () >
mind_body::heartbeat: impl FileStore: fn new (path : impl Into < PathBuf >) -> Self
mind_body::heartbeat: impl HeartbeatView for FileStore
mind_body::heartbeat: impl PersonaId
mind_body::heartbeat: impl PersonaId: fn parse (spec : & str) -> Result < Self >
mind_body::heartbeat: impl Row < '_ >
mind_body::heartbeat: impl Store for FileStore
mind_body::heartbeat: impl TempoView for FileStore
mind_body::heartbeat: impl fmt :: Display for Outcome
mind_body::heartbeat: impl fmt :: Display for PollTrace
mind_body::heartbeat: pub trait Control { fn envelope (& self) -> SwarmEffective ; fn effective (& self , instance : & Slug) -> Effective ; }
mind_body::heartbeat: pub trait Store { fn load (& self) -> Result < Option < HeartbeatState > > ; fn save (& self , state : & HeartbeatState) -> Result < () > ; fn record (& self , trace : & PollTrace) -> Result < () > ; }
mind_body::heartbeat: pub trait TempoView { fn latest (& self) -> Result < Option < PollTrace > > ; }
mind_body::heartbeat: pub trait HeartbeatView { fn latest (& self) -> Result < Option < PollTrace > > ; fn addressing (& self) -> Result < Option < Addressing > > ; }
mind_body::heartbeat: pub trait Store { fn load (& self) -> Result < Option < HeartbeatState > > ; fn save (& self , state : & HeartbeatState) -> Result < () > ; fn record (& self , trace : & PollTrace) -> Result < () > ; fn load_addressing (& self) -> Result < Option < Addressing > > ; fn save_addressing (& self , addressing : & Addressing) -> Result < () > ; }
mind_body::heartbeat: struct Addressing # [derive (Clone , Debug , Default , PartialEq , Eq , DatabaseEntry)] pub-fields[minds: Vec < Addressee >]
mind_body::heartbeat: struct Config # [derive (Clone , Debug , PartialEq , Eq)] pub-fields[personas: Vec < PersonaId >, operators: Vec < String >]
mind_body::heartbeat: struct FileControl pub-fields[]
mind_body::heartbeat: struct FileStore pub-fields[]
@ -191,7 +194,7 @@ mind_body::persona: pub use model_connector :: PlanQuota ;
mind_body::persona: struct Config # [derive (Clone , Debug , PartialEq , Eq)] pub-fields[rooms: Vec < String >, operators: Vec < String >, minds: Vec < String >, own_sender: String, model: String, doctrine: Vec < PathBuf >]
mind_body::persona: struct FileTrace pub-fields[]
mind_body::persona: struct HuginnPersona pub-fields[]
mind_body::persona: struct Organs< 'a > pub-fields[mind: & 'a dyn MindPort, launcher: & 'a dyn Launcher, clock: & 'a dyn Clock, host: & 'a str, chat: & 'a dyn Chat, persona: & 'a dyn PersonaState, trace: & 'a dyn Trace, tempo: Option < & 'a dyn TempoView >, lender: & 'a dyn Lender, spawner: & 'a dyn Spawner, run_cap_s: u64, sandbox: & 'a Path, scratch: & 'a Path]
mind_body::persona: struct Organs< 'a > pub-fields[mind: & 'a dyn MindPort, launcher: & 'a dyn Launcher, clock: & 'a dyn Clock, host: & 'a str, chat: & 'a dyn Chat, persona: & 'a dyn PersonaState, trace: & 'a dyn Trace, heartbeat: Option < & 'a dyn HeartbeatView >, lender: & 'a dyn Lender, spawner: & 'a dyn Spawner, run_cap_s: u64, sandbox: & 'a Path, scratch: & 'a Path]
mind_body::persona: struct PersonaReply # [derive (Clone , Debug , PartialEq , Eq , Serialize , Deserialize)] pub-fields[intent: String, say: Vec < Say >, start_self_run: Option < StartSelfRun >, remember: Vec < Remember >, settle: Vec < Settle >, tempo_vote_beat_s: Option < Option < u32 > >, urgency_permille: Option < u16 >]
mind_body::persona: struct Remember # [derive (Clone , Debug , PartialEq , Eq , Serialize , Deserialize)] pub-fields[sort: MemorySort, text: String, about: Vec < String >, salience_permille: u16]
mind_body::persona: struct Say # [derive (Clone , Debug , PartialEq , Eq , Serialize , Deserialize)] pub-fields[room: String, text: String]