Skip to main content

mj_core/state/
session_move.rs

1//! Durable intent for a verified stop followed by destination restoration.
2
3use super::*;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "kebab-case")]
7pub enum ResumeQueueDisposition {
8    Start,
9    Discard,
10}
11
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(deny_unknown_fields)]
14pub struct MoveSelection {
15    #[serde(default)]
16    pub clear_resource_allocation: bool,
17    pub session_id: String,
18    pub profile_id: Option<String>,
19    pub target_template_id: Option<String>,
20    pub additional_mounts: Option<Vec<AdditionalMount>>,
21    pub resource_allocation: Option<SessionResourceAllocation>,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25#[serde(deny_unknown_fields)]
26pub struct MovePreparation {
27    #[serde(default)]
28    pub source_unavailable: bool,
29    pub selection: MoveSelection,
30    pub source_profile_id: String,
31    pub source_target_template_id: String,
32    pub cross_harness: bool,
33    pub active: bool,
34    pub queued_commands: Vec<MaterializedQueuedPrompt>,
35    pub fingerprint: String,
36    pub operation_id: String,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(deny_unknown_fields)]
41pub struct MoveSessionRequest {
42    pub preparation: MovePreparation,
43    pub queue: Option<ResumeQueueDisposition>,
44    pub acknowledge_interruption: bool,
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
48#[serde(deny_unknown_fields)]
49pub struct MoveOutcome {
50    pub operation_id: String,
51    pub session_id: String,
52    pub profile_id: String,
53    pub target_template_id: String,
54    pub outcome: String,
55    pub error: Option<String>,
56    pub recovery: Option<String>,
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
60#[serde(rename_all = "snake_case")]
61pub enum MovePhase {
62    Preparing,
63    ClosingSource,
64    ResumingDestination,
65    StartingQueue,
66    Completed,
67    Failed,
68    Cancelled,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
72#[serde(deny_unknown_fields)]
73pub struct MoveOperation {
74    /// Keep the source harness stopped across recovery until destination restoration.
75    #[serde(default)]
76    pub source_checkpoint_only: bool,
77    pub operation_id: String,
78    pub selection: MoveSelection,
79    pub source_profile_id: String,
80    pub source_target_template_id: String,
81    pub source_target: Option<TargetLocator>,
82    pub source_native_session_id: Option<String>,
83    pub source_additional_mounts: Vec<AdditionalMount>,
84    pub source_resource_allocation: Option<SessionResourceAllocation>,
85    pub destination_target: Option<TargetLocator>,
86    pub destination_native_session_id: Option<String>,
87    pub destination_store_id: Option<String>,
88    pub configuration_fingerprint: String,
89    pub checkpoint: Option<CheckpointMetadata>,
90    /// Stopped identity retained across partially written resume conversions.
91    pub recovery_session: Option<SessionRecord>,
92    pub queue: ResumeQueueDisposition,
93    pub phase: MovePhase,
94    /// A durable boundary: once set, never restore or replay on another relay.
95    pub queue_admission_started: bool,
96    pub queue_admission_finished: bool,
97    pub cancellation_requested: bool,
98    pub created_at: String,
99    pub updated_at: String,
100    pub error: Option<String>,
101}
102
103impl MoveOperation {
104    pub fn retains_checkpoint(&self) -> bool {
105        !matches!(self.phase, MovePhase::Completed | MovePhase::Cancelled)
106            || (self.queue_admission_started && !self.queue_admission_finished)
107    }
108
109    pub fn is_active(&self) -> bool {
110        matches!(
111            self.phase,
112            MovePhase::Preparing
113                | MovePhase::ClosingSource
114                | MovePhase::ResumingDestination
115                | MovePhase::StartingQueue
116        )
117    }
118}