Skip to main content

rings_measure/
event.rs

1use std::num::NonZeroU64;
2
3use serde::Deserialize;
4use serde::Serialize;
5
6/// Why an observation can be attributed to a stable peer identity.
7///
8/// This is an explicit proof token at the pure transition boundary. Inbound
9/// observations require a cryptographically verified peer. An outbound failure
10/// may instead be attributed to the stable DID selected by the local caller;
11/// it makes no remote identity claim. Pre-authentication ingress remains
12/// unattributable and cannot change the ledger.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum Authentication {
15    /// The event belongs to a cryptographically authenticated stable peer identity.
16    Authenticated,
17    /// Local code explicitly addressed the event to this stable peer identity.
18    ///
19    /// This variant is valid only for locally originated observations, such as
20    /// [`MeasurementEvent::FailedToSend`] when no connection exists. It must
21    /// never authenticate bytes or claims received from the network. A ledger
22    /// may use it to update reliability for an already-retained peer, but it
23    /// must not create a peer record or refresh authenticated-observation time.
24    LocallyAddressed,
25    /// The transport has not authenticated the stable peer identity.
26    Unauthenticated,
27}
28
29impl Authentication {
30    /// Return whether this proof source permits attribution of `event`.
31    pub const fn permits(self, event: MeasurementEvent) -> bool {
32        match self {
33            Self::Authenticated => true,
34            Self::LocallyAddressed => matches!(event, MeasurementEvent::FailedToSend),
35            Self::Unauthenticated => false,
36        }
37    }
38
39    /// Return whether this proof can establish a new retained peer record.
40    pub const fn establishes_peer(self) -> bool {
41        matches!(self, Self::Authenticated)
42    }
43
44    /// Return whether this proof refreshes authenticated peer-observation time.
45    pub const fn refreshes_peer_observation(self) -> bool {
46        matches!(self, Self::Authenticated)
47    }
48}
49
50/// One logical local observation about a remote peer.
51///
52/// Successful transfer variants carry useful payload bytes. Framing, duplicate
53/// chunks, retransmissions, and unverified bytes are not useful payload.
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
55pub enum MeasurementEvent {
56    /// A connection attempt completed successfully.
57    Connected,
58    /// An established or attempted connection ended unsuccessfully.
59    Disconnected,
60    /// One logical message was delivered to the peer.
61    Sent {
62        /// Useful payload bytes delivered to the peer.
63        useful_bytes: u64,
64    },
65    /// One logical message could not be delivered to the peer.
66    ///
67    /// A failure after selecting a destination DID is locally attributable even
68    /// when no authenticated connection exists. A bounded ledger retains that
69    /// evidence only for a peer already established by authenticated observation.
70    /// Remote-originated failures still require authenticated ingress.
71    FailedToSend,
72    /// One logical message from the peer was fully received and verified.
73    Received {
74        /// Useful payload bytes received and verified from the peer.
75        useful_bytes: u64,
76    },
77    /// One logical inbound message failed reassembly, decoding, or verification.
78    FailedToReceive,
79}
80
81/// One or more homogeneous logical observations applied atomically.
82///
83/// For successful transfer events, `useful_bytes` is the aggregate useful
84/// payload across every occurrence. Reliability evidence advances by
85/// [`Self::occurrences`], while byte credit advances once by that aggregate.
86/// This representation lets effect adapters coalesce events in constant space
87/// without inventing zero-byte messages or exposing partial transitions.
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub struct MeasurementBatch {
90    event: MeasurementEvent,
91    occurrences: NonZeroU64,
92}
93
94impl MeasurementBatch {
95    /// Construct an atomic homogeneous batch.
96    pub const fn new(event: MeasurementEvent, occurrences: NonZeroU64) -> Self {
97        Self { event, occurrences }
98    }
99
100    /// Construct a batch containing exactly one observation.
101    pub const fn single(event: MeasurementEvent) -> Self {
102        Self::new(event, NonZeroU64::MIN)
103    }
104
105    /// Aggregate event, including aggregate useful bytes for transfers.
106    pub const fn event(self) -> MeasurementEvent {
107        self.event
108    }
109
110    /// Number of logical observations represented by this batch.
111    pub const fn occurrences(self) -> NonZeroU64 {
112        self.occurrences
113    }
114}
115
116/// A named counter whose checked update can overflow.
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub enum Metric {
119    /// Useful payload bytes sent to a peer.
120    BytesSent,
121    /// Useful payload bytes received from a peer.
122    BytesReceived,
123    /// Successful connection observations.
124    Connected,
125    /// Disconnection observations.
126    Disconnected,
127    /// Successful logical sends.
128    Sent,
129    /// Failed logical sends.
130    FailedToSend,
131    /// Successful verified logical receives.
132    Received,
133    /// Failed logical receives.
134    FailedToReceive,
135}
136
137/// Result of applying an observation at the authentication boundary.
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub enum ApplyOutcome {
140    /// The attributable observation changed the peer record.
141    Applied,
142    /// The proof source cannot attribute this event to the supplied peer.
143    IgnoredUnattributable,
144    /// Local evidence addressed a peer with no retained authenticated record.
145    ///
146    /// Purely local failures cannot establish that the remote peer was ever
147    /// observed, so ignoring them keeps identity rotation from consuming ledger
148    /// capacity or evicting authenticated credit.
149    IgnoredUnknownPeer,
150}