1use serde::Serialize;
2
3pub const CAPABILITY_SCHEMA_VERSION: u32 = 1;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
8#[serde(rename_all = "snake_case")]
9pub enum ExecutionTarget {
10 SingleRing,
12 LaneGraph,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
18#[serde(rename_all = "snake_case")]
19pub enum LaneFeature {
20 Events,
22 SequencedSlots,
24 Journal,
26 FanoutBroadcast,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
32#[serde(rename_all = "snake_case")]
33pub enum StageKeyKind {
34 Stable,
36 Prefix,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
42#[serde(rename_all = "snake_case")]
43pub enum PolicyClassId {
44 PureTransform,
46 SideEffecting,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
52#[serde(rename_all = "snake_case")]
53pub enum ReplaySupport {
54 Allowed,
56 DryRunOnly,
58 Unsupported,
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
64#[serde(rename_all = "snake_case")]
65pub enum RuntimeEnvironment {
66 Dev,
68 Staging,
70 Prod,
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
76#[serde(rename_all = "snake_case")]
77pub enum EnvironmentSideEffects {
78 Allowed,
80 ApprovalRequired,
82 Denied,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
88#[serde(rename_all = "camelCase")]
89pub struct LaneFeatureSupport {
90 pub feature: LaneFeature,
92 pub supported_targets: Vec<ExecutionTarget>,
94}
95
96#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
98#[serde(rename_all = "camelCase")]
99pub struct PolicyClassDefinition {
100 pub id: PolicyClassId,
102 pub description: String,
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
108#[serde(rename_all = "camelCase")]
109pub struct ReplayConstraints {
110 pub default_mode: ReplaySupport,
112 pub max_actions: u64,
114 pub max_input_bytes: u64,
116}
117
118#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
120#[serde(rename_all = "camelCase")]
121pub struct EnvironmentRestriction {
122 pub environment: RuntimeEnvironment,
124 pub side_effects: EnvironmentSideEffects,
126 #[serde(default, skip_serializing_if = "Vec::is_empty")]
128 pub required_approval_capabilities: Vec<String>,
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
133#[serde(rename_all = "camelCase")]
134pub struct StageCatalogEntry {
135 pub key: String,
137 pub key_kind: StageKeyKind,
139 pub description: String,
141 pub supported_targets: Vec<ExecutionTarget>,
143 pub policy_class: PolicyClassId,
145 #[serde(default, skip_serializing_if = "Vec::is_empty")]
147 pub approval_capabilities: Vec<String>,
148 pub replay_support: ReplaySupport,
150 pub environments: Vec<RuntimeEnvironment>,
152}
153
154#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
156#[serde(rename_all = "camelCase")]
157pub struct RuntimeCapabilityDocument {
158 pub schema_version: u32,
160 pub product: String,
162 pub supported_targets: Vec<ExecutionTarget>,
164 pub lane_features: Vec<LaneFeatureSupport>,
166 pub stage_catalog: Vec<StageCatalogEntry>,
168 pub policy_classes: Vec<PolicyClassDefinition>,
170 pub replay_constraints: ReplayConstraints,
172 pub environment_restrictions: Vec<EnvironmentRestriction>,
174}
175
176pub fn stable_stage_catalog_entry(
178 key: impl Into<String>,
179 description: impl Into<String>,
180 supported_targets: Vec<ExecutionTarget>,
181 policy_class: PolicyClassId,
182 replay_support: ReplaySupport,
183 environments: Vec<RuntimeEnvironment>,
184 approval_capabilities: Vec<String>,
185) -> StageCatalogEntry {
186 StageCatalogEntry {
187 key: key.into(),
188 key_kind: StageKeyKind::Stable,
189 description: description.into(),
190 supported_targets,
191 policy_class,
192 approval_capabilities,
193 replay_support,
194 environments,
195 }
196}
197
198pub fn prefix_stage_catalog_entry(
200 key: impl Into<String>,
201 description: impl Into<String>,
202 supported_targets: Vec<ExecutionTarget>,
203 policy_class: PolicyClassId,
204 replay_support: ReplaySupport,
205 environments: Vec<RuntimeEnvironment>,
206 approval_capabilities: Vec<String>,
207) -> StageCatalogEntry {
208 StageCatalogEntry {
209 key: key.into(),
210 key_kind: StageKeyKind::Prefix,
211 description: description.into(),
212 supported_targets,
213 policy_class,
214 approval_capabilities,
215 replay_support,
216 environments,
217 }
218}
219
220pub fn runtime_capability_document(
222 product: impl Into<String>,
223 stage_catalog: Vec<StageCatalogEntry>,
224) -> RuntimeCapabilityDocument {
225 let replay_limits = byteor_policy::ReplayLimits::default();
226 RuntimeCapabilityDocument {
227 schema_version: CAPABILITY_SCHEMA_VERSION,
228 product: product.into(),
229 supported_targets: default_supported_targets(),
230 lane_features: default_lane_feature_support(),
231 stage_catalog,
232 policy_classes: vec![
233 PolicyClassDefinition {
234 id: PolicyClassId::PureTransform,
235 description: "Deterministic or pure transforms with no external side effects"
236 .to_string(),
237 },
238 PolicyClassDefinition {
239 id: PolicyClassId::SideEffecting,
240 description:
241 "Side-effecting execution that may require approval and replay gating"
242 .to_string(),
243 },
244 ],
245 replay_constraints: ReplayConstraints {
246 default_mode: ReplaySupport::DryRunOnly,
247 max_actions: replay_limits.max_actions,
248 max_input_bytes: replay_limits.max_input_bytes,
249 },
250 environment_restrictions: vec![
251 EnvironmentRestriction {
252 environment: RuntimeEnvironment::Dev,
253 side_effects: EnvironmentSideEffects::Allowed,
254 required_approval_capabilities: Vec::new(),
255 },
256 EnvironmentRestriction {
257 environment: RuntimeEnvironment::Staging,
258 side_effects: EnvironmentSideEffects::ApprovalRequired,
259 required_approval_capabilities: vec!["execute_side_effects".to_string()],
260 },
261 EnvironmentRestriction {
262 environment: RuntimeEnvironment::Prod,
263 side_effects: EnvironmentSideEffects::ApprovalRequired,
264 required_approval_capabilities: vec!["execute_side_effects".to_string()],
265 },
266 ],
267 }
268}
269
270fn default_supported_targets() -> Vec<ExecutionTarget> {
271 vec![ExecutionTarget::SingleRing, ExecutionTarget::LaneGraph]
272}
273
274fn default_lane_feature_support() -> Vec<LaneFeatureSupport> {
275 let lane_graph_only = vec![ExecutionTarget::LaneGraph];
276 vec![
277 LaneFeatureSupport {
278 feature: LaneFeature::Events,
279 supported_targets: lane_graph_only.clone(),
280 },
281 LaneFeatureSupport {
282 feature: LaneFeature::SequencedSlots,
283 supported_targets: lane_graph_only.clone(),
284 },
285 LaneFeatureSupport {
286 feature: LaneFeature::Journal,
287 supported_targets: lane_graph_only.clone(),
288 },
289 LaneFeatureSupport {
290 feature: LaneFeature::FanoutBroadcast,
291 supported_targets: lane_graph_only,
292 },
293 ]
294}