From ef7c5e5f2fd819d5c8d9fc0e527687303746851d Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 10 Oct 2026 06:09:42 +0200 Subject: [PATCH] Persona: the view's receipt is the newest one that wrote the document The match on type, key and bytes was three conditions for one fact; the newest receipt writing the persona identity is that fact. Tests pin the declared-name walk and the receipt of each of five consecutive puts. Co-Authored-By: Claude Opus 5.5 --- crates/huginn-mind/src/persona.rs | 37 ++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/crates/huginn-mind/src/persona.rs b/crates/huginn-mind/src/persona.rs index f77a4a0..13f4fc8 100644 --- a/crates/huginn-mind/src/persona.rs +++ b/crates/huginn-mind/src/persona.rs @@ -20,7 +20,6 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use crate::mind::Mind; -use crate::receipt::HuginnCommitReceipt; use crate::refusal::MindRefusal; use crate::store::MindStore; @@ -147,16 +146,12 @@ impl Mind { let value = decode(envelope)?; let integrity = |detail: &str| MindRefusal::Unavailable { detail: detail.into() }; let updated_at = updated_at(&value).ok_or_else(|| integrity("the stored persona has no updatedAt"))?.to_string(); + let identity = (envelope.r#type.as_str(), envelope.key.as_str()); let receipt_id = self .receipts()? .into_iter() - .find(|receipt: &HuginnCommitReceipt| { - receipt.writes.iter().any(|write| { - write.document_type == envelope.r#type - && write.document_key == envelope.key - && write.payload_msgpack == envelope.payload - }) - }) + .filter(|receipt| receipt.writes.iter().any(|write| write.identity() == identity)) + .max_by_key(|receipt| receipt.ordinal) .ok_or_else(|| integrity("the stored persona has no receipt"))? .receipt_id; Ok(Some(PersonaStateView { value, updated_at, receipt_id })) @@ -263,6 +258,32 @@ mod tests { } } + #[test] + fn declared_names_are_every_property_name_at_any_depth() { + let schema = json!({ + "properties": { "a": { "properties": { "b": {} } } }, + "allOf": [{ "properties": { "c": {} } }], + "definitions": { "d": { "properties": { "e": {} } } }, + "required": ["not-a-property"] + }); + let mut names = BTreeSet::new(); + declared_names(&schema, &mut names); + assert_eq!(names, BTreeSet::from(["a", "b", "c", "e"].map(String::from))); + } + + #[test] + fn the_view_names_the_receipt_of_the_latest_put() { + let store = MemoryStore::new(); + let mut mind = seeded_over(&store); + let mut previous: Option = None; + for second in 0..5 { + let stamp = format!("2026-10-10T10:00:0{second}Z"); + let receipt = committed(put(&mut mind, persona(INSTANCE, &stamp), previous.as_deref())); + assert_eq!(mind.persona().unwrap().unwrap().receipt_id, receipt, "after put {second}"); + previous = Some(stamp); + } + } + #[test] fn a_persona_document_is_validated_at_the_door() { let store = MemoryStore::new();