Skip to main content

made_core/value_objects/ceremony/
ceremony_guard.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5use super::{CeremonyContext, GuardCondition, GuardName, StepExecutionRecord, StepId};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8pub struct CeremonyGuard {
9    name: GuardName,
10    condition: GuardCondition,
11}
12
13impl CeremonyGuard {
14    #[must_use]
15    pub fn new(name: GuardName, condition: GuardCondition) -> Self {
16        Self { name, condition }
17    }
18
19    #[must_use]
20    pub fn name(&self) -> &GuardName {
21        &self.name
22    }
23
24    #[must_use]
25    pub fn condition(&self) -> &GuardCondition {
26        &self.condition
27    }
28
29    #[must_use]
30    pub fn is_satisfied(
31        &self,
32        records: &BTreeMap<StepId, StepExecutionRecord>,
33        context: &CeremonyContext,
34    ) -> bool {
35        match &self.condition {
36            GuardCondition::Always => true,
37            GuardCondition::AllStepsCompleted => {
38                !records.is_empty() && records.values().all(|record| record.status().is_success())
39            }
40            GuardCondition::AnyStepCompleted => {
41                records.values().any(|record| record.status().is_success())
42            }
43            GuardCondition::StepsCompleted(count) => {
44                records
45                    .values()
46                    .filter(|record| record.status().is_success())
47                    .count()
48                    >= count.get() as usize
49            }
50            GuardCondition::StepStatus { step_id, status } => records
51                .get(step_id)
52                .is_some_and(|record| record.status() == *status),
53            GuardCondition::OutputField(condition) => records
54                .get(condition.step_id())
55                .is_some_and(|record| condition.is_satisfied(record)),
56            // Exhaustion needs the referenced step policy and transition source.
57            // Child completion needs the instance's durable child-group fold and
58            // exact execution coordinates. Definition-only evaluation cannot
59            // prove either condition.
60            GuardCondition::StepRepeatExhausted(_) | GuardCondition::ChildrenCompleted(_) => false,
61            GuardCondition::HumanApproval => context.is_guard_approved(&self.name),
62        }
63    }
64}