nixfleet_state_machine/rollout/error.rs
1//! Rollout reducer error path. Parallel to the per-host `TransitionError`
2//! (`crate::error`). The applier logs + drops or surfaces depending on
3//! the variant.
4
5use thiserror::Error;
6
7use crate::rollout::state::{RolloutId, RolloutState};
8
9#[derive(Debug, Error, Clone, PartialEq)]
10pub enum RolloutTransitionError {
11 /// The event is not legal from the current `RolloutState`. Typically
12 /// out-of-order arrival (e.g., `RolloutTerminal` from `Opening` before
13 /// any host joined).
14 #[error("event {event} not legal from rollout state {from:?} (rollout {rollout_id})")]
15 IllegalForState {
16 from: RolloutState,
17 event: &'static str,
18 rollout_id: RolloutId,
19 },
20
21 /// A `RolloutOpened` arrived for a `(channel, ref)` whose channel
22 /// already has an `active_rollout_id`. The planner must emit
23 /// `SuccessorOpened` first (RFC-0008 §3 invariant).
24 #[error(
25 "rollout {rollout_id} opened on channel {channel} without prior SuccessorOpened (expected supersession)"
26 )]
27 SupersessionExpected {
28 rollout_id: RolloutId,
29 channel: String,
30 },
31
32 /// Invariant from RFC-0008 §3 violated by the event's payload (e.g.,
33 /// `RolloutTerminal` while at least one host is not Converged).
34 #[error("rollout invariant violation: {0}")]
35 Invariant(&'static str),
36
37 /// Reducer arm not yet implemented. Returned by the Phase 10a
38 /// skeleton; every variant gets a real arm in Phase 10b. Should never
39 /// be reached after Phase 10 closes — if it is, that's a code defect.
40 #[error("rollout transition not yet implemented for event {event} from state {from:?}")]
41 Unimplemented {
42 from: RolloutState,
43 event: &'static str,
44 },
45}