Skip to main content

liminal_protocol/outcome/
local.rs

1use crate::wire::{ConversationId, Generation, ParticipantId};
2
3/// Complete SDK-local participant request exceeded `min(R, WF)`.
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub struct SdkParticipantRequestTooLarge {
6    /// Conversation named by the unsent request.
7    pub conversation_id: ConversationId,
8    /// Complete encoded participant request bytes.
9    pub encoded_bytes: u64,
10    /// Exact signed effective request limit `R_send`.
11    pub limit: u64,
12}
13
14/// Closed five-way SDK parking-capacity outcome.
15///
16/// Encoding the scope/dimension pair in the enum makes the forbidden
17/// `PerConversation/Conversations` combination unconstructible.
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub enum SdkObserverParkCapacityExceeded {
20    /// Per-conversation row count exceeded `N`.
21    PerConversationRows {
22        /// Conversation receiving the row.
23        conversation_id: ConversationId,
24        /// Signed per-conversation row limit.
25        limit: u64,
26        /// Current rows in the conversation.
27        occupied: u64,
28        /// Full requested row count.
29        requested: u64,
30    },
31    /// Per-conversation charged bytes exceeded `C`.
32    PerConversationBytes {
33        /// Conversation receiving the row.
34        conversation_id: ConversationId,
35        /// Signed per-conversation byte limit.
36        limit: u64,
37        /// Current full-row bytes in the conversation.
38        occupied: u64,
39        /// Exact full-row bytes requested.
40        requested: u64,
41    },
42    /// SDK-wide parked-conversation count exceeded `P`.
43    SdkWideConversations {
44        /// Conversation requiring its first parked slot.
45        conversation_id: ConversationId,
46        /// Signed SDK conversation limit.
47        limit: u64,
48        /// Current parked-conversation count.
49        occupied: u64,
50        /// Requested conversations; v1 requests one.
51        requested: u64,
52    },
53    /// SDK-wide parked-row count exceeded `G`.
54    SdkWideRows {
55        /// Conversation receiving the row.
56        conversation_id: ConversationId,
57        /// Signed SDK row limit.
58        limit: u64,
59        /// Current SDK row count.
60        occupied: u64,
61        /// Full requested row count.
62        requested: u64,
63    },
64    /// SDK-wide parked bytes exceeded `D`.
65    SdkWideBytes {
66        /// Conversation receiving the row.
67        conversation_id: ConversationId,
68        /// Signed SDK byte limit.
69        limit: u64,
70        /// Current SDK full-row bytes.
71        occupied: u64,
72        /// Exact full-row bytes requested.
73        requested: u64,
74    },
75}
76
77/// Singleton local counter selector.
78#[derive(Clone, Copy, Debug, PartialEq, Eq)]
79pub enum ParkOrderCounter {
80    /// Per-conversation durable park order.
81    ParkOrder,
82}
83
84/// Nonempty parked set exhausted its checked park-order counter.
85#[derive(Clone, Copy, Debug, PartialEq, Eq)]
86pub struct SdkParkOrderExhausted {
87    conversation_id: ConversationId,
88}
89
90impl SdkParkOrderExhausted {
91    /// Constructs the only legal exhausted-counter payload.
92    #[must_use]
93    pub const fn new(conversation_id: ConversationId) -> Self {
94        Self { conversation_id }
95    }
96
97    /// Conversation whose nonempty set exhausted.
98    #[must_use]
99    pub const fn conversation_id(self) -> ConversationId {
100        self.conversation_id
101    }
102
103    /// Returns the fixed counter selector.
104    #[must_use]
105    pub const fn counter(self) -> ParkOrderCounter {
106        let _ = self;
107        ParkOrderCounter::ParkOrder
108    }
109
110    /// Returns the terminal maximum counter value.
111    #[must_use]
112    pub const fn value(self) -> u64 {
113        let _ = self;
114        u64::MAX
115    }
116}
117
118/// Singleton ambiguous local operation selector.
119#[derive(Clone, Copy, Debug, PartialEq, Eq)]
120pub enum RecordAdmissionOperation {
121    /// Untokenized ordinary record admission.
122    OrdinaryRecordAdmission,
123}
124
125/// SDK-local terminal ambiguity after an ordinary record response is lost.
126#[derive(Clone, Copy, Debug, PartialEq, Eq)]
127pub struct RecordAdmissionUnknown {
128    /// Conversation from the lost request.
129    pub conversation_id: ConversationId,
130    /// Participant from the lost request.
131    pub participant_id: ParticipantId,
132    /// Presented generation from the lost request.
133    pub capability_generation: Generation,
134    /// Operation is exactly ordinary record admission.
135    pub operation: RecordAdmissionOperation,
136    /// Durable SDK row order deleted by this transition.
137    pub park_order: u64,
138}
139
140/// SDK terminal state after a credential-rotation result becomes unrecoverable.
141#[derive(Clone, Copy, Debug, PartialEq, Eq)]
142pub struct CredentialRecoveryLost {
143    /// Conversation whose credential continuity was lost.
144    pub conversation_id: ConversationId,
145    /// Preserved permanent participant identity.
146    pub participant_id: ParticipantId,
147    /// Last credential generation durably known by the SDK.
148    pub last_known_generation: Generation,
149}
150
151/// Reconnect lifecycle state reported without exposing permit identity.
152#[derive(Clone, Copy, Debug, PartialEq, Eq)]
153pub enum ReconnectState {
154    /// No authorization or attempt is outstanding.
155    Parked,
156    /// One fresh-event permit is outstanding.
157    PermitOutstanding,
158    /// One real connection attempt is in progress.
159    AttemptInProgress,
160    /// The connection is proved online.
161    Online,
162}
163
164/// Fresh event class required to mint one reconnect permit.
165#[derive(Clone, Copy, Debug, PartialEq, Eq)]
166pub enum ReconnectRequiredEvent {
167    /// Established-connection transport fate.
168    TransportFate,
169    /// Proved online transition.
170    OnlineTransition,
171    /// Explicit caller action.
172    ExplicitCallerAction,
173}
174
175/// Exact SDK-local reconnect result, retained under its stable name.
176///
177/// The former delay field is deliberately absent: fresh events authorize one
178/// real attempt and never a timer arm.
179#[derive(Clone, Copy, Debug, PartialEq, Eq)]
180pub enum ReconnectDelayResult {
181    /// A fresh single-use event permit was minted.
182    ReconnectArmed {
183        /// Exact fresh event class that minted the permit.
184        event: ReconnectRequiredEvent,
185    },
186    /// No fresh event permit was minted.
187    ReconnectNotArmed {
188        /// Current reconnect state.
189        state: ReconnectState,
190        /// Event class required for a future authorization.
191        required_event: ReconnectRequiredEvent,
192    },
193}