Skip to main content

liminal_protocol/wire/
server_codec.rs

1//! Deterministic body codec for the contiguous server-value registry.
2//!
3//! The complete-frame codec delegates only the semantic body to this module.
4//! In particular, `originating_request` and observer-recovery `status_count`
5//! are routing selectors: invalid routes fail before an unread suffix is
6//! interpreted.
7
8use alloc::{string::String, vec::Vec};
9
10use crate::algebra::{ResourceDimension, ResourceVector, WideResourceVector};
11
12use super::codec::CodecError;
13use super::{
14    AttachAttemptToken, AttachSecret, BindingEpoch, ConnectionIncarnation, DetachAttemptToken,
15    EnrollmentToken, Generation, LeaveAttemptToken, ProtocolVersion, RecordAdmissionAttemptToken,
16    closure as c, envelope as e, response as r, tags as t,
17};
18
19const TOKEN_LEN: usize = 16;
20const SECRET_LEN: usize = 32;
21const RECOVERY_STATUS_LEN: u128 = 26;
22
23/// Unforgeable outside this module; authorizes construction from authenticated
24/// wire bytes without weakening the server-side terminalized-state signature.
25pub(super) struct TerminalizedWireDecodeAuthority(());
26
27const TERMINALIZED_WIRE_DECODE_AUTHORITY: TerminalizedWireDecodeAuthority =
28    TerminalizedWireDecodeAuthority(());
29
30/// Encodes a semantic server value's exact v1 body.
31///
32/// The returned discriminant belongs with the returned body and cannot drift
33/// from the selected Rust variant.
34///
35/// # Errors
36///
37/// Returns [`CodecError::UnsupportedVersion`] for a version other than v1.0,
38/// [`CodecError::LengthOverflow`] for a variable field that cannot fit its
39/// canonical length prefix, or [`CodecError::InvalidValue`] when a typed value
40/// violates a fixed wire invariant.
41pub fn encode_server_value_body(
42    value: &r::ServerValue,
43    version: ProtocolVersion,
44) -> Result<(t::ServerDiscriminant, Vec<u8>), CodecError> {
45    require_v1(version)?;
46    let discriminant = value.discriminant();
47    let mut encoder = Encoder::default();
48
49    if carries_origin(discriminant) {
50        let originating_request = value
51            .originating_request()
52            .ok_or(CodecError::InvalidValue)?;
53        encoder.put_u16(originating_request.wire_value());
54    }
55
56    encode_server_suffix(value, &mut encoder)?;
57    Ok((discriminant, encoder.bytes))
58}
59
60/// Decodes one exact semantic server-value body under v1.0.
61///
62/// The concrete protocol version is returned beside the decoded value so a
63/// complete-frame caller can preserve its already-validated prefix value.
64///
65/// # Errors
66///
67/// Returns the canonical structural decode class, or
68/// [`CodecError::UnsupportedVersion`] when `version` is not v1.0.
69pub fn decode_server_value_body(
70    discriminant: t::ServerDiscriminant,
71    version: ProtocolVersion,
72    body: &[u8],
73) -> Result<(r::ServerValue, ProtocolVersion), CodecError> {
74    require_v1(version)?;
75    let mut decoder = Decoder::new(body);
76    let originating_request = if carries_origin(discriminant) {
77        let raw = decoder.take_u16()?;
78        let request = t::ClientDiscriminant::try_from(raw)
79            .map_err(|_| decode_error(t::DecodeClass::InvalidField))?;
80        if !origin_is_valid(discriminant, request) {
81            return Err(decode_error(t::DecodeClass::InvalidField));
82        }
83        Some(request)
84    } else {
85        None
86    };
87
88    let value = decode_server_suffix(discriminant, originating_request, &mut decoder)?;
89    decoder.finish()?;
90    Ok((value, version))
91}
92
93fn require_v1(version: ProtocolVersion) -> Result<(), CodecError> {
94    if version == ProtocolVersion::V1 {
95        Ok(())
96    } else {
97        Err(CodecError::UnsupportedVersion {
98            presented: version,
99            supported: ProtocolVersion::V1,
100        })
101    }
102}
103
104const fn decode_error(class: t::DecodeClass) -> CodecError {
105    CodecError::Decode { class }
106}
107
108#[derive(Default)]
109struct Encoder {
110    bytes: Vec<u8>,
111}
112
113impl Encoder {
114    fn put_u8(&mut self, value: u8) {
115        self.bytes.push(value);
116    }
117
118    fn put_u16(&mut self, value: u16) {
119        self.bytes.extend_from_slice(&value.to_be_bytes());
120    }
121
122    fn put_u32(&mut self, value: u32) {
123        self.bytes.extend_from_slice(&value.to_be_bytes());
124    }
125
126    fn put_u64(&mut self, value: u64) {
127        self.bytes.extend_from_slice(&value.to_be_bytes());
128    }
129
130    fn put_u128(&mut self, value: u128) {
131        self.bytes.extend_from_slice(&value.to_be_bytes());
132    }
133
134    fn put_fixed(&mut self, value: &[u8]) {
135        self.bytes.extend_from_slice(value);
136    }
137
138    fn put_bool(&mut self, value: bool) {
139        self.put_u8(u8::from(value));
140    }
141
142    fn put_option_u64(&mut self, value: Option<u64>) {
143        match value {
144            Some(value) => {
145                self.put_u8(1);
146                self.put_u64(value);
147            }
148            None => self.put_u8(0),
149        }
150    }
151
152    fn put_option_generation(&mut self, value: Option<Generation>) {
153        match value {
154            Some(value) => {
155                self.put_u8(1);
156                self.put_generation(value);
157            }
158            None => self.put_u8(0),
159        }
160    }
161
162    fn put_option_binding_epoch(&mut self, value: Option<BindingEpoch>) {
163        match value {
164            Some(value) => {
165                self.put_u8(1);
166                self.put_binding_epoch(value);
167            }
168            None => self.put_u8(0),
169        }
170    }
171
172    fn put_generation(&mut self, value: Generation) {
173        self.put_u64(value.get());
174    }
175
176    fn put_protocol_version(&mut self, value: ProtocolVersion) {
177        self.put_u16(value.major);
178        self.put_u16(value.minor);
179    }
180
181    fn put_binding_epoch(&mut self, value: BindingEpoch) {
182        self.put_u64(value.connection_incarnation.server_incarnation);
183        self.put_u64(value.connection_incarnation.connection_ordinal);
184        self.put_generation(value.capability_generation);
185    }
186
187    fn put_resource_vector(&mut self, value: ResourceVector) {
188        self.put_u64(value.entries);
189        self.put_u64(value.bytes);
190    }
191
192    fn put_wide_resource_vector(&mut self, value: WideResourceVector) {
193        self.put_u128(value.entries);
194        self.put_u128(value.bytes);
195    }
196
197    fn put_string(&mut self, value: &str) -> Result<(), CodecError> {
198        let length: u32 = value
199            .len()
200            .try_into()
201            .map_err(|_| CodecError::LengthOverflow)?;
202        self.put_u32(length);
203        self.put_fixed(value.as_bytes());
204        Ok(())
205    }
206}
207
208struct Decoder<'a> {
209    input: &'a [u8],
210    position: usize,
211    invalid_field: bool,
212}
213
214impl<'a> Decoder<'a> {
215    const fn new(input: &'a [u8]) -> Self {
216        Self {
217            input,
218            position: 0,
219            invalid_field: false,
220        }
221    }
222
223    const fn remaining(&self) -> usize {
224        self.input.len().saturating_sub(self.position)
225    }
226
227    fn take(&mut self, length: usize) -> Result<&'a [u8], CodecError> {
228        let end = self
229            .position
230            .checked_add(length)
231            .ok_or_else(|| decode_error(t::DecodeClass::MissingRequiredField))?;
232        let value = self
233            .input
234            .get(self.position..end)
235            .ok_or_else(|| decode_error(t::DecodeClass::MissingRequiredField))?;
236        self.position = end;
237        Ok(value)
238    }
239
240    fn take_u8(&mut self) -> Result<u8, CodecError> {
241        let bytes = self.take(1)?;
242        bytes
243            .first()
244            .copied()
245            .ok_or_else(|| decode_error(t::DecodeClass::MissingRequiredField))
246    }
247
248    fn take_u16(&mut self) -> Result<u16, CodecError> {
249        let bytes: [u8; 2] = self
250            .take(2)?
251            .try_into()
252            .map_err(|_| decode_error(t::DecodeClass::MissingRequiredField))?;
253        Ok(u16::from_be_bytes(bytes))
254    }
255
256    fn take_u32(&mut self) -> Result<u32, CodecError> {
257        let bytes: [u8; 4] = self
258            .take(4)?
259            .try_into()
260            .map_err(|_| decode_error(t::DecodeClass::MissingRequiredField))?;
261        Ok(u32::from_be_bytes(bytes))
262    }
263
264    fn take_u64(&mut self) -> Result<u64, CodecError> {
265        let bytes: [u8; 8] = self
266            .take(8)?
267            .try_into()
268            .map_err(|_| decode_error(t::DecodeClass::MissingRequiredField))?;
269        Ok(u64::from_be_bytes(bytes))
270    }
271
272    fn take_u128(&mut self) -> Result<u128, CodecError> {
273        let bytes: [u8; 16] = self
274            .take(16)?
275            .try_into()
276            .map_err(|_| decode_error(t::DecodeClass::MissingRequiredField))?;
277        Ok(u128::from_be_bytes(bytes))
278    }
279
280    fn take_fixed<const N: usize>(&mut self) -> Result<[u8; N], CodecError> {
281        self.take(N)?
282            .try_into()
283            .map_err(|_| decode_error(t::DecodeClass::MissingRequiredField))
284    }
285
286    fn take_bool(&mut self) -> Result<bool, CodecError> {
287        match self.take_u8()? {
288            0 => Ok(false),
289            1 => Ok(true),
290            _ => Err(decode_error(t::DecodeClass::InvalidField)),
291        }
292    }
293
294    fn take_option_u64(&mut self) -> Result<Option<u64>, CodecError> {
295        match self.take_u8()? {
296            0 => Ok(None),
297            1 => self.take_u64().map(Some),
298            _ => Err(decode_error(t::DecodeClass::InvalidField)),
299        }
300    }
301
302    fn take_generation(&mut self) -> Result<Generation, CodecError> {
303        let raw = self.take_u64()?;
304        if let Some(value) = Generation::new(raw) {
305            Ok(value)
306        } else {
307            self.invalid_field = true;
308            generation_one()
309        }
310    }
311
312    fn take_option_generation(&mut self) -> Result<Option<Generation>, CodecError> {
313        match self.take_u8()? {
314            0 => Ok(None),
315            1 => self.take_generation().map(Some),
316            _ => Err(decode_error(t::DecodeClass::InvalidField)),
317        }
318    }
319
320    fn take_binding_epoch(&mut self) -> Result<BindingEpoch, CodecError> {
321        Ok(BindingEpoch::new(
322            ConnectionIncarnation::new(self.take_u64()?, self.take_u64()?),
323            self.take_generation()?,
324        ))
325    }
326
327    fn take_option_binding_epoch(&mut self) -> Result<Option<BindingEpoch>, CodecError> {
328        match self.take_u8()? {
329            0 => Ok(None),
330            1 => self.take_binding_epoch().map(Some),
331            _ => Err(decode_error(t::DecodeClass::InvalidField)),
332        }
333    }
334
335    fn take_protocol_version(&mut self) -> Result<ProtocolVersion, CodecError> {
336        Ok(ProtocolVersion::new(self.take_u16()?, self.take_u16()?))
337    }
338
339    fn take_resource_vector(&mut self) -> Result<ResourceVector, CodecError> {
340        Ok(ResourceVector::new(self.take_u64()?, self.take_u64()?))
341    }
342
343    fn take_wide_resource_vector(&mut self) -> Result<WideResourceVector, CodecError> {
344        Ok(WideResourceVector::new(
345            self.take_u128()?,
346            self.take_u128()?,
347        ))
348    }
349
350    fn take_string(&mut self) -> Result<String, CodecError> {
351        let length: usize = self
352            .take_u32()?
353            .try_into()
354            .map_err(|_| decode_error(t::DecodeClass::MissingRequiredField))?;
355        let bytes = self.take(length)?;
356        if let Ok(value) = core::str::from_utf8(bytes) {
357            Ok(String::from(value))
358        } else {
359            self.invalid_field = true;
360            Ok(String::new())
361        }
362    }
363
364    const fn invalidate(&mut self) {
365        self.invalid_field = true;
366    }
367
368    const fn finish(self) -> Result<(), CodecError> {
369        if self.remaining() != 0 {
370            Err(decode_error(t::DecodeClass::CanonicalEncoding))
371        } else if self.invalid_field {
372            Err(decode_error(t::DecodeClass::InvalidField))
373        } else {
374            Ok(())
375        }
376    }
377}
378
379fn generation_one() -> Result<Generation, CodecError> {
380    Generation::new(1).ok_or(CodecError::InvalidValue)
381}
382
383fn put_enrollment(value: &e::EnrollmentEnvelope, encoder: &mut Encoder) {
384    encoder.put_u64(value.conversation_id);
385    encoder.put_fixed(value.enrollment_token.as_bytes());
386}
387
388fn put_attach(value: &e::AttachEnvelope, encoder: &mut Encoder) {
389    encoder.put_u64(value.conversation_id);
390    encoder.put_u64(value.participant_id);
391    encoder.put_generation(value.capability_generation);
392    encoder.put_fixed(value.attach_attempt_token.as_bytes());
393    encoder.put_option_u64(value.accept_marker_delivery_seq);
394}
395
396fn put_detach(value: &e::DetachEnvelope, encoder: &mut Encoder) {
397    encoder.put_u64(value.conversation_id);
398    encoder.put_u64(value.participant_id);
399    encoder.put_generation(value.capability_generation);
400    encoder.put_fixed(value.detach_attempt_token.as_bytes());
401}
402
403fn put_participant_ack(value: &e::ParticipantAckEnvelope, encoder: &mut Encoder) {
404    encoder.put_u64(value.conversation_id);
405    encoder.put_u64(value.participant_id);
406    encoder.put_generation(value.capability_generation);
407    encoder.put_u64(value.through_seq);
408}
409
410fn put_leave(value: &e::LeaveEnvelope, encoder: &mut Encoder) {
411    encoder.put_u64(value.conversation_id);
412    encoder.put_u64(value.participant_id);
413    encoder.put_generation(value.capability_generation);
414    encoder.put_fixed(value.leave_attempt_token.as_bytes());
415}
416
417fn put_marker_ack(value: &e::MarkerAckEnvelope, encoder: &mut Encoder) {
418    encoder.put_u64(value.conversation_id);
419    encoder.put_u64(value.participant_id);
420    encoder.put_generation(value.capability_generation);
421    encoder.put_u64(value.marker_delivery_seq);
422}
423
424fn put_record_admission(value: &e::RecordAdmissionEnvelope, encoder: &mut Encoder) {
425    encoder.put_u64(value.conversation_id);
426    encoder.put_u64(value.participant_id);
427    encoder.put_generation(value.capability_generation);
428    encoder.put_fixed(value.record_admission_attempt_token.as_bytes());
429}
430
431fn put_response_envelope(value: &e::ResponseEnvelope, encoder: &mut Encoder) {
432    match value {
433        e::ResponseEnvelope::Enrollment(value) => put_enrollment(value, encoder),
434        e::ResponseEnvelope::CredentialAttach(value) => put_attach(value, encoder),
435        e::ResponseEnvelope::Detach(value) => put_detach(value, encoder),
436        e::ResponseEnvelope::ParticipantAck(value) => put_participant_ack(value, encoder),
437        e::ResponseEnvelope::Leave(value) => put_leave(value, encoder),
438        e::ResponseEnvelope::MarkerAck(value) => put_marker_ack(value, encoder),
439        e::ResponseEnvelope::RecordAdmission(value) => put_record_admission(value, encoder),
440    }
441}
442
443fn put_participant_reference(value: &r::ParticipantReferenceEnvelope, encoder: &mut Encoder) {
444    match value {
445        r::ParticipantReferenceEnvelope::CredentialAttach(value) => put_attach(value, encoder),
446        r::ParticipantReferenceEnvelope::Detach(value) => put_detach(value, encoder),
447        r::ParticipantReferenceEnvelope::ParticipantAck(value) => {
448            put_participant_ack(value, encoder);
449        }
450        r::ParticipantReferenceEnvelope::Leave(value) => put_leave(value, encoder),
451        r::ParticipantReferenceEnvelope::MarkerAck(value) => put_marker_ack(value, encoder),
452        r::ParticipantReferenceEnvelope::RecordAdmission(value) => {
453            put_record_admission(value, encoder);
454        }
455    }
456}
457
458fn put_binding_required(value: &r::BindingRequiredEnvelope, encoder: &mut Encoder) {
459    match value {
460        r::BindingRequiredEnvelope::Detach(value) => put_detach(value, encoder),
461        r::BindingRequiredEnvelope::ParticipantAck(value) => put_participant_ack(value, encoder),
462        r::BindingRequiredEnvelope::Leave(value) => put_leave(value, encoder),
463        r::BindingRequiredEnvelope::MarkerAck(value) => put_marker_ack(value, encoder),
464        r::BindingRequiredEnvelope::RecordAdmission(value) => put_record_admission(value, encoder),
465    }
466}
467
468fn put_order_allocating(value: &r::OrderAllocatingEnvelope, encoder: &mut Encoder) {
469    match value {
470        r::OrderAllocatingEnvelope::Enrollment(value) => put_enrollment(value, encoder),
471        r::OrderAllocatingEnvelope::CredentialAttach(value) => put_attach(value, encoder),
472        r::OrderAllocatingEnvelope::RecordAdmission(value) => put_record_admission(value, encoder),
473    }
474}
475
476fn put_closure_checked(value: &c::ClosureCheckedEnvelope, encoder: &mut Encoder) {
477    match value {
478        c::ClosureCheckedEnvelope::Enrollment(value) => put_enrollment(value, encoder),
479        c::ClosureCheckedEnvelope::CredentialAttach(value) => put_attach(value, encoder),
480        c::ClosureCheckedEnvelope::Leave(value) => put_leave(value, encoder),
481        c::ClosureCheckedEnvelope::RecordAdmission(value) => put_record_admission(value, encoder),
482    }
483}
484
485fn put_sequence_allocating(value: &r::SequenceAllocatingEnvelope, encoder: &mut Encoder) {
486    match value {
487        r::SequenceAllocatingEnvelope::Enrollment(value) => put_enrollment(value, encoder),
488        r::SequenceAllocatingEnvelope::CredentialAttach(value) => put_attach(value, encoder),
489        r::SequenceAllocatingEnvelope::RecordAdmission(value) => {
490            put_record_admission(value, encoder);
491        }
492    }
493}
494
495fn put_marker_proof(value: &r::MarkerProofRequest, encoder: &mut Encoder) {
496    match value {
497        r::MarkerProofRequest::CredentialAttach(value) => {
498            encoder.put_u64(value.conversation_id);
499            encoder.put_fixed(value.token.as_bytes());
500            encoder.put_u64(value.participant_id);
501            encoder.put_generation(value.capability_generation);
502            encoder.put_u64(value.requested_marker_delivery_seq);
503        }
504        r::MarkerProofRequest::MarkerAck(value) => {
505            encoder.put_u64(value.conversation_id);
506            encoder.put_u64(value.participant_id);
507            encoder.put_generation(value.capability_generation);
508            encoder.put_u64(value.requested_marker_delivery_seq);
509        }
510    }
511}
512
513fn put_repayment_edge(value: c::RepaymentEdge, encoder: &mut Encoder) {
514    encoder.put_u16(value.tag().wire_value());
515    match value {
516        c::RepaymentEdge::None => {}
517        c::RepaymentEdge::ObserverProjection { through_seq } => encoder.put_u64(through_seq),
518        c::RepaymentEdge::PhysicalCompaction {
519            from_floor,
520            through_seq,
521        } => {
522            encoder.put_u64(from_floor);
523            encoder.put_u64(through_seq);
524        }
525        c::RepaymentEdge::MarkerDelivery {
526            participant_id,
527            binding_epoch,
528            marker_delivery_seq,
529        } => {
530            encoder.put_u64(participant_id);
531            encoder.put_binding_epoch(binding_epoch);
532            encoder.put_u64(marker_delivery_seq);
533        }
534        c::RepaymentEdge::ParticipantCursorProgress(value) => {
535            encoder.put_u64(value.participant_id);
536            encoder.put_binding_epoch(value.binding_epoch);
537            encoder.put_u64(value.through_seq);
538            encoder.put_option_u64(value.marker_delivery_seq);
539        }
540        c::RepaymentEdge::DetachedCredentialRecovery {
541            participant_id,
542            marker_delivery_seq,
543            prior_binding_epoch,
544        } => {
545            encoder.put_u64(participant_id);
546            encoder.put_u64(marker_delivery_seq);
547            encoder.put_binding_epoch(prior_binding_epoch);
548        }
549        c::RepaymentEdge::DetachedMarkerRelease {
550            participant_id,
551            marker_delivery_seq,
552            last_dead_binding_epoch,
553        } => {
554            encoder.put_u64(participant_id);
555            encoder.put_u64(marker_delivery_seq);
556            encoder.put_binding_epoch(last_dead_binding_epoch);
557        }
558        c::RepaymentEdge::DetachedCursorRelease {
559            participant_id,
560            last_dead_binding_epoch,
561        } => {
562            encoder.put_u64(participant_id);
563            encoder.put_binding_epoch(last_dead_binding_epoch);
564        }
565    }
566}
567
568fn put_closure_snapshot(value: c::ClosureSnapshot, encoder: &mut Encoder) {
569    encoder.put_u64(value.marker_capacity_credits);
570    encoder.put_u64(value.marker_anchors);
571    encoder.put_u64(value.entry_debt);
572    encoder.put_u64(value.byte_debt);
573    put_repayment_edge(value.repayment_edge, encoder);
574    encoder.put_u64(value.edge_sequence_claims);
575    encoder.put_u64(value.edge_order_position_claims);
576    encoder.put_resource_vector(value.edge_k_remaining);
577    encoder.put_wide_resource_vector(value.k_headroom);
578    encoder.put_u64(value.episode_churn_used);
579    encoder.put_u64(value.delta_cycles);
580    encoder.put_u64(value.episode_churn_limit);
581}
582
583fn put_sequence_budget(value: super::SequenceBudget, encoder: &mut Encoder) {
584    encoder.put_u64(value.high_watermark);
585    encoder.put_u64(value.remaining);
586    encoder.put_u64(value.e);
587    encoder.put_u64(value.t);
588    encoder.put_u64(value.m);
589    encoder.put_u64(value.rs);
590    encoder.put_u64(value.rt);
591    encoder.put_u128(value.l_times_t);
592    encoder.put_u128(value.l_times_rt);
593    encoder.put_u128(value.l_other_times_e);
594}
595
596#[allow(clippy::too_many_lines)]
597fn encode_server_suffix(value: &r::ServerValue, encoder: &mut Encoder) -> Result<(), CodecError> {
598    match value {
599        r::ServerValue::ParticipantTransportRejected(value) => match &value.reason {
600            r::TransportRejectionReason::FrameTooLarge {
601                complete_frame_bytes,
602                max_frame_bytes,
603            } => {
604                encoder.put_u16(t::TransportReasonTag::FrameTooLarge.wire_value());
605                encoder.put_u64(*complete_frame_bytes);
606                encoder.put_u64(*max_frame_bytes);
607            }
608            r::TransportRejectionReason::DecodeFailed { decode_class } => {
609                encoder.put_u16(t::TransportReasonTag::DecodeFailed.wire_value());
610                encoder.put_u16(decode_class.wire_value());
611            }
612            r::TransportRejectionReason::UnsupportedVersion {
613                presented_version,
614                supported_version,
615            } => {
616                encoder.put_u16(t::TransportReasonTag::UnsupportedVersion.wire_value());
617                encoder.put_protocol_version(*presented_version);
618                encoder.put_protocol_version(*supported_version);
619            }
620            r::TransportRejectionReason::AuthenticationFailed => {
621                encoder.put_u16(t::TransportReasonTag::AuthenticationFailed.wire_value());
622            }
623            r::TransportRejectionReason::ParticipantCapabilityRequired => {
624                encoder.put_u16(t::TransportReasonTag::ParticipantCapabilityRequired.wire_value());
625                encoder.put_string(r::PARTICIPANT_CAPABILITY)?;
626            }
627            r::TransportRejectionReason::EnrollmentNotPermitted => {
628                encoder.put_u16(t::TransportReasonTag::EnrollmentNotPermitted.wire_value());
629            }
630            r::TransportRejectionReason::EnrollmentConversationOutOfScope => encoder
631                .put_u16(t::TransportReasonTag::EnrollmentConversationOutOfScope.wire_value()),
632            r::TransportRejectionReason::CredentialAttachConversationOutOfScope => encoder.put_u16(
633                t::TransportReasonTag::CredentialAttachConversationOutOfScope.wire_value(),
634            ),
635        },
636        r::ServerValue::AttemptTokenBodyConflict(value) => match value {
637            r::AttemptTokenBodyConflict::CredentialAttach {
638                token,
639                conversation_id,
640                presented_participant_id,
641                presented_generation,
642                presented_marker_delivery_seq,
643                conflict,
644            } => {
645                encoder.put_fixed(token.as_bytes());
646                encoder.put_u16(t::AttemptOperation::CredentialAttachRequest.wire_value());
647                encoder.put_u64(*conversation_id);
648                encoder.put_u64(*presented_participant_id);
649                encoder.put_generation(*presented_generation);
650                encoder.put_option_u64(*presented_marker_delivery_seq);
651                encoder.put_u16(conflict.wire_value());
652            }
653            r::AttemptTokenBodyConflict::Leave {
654                token,
655                conversation_id,
656                presented_participant_id,
657                presented_generation,
658            } => {
659                encoder.put_fixed(token.as_bytes());
660                encoder.put_u16(t::AttemptOperation::LeaveRequest.wire_value());
661                encoder.put_u64(*conversation_id);
662                encoder.put_u64(*presented_participant_id);
663                encoder.put_generation(*presented_generation);
664                encoder.put_u16(t::AttemptConflict::Generation.wire_value());
665            }
666            r::AttemptTokenBodyConflict::RecordAdmission {
667                token,
668                conversation_id,
669                presented_participant_id,
670                presented_generation,
671            } => {
672                encoder.put_fixed(token.as_bytes());
673                encoder.put_u16(t::AttemptOperation::RecordAdmission.wire_value());
674                encoder.put_u64(*conversation_id);
675                encoder.put_u64(*presented_participant_id);
676                encoder.put_generation(*presented_generation);
677            }
678        },
679        r::ServerValue::ConnectionConversationCapacityExceeded(value) => match value {
680            r::ConnectionConversationCapacityExceeded::SemanticRequest { request, limit } => {
681                put_response_envelope(request, encoder);
682                encoder.put_u64(*limit);
683            }
684            r::ConnectionConversationCapacityExceeded::ObserverRecovery {
685                conversation_id,
686                limit,
687            } => {
688                encoder.put_u64(0);
689                encoder.put_u64(*conversation_id);
690                encoder.put_u64(*limit);
691            }
692        },
693        r::ServerValue::ConnectionConversationBindingOccupied(value) => match value {
694            r::ConnectionConversationBindingOccupied::Enrollment {
695                conversation_id,
696                enrollment_token,
697            } => {
698                encoder.put_u64(*conversation_id);
699                encoder.put_fixed(enrollment_token.as_bytes());
700                encoder.put_option_u64(None);
701            }
702            r::ConnectionConversationBindingOccupied::CredentialAttach {
703                conversation_id,
704                participant_id,
705                capability_generation,
706                attach_attempt_token,
707                accept_marker_delivery_seq,
708            } => {
709                encoder.put_u64(*conversation_id);
710                encoder.put_u64(*participant_id);
711                encoder.put_generation(*capability_generation);
712                encoder.put_fixed(attach_attempt_token.as_bytes());
713                encoder.put_option_u64(*accept_marker_delivery_seq);
714                encoder.put_option_u64(Some(*participant_id));
715            }
716        },
717        r::ServerValue::ConversationOrderExhausted(value) => {
718            put_order_allocating(value.request(), encoder);
719            encoder.put_u16(value.counter().wire_value());
720            encoder.put_u64(value.high());
721            encoder.put_option_u64(value.next_value());
722            encoder.put_u128(value.order_remaining());
723            encoder.put_u128(value.reserved_claims());
724            encoder.put_u64(r::ConversationOrderExhausted::REQUIRED_MAJORS);
725            encoder.put_u128(value.resulting_order_remaining());
726            encoder.put_u128(value.resulting_reserved_claims());
727        }
728        r::ServerValue::ParticipantUnknown(value) => {
729            put_participant_reference(&value.request, encoder);
730        }
731        r::ServerValue::NoBinding(value) => put_binding_required(&value.request, encoder),
732        r::ServerValue::StaleAuthority(value) => put_stale_authority(value, encoder),
733        r::ServerValue::Retired(value) => match value {
734            r::Retired::Enrollment {
735                request,
736                participant_id,
737                retired_generation,
738            } => {
739                put_enrollment(request, encoder);
740                encoder.put_u64(*participant_id);
741                encoder.put_generation(*retired_generation);
742            }
743            r::Retired::Participant {
744                request,
745                retired_generation,
746            } => {
747                put_participant_reference(request, encoder);
748                encoder.put_generation(*retired_generation);
749            }
750        },
751        r::ServerValue::MarkerClosureCapacityExceeded(value) => {
752            put_closure_checked(&value.request, encoder);
753            let scope = match value.reason {
754                c::ClosureRefusalReason::Capacity(_) => t::ClosureScope::Capacity,
755                c::ClosureRefusalReason::RecoveryFence => t::ClosureScope::RecoveryFence,
756                c::ClosureRefusalReason::DeliveredMarkerAwaitingAck => {
757                    t::ClosureScope::DeliveredMarkerAwaitingAck
758                }
759                c::ClosureRefusalReason::EpisodeChurnLimit => t::ClosureScope::EpisodeChurnLimit,
760            };
761            encoder.put_u16(scope.wire_value());
762            put_closure_snapshot(value.snapshot, encoder);
763            if let c::ClosureRefusalReason::Capacity(reason) = value.reason {
764                encoder.put_u16(t::ResourceDimensionTag::from(reason.dimension).wire_value());
765                encoder.put_u128(reason.required);
766                encoder.put_u128(reason.limit);
767            }
768        }
769        r::ServerValue::EnrollBound(value) => {
770            encoder.put_u64(value.conversation_id());
771            encoder.put_fixed(value.token().as_bytes());
772            encoder.put_u64(value.participant_id());
773            encoder.put_option_generation(value.request_generation());
774            encoder.put_generation(value.capability_generation());
775            encoder.put_fixed(value.attach_secret().as_bytes());
776            encoder.put_binding_epoch(value.origin_binding_epoch());
777            encoder.put_u64(value.persisted_cursor());
778            encoder.put_option_u64(value.accepted_marker_delivery_seq());
779            encoder.put_u128(value.receipt_expires_at());
780            encoder.put_u128(value.provenance_expires_at());
781        }
782        r::ServerValue::EnrollmentKnown(value) => {
783            encoder.put_u64(value.conversation_id);
784            encoder.put_fixed(value.token.as_bytes());
785            encoder.put_u64(value.participant_id);
786            encoder.put_generation(value.current_generation);
787        }
788        r::ServerValue::ReceiptExpired(value) => put_receipt_expired(value, encoder),
789        r::ServerValue::ReceiptCapacityExceeded(value) => {
790            put_receipt_capacity(value, encoder);
791        }
792        r::ServerValue::IdentityCapacityExceeded(value) => {
793            put_enrollment(&value.request, encoder);
794            encoder.put_u16(value.scope.wire_value());
795            encoder.put_u64(value.limit);
796            encoder.put_u64(value.occupied);
797            encoder.put_u64(r::IdentityCapacityExceeded::REQUESTED);
798        }
799        r::ServerValue::ObserverBackpressure(value) => put_observer_backpressure(value, encoder),
800        r::ServerValue::ConversationSequenceExhausted(value) => {
801            put_sequence_allocating(&value.request, encoder);
802            put_sequence_budget(value.sequence_budget, encoder);
803        }
804        r::ServerValue::AttachBound(value) => {
805            encoder.put_u64(value.conversation_id());
806            encoder.put_fixed(value.token().as_bytes());
807            encoder.put_u64(value.participant_id());
808            encoder.put_option_generation(Some(value.request_generation()));
809            encoder.put_generation(value.capability_generation());
810            encoder.put_fixed(value.attach_secret().as_bytes());
811            encoder.put_binding_epoch(value.origin_binding_epoch());
812            encoder.put_u64(value.persisted_cursor());
813            encoder.put_option_u64(value.accepted_marker_delivery_seq());
814            encoder.put_u128(value.receipt_expires_at());
815            encoder.put_u128(value.provenance_expires_at());
816        }
817        r::ServerValue::StaleOrUnknownReceipt(value) => {
818            encoder.put_u64(value.conversation_id);
819            encoder.put_fixed(value.token.as_bytes());
820            encoder.put_u64(value.participant_id);
821            encoder.put_generation(value.presented_generation);
822            encoder.put_option_u64(value.presented_marker_delivery_seq);
823            encoder.put_generation(value.current_generation);
824        }
825        r::ServerValue::MarkerNotDelivered(value) => {
826            put_marker_proof(&value.request, encoder);
827            encoder.put_u16(value.reason.wire_value());
828            encoder.put_u64(value.expected_marker_delivery_seq);
829        }
830        r::ServerValue::MarkerMismatch(value) => {
831            put_marker_proof(&value.request, encoder);
832            encoder.put_u16(value.mismatch.reason().wire_value());
833            match value.mismatch {
834                r::MarkerMismatchBody::BelowCursor { current_cursor } => {
835                    encoder.put_u64(current_cursor);
836                }
837                r::MarkerMismatchBody::NoMarkerExpected => {}
838                r::MarkerMismatchBody::ExpectedDifferentMarker {
839                    expected_marker_delivery_seq,
840                } => encoder.put_u64(expected_marker_delivery_seq),
841            }
842        }
843        r::ServerValue::Bound(value) | r::ServerValue::UnboundReceipt(value) => {
844            put_receipt_replay(value, encoder);
845        }
846        r::ServerValue::DetachCommitted(value) => {
847            encoder.put_u64(value.conversation_id());
848            encoder.put_u64(value.participant_id());
849            encoder.put_generation(value.capability_generation());
850            encoder.put_fixed(value.detach_attempt_token().as_bytes());
851            encoder.put_binding_epoch(value.committed_binding_epoch());
852            encoder.put_u64(value.detached_delivery_seq());
853        }
854        r::ServerValue::DetachInProgress(value) => {
855            encoder.put_u64(value.conversation_id);
856            encoder.put_u64(value.participant_id);
857            encoder.put_fixed(value.presented_token.as_bytes());
858            encoder.put_generation(value.presented_generation);
859            encoder.put_binding_epoch(value.committed_binding_epoch);
860        }
861        r::ServerValue::AckCommitted(value) => {
862            put_participant_ack(value.request(), encoder);
863            encoder.put_u64(value.current_cursor());
864        }
865        r::ServerValue::AckNoOp(value) => match value {
866            r::AckNoOp::ParticipantAck(request) => {
867                put_participant_ack(request, encoder);
868                encoder.put_u64(value.current_cursor());
869            }
870            r::AckNoOp::MarkerAck(request) => {
871                put_marker_ack(request, encoder);
872                encoder.put_u64(value.current_cursor());
873            }
874        },
875        r::ServerValue::AckGap(value) => {
876            put_participant_ack(value.request(), encoder);
877            encoder.put_u64(value.current_cursor());
878            encoder.put_u16(value.reason().wire_value());
879        }
880        r::ServerValue::AckRegression(value) => {
881            put_participant_ack(value.request(), encoder);
882            encoder.put_u64(value.current_cursor());
883            encoder.put_u16(value.reason().wire_value());
884        }
885        r::ServerValue::LeaveCommitted(value) => {
886            encoder.put_u64(value.conversation_id());
887            encoder.put_fixed(value.leave_attempt_token().as_bytes());
888            encoder.put_u64(value.participant_id());
889            encoder.put_generation(value.presented_generation());
890            encoder.put_generation(value.retired_generation());
891            encoder.put_option_binding_epoch(value.ended_binding_epoch());
892            encoder.put_option_u64(value.prior_terminal_delivery_seq());
893            encoder.put_u64(value.left_delivery_seq());
894        }
895        r::ServerValue::MarkerAckCommitted(value) => {
896            put_marker_ack(value.request(), encoder);
897            encoder.put_u64(value.current_cursor());
898        }
899        r::ServerValue::SettlementAnswer(value) => {
900            encoder.put_u64(value.conversation_id);
901            encoder.put_u64(value.participant_id);
902            encoder.put_fixed(value.record_admission_attempt_token.as_bytes());
903            match value.outcome {
904                r::SettlementOutcome::Committed { delivery_seq } => {
905                    encoder.put_u8(1);
906                    encoder.put_u64(delivery_seq);
907                }
908                r::SettlementOutcome::Withdrawn => encoder.put_u8(2),
909                r::SettlementOutcome::Expired => encoder.put_u8(3),
910                r::SettlementOutcome::NotCommitted => encoder.put_u8(4),
911                r::SettlementOutcome::Unknown => encoder.put_u8(5),
912            }
913        }
914        r::ServerValue::RecordCommitted(value) => {
915            put_record_admission(value.request(), encoder);
916            encoder.put_u64(value.sender_participant_id());
917            encoder.put_u64(value.delivery_seq());
918        }
919        r::ServerValue::RecordTooLarge(value) => {
920            put_record_admission(&value.request, encoder);
921            encoder.put_u16(t::ResourceDimensionTag::from(value.dimension).wire_value());
922            encoder.put_resource_vector(value.encoded_record_charge);
923            encoder.put_resource_vector(value.max_ordinary_record_charge);
924        }
925        r::ServerValue::ObserverRecoveryAccepted(value) => {
926            let count: u64 = value
927                .statuses
928                .len()
929                .try_into()
930                .map_err(|_| CodecError::LengthOverflow)?;
931            encoder.put_u64(count);
932            for status in &value.statuses {
933                encoder.put_u64(status.conversation_id);
934                encoder.put_u64(status.refused_epoch);
935                encoder.put_u64(status.current_observer_progress);
936                encoder.put_bool(status.armed);
937                encoder.put_bool(status.progressed);
938            }
939        }
940        r::ServerValue::InvalidObserverEpoch(value) => {
941            encoder.put_u64(0);
942            encoder.put_u16(value.reason().wire_value());
943            match value {
944                r::InvalidObserverEpoch::ConversationUnknown {
945                    conversation_id,
946                    presented_epoch,
947                } => {
948                    encoder.put_u64(*conversation_id);
949                    encoder.put_u64(*presented_epoch);
950                    encoder.put_option_u64(None);
951                }
952                r::InvalidObserverEpoch::EpochAhead {
953                    conversation_id,
954                    presented_epoch,
955                    current_observer_progress,
956                } => {
957                    encoder.put_u64(*conversation_id);
958                    encoder.put_u64(*presented_epoch);
959                    encoder.put_option_u64(Some(*current_observer_progress));
960                }
961            }
962        }
963        r::ServerValue::InvalidObserverEpochList(value) => {
964            encoder.put_u64(0);
965            encoder.put_u16(value.reason().wire_value());
966            match value {
967                r::InvalidObserverEpochList::TooManyEntries {
968                    presented_entries,
969                    max_entries,
970                } => {
971                    encoder.put_u64(*presented_entries);
972                    encoder.put_u64(*max_entries);
973                }
974                r::InvalidObserverEpochList::DuplicateConversation {
975                    conversation_id,
976                    first_index,
977                    duplicate_index,
978                } => {
979                    encoder.put_u64(*conversation_id);
980                    encoder.put_u64(*first_index);
981                    encoder.put_u64(*duplicate_index);
982                }
983            }
984        }
985        r::ServerValue::MarkerSettlementBackpressure(value) => match value {
986            r::MarkerSettlementBackpressure::CredentialAttach {
987                conversation_id,
988                refused_epoch,
989            }
990            | r::MarkerSettlementBackpressure::Detach {
991                conversation_id,
992                refused_epoch,
993            } => {
994                encoder.put_u64(*conversation_id);
995                encoder.put_u64(*refused_epoch);
996            }
997        },
998        r::ServerValue::EnrollmentSettlementBackpressure(value) => {
999            encoder.put_u64(value.conversation_id);
1000        }
1001        r::ServerValue::RecordAdmissionProtocolFault(value) => {
1002            put_record_admission(&value.request, encoder);
1003            encoder.put_u16(value.class.tag().wire_value());
1004        }
1005        r::ServerValue::WriteOutcomeUnknown(value) => put_write_outcome_unknown(value, encoder),
1006    }
1007    Ok(())
1008}
1009
1010fn put_write_outcome_unknown(value: &r::WriteOutcomeUnknown, encoder: &mut Encoder) {
1011    match value {
1012        r::WriteOutcomeUnknown::Enrollment { request } => put_enrollment(request, encoder),
1013        r::WriteOutcomeUnknown::CredentialAttach { request } => put_attach(request, encoder),
1014        r::WriteOutcomeUnknown::Detach { request } => put_detach(request, encoder),
1015        r::WriteOutcomeUnknown::Leave { request } => put_leave(request, encoder),
1016        r::WriteOutcomeUnknown::RecordAdmission { request } => {
1017            put_record_admission(request, encoder);
1018        }
1019    }
1020}
1021
1022fn put_stale_authority(value: &r::StaleAuthority, encoder: &mut Encoder) {
1023    match value {
1024        r::StaleAuthority::Live {
1025            request,
1026            current_generation,
1027        } => {
1028            match request {
1029                r::CommonStaleAuthorityEnvelope::CredentialAttach(value) => {
1030                    put_attach(value, encoder);
1031                }
1032                r::CommonStaleAuthorityEnvelope::ParticipantAck(value) => {
1033                    put_participant_ack(value, encoder);
1034                }
1035                r::CommonStaleAuthorityEnvelope::MarkerAck(value) => {
1036                    put_marker_ack(value, encoder);
1037                }
1038                r::CommonStaleAuthorityEnvelope::RecordAdmission(value) => {
1039                    put_record_admission(value, encoder);
1040                }
1041            }
1042            encoder.put_generation(*current_generation);
1043        }
1044        r::StaleAuthority::Detach(value) => {
1045            encoder.put_u16(value.authority_state_tag().wire_value());
1046            match value {
1047                r::DetachStaleAuthority::Live {
1048                    conversation_id,
1049                    participant_id,
1050                    capability_generation,
1051                    detach_attempt_token,
1052                    current_generation,
1053                } => {
1054                    encoder.put_u64(*conversation_id);
1055                    encoder.put_u64(*participant_id);
1056                    encoder.put_generation(*capability_generation);
1057                    encoder.put_fixed(detach_attempt_token.as_bytes());
1058                    encoder.put_generation(*current_generation);
1059                }
1060                r::DetachStaleAuthority::TerminalizedDetachCell(value) => {
1061                    encoder.put_u64(value.conversation_id());
1062                    encoder.put_u64(value.participant_id());
1063                    encoder.put_generation(value.capability_generation());
1064                    encoder.put_fixed(value.detach_attempt_token().as_bytes());
1065                    encoder.put_generation(value.current_generation());
1066                    encoder.put_binding_epoch(value.committed_binding_epoch());
1067                    encoder.put_u16(value.binding_state().tag().wire_value());
1068                    if let r::BindingStateView::Bound {
1069                        current_binding_epoch,
1070                    } = value.binding_state()
1071                    {
1072                        encoder.put_binding_epoch(current_binding_epoch);
1073                    }
1074                }
1075            }
1076        }
1077        r::StaleAuthority::Leave(value) => {
1078            encoder.put_u16(value.authority_state_tag().wire_value());
1079            match value {
1080                r::LeaveStaleAuthority::Live {
1081                    conversation_id,
1082                    participant_id,
1083                    presented_generation,
1084                    leave_attempt_token,
1085                    current_generation,
1086                } => {
1087                    encoder.put_u64(*conversation_id);
1088                    encoder.put_u64(*participant_id);
1089                    encoder.put_generation(*presented_generation);
1090                    encoder.put_fixed(leave_attempt_token.as_bytes());
1091                    encoder.put_generation(*current_generation);
1092                }
1093                r::LeaveStaleAuthority::CommittedLeaveTombstone {
1094                    conversation_id,
1095                    participant_id,
1096                    presented_generation,
1097                    leave_attempt_token,
1098                    retired_generation,
1099                } => {
1100                    encoder.put_u64(*conversation_id);
1101                    encoder.put_u64(*participant_id);
1102                    encoder.put_generation(*presented_generation);
1103                    encoder.put_fixed(leave_attempt_token.as_bytes());
1104                    encoder.put_generation(*retired_generation);
1105                }
1106            }
1107        }
1108    }
1109}
1110
1111fn put_receipt_expired(value: &r::ReceiptExpired, encoder: &mut Encoder) {
1112    match value {
1113        r::ReceiptExpired::Enrollment {
1114            conversation_id,
1115            token,
1116            participant_id,
1117            result_generation,
1118            current_generation,
1119            reason,
1120        } => {
1121            encoder.put_u64(*conversation_id);
1122            encoder.put_fixed(token.as_bytes());
1123            encoder.put_u64(*participant_id);
1124            encoder.put_option_generation(None);
1125            encoder.put_generation(*result_generation);
1126            encoder.put_generation(*current_generation);
1127            encoder.put_u16(reason.wire_value());
1128        }
1129        r::ReceiptExpired::CredentialAttach {
1130            conversation_id,
1131            token,
1132            participant_id,
1133            presented_generation,
1134            presented_marker_delivery_seq,
1135            result_generation,
1136            current_generation,
1137            reason,
1138        } => {
1139            encoder.put_u64(*conversation_id);
1140            encoder.put_fixed(token.as_bytes());
1141            encoder.put_u64(*participant_id);
1142            encoder.put_option_generation(Some(*presented_generation));
1143            encoder.put_option_u64(*presented_marker_delivery_seq);
1144            encoder.put_generation(*result_generation);
1145            encoder.put_generation(*current_generation);
1146            encoder.put_u16(reason.wire_value());
1147        }
1148    }
1149}
1150
1151fn put_receipt_capacity(value: &r::ReceiptCapacityExceeded, encoder: &mut Encoder) {
1152    match value {
1153        r::ReceiptCapacityExceeded::Enrollment {
1154            request,
1155            scope,
1156            limit,
1157            occupied,
1158        } => {
1159            put_enrollment(request, encoder);
1160            encoder.put_u16(scope.wire_scope().wire_value());
1161            encoder.put_u64(*limit);
1162            encoder.put_u64(*occupied);
1163            encoder.put_u64(r::ReceiptCapacityExceeded::REQUESTED);
1164        }
1165        r::ReceiptCapacityExceeded::CredentialAttach {
1166            request,
1167            scope,
1168            limit,
1169            occupied,
1170        } => {
1171            put_attach(request, encoder);
1172            encoder.put_u16(scope.wire_value());
1173            encoder.put_u64(*limit);
1174            encoder.put_u64(*occupied);
1175            encoder.put_u64(r::ReceiptCapacityExceeded::REQUESTED);
1176        }
1177    }
1178}
1179
1180fn put_observer_backpressure(value: &r::ObserverBackpressure, encoder: &mut Encoder) {
1181    match value {
1182        r::ObserverBackpressure::Enrollment { request, state } => {
1183            put_enrollment(request, encoder);
1184            put_backpressure_state(*state, encoder);
1185        }
1186        r::ObserverBackpressure::CredentialAttach { request, state } => {
1187            put_attach(request, encoder);
1188            put_backpressure_state(*state, encoder);
1189        }
1190        r::ObserverBackpressure::Detach {
1191            request,
1192            committed_binding_epoch,
1193            state,
1194        } => {
1195            put_detach(request, encoder);
1196            encoder.put_binding_epoch(*committed_binding_epoch);
1197            put_backpressure_state(*state, encoder);
1198        }
1199        r::ObserverBackpressure::Leave {
1200            request,
1201            state,
1202            prior_terminal_cell_exists,
1203        } => {
1204            put_leave(request, encoder);
1205            put_backpressure_state(*state, encoder);
1206            encoder.put_bool(*prior_terminal_cell_exists);
1207        }
1208        r::ObserverBackpressure::RecordAdmission { request, state } => {
1209            put_record_admission(request, encoder);
1210            put_backpressure_state(*state, encoder);
1211        }
1212    }
1213}
1214
1215fn put_backpressure_state(value: r::ObserverBackpressureState, encoder: &mut Encoder) {
1216    encoder.put_u64(value.backpressure_epoch());
1217    encoder.put_u64(value.observer_progress());
1218}
1219
1220fn put_receipt_replay(value: &r::ReceiptReplay, encoder: &mut Encoder) {
1221    match value {
1222        r::ReceiptReplay::Enrollment(value) => {
1223            encoder.put_u64(value.conversation_id());
1224            encoder.put_fixed(value.token().as_bytes());
1225            encoder.put_u64(value.participant_id());
1226            encoder.put_option_generation(None);
1227            encoder.put_generation(value.capability_generation());
1228            encoder.put_fixed(value.attach_secret().as_bytes());
1229            encoder.put_binding_epoch(value.origin_binding_epoch());
1230            encoder.put_u64(value.persisted_cursor());
1231            encoder.put_option_u64(None);
1232            encoder.put_u128(value.receipt_expires_at());
1233            encoder.put_u128(value.provenance_expires_at());
1234        }
1235        r::ReceiptReplay::CredentialAttach(value) => {
1236            encoder.put_u64(value.conversation_id());
1237            encoder.put_fixed(value.token().as_bytes());
1238            encoder.put_u64(value.participant_id());
1239            encoder.put_option_generation(Some(value.request_generation()));
1240            encoder.put_generation(value.capability_generation());
1241            encoder.put_fixed(value.attach_secret().as_bytes());
1242            encoder.put_binding_epoch(value.origin_binding_epoch());
1243            encoder.put_u64(value.persisted_cursor());
1244            encoder.put_option_u64(value.accepted_marker_delivery_seq());
1245            encoder.put_u128(value.receipt_expires_at());
1246            encoder.put_u128(value.provenance_expires_at());
1247        }
1248    }
1249}
1250
1251/// Returns whether a body is prefixed by its originating-request selector.
1252///
1253/// Exactly the rows [`origin_is_valid`] admits some origin for, stated as that
1254/// complement rather than as a numeric window: the old `0x0101..=0x0120` range
1255/// was contiguous only until the settlement rows were appended ABOVE the
1256/// origin-free observer-recovery block (`0x0121..=0x0124`), and a window cannot
1257/// express that shape without silently dropping a row's origin prefix.
1258const fn carries_origin(discriminant: t::ServerDiscriminant) -> bool {
1259    use t::ServerDiscriminant as D;
1260
1261    !matches!(
1262        discriminant,
1263        D::ParticipantTransportRejected
1264            | D::ObserverRecoveryAccepted
1265            | D::InvalidObserverEpoch
1266            | D::InvalidObserverEpochList
1267            | D::ObserverRecoveryConnectionCapacityExceeded
1268    )
1269}
1270
1271const fn origin_is_valid(
1272    discriminant: t::ServerDiscriminant,
1273    origin: t::ClientDiscriminant,
1274) -> bool {
1275    use t::ClientDiscriminant as O;
1276    use t::ServerDiscriminant as D;
1277
1278    match discriminant {
1279        D::AttemptTokenBodyConflict => matches!(
1280            origin,
1281            O::CredentialAttachRequest | O::LeaveRequest | O::RecordAdmission
1282        ),
1283        D::ConnectionConversationCapacityExceeded => {
1284            !matches!(origin, O::ObserverRecoveryHandshake)
1285        }
1286        D::ConnectionConversationBindingOccupied => {
1287            matches!(origin, O::EnrollmentRequest | O::CredentialAttachRequest)
1288        }
1289        D::ConversationOrderExhausted => matches!(
1290            origin,
1291            O::EnrollmentRequest | O::CredentialAttachRequest | O::RecordAdmission
1292        ),
1293        D::ParticipantUnknown => {
1294            !matches!(origin, O::EnrollmentRequest | O::ObserverRecoveryHandshake)
1295        }
1296        D::NoBinding => !matches!(
1297            origin,
1298            O::EnrollmentRequest | O::CredentialAttachRequest | O::ObserverRecoveryHandshake
1299        ),
1300        D::StaleAuthority => !matches!(origin, O::EnrollmentRequest | O::ObserverRecoveryHandshake),
1301        D::Retired => !matches!(origin, O::ObserverRecoveryHandshake),
1302        D::MarkerClosureCapacityExceeded => matches!(
1303            origin,
1304            O::EnrollmentRequest
1305                | O::CredentialAttachRequest
1306                | O::LeaveRequest
1307                | O::RecordAdmission
1308        ),
1309        D::EnrollBound | D::EnrollmentKnown | D::IdentityCapacityExceeded => {
1310            matches!(origin, O::EnrollmentRequest)
1311        }
1312        D::ReceiptExpired | D::ReceiptCapacityExceeded | D::Bound | D::UnboundReceipt => {
1313            matches!(origin, O::EnrollmentRequest | O::CredentialAttachRequest)
1314        }
1315        D::ObserverBackpressure | D::WriteOutcomeUnknown => matches!(
1316            origin,
1317            O::EnrollmentRequest
1318                | O::CredentialAttachRequest
1319                | O::DetachRequest
1320                | O::LeaveRequest
1321                | O::RecordAdmission
1322        ),
1323        D::ConversationSequenceExhausted => matches!(
1324            origin,
1325            O::EnrollmentRequest | O::CredentialAttachRequest | O::RecordAdmission
1326        ),
1327        D::AttachBound | D::StaleOrUnknownReceipt => {
1328            matches!(origin, O::CredentialAttachRequest)
1329        }
1330        D::MarkerNotDelivered | D::MarkerMismatch => {
1331            matches!(origin, O::CredentialAttachRequest | O::MarkerAck)
1332        }
1333        D::DetachCommitted | D::DetachInProgress => matches!(origin, O::DetachRequest),
1334        D::AckCommitted | D::AckGap | D::AckRegression => matches!(origin, O::ParticipantAck),
1335        D::AckNoOp => matches!(origin, O::ParticipantAck | O::MarkerAck),
1336        D::LeaveCommitted => matches!(origin, O::LeaveRequest),
1337        D::MarkerAckCommitted => matches!(origin, O::MarkerAck),
1338        D::SettlementAnswer => matches!(origin, O::SettlementQuery),
1339        D::RecordCommitted | D::RecordTooLarge | D::RecordAdmissionProtocolFault => {
1340            matches!(origin, O::RecordAdmission)
1341        }
1342        D::MarkerSettlementBackpressure => {
1343            matches!(origin, O::CredentialAttachRequest | O::DetachRequest)
1344        }
1345        D::EnrollmentSettlementBackpressure => matches!(origin, O::EnrollmentRequest),
1346        D::ParticipantTransportRejected
1347        | D::ObserverRecoveryAccepted
1348        | D::InvalidObserverEpoch
1349        | D::InvalidObserverEpochList
1350        | D::ObserverRecoveryConnectionCapacityExceeded => false,
1351    }
1352}
1353
1354// Decoding is kept below encoding so every selected schema can be compared
1355// field-for-field in one source file.
1356
1357fn take_enrollment(decoder: &mut Decoder<'_>) -> Result<e::EnrollmentEnvelope, CodecError> {
1358    Ok(e::EnrollmentEnvelope {
1359        conversation_id: decoder.take_u64()?,
1360        enrollment_token: EnrollmentToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1361    })
1362}
1363
1364fn take_attach(decoder: &mut Decoder<'_>) -> Result<e::AttachEnvelope, CodecError> {
1365    Ok(e::AttachEnvelope {
1366        conversation_id: decoder.take_u64()?,
1367        participant_id: decoder.take_u64()?,
1368        capability_generation: decoder.take_generation()?,
1369        attach_attempt_token: AttachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1370        accept_marker_delivery_seq: decoder.take_option_u64()?,
1371    })
1372}
1373
1374fn take_detach(decoder: &mut Decoder<'_>) -> Result<e::DetachEnvelope, CodecError> {
1375    Ok(e::DetachEnvelope {
1376        conversation_id: decoder.take_u64()?,
1377        participant_id: decoder.take_u64()?,
1378        capability_generation: decoder.take_generation()?,
1379        detach_attempt_token: DetachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1380    })
1381}
1382
1383fn take_participant_ack(
1384    decoder: &mut Decoder<'_>,
1385) -> Result<e::ParticipantAckEnvelope, CodecError> {
1386    Ok(e::ParticipantAckEnvelope {
1387        conversation_id: decoder.take_u64()?,
1388        participant_id: decoder.take_u64()?,
1389        capability_generation: decoder.take_generation()?,
1390        through_seq: decoder.take_u64()?,
1391    })
1392}
1393
1394fn take_leave(decoder: &mut Decoder<'_>) -> Result<e::LeaveEnvelope, CodecError> {
1395    Ok(e::LeaveEnvelope {
1396        conversation_id: decoder.take_u64()?,
1397        participant_id: decoder.take_u64()?,
1398        capability_generation: decoder.take_generation()?,
1399        leave_attempt_token: LeaveAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1400    })
1401}
1402
1403fn take_marker_ack(decoder: &mut Decoder<'_>) -> Result<e::MarkerAckEnvelope, CodecError> {
1404    Ok(e::MarkerAckEnvelope {
1405        conversation_id: decoder.take_u64()?,
1406        participant_id: decoder.take_u64()?,
1407        capability_generation: decoder.take_generation()?,
1408        marker_delivery_seq: decoder.take_u64()?,
1409    })
1410}
1411
1412fn take_record_admission(
1413    decoder: &mut Decoder<'_>,
1414) -> Result<e::RecordAdmissionEnvelope, CodecError> {
1415    Ok(e::RecordAdmissionEnvelope {
1416        conversation_id: decoder.take_u64()?,
1417        participant_id: decoder.take_u64()?,
1418        capability_generation: decoder.take_generation()?,
1419        record_admission_attempt_token: RecordAdmissionAttemptToken::new(
1420            decoder.take_fixed::<TOKEN_LEN>()?,
1421        ),
1422    })
1423}
1424
1425fn take_response_envelope(
1426    origin: t::ClientDiscriminant,
1427    decoder: &mut Decoder<'_>,
1428) -> Result<e::ResponseEnvelope, CodecError> {
1429    match origin {
1430        t::ClientDiscriminant::EnrollmentRequest => {
1431            take_enrollment(decoder).map(e::ResponseEnvelope::Enrollment)
1432        }
1433        t::ClientDiscriminant::CredentialAttachRequest => {
1434            take_attach(decoder).map(e::ResponseEnvelope::CredentialAttach)
1435        }
1436        t::ClientDiscriminant::DetachRequest => {
1437            take_detach(decoder).map(e::ResponseEnvelope::Detach)
1438        }
1439        t::ClientDiscriminant::ParticipantAck => {
1440            take_participant_ack(decoder).map(e::ResponseEnvelope::ParticipantAck)
1441        }
1442        t::ClientDiscriminant::LeaveRequest => take_leave(decoder).map(e::ResponseEnvelope::Leave),
1443        t::ClientDiscriminant::MarkerAck => {
1444            take_marker_ack(decoder).map(e::ResponseEnvelope::MarkerAck)
1445        }
1446        t::ClientDiscriminant::RecordAdmission => {
1447            take_record_admission(decoder).map(e::ResponseEnvelope::RecordAdmission)
1448        }
1449        t::ClientDiscriminant::ObserverRecoveryHandshake
1450        | t::ClientDiscriminant::SettlementQuery => Err(decode_error(t::DecodeClass::InvalidField)),
1451    }
1452}
1453
1454fn take_participant_reference(
1455    origin: t::ClientDiscriminant,
1456    decoder: &mut Decoder<'_>,
1457) -> Result<r::ParticipantReferenceEnvelope, CodecError> {
1458    match origin {
1459        t::ClientDiscriminant::CredentialAttachRequest => {
1460            take_attach(decoder).map(r::ParticipantReferenceEnvelope::CredentialAttach)
1461        }
1462        t::ClientDiscriminant::DetachRequest => {
1463            take_detach(decoder).map(r::ParticipantReferenceEnvelope::Detach)
1464        }
1465        t::ClientDiscriminant::ParticipantAck => {
1466            take_participant_ack(decoder).map(r::ParticipantReferenceEnvelope::ParticipantAck)
1467        }
1468        t::ClientDiscriminant::LeaveRequest => {
1469            take_leave(decoder).map(r::ParticipantReferenceEnvelope::Leave)
1470        }
1471        t::ClientDiscriminant::MarkerAck => {
1472            take_marker_ack(decoder).map(r::ParticipantReferenceEnvelope::MarkerAck)
1473        }
1474        t::ClientDiscriminant::RecordAdmission => {
1475            take_record_admission(decoder).map(r::ParticipantReferenceEnvelope::RecordAdmission)
1476        }
1477        t::ClientDiscriminant::EnrollmentRequest
1478        | t::ClientDiscriminant::ObserverRecoveryHandshake
1479        | t::ClientDiscriminant::SettlementQuery => Err(decode_error(t::DecodeClass::InvalidField)),
1480    }
1481}
1482
1483fn take_binding_required(
1484    origin: t::ClientDiscriminant,
1485    decoder: &mut Decoder<'_>,
1486) -> Result<r::BindingRequiredEnvelope, CodecError> {
1487    match origin {
1488        t::ClientDiscriminant::DetachRequest => {
1489            take_detach(decoder).map(r::BindingRequiredEnvelope::Detach)
1490        }
1491        t::ClientDiscriminant::ParticipantAck => {
1492            take_participant_ack(decoder).map(r::BindingRequiredEnvelope::ParticipantAck)
1493        }
1494        t::ClientDiscriminant::LeaveRequest => {
1495            take_leave(decoder).map(r::BindingRequiredEnvelope::Leave)
1496        }
1497        t::ClientDiscriminant::MarkerAck => {
1498            take_marker_ack(decoder).map(r::BindingRequiredEnvelope::MarkerAck)
1499        }
1500        t::ClientDiscriminant::RecordAdmission => {
1501            take_record_admission(decoder).map(r::BindingRequiredEnvelope::RecordAdmission)
1502        }
1503        t::ClientDiscriminant::EnrollmentRequest
1504        | t::ClientDiscriminant::CredentialAttachRequest
1505        | t::ClientDiscriminant::ObserverRecoveryHandshake
1506        | t::ClientDiscriminant::SettlementQuery => Err(decode_error(t::DecodeClass::InvalidField)),
1507    }
1508}
1509
1510fn take_order_allocating(
1511    origin: t::ClientDiscriminant,
1512    decoder: &mut Decoder<'_>,
1513) -> Result<r::OrderAllocatingEnvelope, CodecError> {
1514    match origin {
1515        t::ClientDiscriminant::EnrollmentRequest => {
1516            take_enrollment(decoder).map(r::OrderAllocatingEnvelope::Enrollment)
1517        }
1518        t::ClientDiscriminant::CredentialAttachRequest => {
1519            take_attach(decoder).map(r::OrderAllocatingEnvelope::CredentialAttach)
1520        }
1521        t::ClientDiscriminant::RecordAdmission => {
1522            take_record_admission(decoder).map(r::OrderAllocatingEnvelope::RecordAdmission)
1523        }
1524        _ => Err(decode_error(t::DecodeClass::InvalidField)),
1525    }
1526}
1527
1528fn take_closure_checked(
1529    origin: t::ClientDiscriminant,
1530    decoder: &mut Decoder<'_>,
1531) -> Result<c::ClosureCheckedEnvelope, CodecError> {
1532    match origin {
1533        t::ClientDiscriminant::EnrollmentRequest => {
1534            take_enrollment(decoder).map(c::ClosureCheckedEnvelope::Enrollment)
1535        }
1536        t::ClientDiscriminant::CredentialAttachRequest => {
1537            take_attach(decoder).map(c::ClosureCheckedEnvelope::CredentialAttach)
1538        }
1539        t::ClientDiscriminant::LeaveRequest => {
1540            take_leave(decoder).map(c::ClosureCheckedEnvelope::Leave)
1541        }
1542        t::ClientDiscriminant::RecordAdmission => {
1543            take_record_admission(decoder).map(c::ClosureCheckedEnvelope::RecordAdmission)
1544        }
1545        _ => Err(decode_error(t::DecodeClass::InvalidField)),
1546    }
1547}
1548
1549fn take_sequence_allocating(
1550    origin: t::ClientDiscriminant,
1551    decoder: &mut Decoder<'_>,
1552) -> Result<r::SequenceAllocatingEnvelope, CodecError> {
1553    match origin {
1554        t::ClientDiscriminant::EnrollmentRequest => {
1555            take_enrollment(decoder).map(r::SequenceAllocatingEnvelope::Enrollment)
1556        }
1557        t::ClientDiscriminant::CredentialAttachRequest => {
1558            take_attach(decoder).map(r::SequenceAllocatingEnvelope::CredentialAttach)
1559        }
1560        t::ClientDiscriminant::RecordAdmission => {
1561            take_record_admission(decoder).map(r::SequenceAllocatingEnvelope::RecordAdmission)
1562        }
1563        _ => Err(decode_error(t::DecodeClass::InvalidField)),
1564    }
1565}
1566
1567fn take_marker_proof(
1568    origin: t::ClientDiscriminant,
1569    decoder: &mut Decoder<'_>,
1570) -> Result<r::MarkerProofRequest, CodecError> {
1571    match origin {
1572        t::ClientDiscriminant::CredentialAttachRequest => Ok(
1573            r::MarkerProofRequest::CredentialAttach(r::AttachMarkerProof {
1574                conversation_id: decoder.take_u64()?,
1575                token: AttachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1576                participant_id: decoder.take_u64()?,
1577                capability_generation: decoder.take_generation()?,
1578                requested_marker_delivery_seq: decoder.take_u64()?,
1579            }),
1580        ),
1581        t::ClientDiscriminant::MarkerAck => {
1582            Ok(r::MarkerProofRequest::MarkerAck(r::MarkerAckProof {
1583                conversation_id: decoder.take_u64()?,
1584                participant_id: decoder.take_u64()?,
1585                capability_generation: decoder.take_generation()?,
1586                requested_marker_delivery_seq: decoder.take_u64()?,
1587            }))
1588        }
1589        _ => Err(decode_error(t::DecodeClass::InvalidField)),
1590    }
1591}
1592
1593fn take_repayment_edge(decoder: &mut Decoder<'_>) -> Result<c::RepaymentEdge, CodecError> {
1594    let tag = t::RepaymentEdgeTag::try_from(decoder.take_u16()?)
1595        .map_err(|_| decode_error(t::DecodeClass::InvalidField))?;
1596    match tag {
1597        t::RepaymentEdgeTag::None => Ok(c::RepaymentEdge::None),
1598        t::RepaymentEdgeTag::ObserverProjection => Ok(c::RepaymentEdge::ObserverProjection {
1599            through_seq: decoder.take_u64()?,
1600        }),
1601        t::RepaymentEdgeTag::PhysicalCompaction => Ok(c::RepaymentEdge::PhysicalCompaction {
1602            from_floor: decoder.take_u64()?,
1603            through_seq: decoder.take_u64()?,
1604        }),
1605        t::RepaymentEdgeTag::MarkerDelivery => Ok(c::RepaymentEdge::MarkerDelivery {
1606            participant_id: decoder.take_u64()?,
1607            binding_epoch: decoder.take_binding_epoch()?,
1608            marker_delivery_seq: decoder.take_u64()?,
1609        }),
1610        t::RepaymentEdgeTag::ParticipantCursorProgress => Ok(
1611            c::RepaymentEdge::ParticipantCursorProgress(c::ParticipantCursorProgressEdge {
1612                participant_id: decoder.take_u64()?,
1613                binding_epoch: decoder.take_binding_epoch()?,
1614                through_seq: decoder.take_u64()?,
1615                marker_delivery_seq: decoder.take_option_u64()?,
1616            }),
1617        ),
1618        t::RepaymentEdgeTag::DetachedCredentialRecovery => {
1619            Ok(c::RepaymentEdge::DetachedCredentialRecovery {
1620                participant_id: decoder.take_u64()?,
1621                marker_delivery_seq: decoder.take_u64()?,
1622                prior_binding_epoch: decoder.take_binding_epoch()?,
1623            })
1624        }
1625        t::RepaymentEdgeTag::DetachedMarkerRelease => Ok(c::RepaymentEdge::DetachedMarkerRelease {
1626            participant_id: decoder.take_u64()?,
1627            marker_delivery_seq: decoder.take_u64()?,
1628            last_dead_binding_epoch: decoder.take_binding_epoch()?,
1629        }),
1630        t::RepaymentEdgeTag::DetachedCursorRelease => Ok(c::RepaymentEdge::DetachedCursorRelease {
1631            participant_id: decoder.take_u64()?,
1632            last_dead_binding_epoch: decoder.take_binding_epoch()?,
1633        }),
1634    }
1635}
1636
1637fn take_closure_snapshot(decoder: &mut Decoder<'_>) -> Result<c::ClosureSnapshot, CodecError> {
1638    Ok(c::ClosureSnapshot {
1639        marker_capacity_credits: decoder.take_u64()?,
1640        marker_anchors: decoder.take_u64()?,
1641        entry_debt: decoder.take_u64()?,
1642        byte_debt: decoder.take_u64()?,
1643        repayment_edge: take_repayment_edge(decoder)?,
1644        edge_sequence_claims: decoder.take_u64()?,
1645        edge_order_position_claims: decoder.take_u64()?,
1646        edge_k_remaining: decoder.take_resource_vector()?,
1647        k_headroom: decoder.take_wide_resource_vector()?,
1648        episode_churn_used: decoder.take_u64()?,
1649        delta_cycles: decoder.take_u64()?,
1650        episode_churn_limit: decoder.take_u64()?,
1651    })
1652}
1653
1654fn take_sequence_budget(decoder: &mut Decoder<'_>) -> Result<super::SequenceBudget, CodecError> {
1655    Ok(super::SequenceBudget {
1656        high_watermark: decoder.take_u64()?,
1657        remaining: decoder.take_u64()?,
1658        e: decoder.take_u64()?,
1659        t: decoder.take_u64()?,
1660        m: decoder.take_u64()?,
1661        rs: decoder.take_u64()?,
1662        rt: decoder.take_u64()?,
1663        l_times_t: decoder.take_u128()?,
1664        l_times_rt: decoder.take_u128()?,
1665        l_other_times_e: decoder.take_u128()?,
1666    })
1667}
1668
1669fn required_origin(
1670    origin: Option<t::ClientDiscriminant>,
1671) -> Result<t::ClientDiscriminant, CodecError> {
1672    origin.ok_or_else(|| decode_error(t::DecodeClass::InvalidField))
1673}
1674
1675#[allow(clippy::too_many_lines)]
1676fn decode_server_suffix(
1677    discriminant: t::ServerDiscriminant,
1678    origin: Option<t::ClientDiscriminant>,
1679    decoder: &mut Decoder<'_>,
1680) -> Result<r::ServerValue, CodecError> {
1681    use t::ServerDiscriminant as D;
1682
1683    match discriminant {
1684        D::ParticipantTransportRejected => {
1685            let reason = match take_tag::<t::TransportReasonTag>(decoder)? {
1686                t::TransportReasonTag::FrameTooLarge => {
1687                    r::TransportRejectionReason::FrameTooLarge {
1688                        complete_frame_bytes: decoder.take_u64()?,
1689                        max_frame_bytes: decoder.take_u64()?,
1690                    }
1691                }
1692                t::TransportReasonTag::DecodeFailed => {
1693                    let decode_class = take_tag::<t::DecodeClass>(decoder)?;
1694                    r::TransportRejectionReason::DecodeFailed { decode_class }
1695                }
1696                t::TransportReasonTag::UnsupportedVersion => {
1697                    r::TransportRejectionReason::UnsupportedVersion {
1698                        presented_version: decoder.take_protocol_version()?,
1699                        supported_version: decoder.take_protocol_version()?,
1700                    }
1701                }
1702                t::TransportReasonTag::AuthenticationFailed => {
1703                    r::TransportRejectionReason::AuthenticationFailed
1704                }
1705                t::TransportReasonTag::ParticipantCapabilityRequired => {
1706                    let capability = decoder.take_string()?;
1707                    if capability != r::PARTICIPANT_CAPABILITY {
1708                        decoder.invalidate();
1709                    }
1710                    r::TransportRejectionReason::ParticipantCapabilityRequired
1711                }
1712                t::TransportReasonTag::EnrollmentNotPermitted => {
1713                    r::TransportRejectionReason::EnrollmentNotPermitted
1714                }
1715                t::TransportReasonTag::EnrollmentConversationOutOfScope => {
1716                    r::TransportRejectionReason::EnrollmentConversationOutOfScope
1717                }
1718                t::TransportReasonTag::CredentialAttachConversationOutOfScope => {
1719                    r::TransportRejectionReason::CredentialAttachConversationOutOfScope
1720                }
1721            };
1722            Ok(r::ServerValue::ParticipantTransportRejected(
1723                r::ParticipantTransportRejected { reason },
1724            ))
1725        }
1726        D::AttemptTokenBodyConflict => {
1727            let origin = required_origin(origin)?;
1728            let token = decoder.take_fixed::<TOKEN_LEN>()?;
1729            let operation = take_tag::<t::AttemptOperation>(decoder)?;
1730            match origin {
1731                t::ClientDiscriminant::CredentialAttachRequest => {
1732                    if operation != t::AttemptOperation::CredentialAttachRequest {
1733                        return Err(decode_error(t::DecodeClass::InvalidField));
1734                    }
1735                    Ok(r::ServerValue::AttemptTokenBodyConflict(
1736                        r::AttemptTokenBodyConflict::CredentialAttach {
1737                            token: AttachAttemptToken::new(token),
1738                            conversation_id: decoder.take_u64()?,
1739                            presented_participant_id: decoder.take_u64()?,
1740                            presented_generation: decoder.take_generation()?,
1741                            presented_marker_delivery_seq: decoder.take_option_u64()?,
1742                            conflict: take_tag::<t::AttemptConflict>(decoder)?,
1743                        },
1744                    ))
1745                }
1746                t::ClientDiscriminant::LeaveRequest => {
1747                    if operation != t::AttemptOperation::LeaveRequest {
1748                        return Err(decode_error(t::DecodeClass::InvalidField));
1749                    }
1750                    let value = r::AttemptTokenBodyConflict::Leave {
1751                        token: LeaveAttemptToken::new(token),
1752                        conversation_id: decoder.take_u64()?,
1753                        presented_participant_id: decoder.take_u64()?,
1754                        presented_generation: decoder.take_generation()?,
1755                    };
1756                    if take_tag::<t::AttemptConflict>(decoder)? != t::AttemptConflict::Generation {
1757                        decoder.invalidate();
1758                    }
1759                    Ok(r::ServerValue::AttemptTokenBodyConflict(value))
1760                }
1761                t::ClientDiscriminant::RecordAdmission => {
1762                    if operation != t::AttemptOperation::RecordAdmission {
1763                        return Err(decode_error(t::DecodeClass::InvalidField));
1764                    }
1765                    Ok(r::ServerValue::AttemptTokenBodyConflict(
1766                        r::AttemptTokenBodyConflict::RecordAdmission {
1767                            token: RecordAdmissionAttemptToken::new(token),
1768                            conversation_id: decoder.take_u64()?,
1769                            presented_participant_id: decoder.take_u64()?,
1770                            presented_generation: decoder.take_generation()?,
1771                        },
1772                    ))
1773                }
1774                _ => Err(decode_error(t::DecodeClass::InvalidField)),
1775            }
1776        }
1777        D::ConnectionConversationCapacityExceeded => {
1778            let origin = required_origin(origin)?;
1779            Ok(r::ServerValue::ConnectionConversationCapacityExceeded(
1780                r::ConnectionConversationCapacityExceeded::SemanticRequest {
1781                    request: take_response_envelope(origin, decoder)?,
1782                    limit: decoder.take_u64()?,
1783                },
1784            ))
1785        }
1786        D::ConnectionConversationBindingOccupied => {
1787            let origin = required_origin(origin)?;
1788            let value = match origin {
1789                t::ClientDiscriminant::EnrollmentRequest => {
1790                    let conversation_id = decoder.take_u64()?;
1791                    let enrollment_token = EnrollmentToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
1792                    if decoder.take_option_u64()?.is_some() {
1793                        decoder.invalidate();
1794                    }
1795                    r::ConnectionConversationBindingOccupied::Enrollment {
1796                        conversation_id,
1797                        enrollment_token,
1798                    }
1799                }
1800                t::ClientDiscriminant::CredentialAttachRequest => {
1801                    let conversation_id = decoder.take_u64()?;
1802                    let participant_id = decoder.take_u64()?;
1803                    let capability_generation = decoder.take_generation()?;
1804                    let attach_attempt_token =
1805                        AttachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
1806                    let accept_marker_delivery_seq = decoder.take_option_u64()?;
1807                    if decoder.take_option_u64()? != Some(participant_id) {
1808                        decoder.invalidate();
1809                    }
1810                    r::ConnectionConversationBindingOccupied::CredentialAttach {
1811                        conversation_id,
1812                        participant_id,
1813                        capability_generation,
1814                        attach_attempt_token,
1815                        accept_marker_delivery_seq,
1816                    }
1817                }
1818                _ => return Err(decode_error(t::DecodeClass::InvalidField)),
1819            };
1820            Ok(r::ServerValue::ConnectionConversationBindingOccupied(value))
1821        }
1822        D::ConversationOrderExhausted => {
1823            let origin = required_origin(origin)?;
1824            let request = take_order_allocating(origin, decoder)?;
1825            let _counter = take_tag::<t::Counter>(decoder)?;
1826            let high = decoder.take_u64()?;
1827            let next_value = decoder.take_option_u64()?;
1828            let order_remaining = decoder.take_u128()?;
1829            let reserved_claims = decoder.take_u128()?;
1830            if decoder.take_u64()? != r::ConversationOrderExhausted::REQUIRED_MAJORS {
1831                decoder.invalidate();
1832            }
1833            let resulting_order_remaining = decoder.take_u128()?;
1834            let resulting_reserved_claims = decoder.take_u128()?;
1835            let value = r::ConversationOrderExhausted::new(
1836                request,
1837                high,
1838                order_remaining,
1839                reserved_claims,
1840                resulting_order_remaining,
1841                resulting_reserved_claims,
1842            );
1843            if next_value != value.next_value() {
1844                decoder.invalidate();
1845            }
1846            Ok(r::ServerValue::ConversationOrderExhausted(
1847                alloc::boxed::Box::new(value),
1848            ))
1849        }
1850        D::ParticipantUnknown => {
1851            let origin = required_origin(origin)?;
1852            Ok(r::ServerValue::ParticipantUnknown(r::ParticipantUnknown {
1853                request: take_participant_reference(origin, decoder)?,
1854            }))
1855        }
1856        D::NoBinding => {
1857            let origin = required_origin(origin)?;
1858            Ok(r::ServerValue::NoBinding(r::NoBinding {
1859                request: take_binding_required(origin, decoder)?,
1860            }))
1861        }
1862        D::StaleAuthority => take_stale_authority(required_origin(origin)?, decoder)
1863            .map(r::ServerValue::StaleAuthority),
1864        D::Retired => {
1865            let origin = required_origin(origin)?;
1866            let value = if origin == t::ClientDiscriminant::EnrollmentRequest {
1867                r::Retired::Enrollment {
1868                    request: take_enrollment(decoder)?,
1869                    participant_id: decoder.take_u64()?,
1870                    retired_generation: decoder.take_generation()?,
1871                }
1872            } else {
1873                r::Retired::Participant {
1874                    request: take_participant_reference(origin, decoder)?,
1875                    retired_generation: decoder.take_generation()?,
1876                }
1877            };
1878            Ok(r::ServerValue::Retired(value))
1879        }
1880        D::MarkerClosureCapacityExceeded => {
1881            let origin = required_origin(origin)?;
1882            let request = take_closure_checked(origin, decoder)?;
1883            let scope = take_tag::<t::ClosureScope>(decoder)?;
1884            let snapshot = take_closure_snapshot(decoder)?;
1885            let reason = match scope {
1886                t::ClosureScope::Capacity => {
1887                    let dimension =
1888                        ResourceDimension::from(take_tag::<t::ResourceDimensionTag>(decoder)?);
1889                    c::ClosureRefusalReason::Capacity(c::ClosureCapacityReason {
1890                        dimension,
1891                        required: decoder.take_u128()?,
1892                        limit: decoder.take_u128()?,
1893                    })
1894                }
1895                t::ClosureScope::RecoveryFence => c::ClosureRefusalReason::RecoveryFence,
1896                t::ClosureScope::DeliveredMarkerAwaitingAck => {
1897                    c::ClosureRefusalReason::DeliveredMarkerAwaitingAck
1898                }
1899                t::ClosureScope::EpisodeChurnLimit => c::ClosureRefusalReason::EpisodeChurnLimit,
1900            };
1901            Ok(r::ServerValue::MarkerClosureCapacityExceeded(
1902                alloc::boxed::Box::new(c::MarkerClosureCapacityExceeded {
1903                    request,
1904                    snapshot,
1905                    reason,
1906                }),
1907            ))
1908        }
1909        D::EnrollBound => take_enroll_bound(decoder).map(r::ServerValue::EnrollBound),
1910        D::EnrollmentKnown => Ok(r::ServerValue::EnrollmentKnown(r::EnrollmentKnown {
1911            conversation_id: decoder.take_u64()?,
1912            token: EnrollmentToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1913            participant_id: decoder.take_u64()?,
1914            current_generation: decoder.take_generation()?,
1915        })),
1916        D::ReceiptExpired => take_receipt_expired(required_origin(origin)?, decoder)
1917            .map(r::ServerValue::ReceiptExpired),
1918        D::ReceiptCapacityExceeded => take_receipt_capacity(required_origin(origin)?, decoder)
1919            .map(r::ServerValue::ReceiptCapacityExceeded),
1920        D::IdentityCapacityExceeded => {
1921            let request = take_enrollment(decoder)?;
1922            let scope = take_tag::<t::IdentityCapacityScope>(decoder)?;
1923            let limit = decoder.take_u64()?;
1924            let occupied = decoder.take_u64()?;
1925            if decoder.take_u64()? != r::IdentityCapacityExceeded::REQUESTED {
1926                decoder.invalidate();
1927            }
1928            Ok(r::ServerValue::IdentityCapacityExceeded(
1929                r::IdentityCapacityExceeded {
1930                    request,
1931                    scope,
1932                    limit,
1933                    occupied,
1934                },
1935            ))
1936        }
1937        D::ObserverBackpressure => take_observer_backpressure(required_origin(origin)?, decoder)
1938            .map(r::ServerValue::ObserverBackpressure),
1939        D::ConversationSequenceExhausted => {
1940            let request = take_sequence_allocating(required_origin(origin)?, decoder)?;
1941            Ok(r::ServerValue::ConversationSequenceExhausted(
1942                alloc::boxed::Box::new(r::ConversationSequenceExhausted {
1943                    request,
1944                    sequence_budget: take_sequence_budget(decoder)?,
1945                }),
1946            ))
1947        }
1948        D::AttachBound => take_attach_bound(decoder).map(r::ServerValue::AttachBound),
1949        D::StaleOrUnknownReceipt => Ok(r::ServerValue::StaleOrUnknownReceipt(
1950            r::StaleOrUnknownReceipt {
1951                conversation_id: decoder.take_u64()?,
1952                token: AttachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1953                participant_id: decoder.take_u64()?,
1954                presented_generation: decoder.take_generation()?,
1955                presented_marker_delivery_seq: decoder.take_option_u64()?,
1956                current_generation: decoder.take_generation()?,
1957            },
1958        )),
1959        D::MarkerNotDelivered => {
1960            let request = take_marker_proof(required_origin(origin)?, decoder)?;
1961            let reason = take_tag::<t::MarkerNotDeliveredReason>(decoder)?;
1962            Ok(r::ServerValue::MarkerNotDelivered(r::MarkerNotDelivered {
1963                request,
1964                reason,
1965                expected_marker_delivery_seq: decoder.take_u64()?,
1966            }))
1967        }
1968        D::MarkerMismatch => {
1969            let request = take_marker_proof(required_origin(origin)?, decoder)?;
1970            let reason = take_tag::<t::MarkerMismatchReason>(decoder)?;
1971            let mismatch = match reason {
1972                t::MarkerMismatchReason::BelowCursor => r::MarkerMismatchBody::BelowCursor {
1973                    current_cursor: decoder.take_u64()?,
1974                },
1975                t::MarkerMismatchReason::NoMarkerExpected => {
1976                    r::MarkerMismatchBody::NoMarkerExpected
1977                }
1978                t::MarkerMismatchReason::ExpectedDifferentMarker => {
1979                    r::MarkerMismatchBody::ExpectedDifferentMarker {
1980                        expected_marker_delivery_seq: decoder.take_u64()?,
1981                    }
1982                }
1983            };
1984            Ok(r::ServerValue::MarkerMismatch(r::MarkerMismatch {
1985                request,
1986                mismatch,
1987            }))
1988        }
1989        D::Bound => {
1990            take_receipt_replay(required_origin(origin)?, decoder).map(r::ServerValue::Bound)
1991        }
1992        D::UnboundReceipt => take_receipt_replay(required_origin(origin)?, decoder)
1993            .map(r::ServerValue::UnboundReceipt),
1994        D::DetachCommitted => {
1995            let conversation_id = decoder.take_u64()?;
1996            let participant_id = decoder.take_u64()?;
1997            let capability_generation = decoder.take_generation()?;
1998            let detach_attempt_token = DetachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
1999            let committed_binding_epoch = decoder.take_binding_epoch()?;
2000            let detached_delivery_seq = decoder.take_u64()?;
2001            if capability_generation != committed_binding_epoch.capability_generation {
2002                decoder.invalidate();
2003            }
2004            Ok(r::ServerValue::DetachCommitted(r::DetachCommitted::new(
2005                conversation_id,
2006                participant_id,
2007                detach_attempt_token,
2008                committed_binding_epoch,
2009                detached_delivery_seq,
2010            )))
2011        }
2012        D::DetachInProgress => Ok(r::ServerValue::DetachInProgress(r::DetachInProgress {
2013            conversation_id: decoder.take_u64()?,
2014            participant_id: decoder.take_u64()?,
2015            presented_token: DetachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
2016            presented_generation: decoder.take_generation()?,
2017            committed_binding_epoch: decoder.take_binding_epoch()?,
2018        })),
2019        D::AckCommitted => {
2020            let request = take_participant_ack(decoder)?;
2021            if decoder.take_u64()? != request.through_seq {
2022                decoder.invalidate();
2023            }
2024            Ok(r::ServerValue::AckCommitted(r::AckCommitted::new(request)))
2025        }
2026        D::AckNoOp => {
2027            take_ack_no_op(required_origin(origin)?, decoder).map(r::ServerValue::AckNoOp)
2028        }
2029        D::AckGap => {
2030            let request = take_participant_ack(decoder)?;
2031            let current_cursor = decoder.take_u64()?;
2032            let _reason = take_tag::<t::AckGapReason>(decoder)?;
2033            r::AckGap::new(request, current_cursor)
2034                .map(r::ServerValue::AckGap)
2035                .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))
2036        }
2037        D::AckRegression => {
2038            let request = take_participant_ack(decoder)?;
2039            let current_cursor = decoder.take_u64()?;
2040            let _reason = take_tag::<t::AckRegressionReason>(decoder)?;
2041            r::AckRegression::new(request, current_cursor)
2042                .map(r::ServerValue::AckRegression)
2043                .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))
2044        }
2045        D::LeaveCommitted => {
2046            let conversation_id = decoder.take_u64()?;
2047            let leave_attempt_token = LeaveAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2048            let participant_id = decoder.take_u64()?;
2049            let presented_generation = decoder.take_generation()?;
2050            let retired_generation = decoder.take_generation()?;
2051            let ended_binding_epoch = decoder.take_option_binding_epoch()?;
2052            let prior_terminal_delivery_seq = decoder.take_option_u64()?;
2053            let left_delivery_seq = decoder.take_u64()?;
2054            if presented_generation != retired_generation {
2055                return Err(decode_error(t::DecodeClass::InvalidField));
2056            }
2057            r::LeaveCommitted::new(
2058                conversation_id,
2059                leave_attempt_token,
2060                participant_id,
2061                retired_generation,
2062                ended_binding_epoch,
2063                prior_terminal_delivery_seq,
2064                left_delivery_seq,
2065            )
2066            .map(r::ServerValue::LeaveCommitted)
2067            .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))
2068        }
2069        D::MarkerAckCommitted => {
2070            let request = take_marker_ack(decoder)?;
2071            if decoder.take_u64()? != request.marker_delivery_seq {
2072                decoder.invalidate();
2073            }
2074            Ok(r::ServerValue::MarkerAckCommitted(
2075                r::MarkerAckCommitted::new(request),
2076            ))
2077        }
2078        D::SettlementAnswer => {
2079            let conversation_id = decoder.take_u64()?;
2080            let participant_id = decoder.take_u64()?;
2081            let record_admission_attempt_token =
2082                RecordAdmissionAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2083            let outcome = match decoder.take_u8()? {
2084                1 => r::SettlementOutcome::Committed {
2085                    delivery_seq: decoder.take_u64()?,
2086                },
2087                2 => r::SettlementOutcome::Withdrawn,
2088                3 => r::SettlementOutcome::Expired,
2089                4 => r::SettlementOutcome::NotCommitted,
2090                5 => r::SettlementOutcome::Unknown,
2091                _ => return Err(decode_error(t::DecodeClass::InvalidField)),
2092            };
2093            Ok(r::ServerValue::SettlementAnswer(r::SettlementAnswer {
2094                conversation_id,
2095                participant_id,
2096                record_admission_attempt_token,
2097                outcome,
2098            }))
2099        }
2100        D::RecordCommitted => {
2101            let request = take_record_admission(decoder)?;
2102            if decoder.take_u64()? != request.participant_id {
2103                decoder.invalidate();
2104            }
2105            let delivery_seq = decoder.take_u64()?;
2106            Ok(r::ServerValue::RecordCommitted(r::RecordCommitted::new(
2107                request,
2108                delivery_seq,
2109            )))
2110        }
2111        D::RecordTooLarge => Ok(r::ServerValue::RecordTooLarge(r::RecordTooLarge {
2112            request: take_record_admission(decoder)?,
2113            dimension: ResourceDimension::from(take_tag::<t::ResourceDimensionTag>(decoder)?),
2114            encoded_record_charge: decoder.take_resource_vector()?,
2115            max_ordinary_record_charge: decoder.take_resource_vector()?,
2116        })),
2117        D::ObserverRecoveryAccepted => {
2118            take_recovery_accepted(decoder).map(r::ServerValue::ObserverRecoveryAccepted)
2119        }
2120        D::InvalidObserverEpoch => {
2121            require_zero_recovery_count(decoder)?;
2122            take_invalid_observer_epoch(decoder).map(r::ServerValue::InvalidObserverEpoch)
2123        }
2124        D::InvalidObserverEpochList => {
2125            require_zero_recovery_count(decoder)?;
2126            take_invalid_observer_epoch_list(decoder).map(r::ServerValue::InvalidObserverEpochList)
2127        }
2128        D::ObserverRecoveryConnectionCapacityExceeded => {
2129            require_zero_recovery_count(decoder)?;
2130            Ok(r::ServerValue::ConnectionConversationCapacityExceeded(
2131                r::ConnectionConversationCapacityExceeded::ObserverRecovery {
2132                    conversation_id: decoder.take_u64()?,
2133                    limit: decoder.take_u64()?,
2134                },
2135            ))
2136        }
2137        D::MarkerSettlementBackpressure => {
2138            let origin = required_origin(origin)?;
2139            let conversation_id = decoder.take_u64()?;
2140            let refused_epoch = decoder.take_u64()?;
2141            let value = match origin {
2142                t::ClientDiscriminant::CredentialAttachRequest => {
2143                    r::MarkerSettlementBackpressure::CredentialAttach {
2144                        conversation_id,
2145                        refused_epoch,
2146                    }
2147                }
2148                t::ClientDiscriminant::DetachRequest => r::MarkerSettlementBackpressure::Detach {
2149                    conversation_id,
2150                    refused_epoch,
2151                },
2152                _ => return Err(decode_error(t::DecodeClass::InvalidField)),
2153            };
2154            Ok(r::ServerValue::MarkerSettlementBackpressure(value))
2155        }
2156        D::EnrollmentSettlementBackpressure => {
2157            required_origin(origin)?;
2158            Ok(r::ServerValue::EnrollmentSettlementBackpressure(
2159                r::EnrollmentSettlementBackpressure {
2160                    conversation_id: decoder.take_u64()?,
2161                },
2162            ))
2163        }
2164        D::RecordAdmissionProtocolFault => Ok(r::ServerValue::RecordAdmissionProtocolFault(
2165            r::RecordAdmissionProtocolFault {
2166                request: take_record_admission(decoder)?,
2167                class: r::RecordAdmissionFaultClass::from(take_tag::<
2168                    t::RecordAdmissionFaultClassTag,
2169                >(decoder)?),
2170            },
2171        )),
2172        D::WriteOutcomeUnknown => take_write_outcome_unknown(required_origin(origin)?, decoder)
2173            .map(r::ServerValue::WriteOutcomeUnknown),
2174    }
2175}
2176
2177fn take_write_outcome_unknown(
2178    origin: t::ClientDiscriminant,
2179    decoder: &mut Decoder<'_>,
2180) -> Result<r::WriteOutcomeUnknown, CodecError> {
2181    match origin {
2182        t::ClientDiscriminant::EnrollmentRequest => Ok(r::WriteOutcomeUnknown::Enrollment {
2183            request: take_enrollment(decoder)?,
2184        }),
2185        t::ClientDiscriminant::CredentialAttachRequest => {
2186            Ok(r::WriteOutcomeUnknown::CredentialAttach {
2187                request: take_attach(decoder)?,
2188            })
2189        }
2190        t::ClientDiscriminant::DetachRequest => Ok(r::WriteOutcomeUnknown::Detach {
2191            request: take_detach(decoder)?,
2192        }),
2193        t::ClientDiscriminant::LeaveRequest => Ok(r::WriteOutcomeUnknown::Leave {
2194            request: take_leave(decoder)?,
2195        }),
2196        t::ClientDiscriminant::RecordAdmission => Ok(r::WriteOutcomeUnknown::RecordAdmission {
2197            request: take_record_admission(decoder)?,
2198        }),
2199        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2200    }
2201}
2202
2203trait WireTag: TryFrom<u16> {}
2204
2205impl WireTag for t::TransportReasonTag {}
2206impl WireTag for t::DecodeClass {}
2207impl WireTag for t::AttemptOperation {}
2208impl WireTag for t::AttemptConflict {}
2209impl WireTag for t::Counter {}
2210impl WireTag for t::ClosureScope {}
2211impl WireTag for t::ResourceDimensionTag {}
2212impl WireTag for t::IdentityCapacityScope {}
2213impl WireTag for t::MarkerNotDeliveredReason {}
2214impl WireTag for t::MarkerMismatchReason {}
2215impl WireTag for t::AckGapReason {}
2216impl WireTag for t::AckRegressionReason {}
2217impl WireTag for t::InvalidObserverEpochReason {}
2218impl WireTag for t::InvalidObserverEpochListReason {}
2219impl WireTag for t::RecordAdmissionFaultClassTag {}
2220
2221fn take_tag<T>(decoder: &mut Decoder<'_>) -> Result<T, CodecError>
2222where
2223    T: WireTag,
2224{
2225    T::try_from(decoder.take_u16()?).map_err(|_| decode_error(t::DecodeClass::InvalidField))
2226}
2227
2228fn take_stale_authority(
2229    origin: t::ClientDiscriminant,
2230    decoder: &mut Decoder<'_>,
2231) -> Result<r::StaleAuthority, CodecError> {
2232    match origin {
2233        t::ClientDiscriminant::CredentialAttachRequest => Ok(r::StaleAuthority::Live {
2234            request: r::CommonStaleAuthorityEnvelope::CredentialAttach(take_attach(decoder)?),
2235            current_generation: decoder.take_generation()?,
2236        }),
2237        t::ClientDiscriminant::ParticipantAck => Ok(r::StaleAuthority::Live {
2238            request: r::CommonStaleAuthorityEnvelope::ParticipantAck(take_participant_ack(
2239                decoder,
2240            )?),
2241            current_generation: decoder.take_generation()?,
2242        }),
2243        t::ClientDiscriminant::MarkerAck => Ok(r::StaleAuthority::Live {
2244            request: r::CommonStaleAuthorityEnvelope::MarkerAck(take_marker_ack(decoder)?),
2245            current_generation: decoder.take_generation()?,
2246        }),
2247        t::ClientDiscriminant::RecordAdmission => Ok(r::StaleAuthority::Live {
2248            request: r::CommonStaleAuthorityEnvelope::RecordAdmission(take_record_admission(
2249                decoder,
2250            )?),
2251            current_generation: decoder.take_generation()?,
2252        }),
2253        t::ClientDiscriminant::DetachRequest => {
2254            let authority = t::DetachAuthorityStateTag::try_from(decoder.take_u16()?)
2255                .map_err(|_| decode_error(t::DecodeClass::InvalidField))?;
2256            let value = match authority {
2257                t::DetachAuthorityStateTag::Live => r::DetachStaleAuthority::Live {
2258                    conversation_id: decoder.take_u64()?,
2259                    participant_id: decoder.take_u64()?,
2260                    capability_generation: decoder.take_generation()?,
2261                    detach_attempt_token: DetachAttemptToken::new(
2262                        decoder.take_fixed::<TOKEN_LEN>()?,
2263                    ),
2264                    current_generation: decoder.take_generation()?,
2265                },
2266                t::DetachAuthorityStateTag::TerminalizedDetachCell => {
2267                    let conversation_id = decoder.take_u64()?;
2268                    let participant_id = decoder.take_u64()?;
2269                    let capability_generation = decoder.take_generation()?;
2270                    let detach_attempt_token =
2271                        DetachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2272                    let current_generation = decoder.take_generation()?;
2273                    let committed_binding_epoch = decoder.take_binding_epoch()?;
2274                    let binding_state = match t::BindingStateTag::try_from(decoder.take_u16()?)
2275                        .map_err(|_| decode_error(t::DecodeClass::InvalidField))?
2276                    {
2277                        t::BindingStateTag::Bound => r::BindingStateView::Bound {
2278                            current_binding_epoch: decoder.take_binding_epoch()?,
2279                        },
2280                        t::BindingStateTag::Detached => r::BindingStateView::Detached,
2281                    };
2282                    r::DetachStaleAuthority::TerminalizedDetachCell(
2283                        r::TerminalizedDetachCell::from_wire_decode(
2284                            TERMINALIZED_WIRE_DECODE_AUTHORITY,
2285                            conversation_id,
2286                            participant_id,
2287                            capability_generation,
2288                            detach_attempt_token,
2289                            current_generation,
2290                            committed_binding_epoch,
2291                            binding_state,
2292                        ),
2293                    )
2294                }
2295            };
2296            Ok(r::StaleAuthority::Detach(value))
2297        }
2298        t::ClientDiscriminant::LeaveRequest => {
2299            let authority = t::LeaveAuthorityStateTag::try_from(decoder.take_u16()?)
2300                .map_err(|_| decode_error(t::DecodeClass::InvalidField))?;
2301            let conversation_id = decoder.take_u64()?;
2302            let participant_id = decoder.take_u64()?;
2303            let presented_generation = decoder.take_generation()?;
2304            let leave_attempt_token = LeaveAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2305            let value = match authority {
2306                t::LeaveAuthorityStateTag::Live => r::LeaveStaleAuthority::Live {
2307                    conversation_id,
2308                    participant_id,
2309                    presented_generation,
2310                    leave_attempt_token,
2311                    current_generation: decoder.take_generation()?,
2312                },
2313                t::LeaveAuthorityStateTag::CommittedLeaveTombstone => {
2314                    r::LeaveStaleAuthority::CommittedLeaveTombstone {
2315                        conversation_id,
2316                        participant_id,
2317                        presented_generation,
2318                        leave_attempt_token,
2319                        retired_generation: decoder.take_generation()?,
2320                    }
2321                }
2322            };
2323            Ok(r::StaleAuthority::Leave(value))
2324        }
2325        t::ClientDiscriminant::EnrollmentRequest
2326        | t::ClientDiscriminant::ObserverRecoveryHandshake
2327        | t::ClientDiscriminant::SettlementQuery => Err(decode_error(t::DecodeClass::InvalidField)),
2328    }
2329}
2330
2331fn take_enroll_bound(decoder: &mut Decoder<'_>) -> Result<r::EnrollBound, CodecError> {
2332    let conversation_id = decoder.take_u64()?;
2333    let token = EnrollmentToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2334    let participant_id = decoder.take_u64()?;
2335    if decoder.take_option_generation()?.is_some() {
2336        decoder.invalidate();
2337    }
2338    let capability_generation = decoder.take_generation()?;
2339    if capability_generation.get() != 1 {
2340        decoder.invalidate();
2341    }
2342    let attach_secret = AttachSecret::new(decoder.take_fixed::<SECRET_LEN>()?);
2343    let origin_binding_epoch = decoder.take_binding_epoch()?;
2344    if origin_binding_epoch.capability_generation.get() != 1 {
2345        decoder.invalidate();
2346    }
2347    if decoder.take_u64()? != 0 {
2348        decoder.invalidate();
2349    }
2350    if decoder.take_option_u64()?.is_some() {
2351        decoder.invalidate();
2352    }
2353    let receipt_expires_at = decoder.take_u128()?;
2354    let provenance_expires_at = decoder.take_u128()?;
2355
2356    let valid_epoch = if origin_binding_epoch.capability_generation.get() == 1 {
2357        origin_binding_epoch
2358    } else {
2359        BindingEpoch::new(
2360            origin_binding_epoch.connection_incarnation,
2361            generation_one()?,
2362        )
2363    };
2364    r::EnrollBound::new(
2365        conversation_id,
2366        token,
2367        participant_id,
2368        attach_secret,
2369        valid_epoch,
2370        receipt_expires_at,
2371        provenance_expires_at,
2372    )
2373    .ok_or(CodecError::InvalidValue)
2374}
2375
2376fn take_receipt_expired(
2377    origin: t::ClientDiscriminant,
2378    decoder: &mut Decoder<'_>,
2379) -> Result<r::ReceiptExpired, CodecError> {
2380    let conversation_id = decoder.take_u64()?;
2381    let token = decoder.take_fixed::<TOKEN_LEN>()?;
2382    let participant_id = decoder.take_u64()?;
2383    match origin {
2384        t::ClientDiscriminant::EnrollmentRequest => {
2385            if decoder.take_option_generation()?.is_some() {
2386                decoder.invalidate();
2387            }
2388            Ok(r::ReceiptExpired::Enrollment {
2389                conversation_id,
2390                token: EnrollmentToken::new(token),
2391                participant_id,
2392                result_generation: decoder.take_generation()?,
2393                current_generation: decoder.take_generation()?,
2394                reason: take_tag::<t::ReceiptExpiryReason>(decoder)?,
2395            })
2396        }
2397        t::ClientDiscriminant::CredentialAttachRequest => {
2398            let presented_generation = required_generation_option(decoder)?;
2399            Ok(r::ReceiptExpired::CredentialAttach {
2400                conversation_id,
2401                token: AttachAttemptToken::new(token),
2402                participant_id,
2403                presented_generation,
2404                presented_marker_delivery_seq: decoder.take_option_u64()?,
2405                result_generation: decoder.take_generation()?,
2406                current_generation: decoder.take_generation()?,
2407                reason: take_tag::<t::ReceiptExpiryReason>(decoder)?,
2408            })
2409        }
2410        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2411    }
2412}
2413
2414impl WireTag for t::ReceiptExpiryReason {}
2415impl WireTag for t::ReceiptCapacityScope {}
2416
2417fn take_receipt_capacity(
2418    origin: t::ClientDiscriminant,
2419    decoder: &mut Decoder<'_>,
2420) -> Result<r::ReceiptCapacityExceeded, CodecError> {
2421    match origin {
2422        t::ClientDiscriminant::EnrollmentRequest => {
2423            let request = take_enrollment(decoder)?;
2424            let scope = match take_tag::<t::ReceiptCapacityScope>(decoder)? {
2425                t::ReceiptCapacityScope::LiveReceiptServer => {
2426                    r::EnrollmentReceiptCapacityScope::LiveReceiptServer
2427                }
2428                t::ReceiptCapacityScope::ProvenanceServer => {
2429                    r::EnrollmentReceiptCapacityScope::ProvenanceServer
2430                }
2431                t::ReceiptCapacityScope::ProvenanceConversation => {
2432                    r::EnrollmentReceiptCapacityScope::ProvenanceConversation
2433                }
2434                t::ReceiptCapacityScope::LiveReceiptParticipant
2435                | t::ReceiptCapacityScope::ProvenanceParticipant => {
2436                    return Err(decode_error(t::DecodeClass::InvalidField));
2437                }
2438            };
2439            let limit = decoder.take_u64()?;
2440            let occupied = decoder.take_u64()?;
2441            require_one(decoder, r::ReceiptCapacityExceeded::REQUESTED)?;
2442            Ok(r::ReceiptCapacityExceeded::Enrollment {
2443                request,
2444                scope,
2445                limit,
2446                occupied,
2447            })
2448        }
2449        t::ClientDiscriminant::CredentialAttachRequest => {
2450            let request = take_attach(decoder)?;
2451            let scope = take_tag::<t::ReceiptCapacityScope>(decoder)?;
2452            let limit = decoder.take_u64()?;
2453            let occupied = decoder.take_u64()?;
2454            require_one(decoder, r::ReceiptCapacityExceeded::REQUESTED)?;
2455            Ok(r::ReceiptCapacityExceeded::CredentialAttach {
2456                request,
2457                scope,
2458                limit,
2459                occupied,
2460            })
2461        }
2462        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2463    }
2464}
2465
2466fn require_one(decoder: &mut Decoder<'_>, expected: u64) -> Result<(), CodecError> {
2467    if decoder.take_u64()? != expected {
2468        decoder.invalidate();
2469    }
2470    Ok(())
2471}
2472
2473fn take_observer_backpressure(
2474    origin: t::ClientDiscriminant,
2475    decoder: &mut Decoder<'_>,
2476) -> Result<r::ObserverBackpressure, CodecError> {
2477    match origin {
2478        t::ClientDiscriminant::EnrollmentRequest => Ok(r::ObserverBackpressure::Enrollment {
2479            request: take_enrollment(decoder)?,
2480            state: take_backpressure_state(decoder)?,
2481        }),
2482        t::ClientDiscriminant::CredentialAttachRequest => {
2483            Ok(r::ObserverBackpressure::CredentialAttach {
2484                request: take_attach(decoder)?,
2485                state: take_backpressure_state(decoder)?,
2486            })
2487        }
2488        t::ClientDiscriminant::DetachRequest => Ok(r::ObserverBackpressure::Detach {
2489            request: take_detach(decoder)?,
2490            committed_binding_epoch: decoder.take_binding_epoch()?,
2491            state: take_backpressure_state(decoder)?,
2492        }),
2493        t::ClientDiscriminant::LeaveRequest => Ok(r::ObserverBackpressure::Leave {
2494            request: take_leave(decoder)?,
2495            state: take_backpressure_state(decoder)?,
2496            prior_terminal_cell_exists: decoder.take_bool()?,
2497        }),
2498        t::ClientDiscriminant::RecordAdmission => Ok(r::ObserverBackpressure::RecordAdmission {
2499            request: take_record_admission(decoder)?,
2500            state: take_backpressure_state(decoder)?,
2501        }),
2502        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2503    }
2504}
2505
2506fn take_backpressure_state(
2507    decoder: &mut Decoder<'_>,
2508) -> Result<r::ObserverBackpressureState, CodecError> {
2509    let backpressure_epoch = decoder.take_u64()?;
2510    let observer_progress = decoder.take_u64()?;
2511    r::ObserverBackpressureState::replay(backpressure_epoch, observer_progress)
2512        .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))
2513}
2514
2515fn required_generation_option(decoder: &mut Decoder<'_>) -> Result<Generation, CodecError> {
2516    decoder.take_option_generation()?.map_or_else(
2517        || {
2518            decoder.invalidate();
2519            generation_one()
2520        },
2521        Ok,
2522    )
2523}
2524
2525fn take_attach_bound(decoder: &mut Decoder<'_>) -> Result<r::AttachBound, CodecError> {
2526    let conversation_id = decoder.take_u64()?;
2527    let token = AttachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2528    let participant_id = decoder.take_u64()?;
2529    let request_generation = required_generation_option(decoder)?;
2530    let capability_generation = decoder.take_generation()?;
2531    let attach_secret = AttachSecret::new(decoder.take_fixed::<SECRET_LEN>()?);
2532    let origin_binding_epoch = decoder.take_binding_epoch()?;
2533    let persisted_cursor = decoder.take_u64()?;
2534    let accepted_marker_delivery_seq = decoder.take_option_u64()?;
2535    let receipt_expires_at = decoder.take_u128()?;
2536    let provenance_expires_at = decoder.take_u128()?;
2537
2538    let value = match accepted_marker_delivery_seq {
2539        Some(marker) if persisted_cursor == marker => r::AttachBound::fenced(
2540            conversation_id,
2541            token,
2542            participant_id,
2543            request_generation,
2544            attach_secret,
2545            origin_binding_epoch,
2546            marker,
2547            receipt_expires_at,
2548            provenance_expires_at,
2549        ),
2550        Some(_) => None,
2551        None => r::AttachBound::ordinary(
2552            conversation_id,
2553            token,
2554            participant_id,
2555            request_generation,
2556            attach_secret,
2557            origin_binding_epoch,
2558            persisted_cursor,
2559            receipt_expires_at,
2560            provenance_expires_at,
2561        ),
2562    }
2563    .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))?;
2564    if value.capability_generation() == capability_generation {
2565        Ok(value)
2566    } else {
2567        Err(decode_error(t::DecodeClass::InvalidField))
2568    }
2569}
2570
2571fn take_receipt_replay(
2572    origin: t::ClientDiscriminant,
2573    decoder: &mut Decoder<'_>,
2574) -> Result<r::ReceiptReplay, CodecError> {
2575    let conversation_id = decoder.take_u64()?;
2576    let token = decoder.take_fixed::<TOKEN_LEN>()?;
2577    let participant_id = decoder.take_u64()?;
2578    match origin {
2579        t::ClientDiscriminant::EnrollmentRequest => {
2580            let request_generation = decoder.take_option_generation()?;
2581            let capability_generation = decoder.take_generation()?;
2582            let attach_secret = AttachSecret::new(decoder.take_fixed::<SECRET_LEN>()?);
2583            let origin_binding_epoch = decoder.take_binding_epoch()?;
2584            let persisted_cursor = decoder.take_u64()?;
2585            let accepted_marker_delivery_seq = decoder.take_option_u64()?;
2586            let receipt_expires_at = decoder.take_u128()?;
2587            let provenance_expires_at = decoder.take_u128()?;
2588            let value = r::EnrollBound::new(
2589                conversation_id,
2590                EnrollmentToken::new(token),
2591                participant_id,
2592                attach_secret,
2593                origin_binding_epoch,
2594                receipt_expires_at,
2595                provenance_expires_at,
2596            )
2597            .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))?;
2598            if request_generation.is_none()
2599                && capability_generation == Generation::ONE
2600                && persisted_cursor == 0
2601                && accepted_marker_delivery_seq.is_none()
2602            {
2603                Ok(r::ReceiptReplay::Enrollment(value))
2604            } else {
2605                Err(decode_error(t::DecodeClass::InvalidField))
2606            }
2607        }
2608        t::ClientDiscriminant::CredentialAttachRequest => {
2609            let request_generation = required_generation_option(decoder)?;
2610            let capability_generation = decoder.take_generation()?;
2611            let attach_secret = AttachSecret::new(decoder.take_fixed::<SECRET_LEN>()?);
2612            let origin_binding_epoch = decoder.take_binding_epoch()?;
2613            let persisted_cursor = decoder.take_u64()?;
2614            let accepted_marker_delivery_seq = decoder.take_option_u64()?;
2615            let receipt_expires_at = decoder.take_u128()?;
2616            let provenance_expires_at = decoder.take_u128()?;
2617            let attach_token = AttachAttemptToken::new(token);
2618            let value = match accepted_marker_delivery_seq {
2619                Some(marker) if persisted_cursor == marker => r::AttachBound::fenced(
2620                    conversation_id,
2621                    attach_token,
2622                    participant_id,
2623                    request_generation,
2624                    attach_secret,
2625                    origin_binding_epoch,
2626                    marker,
2627                    receipt_expires_at,
2628                    provenance_expires_at,
2629                ),
2630                Some(_) => None,
2631                None => r::AttachBound::ordinary(
2632                    conversation_id,
2633                    attach_token,
2634                    participant_id,
2635                    request_generation,
2636                    attach_secret,
2637                    origin_binding_epoch,
2638                    persisted_cursor,
2639                    receipt_expires_at,
2640                    provenance_expires_at,
2641                ),
2642            }
2643            .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))?;
2644            if value.capability_generation() == capability_generation {
2645                Ok(r::ReceiptReplay::CredentialAttach(value))
2646            } else {
2647                Err(decode_error(t::DecodeClass::InvalidField))
2648            }
2649        }
2650        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2651    }
2652}
2653
2654fn take_ack_no_op(
2655    origin: t::ClientDiscriminant,
2656    decoder: &mut Decoder<'_>,
2657) -> Result<r::AckNoOp, CodecError> {
2658    match origin {
2659        t::ClientDiscriminant::ParticipantAck => {
2660            let request = take_participant_ack(decoder)?;
2661            if decoder.take_u64()? != request.through_seq {
2662                decoder.invalidate();
2663            }
2664            Ok(r::AckNoOp::participant_ack(request))
2665        }
2666        t::ClientDiscriminant::MarkerAck => {
2667            let request = take_marker_ack(decoder)?;
2668            if decoder.take_u64()? != request.marker_delivery_seq {
2669                decoder.invalidate();
2670            }
2671            Ok(r::AckNoOp::marker_ack(request))
2672        }
2673        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2674    }
2675}
2676
2677fn take_recovery_accepted(
2678    decoder: &mut Decoder<'_>,
2679) -> Result<r::ObserverRecoveryAccepted, CodecError> {
2680    let count = decoder.take_u64()?;
2681    let required = u128::from(count) * RECOVERY_STATUS_LEN;
2682    let remaining = u64::try_from(decoder.remaining())
2683        .map_err(|_| decode_error(t::DecodeClass::MissingRequiredField))?;
2684    if required > u128::from(remaining) {
2685        return Err(decode_error(t::DecodeClass::MissingRequiredField));
2686    }
2687    let count_usize: usize = count
2688        .try_into()
2689        .map_err(|_| decode_error(t::DecodeClass::MissingRequiredField))?;
2690
2691    let mut statuses = Vec::new();
2692    for _ in 0..count_usize {
2693        statuses.push(r::ObserverProgressStatus {
2694            conversation_id: decoder.take_u64()?,
2695            refused_epoch: decoder.take_u64()?,
2696            current_observer_progress: decoder.take_u64()?,
2697            armed: decoder.take_bool()?,
2698            progressed: decoder.take_bool()?,
2699        });
2700    }
2701    Ok(r::ObserverRecoveryAccepted { statuses })
2702}
2703
2704fn require_zero_recovery_count(decoder: &mut Decoder<'_>) -> Result<(), CodecError> {
2705    if decoder.take_u64()? == 0 {
2706        Ok(())
2707    } else {
2708        Err(decode_error(t::DecodeClass::InvalidField))
2709    }
2710}
2711
2712fn take_invalid_observer_epoch(
2713    decoder: &mut Decoder<'_>,
2714) -> Result<r::InvalidObserverEpoch, CodecError> {
2715    let reason = take_tag::<t::InvalidObserverEpochReason>(decoder)?;
2716    let conversation_id = decoder.take_u64()?;
2717    let presented_epoch = decoder.take_u64()?;
2718    let current = decoder.take_option_u64()?;
2719    match reason {
2720        t::InvalidObserverEpochReason::ConversationUnknown => {
2721            if current.is_some() {
2722                decoder.invalidate();
2723            }
2724            Ok(r::InvalidObserverEpoch::ConversationUnknown {
2725                conversation_id,
2726                presented_epoch,
2727            })
2728        }
2729        t::InvalidObserverEpochReason::EpochAhead => {
2730            let current_observer_progress = current.unwrap_or_else(|| {
2731                decoder.invalidate();
2732                0
2733            });
2734            Ok(r::InvalidObserverEpoch::EpochAhead {
2735                conversation_id,
2736                presented_epoch,
2737                current_observer_progress,
2738            })
2739        }
2740    }
2741}
2742
2743fn take_invalid_observer_epoch_list(
2744    decoder: &mut Decoder<'_>,
2745) -> Result<r::InvalidObserverEpochList, CodecError> {
2746    match take_tag::<t::InvalidObserverEpochListReason>(decoder)? {
2747        t::InvalidObserverEpochListReason::TooManyEntries => {
2748            Ok(r::InvalidObserverEpochList::TooManyEntries {
2749                presented_entries: decoder.take_u64()?,
2750                max_entries: decoder.take_u64()?,
2751            })
2752        }
2753        t::InvalidObserverEpochListReason::DuplicateConversation => {
2754            Ok(r::InvalidObserverEpochList::DuplicateConversation {
2755                conversation_id: decoder.take_u64()?,
2756                first_index: decoder.take_u64()?,
2757                duplicate_index: decoder.take_u64()?,
2758            })
2759        }
2760    }
2761}