Skip to main content

appcore_contracts/policy/
capability.rs

1// =============================================================================
2//        #######
3//     ###       ###     F: capability.rs
4//    ##   ## ##   ##    P: AppCore-Runtime
5//         ## ##
6//                       C: 2026/07/22 15:41:18 by dnettoRaw
7//    ##   ## ##   ##    U: 2026/07/23 10:59:21 by dnettoRaw
8//      ###########      S: 1.0.1-rc.8
9// =============================================================================
10
11use super::*;
12
13/// Ownership boundary for a capability declaration.
14#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(rename_all = "snake_case")]
16pub enum CapabilityClass {
17    /// Infrastructure behavior owned and consumed by the Runtime.
18    Infrastructure,
19    /// Application behavior implemented by consumer code.
20    #[default]
21    Functional,
22}
23
24impl CapabilityClass {
25    fn is_functional(&self) -> bool {
26        *self == Self::Functional
27    }
28}
29
30/// Where a capability may be resolved.
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
32#[serde(rename_all = "snake_case")]
33pub enum CapabilityVisibility {
34    /// Only inside the current process.
35    Local,
36    /// Across compatible peers in the cluster.
37    Cluster,
38    /// Across peers belonging to the same tenant boundary.
39    Tenant,
40}
41
42/// Application declaration for one generic capability.
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44pub struct CapabilityDeclaration {
45    id: CapabilityId,
46    #[serde(default, skip_serializing_if = "CapabilityClass::is_functional")]
47    class: CapabilityClass,
48    version: String,
49    mode: CapabilityMode,
50    visibility: CapabilityVisibility,
51    requires_leader: bool,
52    idempotency_required: bool,
53}
54
55impl CapabilityDeclaration {
56    /// Creates a capability declaration.
57    pub fn new(
58        id: CapabilityId,
59        version: impl Into<String>,
60        mode: CapabilityMode,
61        visibility: CapabilityVisibility,
62    ) -> ContractResult<Self> {
63        let declaration = Self {
64            id,
65            class: CapabilityClass::Functional,
66            version: version.into(),
67            mode,
68            visibility,
69            requires_leader: false,
70            idempotency_required: false,
71        };
72        declaration.validate()?;
73        Ok(declaration)
74    }
75
76    /// Classifies the capability as Runtime infrastructure or application behavior.
77    pub fn with_class(mut self, class: CapabilityClass) -> Self {
78        self.class = class;
79        self
80    }
81
82    /// Marks whether execution requires service leadership.
83    pub fn with_leadership(mut self, required: bool) -> Self {
84        self.requires_leader = required;
85        self
86    }
87
88    /// Marks whether command invocations require an idempotency key.
89    pub fn with_idempotency(mut self, required: bool) -> Self {
90        self.idempotency_required = required;
91        self
92    }
93
94    /// Returns the capability identity.
95    pub fn id(&self) -> &CapabilityId {
96        &self.id
97    }
98
99    /// Returns the capability ownership boundary.
100    pub fn class(&self) -> CapabilityClass {
101        self.class
102    }
103
104    /// Returns the declared capability version.
105    pub fn version(&self) -> &str {
106        &self.version
107    }
108
109    /// Returns the invocation mode.
110    pub fn mode(&self) -> CapabilityMode {
111        self.mode
112    }
113
114    /// Returns the visibility boundary.
115    pub fn visibility(&self) -> CapabilityVisibility {
116        self.visibility
117    }
118
119    /// Reports whether the capability requires leadership.
120    pub fn requires_leader(&self) -> bool {
121        self.requires_leader
122    }
123
124    /// Reports whether commands require an idempotency key.
125    pub fn idempotency_required(&self) -> bool {
126        self.idempotency_required
127    }
128
129    pub(crate) fn validate(&self) -> ContractResult<()> {
130        validate_text("capability.version", &self.version, 64)
131    }
132}
133
134/// Runtime and protocol versions required by an application.
135#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
136pub struct RuntimeRequirements {
137    minimum_runtime_version: String,
138    maximum_runtime_version: Option<String>,
139    protocol_version: String,
140    required_features: BTreeSet<FeatureId>,
141}
142
143impl RuntimeRequirements {
144    /// Creates minimum runtime and protocol requirements.
145    pub fn new(
146        minimum_runtime_version: impl Into<String>,
147        protocol_version: impl Into<String>,
148    ) -> ContractResult<Self> {
149        let requirements = Self {
150            minimum_runtime_version: minimum_runtime_version.into(),
151            maximum_runtime_version: None,
152            protocol_version: protocol_version.into(),
153            required_features: BTreeSet::new(),
154        };
155        requirements.validate()?;
156        Ok(requirements)
157    }
158
159    /// Adds an inclusive maximum runtime version.
160    pub fn with_maximum_runtime_version(
161        mut self,
162        version: impl Into<String>,
163    ) -> ContractResult<Self> {
164        let version = version.into();
165        validate_text("runtime.maximum_version", &version, 64)?;
166        self.maximum_runtime_version = Some(version);
167        Ok(self)
168    }
169
170    /// Adds a runtime feature required by the application.
171    pub fn with_required_feature(mut self, feature: FeatureId) -> Self {
172        self.required_features.insert(feature);
173        self
174    }
175
176    /// Returns the minimum compatible runtime version.
177    pub fn minimum_runtime_version(&self) -> &str {
178        &self.minimum_runtime_version
179    }
180
181    /// Returns the optional maximum compatible runtime version.
182    pub fn maximum_runtime_version(&self) -> Option<&str> {
183        self.maximum_runtime_version.as_deref()
184    }
185
186    /// Returns the required distributed protocol version.
187    pub fn protocol_version(&self) -> &str {
188        &self.protocol_version
189    }
190
191    /// Returns required runtime features.
192    pub fn required_features(&self) -> &BTreeSet<FeatureId> {
193        &self.required_features
194    }
195
196    pub(crate) fn validate(&self) -> ContractResult<()> {
197        validate_text("runtime.minimum_version", &self.minimum_runtime_version, 64)?;
198        validate_text("runtime.protocol_version", &self.protocol_version, 64)?;
199        if let Some(version) = &self.maximum_runtime_version {
200            validate_text("runtime.maximum_version", version, 64)?;
201        }
202        Ok(())
203    }
204}