Skip to main content

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    ///
106    /// The compact capsule uses the same [`RelationshipKind`] for every
107    /// parent. Use separate capsules when parents need different relationship
108    /// meanings.
109    pub parents: &'a [EventId],
110    /// Relationship used for every parent in this compact capsule.
111    pub relationship: RelationshipKind,
112    /// Observable cause class.
113    pub cause_kind: CauseKind,
114    /// Requested action.
115    pub action: OperationAction,
116    /// Optional authority reference.
117    pub authority: Option<CapabilityRef>,
118    /// Optional policy epoch reference.
119    pub policy_epoch: Option<PolicyEpoch>,
120}
121
122/// Validated compact event capsule for causal parentage.
123#[derive(Clone, Copy, Debug, Eq, PartialEq)]
124pub struct CauseCapsule<'a> {
125    event_id: EventId,
126    parents: &'a [EventId],
127    relationship: RelationshipKind,
128    cause_kind: CauseKind,
129    action: OperationAction,
130    authority: Option<CapabilityRef>,
131    policy_epoch: Option<PolicyEpoch>,
132}
133
134impl<'a> CauseCapsule<'a> {
135    /// Creates a validated compact cause capsule.
136    pub fn new(parts: CauseCapsuleParts<'a>, limits: WireLimits) -> Result<Self, ValidationError> {
137        let capsule = Self {
138            event_id: parts.event_id,
139            parents: parts.parents,
140            relationship: parts.relationship,
141            cause_kind: parts.cause_kind,
142            action: parts.action,
143            authority: parts.authority,
144            policy_epoch: parts.policy_epoch,
145        };
146        match capsule.validate(limits) {
147            Ok(()) => Ok(capsule),
148            Err(error) => Err(error),
149        }
150    }
151
152    /// Validates bounded capsule shape and rejects direct self-parent cycles.
153    pub fn validate(&self, limits: WireLimits) -> Result<(), ValidationError> {
154        if self.parents.is_empty() {
155            return Err(ValidationError::Empty);
156        }
157        if self.parents.len() > limits.maximum_parent_events() {
158            return Err(ValidationError::TooLarge);
159        }
160        if self.parents.iter().any(|parent| parent == &self.event_id) {
161            return Err(ValidationError::Malformed);
162        }
163        Ok(())
164    }
165
166    /// Returns the local event identifier.
167    #[must_use]
168    pub const fn event_id(&self) -> EventId {
169        self.event_id
170    }
171
172    /// Returns parent event identifiers.
173    #[must_use]
174    pub const fn parents(&self) -> &'a [EventId] {
175        self.parents
176    }
177
178    /// Returns the relationship used for each parent.
179    #[must_use]
180    pub const fn relationship(&self) -> RelationshipKind {
181        self.relationship
182    }
183
184    /// Returns the observable cause class.
185    #[must_use]
186    pub const fn cause_kind(&self) -> CauseKind {
187        self.cause_kind
188    }
189
190    /// Returns the requested action.
191    #[must_use]
192    pub const fn action(&self) -> OperationAction {
193        self.action
194    }
195
196    /// Returns the optional authority reference.
197    #[must_use]
198    pub const fn authority(&self) -> Option<CapabilityRef> {
199        self.authority
200    }
201
202    /// Returns the optional policy epoch reference.
203    #[must_use]
204    pub const fn policy_epoch(&self) -> Option<PolicyEpoch> {
205        self.policy_epoch
206    }
207}