use alloc::{boxed::Box, vec::Vec};
use crate::{
algebra::ResourceVector,
outcome::CandidatePhase,
wire::{
BindingEpoch, ClosureCheckedEnvelope, DeliverySeq, OrderAllocatingEnvelope,
RecordAdmission, RecordAdmissionEnvelope, RecordAdmissionResponse, RecordCommitted,
SequenceAllocatingEnvelope, TransactionOrder,
},
};
use super::{
super::{
AdmissionOrder, BindingRequiredLookupResult, BindingState, CapacityCounter, ClaimFrontiers,
ClosureAccounting, ClosureState, ConnectionConversationCapacityCommit,
ConnectionConversationTracking, ImmutableSequenceCandidate, ObserverCheckedOperation,
ObserverFloorDecision, ObserverFloorPermit, OrderAdmissionError, OrderAllocation,
ParticipantBindingRequest, PresentedIdentity, RemainingClosureDecision,
RemainingClosurePermit, RequiredCapacityPlan, RequiredCapacityPlanError,
SemanticConnectionCapacityDecision, SequenceAdmission, SequenceAdmissionError, StoredEdge,
admit_sequence, allocate_order, check_observer_floor, check_record_size,
check_remaining_closure, lookup_binding_required, select_semantic_connection_capacity,
},
OrdinaryProjectionError, OrdinaryProjectionLimits, OrdinaryRecordProjectionDecision,
OrdinaryRecordProjectionInput, ProjectedOrdinaryRecord, RetainedRecordCharge,
};
#[derive(Debug)]
pub struct RecordAdmissionPrestate<'a, EF, V, LF> {
request: RecordAdmission,
presented_identity: PresentedIdentity<'a, EF, V, LF>,
binding: &'a BindingState,
receiving_binding_epoch: BindingEpoch,
connection_tracking: ConnectionConversationTracking,
connection_capacity: CapacityCounter,
closure_accounting: ClosureAccounting,
max_ordinary_record_charge: ResourceVector,
frontiers: ClaimFrontiers,
retained_charges: Vec<RetainedRecordCharge>,
observer_progress: DeliverySeq,
projection_limits: OrdinaryProjectionLimits,
}
impl<'a, EF, V, LF> RecordAdmissionPrestate<'a, EF, V, LF> {
#[allow(clippy::too_many_arguments)]
#[must_use]
pub const fn new(
request: RecordAdmission,
presented_identity: PresentedIdentity<'a, EF, V, LF>,
binding: &'a BindingState,
receiving_binding_epoch: BindingEpoch,
connection_tracking: ConnectionConversationTracking,
connection_capacity: CapacityCounter,
closure_accounting: ClosureAccounting,
max_ordinary_record_charge: ResourceVector,
frontiers: ClaimFrontiers,
retained_charges: Vec<RetainedRecordCharge>,
observer_progress: DeliverySeq,
projection_limits: OrdinaryProjectionLimits,
) -> Self {
Self {
request,
presented_identity,
binding,
receiving_binding_epoch,
connection_tracking,
connection_capacity,
closure_accounting,
max_ordinary_record_charge,
frontiers,
retained_charges,
observer_progress,
projection_limits,
}
}
#[must_use]
pub const fn request(&self) -> &RecordAdmission {
&self.request
}
#[must_use]
pub const fn binding(&self) -> &BindingState {
self.binding
}
#[must_use]
pub const fn receiving_binding_epoch(&self) -> BindingEpoch {
self.receiving_binding_epoch
}
#[must_use]
pub const fn frontiers(&self) -> &ClaimFrontiers {
&self.frontiers
}
#[must_use]
pub const fn connection_capacity(&self) -> CapacityCounter {
self.connection_capacity
}
#[must_use]
pub const fn closure_accounting(&self) -> ClosureAccounting {
self.closure_accounting
}
#[must_use]
pub const fn observer_progress(&self) -> DeliverySeq {
self.observer_progress
}
pub(super) fn into_live_owner_parts(
self,
) -> (
RecordAdmission,
ClaimFrontiers,
ClosureAccounting,
Vec<RetainedRecordCharge>,
) {
(
self.request,
self.frontiers,
self.closure_accounting,
self.retained_charges,
)
}
#[must_use]
pub fn retained_charges(&self) -> &[RetainedRecordCharge] {
&self.retained_charges
}
}
#[derive(Debug)]
pub struct UnchangedRecordAdmission<'a, EF, V, LF> {
prestate: RecordAdmissionPrestate<'a, EF, V, LF>,
encoded_record_charge: ResourceVector,
}
impl<'a, EF, V, LF> UnchangedRecordAdmission<'a, EF, V, LF> {
const fn new(
prestate: RecordAdmissionPrestate<'a, EF, V, LF>,
encoded_record_charge: ResourceVector,
) -> Self {
Self {
prestate,
encoded_record_charge,
}
}
#[must_use]
pub const fn prestate(&self) -> &RecordAdmissionPrestate<'a, EF, V, LF> {
&self.prestate
}
#[must_use]
pub const fn encoded_record_charge(&self) -> ResourceVector {
self.encoded_record_charge
}
#[must_use]
pub fn into_parts(self) -> (RecordAdmissionPrestate<'a, EF, V, LF>, ResourceVector) {
(self.prestate, self.encoded_record_charge)
}
}
#[derive(Debug)]
pub struct RecordAdmissionRefusal<'a, EF, V, LF> {
response: RecordAdmissionResponse,
unchanged: UnchangedRecordAdmission<'a, EF, V, LF>,
}
impl<'a, EF, V, LF> RecordAdmissionRefusal<'a, EF, V, LF> {
#[must_use]
pub const fn response(&self) -> &RecordAdmissionResponse {
&self.response
}
#[must_use]
pub const fn unchanged(&self) -> &UnchangedRecordAdmission<'a, EF, V, LF> {
&self.unchanged
}
#[must_use]
pub fn into_parts(
self,
) -> (
RecordAdmissionResponse,
UnchangedRecordAdmission<'a, EF, V, LF>,
) {
(self.response, self.unchanged)
}
}
#[derive(Debug)]
pub struct RecordAdmissionDrainFirst<'a, EF, V, LF> {
candidate: ImmutableSequenceCandidate,
unchanged: UnchangedRecordAdmission<'a, EF, V, LF>,
}
impl<'a, EF, V, LF> RecordAdmissionDrainFirst<'a, EF, V, LF> {
#[must_use]
pub const fn candidate(&self) -> ImmutableSequenceCandidate {
self.candidate
}
#[must_use]
pub const fn unchanged(&self) -> &UnchangedRecordAdmission<'a, EF, V, LF> {
&self.unchanged
}
#[must_use]
pub fn into_parts(
self,
) -> (
ImmutableSequenceCandidate,
UnchangedRecordAdmission<'a, EF, V, LF>,
) {
(self.candidate, self.unchanged)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CommittedOrdinaryRecord {
request: RecordAdmission,
admission_order: AdmissionOrder,
delivery_seq: DeliverySeq,
encoded_record_charge: ResourceVector,
}
impl CommittedOrdinaryRecord {
#[must_use]
pub const fn request(&self) -> &RecordAdmission {
&self.request
}
#[must_use]
pub const fn admission_order(&self) -> AdmissionOrder {
self.admission_order
}
#[must_use]
pub const fn delivery_seq(&self) -> DeliverySeq {
self.delivery_seq
}
#[must_use]
pub const fn encoded_record_charge(&self) -> ResourceVector {
self.encoded_record_charge
}
const fn new(
request: RecordAdmission,
transaction_order: TransactionOrder,
delivery_seq: DeliverySeq,
encoded_record_charge: ResourceVector,
) -> Self {
let participant_id = request.participant_id;
Self {
request,
admission_order: AdmissionOrder::new(
transaction_order,
CandidatePhase::OrdinaryRecord,
participant_id,
),
delivery_seq,
encoded_record_charge,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct RecordAdmissionCommit {
outcome: RecordCommitted,
record: CommittedOrdinaryRecord,
connection_capacity: ConnectionConversationCapacityCommit,
projection: Box<ProjectedOrdinaryRecord>,
}
#[derive(Debug)]
pub struct RecordAdmissionPersistenceParts {
pub outcome: RecordCommitted,
pub record: CommittedOrdinaryRecord,
pub connection_capacity: ConnectionConversationCapacityCommit,
pub order: OrderAllocation,
pub sequence: SequenceAdmission,
pub observer_floor: ObserverFloorPermit,
pub closure: RemainingClosurePermit,
pub frontiers: ClaimFrontiers,
pub floor: crate::algebra::FloorComputation,
pub retained_charge: crate::algebra::WideResourceVector,
pub baseline: crate::algebra::WideResourceVector,
pub accounting: ClosureAccounting,
pub required_capacity: RequiredCapacityPlan,
pub caller_record: super::super::RetainedCausalRecord,
pub caller_charge: RetainedRecordCharge,
pub retained_charges: Vec<RetainedRecordCharge>,
pub marker_candidates: Vec<super::super::MarkerCandidateAuthority>,
}
impl RecordAdmissionCommit {
#[must_use]
pub const fn outcome(&self) -> &RecordCommitted {
&self.outcome
}
#[must_use]
pub const fn record(&self) -> &CommittedOrdinaryRecord {
&self.record
}
#[must_use]
pub const fn connection_capacity(&self) -> ConnectionConversationCapacityCommit {
self.connection_capacity
}
#[must_use]
pub const fn order(&self) -> OrderAllocation {
self.projection.order()
}
#[must_use]
pub const fn sequence(&self) -> SequenceAdmission {
self.projection.sequence()
}
#[must_use]
pub const fn observer_floor(&self) -> ObserverFloorPermit {
self.projection.observer_floor()
}
#[must_use]
pub const fn closure(&self) -> &RemainingClosurePermit {
&self.projection.closure
}
#[must_use]
pub const fn projection(&self) -> &ProjectedOrdinaryRecord {
&self.projection
}
#[must_use]
pub fn into_persistence_parts(self) -> RecordAdmissionPersistenceParts {
let ProjectedOrdinaryRecord {
frontiers,
floor,
retained_charge,
baseline,
accounting,
required_capacity,
order,
sequence,
observer_floor,
closure,
caller_record,
caller_charge,
retained_charges,
new_marker_candidates,
} = *self.projection;
RecordAdmissionPersistenceParts {
outcome: self.outcome,
record: self.record,
connection_capacity: self.connection_capacity,
order,
sequence,
observer_floor,
closure,
frontiers,
floor,
retained_charge,
baseline,
accounting,
required_capacity,
caller_record,
caller_charge,
retained_charges,
marker_candidates: new_marker_candidates,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RecordAdmissionFault {
Projection(OrdinaryProjectionError),
Order(OrderAdmissionError),
Sequence(SequenceAdmissionError),
RequiredCapacity(RequiredCapacityPlanError),
RefusalInvariant,
}
#[derive(Debug)]
pub struct RecordAdmissionFailure<'a, EF, V, LF> {
fault: RecordAdmissionFault,
unchanged: UnchangedRecordAdmission<'a, EF, V, LF>,
}
impl<'a, EF, V, LF> RecordAdmissionFailure<'a, EF, V, LF> {
#[must_use]
pub const fn fault(&self) -> &RecordAdmissionFault {
&self.fault
}
#[must_use]
pub const fn unchanged(&self) -> &UnchangedRecordAdmission<'a, EF, V, LF> {
&self.unchanged
}
#[must_use]
pub fn into_parts(
self,
) -> (
RecordAdmissionFault,
UnchangedRecordAdmission<'a, EF, V, LF>,
) {
(self.fault, self.unchanged)
}
}
#[derive(Debug)]
pub enum RecordAdmissionDecision<'a, EF, V, LF> {
Respond(Box<RecordAdmissionRefusal<'a, EF, V, LF>>),
DrainFirst(Box<RecordAdmissionDrainFirst<'a, EF, V, LF>>),
Commit(Box<RecordAdmissionCommit>),
Fault(Box<RecordAdmissionFailure<'a, EF, V, LF>>),
}
#[must_use]
pub fn classify_record_admission_binding<EF, V, LF>(
presented_identity: PresentedIdentity<'_, EF, V, LF>,
binding: &BindingState,
receiving_binding_epoch: BindingEpoch,
request: &RecordAdmission,
) -> Option<RecordAdmissionResponse> {
let lookup_request = ParticipantBindingRequest::RecordAdmission(request.clone());
match lookup_binding_required(
presented_identity,
binding,
Some(receiving_binding_epoch),
&lookup_request,
) {
BindingRequiredLookupResult::Retired(value) => {
Some(RecordAdmissionResponse::from_retired(value))
}
BindingRequiredLookupResult::ParticipantUnknown(value) => {
Some(RecordAdmissionResponse::from_participant_unknown(value))
}
BindingRequiredLookupResult::StaleAuthority(value) => {
Some(RecordAdmissionResponse::from_stale_authority(value))
}
BindingRequiredLookupResult::NoBinding(value) => {
Some(RecordAdmissionResponse::from_no_binding(value))
}
BindingRequiredLookupResult::Authorized { .. } => None,
}
}
#[must_use]
#[allow(
clippy::too_many_lines,
reason = "the operation keeps the frozen total selector order visible in one function"
)]
pub fn apply_record_admission<EF, V, LF>(
input: RecordAdmissionPrestate<'_, EF, V, LF>,
encoded_record_charge: ResourceVector,
) -> RecordAdmissionDecision<'_, EF, V, LF> {
let envelope = record_envelope(&input.request);
let lookup_request = ParticipantBindingRequest::RecordAdmission(input.request.clone());
match lookup_binding_required(
input.presented_identity,
input.binding,
Some(input.receiving_binding_epoch),
&lookup_request,
) {
BindingRequiredLookupResult::Retired(value) => {
return refused(
input,
encoded_record_charge,
RecordAdmissionResponse::from_retired(value),
);
}
BindingRequiredLookupResult::ParticipantUnknown(value) => {
return refused(
input,
encoded_record_charge,
RecordAdmissionResponse::from_participant_unknown(value),
);
}
BindingRequiredLookupResult::StaleAuthority(value) => {
return refused(
input,
encoded_record_charge,
RecordAdmissionResponse::from_stale_authority(value),
);
}
BindingRequiredLookupResult::NoBinding(value) => {
return refused(
input,
encoded_record_charge,
RecordAdmissionResponse::from_no_binding(value),
);
}
BindingRequiredLookupResult::Authorized { .. } => {}
}
let connection_capacity = match select_semantic_connection_capacity(
input.connection_tracking,
input.connection_capacity,
) {
SemanticConnectionCapacityDecision::Commit(value) => value,
SemanticConnectionCapacityDecision::Respond { limit } => {
let response =
RecordAdmissionResponse::connection_conversation_capacity_exceeded(envelope, limit);
return refused(input, encoded_record_charge, response);
}
};
let size = match check_record_size(
envelope.clone(),
encoded_record_charge,
input.max_ordinary_record_charge,
) {
super::super::RecordSizeDecision::Eligible(value) => value,
super::super::RecordSizeDecision::Respond(value) => {
return refused(
input,
encoded_record_charge,
RecordAdmissionResponse::record_too_large(value),
);
}
};
if input.frontiers.sequence().immutable_candidates().is_empty()
&& !matches!(input.closure_accounting.state(), ClosureState::Clear)
{
return match nonzero_debt_response(
&envelope,
&input.frontiers,
input.closure_accounting,
input.observer_progress,
input.projection_limits,
) {
Ok(response) => refused(input, encoded_record_charge, response),
Err(operation_fault) => fault(input, encoded_record_charge, operation_fault),
};
}
let RecordAdmissionPrestate {
request,
presented_identity,
binding,
receiving_binding_epoch,
connection_tracking,
connection_capacity: original_connection_capacity,
closure_accounting,
max_ordinary_record_charge,
frontiers,
retained_charges,
observer_progress,
projection_limits,
} = input;
let shell = RecordAdmissionProjectionShell {
request,
presented_identity,
binding,
connection_tracking,
connection_capacity: original_connection_capacity,
max_ordinary_record_charge,
};
let projection_input = OrdinaryRecordProjectionInput::new(
envelope.clone(),
receiving_binding_epoch,
size.encoded_record_charge(),
retained_charges,
observer_progress,
closure_accounting,
projection_limits,
);
let projected = match frontiers.project_ordinary_record(projection_input) {
Ok(OrdinaryRecordProjectionDecision::DrainFirst(value)) => {
let candidate = value.candidate();
let (frontiers, projection_input) = value.into_unchanged_parts();
let unchanged = UnchangedRecordAdmission::new(
shell.rebuild(frontiers, projection_input),
encoded_record_charge,
);
return RecordAdmissionDecision::DrainFirst(Box::new(RecordAdmissionDrainFirst {
candidate,
unchanged,
}));
}
Ok(OrdinaryRecordProjectionDecision::Projected(value)) => value,
Err(failure) => {
let (frontiers, projection_input, error) = failure.into_parts();
let prestate = shell.rebuild(frontiers, projection_input);
return match projection_failure(error, &envelope, closure_accounting) {
Ok(response) => refused(prestate, encoded_record_charge, response),
Err(operation_fault) => fault(prestate, encoded_record_charge, operation_fault),
};
}
};
let order = projected.order();
let sequence = projected.sequence();
let delivery_seq = sequence.resulting().high_watermark();
let record = CommittedOrdinaryRecord::new(
shell.request,
order.major(),
delivery_seq,
size.encoded_record_charge(),
);
RecordAdmissionDecision::Commit(Box::new(RecordAdmissionCommit {
outcome: RecordCommitted::new(envelope, delivery_seq),
record,
connection_capacity,
projection: projected,
}))
}
struct RecordAdmissionProjectionShell<'a, EF, V, LF> {
request: RecordAdmission,
presented_identity: PresentedIdentity<'a, EF, V, LF>,
binding: &'a BindingState,
connection_tracking: ConnectionConversationTracking,
connection_capacity: CapacityCounter,
max_ordinary_record_charge: ResourceVector,
}
impl<'a, EF, V, LF> RecordAdmissionProjectionShell<'a, EF, V, LF> {
fn rebuild(
self,
frontiers: ClaimFrontiers,
projection: OrdinaryRecordProjectionInput,
) -> RecordAdmissionPrestate<'a, EF, V, LF> {
let (
_envelope,
receiving_binding_epoch,
_encoded_record_charge,
retained_charges,
observer_progress,
closure_accounting,
projection_limits,
) = projection.into_parts();
RecordAdmissionPrestate {
request: self.request,
presented_identity: self.presented_identity,
binding: self.binding,
receiving_binding_epoch,
connection_tracking: self.connection_tracking,
connection_capacity: self.connection_capacity,
closure_accounting,
max_ordinary_record_charge: self.max_ordinary_record_charge,
frontiers,
retained_charges,
observer_progress,
projection_limits,
}
}
}
fn refused<EF, V, LF>(
prestate: RecordAdmissionPrestate<'_, EF, V, LF>,
encoded_record_charge: ResourceVector,
response: RecordAdmissionResponse,
) -> RecordAdmissionDecision<'_, EF, V, LF> {
RecordAdmissionDecision::Respond(Box::new(RecordAdmissionRefusal {
response,
unchanged: UnchangedRecordAdmission::new(prestate, encoded_record_charge),
}))
}
fn fault<EF, V, LF>(
prestate: RecordAdmissionPrestate<'_, EF, V, LF>,
encoded_record_charge: ResourceVector,
operation_fault: RecordAdmissionFault,
) -> RecordAdmissionDecision<'_, EF, V, LF> {
RecordAdmissionDecision::Fault(Box::new(RecordAdmissionFailure {
fault: operation_fault,
unchanged: UnchangedRecordAdmission::new(prestate, encoded_record_charge),
}))
}
fn nonzero_debt_response(
envelope: &RecordAdmissionEnvelope,
frontiers: &ClaimFrontiers,
accounting: ClosureAccounting,
observer_progress: DeliverySeq,
limits: OrdinaryProjectionLimits,
) -> Result<RecordAdmissionResponse, RecordAdmissionFault> {
let order = match allocate_order(
OrderAllocatingEnvelope::RecordAdmission(envelope.clone()),
frontiers.order().ledger(),
frontiers.order().ledger().plan_ordinary_record(),
) {
Ok(value) => value,
Err(error) => return order_failure(error),
};
let sequence_plan = match frontiers.sequence().ledger().plan_ordinary_record(0) {
Ok(value) => value,
Err(error) => return sequence_failure(error),
};
if let Err(error) = admit_sequence(
SequenceAllocatingEnvelope::RecordAdmission(envelope.clone()),
sequence_plan,
) {
return sequence_failure(error);
}
match check_observer_floor(
ObserverCheckedOperation::RecordAdmission(envelope.clone()),
observer_progress,
frontiers.retained_floor(),
) {
ObserverFloorDecision::Eligible(_) => {}
ObserverFloorDecision::Respond(value) => {
return Ok(RecordAdmissionResponse::from_observer_backpressure(value));
}
}
let required = match RequiredCapacityPlan::ordinary(
accounting.baseline(),
limits.mandatory_bound(),
accounting.edge_k_remaining(),
) {
Ok(value) => value,
Err(error) => {
return Err(RecordAdmissionFault::RequiredCapacity(error));
}
};
let delivered_marker_awaiting_ack = matches!(
accounting.state(),
ClosureState::Owed {
edge: StoredEdge::ParticipantCursorProgress(progress),
..
} if progress.marker_delivery_seq().is_some()
);
match check_remaining_closure(
&ClosureCheckedEnvelope::RecordAdmission(envelope.clone()),
accounting,
delivered_marker_awaiting_ack,
0,
required,
) {
RemainingClosureDecision::Respond(value) => {
Ok(RecordAdmissionResponse::from_marker_closure_capacity_exceeded(value))
}
RemainingClosureDecision::Eligible(_) => {
let _ = order;
Err(RecordAdmissionFault::RefusalInvariant)
}
}
}
fn projection_failure(
error: OrdinaryProjectionError,
envelope: &RecordAdmissionEnvelope,
accounting: ClosureAccounting,
) -> Result<RecordAdmissionResponse, RecordAdmissionFault> {
match error {
OrdinaryProjectionError::Order(error) => order_failure(error),
OrdinaryProjectionError::Sequence(error) => sequence_failure(error),
OrdinaryProjectionError::ObserverBackpressure {
cap_floor,
observer_progress,
} => match check_observer_floor(
ObserverCheckedOperation::RecordAdmission(envelope.clone()),
observer_progress,
cap_floor,
) {
ObserverFloorDecision::Respond(value) => {
Ok(RecordAdmissionResponse::from_observer_backpressure(value))
}
ObserverFloorDecision::Eligible(_) => Err(RecordAdmissionFault::Projection(
OrdinaryProjectionError::ObserverBackpressure {
cap_floor,
observer_progress,
},
)),
},
OrdinaryProjectionError::Capacity { required, .. }
| OrdinaryProjectionError::MarkerAnchorCapacity { required, .. } => {
capacity_failure(required, envelope, accounting)
}
other => Err(RecordAdmissionFault::Projection(other)),
}
}
fn capacity_failure(
required: crate::algebra::WideResourceVector,
envelope: &RecordAdmissionEnvelope,
accounting: ClosureAccounting,
) -> Result<RecordAdmissionResponse, RecordAdmissionFault> {
let required_capacity = match RequiredCapacityPlan::from_successors(&[required]) {
Ok(value) => value,
Err(error) => {
return Err(RecordAdmissionFault::RequiredCapacity(error));
}
};
match check_remaining_closure(
&ClosureCheckedEnvelope::RecordAdmission(envelope.clone()),
accounting,
false,
0,
required_capacity,
) {
RemainingClosureDecision::Respond(value) => {
Ok(RecordAdmissionResponse::from_marker_closure_capacity_exceeded(value))
}
RemainingClosureDecision::Eligible(_) => Err(RecordAdmissionFault::RefusalInvariant),
}
}
fn order_failure(
error: OrderAdmissionError,
) -> Result<RecordAdmissionResponse, RecordAdmissionFault> {
match error {
OrderAdmissionError::Exhausted(value) => Ok(
RecordAdmissionResponse::from_conversation_order_exhausted(value),
),
other => Err(RecordAdmissionFault::Order(other)),
}
}
fn sequence_failure(
error: SequenceAdmissionError,
) -> Result<RecordAdmissionResponse, RecordAdmissionFault> {
match error {
SequenceAdmissionError::Exhausted(value) => {
Ok(RecordAdmissionResponse::from_conversation_sequence_exhausted(value))
}
other => Err(RecordAdmissionFault::Sequence(other)),
}
}
const fn record_envelope(request: &RecordAdmission) -> RecordAdmissionEnvelope {
RecordAdmissionEnvelope {
conversation_id: request.conversation_id,
participant_id: request.participant_id,
capability_generation: request.capability_generation,
record_admission_attempt_token: request.record_admission_attempt_token,
}
}