From 2023c0a1e37076f9dc96d2f62da8695987e6b30b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 26 Oct 2026 15:03:47 +0100 Subject: [PATCH] Let tests replace the read path under the gate so the view comparison is pinned Co-Authored-By: Claude Sonnet 5.5 --- crates/huginn-mind/src/query.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/crates/huginn-mind/src/query.rs b/crates/huginn-mind/src/query.rs index 5e10fba..992826d 100644 --- a/crates/huginn-mind/src/query.rs +++ b/crates/huginn-mind/src/query.rs @@ -473,6 +473,15 @@ impl Mind { /// because `Reader::at` is the expensive build. Admits nothing. A fault /// names the document's key and what failed, never its content. pub fn read_back(&self) -> Result { + self.read_back_through(Reader::view) + } + + /// The gate's one body; `lookup` is the read path under test, which tests + /// replace with a lying one to prove the view comparison refuses. + fn read_back_through( + &self, + lookup: impl Fn(&Reader, &PipelineRef) -> Result, MindRefusal>, + ) -> Result { let cache = schema_cache()?; let reader = Reader::at(self, receipt::head(self)?)?; let mut count = 0; @@ -488,7 +497,7 @@ impl Mind { if (&again.key, &again.r#type, &again.payload) != (key, &envelope.r#type, &envelope.payload) { return Err(integrity(&envelope.r#type, key, "does not re-encode to its stored bytes")); } - let viewed = reader.view(&PipelineRef { kind, id: Short(key.clone()) })?; + let viewed = lookup(&reader, &PipelineRef { kind, id: Short(key.clone()) })?; if viewed.map(|view| view.document).as_ref() != Some(&stored) { return Err(integrity(&envelope.r#type, key, "does not view back as stored")); } @@ -2305,6 +2314,24 @@ mod tests { assert!(matches!(read_back_of(rows), Err(MindRefusal::Document(_) | MindRefusal::Unavailable { .. }))); } + /// The read path is what the gate compares the stored bytes against: a path + /// that answers nothing, or another document, is refused. + #[test] + fn read_back_refuses_a_read_path_that_does_not_return_the_stored_document() { + let mind = |rows| { + let store = MemoryStore::new(); + rows.into_iter().for_each(|row| store.plant(row)); + Mind::open_with(store, &slug(INSTANCE)).unwrap() + }; + let absent = mind(gate_rows()).read_back_through(|_, _| Ok(None)); + assert!(matches!(&absent, Err(MindRefusal::Unavailable { detail }) if detail.contains("does not view back")), "{absent:?}"); + let other = mind(gate_rows()).read_back_through(|reader, id| { + let first = reader.docs.image.iter().find(|held| held.kind == id.kind).unwrap(); + reader.view_of(first).map(Some) + }); + assert!(matches!(&other, Err(MindRefusal::Unavailable { detail }) if detail.contains("does not view back")), "{other:?}"); + } + #[test] fn read_back_refuses_an_empty_store() { refused_with(Vec::new(), "holds no pipeline document", "");