Skip to main content

mempill_types/
disposition.rs

1//! Disposition: the 12-state outcome model returned on every write.
2
3/// The 12-state disposition model.
4///
5/// Returned synchronously on every write. For heavy-path (belief-overturning) operations,
6/// the engine returns `QueuedForAdjudication` immediately; the final state arrives
7/// asynchronously via the oracle callback.
8#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
9#[non_exhaustive]
10pub enum Disposition {
11    /// New non-conflicting first-hand external fact; committed Active at low currency.
12    CommittedCheap,
13    /// ModelDerived; committed down-weighted, ineligible to overturn until anchored.
14    CommittedInferred,
15    /// Belief-overturning op accepted into async adjudication (non-blocking return).
16    QueuedForAdjudication,
17    /// External contradiction; oracle absent; incumbent downgraded; no resolution yet.
18    Contested,
19    /// Not enough to overturn; both claims surfaced; awaiting evidence/oracle.
20    PendingConflict,
21    /// A depended-on parent was superseded; dependent flagged for review (not auto-invalidated).
22    PendingReview,
23    /// Ambiguous/weak source; held pending corroboration/oracle confirmation.
24    PendingLowConfidence,
25    /// Burst/loop signature or incoherent tx/valid; parked, auditable, not destroyed.
26    Quarantined,
27    /// Belief-overturning accepted; prior claim bounded and retained in history.
28    Superseded,
29    /// Validity assertion marks claim as no-longer-true; retained in history.
30    Invalidated,
31    /// Valid-time reopened by external/first-hand assertion (non-terminal).
32    Reinstated,
33    /// Structural failure: missing/invalid provenance, malformed fact, write-authority violation.
34    Rejected,
35}
36
37/// The synchronous write outcome returned from the engine.
38///
39/// For heavy-path (belief-overturning) operations, `disposition = QueuedForAdjudication`;
40/// the final state arrives asynchronously via the oracle callback.
41#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
42pub struct WriteOutcome {
43    /// Stable reference to the committed (or rejected) claim.
44    pub claim_ref: crate::identity::ClaimRef,
45    /// The synchronous disposition assigned by the engine on this write.
46    pub disposition: Disposition,
47    /// Populated when disposition is Contested or PendingConflict.
48    pub contested_with: Vec<crate::identity::ClaimRef>,
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn disposition_has_exactly_12_variants() {
57        // Enumerate all 12 variants — this test fails to compile if any are missing or renamed.
58        let variants = [
59            Disposition::CommittedCheap,
60            Disposition::CommittedInferred,
61            Disposition::QueuedForAdjudication,
62            Disposition::Contested,
63            Disposition::PendingConflict,
64            Disposition::PendingReview,
65            Disposition::PendingLowConfidence,
66            Disposition::Quarantined,
67            Disposition::Superseded,
68            Disposition::Invalidated,
69            Disposition::Reinstated,
70            Disposition::Rejected,
71        ];
72        assert_eq!(variants.len(), 12);
73    }
74
75    #[test]
76    fn disposition_equality() {
77        assert_eq!(Disposition::CommittedCheap, Disposition::CommittedCheap);
78        assert_ne!(Disposition::CommittedCheap, Disposition::Rejected);
79    }
80
81    #[test]
82    fn disposition_round_trip_serde() {
83        let d = Disposition::PendingReview;
84        let json = serde_json::to_string(&d).unwrap();
85        let back: Disposition = serde_json::from_str(&json).unwrap();
86        assert_eq!(d, back);
87    }
88
89    #[test]
90    fn all_dispositions_round_trip_serde() {
91        let variants = [
92            Disposition::CommittedCheap,
93            Disposition::CommittedInferred,
94            Disposition::QueuedForAdjudication,
95            Disposition::Contested,
96            Disposition::PendingConflict,
97            Disposition::PendingReview,
98            Disposition::PendingLowConfidence,
99            Disposition::Quarantined,
100            Disposition::Superseded,
101            Disposition::Invalidated,
102            Disposition::Reinstated,
103            Disposition::Rejected,
104        ];
105        for d in &variants {
106            let json = serde_json::to_string(d).unwrap();
107            let back: Disposition = serde_json::from_str(&json).unwrap();
108            assert_eq!(d, &back);
109        }
110    }
111}