bcx_model/event.rs
1use bcx_core::{CapabilityRef, EventId, PolicyEpoch, ValidationError};
2use bcx_wire::WireLimits;
3
4/// Relationship between a BCX event and one of its parents.
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub enum RelationshipKind {
7 /// The parent directly caused this event.
8 CausedBy,
9 /// The event was delegated by the parent.
10 DelegatedFrom,
11 /// The event retries the parent.
12 RetryOf,
13 /// The event was scheduled by the parent.
14 ScheduledBy,
15 /// The event was derived from the parent.
16 DerivedFrom,
17 /// The event joins several parent branches.
18 JoinedFrom,
19}
20
21/// Observable cause class for an operation.
22#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23pub enum CauseKind {
24 /// An external network request entered the local trust boundary.
25 ExternalRequest,
26 /// A runtime or client attested an explicit user action.
27 ExplicitUserAction,
28 /// Application code initiated the operation.
29 ApplicationAction,
30 /// A service call was delegated by another participant.
31 DelegatedServiceCall,
32 /// A timer or schedule initiated the operation.
33 Timer,
34 /// A queue message initiated the operation.
35 QueueMessage,
36 /// The operation is a retry.
37 Retry,
38 /// An administrator initiated the operation.
39 Administrator,
40 /// An autonomous agent initiated the operation.
41 AutonomousAgent,
42}
43
44/// High-level operation action.
45#[derive(Clone, Copy, Debug, Eq, PartialEq)]
46pub enum OperationAction {
47 /// Read data without modifying authoritative state.
48 Read,
49 /// Create a new object or state transition.
50 Create,
51 /// Update existing state.
52 Update,
53 /// Delete or tombstone existing state.
54 Delete,
55 /// Derive an output from one or more inputs.
56 Derive,
57 /// Execute a component or tool.
58 Execute,
59 /// Transfer data or authority across a boundary.
60 Transfer,
61 /// Subscribe to future updates.
62 Subscribe,
63 /// Publish an event.
64 Publish,
65}
66
67/// Admission decision produced before execution.
68#[derive(Clone, Copy, Debug, Eq, PartialEq)]
69pub enum AdmissionResult {
70 /// The operation may continue as requested.
71 Allow,
72 /// The operation is denied.
73 Deny,
74 /// The operation may continue only with a narrower scope.
75 Narrow,
76 /// The operation requires stronger approval.
77 RequireApproval,
78 /// The operation is quarantined for later review.
79 Quarantine,
80}
81
82/// Execution result recorded after an operation attempt.
83#[derive(Clone, Copy, Debug, Eq, PartialEq)]
84pub enum EffectResult {
85 /// The operation completed.
86 Completed,
87 /// The operation partially completed.
88 Partial,
89 /// The executor rejected the operation.
90 Rejected,
91 /// Execution failed.
92 Failed,
93 /// Execution was cancelled.
94 Cancelled,
95 /// Execution timed out.
96 TimedOut,
97}
98
99/// Compact event capsule for causal parentage.
100#[derive(Clone, Copy, Debug, Eq, PartialEq)]
101pub struct CauseCapsuleParts<'a> {
102 /// Local event identifier.
103 pub event_id: EventId,
104 /// Parent event identifiers.
105 pub parents: &'a [EventId],
106 /// Relationship used for every parent in this compact capsule.
107 pub relationship: RelationshipKind,
108 /// Observable cause class.
109 pub cause_kind: CauseKind,
110 /// Requested action.
111 pub action: OperationAction,
112 /// Optional authority reference.
113 pub authority: Option<CapabilityRef>,
114 /// Optional policy epoch reference.
115 pub policy_epoch: Option<PolicyEpoch>,
116}
117
118/// Validated compact event capsule for causal parentage.
119#[derive(Clone, Copy, Debug, Eq, PartialEq)]
120pub struct CauseCapsule<'a> {
121 event_id: EventId,
122 parents: &'a [EventId],
123 relationship: RelationshipKind,
124 cause_kind: CauseKind,
125 action: OperationAction,
126 authority: Option<CapabilityRef>,
127 policy_epoch: Option<PolicyEpoch>,
128}
129
130impl<'a> CauseCapsule<'a> {
131 /// Creates a validated compact cause capsule.
132 pub const fn new(
133 parts: CauseCapsuleParts<'a>,
134 limits: WireLimits,
135 ) -> Result<Self, ValidationError> {
136 let capsule = Self {
137 event_id: parts.event_id,
138 parents: parts.parents,
139 relationship: parts.relationship,
140 cause_kind: parts.cause_kind,
141 action: parts.action,
142 authority: parts.authority,
143 policy_epoch: parts.policy_epoch,
144 };
145 match capsule.validate(limits) {
146 Ok(()) => Ok(capsule),
147 Err(error) => Err(error),
148 }
149 }
150
151 /// Validates bounded capsule shape.
152 pub const fn validate(&self, limits: WireLimits) -> Result<(), ValidationError> {
153 if self.parents.is_empty() {
154 return Err(ValidationError::Empty);
155 }
156 if self.parents.len() > limits.maximum_parent_events() {
157 Err(ValidationError::TooLarge)
158 } else {
159 Ok(())
160 }
161 }
162
163 /// Returns the local event identifier.
164 #[must_use]
165 pub const fn event_id(&self) -> EventId {
166 self.event_id
167 }
168
169 /// Returns parent event identifiers.
170 #[must_use]
171 pub const fn parents(&self) -> &'a [EventId] {
172 self.parents
173 }
174
175 /// Returns the relationship used for each parent.
176 #[must_use]
177 pub const fn relationship(&self) -> RelationshipKind {
178 self.relationship
179 }
180
181 /// Returns the observable cause class.
182 #[must_use]
183 pub const fn cause_kind(&self) -> CauseKind {
184 self.cause_kind
185 }
186
187 /// Returns the requested action.
188 #[must_use]
189 pub const fn action(&self) -> OperationAction {
190 self.action
191 }
192
193 /// Returns the optional authority reference.
194 #[must_use]
195 pub const fn authority(&self) -> Option<CapabilityRef> {
196 self.authority
197 }
198
199 /// Returns the optional policy epoch reference.
200 #[must_use]
201 pub const fn policy_epoch(&self) -> Option<PolicyEpoch> {
202 self.policy_epoch
203 }
204}