Skip to main content

liminal_protocol/wire/authority/
enrollment.rs

1//! Response authority bound to `ClientRequest::Enrollment` (`0x0001`).
2
3use alloc::boxed::Box;
4
5use super::super::{
6    ConnectionConversationBindingOccupied, ConnectionConversationCapacityExceeded,
7    ConversationOrderExhausted, ConversationSequenceExhausted, EnrollBound, EnrollmentEnvelope,
8    EnrollmentKnown, EnrollmentReceiptCapacityScope, Generation, IdentityCapacityExceeded,
9    MarkerClosureCapacityExceeded, ObserverBackpressure, ObserverBackpressureState,
10    ReceiptCapacityExceeded, ReceiptExpired, ReceiptExpiryReason, ReceiptReplay, ResponseEnvelope,
11    Retired, ServerDiscriminant, ServerValue,
12};
13
14/// Server response bound to one enrollment request.
15///
16/// Constructors exist only for the outcomes the frozen R-D1 register admits
17/// for enrollment; every other pairing is a compile error by construction.
18#[derive(Clone, Debug, PartialEq, Eq)]
19pub struct EnrollmentResponse {
20    value: ServerValue,
21}
22
23impl EnrollmentResponse {
24    /// First decoded semantic operation for an untracked conversation
25    /// exceeded the connection-conversation limit (register row 5641).
26    #[must_use]
27    pub const fn connection_conversation_capacity_exceeded(
28        request: EnrollmentEnvelope,
29        limit: u64,
30    ) -> Self {
31        Self {
32            value: ServerValue::ConnectionConversationCapacityExceeded(
33                ConnectionConversationCapacityExceeded::SemanticRequest {
34                    request: ResponseEnvelope::Enrollment(request),
35                    limit,
36                },
37            ),
38        }
39    }
40
41    /// Enrollment binding attempt found an occupied connection/conversation
42    /// slot (register row 5643).
43    #[must_use]
44    pub const fn connection_conversation_binding_occupied(request: &EnrollmentEnvelope) -> Self {
45        Self {
46            value: ServerValue::ConnectionConversationBindingOccupied(
47                ConnectionConversationBindingOccupied::Enrollment {
48                    conversation_id: request.conversation_id,
49                    enrollment_token: request.enrollment_token,
50                },
51            ),
52        }
53    }
54
55    /// Enrollment required an unreserved `transaction_order` major and the
56    /// conversation order is exhausted (register row 5644).
57    ///
58    /// The payload is minted only by the shared order allocator invoked with
59    /// this request's own envelope.
60    pub(crate) const fn from_conversation_order_exhausted(
61        value: Box<ConversationOrderExhausted>,
62    ) -> Self {
63        Self {
64            value: ServerValue::ConversationOrderExhausted(value),
65        }
66    }
67
68    /// Enrollment token mapping resolved to a tombstone (register row 5653).
69    ///
70    /// The payload is minted only by `lookup_enrollment` for this exact
71    /// request.
72    pub(crate) const fn from_retired(value: Retired) -> Self {
73        Self {
74            value: ServerValue::Retired(value),
75        }
76    }
77
78    /// Closure-checked enrollment admission exceeded marker-closure capacity
79    /// (register row 5649).
80    ///
81    /// The payload is minted only by the shared remaining-closure selector
82    /// invoked with this request's own envelope.
83    pub(crate) const fn from_marker_closure_capacity_exceeded(
84        value: Box<MarkerClosureCapacityExceeded>,
85    ) -> Self {
86        Self {
87            value: ServerValue::MarkerClosureCapacityExceeded(value),
88        }
89    }
90
91    /// Successful enrollment attach (register row 5650).
92    #[must_use]
93    pub const fn enroll_bound(value: EnrollBound) -> Self {
94        Self {
95            value: ServerValue::EnrollBound(value),
96        }
97    }
98
99    /// Post-provenance replay for a live non-retired mapped identity
100    /// (register row 5651).
101    #[must_use]
102    pub const fn enrollment_known(value: EnrollmentKnown) -> Self {
103        Self {
104            value: ServerValue::EnrollmentKnown(value),
105        }
106    }
107
108    /// Exact enrollment provenance window response (register row 5652).
109    ///
110    /// The payload is minted only by `lookup_enrollment` for this exact
111    /// request.
112    pub(crate) const fn from_receipt_expired(value: ReceiptExpired) -> Self {
113        Self {
114            value: ServerValue::ReceiptExpired(value),
115        }
116    }
117
118    /// Exact enrollment provenance window response with the flattened
119    /// request-echo fields derived from the request's own envelope (register
120    /// row 5652) — the same public field-wise form as the credential-attach
121    /// authority's `receipt_expired`.
122    ///
123    /// The participant id and both generations must come from the identity
124    /// resolved by the lifetime token mapping and its retained provenance
125    /// record; `presented_generation` is structurally `None` for enrollment
126    /// and the marker option is structurally absent.
127    #[must_use]
128    pub const fn receipt_expired(
129        request: &EnrollmentEnvelope,
130        participant_id: u64,
131        result_generation: Generation,
132        current_generation: Generation,
133        reason: ReceiptExpiryReason,
134    ) -> Self {
135        Self {
136            value: ServerValue::ReceiptExpired(ReceiptExpired::Enrollment {
137                conversation_id: request.conversation_id,
138                token: request.enrollment_token,
139                participant_id,
140                result_generation,
141                current_generation,
142                reason,
143            }),
144        }
145    }
146
147    /// One of the three receipt/provenance scopes reachable before identity
148    /// mint is full (register row 5654).
149    #[must_use]
150    pub const fn receipt_capacity_exceeded(
151        request: EnrollmentEnvelope,
152        scope: EnrollmentReceiptCapacityScope,
153        limit: u64,
154        occupied: u64,
155    ) -> Self {
156        Self {
157            value: ServerValue::ReceiptCapacityExceeded(ReceiptCapacityExceeded::Enrollment {
158                request,
159                scope,
160                limit,
161                occupied,
162            }),
163        }
164    }
165
166    /// Server or conversation identity capacity is full (register row 5655).
167    #[must_use]
168    pub const fn identity_capacity_exceeded(value: IdentityCapacityExceeded) -> Self {
169        Self {
170            value: ServerValue::IdentityCapacityExceeded(value),
171        }
172    }
173
174    /// Hard-observer retention refused the enrollment append (register row
175    /// 5656).
176    #[must_use]
177    pub const fn observer_backpressure(
178        request: EnrollmentEnvelope,
179        state: ObserverBackpressureState,
180    ) -> Self {
181        Self {
182            value: ServerValue::ObserverBackpressure(ObserverBackpressure::Enrollment {
183                request,
184                state,
185            }),
186        }
187    }
188
189    /// Hard-observer retention refusal minted by the shared observer-floor
190    /// selector invoked with this request's own envelope (register row 5656).
191    pub(crate) const fn from_observer_backpressure(value: ObserverBackpressure) -> Self {
192        Self {
193            value: ServerValue::ObserverBackpressure(value),
194        }
195    }
196
197    /// Canonical resulting sequence-reserve check failed (register row 5657).
198    ///
199    /// The payload is minted only by the shared sequence allocator invoked
200    /// with this request's own envelope.
201    pub(crate) const fn from_conversation_sequence_exhausted(
202        value: Box<ConversationSequenceExhausted>,
203    ) -> Self {
204        Self {
205            value: ServerValue::ConversationSequenceExhausted(value),
206        }
207    }
208
209    /// Byte-identical receipt replay whose exact binding epoch still occupies
210    /// its origin slot (register row 5663).
211    #[must_use]
212    pub const fn bound(value: EnrollBound) -> Self {
213        Self {
214            value: ServerValue::Bound(ReceiptReplay::Enrollment(value)),
215        }
216    }
217
218    /// Byte-identical receipt replay whose origin slot is empty, replaced, or
219    /// at a later epoch (register row 5663).
220    #[must_use]
221    pub const fn unbound_receipt(value: EnrollBound) -> Self {
222        Self {
223            value: ServerValue::UnboundReceipt(ReceiptReplay::Enrollment(value)),
224        }
225    }
226
227    /// Byte-identical live-receipt replay minted by `lookup_enrollment`
228    /// (register row 5663).
229    pub(crate) const fn from_bound(value: ReceiptReplay) -> Self {
230        Self {
231            value: ServerValue::Bound(value),
232        }
233    }
234
235    /// Byte-identical unbound-receipt replay minted by `lookup_enrollment`
236    /// (register row 5663).
237    pub(crate) const fn from_unbound_receipt(value: ReceiptReplay) -> Self {
238        Self {
239            value: ServerValue::UnboundReceipt(value),
240        }
241    }
242
243    /// Borrows the bound wire value for encoding or inspection.
244    #[must_use]
245    pub const fn server_value(&self) -> &ServerValue {
246        &self.value
247    }
248
249    /// Returns the bound value's exact wire discriminant.
250    #[must_use]
251    pub const fn discriminant(&self) -> ServerDiscriminant {
252        self.value.discriminant()
253    }
254
255    /// Moves the bound wire value out for transmission.
256    #[must_use]
257    pub fn into_server_value(self) -> ServerValue {
258        self.value
259    }
260}