Skip to main content

liminal_protocol/wire/authority/
credential_attach.rs

1//! Response authority bound to `ClientRequest::CredentialAttach` (`0x0002`).
2
3use alloc::boxed::Box;
4
5use super::super::{
6    AttachBound, AttachEnvelope, AttachMarkerProof, AttemptConflict, AttemptTokenBodyConflict,
7    CommonStaleAuthorityEnvelope, ConnectionConversationBindingOccupied,
8    ConnectionConversationCapacityExceeded, ConversationOrderExhausted,
9    ConversationSequenceExhausted, DeliverySeq, Generation, MarkerClosureCapacityExceeded,
10    MarkerMismatch, MarkerMismatchBody, MarkerNotDelivered, MarkerNotDeliveredReason,
11    MarkerProofRequest, ObserverBackpressure, ObserverBackpressureState,
12    ParticipantReferenceEnvelope, ParticipantUnknown, ReceiptCapacityExceeded,
13    ReceiptCapacityScope, ReceiptExpired, ReceiptExpiryReason, ReceiptReplay, ResponseEnvelope,
14    Retired, SequenceAllocatingEnvelope, SequenceBudget, ServerDiscriminant, ServerValue,
15    StaleAuthority, StaleOrUnknownReceipt,
16};
17use crate::wire::closure::{ClosureCheckedEnvelope, ClosureRefusalReason, ClosureSnapshot};
18
19/// Server response bound to one credential-attach request.
20///
21/// Constructors exist only for the outcomes the frozen R-D1 register admits
22/// for credential attach; every other pairing is a compile error by
23/// construction.
24#[derive(Clone, Debug, PartialEq, Eq)]
25pub struct CredentialAttachResponse {
26    value: ServerValue,
27}
28
29impl CredentialAttachResponse {
30    /// Verified exact live receipt with a changed canonical non-secret body;
31    /// generation is tested before the marker sequence (register row 5639).
32    #[must_use]
33    pub const fn attempt_token_body_conflict(
34        request: &AttachEnvelope,
35        conflict: AttemptConflict,
36    ) -> Self {
37        Self {
38            value: ServerValue::AttemptTokenBodyConflict(
39                AttemptTokenBodyConflict::CredentialAttach {
40                    token: request.attach_attempt_token,
41                    conversation_id: request.conversation_id,
42                    presented_participant_id: request.participant_id,
43                    presented_generation: request.capability_generation,
44                    presented_marker_delivery_seq: request.accept_marker_delivery_seq,
45                    conflict,
46                },
47            ),
48        }
49    }
50
51    /// First decoded semantic operation for an untracked conversation
52    /// exceeded the connection-conversation limit (register row 5641).
53    #[must_use]
54    pub const fn connection_conversation_capacity_exceeded(
55        request: AttachEnvelope,
56        limit: u64,
57    ) -> Self {
58        Self {
59            value: ServerValue::ConnectionConversationCapacityExceeded(
60                ConnectionConversationCapacityExceeded::SemanticRequest {
61                    request: ResponseEnvelope::CredentialAttach(request),
62                    limit,
63                },
64            ),
65        }
66    }
67
68    /// Credential-attach binding attempt found an occupied slot owned by a
69    /// different participant (register row 5643).
70    #[must_use]
71    pub const fn connection_conversation_binding_occupied(request: &AttachEnvelope) -> Self {
72        Self {
73            value: ServerValue::ConnectionConversationBindingOccupied(
74                ConnectionConversationBindingOccupied::CredentialAttach {
75                    conversation_id: request.conversation_id,
76                    participant_id: request.participant_id,
77                    capability_generation: request.capability_generation,
78                    attach_attempt_token: request.attach_attempt_token,
79                    accept_marker_delivery_seq: request.accept_marker_delivery_seq,
80                },
81            ),
82        }
83    }
84
85    /// Credential attach required an unreserved `transaction_order` major and
86    /// the conversation order is exhausted (register row 5644).
87    #[must_use]
88    pub fn conversation_order_exhausted(
89        request: AttachEnvelope,
90        high: u64,
91        order_remaining: u128,
92        reserved_claims: u128,
93        resulting_order_remaining: u128,
94        resulting_reserved_claims: u128,
95    ) -> Self {
96        Self {
97            value: ServerValue::ConversationOrderExhausted(Box::new(
98                ConversationOrderExhausted::new(
99                    super::super::OrderAllocatingEnvelope::CredentialAttach(request),
100                    high,
101                    order_remaining,
102                    reserved_claims,
103                    resulting_order_remaining,
104                    resulting_reserved_claims,
105                ),
106            )),
107        }
108    }
109
110    /// Presented participant is unknown (register row 5645).
111    #[must_use]
112    pub const fn participant_unknown(request: AttachEnvelope) -> Self {
113        Self {
114            value: ServerValue::ParticipantUnknown(ParticipantUnknown {
115                request: ParticipantReferenceEnvelope::CredentialAttach(request),
116            }),
117        }
118    }
119
120    /// Live generation or secret authority is stale (register rows 5647,
121    /// 5660, 5665).
122    #[must_use]
123    pub const fn stale_authority(request: AttachEnvelope, current_generation: Generation) -> Self {
124        Self {
125            value: ServerValue::StaleAuthority(StaleAuthority::Live {
126                request: CommonStaleAuthorityEnvelope::CredentialAttach(request),
127                current_generation,
128            }),
129        }
130    }
131
132    /// Presented id or exact token resolved to a tombstone (register rows
133    /// 5648, 5659, 5667).
134    #[must_use]
135    pub const fn retired(request: AttachEnvelope, retired_generation: Generation) -> Self {
136        Self {
137            value: ServerValue::Retired(Retired::Participant {
138                request: ParticipantReferenceEnvelope::CredentialAttach(request),
139                retired_generation,
140            }),
141        }
142    }
143
144    /// Closure-checked attach admission exceeded marker-closure capacity
145    /// (register rows 5649, 5662).
146    #[must_use]
147    pub fn marker_closure_capacity_exceeded(
148        request: AttachEnvelope,
149        snapshot: ClosureSnapshot,
150        reason: ClosureRefusalReason,
151    ) -> Self {
152        Self {
153            value: ServerValue::MarkerClosureCapacityExceeded(Box::new(
154                MarkerClosureCapacityExceeded {
155                    request: ClosureCheckedEnvelope::CredentialAttach(request),
156                    snapshot,
157                    reason,
158                },
159            )),
160        }
161    }
162
163    /// Successful credential attach (register row 5658).
164    #[must_use]
165    pub const fn attach_bound(value: AttachBound) -> Self {
166        Self {
167            value: ServerValue::AttachBound(value),
168        }
169    }
170
171    /// Exact credential-attach provenance window response; the flattened
172    /// request-echo fields are derived from the request's own envelope
173    /// (register rows 5659, 5664).
174    #[must_use]
175    pub const fn receipt_expired(
176        request: &AttachEnvelope,
177        result_generation: Generation,
178        current_generation: Generation,
179        reason: ReceiptExpiryReason,
180    ) -> Self {
181        Self {
182            value: ServerValue::ReceiptExpired(ReceiptExpired::CredentialAttach {
183                conversation_id: request.conversation_id,
184                token: request.attach_attempt_token,
185                participant_id: request.participant_id,
186                presented_generation: request.capability_generation,
187                presented_marker_delivery_seq: request.accept_marker_delivery_seq,
188                result_generation,
189                current_generation,
190                reason,
191            }),
192        }
193    }
194
195    /// Post-provenance ambiguity: the receipt is no longer known (register
196    /// rows 5659, 5666).
197    #[must_use]
198    pub const fn stale_or_unknown_receipt(value: StaleOrUnknownReceipt) -> Self {
199        Self {
200            value: ServerValue::StaleOrUnknownReceipt(value),
201        }
202    }
203
204    /// Fenced attach named a marker that was never delivered to the proof
205    /// epoch (register row 5661).
206    #[must_use]
207    pub const fn marker_not_delivered(
208        proof: AttachMarkerProof,
209        reason: MarkerNotDeliveredReason,
210        expected_marker_delivery_seq: DeliverySeq,
211    ) -> Self {
212        Self {
213            value: ServerValue::MarkerNotDelivered(MarkerNotDelivered {
214                request: MarkerProofRequest::CredentialAttach(proof),
215                reason,
216                expected_marker_delivery_seq,
217            }),
218        }
219    }
220
221    /// Fenced attach named a marker that mismatches current marker state
222    /// (register row 5661).
223    #[must_use]
224    pub const fn marker_mismatch(proof: AttachMarkerProof, mismatch: MarkerMismatchBody) -> Self {
225        Self {
226            value: ServerValue::MarkerMismatch(MarkerMismatch {
227                request: MarkerProofRequest::CredentialAttach(proof),
228                mismatch,
229            }),
230        }
231    }
232
233    /// The first full scope in the exact five-scope receipt/provenance order
234    /// (register row 5662).
235    #[must_use]
236    pub const fn receipt_capacity_exceeded(
237        request: AttachEnvelope,
238        scope: ReceiptCapacityScope,
239        limit: u64,
240        occupied: u64,
241    ) -> Self {
242        Self {
243            value: ServerValue::ReceiptCapacityExceeded(
244                ReceiptCapacityExceeded::CredentialAttach {
245                    request,
246                    scope,
247                    limit,
248                    occupied,
249                },
250            ),
251        }
252    }
253
254    /// Hard-observer retention refused the attach append (register row 5662).
255    #[must_use]
256    pub const fn observer_backpressure(
257        request: AttachEnvelope,
258        state: ObserverBackpressureState,
259    ) -> Self {
260        Self {
261            value: ServerValue::ObserverBackpressure(ObserverBackpressure::CredentialAttach {
262                request,
263                state,
264            }),
265        }
266    }
267
268    /// Canonical resulting sequence-reserve check failed (register row 5662).
269    #[must_use]
270    pub fn conversation_sequence_exhausted(
271        request: AttachEnvelope,
272        sequence_budget: SequenceBudget,
273    ) -> Self {
274        Self {
275            value: ServerValue::ConversationSequenceExhausted(Box::new(
276                ConversationSequenceExhausted {
277                    request: SequenceAllocatingEnvelope::CredentialAttach(request),
278                    sequence_budget,
279                },
280            )),
281        }
282    }
283
284    /// Byte-identical receipt replay whose exact binding epoch still occupies
285    /// its origin slot (register row 5663).
286    #[must_use]
287    pub const fn bound(value: AttachBound) -> Self {
288        Self {
289            value: ServerValue::Bound(ReceiptReplay::CredentialAttach(value)),
290        }
291    }
292
293    /// Byte-identical receipt replay whose origin slot is empty, replaced, or
294    /// at a later epoch (register row 5663).
295    #[must_use]
296    pub const fn unbound_receipt(value: AttachBound) -> Self {
297        Self {
298            value: ServerValue::UnboundReceipt(ReceiptReplay::CredentialAttach(value)),
299        }
300    }
301
302    /// Borrows the bound wire value for encoding or inspection.
303    #[must_use]
304    pub const fn server_value(&self) -> &ServerValue {
305        &self.value
306    }
307
308    /// Returns the bound value's exact wire discriminant.
309    #[must_use]
310    pub const fn discriminant(&self) -> ServerDiscriminant {
311        self.value.discriminant()
312    }
313
314    /// Moves the bound wire value out for transmission.
315    #[must_use]
316    pub fn into_server_value(self) -> ServerValue {
317        self.value
318    }
319}