From 5357e9d906d2edeee42b664a37e96672ca3e21bb Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 31 Oct 2026 09:54:39 +0100 Subject: [PATCH] tests: a withdrawal pulse crosses encoding, admission and the read as a withdrawal (withdrawal-wire-unpinned) Co-Authored-By: Claude Sonnet 5.5 --- crates/eureka-pipeline/src/lib.rs | 24 ++++++++++++++++++++++++ crates/huginn-mind/src/query.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/crates/eureka-pipeline/src/lib.rs b/crates/eureka-pipeline/src/lib.rs index 11f4f65..a99b990 100644 --- a/crates/eureka-pipeline/src/lib.rs +++ b/crates/eureka-pipeline/src/lib.rs @@ -1462,6 +1462,30 @@ mod tests { ruling } + /// A withdrawal is a pulse that says only `tempo_vote_withdrawn`: it must survive + /// encoding to an envelope, JSON and named MessagePack as a withdrawal, and an + /// unwithdrawn pulse must not write the key. + #[test] + fn a_withdrawal_pulse_encodes_and_reads_back_as_a_withdrawal() -> Result<()> { + let cache = schema_cache()?; + let pulse = |withdrawn: bool, urgency: Option| { + PipelineDocument::Pulse(PipelinePulse { instance: slug(INSTANCE), label: l("2026-10-31t041200-t0"), tempo_vote_beat_s: None, tempo_vote_withdrawn: withdrawn, urgency_permille: urgency, note: "".into() }) + }; + let withdrawal = pulse(true, None); + withdrawal.validate()?; + let read_back = PipelineDocument::decode(&withdrawal.prepare(&cache)?)?; + assert!(matches!(&read_back, PipelineDocument::Pulse(read) if read.tempo_vote_withdrawn), "{read_back:?}"); + let json = serde_json::to_value(&withdrawal)?; + assert_eq!(json["value"]["tempo_vote_withdrawn"], true); + assert!(matches!(serde_json::from_value::(json)?, PipelineDocument::Pulse(read) if read.tempo_vote_withdrawn)); + let packed = rmp_serde::to_vec_named(&withdrawal)?; + assert!(matches!(rmp_serde::from_slice::(&packed)?, PipelineDocument::Pulse(read) if read.tempo_vote_withdrawn)); + let urging = pulse(false, Some(5)); + assert!(serde_json::to_value(&urging)?["value"].get("tempo_vote_withdrawn").is_none(), "an unwithdrawn pulse writes no key"); + assert!(matches!(PipelineDocument::decode(&urging.prepare(&cache)?)?, PipelineDocument::Pulse(read) if !read.tempo_vote_withdrawn)); + Ok(()) + } + #[test] fn a_ruling_with_authority_mind_keys_encodes_and_round_trips_like_any_ruling() -> Result<()> { let cache = schema_cache()?; diff --git a/crates/huginn-mind/src/query.rs b/crates/huginn-mind/src/query.rs index e77346a..634320e 100644 --- a/crates/huginn-mind/src/query.rs +++ b/crates/huginn-mind/src/query.rs @@ -1486,6 +1486,37 @@ mod tests { assert!(invalid("fields[0].values", "false")(&refused(&mind, &outside))); } + /// A withdrawal pulse admitted into the mind is read back as a withdrawal: its + /// facts say so, `voted` selects it, and a later plain vote is not one. + #[test] + fn an_admitted_withdrawal_pulse_reads_back_as_a_withdrawal() { + let mut mind = seeded(); + let pulse = |label: &str, beat: Option, withdrawn: bool| { + D::Pulse(eureka_pipeline::PipelinePulse { + instance: Slug(INSTANCE.into()), + label: Label(label.into()), + tempo_vote_beat_s: beat, + tempo_vote_withdrawn: withdrawn, + urgency_permille: None, + note: "n".into(), + }) + }; + committed(admit(&mut mind, vec![pulse("vote", Some(60), false)])); + committed(admit(&mut mind, vec![pulse("withdraw", None, true)])); + let newest = || { + let selection = Selection { descending: true, limit: Some(1), ..with(of_kinds(&[K::Pulse]), any_of("voted", &["true"])) }; + let page = mind.query(&selection).unwrap(); + headers(&page).to_vec() + }; + let found = newest(); + assert_eq!(found.len(), 1); + assert_eq!(found[0].id.id.0, format!("{INSTANCE}:pulse:withdraw")); + assert!(matches!(found[0].facts, PipelineFacts::Pulse { tempo_vote_beat_s: None, tempo_vote_withdrawn: true, .. }), "{:?}", found[0].facts); + committed(admit(&mut mind, vec![pulse("again", Some(90), false)])); + let found = newest(); + assert!(matches!(found[0].facts, PipelineFacts::Pulse { tempo_vote_beat_s: Some(90), tempo_vote_withdrawn: false, .. }), "{:?}", found[0].facts); + } + /// The substrate's own refusals cross as themselves: an undeclared alias /// is a `SelectionInvalid` from the substrate's door, before the organ's. #[test]