Skip to main content

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}