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