Skip to main content

canic_core/dto/
component_provisioning.rs

1//! Module: dto::component_provisioning
2//!
3//! Responsibility: carry one canonical Fleet Component provisioning plan across boundaries.
4//! Does not own: plan derivation, validation, persistence, root effects, or receipts.
5//! Boundary: the Coordinator retains the complete plan and sends each root only its exact batch.
6
7use crate::{
8    cdk::types::Cycles,
9    config::{ComponentDeploymentLabel, ComponentDeploymentLimits, ComponentDeploymentPurpose},
10    dto::fleet_registry::FleetRegistryVersion,
11    ids::{
12        ComponentBinding, ComponentDeploymentConfigurationDigest, ComponentGroupDeploymentId,
13        ComponentGroupMemberPath, ComponentGroupPlacementId, ComponentGroupSpecId, ComponentSpecId,
14        FleetBinding, FleetSubnetRootBinding, FleetSubnetRootReleaseSet,
15    },
16};
17use candid::{CandidType, Principal};
18use serde::{Deserialize, Serialize};
19
20pub use crate::domain::provisioning_failure::{
21    ProvisioningFailureStage, ProvisioningRetryCategory,
22};
23
24/// Complete canonical provisioning authority retained before any root effect.
25#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
26#[serde(deny_unknown_fields)]
27pub struct FleetComponentProvisioningPlan {
28    pub fleet: FleetBinding,
29    pub fleet_registry: FleetRegistryVersion,
30    pub configuration_digest: ComponentDeploymentConfigurationDigest,
31    pub operation: FleetComponentProvisioningOperation,
32    pub directory_confirmation_roots: Vec<Principal>,
33    pub batches: Vec<FleetSubnetRootProvisioningBatch>,
34}
35
36/// Controller-authenticated command that durably freezes one complete plan.
37#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
38#[serde(deny_unknown_fields)]
39pub struct FleetComponentProvisioningPrepareRequest {
40    pub operation_id: [u8; 32],
41    pub plan: FleetComponentProvisioningPlan,
42}
43
44/// Controller-authenticated command advancing one exact Coordinator provisioning step.
45#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
46#[serde(deny_unknown_fields)]
47pub struct FleetComponentProvisioningAdvanceRequest {
48    pub operation_id: [u8; 32],
49    pub plan_hash: [u8; 32],
50    pub expected_phase: FleetComponentProvisioningPhase,
51    pub expected_accepted_root_count: u32,
52    pub expected_provisioned_root_count: u32,
53    pub expected_current_root: Option<FleetComponentProvisioningRootProgress>,
54    pub expected_directory_confirmed_root_count: u32,
55    pub expected_current_synchronization: Option<FleetComponentSynchronizationRootProgress>,
56    pub expected_current_publication: Option<FleetComponentPublicationRootProgress>,
57    pub expected_runtime_activated_root_count: u32,
58    pub expected_current_activation: Option<FleetComponentActivationRootProgress>,
59}
60
61/// Exact root-local cursor copied from passive Coordinator status before one advance.
62#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
63#[serde(deny_unknown_fields)]
64pub struct FleetComponentProvisioningRootProgress {
65    pub fleet_subnet_root: Principal,
66    pub component_count: u32,
67    pub reserved_component_count: u32,
68    pub claimed_component_count: u32,
69    pub installed_component_count: u32,
70    pub registry_committed_component_count: u32,
71}
72
73/// Exact root-local Directory cursor copied from passive Coordinator status.
74#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
75#[serde(deny_unknown_fields)]
76pub struct FleetComponentPublicationRootProgress {
77    pub fleet_subnet_root: Principal,
78    pub component_count: u32,
79    pub published_component_count: u32,
80}
81
82/// Exact affected-service synchronization cursor copied from passive Coordinator status.
83#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
84#[serde(deny_unknown_fields)]
85pub struct FleetComponentSynchronizationRootProgress {
86    pub fleet_subnet_root: Principal,
87    pub affected_component_count: u32,
88    pub synchronized_component_count: u32,
89    pub complete: bool,
90}
91
92/// Exact root-local runtime-activation cursor copied from passive Coordinator status.
93#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
94#[serde(deny_unknown_fields)]
95pub struct FleetComponentActivationRootProgress {
96    pub fleet_subnet_root: Principal,
97    pub component_count: u32,
98    pub activated_component_count: u32,
99    pub root_runtime_active: bool,
100}
101
102/// Exact passive lookup key for one Coordinator-owned provisioning operation.
103#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
104#[serde(deny_unknown_fields)]
105pub struct FleetComponentProvisioningStatusRequest {
106    pub operation_id: [u8; 32],
107    pub plan_hash: [u8; 32],
108}
109
110/// Durable Coordinator progress exposed without returning the complete plan.
111#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
112pub enum FleetComponentProvisioningPhase {
113    Planned,
114    AcceptingRoots,
115    RootsAccepted,
116    ProvisioningRoots,
117    ComponentsProvisioned,
118    ServiceTopologyPublished,
119    ConfirmingDirectories,
120    DirectoriesConfirmed,
121    ActivatingRuntimes,
122    RuntimesActivated,
123}
124
125/// Exact Coordinator step whose current Root call most recently failed.
126#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
127pub enum FleetComponentProvisioningRetryStage {
128    RootAcceptance,
129    RootProvisioning,
130    DirectoryConfirmation,
131    RuntimeActivation,
132}
133
134/// Bounded typed diagnostic retained for the Root call that remains retryable.
135#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
136#[serde(deny_unknown_fields)]
137pub struct FleetComponentProvisioningRootFailure {
138    pub origin: Option<ProvisioningFailureOrigin>,
139    pub fleet_subnet_root: Principal,
140    pub stage: FleetComponentProvisioningRetryStage,
141    pub diagnostic_code: u16,
142    pub failed_at_ns: u64,
143}
144
145/// Compact exact status for one Coordinator-owned provisioning operation.
146#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
147#[serde(deny_unknown_fields)]
148pub struct FleetComponentProvisioningStatusResponse {
149    pub operation_id: [u8; 32],
150    pub plan_hash: [u8; 32],
151    pub fleet_registry: FleetRegistryVersion,
152    pub configuration_digest: ComponentDeploymentConfigurationDigest,
153    pub operation: FleetComponentProvisioningOperation,
154    pub phase: FleetComponentProvisioningPhase,
155    pub directory_confirmation_root_count: u32,
156    pub root_batch_count: u32,
157    pub accepted_root_count: u32,
158    pub acceptance_in_flight_root: Option<Principal>,
159    pub provisioned_root_count: u32,
160    pub current_root: Option<FleetComponentProvisioningRootProgress>,
161    pub provisioning_in_flight_root: Option<Principal>,
162    pub directory_confirmed_root_count: u32,
163    pub current_synchronization: Option<FleetComponentSynchronizationRootProgress>,
164    pub current_publication: Option<FleetComponentPublicationRootProgress>,
165    pub publication_in_flight_root: Option<Principal>,
166    pub runtime_activated_root_count: u32,
167    pub current_activation: Option<FleetComponentActivationRootProgress>,
168    pub activation_in_flight_root: Option<Principal>,
169    pub pending_root_failure: Option<FleetComponentProvisioningRootFailure>,
170    pub estate_funding_required: Option<RootEstateFundingRequired>,
171    pub group_placement_count: u32,
172    pub component_count: u32,
173    pub planned_at_ns: u64,
174    pub roots_accepted_at_ns: Option<u64>,
175    pub components_provisioned_at_ns: Option<u64>,
176    pub published_fleet_registry: Option<FleetRegistryVersion>,
177    pub service_topology_published_at_ns: Option<u64>,
178    pub directories_confirmed_at_ns: Option<u64>,
179    pub runtimes_activated_at_ns: Option<u64>,
180}
181
182/// Fresh-install or monotonic scale-out scope covered by one plan.
183#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
184#[serde(deny_unknown_fields)]
185pub enum FleetComponentProvisioningOperation {
186    FreshInstall,
187    ScaleOut {
188        deployment: ComponentGroupDeploymentId,
189        previous_placements: u32,
190        requested_placements: u32,
191    },
192}
193
194/// One selected root's complete canonical provisioning batch.
195#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
196#[serde(deny_unknown_fields)]
197pub struct FleetSubnetRootProvisioningBatch {
198    pub root: FleetSubnetRootBinding,
199    pub active_release_set: FleetSubnetRootReleaseSet,
200    pub placements: Vec<ComponentGroupPlacementPlan>,
201}
202
203/// One materialized copy of a completely flattened Component Group.
204#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
205#[serde(deny_unknown_fields)]
206pub struct ComponentGroupPlacementPlan {
207    pub group_placement: ComponentGroupPlacementId,
208    pub component_group: ComponentGroupSpecId,
209    pub entries: Vec<ComponentGroupPlanEntry>,
210}
211
212/// One exact top-level Component occurrence within a group placement.
213#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
214#[serde(deny_unknown_fields)]
215pub struct ComponentGroupPlanEntry {
216    pub member_path: ComponentGroupMemberPath,
217    pub component_spec: ComponentSpecId,
218    pub spec_hash: [u8; 32],
219    pub purpose: ComponentDeploymentPurpose,
220    pub labels: Vec<ComponentDeploymentLabel>,
221    pub limits: ComponentDeploymentLimits,
222}
223
224/// Coordinator-authenticated command asking one root to retain its exact plan batch.
225#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
226#[serde(deny_unknown_fields)]
227pub struct RootComponentProvisioningAcceptanceRequest {
228    pub fleet_registry: FleetRegistryVersion,
229    pub configuration_digest: ComponentDeploymentConfigurationDigest,
230    pub operation_id: [u8; 32],
231    pub plan_hash: [u8; 32],
232    pub batch: FleetSubnetRootProvisioningBatch,
233}
234
235/// Read-only lookup key for one exact root provisioning operation.
236#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
237#[serde(deny_unknown_fields)]
238pub struct RootComponentProvisioningStatusRequest {
239    pub operation_id: [u8; 32],
240    pub plan_hash: [u8; 32],
241}
242
243/// Coordinator-authenticated command advancing one exact bounded provisioning step.
244#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
245#[serde(deny_unknown_fields)]
246pub struct RootComponentProvisioningAdvanceRequest {
247    pub operation_id: [u8; 32],
248    pub plan_hash: [u8; 32],
249    pub expected_reserved_component_count: u32,
250    pub expected_claimed_component_count: u32,
251    pub expected_installed_component_count: u32,
252    pub expected_registry_committed_component_count: u32,
253}
254
255/// One exact member of a root-derived Component Group Directory.
256#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
257#[serde(deny_unknown_fields)]
258pub struct ComponentGroupDirectoryMember {
259    pub member_path: ComponentGroupMemberPath,
260    pub component_spec: ComponentSpecId,
261    pub purpose: ComponentDeploymentPurpose,
262    pub labels: Vec<ComponentDeploymentLabel>,
263    pub binding: ComponentBinding,
264}
265
266/// Protected origin of one root-derived Component Group Directory.
267#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
268#[serde(deny_unknown_fields)]
269pub struct ComponentGroupDirectoryProvenance {
270    pub authority: crate::ids::FleetRegistryAuthority,
271    pub fleet_subnet_root: Principal,
272    pub group_placement: ComponentGroupPlacementId,
273    pub component_group: ComponentGroupSpecId,
274    pub operation_id: [u8; 32],
275    pub plan_hash: [u8; 32],
276    pub placement_receipt_content_hash: [u8; 32],
277}
278
279/// Complete bounded sibling projection for one materialized Component Group placement.
280#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
281#[serde(deny_unknown_fields)]
282pub struct ComponentGroupDirectory {
283    pub provenance: ComponentGroupDirectoryProvenance,
284    pub members: Vec<ComponentGroupDirectoryMember>,
285}
286
287/// Compact proof of one exact Component Directory delivered during publication.
288#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
289#[serde(deny_unknown_fields)]
290pub struct ComponentDirectoryPublicationEvidence {
291    pub component: crate::ids::ComponentInstanceId,
292    pub content_hash: [u8; 32],
293}
294
295/// Compact proof of one exact Component Group Directory delivered during publication.
296#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
297#[serde(deny_unknown_fields)]
298pub struct ComponentGroupDirectoryPublicationEvidence {
299    pub group_placement: ComponentGroupPlacementId,
300    pub content_hash: [u8; 32],
301}
302
303/// Complete root-local evidence for one published provisioning batch.
304#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
305#[serde(deny_unknown_fields)]
306pub struct RootComponentPublicationEvidence {
307    pub fleet_registry: FleetRegistryVersion,
308    pub fleet_directory_content_hash: [u8; 32],
309    pub component_directories: Vec<ComponentDirectoryPublicationEvidence>,
310    pub component_group_directories: Vec<ComponentGroupDirectoryPublicationEvidence>,
311}
312
313/// Coordinator-authenticated command advancing one bounded root publication step.
314#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
315#[serde(deny_unknown_fields)]
316pub struct RootComponentPublicationRequest {
317    pub operation_id: [u8; 32],
318    pub plan_hash: [u8; 32],
319    pub published_fleet_registry: FleetRegistryVersion,
320    pub expected_published_component_count: u32,
321}
322
323///
324/// RootComponentDirectorySynchronizationRequest
325///
326/// Coordinator-authenticated command advancing one affected-root scale-out Directory step.
327///
328
329#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
330#[serde(deny_unknown_fields)]
331pub struct RootComponentDirectorySynchronizationRequest {
332    pub operation_id: [u8; 32],
333    pub plan_hash: [u8; 32],
334    pub source_fleet_registry: FleetRegistryVersion,
335    pub published_fleet_registry: FleetRegistryVersion,
336    pub expected_synchronized_component_count: u32,
337}
338
339///
340/// RootComponentDirectorySynchronizationResponse
341///
342/// Compact exact progress for one root's affected existing service members.
343///
344
345#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
346#[serde(deny_unknown_fields)]
347pub struct RootComponentDirectorySynchronizationResponse {
348    pub operation_id: [u8; 32],
349    pub plan_hash: [u8; 32],
350    pub source_fleet_registry: FleetRegistryVersion,
351    pub published_fleet_registry: FleetRegistryVersion,
352    pub fleet_subnet_root: Principal,
353    pub affected_component_count: u32,
354    pub synchronized_component_count: u32,
355    pub fleet_directory_content_hash: [u8; 32],
356    pub complete: bool,
357    pub synchronized_at_ns: Option<u64>,
358    pub receipt_content_hash: [u8; 32],
359}
360
361/// Coordinator-authenticated command advancing one bounded root activation step.
362#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
363#[serde(deny_unknown_fields)]
364pub struct RootComponentActivationRequest {
365    pub operation_id: [u8; 32],
366    pub plan_hash: [u8; 32],
367    pub expected_activated_component_count: u32,
368    pub expected_root_runtime_active: bool,
369}
370
371/// Compact terminal evidence binding Component inventory and root runtime activation.
372#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
373#[serde(deny_unknown_fields)]
374pub struct RootComponentActivationEvidence {
375    pub fleet_activation_operation_id: [u8; 32],
376    pub initial_inventory_hash: [u8; 32],
377    pub component_count: u32,
378    pub root_activated_at_ns: u64,
379}
380
381/// One exact provisioned Component occurrence and its committed Registry identity.
382#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
383#[serde(deny_unknown_fields)]
384pub struct RootProvisionedGroupMember {
385    pub member_operation_id: [u8; 32],
386    pub member_path: ComponentGroupMemberPath,
387    pub component_spec: ComponentSpecId,
388    pub purpose: ComponentDeploymentPurpose,
389    pub limits: ComponentDeploymentLimits,
390    pub binding: ComponentBinding,
391    pub component_registry_revision: u64,
392    pub component_registry_content_hash: [u8; 32],
393}
394
395/// Complete provisioned result for one exact group placement on this root.
396#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
397#[serde(deny_unknown_fields)]
398pub struct RootProvisionedGroupPlacement {
399    pub group_placement: ComponentGroupPlacementId,
400    pub component_group: ComponentGroupSpecId,
401    pub members: Vec<RootProvisionedGroupMember>,
402}
403
404/// Complete group-partitioned result of one root provisioning operation.
405#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
406#[serde(deny_unknown_fields)]
407pub struct RootComponentProvisioningResult {
408    pub placements: Vec<RootProvisionedGroupPlacement>,
409}
410
411/// Durable aggregate progress of one root provisioning batch.
412#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
413pub enum RootComponentProvisioningPhase {
414    Accepted,
415    Provisioned,
416    Published,
417    RuntimesActive,
418}
419
420/// Durable progress or complete terminal result for one exact root provisioning operation.
421#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
422#[serde(deny_unknown_fields)]
423pub struct RootComponentProvisioningStatusResponse {
424    pub last_failure: Option<RootComponentProvisioningFailure>,
425    pub operation_id: [u8; 32],
426    pub plan_hash: [u8; 32],
427    pub fleet_registry: FleetRegistryVersion,
428    pub configuration_digest: ComponentDeploymentConfigurationDigest,
429    pub fleet_subnet_root: Principal,
430    pub estate_funding_required: Option<RootEstateFundingRequired>,
431    pub phase: RootComponentProvisioningPhase,
432    pub placement_count: u32,
433    pub component_count: u32,
434    pub reserved_component_count: u32,
435    pub claimed_component_count: u32,
436    pub installed_component_count: u32,
437    pub registry_committed_component_count: u32,
438    pub published_component_count: u32,
439    pub activated_component_count: u32,
440    pub root_runtime_active: bool,
441    pub result: Option<RootComponentProvisioningResult>,
442    pub publication: Option<RootComponentPublicationEvidence>,
443    pub activation: Option<RootComponentActivationEvidence>,
444    pub accepted_at_ns: u64,
445    pub provisioned_at_ns: Option<u64>,
446    pub published_at_ns: Option<u64>,
447    pub activation_started_at_ns: Option<u64>,
448    pub runtimes_activated_at_ns: Option<u64>,
449    pub receipt_content_hash: [u8; 32],
450}
451
452/// Protected origin carried through outer provisioning stages without public error expansion.
453#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
454#[serde(deny_unknown_fields)]
455pub struct ProvisioningFailureOrigin {
456    pub failed_at_ns: u64,
457    pub stage: ProvisioningFailureStage,
458    pub target: Principal,
459    pub operation_id: [u8; 32],
460    pub diagnostic_code: u16,
461    pub retry_category: ProvisioningRetryCategory,
462}
463
464/// Latest protected originating failure and the existing scheduler's bounded retry state.
465#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
466#[serde(deny_unknown_fields)]
467pub struct RootComponentProvisioningFailure {
468    pub stage: ProvisioningFailureStage,
469    pub target: Principal,
470    pub operation_id: [u8; 32],
471    pub diagnostic_code: u16,
472    pub retry_category: ProvisioningRetryCategory,
473    pub failed_at_ns: u64,
474    pub consecutive_failures: u32,
475    pub retry_at_ns: Option<u64>,
476}
477
478/// Exact durable funding pause for one Root-owned autonomous pool creation.
479#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
480#[serde(deny_unknown_fields)]
481pub struct RootEstateFundingRequired {
482    pub available: Cycles,
483    pub attempt_count: u32,
484    pub creation_amount: Cycles,
485    pub cycles_ledger: Principal,
486    pub execution_margin: Cycles,
487    pub last_attempt_at_ns: Option<u64>,
488    pub ledger_fee: Cycles,
489    pub management_creation_fee: Cycles,
490    pub operation_id: [u8; 32],
491    pub readiness_floor: Cycles,
492    pub required: Cycles,
493    pub retry_at_ns: u64,
494    pub root: Principal,
495    pub shortfall: Cycles,
496}