canic_host/deployment_truth/model/execution/
mod.rs1use super::inventory::ObservationStatusV1;
2use super::safety::SafetyFindingV1;
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
9pub struct DeploymentReceiptV1 {
10 pub schema_version: u32,
11 pub operation_id: String,
12 pub plan_id: String,
13 pub execution_context: Option<DeploymentExecutionContextV1>,
14 pub operation_status: DeploymentExecutionStatusV1,
15 pub started_at: String,
16 pub finished_at: Option<String>,
17 pub operator_principal: Option<String>,
18 pub root_principal: Option<String>,
19 pub previous_observed_deployment_epoch: Option<u64>,
20 pub phase_receipts: Vec<PhaseReceiptV1>,
21 pub role_phase_receipts: Vec<RolePhaseReceiptV1>,
22 pub final_inventory_id: Option<String>,
23 pub command_result: DeploymentCommandResultV1,
24}
25
26#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
30pub struct DeploymentExecutionContextV1 {
31 pub workspace_root: Option<String>,
32 pub icp_root: Option<String>,
33 pub artifact_roots: Vec<String>,
34 pub backend: DeploymentExecutorBackendV1,
35 pub backend_capabilities: Vec<DeploymentExecutorCapabilityV1>,
36}
37
38#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
42pub struct DeploymentExecutionPreflightV1 {
43 pub schema_version: u32,
44 pub plan_id: String,
45 pub safety_report_id: String,
46 pub authority_plan_id: String,
47 pub backend: DeploymentExecutorBackendV1,
48 pub status: DeploymentExecutionPreflightStatusV1,
49 pub planned_phases: Vec<String>,
50 pub required_capabilities: Vec<DeploymentExecutorCapabilityV1>,
51 pub missing_capabilities: Vec<DeploymentExecutorCapabilityV1>,
52 pub blockers: Vec<SafetyFindingV1>,
53}
54
55#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
59pub enum DeploymentExecutionPreflightStatusV1 {
60 Ready,
61 Blocked,
62}
63
64impl DeploymentExecutionPreflightStatusV1 {
65 #[must_use]
66 pub const fn label(self) -> &'static str {
67 match self {
68 Self::Ready => "ready",
69 Self::Blocked => "blocked",
70 }
71 }
72}
73
74#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
78pub enum DeploymentExecutorBackendV1 {
79 CurrentCli,
80 PocketIc,
81 DirectAgent,
82 Other { name: String },
83}
84
85#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
89pub enum DeploymentExecutorCapabilityV1 {
90 CreateCanister,
91 CanisterStatus,
92 UpdateSettings,
93 InstallCode,
94 Call,
95 Query,
96 StageArtifact,
97}
98
99#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
103pub struct PhaseReceiptV1 {
104 pub phase: String,
105 pub started_at: String,
106 pub finished_at: Option<String>,
107 pub attempted_action: String,
108 pub verified_postcondition: VerifiedPostconditionV1,
109}
110
111#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
115pub struct VerifiedPostconditionV1 {
116 pub status: ObservationStatusV1,
117 pub evidence: Vec<String>,
118}
119
120#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
124pub enum DeploymentExecutionStatusV1 {
125 NotStarted,
126 InProgress,
127 FailedBeforeMutation,
128 PartiallyApplied,
129 FailedAfterMutation,
130 Complete,
131}
132
133impl DeploymentExecutionStatusV1 {
134 #[must_use]
135 pub const fn label(self) -> &'static str {
136 match self {
137 Self::NotStarted => "not_started",
138 Self::InProgress => "in_progress",
139 Self::FailedBeforeMutation => "failed_before_mutation",
140 Self::PartiallyApplied => "partially_applied",
141 Self::FailedAfterMutation => "failed_after_mutation",
142 Self::Complete => "complete",
143 }
144 }
145}
146
147#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
151pub enum DeploymentCommandResultV1 {
152 NotFinished,
153 Succeeded,
154 Failed { code: String, message: String },
155}
156
157#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
161pub struct RolePhaseReceiptV1 {
162 pub role: String,
163 pub phase: String,
164 pub result: RolePhaseResultV1,
165 pub previous_module_hash: Option<String>,
166 pub target_module_hash: Option<String>,
167 pub observed_module_hash_after: Option<String>,
168 pub artifact_digest: Option<String>,
169 pub canonical_embedded_config_sha256: Option<String>,
170 pub error: Option<String>,
171}
172
173#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
177pub enum RolePhaseResultV1 {
178 Applied,
179 Failed,
180 Skipped,
181 NotAttempted,
182 VerifiedAlreadyApplied,
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn deployment_execution_preflight_status_owns_text_labels() {
191 assert_eq!(DeploymentExecutionPreflightStatusV1::Ready.label(), "ready");
192 assert_eq!(
193 DeploymentExecutionPreflightStatusV1::Blocked.label(),
194 "blocked"
195 );
196 }
197
198 #[test]
199 fn deployment_execution_status_owns_text_labels() {
200 assert_eq!(
201 DeploymentExecutionStatusV1::NotStarted.label(),
202 "not_started"
203 );
204 assert_eq!(
205 DeploymentExecutionStatusV1::InProgress.label(),
206 "in_progress"
207 );
208 assert_eq!(
209 DeploymentExecutionStatusV1::FailedBeforeMutation.label(),
210 "failed_before_mutation"
211 );
212 assert_eq!(
213 DeploymentExecutionStatusV1::PartiallyApplied.label(),
214 "partially_applied"
215 );
216 assert_eq!(
217 DeploymentExecutionStatusV1::FailedAfterMutation.label(),
218 "failed_after_mutation"
219 );
220 assert_eq!(DeploymentExecutionStatusV1::Complete.label(), "complete");
221 }
222}