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            r::TransportRejectionReason::AccessRefused { refusal } => {
636                encoder.put_u16(t::TransportReasonTag::AccessRefused.wire_value());
637                encoder.put_string(refusal)?;
638            }
639        },
640        r::ServerValue::AttemptTokenBodyConflict(value) => match value {
641            r::AttemptTokenBodyConflict::CredentialAttach {
642                token,
643                conversation_id,
644                presented_participant_id,
645                presented_generation,
646                presented_marker_delivery_seq,
647                conflict,
648            } => {
649                encoder.put_fixed(token.as_bytes());
650                encoder.put_u16(t::AttemptOperation::CredentialAttachRequest.wire_value());
651                encoder.put_u64(*conversation_id);
652                encoder.put_u64(*presented_participant_id);
653                encoder.put_generation(*presented_generation);
654                encoder.put_option_u64(*presented_marker_delivery_seq);
655                encoder.put_u16(conflict.wire_value());
656            }
657            r::AttemptTokenBodyConflict::Leave {
658                token,
659                conversation_id,
660                presented_participant_id,
661                presented_generation,
662            } => {
663                encoder.put_fixed(token.as_bytes());
664                encoder.put_u16(t::AttemptOperation::LeaveRequest.wire_value());
665                encoder.put_u64(*conversation_id);
666                encoder.put_u64(*presented_participant_id);
667                encoder.put_generation(*presented_generation);
668                encoder.put_u16(t::AttemptConflict::Generation.wire_value());
669            }
670            r::AttemptTokenBodyConflict::RecordAdmission {
671                token,
672                conversation_id,
673                presented_participant_id,
674                presented_generation,
675            } => {
676                encoder.put_fixed(token.as_bytes());
677                encoder.put_u16(t::AttemptOperation::RecordAdmission.wire_value());
678                encoder.put_u64(*conversation_id);
679                encoder.put_u64(*presented_participant_id);
680                encoder.put_generation(*presented_generation);
681            }
682        },
683        r::ServerValue::ConnectionConversationCapacityExceeded(value) => match value {
684            r::ConnectionConversationCapacityExceeded::SemanticRequest { request, limit } => {
685                put_response_envelope(request, encoder);
686                encoder.put_u64(*limit);
687            }
688            r::ConnectionConversationCapacityExceeded::ObserverRecovery {
689                conversation_id,
690                limit,
691            } => {
692                encoder.put_u64(0);
693                encoder.put_u64(*conversation_id);
694                encoder.put_u64(*limit);
695            }
696        },
697        r::ServerValue::ConnectionConversationBindingOccupied(value) => match value {
698            r::ConnectionConversationBindingOccupied::Enrollment {
699                conversation_id,
700                enrollment_token,
701            } => {
702                encoder.put_u64(*conversation_id);
703                encoder.put_fixed(enrollment_token.as_bytes());
704                encoder.put_option_u64(None);
705            }
706            r::ConnectionConversationBindingOccupied::CredentialAttach {
707                conversation_id,
708                participant_id,
709                capability_generation,
710                attach_attempt_token,
711                accept_marker_delivery_seq,
712            } => {
713                encoder.put_u64(*conversation_id);
714                encoder.put_u64(*participant_id);
715                encoder.put_generation(*capability_generation);
716                encoder.put_fixed(attach_attempt_token.as_bytes());
717                encoder.put_option_u64(*accept_marker_delivery_seq);
718                encoder.put_option_u64(Some(*participant_id));
719            }
720        },
721        r::ServerValue::ConversationOrderExhausted(value) => {
722            put_order_allocating(value.request(), encoder);
723            encoder.put_u16(value.counter().wire_value());
724            encoder.put_u64(value.high());
725            encoder.put_option_u64(value.next_value());
726            encoder.put_u128(value.order_remaining());
727            encoder.put_u128(value.reserved_claims());
728            encoder.put_u64(r::ConversationOrderExhausted::REQUIRED_MAJORS);
729            encoder.put_u128(value.resulting_order_remaining());
730            encoder.put_u128(value.resulting_reserved_claims());
731        }
732        r::ServerValue::ParticipantUnknown(value) => {
733            put_participant_reference(&value.request, encoder);
734        }
735        r::ServerValue::NoBinding(value) => put_binding_required(&value.request, encoder),
736        r::ServerValue::StaleAuthority(value) => put_stale_authority(value, encoder),
737        r::ServerValue::Retired(value) => match value {
738            r::Retired::Enrollment {
739                request,
740                participant_id,
741                retired_generation,
742            } => {
743                put_enrollment(request, encoder);
744                encoder.put_u64(*participant_id);
745                encoder.put_generation(*retired_generation);
746            }
747            r::Retired::Participant {
748                request,
749                retired_generation,
750            } => {
751                put_participant_reference(request, encoder);
752                encoder.put_generation(*retired_generation);
753            }
754        },
755        r::ServerValue::MarkerClosureCapacityExceeded(value) => {
756            put_closure_checked(&value.request, encoder);
757            let scope = match value.reason {
758                c::ClosureRefusalReason::Capacity(_) => t::ClosureScope::Capacity,
759                c::ClosureRefusalReason::RecoveryFence => t::ClosureScope::RecoveryFence,
760                c::ClosureRefusalReason::DeliveredMarkerAwaitingAck => {
761                    t::ClosureScope::DeliveredMarkerAwaitingAck
762                }
763                c::ClosureRefusalReason::EpisodeChurnLimit => t::ClosureScope::EpisodeChurnLimit,
764            };
765            encoder.put_u16(scope.wire_value());
766            put_closure_snapshot(value.snapshot, encoder);
767            if let c::ClosureRefusalReason::Capacity(reason) = value.reason {
768                encoder.put_u16(t::ResourceDimensionTag::from(reason.dimension).wire_value());
769                encoder.put_u128(reason.required);
770                encoder.put_u128(reason.limit);
771            }
772        }
773        r::ServerValue::EnrollBound(value) => put_enroll_bound(value, encoder),
774        r::ServerValue::EnrollmentKnown(value) => {
775            encoder.put_u64(value.conversation_id);
776            encoder.put_fixed(value.token.as_bytes());
777            encoder.put_u64(value.participant_id);
778            encoder.put_generation(value.current_generation);
779        }
780        r::ServerValue::ReceiptExpired(value) => put_receipt_expired(value, encoder),
781        r::ServerValue::ReceiptCapacityExceeded(value) => {
782            put_receipt_capacity(value, encoder);
783        }
784        r::ServerValue::IdentityCapacityExceeded(value) => {
785            put_enrollment(&value.request, encoder);
786            encoder.put_u16(value.scope.wire_value());
787            encoder.put_u64(value.limit);
788            encoder.put_u64(value.occupied);
789            encoder.put_u64(r::IdentityCapacityExceeded::REQUESTED);
790        }
791        r::ServerValue::ObserverBackpressure(value) => put_observer_backpressure(value, encoder),
792        r::ServerValue::ConversationSequenceExhausted(value) => {
793            put_sequence_allocating(&value.request, encoder);
794            put_sequence_budget(value.sequence_budget, encoder);
795        }
796        r::ServerValue::AttachBound(value) => put_attach_bound(value, encoder),
797        r::ServerValue::StaleOrUnknownReceipt(value) => {
798            encoder.put_u64(value.conversation_id);
799            encoder.put_fixed(value.token.as_bytes());
800            encoder.put_u64(value.participant_id);
801            encoder.put_generation(value.presented_generation);
802            encoder.put_option_u64(value.presented_marker_delivery_seq);
803            encoder.put_generation(value.current_generation);
804        }
805        r::ServerValue::MarkerNotDelivered(value) => {
806            put_marker_proof(&value.request, encoder);
807            encoder.put_u16(value.reason.wire_value());
808            encoder.put_u64(value.expected_marker_delivery_seq);
809        }
810        r::ServerValue::MarkerMismatch(value) => {
811            put_marker_proof(&value.request, encoder);
812            encoder.put_u16(value.mismatch.reason().wire_value());
813            match value.mismatch {
814                r::MarkerMismatchBody::BelowCursor { current_cursor } => {
815                    encoder.put_u64(current_cursor);
816                }
817                r::MarkerMismatchBody::NoMarkerExpected => {}
818                r::MarkerMismatchBody::ExpectedDifferentMarker {
819                    expected_marker_delivery_seq,
820                } => encoder.put_u64(expected_marker_delivery_seq),
821            }
822        }
823        r::ServerValue::Bound(value) | r::ServerValue::UnboundReceipt(value) => {
824            put_receipt_replay(value, encoder);
825        }
826        r::ServerValue::DetachCommitted(value) => {
827            encoder.put_u64(value.conversation_id());
828            encoder.put_u64(value.participant_id());
829            encoder.put_generation(value.capability_generation());
830            encoder.put_fixed(value.detach_attempt_token().as_bytes());
831            encoder.put_binding_epoch(value.committed_binding_epoch());
832            encoder.put_u64(value.detached_delivery_seq());
833        }
834        r::ServerValue::DetachInProgress(value) => {
835            encoder.put_u64(value.conversation_id);
836            encoder.put_u64(value.participant_id);
837            encoder.put_fixed(value.presented_token.as_bytes());
838            encoder.put_generation(value.presented_generation);
839            encoder.put_binding_epoch(value.committed_binding_epoch);
840        }
841        r::ServerValue::AckCommitted(value) => {
842            put_participant_ack(value.request(), encoder);
843            encoder.put_u64(value.current_cursor());
844        }
845        r::ServerValue::AckNoOp(value) => match value {
846            r::AckNoOp::ParticipantAck(request) => {
847                put_participant_ack(request, encoder);
848                encoder.put_u64(value.current_cursor());
849            }
850            r::AckNoOp::MarkerAck(request) => {
851                put_marker_ack(request, encoder);
852                encoder.put_u64(value.current_cursor());
853            }
854        },
855        r::ServerValue::AckGap(value) => {
856            put_participant_ack(value.request(), encoder);
857            encoder.put_u64(value.current_cursor());
858            encoder.put_u16(value.reason().wire_value());
859        }
860        r::ServerValue::AckRegression(value) => {
861            put_participant_ack(value.request(), encoder);
862            encoder.put_u64(value.current_cursor());
863            encoder.put_u16(value.reason().wire_value());
864        }
865        r::ServerValue::LeaveCommitted(value) => {
866            encoder.put_u64(value.conversation_id());
867            encoder.put_fixed(value.leave_attempt_token().as_bytes());
868            encoder.put_u64(value.participant_id());
869            encoder.put_generation(value.presented_generation());
870            encoder.put_generation(value.retired_generation());
871            encoder.put_option_binding_epoch(value.ended_binding_epoch());
872            encoder.put_option_u64(value.prior_terminal_delivery_seq());
873            encoder.put_u64(value.left_delivery_seq());
874        }
875        r::ServerValue::MarkerAckCommitted(value) => {
876            put_marker_ack(value.request(), encoder);
877            encoder.put_u64(value.current_cursor());
878        }
879        r::ServerValue::SettlementAnswer(value) => {
880            encoder.put_u64(value.conversation_id);
881            encoder.put_u64(value.participant_id);
882            encoder.put_fixed(value.record_admission_attempt_token.as_bytes());
883            match value.outcome {
884                r::SettlementOutcome::Committed { delivery_seq } => {
885                    encoder.put_u8(1);
886                    encoder.put_u64(delivery_seq);
887                }
888                r::SettlementOutcome::Withdrawn => encoder.put_u8(2),
889                r::SettlementOutcome::Expired => encoder.put_u8(3),
890                r::SettlementOutcome::NotCommitted => encoder.put_u8(4),
891                r::SettlementOutcome::Unknown => encoder.put_u8(5),
892            }
893        }
894        r::ServerValue::RecordCommitted(value) => {
895            put_record_admission(value.request(), encoder);
896            encoder.put_u64(value.sender_participant_id());
897            encoder.put_u64(value.delivery_seq());
898        }
899        r::ServerValue::RecordTooLarge(value) => {
900            put_record_admission(&value.request, encoder);
901            encoder.put_u16(t::ResourceDimensionTag::from(value.dimension).wire_value());
902            encoder.put_resource_vector(value.encoded_record_charge);
903            encoder.put_resource_vector(value.max_ordinary_record_charge);
904        }
905        r::ServerValue::ObserverRecoveryAccepted(value) => {
906            let count: u64 = value
907                .statuses
908                .len()
909                .try_into()
910                .map_err(|_| CodecError::LengthOverflow)?;
911            encoder.put_u64(count);
912            for status in &value.statuses {
913                encoder.put_u64(status.conversation_id);
914                encoder.put_u64(status.refused_epoch);
915                encoder.put_u64(status.current_observer_progress);
916                encoder.put_bool(status.armed);
917                encoder.put_bool(status.progressed);
918            }
919        }
920        r::ServerValue::InvalidObserverEpoch(value) => {
921            encoder.put_u64(0);
922            encoder.put_u16(value.reason().wire_value());
923            match value {
924                r::InvalidObserverEpoch::ConversationUnknown {
925                    conversation_id,
926                    presented_epoch,
927                } => {
928                    encoder.put_u64(*conversation_id);
929                    encoder.put_u64(*presented_epoch);
930                    encoder.put_option_u64(None);
931                }
932                r::InvalidObserverEpoch::EpochAhead {
933                    conversation_id,
934                    presented_epoch,
935                    current_observer_progress,
936                } => {
937                    encoder.put_u64(*conversation_id);
938                    encoder.put_u64(*presented_epoch);
939                    encoder.put_option_u64(Some(*current_observer_progress));
940                }
941            }
942        }
943        r::ServerValue::InvalidObserverEpochList(value) => {
944            encoder.put_u64(0);
945            encoder.put_u16(value.reason().wire_value());
946            match value {
947                r::InvalidObserverEpochList::TooManyEntries {
948                    presented_entries,
949                    max_entries,
950                } => {
951                    encoder.put_u64(*presented_entries);
952                    encoder.put_u64(*max_entries);
953                }
954                r::InvalidObserverEpochList::DuplicateConversation {
955                    conversation_id,
956                    first_index,
957                    duplicate_index,
958                } => {
959                    encoder.put_u64(*conversation_id);
960                    encoder.put_u64(*first_index);
961                    encoder.put_u64(*duplicate_index);
962                }
963            }
964        }
965        r::ServerValue::MarkerSettlementBackpressure(value) => match value {
966            r::MarkerSettlementBackpressure::CredentialAttach {
967                conversation_id,
968                refused_epoch,
969            }
970            | r::MarkerSettlementBackpressure::Detach {
971                conversation_id,
972                refused_epoch,
973            } => {
974                encoder.put_u64(*conversation_id);
975                encoder.put_u64(*refused_epoch);
976            }
977        },
978        r::ServerValue::EnrollmentSettlementBackpressure(value) => {
979            encoder.put_u64(value.conversation_id);
980        }
981        r::ServerValue::RecordAdmissionProtocolFault(value) => {
982            put_record_admission(&value.request, encoder);
983            encoder.put_u16(value.class.tag().wire_value());
984        }
985        r::ServerValue::WriteOutcomeUnknown(value) => put_write_outcome_unknown(value, encoder),
986    }
987    Ok(())
988}
989
990fn put_write_outcome_unknown(value: &r::WriteOutcomeUnknown, encoder: &mut Encoder) {
991    match value {
992        r::WriteOutcomeUnknown::Enrollment { request } => put_enrollment(request, encoder),
993        r::WriteOutcomeUnknown::CredentialAttach { request } => put_attach(request, encoder),
994        r::WriteOutcomeUnknown::Detach { request } => put_detach(request, encoder),
995        r::WriteOutcomeUnknown::Leave { request } => put_leave(request, encoder),
996        r::WriteOutcomeUnknown::RecordAdmission { request } => {
997            put_record_admission(request, encoder);
998        }
999    }
1000}
1001
1002fn put_stale_authority(value: &r::StaleAuthority, encoder: &mut Encoder) {
1003    match value {
1004        r::StaleAuthority::Live {
1005            request,
1006            current_generation,
1007        } => {
1008            match request {
1009                r::CommonStaleAuthorityEnvelope::CredentialAttach(value) => {
1010                    put_attach(value, encoder);
1011                }
1012                r::CommonStaleAuthorityEnvelope::ParticipantAck(value) => {
1013                    put_participant_ack(value, encoder);
1014                }
1015                r::CommonStaleAuthorityEnvelope::MarkerAck(value) => {
1016                    put_marker_ack(value, encoder);
1017                }
1018                r::CommonStaleAuthorityEnvelope::RecordAdmission(value) => {
1019                    put_record_admission(value, encoder);
1020                }
1021            }
1022            encoder.put_generation(*current_generation);
1023        }
1024        r::StaleAuthority::Detach(value) => {
1025            encoder.put_u16(value.authority_state_tag().wire_value());
1026            match value {
1027                r::DetachStaleAuthority::Live {
1028                    conversation_id,
1029                    participant_id,
1030                    capability_generation,
1031                    detach_attempt_token,
1032                    current_generation,
1033                } => {
1034                    encoder.put_u64(*conversation_id);
1035                    encoder.put_u64(*participant_id);
1036                    encoder.put_generation(*capability_generation);
1037                    encoder.put_fixed(detach_attempt_token.as_bytes());
1038                    encoder.put_generation(*current_generation);
1039                }
1040                r::DetachStaleAuthority::TerminalizedDetachCell(value) => {
1041                    encoder.put_u64(value.conversation_id());
1042                    encoder.put_u64(value.participant_id());
1043                    encoder.put_generation(value.capability_generation());
1044                    encoder.put_fixed(value.detach_attempt_token().as_bytes());
1045                    encoder.put_generation(value.current_generation());
1046                    encoder.put_binding_epoch(value.committed_binding_epoch());
1047                    encoder.put_u16(value.binding_state().tag().wire_value());
1048                    if let r::BindingStateView::Bound {
1049                        current_binding_epoch,
1050                    } = value.binding_state()
1051                    {
1052                        encoder.put_binding_epoch(current_binding_epoch);
1053                    }
1054                }
1055            }
1056        }
1057        r::StaleAuthority::Leave(value) => {
1058            encoder.put_u16(value.authority_state_tag().wire_value());
1059            match value {
1060                r::LeaveStaleAuthority::Live {
1061                    conversation_id,
1062                    participant_id,
1063                    presented_generation,
1064                    leave_attempt_token,
1065                    current_generation,
1066                } => {
1067                    encoder.put_u64(*conversation_id);
1068                    encoder.put_u64(*participant_id);
1069                    encoder.put_generation(*presented_generation);
1070                    encoder.put_fixed(leave_attempt_token.as_bytes());
1071                    encoder.put_generation(*current_generation);
1072                }
1073                r::LeaveStaleAuthority::CommittedLeaveTombstone {
1074                    conversation_id,
1075                    participant_id,
1076                    presented_generation,
1077                    leave_attempt_token,
1078                    retired_generation,
1079                } => {
1080                    encoder.put_u64(*conversation_id);
1081                    encoder.put_u64(*participant_id);
1082                    encoder.put_generation(*presented_generation);
1083                    encoder.put_fixed(leave_attempt_token.as_bytes());
1084                    encoder.put_generation(*retired_generation);
1085                }
1086            }
1087        }
1088    }
1089}
1090
1091fn put_receipt_expired(value: &r::ReceiptExpired, encoder: &mut Encoder) {
1092    match value {
1093        r::ReceiptExpired::Enrollment {
1094            conversation_id,
1095            token,
1096            participant_id,
1097            result_generation,
1098            current_generation,
1099            reason,
1100        } => {
1101            encoder.put_u64(*conversation_id);
1102            encoder.put_fixed(token.as_bytes());
1103            encoder.put_u64(*participant_id);
1104            encoder.put_option_generation(None);
1105            encoder.put_generation(*result_generation);
1106            encoder.put_generation(*current_generation);
1107            encoder.put_u16(reason.wire_value());
1108        }
1109        r::ReceiptExpired::CredentialAttach {
1110            conversation_id,
1111            token,
1112            participant_id,
1113            presented_generation,
1114            presented_marker_delivery_seq,
1115            result_generation,
1116            current_generation,
1117            reason,
1118        } => {
1119            encoder.put_u64(*conversation_id);
1120            encoder.put_fixed(token.as_bytes());
1121            encoder.put_u64(*participant_id);
1122            encoder.put_option_generation(Some(*presented_generation));
1123            encoder.put_option_u64(*presented_marker_delivery_seq);
1124            encoder.put_generation(*result_generation);
1125            encoder.put_generation(*current_generation);
1126            encoder.put_u16(reason.wire_value());
1127        }
1128    }
1129}
1130
1131fn put_receipt_capacity(value: &r::ReceiptCapacityExceeded, encoder: &mut Encoder) {
1132    match value {
1133        r::ReceiptCapacityExceeded::Enrollment {
1134            request,
1135            scope,
1136            limit,
1137            occupied,
1138        } => {
1139            put_enrollment(request, encoder);
1140            encoder.put_u16(scope.wire_scope().wire_value());
1141            encoder.put_u64(*limit);
1142            encoder.put_u64(*occupied);
1143            encoder.put_u64(r::ReceiptCapacityExceeded::REQUESTED);
1144        }
1145        r::ReceiptCapacityExceeded::CredentialAttach {
1146            request,
1147            scope,
1148            limit,
1149            occupied,
1150        } => {
1151            put_attach(request, encoder);
1152            encoder.put_u16(scope.wire_value());
1153            encoder.put_u64(*limit);
1154            encoder.put_u64(*occupied);
1155            encoder.put_u64(r::ReceiptCapacityExceeded::REQUESTED);
1156        }
1157    }
1158}
1159
1160fn put_observer_backpressure(value: &r::ObserverBackpressure, encoder: &mut Encoder) {
1161    match value {
1162        r::ObserverBackpressure::Enrollment { request, state } => {
1163            put_enrollment(request, encoder);
1164            put_backpressure_state(*state, encoder);
1165        }
1166        r::ObserverBackpressure::CredentialAttach { request, state } => {
1167            put_attach(request, encoder);
1168            put_backpressure_state(*state, encoder);
1169        }
1170        r::ObserverBackpressure::Detach {
1171            request,
1172            committed_binding_epoch,
1173            state,
1174        } => {
1175            put_detach(request, encoder);
1176            encoder.put_binding_epoch(*committed_binding_epoch);
1177            put_backpressure_state(*state, encoder);
1178        }
1179        r::ObserverBackpressure::Leave {
1180            request,
1181            state,
1182            prior_terminal_cell_exists,
1183        } => {
1184            put_leave(request, encoder);
1185            put_backpressure_state(*state, encoder);
1186            encoder.put_bool(*prior_terminal_cell_exists);
1187        }
1188        r::ObserverBackpressure::RecordAdmission { request, state } => {
1189            put_record_admission(request, encoder);
1190            put_backpressure_state(*state, encoder);
1191        }
1192    }
1193}
1194
1195fn put_backpressure_state(value: r::ObserverBackpressureState, encoder: &mut Encoder) {
1196    encoder.put_u64(value.backpressure_epoch());
1197    encoder.put_u64(value.observer_progress());
1198}
1199
1200fn put_receipt_replay(value: &r::ReceiptReplay, encoder: &mut Encoder) {
1201    match value {
1202        r::ReceiptReplay::Enrollment(value) => {
1203            encoder.put_u64(value.conversation_id());
1204            encoder.put_fixed(value.token().as_bytes());
1205            encoder.put_u64(value.participant_id());
1206            encoder.put_option_generation(None);
1207            encoder.put_generation(value.capability_generation());
1208            encoder.put_fixed(value.attach_secret().as_bytes());
1209            encoder.put_binding_epoch(value.origin_binding_epoch());
1210            encoder.put_u64(value.persisted_cursor());
1211            encoder.put_option_u64(None);
1212            encoder.put_u128(value.receipt_expires_at());
1213            encoder.put_u128(value.provenance_expires_at());
1214        }
1215        r::ReceiptReplay::CredentialAttach(value) => {
1216            encoder.put_u64(value.conversation_id());
1217            encoder.put_fixed(value.token().as_bytes());
1218            encoder.put_u64(value.participant_id());
1219            encoder.put_option_generation(Some(value.request_generation()));
1220            encoder.put_generation(value.capability_generation());
1221            encoder.put_fixed(value.attach_secret().as_bytes());
1222            encoder.put_binding_epoch(value.origin_binding_epoch());
1223            encoder.put_u64(value.persisted_cursor());
1224            encoder.put_option_u64(value.accepted_marker_delivery_seq());
1225            encoder.put_u128(value.receipt_expires_at());
1226            encoder.put_u128(value.provenance_expires_at());
1227        }
1228    }
1229}
1230
1231/// Returns whether a body is prefixed by its originating-request selector.
1232///
1233/// Exactly the rows [`origin_is_valid`] admits some origin for, stated as that
1234/// complement rather than as a numeric window: the old `0x0101..=0x0120` range
1235/// was contiguous only until the settlement rows were appended ABOVE the
1236/// origin-free observer-recovery block (`0x0121..=0x0124`), and a window cannot
1237/// express that shape without silently dropping a row's origin prefix.
1238const fn carries_origin(discriminant: t::ServerDiscriminant) -> bool {
1239    use t::ServerDiscriminant as D;
1240
1241    !matches!(
1242        discriminant,
1243        D::ParticipantTransportRejected
1244            | D::ObserverRecoveryAccepted
1245            | D::InvalidObserverEpoch
1246            | D::InvalidObserverEpochList
1247            | D::ObserverRecoveryConnectionCapacityExceeded
1248    )
1249}
1250
1251const fn origin_is_valid(
1252    discriminant: t::ServerDiscriminant,
1253    origin: t::ClientDiscriminant,
1254) -> bool {
1255    use t::ClientDiscriminant as O;
1256    use t::ServerDiscriminant as D;
1257
1258    match discriminant {
1259        D::AttemptTokenBodyConflict => matches!(
1260            origin,
1261            O::CredentialAttachRequest | O::LeaveRequest | O::RecordAdmission
1262        ),
1263        D::ConnectionConversationCapacityExceeded => {
1264            !matches!(origin, O::ObserverRecoveryHandshake)
1265        }
1266        D::ConnectionConversationBindingOccupied => {
1267            matches!(origin, O::EnrollmentRequest | O::CredentialAttachRequest)
1268        }
1269        D::ConversationOrderExhausted => matches!(
1270            origin,
1271            O::EnrollmentRequest | O::CredentialAttachRequest | O::RecordAdmission
1272        ),
1273        D::ParticipantUnknown => {
1274            !matches!(origin, O::EnrollmentRequest | O::ObserverRecoveryHandshake)
1275        }
1276        D::NoBinding => !matches!(
1277            origin,
1278            O::EnrollmentRequest | O::CredentialAttachRequest | O::ObserverRecoveryHandshake
1279        ),
1280        D::StaleAuthority => !matches!(origin, O::EnrollmentRequest | O::ObserverRecoveryHandshake),
1281        D::Retired => !matches!(origin, O::ObserverRecoveryHandshake),
1282        D::MarkerClosureCapacityExceeded => matches!(
1283            origin,
1284            O::EnrollmentRequest
1285                | O::CredentialAttachRequest
1286                | O::LeaveRequest
1287                | O::RecordAdmission
1288        ),
1289        D::EnrollBound | D::EnrollmentKnown | D::IdentityCapacityExceeded => {
1290            matches!(origin, O::EnrollmentRequest)
1291        }
1292        D::ReceiptExpired | D::ReceiptCapacityExceeded | D::Bound | D::UnboundReceipt => {
1293            matches!(origin, O::EnrollmentRequest | O::CredentialAttachRequest)
1294        }
1295        D::ObserverBackpressure | D::WriteOutcomeUnknown => matches!(
1296            origin,
1297            O::EnrollmentRequest
1298                | O::CredentialAttachRequest
1299                | O::DetachRequest
1300                | O::LeaveRequest
1301                | O::RecordAdmission
1302        ),
1303        D::ConversationSequenceExhausted => matches!(
1304            origin,
1305            O::EnrollmentRequest | O::CredentialAttachRequest | O::RecordAdmission
1306        ),
1307        D::AttachBound | D::StaleOrUnknownReceipt => {
1308            matches!(origin, O::CredentialAttachRequest)
1309        }
1310        D::MarkerNotDelivered | D::MarkerMismatch => {
1311            matches!(origin, O::CredentialAttachRequest | O::MarkerAck)
1312        }
1313        D::DetachCommitted | D::DetachInProgress => matches!(origin, O::DetachRequest),
1314        D::AckCommitted | D::AckGap | D::AckRegression => matches!(origin, O::ParticipantAck),
1315        D::AckNoOp => matches!(origin, O::ParticipantAck | O::MarkerAck),
1316        D::LeaveCommitted => matches!(origin, O::LeaveRequest),
1317        D::MarkerAckCommitted => matches!(origin, O::MarkerAck),
1318        D::SettlementAnswer => matches!(origin, O::SettlementQuery),
1319        D::RecordCommitted | D::RecordTooLarge | D::RecordAdmissionProtocolFault => {
1320            matches!(origin, O::RecordAdmission)
1321        }
1322        D::MarkerSettlementBackpressure => {
1323            matches!(origin, O::CredentialAttachRequest | O::DetachRequest)
1324        }
1325        D::EnrollmentSettlementBackpressure => matches!(origin, O::EnrollmentRequest),
1326        D::ParticipantTransportRejected
1327        | D::ObserverRecoveryAccepted
1328        | D::InvalidObserverEpoch
1329        | D::InvalidObserverEpochList
1330        | D::ObserverRecoveryConnectionCapacityExceeded => false,
1331    }
1332}
1333
1334// Decoding is kept below encoding so every selected schema can be compared
1335// field-for-field in one source file.
1336
1337fn take_enrollment(decoder: &mut Decoder<'_>) -> Result<e::EnrollmentEnvelope, CodecError> {
1338    Ok(e::EnrollmentEnvelope {
1339        conversation_id: decoder.take_u64()?,
1340        enrollment_token: EnrollmentToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1341    })
1342}
1343
1344fn take_attach(decoder: &mut Decoder<'_>) -> Result<e::AttachEnvelope, CodecError> {
1345    Ok(e::AttachEnvelope {
1346        conversation_id: decoder.take_u64()?,
1347        participant_id: decoder.take_u64()?,
1348        capability_generation: decoder.take_generation()?,
1349        attach_attempt_token: AttachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1350        accept_marker_delivery_seq: decoder.take_option_u64()?,
1351    })
1352}
1353
1354fn take_detach(decoder: &mut Decoder<'_>) -> Result<e::DetachEnvelope, CodecError> {
1355    Ok(e::DetachEnvelope {
1356        conversation_id: decoder.take_u64()?,
1357        participant_id: decoder.take_u64()?,
1358        capability_generation: decoder.take_generation()?,
1359        detach_attempt_token: DetachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1360    })
1361}
1362
1363fn take_participant_ack(
1364    decoder: &mut Decoder<'_>,
1365) -> Result<e::ParticipantAckEnvelope, CodecError> {
1366    Ok(e::ParticipantAckEnvelope {
1367        conversation_id: decoder.take_u64()?,
1368        participant_id: decoder.take_u64()?,
1369        capability_generation: decoder.take_generation()?,
1370        through_seq: decoder.take_u64()?,
1371    })
1372}
1373
1374fn take_leave(decoder: &mut Decoder<'_>) -> Result<e::LeaveEnvelope, CodecError> {
1375    Ok(e::LeaveEnvelope {
1376        conversation_id: decoder.take_u64()?,
1377        participant_id: decoder.take_u64()?,
1378        capability_generation: decoder.take_generation()?,
1379        leave_attempt_token: LeaveAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1380    })
1381}
1382
1383fn take_marker_ack(decoder: &mut Decoder<'_>) -> Result<e::MarkerAckEnvelope, CodecError> {
1384    Ok(e::MarkerAckEnvelope {
1385        conversation_id: decoder.take_u64()?,
1386        participant_id: decoder.take_u64()?,
1387        capability_generation: decoder.take_generation()?,
1388        marker_delivery_seq: decoder.take_u64()?,
1389    })
1390}
1391
1392fn take_record_admission(
1393    decoder: &mut Decoder<'_>,
1394) -> Result<e::RecordAdmissionEnvelope, CodecError> {
1395    Ok(e::RecordAdmissionEnvelope {
1396        conversation_id: decoder.take_u64()?,
1397        participant_id: decoder.take_u64()?,
1398        capability_generation: decoder.take_generation()?,
1399        record_admission_attempt_token: RecordAdmissionAttemptToken::new(
1400            decoder.take_fixed::<TOKEN_LEN>()?,
1401        ),
1402    })
1403}
1404
1405fn take_response_envelope(
1406    origin: t::ClientDiscriminant,
1407    decoder: &mut Decoder<'_>,
1408) -> Result<e::ResponseEnvelope, CodecError> {
1409    match origin {
1410        t::ClientDiscriminant::EnrollmentRequest => {
1411            take_enrollment(decoder).map(e::ResponseEnvelope::Enrollment)
1412        }
1413        t::ClientDiscriminant::CredentialAttachRequest => {
1414            take_attach(decoder).map(e::ResponseEnvelope::CredentialAttach)
1415        }
1416        t::ClientDiscriminant::DetachRequest => {
1417            take_detach(decoder).map(e::ResponseEnvelope::Detach)
1418        }
1419        t::ClientDiscriminant::ParticipantAck => {
1420            take_participant_ack(decoder).map(e::ResponseEnvelope::ParticipantAck)
1421        }
1422        t::ClientDiscriminant::LeaveRequest => take_leave(decoder).map(e::ResponseEnvelope::Leave),
1423        t::ClientDiscriminant::MarkerAck => {
1424            take_marker_ack(decoder).map(e::ResponseEnvelope::MarkerAck)
1425        }
1426        t::ClientDiscriminant::RecordAdmission => {
1427            take_record_admission(decoder).map(e::ResponseEnvelope::RecordAdmission)
1428        }
1429        t::ClientDiscriminant::ObserverRecoveryHandshake
1430        | t::ClientDiscriminant::SettlementQuery => Err(decode_error(t::DecodeClass::InvalidField)),
1431    }
1432}
1433
1434fn take_participant_reference(
1435    origin: t::ClientDiscriminant,
1436    decoder: &mut Decoder<'_>,
1437) -> Result<r::ParticipantReferenceEnvelope, CodecError> {
1438    match origin {
1439        t::ClientDiscriminant::CredentialAttachRequest => {
1440            take_attach(decoder).map(r::ParticipantReferenceEnvelope::CredentialAttach)
1441        }
1442        t::ClientDiscriminant::DetachRequest => {
1443            take_detach(decoder).map(r::ParticipantReferenceEnvelope::Detach)
1444        }
1445        t::ClientDiscriminant::ParticipantAck => {
1446            take_participant_ack(decoder).map(r::ParticipantReferenceEnvelope::ParticipantAck)
1447        }
1448        t::ClientDiscriminant::LeaveRequest => {
1449            take_leave(decoder).map(r::ParticipantReferenceEnvelope::Leave)
1450        }
1451        t::ClientDiscriminant::MarkerAck => {
1452            take_marker_ack(decoder).map(r::ParticipantReferenceEnvelope::MarkerAck)
1453        }
1454        t::ClientDiscriminant::RecordAdmission => {
1455            take_record_admission(decoder).map(r::ParticipantReferenceEnvelope::RecordAdmission)
1456        }
1457        t::ClientDiscriminant::EnrollmentRequest
1458        | t::ClientDiscriminant::ObserverRecoveryHandshake
1459        | t::ClientDiscriminant::SettlementQuery => Err(decode_error(t::DecodeClass::InvalidField)),
1460    }
1461}
1462
1463fn take_binding_required(
1464    origin: t::ClientDiscriminant,
1465    decoder: &mut Decoder<'_>,
1466) -> Result<r::BindingRequiredEnvelope, CodecError> {
1467    match origin {
1468        t::ClientDiscriminant::DetachRequest => {
1469            take_detach(decoder).map(r::BindingRequiredEnvelope::Detach)
1470        }
1471        t::ClientDiscriminant::ParticipantAck => {
1472            take_participant_ack(decoder).map(r::BindingRequiredEnvelope::ParticipantAck)
1473        }
1474        t::ClientDiscriminant::LeaveRequest => {
1475            take_leave(decoder).map(r::BindingRequiredEnvelope::Leave)
1476        }
1477        t::ClientDiscriminant::MarkerAck => {
1478            take_marker_ack(decoder).map(r::BindingRequiredEnvelope::MarkerAck)
1479        }
1480        t::ClientDiscriminant::RecordAdmission => {
1481            take_record_admission(decoder).map(r::BindingRequiredEnvelope::RecordAdmission)
1482        }
1483        t::ClientDiscriminant::EnrollmentRequest
1484        | t::ClientDiscriminant::CredentialAttachRequest
1485        | t::ClientDiscriminant::ObserverRecoveryHandshake
1486        | t::ClientDiscriminant::SettlementQuery => Err(decode_error(t::DecodeClass::InvalidField)),
1487    }
1488}
1489
1490fn take_order_allocating(
1491    origin: t::ClientDiscriminant,
1492    decoder: &mut Decoder<'_>,
1493) -> Result<r::OrderAllocatingEnvelope, CodecError> {
1494    match origin {
1495        t::ClientDiscriminant::EnrollmentRequest => {
1496            take_enrollment(decoder).map(r::OrderAllocatingEnvelope::Enrollment)
1497        }
1498        t::ClientDiscriminant::CredentialAttachRequest => {
1499            take_attach(decoder).map(r::OrderAllocatingEnvelope::CredentialAttach)
1500        }
1501        t::ClientDiscriminant::RecordAdmission => {
1502            take_record_admission(decoder).map(r::OrderAllocatingEnvelope::RecordAdmission)
1503        }
1504        _ => Err(decode_error(t::DecodeClass::InvalidField)),
1505    }
1506}
1507
1508fn take_closure_checked(
1509    origin: t::ClientDiscriminant,
1510    decoder: &mut Decoder<'_>,
1511) -> Result<c::ClosureCheckedEnvelope, CodecError> {
1512    match origin {
1513        t::ClientDiscriminant::EnrollmentRequest => {
1514            take_enrollment(decoder).map(c::ClosureCheckedEnvelope::Enrollment)
1515        }
1516        t::ClientDiscriminant::CredentialAttachRequest => {
1517            take_attach(decoder).map(c::ClosureCheckedEnvelope::CredentialAttach)
1518        }
1519        t::ClientDiscriminant::LeaveRequest => {
1520            take_leave(decoder).map(c::ClosureCheckedEnvelope::Leave)
1521        }
1522        t::ClientDiscriminant::RecordAdmission => {
1523            take_record_admission(decoder).map(c::ClosureCheckedEnvelope::RecordAdmission)
1524        }
1525        _ => Err(decode_error(t::DecodeClass::InvalidField)),
1526    }
1527}
1528
1529fn take_sequence_allocating(
1530    origin: t::ClientDiscriminant,
1531    decoder: &mut Decoder<'_>,
1532) -> Result<r::SequenceAllocatingEnvelope, CodecError> {
1533    match origin {
1534        t::ClientDiscriminant::EnrollmentRequest => {
1535            take_enrollment(decoder).map(r::SequenceAllocatingEnvelope::Enrollment)
1536        }
1537        t::ClientDiscriminant::CredentialAttachRequest => {
1538            take_attach(decoder).map(r::SequenceAllocatingEnvelope::CredentialAttach)
1539        }
1540        t::ClientDiscriminant::RecordAdmission => {
1541            take_record_admission(decoder).map(r::SequenceAllocatingEnvelope::RecordAdmission)
1542        }
1543        _ => Err(decode_error(t::DecodeClass::InvalidField)),
1544    }
1545}
1546
1547fn take_marker_proof(
1548    origin: t::ClientDiscriminant,
1549    decoder: &mut Decoder<'_>,
1550) -> Result<r::MarkerProofRequest, CodecError> {
1551    match origin {
1552        t::ClientDiscriminant::CredentialAttachRequest => Ok(
1553            r::MarkerProofRequest::CredentialAttach(r::AttachMarkerProof {
1554                conversation_id: decoder.take_u64()?,
1555                token: AttachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1556                participant_id: decoder.take_u64()?,
1557                capability_generation: decoder.take_generation()?,
1558                requested_marker_delivery_seq: decoder.take_u64()?,
1559            }),
1560        ),
1561        t::ClientDiscriminant::MarkerAck => {
1562            Ok(r::MarkerProofRequest::MarkerAck(r::MarkerAckProof {
1563                conversation_id: decoder.take_u64()?,
1564                participant_id: decoder.take_u64()?,
1565                capability_generation: decoder.take_generation()?,
1566                requested_marker_delivery_seq: decoder.take_u64()?,
1567            }))
1568        }
1569        _ => Err(decode_error(t::DecodeClass::InvalidField)),
1570    }
1571}
1572
1573fn take_repayment_edge(decoder: &mut Decoder<'_>) -> Result<c::RepaymentEdge, CodecError> {
1574    let tag = t::RepaymentEdgeTag::try_from(decoder.take_u16()?)
1575        .map_err(|_| decode_error(t::DecodeClass::InvalidField))?;
1576    match tag {
1577        t::RepaymentEdgeTag::None => Ok(c::RepaymentEdge::None),
1578        t::RepaymentEdgeTag::ObserverProjection => Ok(c::RepaymentEdge::ObserverProjection {
1579            through_seq: decoder.take_u64()?,
1580        }),
1581        t::RepaymentEdgeTag::PhysicalCompaction => Ok(c::RepaymentEdge::PhysicalCompaction {
1582            from_floor: decoder.take_u64()?,
1583            through_seq: decoder.take_u64()?,
1584        }),
1585        t::RepaymentEdgeTag::MarkerDelivery => Ok(c::RepaymentEdge::MarkerDelivery {
1586            participant_id: decoder.take_u64()?,
1587            binding_epoch: decoder.take_binding_epoch()?,
1588            marker_delivery_seq: decoder.take_u64()?,
1589        }),
1590        t::RepaymentEdgeTag::ParticipantCursorProgress => Ok(
1591            c::RepaymentEdge::ParticipantCursorProgress(c::ParticipantCursorProgressEdge {
1592                participant_id: decoder.take_u64()?,
1593                binding_epoch: decoder.take_binding_epoch()?,
1594                through_seq: decoder.take_u64()?,
1595                marker_delivery_seq: decoder.take_option_u64()?,
1596            }),
1597        ),
1598        t::RepaymentEdgeTag::DetachedCredentialRecovery => {
1599            Ok(c::RepaymentEdge::DetachedCredentialRecovery {
1600                participant_id: decoder.take_u64()?,
1601                marker_delivery_seq: decoder.take_u64()?,
1602                prior_binding_epoch: decoder.take_binding_epoch()?,
1603            })
1604        }
1605        t::RepaymentEdgeTag::DetachedMarkerRelease => Ok(c::RepaymentEdge::DetachedMarkerRelease {
1606            participant_id: decoder.take_u64()?,
1607            marker_delivery_seq: decoder.take_u64()?,
1608            last_dead_binding_epoch: decoder.take_binding_epoch()?,
1609        }),
1610        t::RepaymentEdgeTag::DetachedCursorRelease => Ok(c::RepaymentEdge::DetachedCursorRelease {
1611            participant_id: decoder.take_u64()?,
1612            last_dead_binding_epoch: decoder.take_binding_epoch()?,
1613        }),
1614    }
1615}
1616
1617fn take_closure_snapshot(decoder: &mut Decoder<'_>) -> Result<c::ClosureSnapshot, CodecError> {
1618    Ok(c::ClosureSnapshot {
1619        marker_capacity_credits: decoder.take_u64()?,
1620        marker_anchors: decoder.take_u64()?,
1621        entry_debt: decoder.take_u64()?,
1622        byte_debt: decoder.take_u64()?,
1623        repayment_edge: take_repayment_edge(decoder)?,
1624        edge_sequence_claims: decoder.take_u64()?,
1625        edge_order_position_claims: decoder.take_u64()?,
1626        edge_k_remaining: decoder.take_resource_vector()?,
1627        k_headroom: decoder.take_wide_resource_vector()?,
1628        episode_churn_used: decoder.take_u64()?,
1629        delta_cycles: decoder.take_u64()?,
1630        episode_churn_limit: decoder.take_u64()?,
1631    })
1632}
1633
1634fn take_sequence_budget(decoder: &mut Decoder<'_>) -> Result<super::SequenceBudget, CodecError> {
1635    Ok(super::SequenceBudget {
1636        high_watermark: decoder.take_u64()?,
1637        remaining: decoder.take_u64()?,
1638        e: decoder.take_u64()?,
1639        t: decoder.take_u64()?,
1640        m: decoder.take_u64()?,
1641        rs: decoder.take_u64()?,
1642        rt: decoder.take_u64()?,
1643        l_times_t: decoder.take_u128()?,
1644        l_times_rt: decoder.take_u128()?,
1645        l_other_times_e: decoder.take_u128()?,
1646    })
1647}
1648
1649fn required_origin(
1650    origin: Option<t::ClientDiscriminant>,
1651) -> Result<t::ClientDiscriminant, CodecError> {
1652    origin.ok_or_else(|| decode_error(t::DecodeClass::InvalidField))
1653}
1654
1655#[allow(clippy::too_many_lines)]
1656fn decode_server_suffix(
1657    discriminant: t::ServerDiscriminant,
1658    origin: Option<t::ClientDiscriminant>,
1659    decoder: &mut Decoder<'_>,
1660) -> Result<r::ServerValue, CodecError> {
1661    use t::ServerDiscriminant as D;
1662
1663    match discriminant {
1664        D::ParticipantTransportRejected => {
1665            let reason = match take_tag::<t::TransportReasonTag>(decoder)? {
1666                t::TransportReasonTag::FrameTooLarge => {
1667                    r::TransportRejectionReason::FrameTooLarge {
1668                        complete_frame_bytes: decoder.take_u64()?,
1669                        max_frame_bytes: decoder.take_u64()?,
1670                    }
1671                }
1672                t::TransportReasonTag::DecodeFailed => {
1673                    let decode_class = take_tag::<t::DecodeClass>(decoder)?;
1674                    r::TransportRejectionReason::DecodeFailed { decode_class }
1675                }
1676                t::TransportReasonTag::UnsupportedVersion => {
1677                    r::TransportRejectionReason::UnsupportedVersion {
1678                        presented_version: decoder.take_protocol_version()?,
1679                        supported_version: decoder.take_protocol_version()?,
1680                    }
1681                }
1682                t::TransportReasonTag::AuthenticationFailed => {
1683                    r::TransportRejectionReason::AuthenticationFailed
1684                }
1685                t::TransportReasonTag::ParticipantCapabilityRequired => {
1686                    let capability = decoder.take_string()?;
1687                    if capability != r::PARTICIPANT_CAPABILITY {
1688                        decoder.invalidate();
1689                    }
1690                    r::TransportRejectionReason::ParticipantCapabilityRequired
1691                }
1692                t::TransportReasonTag::EnrollmentNotPermitted => {
1693                    r::TransportRejectionReason::EnrollmentNotPermitted
1694                }
1695                t::TransportReasonTag::EnrollmentConversationOutOfScope => {
1696                    r::TransportRejectionReason::EnrollmentConversationOutOfScope
1697                }
1698                t::TransportReasonTag::CredentialAttachConversationOutOfScope => {
1699                    r::TransportRejectionReason::CredentialAttachConversationOutOfScope
1700                }
1701                t::TransportReasonTag::AccessRefused => {
1702                    r::TransportRejectionReason::AccessRefused {
1703                        refusal: decoder.take_string()?,
1704                    }
1705                }
1706            };
1707            Ok(r::ServerValue::ParticipantTransportRejected(
1708                r::ParticipantTransportRejected { reason },
1709            ))
1710        }
1711        D::AttemptTokenBodyConflict => {
1712            let origin = required_origin(origin)?;
1713            let token = decoder.take_fixed::<TOKEN_LEN>()?;
1714            let operation = take_tag::<t::AttemptOperation>(decoder)?;
1715            match origin {
1716                t::ClientDiscriminant::CredentialAttachRequest => {
1717                    if operation != t::AttemptOperation::CredentialAttachRequest {
1718                        return Err(decode_error(t::DecodeClass::InvalidField));
1719                    }
1720                    Ok(r::ServerValue::AttemptTokenBodyConflict(
1721                        r::AttemptTokenBodyConflict::CredentialAttach {
1722                            token: AttachAttemptToken::new(token),
1723                            conversation_id: decoder.take_u64()?,
1724                            presented_participant_id: decoder.take_u64()?,
1725                            presented_generation: decoder.take_generation()?,
1726                            presented_marker_delivery_seq: decoder.take_option_u64()?,
1727                            conflict: take_tag::<t::AttemptConflict>(decoder)?,
1728                        },
1729                    ))
1730                }
1731                t::ClientDiscriminant::LeaveRequest => {
1732                    if operation != t::AttemptOperation::LeaveRequest {
1733                        return Err(decode_error(t::DecodeClass::InvalidField));
1734                    }
1735                    let value = r::AttemptTokenBodyConflict::Leave {
1736                        token: LeaveAttemptToken::new(token),
1737                        conversation_id: decoder.take_u64()?,
1738                        presented_participant_id: decoder.take_u64()?,
1739                        presented_generation: decoder.take_generation()?,
1740                    };
1741                    if take_tag::<t::AttemptConflict>(decoder)? != t::AttemptConflict::Generation {
1742                        decoder.invalidate();
1743                    }
1744                    Ok(r::ServerValue::AttemptTokenBodyConflict(value))
1745                }
1746                t::ClientDiscriminant::RecordAdmission => {
1747                    if operation != t::AttemptOperation::RecordAdmission {
1748                        return Err(decode_error(t::DecodeClass::InvalidField));
1749                    }
1750                    Ok(r::ServerValue::AttemptTokenBodyConflict(
1751                        r::AttemptTokenBodyConflict::RecordAdmission {
1752                            token: RecordAdmissionAttemptToken::new(token),
1753                            conversation_id: decoder.take_u64()?,
1754                            presented_participant_id: decoder.take_u64()?,
1755                            presented_generation: decoder.take_generation()?,
1756                        },
1757                    ))
1758                }
1759                _ => Err(decode_error(t::DecodeClass::InvalidField)),
1760            }
1761        }
1762        D::ConnectionConversationCapacityExceeded => {
1763            let origin = required_origin(origin)?;
1764            Ok(r::ServerValue::ConnectionConversationCapacityExceeded(
1765                r::ConnectionConversationCapacityExceeded::SemanticRequest {
1766                    request: take_response_envelope(origin, decoder)?,
1767                    limit: decoder.take_u64()?,
1768                },
1769            ))
1770        }
1771        D::ConnectionConversationBindingOccupied => {
1772            let origin = required_origin(origin)?;
1773            let value = match origin {
1774                t::ClientDiscriminant::EnrollmentRequest => {
1775                    let conversation_id = decoder.take_u64()?;
1776                    let enrollment_token = EnrollmentToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
1777                    if decoder.take_option_u64()?.is_some() {
1778                        decoder.invalidate();
1779                    }
1780                    r::ConnectionConversationBindingOccupied::Enrollment {
1781                        conversation_id,
1782                        enrollment_token,
1783                    }
1784                }
1785                t::ClientDiscriminant::CredentialAttachRequest => {
1786                    let conversation_id = decoder.take_u64()?;
1787                    let participant_id = decoder.take_u64()?;
1788                    let capability_generation = decoder.take_generation()?;
1789                    let attach_attempt_token =
1790                        AttachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
1791                    let accept_marker_delivery_seq = decoder.take_option_u64()?;
1792                    if decoder.take_option_u64()? != Some(participant_id) {
1793                        decoder.invalidate();
1794                    }
1795                    r::ConnectionConversationBindingOccupied::CredentialAttach {
1796                        conversation_id,
1797                        participant_id,
1798                        capability_generation,
1799                        attach_attempt_token,
1800                        accept_marker_delivery_seq,
1801                    }
1802                }
1803                _ => return Err(decode_error(t::DecodeClass::InvalidField)),
1804            };
1805            Ok(r::ServerValue::ConnectionConversationBindingOccupied(value))
1806        }
1807        D::ConversationOrderExhausted => {
1808            let origin = required_origin(origin)?;
1809            let request = take_order_allocating(origin, decoder)?;
1810            let _counter = take_tag::<t::Counter>(decoder)?;
1811            let high = decoder.take_u64()?;
1812            let next_value = decoder.take_option_u64()?;
1813            let order_remaining = decoder.take_u128()?;
1814            let reserved_claims = decoder.take_u128()?;
1815            if decoder.take_u64()? != r::ConversationOrderExhausted::REQUIRED_MAJORS {
1816                decoder.invalidate();
1817            }
1818            let resulting_order_remaining = decoder.take_u128()?;
1819            let resulting_reserved_claims = decoder.take_u128()?;
1820            let value = r::ConversationOrderExhausted::new(
1821                request,
1822                high,
1823                order_remaining,
1824                reserved_claims,
1825                resulting_order_remaining,
1826                resulting_reserved_claims,
1827            );
1828            if next_value != value.next_value() {
1829                decoder.invalidate();
1830            }
1831            Ok(r::ServerValue::ConversationOrderExhausted(
1832                alloc::boxed::Box::new(value),
1833            ))
1834        }
1835        D::ParticipantUnknown => {
1836            let origin = required_origin(origin)?;
1837            Ok(r::ServerValue::ParticipantUnknown(r::ParticipantUnknown {
1838                request: take_participant_reference(origin, decoder)?,
1839            }))
1840        }
1841        D::NoBinding => {
1842            let origin = required_origin(origin)?;
1843            Ok(r::ServerValue::NoBinding(r::NoBinding {
1844                request: take_binding_required(origin, decoder)?,
1845            }))
1846        }
1847        D::StaleAuthority => take_stale_authority(required_origin(origin)?, decoder)
1848            .map(r::ServerValue::StaleAuthority),
1849        D::Retired => {
1850            let origin = required_origin(origin)?;
1851            let value = if origin == t::ClientDiscriminant::EnrollmentRequest {
1852                r::Retired::Enrollment {
1853                    request: take_enrollment(decoder)?,
1854                    participant_id: decoder.take_u64()?,
1855                    retired_generation: decoder.take_generation()?,
1856                }
1857            } else {
1858                r::Retired::Participant {
1859                    request: take_participant_reference(origin, decoder)?,
1860                    retired_generation: decoder.take_generation()?,
1861                }
1862            };
1863            Ok(r::ServerValue::Retired(value))
1864        }
1865        D::MarkerClosureCapacityExceeded => {
1866            let origin = required_origin(origin)?;
1867            let request = take_closure_checked(origin, decoder)?;
1868            let scope = take_tag::<t::ClosureScope>(decoder)?;
1869            let snapshot = take_closure_snapshot(decoder)?;
1870            let reason = match scope {
1871                t::ClosureScope::Capacity => {
1872                    let dimension =
1873                        ResourceDimension::from(take_tag::<t::ResourceDimensionTag>(decoder)?);
1874                    c::ClosureRefusalReason::Capacity(c::ClosureCapacityReason {
1875                        dimension,
1876                        required: decoder.take_u128()?,
1877                        limit: decoder.take_u128()?,
1878                    })
1879                }
1880                t::ClosureScope::RecoveryFence => c::ClosureRefusalReason::RecoveryFence,
1881                t::ClosureScope::DeliveredMarkerAwaitingAck => {
1882                    c::ClosureRefusalReason::DeliveredMarkerAwaitingAck
1883                }
1884                t::ClosureScope::EpisodeChurnLimit => c::ClosureRefusalReason::EpisodeChurnLimit,
1885            };
1886            Ok(r::ServerValue::MarkerClosureCapacityExceeded(
1887                alloc::boxed::Box::new(c::MarkerClosureCapacityExceeded {
1888                    request,
1889                    snapshot,
1890                    reason,
1891                }),
1892            ))
1893        }
1894        D::EnrollBound => take_enroll_bound(decoder).map(r::ServerValue::EnrollBound),
1895        D::EnrollmentKnown => Ok(r::ServerValue::EnrollmentKnown(r::EnrollmentKnown {
1896            conversation_id: decoder.take_u64()?,
1897            token: EnrollmentToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1898            participant_id: decoder.take_u64()?,
1899            current_generation: decoder.take_generation()?,
1900        })),
1901        D::ReceiptExpired => take_receipt_expired(required_origin(origin)?, decoder)
1902            .map(r::ServerValue::ReceiptExpired),
1903        D::ReceiptCapacityExceeded => take_receipt_capacity(required_origin(origin)?, decoder)
1904            .map(r::ServerValue::ReceiptCapacityExceeded),
1905        D::IdentityCapacityExceeded => {
1906            let request = take_enrollment(decoder)?;
1907            let scope = take_tag::<t::IdentityCapacityScope>(decoder)?;
1908            let limit = decoder.take_u64()?;
1909            let occupied = decoder.take_u64()?;
1910            if decoder.take_u64()? != r::IdentityCapacityExceeded::REQUESTED {
1911                decoder.invalidate();
1912            }
1913            Ok(r::ServerValue::IdentityCapacityExceeded(
1914                r::IdentityCapacityExceeded {
1915                    request,
1916                    scope,
1917                    limit,
1918                    occupied,
1919                },
1920            ))
1921        }
1922        D::ObserverBackpressure => take_observer_backpressure(required_origin(origin)?, decoder)
1923            .map(r::ServerValue::ObserverBackpressure),
1924        D::ConversationSequenceExhausted => {
1925            let request = take_sequence_allocating(required_origin(origin)?, decoder)?;
1926            Ok(r::ServerValue::ConversationSequenceExhausted(
1927                alloc::boxed::Box::new(r::ConversationSequenceExhausted {
1928                    request,
1929                    sequence_budget: take_sequence_budget(decoder)?,
1930                }),
1931            ))
1932        }
1933        D::AttachBound => take_attach_bound(decoder).map(r::ServerValue::AttachBound),
1934        D::StaleOrUnknownReceipt => Ok(r::ServerValue::StaleOrUnknownReceipt(
1935            r::StaleOrUnknownReceipt {
1936                conversation_id: decoder.take_u64()?,
1937                token: AttachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
1938                participant_id: decoder.take_u64()?,
1939                presented_generation: decoder.take_generation()?,
1940                presented_marker_delivery_seq: decoder.take_option_u64()?,
1941                current_generation: decoder.take_generation()?,
1942            },
1943        )),
1944        D::MarkerNotDelivered => {
1945            let request = take_marker_proof(required_origin(origin)?, decoder)?;
1946            let reason = take_tag::<t::MarkerNotDeliveredReason>(decoder)?;
1947            Ok(r::ServerValue::MarkerNotDelivered(r::MarkerNotDelivered {
1948                request,
1949                reason,
1950                expected_marker_delivery_seq: decoder.take_u64()?,
1951            }))
1952        }
1953        D::MarkerMismatch => {
1954            let request = take_marker_proof(required_origin(origin)?, decoder)?;
1955            let reason = take_tag::<t::MarkerMismatchReason>(decoder)?;
1956            let mismatch = match reason {
1957                t::MarkerMismatchReason::BelowCursor => r::MarkerMismatchBody::BelowCursor {
1958                    current_cursor: decoder.take_u64()?,
1959                },
1960                t::MarkerMismatchReason::NoMarkerExpected => {
1961                    r::MarkerMismatchBody::NoMarkerExpected
1962                }
1963                t::MarkerMismatchReason::ExpectedDifferentMarker => {
1964                    r::MarkerMismatchBody::ExpectedDifferentMarker {
1965                        expected_marker_delivery_seq: decoder.take_u64()?,
1966                    }
1967                }
1968            };
1969            Ok(r::ServerValue::MarkerMismatch(r::MarkerMismatch {
1970                request,
1971                mismatch,
1972            }))
1973        }
1974        D::Bound => {
1975            take_receipt_replay(required_origin(origin)?, decoder).map(r::ServerValue::Bound)
1976        }
1977        D::UnboundReceipt => take_receipt_replay(required_origin(origin)?, decoder)
1978            .map(r::ServerValue::UnboundReceipt),
1979        D::DetachCommitted => {
1980            let conversation_id = decoder.take_u64()?;
1981            let participant_id = decoder.take_u64()?;
1982            let capability_generation = decoder.take_generation()?;
1983            let detach_attempt_token = DetachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
1984            let committed_binding_epoch = decoder.take_binding_epoch()?;
1985            let detached_delivery_seq = decoder.take_u64()?;
1986            if capability_generation != committed_binding_epoch.capability_generation {
1987                decoder.invalidate();
1988            }
1989            Ok(r::ServerValue::DetachCommitted(r::DetachCommitted::new(
1990                conversation_id,
1991                participant_id,
1992                detach_attempt_token,
1993                committed_binding_epoch,
1994                detached_delivery_seq,
1995            )))
1996        }
1997        D::DetachInProgress => Ok(r::ServerValue::DetachInProgress(r::DetachInProgress {
1998            conversation_id: decoder.take_u64()?,
1999            participant_id: decoder.take_u64()?,
2000            presented_token: DetachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?),
2001            presented_generation: decoder.take_generation()?,
2002            committed_binding_epoch: decoder.take_binding_epoch()?,
2003        })),
2004        D::AckCommitted => {
2005            let request = take_participant_ack(decoder)?;
2006            if decoder.take_u64()? != request.through_seq {
2007                decoder.invalidate();
2008            }
2009            Ok(r::ServerValue::AckCommitted(r::AckCommitted::new(request)))
2010        }
2011        D::AckNoOp => {
2012            take_ack_no_op(required_origin(origin)?, decoder).map(r::ServerValue::AckNoOp)
2013        }
2014        D::AckGap => {
2015            let request = take_participant_ack(decoder)?;
2016            let current_cursor = decoder.take_u64()?;
2017            let _reason = take_tag::<t::AckGapReason>(decoder)?;
2018            r::AckGap::new(request, current_cursor)
2019                .map(r::ServerValue::AckGap)
2020                .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))
2021        }
2022        D::AckRegression => {
2023            let request = take_participant_ack(decoder)?;
2024            let current_cursor = decoder.take_u64()?;
2025            let _reason = take_tag::<t::AckRegressionReason>(decoder)?;
2026            r::AckRegression::new(request, current_cursor)
2027                .map(r::ServerValue::AckRegression)
2028                .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))
2029        }
2030        D::LeaveCommitted => {
2031            let conversation_id = decoder.take_u64()?;
2032            let leave_attempt_token = LeaveAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2033            let participant_id = decoder.take_u64()?;
2034            let presented_generation = decoder.take_generation()?;
2035            let retired_generation = decoder.take_generation()?;
2036            let ended_binding_epoch = decoder.take_option_binding_epoch()?;
2037            let prior_terminal_delivery_seq = decoder.take_option_u64()?;
2038            let left_delivery_seq = decoder.take_u64()?;
2039            if presented_generation != retired_generation {
2040                return Err(decode_error(t::DecodeClass::InvalidField));
2041            }
2042            r::LeaveCommitted::new(
2043                conversation_id,
2044                leave_attempt_token,
2045                participant_id,
2046                retired_generation,
2047                ended_binding_epoch,
2048                prior_terminal_delivery_seq,
2049                left_delivery_seq,
2050            )
2051            .map(r::ServerValue::LeaveCommitted)
2052            .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))
2053        }
2054        D::MarkerAckCommitted => {
2055            let request = take_marker_ack(decoder)?;
2056            if decoder.take_u64()? != request.marker_delivery_seq {
2057                decoder.invalidate();
2058            }
2059            Ok(r::ServerValue::MarkerAckCommitted(
2060                r::MarkerAckCommitted::new(request),
2061            ))
2062        }
2063        D::SettlementAnswer => {
2064            let conversation_id = decoder.take_u64()?;
2065            let participant_id = decoder.take_u64()?;
2066            let record_admission_attempt_token =
2067                RecordAdmissionAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2068            let outcome = match decoder.take_u8()? {
2069                1 => r::SettlementOutcome::Committed {
2070                    delivery_seq: decoder.take_u64()?,
2071                },
2072                2 => r::SettlementOutcome::Withdrawn,
2073                3 => r::SettlementOutcome::Expired,
2074                4 => r::SettlementOutcome::NotCommitted,
2075                5 => r::SettlementOutcome::Unknown,
2076                _ => return Err(decode_error(t::DecodeClass::InvalidField)),
2077            };
2078            Ok(r::ServerValue::SettlementAnswer(r::SettlementAnswer {
2079                conversation_id,
2080                participant_id,
2081                record_admission_attempt_token,
2082                outcome,
2083            }))
2084        }
2085        D::RecordCommitted => {
2086            let request = take_record_admission(decoder)?;
2087            if decoder.take_u64()? != request.participant_id {
2088                decoder.invalidate();
2089            }
2090            let delivery_seq = decoder.take_u64()?;
2091            Ok(r::ServerValue::RecordCommitted(r::RecordCommitted::new(
2092                request,
2093                delivery_seq,
2094            )))
2095        }
2096        D::RecordTooLarge => Ok(r::ServerValue::RecordTooLarge(r::RecordTooLarge {
2097            request: take_record_admission(decoder)?,
2098            dimension: ResourceDimension::from(take_tag::<t::ResourceDimensionTag>(decoder)?),
2099            encoded_record_charge: decoder.take_resource_vector()?,
2100            max_ordinary_record_charge: decoder.take_resource_vector()?,
2101        })),
2102        D::ObserverRecoveryAccepted => {
2103            take_recovery_accepted(decoder).map(r::ServerValue::ObserverRecoveryAccepted)
2104        }
2105        D::InvalidObserverEpoch => {
2106            require_zero_recovery_count(decoder)?;
2107            take_invalid_observer_epoch(decoder).map(r::ServerValue::InvalidObserverEpoch)
2108        }
2109        D::InvalidObserverEpochList => {
2110            require_zero_recovery_count(decoder)?;
2111            take_invalid_observer_epoch_list(decoder).map(r::ServerValue::InvalidObserverEpochList)
2112        }
2113        D::ObserverRecoveryConnectionCapacityExceeded => {
2114            require_zero_recovery_count(decoder)?;
2115            Ok(r::ServerValue::ConnectionConversationCapacityExceeded(
2116                r::ConnectionConversationCapacityExceeded::ObserverRecovery {
2117                    conversation_id: decoder.take_u64()?,
2118                    limit: decoder.take_u64()?,
2119                },
2120            ))
2121        }
2122        D::MarkerSettlementBackpressure => {
2123            let origin = required_origin(origin)?;
2124            let conversation_id = decoder.take_u64()?;
2125            let refused_epoch = decoder.take_u64()?;
2126            let value = match origin {
2127                t::ClientDiscriminant::CredentialAttachRequest => {
2128                    r::MarkerSettlementBackpressure::CredentialAttach {
2129                        conversation_id,
2130                        refused_epoch,
2131                    }
2132                }
2133                t::ClientDiscriminant::DetachRequest => r::MarkerSettlementBackpressure::Detach {
2134                    conversation_id,
2135                    refused_epoch,
2136                },
2137                _ => return Err(decode_error(t::DecodeClass::InvalidField)),
2138            };
2139            Ok(r::ServerValue::MarkerSettlementBackpressure(value))
2140        }
2141        D::EnrollmentSettlementBackpressure => {
2142            required_origin(origin)?;
2143            Ok(r::ServerValue::EnrollmentSettlementBackpressure(
2144                r::EnrollmentSettlementBackpressure {
2145                    conversation_id: decoder.take_u64()?,
2146                },
2147            ))
2148        }
2149        D::RecordAdmissionProtocolFault => Ok(r::ServerValue::RecordAdmissionProtocolFault(
2150            r::RecordAdmissionProtocolFault {
2151                request: take_record_admission(decoder)?,
2152                class: r::RecordAdmissionFaultClass::from(take_tag::<
2153                    t::RecordAdmissionFaultClassTag,
2154                >(decoder)?),
2155            },
2156        )),
2157        D::WriteOutcomeUnknown => take_write_outcome_unknown(required_origin(origin)?, decoder)
2158            .map(r::ServerValue::WriteOutcomeUnknown),
2159    }
2160}
2161
2162fn take_write_outcome_unknown(
2163    origin: t::ClientDiscriminant,
2164    decoder: &mut Decoder<'_>,
2165) -> Result<r::WriteOutcomeUnknown, CodecError> {
2166    match origin {
2167        t::ClientDiscriminant::EnrollmentRequest => Ok(r::WriteOutcomeUnknown::Enrollment {
2168            request: take_enrollment(decoder)?,
2169        }),
2170        t::ClientDiscriminant::CredentialAttachRequest => {
2171            Ok(r::WriteOutcomeUnknown::CredentialAttach {
2172                request: take_attach(decoder)?,
2173            })
2174        }
2175        t::ClientDiscriminant::DetachRequest => Ok(r::WriteOutcomeUnknown::Detach {
2176            request: take_detach(decoder)?,
2177        }),
2178        t::ClientDiscriminant::LeaveRequest => Ok(r::WriteOutcomeUnknown::Leave {
2179            request: take_leave(decoder)?,
2180        }),
2181        t::ClientDiscriminant::RecordAdmission => Ok(r::WriteOutcomeUnknown::RecordAdmission {
2182            request: take_record_admission(decoder)?,
2183        }),
2184        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2185    }
2186}
2187
2188trait WireTag: TryFrom<u16> {}
2189
2190impl WireTag for t::TransportReasonTag {}
2191impl WireTag for t::DecodeClass {}
2192impl WireTag for t::AttemptOperation {}
2193impl WireTag for t::AttemptConflict {}
2194impl WireTag for t::Counter {}
2195impl WireTag for t::ClosureScope {}
2196impl WireTag for t::ResourceDimensionTag {}
2197impl WireTag for t::IdentityCapacityScope {}
2198impl WireTag for t::MarkerNotDeliveredReason {}
2199impl WireTag for t::MarkerMismatchReason {}
2200impl WireTag for t::AckGapReason {}
2201impl WireTag for t::AckRegressionReason {}
2202impl WireTag for t::InvalidObserverEpochReason {}
2203impl WireTag for t::InvalidObserverEpochListReason {}
2204impl WireTag for t::RecordAdmissionFaultClassTag {}
2205
2206fn take_tag<T>(decoder: &mut Decoder<'_>) -> Result<T, CodecError>
2207where
2208    T: WireTag,
2209{
2210    T::try_from(decoder.take_u16()?).map_err(|_| decode_error(t::DecodeClass::InvalidField))
2211}
2212
2213fn take_stale_authority(
2214    origin: t::ClientDiscriminant,
2215    decoder: &mut Decoder<'_>,
2216) -> Result<r::StaleAuthority, CodecError> {
2217    match origin {
2218        t::ClientDiscriminant::CredentialAttachRequest => Ok(r::StaleAuthority::Live {
2219            request: r::CommonStaleAuthorityEnvelope::CredentialAttach(take_attach(decoder)?),
2220            current_generation: decoder.take_generation()?,
2221        }),
2222        t::ClientDiscriminant::ParticipantAck => Ok(r::StaleAuthority::Live {
2223            request: r::CommonStaleAuthorityEnvelope::ParticipantAck(take_participant_ack(
2224                decoder,
2225            )?),
2226            current_generation: decoder.take_generation()?,
2227        }),
2228        t::ClientDiscriminant::MarkerAck => Ok(r::StaleAuthority::Live {
2229            request: r::CommonStaleAuthorityEnvelope::MarkerAck(take_marker_ack(decoder)?),
2230            current_generation: decoder.take_generation()?,
2231        }),
2232        t::ClientDiscriminant::RecordAdmission => Ok(r::StaleAuthority::Live {
2233            request: r::CommonStaleAuthorityEnvelope::RecordAdmission(take_record_admission(
2234                decoder,
2235            )?),
2236            current_generation: decoder.take_generation()?,
2237        }),
2238        t::ClientDiscriminant::DetachRequest => {
2239            let authority = t::DetachAuthorityStateTag::try_from(decoder.take_u16()?)
2240                .map_err(|_| decode_error(t::DecodeClass::InvalidField))?;
2241            let value = match authority {
2242                t::DetachAuthorityStateTag::Live => r::DetachStaleAuthority::Live {
2243                    conversation_id: decoder.take_u64()?,
2244                    participant_id: decoder.take_u64()?,
2245                    capability_generation: decoder.take_generation()?,
2246                    detach_attempt_token: DetachAttemptToken::new(
2247                        decoder.take_fixed::<TOKEN_LEN>()?,
2248                    ),
2249                    current_generation: decoder.take_generation()?,
2250                },
2251                t::DetachAuthorityStateTag::TerminalizedDetachCell => {
2252                    let conversation_id = decoder.take_u64()?;
2253                    let participant_id = decoder.take_u64()?;
2254                    let capability_generation = decoder.take_generation()?;
2255                    let detach_attempt_token =
2256                        DetachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2257                    let current_generation = decoder.take_generation()?;
2258                    let committed_binding_epoch = decoder.take_binding_epoch()?;
2259                    let binding_state = match t::BindingStateTag::try_from(decoder.take_u16()?)
2260                        .map_err(|_| decode_error(t::DecodeClass::InvalidField))?
2261                    {
2262                        t::BindingStateTag::Bound => r::BindingStateView::Bound {
2263                            current_binding_epoch: decoder.take_binding_epoch()?,
2264                        },
2265                        t::BindingStateTag::Detached => r::BindingStateView::Detached,
2266                    };
2267                    r::DetachStaleAuthority::TerminalizedDetachCell(
2268                        r::TerminalizedDetachCell::from_wire_decode(
2269                            TERMINALIZED_WIRE_DECODE_AUTHORITY,
2270                            conversation_id,
2271                            participant_id,
2272                            capability_generation,
2273                            detach_attempt_token,
2274                            current_generation,
2275                            committed_binding_epoch,
2276                            binding_state,
2277                        ),
2278                    )
2279                }
2280            };
2281            Ok(r::StaleAuthority::Detach(value))
2282        }
2283        t::ClientDiscriminant::LeaveRequest => {
2284            let authority = t::LeaveAuthorityStateTag::try_from(decoder.take_u16()?)
2285                .map_err(|_| decode_error(t::DecodeClass::InvalidField))?;
2286            let conversation_id = decoder.take_u64()?;
2287            let participant_id = decoder.take_u64()?;
2288            let presented_generation = decoder.take_generation()?;
2289            let leave_attempt_token = LeaveAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2290            let value = match authority {
2291                t::LeaveAuthorityStateTag::Live => r::LeaveStaleAuthority::Live {
2292                    conversation_id,
2293                    participant_id,
2294                    presented_generation,
2295                    leave_attempt_token,
2296                    current_generation: decoder.take_generation()?,
2297                },
2298                t::LeaveAuthorityStateTag::CommittedLeaveTombstone => {
2299                    r::LeaveStaleAuthority::CommittedLeaveTombstone {
2300                        conversation_id,
2301                        participant_id,
2302                        presented_generation,
2303                        leave_attempt_token,
2304                        retired_generation: decoder.take_generation()?,
2305                    }
2306                }
2307            };
2308            Ok(r::StaleAuthority::Leave(value))
2309        }
2310        t::ClientDiscriminant::EnrollmentRequest
2311        | t::ClientDiscriminant::ObserverRecoveryHandshake
2312        | t::ClientDiscriminant::SettlementQuery => Err(decode_error(t::DecodeClass::InvalidField)),
2313    }
2314}
2315
2316pub fn encode_enrollment_committed_body(value: &r::EnrollBound) -> Vec<u8> {
2317    let mut encoder = Encoder::default();
2318    encoder.put_u16(t::ClientDiscriminant::EnrollmentRequest.wire_value());
2319    put_enroll_bound(value, &mut encoder);
2320    encoder.bytes
2321}
2322
2323pub fn encode_attach_committed_body(value: &r::AttachBound) -> Vec<u8> {
2324    let mut encoder = Encoder::default();
2325    encoder.put_u16(t::ClientDiscriminant::CredentialAttachRequest.wire_value());
2326    put_attach_bound(value, &mut encoder);
2327    encoder.bytes
2328}
2329
2330fn put_enroll_bound(value: &r::EnrollBound, encoder: &mut Encoder) {
2331    encoder.put_u64(value.conversation_id());
2332    encoder.put_fixed(value.token().as_bytes());
2333    encoder.put_u64(value.participant_id());
2334    encoder.put_option_generation(value.request_generation());
2335    encoder.put_generation(value.capability_generation());
2336    encoder.put_fixed(value.attach_secret().as_bytes());
2337    encoder.put_binding_epoch(value.origin_binding_epoch());
2338    encoder.put_u64(value.persisted_cursor());
2339    encoder.put_option_u64(value.accepted_marker_delivery_seq());
2340    encoder.put_u128(value.receipt_expires_at());
2341    encoder.put_u128(value.provenance_expires_at());
2342}
2343
2344fn put_attach_bound(value: &r::AttachBound, encoder: &mut Encoder) {
2345    encoder.put_u64(value.conversation_id());
2346    encoder.put_fixed(value.token().as_bytes());
2347    encoder.put_u64(value.participant_id());
2348    encoder.put_option_generation(Some(value.request_generation()));
2349    encoder.put_generation(value.capability_generation());
2350    encoder.put_fixed(value.attach_secret().as_bytes());
2351    encoder.put_binding_epoch(value.origin_binding_epoch());
2352    encoder.put_u64(value.persisted_cursor());
2353    encoder.put_option_u64(value.accepted_marker_delivery_seq());
2354    encoder.put_u128(value.receipt_expires_at());
2355    encoder.put_u128(value.provenance_expires_at());
2356}
2357
2358fn take_enroll_bound(decoder: &mut Decoder<'_>) -> Result<r::EnrollBound, CodecError> {
2359    let conversation_id = decoder.take_u64()?;
2360    let token = EnrollmentToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2361    let participant_id = decoder.take_u64()?;
2362    if decoder.take_option_generation()?.is_some() {
2363        decoder.invalidate();
2364    }
2365    let capability_generation = decoder.take_generation()?;
2366    if capability_generation.get() != 1 {
2367        decoder.invalidate();
2368    }
2369    let attach_secret = AttachSecret::new(decoder.take_fixed::<SECRET_LEN>()?);
2370    let origin_binding_epoch = decoder.take_binding_epoch()?;
2371    if origin_binding_epoch.capability_generation.get() != 1 {
2372        decoder.invalidate();
2373    }
2374    if decoder.take_u64()? != 0 {
2375        decoder.invalidate();
2376    }
2377    if decoder.take_option_u64()?.is_some() {
2378        decoder.invalidate();
2379    }
2380    let receipt_expires_at = decoder.take_u128()?;
2381    let provenance_expires_at = decoder.take_u128()?;
2382
2383    let valid_epoch = if origin_binding_epoch.capability_generation.get() == 1 {
2384        origin_binding_epoch
2385    } else {
2386        BindingEpoch::new(
2387            origin_binding_epoch.connection_incarnation,
2388            generation_one()?,
2389        )
2390    };
2391    r::EnrollBound::new(
2392        conversation_id,
2393        token,
2394        participant_id,
2395        attach_secret,
2396        valid_epoch,
2397        receipt_expires_at,
2398        provenance_expires_at,
2399    )
2400    .ok_or(CodecError::InvalidValue)
2401}
2402
2403fn take_receipt_expired(
2404    origin: t::ClientDiscriminant,
2405    decoder: &mut Decoder<'_>,
2406) -> Result<r::ReceiptExpired, CodecError> {
2407    let conversation_id = decoder.take_u64()?;
2408    let token = decoder.take_fixed::<TOKEN_LEN>()?;
2409    let participant_id = decoder.take_u64()?;
2410    match origin {
2411        t::ClientDiscriminant::EnrollmentRequest => {
2412            if decoder.take_option_generation()?.is_some() {
2413                decoder.invalidate();
2414            }
2415            Ok(r::ReceiptExpired::Enrollment {
2416                conversation_id,
2417                token: EnrollmentToken::new(token),
2418                participant_id,
2419                result_generation: decoder.take_generation()?,
2420                current_generation: decoder.take_generation()?,
2421                reason: take_tag::<t::ReceiptExpiryReason>(decoder)?,
2422            })
2423        }
2424        t::ClientDiscriminant::CredentialAttachRequest => {
2425            let presented_generation = required_generation_option(decoder)?;
2426            Ok(r::ReceiptExpired::CredentialAttach {
2427                conversation_id,
2428                token: AttachAttemptToken::new(token),
2429                participant_id,
2430                presented_generation,
2431                presented_marker_delivery_seq: decoder.take_option_u64()?,
2432                result_generation: decoder.take_generation()?,
2433                current_generation: decoder.take_generation()?,
2434                reason: take_tag::<t::ReceiptExpiryReason>(decoder)?,
2435            })
2436        }
2437        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2438    }
2439}
2440
2441impl WireTag for t::ReceiptExpiryReason {}
2442impl WireTag for t::ReceiptCapacityScope {}
2443
2444fn take_receipt_capacity(
2445    origin: t::ClientDiscriminant,
2446    decoder: &mut Decoder<'_>,
2447) -> Result<r::ReceiptCapacityExceeded, CodecError> {
2448    match origin {
2449        t::ClientDiscriminant::EnrollmentRequest => {
2450            let request = take_enrollment(decoder)?;
2451            let scope = match take_tag::<t::ReceiptCapacityScope>(decoder)? {
2452                t::ReceiptCapacityScope::LiveReceiptServer => {
2453                    r::EnrollmentReceiptCapacityScope::LiveReceiptServer
2454                }
2455                t::ReceiptCapacityScope::ProvenanceServer => {
2456                    r::EnrollmentReceiptCapacityScope::ProvenanceServer
2457                }
2458                t::ReceiptCapacityScope::ProvenanceConversation => {
2459                    r::EnrollmentReceiptCapacityScope::ProvenanceConversation
2460                }
2461                t::ReceiptCapacityScope::LiveReceiptParticipant
2462                | t::ReceiptCapacityScope::ProvenanceParticipant => {
2463                    return Err(decode_error(t::DecodeClass::InvalidField));
2464                }
2465            };
2466            let limit = decoder.take_u64()?;
2467            let occupied = decoder.take_u64()?;
2468            require_one(decoder, r::ReceiptCapacityExceeded::REQUESTED)?;
2469            Ok(r::ReceiptCapacityExceeded::Enrollment {
2470                request,
2471                scope,
2472                limit,
2473                occupied,
2474            })
2475        }
2476        t::ClientDiscriminant::CredentialAttachRequest => {
2477            let request = take_attach(decoder)?;
2478            let scope = take_tag::<t::ReceiptCapacityScope>(decoder)?;
2479            let limit = decoder.take_u64()?;
2480            let occupied = decoder.take_u64()?;
2481            require_one(decoder, r::ReceiptCapacityExceeded::REQUESTED)?;
2482            Ok(r::ReceiptCapacityExceeded::CredentialAttach {
2483                request,
2484                scope,
2485                limit,
2486                occupied,
2487            })
2488        }
2489        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2490    }
2491}
2492
2493fn require_one(decoder: &mut Decoder<'_>, expected: u64) -> Result<(), CodecError> {
2494    if decoder.take_u64()? != expected {
2495        decoder.invalidate();
2496    }
2497    Ok(())
2498}
2499
2500fn take_observer_backpressure(
2501    origin: t::ClientDiscriminant,
2502    decoder: &mut Decoder<'_>,
2503) -> Result<r::ObserverBackpressure, CodecError> {
2504    match origin {
2505        t::ClientDiscriminant::EnrollmentRequest => Ok(r::ObserverBackpressure::Enrollment {
2506            request: take_enrollment(decoder)?,
2507            state: take_backpressure_state(decoder)?,
2508        }),
2509        t::ClientDiscriminant::CredentialAttachRequest => {
2510            Ok(r::ObserverBackpressure::CredentialAttach {
2511                request: take_attach(decoder)?,
2512                state: take_backpressure_state(decoder)?,
2513            })
2514        }
2515        t::ClientDiscriminant::DetachRequest => Ok(r::ObserverBackpressure::Detach {
2516            request: take_detach(decoder)?,
2517            committed_binding_epoch: decoder.take_binding_epoch()?,
2518            state: take_backpressure_state(decoder)?,
2519        }),
2520        t::ClientDiscriminant::LeaveRequest => Ok(r::ObserverBackpressure::Leave {
2521            request: take_leave(decoder)?,
2522            state: take_backpressure_state(decoder)?,
2523            prior_terminal_cell_exists: decoder.take_bool()?,
2524        }),
2525        t::ClientDiscriminant::RecordAdmission => Ok(r::ObserverBackpressure::RecordAdmission {
2526            request: take_record_admission(decoder)?,
2527            state: take_backpressure_state(decoder)?,
2528        }),
2529        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2530    }
2531}
2532
2533fn take_backpressure_state(
2534    decoder: &mut Decoder<'_>,
2535) -> Result<r::ObserverBackpressureState, CodecError> {
2536    let backpressure_epoch = decoder.take_u64()?;
2537    let observer_progress = decoder.take_u64()?;
2538    r::ObserverBackpressureState::replay(backpressure_epoch, observer_progress)
2539        .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))
2540}
2541
2542fn required_generation_option(decoder: &mut Decoder<'_>) -> Result<Generation, CodecError> {
2543    decoder.take_option_generation()?.map_or_else(
2544        || {
2545            decoder.invalidate();
2546            generation_one()
2547        },
2548        Ok,
2549    )
2550}
2551
2552fn take_attach_bound(decoder: &mut Decoder<'_>) -> Result<r::AttachBound, CodecError> {
2553    let conversation_id = decoder.take_u64()?;
2554    let token = AttachAttemptToken::new(decoder.take_fixed::<TOKEN_LEN>()?);
2555    let participant_id = decoder.take_u64()?;
2556    let request_generation = required_generation_option(decoder)?;
2557    let capability_generation = decoder.take_generation()?;
2558    let attach_secret = AttachSecret::new(decoder.take_fixed::<SECRET_LEN>()?);
2559    let origin_binding_epoch = decoder.take_binding_epoch()?;
2560    let persisted_cursor = decoder.take_u64()?;
2561    let accepted_marker_delivery_seq = decoder.take_option_u64()?;
2562    let receipt_expires_at = decoder.take_u128()?;
2563    let provenance_expires_at = decoder.take_u128()?;
2564
2565    let value = match accepted_marker_delivery_seq {
2566        Some(marker) if persisted_cursor == marker => r::AttachBound::fenced(
2567            conversation_id,
2568            token,
2569            participant_id,
2570            request_generation,
2571            attach_secret,
2572            origin_binding_epoch,
2573            marker,
2574            receipt_expires_at,
2575            provenance_expires_at,
2576        ),
2577        Some(_) => None,
2578        None => r::AttachBound::ordinary(
2579            conversation_id,
2580            token,
2581            participant_id,
2582            request_generation,
2583            attach_secret,
2584            origin_binding_epoch,
2585            persisted_cursor,
2586            receipt_expires_at,
2587            provenance_expires_at,
2588        ),
2589    }
2590    .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))?;
2591    if value.capability_generation() == capability_generation {
2592        Ok(value)
2593    } else {
2594        Err(decode_error(t::DecodeClass::InvalidField))
2595    }
2596}
2597
2598fn take_receipt_replay(
2599    origin: t::ClientDiscriminant,
2600    decoder: &mut Decoder<'_>,
2601) -> Result<r::ReceiptReplay, CodecError> {
2602    let conversation_id = decoder.take_u64()?;
2603    let token = decoder.take_fixed::<TOKEN_LEN>()?;
2604    let participant_id = decoder.take_u64()?;
2605    match origin {
2606        t::ClientDiscriminant::EnrollmentRequest => {
2607            let request_generation = decoder.take_option_generation()?;
2608            let capability_generation = decoder.take_generation()?;
2609            let attach_secret = AttachSecret::new(decoder.take_fixed::<SECRET_LEN>()?);
2610            let origin_binding_epoch = decoder.take_binding_epoch()?;
2611            let persisted_cursor = decoder.take_u64()?;
2612            let accepted_marker_delivery_seq = decoder.take_option_u64()?;
2613            let receipt_expires_at = decoder.take_u128()?;
2614            let provenance_expires_at = decoder.take_u128()?;
2615            let value = r::EnrollBound::new(
2616                conversation_id,
2617                EnrollmentToken::new(token),
2618                participant_id,
2619                attach_secret,
2620                origin_binding_epoch,
2621                receipt_expires_at,
2622                provenance_expires_at,
2623            )
2624            .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))?;
2625            if request_generation.is_none()
2626                && capability_generation == Generation::ONE
2627                && persisted_cursor == 0
2628                && accepted_marker_delivery_seq.is_none()
2629            {
2630                Ok(r::ReceiptReplay::Enrollment(value))
2631            } else {
2632                Err(decode_error(t::DecodeClass::InvalidField))
2633            }
2634        }
2635        t::ClientDiscriminant::CredentialAttachRequest => {
2636            let request_generation = required_generation_option(decoder)?;
2637            let capability_generation = decoder.take_generation()?;
2638            let attach_secret = AttachSecret::new(decoder.take_fixed::<SECRET_LEN>()?);
2639            let origin_binding_epoch = decoder.take_binding_epoch()?;
2640            let persisted_cursor = decoder.take_u64()?;
2641            let accepted_marker_delivery_seq = decoder.take_option_u64()?;
2642            let receipt_expires_at = decoder.take_u128()?;
2643            let provenance_expires_at = decoder.take_u128()?;
2644            let attach_token = AttachAttemptToken::new(token);
2645            let value = match accepted_marker_delivery_seq {
2646                Some(marker) if persisted_cursor == marker => r::AttachBound::fenced(
2647                    conversation_id,
2648                    attach_token,
2649                    participant_id,
2650                    request_generation,
2651                    attach_secret,
2652                    origin_binding_epoch,
2653                    marker,
2654                    receipt_expires_at,
2655                    provenance_expires_at,
2656                ),
2657                Some(_) => None,
2658                None => r::AttachBound::ordinary(
2659                    conversation_id,
2660                    attach_token,
2661                    participant_id,
2662                    request_generation,
2663                    attach_secret,
2664                    origin_binding_epoch,
2665                    persisted_cursor,
2666                    receipt_expires_at,
2667                    provenance_expires_at,
2668                ),
2669            }
2670            .ok_or_else(|| decode_error(t::DecodeClass::InvalidField))?;
2671            if value.capability_generation() == capability_generation {
2672                Ok(r::ReceiptReplay::CredentialAttach(value))
2673            } else {
2674                Err(decode_error(t::DecodeClass::InvalidField))
2675            }
2676        }
2677        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2678    }
2679}
2680
2681fn take_ack_no_op(
2682    origin: t::ClientDiscriminant,
2683    decoder: &mut Decoder<'_>,
2684) -> Result<r::AckNoOp, CodecError> {
2685    match origin {
2686        t::ClientDiscriminant::ParticipantAck => {
2687            let request = take_participant_ack(decoder)?;
2688            if decoder.take_u64()? != request.through_seq {
2689                decoder.invalidate();
2690            }
2691            Ok(r::AckNoOp::participant_ack(request))
2692        }
2693        t::ClientDiscriminant::MarkerAck => {
2694            let request = take_marker_ack(decoder)?;
2695            if decoder.take_u64()? != request.marker_delivery_seq {
2696                decoder.invalidate();
2697            }
2698            Ok(r::AckNoOp::marker_ack(request))
2699        }
2700        _ => Err(decode_error(t::DecodeClass::InvalidField)),
2701    }
2702}
2703
2704fn take_recovery_accepted(
2705    decoder: &mut Decoder<'_>,
2706) -> Result<r::ObserverRecoveryAccepted, CodecError> {
2707    let count = decoder.take_u64()?;
2708    let required = u128::from(count) * RECOVERY_STATUS_LEN;
2709    let remaining = u64::try_from(decoder.remaining())
2710        .map_err(|_| decode_error(t::DecodeClass::MissingRequiredField))?;
2711    if required > u128::from(remaining) {
2712        return Err(decode_error(t::DecodeClass::MissingRequiredField));
2713    }
2714    let count_usize: usize = count
2715        .try_into()
2716        .map_err(|_| decode_error(t::DecodeClass::MissingRequiredField))?;
2717
2718    let mut statuses = Vec::new();
2719    for _ in 0..count_usize {
2720        statuses.push(r::ObserverProgressStatus {
2721            conversation_id: decoder.take_u64()?,
2722            refused_epoch: decoder.take_u64()?,
2723            current_observer_progress: decoder.take_u64()?,
2724            armed: decoder.take_bool()?,
2725            progressed: decoder.take_bool()?,
2726        });
2727    }
2728    Ok(r::ObserverRecoveryAccepted { statuses })
2729}
2730
2731fn require_zero_recovery_count(decoder: &mut Decoder<'_>) -> Result<(), CodecError> {
2732    if decoder.take_u64()? == 0 {
2733        Ok(())
2734    } else {
2735        Err(decode_error(t::DecodeClass::InvalidField))
2736    }
2737}
2738
2739fn take_invalid_observer_epoch(
2740    decoder: &mut Decoder<'_>,
2741) -> Result<r::InvalidObserverEpoch, CodecError> {
2742    let reason = take_tag::<t::InvalidObserverEpochReason>(decoder)?;
2743    let conversation_id = decoder.take_u64()?;
2744    let presented_epoch = decoder.take_u64()?;
2745    let current = decoder.take_option_u64()?;
2746    match reason {
2747        t::InvalidObserverEpochReason::ConversationUnknown => {
2748            if current.is_some() {
2749                decoder.invalidate();
2750            }
2751            Ok(r::InvalidObserverEpoch::ConversationUnknown {
2752                conversation_id,
2753                presented_epoch,
2754            })
2755        }
2756        t::InvalidObserverEpochReason::EpochAhead => {
2757            let current_observer_progress = current.unwrap_or_else(|| {
2758                decoder.invalidate();
2759                0
2760            });
2761            Ok(r::InvalidObserverEpoch::EpochAhead {
2762                conversation_id,
2763                presented_epoch,
2764                current_observer_progress,
2765            })
2766        }
2767    }
2768}
2769
2770fn take_invalid_observer_epoch_list(
2771    decoder: &mut Decoder<'_>,
2772) -> Result<r::InvalidObserverEpochList, CodecError> {
2773    match take_tag::<t::InvalidObserverEpochListReason>(decoder)? {
2774        t::InvalidObserverEpochListReason::TooManyEntries => {
2775            Ok(r::InvalidObserverEpochList::TooManyEntries {
2776                presented_entries: decoder.take_u64()?,
2777                max_entries: decoder.take_u64()?,
2778            })
2779        }
2780        t::InvalidObserverEpochListReason::DuplicateConversation => {
2781            Ok(r::InvalidObserverEpochList::DuplicateConversation {
2782                conversation_id: decoder.take_u64()?,
2783                first_index: decoder.take_u64()?,
2784                duplicate_index: decoder.take_u64()?,
2785            })
2786        }
2787    }
2788}