liminal_protocol/wire/authority/records.rs
1//! Response authorities bound to `ClientRequest::RecordAdmission` (`0x0007`)
2//! and `ClientRequest::ObserverRecovery` (`0x0008`).
3
4use alloc::boxed::Box;
5
6use super::super::{
7 AttemptTokenBodyConflict, ConnectionConversationCapacityExceeded, ConversationId,
8 ConversationOrderExhausted, ConversationSequenceExhausted, Generation, InvalidObserverEpoch,
9 InvalidObserverEpochList, MarkerClosureCapacityExceeded, NoBinding, ObserverBackpressure,
10 ObserverRecoveryAccepted, ParticipantId, ParticipantUnknown, RecordAdmissionAttemptToken,
11 RecordAdmissionEnvelope, RecordCommitted, RecordTooLarge, ResponseEnvelope, Retired,
12 ServerDiscriminant, ServerValue, StaleAuthority,
13};
14
15/// Server response bound to one ordinary record admission.
16///
17/// Constructors exist only for the outcomes the frozen R-D1 register admits
18/// for ordinary admission; every other pairing is a compile error by
19/// construction.
20#[derive(Clone, Debug, PartialEq, Eq)]
21pub struct RecordAdmissionResponse {
22 value: ServerValue,
23}
24
25impl RecordAdmissionResponse {
26 /// Exact committed attempt token re-presented by its OWN verified
27 /// participant under different canonical payload bytes (register row 5639,
28 /// whose admitted-request set gains `RecordAdmission` under contract
29 /// §0.15 amendment A4).
30 ///
31 /// Ordinary admission selects no [`AttemptConflict`](super::super::AttemptConflict)
32 /// selector, in the same way Leave selects no marker one: the committed
33 /// identity is the (token, canonical-payload fingerprint, verified
34 /// participant) triple, so the one conflicting axis is the canonical body
35 /// this row is named for.
36 ///
37 /// ⛔ Only the SAME-participant arm may reach this constructor. A token
38 /// hit belonging to a DIFFERENT participant is a dedup miss that commits
39 /// silently: any token-correlated answer across participants is a probe
40 /// channel A4 outlaws permanently, and the server-side range that finds
41 /// such a hit stays warn-and-fall-through.
42 #[must_use]
43 pub const fn attempt_token_body_conflict(
44 token: RecordAdmissionAttemptToken,
45 conversation_id: ConversationId,
46 presented_participant_id: ParticipantId,
47 presented_generation: Generation,
48 ) -> Self {
49 Self {
50 value: ServerValue::AttemptTokenBodyConflict(
51 AttemptTokenBodyConflict::RecordAdmission {
52 token,
53 conversation_id,
54 presented_participant_id,
55 presented_generation,
56 },
57 ),
58 }
59 }
60
61 /// First decoded semantic operation for an untracked conversation
62 /// exceeded the connection-conversation limit (register row 5641).
63 #[must_use]
64 pub const fn connection_conversation_capacity_exceeded(
65 request: RecordAdmissionEnvelope,
66 limit: u64,
67 ) -> Self {
68 Self {
69 value: ServerValue::ConnectionConversationCapacityExceeded(
70 ConnectionConversationCapacityExceeded::SemanticRequest {
71 request: ResponseEnvelope::RecordAdmission(request),
72 limit,
73 },
74 ),
75 }
76 }
77
78 /// Ordinary admission required an unreserved `transaction_order` major
79 /// and the conversation order is exhausted (register row 5644).
80 ///
81 /// The payload is minted only by the shared order allocator invoked with
82 /// this request's own envelope.
83 pub(crate) const fn from_conversation_order_exhausted(
84 value: Box<ConversationOrderExhausted>,
85 ) -> Self {
86 Self {
87 value: ServerValue::ConversationOrderExhausted(value),
88 }
89 }
90
91 /// Presented participant is unknown (register row 5645).
92 ///
93 /// The payload is minted only by `lookup_binding_required` for this
94 /// exact request.
95 pub(crate) const fn from_participant_unknown(value: ParticipantUnknown) -> Self {
96 Self {
97 value: ServerValue::ParticipantUnknown(value),
98 }
99 }
100
101 /// Exact-binding lookup missed (register row 5646).
102 ///
103 /// The payload is minted only by `lookup_binding_required` for this
104 /// exact request.
105 pub(crate) const fn from_no_binding(value: NoBinding) -> Self {
106 Self {
107 value: ServerValue::NoBinding(value),
108 }
109 }
110
111 /// Live generation authority is stale (register row 5647).
112 ///
113 /// The payload is minted only by `lookup_binding_required` for this
114 /// exact request.
115 pub(crate) const fn from_stale_authority(value: StaleAuthority) -> Self {
116 Self {
117 value: ServerValue::StaleAuthority(value),
118 }
119 }
120
121 /// Presented id has a tombstone (register row 5648).
122 ///
123 /// The payload is minted only by `lookup_binding_required` for this
124 /// exact request.
125 pub(crate) const fn from_retired(value: Retired) -> Self {
126 Self {
127 value: ServerValue::Retired(value),
128 }
129 }
130
131 /// Closure-checked ordinary admission exceeded marker-closure capacity
132 /// (register rows 5649, 5686).
133 ///
134 /// The payload is minted only by the shared remaining-closure selector
135 /// invoked with this request's own envelope.
136 pub(crate) const fn from_marker_closure_capacity_exceeded(
137 value: Box<MarkerClosureCapacityExceeded>,
138 ) -> Self {
139 Self {
140 value: ServerValue::MarkerClosureCapacityExceeded(value),
141 }
142 }
143
144 /// The ordinary record committed (register row 5685).
145 #[must_use]
146 pub const fn record_committed(value: RecordCommitted) -> Self {
147 Self {
148 value: ServerValue::RecordCommitted(value),
149 }
150 }
151
152 /// The record exceeds the configured entry or byte maximum (register row
153 /// 5686).
154 #[must_use]
155 pub const fn record_too_large(value: RecordTooLarge) -> Self {
156 Self {
157 value: ServerValue::RecordTooLarge(value),
158 }
159 }
160
161 /// Canonical resulting sequence-reserve check failed (register row 5686).
162 ///
163 /// The payload is minted only by the shared sequence allocator invoked
164 /// with this request's own envelope.
165 pub(crate) const fn from_conversation_sequence_exhausted(
166 value: Box<ConversationSequenceExhausted>,
167 ) -> Self {
168 Self {
169 value: ServerValue::ConversationSequenceExhausted(value),
170 }
171 }
172
173 /// Hard-observer retention refused the ordinary append (register row
174 /// 5687).
175 ///
176 /// The payload is minted only by the shared observer-floor selector
177 /// invoked with this request's own envelope.
178 pub(crate) const fn from_observer_backpressure(value: ObserverBackpressure) -> Self {
179 Self {
180 value: ServerValue::ObserverBackpressure(value),
181 }
182 }
183
184 /// Borrows the bound wire value for encoding or inspection.
185 #[must_use]
186 pub const fn server_value(&self) -> &ServerValue {
187 &self.value
188 }
189
190 /// Returns the bound value's exact wire discriminant.
191 #[must_use]
192 pub const fn discriminant(&self) -> ServerDiscriminant {
193 self.value.discriminant()
194 }
195
196 /// Moves the bound wire value out for transmission.
197 #[must_use]
198 pub fn into_server_value(self) -> ServerValue {
199 self.value
200 }
201}
202
203/// Server response bound to one observer-recovery handshake batch.
204///
205/// The register admits exactly four outcomes for the one-shot recovery batch
206/// (rows 5642, 5688, 5689); the contract's routing rule (lines 5780-5782)
207/// marks all four as already request-specific, so they carry no
208/// `originating_request` echo. Every other pairing is a compile error by
209/// construction.
210#[derive(Clone, Debug, PartialEq, Eq)]
211pub struct ObserverRecoveryResponse {
212 value: ServerValue,
213}
214
215impl ObserverRecoveryResponse {
216 /// Batch preflight found an untracked conversation that would exceed the
217 /// signed connection-conversation limit (register row 5642, wire
218 /// `0x0124`).
219 #[must_use]
220 pub const fn connection_capacity_exceeded(conversation_id: ConversationId, limit: u64) -> Self {
221 Self {
222 value: ServerValue::ConnectionConversationCapacityExceeded(
223 ConnectionConversationCapacityExceeded::ObserverRecovery {
224 conversation_id,
225 limit,
226 },
227 ),
228 }
229 }
230
231 /// Whole-batch success with request-ordered statuses (register row 5688).
232 #[must_use]
233 pub const fn accepted(value: ObserverRecoveryAccepted) -> Self {
234 Self {
235 value: ServerValue::ObserverRecoveryAccepted(value),
236 }
237 }
238
239 /// Whole-batch unknown-conversation or ahead-epoch refusal (register row
240 /// 5689).
241 #[must_use]
242 pub const fn invalid_observer_epoch(value: InvalidObserverEpoch) -> Self {
243 Self {
244 value: ServerValue::InvalidObserverEpoch(value),
245 }
246 }
247
248 /// Whole-batch list-shape refusal (register row 5689).
249 #[must_use]
250 pub const fn invalid_observer_epoch_list(value: InvalidObserverEpochList) -> Self {
251 Self {
252 value: ServerValue::InvalidObserverEpochList(value),
253 }
254 }
255
256 /// Borrows the bound wire value for encoding or inspection.
257 #[must_use]
258 pub const fn server_value(&self) -> &ServerValue {
259 &self.value
260 }
261
262 /// Returns the bound value's exact wire discriminant.
263 #[must_use]
264 pub const fn discriminant(&self) -> ServerDiscriminant {
265 self.value.discriminant()
266 }
267
268 /// Moves the bound wire value out for transmission.
269 #[must_use]
270 pub fn into_server_value(self) -> ServerValue {
271 self.value
272 }
273}