commit 19b98b2fef4e37f95b3d052793366607e1c52c0d
parent 8efbaa6a51d3d63d6c5cb4e96d324e0e682f160c
Author: triesap <tyson@radroots.org>
Date: Tue, 28 Jul 2026 07:12:19 +0000
event_store: cover transition feed shapes
- exercise exact page limits and stored reference parsing
- accept each governed origin and visibility combination
- reject incoherent admission, origin, and suppression shapes
- preserve production AST hashes while improving governed coverage
Diffstat:
1 file changed, 378 insertions(+), 0 deletions(-)
diff --git a/crates/event_store/src/store/addressable_transition_feed_v1.rs b/crates/event_store/src/store/addressable_transition_feed_v1.rs
@@ -956,3 +956,381 @@ fn corruption(reason: impl Into<String>) -> RadrootsEventStoreError {
reason: reason.into(),
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::model::{RadrootsNip09SuppressionOutcome, RadrootsNip09SuppressionReason};
+
+ fn reference(byte: char, event_seq: i64) -> RadrootsAddressableTransitionEventReferenceV1 {
+ RadrootsAddressableTransitionEventReferenceV1 {
+ event_id: RadrootsEventId::parse(byte.to_string().repeat(64)).expect("event id"),
+ event_seq,
+ }
+ }
+
+ fn visible_evidence() -> RadrootsNip09SuppressionEvidenceV1 {
+ RadrootsNip09SuppressionEvidenceV1 {
+ outcome: RadrootsNip09SuppressionOutcome::Visible,
+ reason: RadrootsNip09SuppressionReason::NoAuthorizedReference,
+ event_reference_request_id: None,
+ address_reference_request_id: None,
+ address_reference_cutoff: None,
+ }
+ }
+
+ fn suppressed_evidence() -> RadrootsNip09SuppressionEvidenceV1 {
+ RadrootsNip09SuppressionEvidenceV1 {
+ outcome: RadrootsNip09SuppressionOutcome::Suppressed,
+ reason: RadrootsNip09SuppressionReason::EventIdReference,
+ event_reference_request_id: Some(reference('e', 1).event_id().clone()),
+ address_reference_request_id: None,
+ address_reference_cutoff: None,
+ }
+ }
+
+ #[test]
+ fn transition_page_limits_and_references_are_bounded() {
+ validate_limit(1).expect("minimum limit");
+ validate_limit(RADROOTS_ADDRESSABLE_TRANSITION_PAGE_LIMIT_MAX_V1).expect("maximum limit");
+ assert!(validate_limit(0).is_err());
+ assert!(validate_limit(RADROOTS_ADDRESSABLE_TRANSITION_PAGE_LIMIT_MAX_V1 + 1).is_err());
+
+ let required = required_reference("fixture", "a".repeat(64), 1).expect("reference");
+ assert_eq!(required.event_seq(), 1);
+ assert!(required_reference("fixture", "a".repeat(64), 0).is_err());
+ assert!(required_reference("fixture", "invalid".to_owned(), 1).is_err());
+ assert_eq!(
+ optional_reference("fixture", Some("a".repeat(64)), Some(1))
+ .expect("optional reference"),
+ Some(required)
+ );
+ assert_eq!(
+ optional_reference("fixture", None, None).expect("none"),
+ None
+ );
+ assert!(optional_reference("fixture", Some("a".repeat(64)), None).is_err());
+ assert!(optional_reference("fixture", None, Some(1)).is_err());
+ assert!(optional_event_id("fixture", None).expect("none").is_none());
+ assert!(
+ optional_event_id("fixture", Some("a".repeat(64)))
+ .expect("event id")
+ .is_some()
+ );
+ assert!(optional_event_id("fixture", Some("invalid".to_owned())).is_err());
+ assert!(matches!(
+ corruption("fixture"),
+ RadrootsEventStoreError::AddressableTransitionCorruption { reason }
+ if reason == "fixture"
+ ));
+ }
+
+ #[test]
+ fn transition_shape_accepts_each_visibility_and_origin() {
+ let raw = reference('a', 1);
+ let cause = reference('b', 2);
+ let visible = visible_evidence();
+ validate_transition_shape(
+ RadrootsAddressableTransitionOriginV1::Baseline,
+ &raw,
+ Some(&raw),
+ None,
+ RadrootsEventAdmissionStatus::Admitted,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Visible,
+ Some(&visible),
+ None,
+ RadrootsAddressableTransitionRawHeadDecisionV1::BaselineRebuild,
+ 7,
+ )
+ .expect("baseline visible");
+ validate_transition_shape(
+ RadrootsAddressableTransitionOriginV1::Incremental,
+ &raw,
+ None,
+ None,
+ RadrootsEventAdmissionStatus::Unsupported,
+ Some("unsupported"),
+ None,
+ RadrootsAddressableTransitionVisibilityV1::NotAdmitted,
+ None,
+ Some(&cause),
+ RadrootsAddressableTransitionRawHeadDecisionV1::NotHeadSelected,
+ 7,
+ )
+ .expect("incremental not admitted");
+ let suppressed = suppressed_evidence();
+ validate_transition_shape(
+ RadrootsAddressableTransitionOriginV1::Incremental,
+ &raw,
+ None,
+ None,
+ RadrootsEventAdmissionStatus::Admitted,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Suppressed,
+ Some(&suppressed),
+ Some(&cause),
+ RadrootsAddressableTransitionRawHeadDecisionV1::Applied,
+ 7,
+ )
+ .expect("incremental suppressed");
+ }
+
+ #[test]
+ fn transition_shape_rejects_every_incoherent_axis() {
+ let raw = reference('a', 1);
+ let other = reference('b', 2);
+ let visible = visible_evidence();
+ let suppressed = suppressed_evidence();
+
+ macro_rules! invalid {
+ (
+ $origin:expr, $visible_event:expr, $retracted:expr,
+ $admission:expr, $code:expr, $contract:expr,
+ $visibility:expr, $suppression:expr, $cause:expr, $decision:expr
+ ) => {
+ assert!(
+ validate_transition_shape(
+ $origin,
+ &raw,
+ $visible_event,
+ $retracted,
+ $admission,
+ $code,
+ $contract,
+ $visibility,
+ $suppression,
+ $cause,
+ $decision,
+ 7,
+ )
+ .is_err()
+ )
+ };
+ }
+
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Baseline,
+ Some(&raw),
+ None,
+ RadrootsEventAdmissionStatus::Admitted,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Visible,
+ Some(&visible),
+ Some(&other),
+ RadrootsAddressableTransitionRawHeadDecisionV1::BaselineRebuild
+ );
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Baseline,
+ Some(&raw),
+ Some(&other),
+ RadrootsEventAdmissionStatus::Admitted,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Visible,
+ Some(&visible),
+ None,
+ RadrootsAddressableTransitionRawHeadDecisionV1::BaselineRebuild
+ );
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Baseline,
+ Some(&raw),
+ None,
+ RadrootsEventAdmissionStatus::Admitted,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Visible,
+ Some(&visible),
+ None,
+ RadrootsAddressableTransitionRawHeadDecisionV1::Applied
+ );
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Incremental,
+ Some(&raw),
+ None,
+ RadrootsEventAdmissionStatus::Admitted,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Visible,
+ Some(&visible),
+ None,
+ RadrootsAddressableTransitionRawHeadDecisionV1::Applied
+ );
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Incremental,
+ Some(&raw),
+ None,
+ RadrootsEventAdmissionStatus::Admitted,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Visible,
+ Some(&visible),
+ Some(&other),
+ RadrootsAddressableTransitionRawHeadDecisionV1::BaselineRebuild
+ );
+
+ for (admission, code, contract) in [
+ (
+ RadrootsEventAdmissionStatus::Admitted,
+ Some("bad"),
+ Some("fixture"),
+ ),
+ (RadrootsEventAdmissionStatus::Admitted, None, None),
+ (RadrootsEventAdmissionStatus::Unsupported, None, None),
+ (
+ RadrootsEventAdmissionStatus::Invalid,
+ Some("invalid"),
+ Some("fixture"),
+ ),
+ ] {
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Baseline,
+ Some(&raw),
+ None,
+ admission,
+ code,
+ contract,
+ RadrootsAddressableTransitionVisibilityV1::Visible,
+ Some(&visible),
+ None,
+ RadrootsAddressableTransitionRawHeadDecisionV1::BaselineRebuild
+ );
+ }
+
+ for (admission, visible_event, evidence) in [
+ (
+ RadrootsEventAdmissionStatus::Unsupported,
+ Some(&raw),
+ Some(&visible),
+ ),
+ (
+ RadrootsEventAdmissionStatus::Admitted,
+ Some(&other),
+ Some(&visible),
+ ),
+ (RadrootsEventAdmissionStatus::Admitted, Some(&raw), None),
+ (
+ RadrootsEventAdmissionStatus::Admitted,
+ Some(&raw),
+ Some(&suppressed),
+ ),
+ ] {
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Baseline,
+ visible_event,
+ None,
+ admission,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Visible,
+ evidence,
+ None,
+ RadrootsAddressableTransitionRawHeadDecisionV1::BaselineRebuild
+ );
+ }
+
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Incremental,
+ Some(&raw),
+ None,
+ RadrootsEventAdmissionStatus::Unsupported,
+ Some("unsupported"),
+ None,
+ RadrootsAddressableTransitionVisibilityV1::NotAdmitted,
+ None,
+ Some(&other),
+ RadrootsAddressableTransitionRawHeadDecisionV1::NotHeadSelected
+ );
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Incremental,
+ None,
+ None,
+ RadrootsEventAdmissionStatus::Unsupported,
+ Some("unsupported"),
+ None,
+ RadrootsAddressableTransitionVisibilityV1::NotAdmitted,
+ Some(&visible),
+ Some(&other),
+ RadrootsAddressableTransitionRawHeadDecisionV1::NotHeadSelected
+ );
+
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Incremental,
+ None,
+ None,
+ RadrootsEventAdmissionStatus::Unsupported,
+ Some("unsupported"),
+ None,
+ RadrootsAddressableTransitionVisibilityV1::Suppressed,
+ Some(&suppressed),
+ Some(&other),
+ RadrootsAddressableTransitionRawHeadDecisionV1::Applied
+ );
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Incremental,
+ Some(&raw),
+ None,
+ RadrootsEventAdmissionStatus::Admitted,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Suppressed,
+ Some(&suppressed),
+ Some(&other),
+ RadrootsAddressableTransitionRawHeadDecisionV1::Applied
+ );
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Incremental,
+ None,
+ None,
+ RadrootsEventAdmissionStatus::Admitted,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Suppressed,
+ None,
+ Some(&other),
+ RadrootsAddressableTransitionRawHeadDecisionV1::Applied
+ );
+ invalid!(
+ RadrootsAddressableTransitionOriginV1::Incremental,
+ None,
+ None,
+ RadrootsEventAdmissionStatus::Admitted,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Suppressed,
+ Some(&visible),
+ Some(&other),
+ RadrootsAddressableTransitionRawHeadDecisionV1::Applied
+ );
+
+ assert!(
+ validate_transition_shape(
+ RadrootsAddressableTransitionOriginV1::Incremental,
+ &raw,
+ Some(&raw),
+ Some(&raw),
+ RadrootsEventAdmissionStatus::Admitted,
+ None,
+ Some("fixture"),
+ RadrootsAddressableTransitionVisibilityV1::Visible,
+ Some(&visible),
+ Some(&other),
+ RadrootsAddressableTransitionRawHeadDecisionV1::Applied,
+ 7,
+ )
+ .is_err()
+ );
+
+ let incoherent = RadrootsNip09SuppressionEvidenceV1 {
+ outcome: RadrootsNip09SuppressionOutcome::Visible,
+ reason: RadrootsNip09SuppressionReason::EventIdReference,
+ event_reference_request_id: None,
+ address_reference_request_id: None,
+ address_reference_cutoff: None,
+ };
+ assert!(validate_suppression_shape(&incoherent, 7).is_err());
+ }
+}