liminal_protocol/outcome/internal.rs
1use crate::lifecycle::AdmissionOrder;
2use crate::wire::{
3 BindingEpoch, CloseCause, ConversationId, DeliverySeq, ParticipantId, ParticipantIndex,
4 RepaymentEdge, TransactionOrder,
5};
6
7/// The only close cause admitted by startup binding recovery.
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub struct UncleanServerRestartCause {
10 /// Server incarnation that previously owned the recovered binding.
11 pub prior_server_incarnation: u64,
12}
13
14impl UncleanServerRestartCause {
15 /// Returns the corresponding shared close-cause value.
16 #[must_use]
17 pub const fn as_close_cause(self) -> CloseCause {
18 CloseCause::UncleanServerRestart {
19 prior_server_incarnation: self.prior_server_incarnation,
20 }
21 }
22}
23
24/// Durable finalization selected by startup binding recovery.
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26pub enum BindingRecoveryFinalization {
27 /// Binding terminal was appended in the recovery transaction.
28 Appended {
29 /// Assigned durable delivery sequence.
30 delivery_seq: DeliverySeq,
31 },
32 /// Capacity-backed terminal remains pending for later append.
33 Pending {
34 /// Immutable ordering key retained by pending finalization.
35 admission_order: AdmissionOrder,
36 },
37}
38
39/// Internal durable success from server-startup binding recovery.
40#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub struct BindingRecoveryCommitted {
42 /// Participant whose dead binding was recovered.
43 pub participant_id: ParticipantId,
44 /// Conversation that owned the recovered binding.
45 pub conversation_id: ConversationId,
46 /// Exact old binding epoch terminalized by recovery.
47 pub recovered_binding_epoch: BindingEpoch,
48 /// Exact unclean-restart cause and prior incarnation.
49 pub cause: UncleanServerRestartCause,
50 /// Assigned conversation transaction-order major.
51 pub assigned_transaction_order: TransactionOrder,
52 /// Appended or bounded-pending terminalization.
53 pub finalization: BindingRecoveryFinalization,
54 /// Exact stored closure-debt repayment edge after recovery.
55 pub repayment_edge: RepaymentEdge,
56}
57
58/// Canonical candidate phase in transaction ordering.
59#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
60#[repr(u8)]
61pub enum CandidatePhase {
62 /// Pending or direct binding terminal.
63 BindingTerminal = 0,
64 /// Membership exit record.
65 MembershipExit = 1,
66 /// Attached lifecycle record.
67 AttachLifecycle = 2,
68 /// Admitted ordinary application record.
69 OrdinaryRecord = 3,
70 /// Induced history-compaction marker.
71 CompactionMarker = 4,
72}
73
74/// Counter whose movable-claim frontier is invalid.
75#[derive(Clone, Copy, Debug, PartialEq, Eq)]
76pub enum ClaimCounter {
77 /// Conversation delivery-sequence frontier.
78 DeliverySeq,
79 /// Conversation transaction-order frontier.
80 TransactionOrder,
81}
82
83/// Exact retained-state corruption reasons that remain after Fix 2.
84///
85/// `docs/design/LP-EXTRACTION-GOAL.md` Fix 2 removes fixed occurrence slots,
86/// so occurrence-array placement, churn-block, duplicate-successor, and
87/// unbacked-occurrence reasons are intentionally not constructible here.
88#[derive(Clone, Copy, Debug, PartialEq, Eq)]
89pub enum ParticipantStateCorruptReason {
90 /// Two live candidates share one complete ordering key.
91 DuplicateCandidateKey {
92 /// Candidate transaction-order major.
93 transaction_order: TransactionOrder,
94 /// Candidate phase within the major.
95 candidate_phase: CandidatePhase,
96 /// Permanent participant-index tie-breaker.
97 participant_index: ParticipantIndex,
98 },
99 /// Numeric or logical movable-claim frontier is malformed.
100 ClaimFrontierInvalid {
101 /// First counter in fixed validation order that failed.
102 counter: ClaimCounter,
103 /// Deterministic checked-u128 position of the first fault.
104 first_bad_position: u128,
105 },
106}
107
108/// Candidate validation or startup decoding found corrupt participant state.
109#[derive(Clone, Copy, Debug, PartialEq, Eq)]
110pub struct ParticipantStateCorrupt {
111 /// Conversation whose durable bytes remain preserved and fail closed.
112 pub conversation_id: ConversationId,
113 /// First exact corruption reason in validation order.
114 pub reason: ParticipantStateCorruptReason,
115}