Skip to main content

mempill_types/
validity.rs

1//! ValidityAssertion: bounds or reopens a claim's valid-time interval.
2
3use crate::claim::Confidence;
4use crate::identity::{AgentId, ClaimRef};
5use crate::provenance::ProvenanceLabel;
6use crate::time::TransactionTime;
7
8/// An assertion that bounds (invalidates) or reopens (reinstates) a claim's valid-time window.
9#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
10pub struct ValidityAssertion {
11    /// Unique ID for this validity assertion (random UUID).
12    pub assertion_ref: uuid::Uuid,
13    /// The agent that submitted this validity assertion.
14    pub agent_id: AgentId,
15    /// The claim whose valid-time this assertion modifies.
16    pub target_claim: ClaimRef,
17    /// Whether this assertion bounds or reopens the target claim.
18    pub kind: AssertionKind,
19    /// Overturning requires External(*) precedence.
20    pub provenance: ProvenanceLabel,
21    /// Confidence in this validity assertion.
22    pub confidence: Confidence,
23    /// Engine-stamped.
24    pub asserted_at: TransactionTime,
25}
26
27/// The kind of validity assertion: whether it bounds or reopens a claim.
28#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
29#[non_exhaustive]
30pub enum AssertionKind {
31    /// Bounds the valid-time of the target claim (marks it no-longer-true as of `bound_at`).
32    Bound {
33        /// The UTC instant at which the claim's validity ends.
34        bound_at: chrono::DateTime<chrono::Utc>,
35    },
36    /// Reopens the valid-time of a previously-bounded claim (Reinstated path).
37    Reopen {
38        /// The UTC instant at which the claim's validity is resumed.
39        reopen_at: chrono::DateTime<chrono::Utc>,
40    },
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46    use crate::identity::AgentId;
47    use crate::claim::Confidence;
48    use crate::provenance::{ExternalKind, ProvenanceLabel};
49    use crate::time::TransactionTime;
50    use chrono::Utc;
51
52    #[test]
53    fn validity_assertion_round_trip_serde() {
54        let now = Utc::now();
55        let va = ValidityAssertion {
56            assertion_ref: uuid::Uuid::new_v4(),
57            agent_id: AgentId("agent-1".into()),
58            target_claim: ClaimRef::new_random(),
59            kind: AssertionKind::Bound { bound_at: now },
60            provenance: ProvenanceLabel::External(ExternalKind::UserAsserted),
61            confidence: Confidence { value_confidence: 1.0, valid_time_confidence: 1.0 },
62            asserted_at: TransactionTime(now),
63        };
64        let json = serde_json::to_string(&va).unwrap();
65        let back: ValidityAssertion = serde_json::from_str(&json).unwrap();
66        assert_eq!(va.assertion_ref, back.assertion_ref);
67        assert_eq!(va.kind, back.kind);
68    }
69
70    #[test]
71    fn assertion_kind_bound_and_reopen_are_distinct() {
72        let now = Utc::now();
73        let bound = AssertionKind::Bound { bound_at: now };
74        let reopen = AssertionKind::Reopen { reopen_at: now };
75        assert_ne!(bound, reopen);
76    }
77}