1use crate::actor::ActorRegistration;
11use crate::budget::BudgetDimension;
12use crate::ids::{ActorId, AttemptId, RunId, TaskId, TenantId};
13use crate::platform::{Capability, LedgerEntry, Role, TenantRegistration};
14use crate::run::state::RunState;
15use crate::run::RunInstance;
16use crate::subscription::{EventFilter, SubscriptionId};
17use crate::task::task_spec::TaskSpec;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum DurabilityPolicy {
22 Immediate,
24 Deferred,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30#[must_use = "mutation commands should be submitted to a MutationAuthority"]
31pub enum MutationCommand {
32 TaskCreate(TaskCreateCommand),
34 RunCreate(RunCreateCommand),
36 RunStateTransition(RunStateTransitionCommand),
38 AttemptStart(AttemptStartCommand),
40 AttemptFinish(AttemptFinishCommand),
42 LeaseAcquire(LeaseAcquireCommand),
44 LeaseHeartbeat(LeaseHeartbeatCommand),
46 LeaseExpire(LeaseExpireCommand),
48 LeaseRelease(LeaseReleaseCommand),
50 EnginePause(EnginePauseCommand),
52 EngineResume(EngineResumeCommand),
54 TaskCancel(TaskCancelCommand),
56 DependencyDeclare(DependencyDeclareCommand),
58 RunSuspend(RunSuspendCommand),
60 RunResume(RunResumeCommand),
62 BudgetAllocate(BudgetAllocateCommand),
64 BudgetConsume(BudgetConsumeCommand),
66 BudgetReplenish(BudgetReplenishCommand),
68 SubscriptionCreate(SubscriptionCreateCommand),
70 SubscriptionCancel(SubscriptionCancelCommand),
72 SubscriptionTrigger(SubscriptionTriggerCommand),
74 ActorRegister(ActorRegisterCommand),
76 ActorDeregister(ActorDeregisterCommand),
78 ActorHeartbeat(ActorHeartbeatCommand),
80 TenantCreate(TenantCreateCommand),
82 RoleAssign(RoleAssignCommand),
84 CapabilityGrant(CapabilityGrantCommand),
86 CapabilityRevoke(CapabilityRevokeCommand),
88 LedgerAppend(LedgerAppendCommand),
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub struct EnginePauseCommand {
95 sequence: u64,
96 timestamp: u64,
97}
98
99impl EnginePauseCommand {
100 pub fn new(sequence: u64, timestamp: u64) -> Self {
102 Self { sequence, timestamp }
103 }
104
105 pub fn sequence(&self) -> u64 {
107 self.sequence
108 }
109
110 pub fn timestamp(&self) -> u64 {
112 self.timestamp
113 }
114}
115
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub struct EngineResumeCommand {
119 sequence: u64,
120 timestamp: u64,
121}
122
123impl EngineResumeCommand {
124 pub fn new(sequence: u64, timestamp: u64) -> Self {
126 Self { sequence, timestamp }
127 }
128
129 pub fn sequence(&self) -> u64 {
131 self.sequence
132 }
133
134 pub fn timestamp(&self) -> u64 {
136 self.timestamp
137 }
138}
139
140#[derive(Debug, Clone, PartialEq, Eq)]
142pub struct TaskCreateCommand {
143 sequence: u64,
144 task_spec: TaskSpec,
145 timestamp: u64,
146}
147
148impl TaskCreateCommand {
149 pub fn new(sequence: u64, task_spec: TaskSpec, timestamp: u64) -> Self {
151 Self { sequence, task_spec, timestamp }
152 }
153
154 pub fn sequence(&self) -> u64 {
156 self.sequence
157 }
158
159 pub fn task_spec(&self) -> &TaskSpec {
161 &self.task_spec
162 }
163
164 pub fn timestamp(&self) -> u64 {
166 self.timestamp
167 }
168}
169
170#[derive(Debug, Clone, PartialEq, Eq)]
172pub struct RunCreateCommand {
173 sequence: u64,
174 run_instance: RunInstance,
175}
176
177impl RunCreateCommand {
178 pub fn new(sequence: u64, run_instance: RunInstance) -> Self {
180 Self { sequence, run_instance }
181 }
182
183 pub fn sequence(&self) -> u64 {
185 self.sequence
186 }
187
188 pub fn run_instance(&self) -> &RunInstance {
190 &self.run_instance
191 }
192}
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq)]
196pub struct RunStateTransitionCommand {
197 sequence: u64,
198 run_id: RunId,
199 previous_state: RunState,
200 new_state: RunState,
201 timestamp: u64,
202}
203
204impl RunStateTransitionCommand {
205 pub fn new(
207 sequence: u64,
208 run_id: RunId,
209 previous_state: RunState,
210 new_state: RunState,
211 timestamp: u64,
212 ) -> Self {
213 Self { sequence, run_id, previous_state, new_state, timestamp }
214 }
215
216 pub fn sequence(&self) -> u64 {
218 self.sequence
219 }
220
221 pub fn run_id(&self) -> RunId {
223 self.run_id
224 }
225
226 pub fn previous_state(&self) -> RunState {
228 self.previous_state
229 }
230
231 pub fn new_state(&self) -> RunState {
233 self.new_state
234 }
235
236 pub fn timestamp(&self) -> u64 {
238 self.timestamp
239 }
240}
241
242#[derive(Debug, Clone, Copy, PartialEq, Eq)]
244pub struct AttemptStartCommand {
245 sequence: u64,
246 run_id: RunId,
247 attempt_id: AttemptId,
248 timestamp: u64,
249}
250
251impl AttemptStartCommand {
252 pub fn new(sequence: u64, run_id: RunId, attempt_id: AttemptId, timestamp: u64) -> Self {
254 Self { sequence, run_id, attempt_id, timestamp }
255 }
256
257 pub fn sequence(&self) -> u64 {
259 self.sequence
260 }
261
262 pub fn run_id(&self) -> RunId {
264 self.run_id
265 }
266
267 pub fn attempt_id(&self) -> AttemptId {
269 self.attempt_id
270 }
271
272 pub fn timestamp(&self) -> u64 {
274 self.timestamp
275 }
276}
277
278#[derive(Debug, Clone, Copy, PartialEq, Eq)]
280#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
281pub enum AttemptResultKind {
282 Success,
284 Failure,
286 Timeout,
288 Suspended,
291}
292
293#[derive(Debug, Clone, PartialEq, Eq)]
301#[must_use = "attempt outcome should be inspected for state transition decisions"]
302pub struct AttemptOutcome {
303 result: AttemptResultKind,
304 error: Option<String>,
305 output: Option<Vec<u8>>,
312}
313
314#[derive(Debug, Clone, PartialEq, Eq)]
316pub enum AttemptOutcomeError {
317 SuccessWithError {
319 error: String,
321 },
322 NonSuccessWithoutError {
324 result: AttemptResultKind,
326 },
327 NonSuccessWithOutput {
329 result: AttemptResultKind,
331 },
332}
333
334impl std::fmt::Display for AttemptOutcomeError {
335 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
336 match self {
337 AttemptOutcomeError::SuccessWithError { error } => {
338 write!(f, "Success/Suspended outcome must not have an error detail, got: {error}")
339 }
340 AttemptOutcomeError::NonSuccessWithoutError { result } => {
341 write!(f, "{result:?} outcome must have an error detail")
342 }
343 AttemptOutcomeError::NonSuccessWithOutput { result } => {
344 write!(f, "non-success outcome {result:?} cannot carry output bytes")
345 }
346 }
347 }
348}
349
350impl std::error::Error for AttemptOutcomeError {}
351
352impl AttemptOutcome {
353 pub fn success() -> Self {
355 Self { result: AttemptResultKind::Success, error: None, output: None }
356 }
357
358 pub fn success_with_output(output: Vec<u8>) -> Self {
362 let output = if output.is_empty() { None } else { Some(output) };
363 Self { result: AttemptResultKind::Success, error: None, output }
364 }
365
366 pub fn failure(error: impl Into<String>) -> Self {
368 Self { result: AttemptResultKind::Failure, error: Some(error.into()), output: None }
369 }
370
371 pub fn timeout(error: impl Into<String>) -> Self {
373 Self { result: AttemptResultKind::Timeout, error: Some(error.into()), output: None }
374 }
375
376 pub fn suspended() -> Self {
380 Self { result: AttemptResultKind::Suspended, error: None, output: None }
381 }
382
383 pub fn suspended_with_output(output: Vec<u8>) -> Self {
388 let output = if output.is_empty() { None } else { Some(output) };
389 Self { result: AttemptResultKind::Suspended, error: None, output }
390 }
391
392 pub fn from_raw_parts(
404 result: AttemptResultKind,
405 error: Option<String>,
406 output: Option<Vec<u8>>,
407 ) -> Result<Self, AttemptOutcomeError> {
408 match result {
409 AttemptResultKind::Success | AttemptResultKind::Suspended => {
410 if let Some(err) = error {
411 return Err(AttemptOutcomeError::SuccessWithError { error: err });
412 }
413 }
414 AttemptResultKind::Failure | AttemptResultKind::Timeout => {
415 if error.is_none() {
416 return Err(AttemptOutcomeError::NonSuccessWithoutError { result });
417 }
418 if output.is_some() {
419 return Err(AttemptOutcomeError::NonSuccessWithOutput { result });
420 }
421 }
422 }
423 Ok(Self { result, error, output })
424 }
425
426 pub fn result(&self) -> AttemptResultKind {
428 self.result
429 }
430
431 pub fn error(&self) -> Option<&str> {
433 self.error.as_deref()
434 }
435
436 pub fn output(&self) -> Option<&[u8]> {
438 self.output.as_deref()
439 }
440
441 pub fn into_parts(self) -> (AttemptResultKind, Option<String>, Option<Vec<u8>>) {
443 (self.result, self.error, self.output)
444 }
445}
446
447#[derive(Debug, Clone, PartialEq, Eq)]
449pub struct AttemptFinishCommand {
450 sequence: u64,
451 run_id: RunId,
452 attempt_id: AttemptId,
453 outcome: AttemptOutcome,
454 timestamp: u64,
455}
456
457impl AttemptFinishCommand {
458 pub fn new(
460 sequence: u64,
461 run_id: RunId,
462 attempt_id: AttemptId,
463 outcome: AttemptOutcome,
464 timestamp: u64,
465 ) -> Self {
466 Self { sequence, run_id, attempt_id, outcome, timestamp }
467 }
468
469 pub fn sequence(&self) -> u64 {
471 self.sequence
472 }
473
474 pub fn run_id(&self) -> RunId {
476 self.run_id
477 }
478
479 pub fn attempt_id(&self) -> AttemptId {
481 self.attempt_id
482 }
483
484 pub fn outcome(&self) -> &AttemptOutcome {
486 &self.outcome
487 }
488
489 pub fn timestamp(&self) -> u64 {
491 self.timestamp
492 }
493
494 pub fn result(&self) -> AttemptResultKind {
496 self.outcome.result
497 }
498
499 pub fn error(&self) -> Option<&str> {
501 self.outcome.error.as_deref()
502 }
503
504 pub fn output(&self) -> Option<&[u8]> {
506 self.outcome.output.as_deref()
507 }
508}
509
510macro_rules! lease_command_accessors {
512 () => {
513 pub fn sequence(&self) -> u64 {
515 self.sequence
516 }
517
518 pub fn run_id(&self) -> RunId {
520 self.run_id
521 }
522
523 pub fn owner(&self) -> &str {
525 &self.owner
526 }
527
528 pub fn expiry(&self) -> u64 {
530 self.expiry
531 }
532
533 pub fn timestamp(&self) -> u64 {
535 self.timestamp
536 }
537 };
538}
539
540#[derive(Debug, Clone, PartialEq, Eq)]
542pub struct LeaseAcquireCommand {
543 sequence: u64,
544 run_id: RunId,
545 owner: String,
546 expiry: u64,
547 timestamp: u64,
548}
549
550impl LeaseAcquireCommand {
551 pub fn new(
553 sequence: u64,
554 run_id: RunId,
555 owner: impl Into<String>,
556 expiry: u64,
557 timestamp: u64,
558 ) -> Self {
559 let owner = owner.into();
560 debug_assert!(!owner.is_empty(), "lease owner must not be empty");
561 Self { sequence, run_id, owner, expiry, timestamp }
562 }
563
564 lease_command_accessors!();
565}
566
567#[derive(Debug, Clone, PartialEq, Eq)]
569pub struct LeaseHeartbeatCommand {
570 sequence: u64,
571 run_id: RunId,
572 owner: String,
573 expiry: u64,
574 timestamp: u64,
575}
576
577impl LeaseHeartbeatCommand {
578 pub fn new(
580 sequence: u64,
581 run_id: RunId,
582 owner: impl Into<String>,
583 expiry: u64,
584 timestamp: u64,
585 ) -> Self {
586 let owner = owner.into();
587 debug_assert!(!owner.is_empty(), "lease owner must not be empty");
588 Self { sequence, run_id, owner, expiry, timestamp }
589 }
590
591 lease_command_accessors!();
592}
593
594#[derive(Debug, Clone, PartialEq, Eq)]
596pub struct LeaseExpireCommand {
597 sequence: u64,
598 run_id: RunId,
599 owner: String,
600 expiry: u64,
601 timestamp: u64,
602}
603
604impl LeaseExpireCommand {
605 pub fn new(
607 sequence: u64,
608 run_id: RunId,
609 owner: impl Into<String>,
610 expiry: u64,
611 timestamp: u64,
612 ) -> Self {
613 let owner = owner.into();
614 debug_assert!(!owner.is_empty(), "lease owner must not be empty");
615 Self { sequence, run_id, owner, expiry, timestamp }
616 }
617
618 lease_command_accessors!();
619}
620
621#[derive(Debug, Clone, PartialEq, Eq)]
623pub struct LeaseReleaseCommand {
624 sequence: u64,
625 run_id: RunId,
626 owner: String,
627 expiry: u64,
628 timestamp: u64,
629}
630
631impl LeaseReleaseCommand {
632 pub fn new(
634 sequence: u64,
635 run_id: RunId,
636 owner: impl Into<String>,
637 expiry: u64,
638 timestamp: u64,
639 ) -> Self {
640 let owner = owner.into();
641 debug_assert!(!owner.is_empty(), "lease owner must not be empty");
642 Self { sequence, run_id, owner, expiry, timestamp }
643 }
644
645 lease_command_accessors!();
646}
647
648#[derive(Debug, Clone, Copy, PartialEq, Eq)]
650pub struct TaskCancelCommand {
651 sequence: u64,
652 task_id: TaskId,
653 timestamp: u64,
654}
655
656impl TaskCancelCommand {
657 pub fn new(sequence: u64, task_id: TaskId, timestamp: u64) -> Self {
659 Self { sequence, task_id, timestamp }
660 }
661
662 pub fn sequence(&self) -> u64 {
664 self.sequence
665 }
666
667 pub fn task_id(&self) -> TaskId {
669 self.task_id
670 }
671
672 pub fn timestamp(&self) -> u64 {
674 self.timestamp
675 }
676}
677
678#[derive(Debug, Clone, PartialEq, Eq)]
680pub struct DependencyDeclareCommand {
681 sequence: u64,
682 task_id: TaskId,
683 depends_on: Vec<TaskId>,
684 timestamp: u64,
685}
686
687impl DependencyDeclareCommand {
688 pub fn new(sequence: u64, task_id: TaskId, depends_on: Vec<TaskId>, timestamp: u64) -> Self {
696 debug_assert!(!depends_on.is_empty());
697 Self { sequence, task_id, depends_on, timestamp }
698 }
699
700 pub fn sequence(&self) -> u64 {
702 self.sequence
703 }
704
705 pub fn task_id(&self) -> TaskId {
707 self.task_id
708 }
709
710 pub fn depends_on(&self) -> &[TaskId] {
712 &self.depends_on
713 }
714
715 pub fn timestamp(&self) -> u64 {
717 self.timestamp
718 }
719}
720
721#[derive(Debug, Clone, PartialEq, Eq)]
723#[must_use]
724pub struct MutationOutcome {
725 sequence: u64,
726 applied: AppliedMutation,
727}
728
729impl MutationOutcome {
730 pub fn new(sequence: u64, applied: AppliedMutation) -> Self {
732 Self { sequence, applied }
733 }
734
735 pub fn sequence(&self) -> u64 {
737 self.sequence
738 }
739
740 pub fn applied(&self) -> &AppliedMutation {
742 &self.applied
743 }
744}
745
746#[derive(Debug, Clone, PartialEq, Eq)]
748pub enum AppliedMutation {
749 TaskCreate {
751 task_id: TaskId,
753 },
754 RunCreate {
756 run_id: RunId,
758 task_id: TaskId,
760 },
761 RunStateTransition {
763 run_id: RunId,
765 previous_state: RunState,
767 new_state: RunState,
769 },
770 AttemptStart {
772 run_id: RunId,
774 attempt_id: AttemptId,
776 },
777 AttemptFinish {
779 run_id: RunId,
781 attempt_id: AttemptId,
783 outcome: AttemptOutcome,
785 },
786 LeaseAcquire {
788 run_id: RunId,
790 owner: String,
792 expiry: u64,
794 },
795 LeaseHeartbeat {
797 run_id: RunId,
799 owner: String,
801 expiry: u64,
803 },
804 LeaseExpire {
806 run_id: RunId,
808 owner: String,
810 expiry: u64,
812 },
813 LeaseRelease {
815 run_id: RunId,
817 owner: String,
819 expiry: u64,
821 },
822 EnginePause,
824 EngineResume,
826 TaskCancel {
828 task_id: TaskId,
830 },
831 DependencyDeclare {
833 task_id: TaskId,
835 depends_on: Vec<TaskId>,
837 },
838 RunSuspend {
840 run_id: RunId,
842 },
843 RunResume {
845 run_id: RunId,
847 },
848 BudgetAllocate {
850 task_id: TaskId,
852 dimension: BudgetDimension,
854 limit: u64,
856 },
857 BudgetConsume {
859 task_id: TaskId,
861 dimension: BudgetDimension,
863 amount: u64,
865 },
866 BudgetReplenish {
868 task_id: TaskId,
870 dimension: BudgetDimension,
872 new_limit: u64,
874 },
875 SubscriptionCreate {
877 subscription_id: SubscriptionId,
879 task_id: TaskId,
881 },
882 SubscriptionCancel {
884 subscription_id: SubscriptionId,
886 },
887 SubscriptionTrigger {
889 subscription_id: SubscriptionId,
891 },
892 NoOp,
894}
895
896pub trait MutationAuthority {
900 type Error;
902
903 fn submit_command(
905 &mut self,
906 command: MutationCommand,
907 durability: DurabilityPolicy,
908 ) -> Result<MutationOutcome, Self::Error>;
909}
910
911#[derive(Debug, Clone, PartialEq, Eq)]
913pub struct RunSuspendCommand {
914 sequence: u64,
915 run_id: RunId,
916 reason: Option<String>,
917 timestamp: u64,
918}
919
920impl RunSuspendCommand {
921 pub fn new(sequence: u64, run_id: RunId, reason: Option<String>, timestamp: u64) -> Self {
923 Self { sequence, run_id, reason, timestamp }
924 }
925
926 pub fn sequence(&self) -> u64 {
928 self.sequence
929 }
930
931 pub fn run_id(&self) -> RunId {
933 self.run_id
934 }
935
936 pub fn reason(&self) -> Option<&str> {
938 self.reason.as_deref()
939 }
940
941 pub fn timestamp(&self) -> u64 {
943 self.timestamp
944 }
945}
946
947#[derive(Debug, Clone, Copy, PartialEq, Eq)]
949pub struct RunResumeCommand {
950 sequence: u64,
951 run_id: RunId,
952 timestamp: u64,
953}
954
955impl RunResumeCommand {
956 pub fn new(sequence: u64, run_id: RunId, timestamp: u64) -> Self {
958 Self { sequence, run_id, timestamp }
959 }
960
961 pub fn sequence(&self) -> u64 {
963 self.sequence
964 }
965
966 pub fn run_id(&self) -> RunId {
968 self.run_id
969 }
970
971 pub fn timestamp(&self) -> u64 {
973 self.timestamp
974 }
975}
976
977#[derive(Debug, Clone, Copy, PartialEq, Eq)]
979pub struct BudgetAllocateCommand {
980 sequence: u64,
981 task_id: TaskId,
982 dimension: BudgetDimension,
983 limit: u64,
984 timestamp: u64,
985}
986
987impl BudgetAllocateCommand {
988 pub fn new(
990 sequence: u64,
991 task_id: TaskId,
992 dimension: BudgetDimension,
993 limit: u64,
994 timestamp: u64,
995 ) -> Self {
996 debug_assert!(limit > 0, "budget limit must be greater than zero");
997 Self { sequence, task_id, dimension, limit, timestamp }
998 }
999
1000 pub fn sequence(&self) -> u64 {
1002 self.sequence
1003 }
1004
1005 pub fn task_id(&self) -> TaskId {
1007 self.task_id
1008 }
1009
1010 pub fn dimension(&self) -> BudgetDimension {
1012 self.dimension
1013 }
1014
1015 pub fn limit(&self) -> u64 {
1017 self.limit
1018 }
1019
1020 pub fn timestamp(&self) -> u64 {
1022 self.timestamp
1023 }
1024}
1025
1026#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1028pub struct BudgetConsumeCommand {
1029 sequence: u64,
1030 task_id: TaskId,
1031 dimension: BudgetDimension,
1032 amount: u64,
1033 timestamp: u64,
1034}
1035
1036impl BudgetConsumeCommand {
1037 pub fn new(
1039 sequence: u64,
1040 task_id: TaskId,
1041 dimension: BudgetDimension,
1042 amount: u64,
1043 timestamp: u64,
1044 ) -> Self {
1045 debug_assert!(amount > 0, "budget consume amount must be greater than zero");
1046 Self { sequence, task_id, dimension, amount, timestamp }
1047 }
1048
1049 pub fn sequence(&self) -> u64 {
1051 self.sequence
1052 }
1053
1054 pub fn task_id(&self) -> TaskId {
1056 self.task_id
1057 }
1058
1059 pub fn dimension(&self) -> BudgetDimension {
1061 self.dimension
1062 }
1063
1064 pub fn amount(&self) -> u64 {
1066 self.amount
1067 }
1068
1069 pub fn timestamp(&self) -> u64 {
1071 self.timestamp
1072 }
1073}
1074
1075#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1077pub struct BudgetReplenishCommand {
1078 sequence: u64,
1079 task_id: TaskId,
1080 dimension: BudgetDimension,
1081 new_limit: u64,
1082 timestamp: u64,
1083}
1084
1085impl BudgetReplenishCommand {
1086 pub fn new(
1088 sequence: u64,
1089 task_id: TaskId,
1090 dimension: BudgetDimension,
1091 new_limit: u64,
1092 timestamp: u64,
1093 ) -> Self {
1094 debug_assert!(new_limit > 0, "budget replenish limit must be greater than zero");
1095 Self { sequence, task_id, dimension, new_limit, timestamp }
1096 }
1097
1098 pub fn sequence(&self) -> u64 {
1100 self.sequence
1101 }
1102
1103 pub fn task_id(&self) -> TaskId {
1105 self.task_id
1106 }
1107
1108 pub fn dimension(&self) -> BudgetDimension {
1110 self.dimension
1111 }
1112
1113 pub fn new_limit(&self) -> u64 {
1115 self.new_limit
1116 }
1117
1118 pub fn timestamp(&self) -> u64 {
1120 self.timestamp
1121 }
1122}
1123
1124#[derive(Debug, Clone, PartialEq, Eq)]
1126pub struct SubscriptionCreateCommand {
1127 sequence: u64,
1128 subscription_id: SubscriptionId,
1129 task_id: TaskId,
1130 filter: EventFilter,
1131 timestamp: u64,
1132}
1133
1134impl SubscriptionCreateCommand {
1135 pub fn new(
1137 sequence: u64,
1138 subscription_id: SubscriptionId,
1139 task_id: TaskId,
1140 filter: EventFilter,
1141 timestamp: u64,
1142 ) -> Self {
1143 if let EventFilter::BudgetThreshold { threshold_pct, .. } = &filter {
1144 debug_assert!(
1145 *threshold_pct <= 100,
1146 "budget threshold percentage must be 0-100, got {threshold_pct}"
1147 );
1148 }
1149 if let EventFilter::Custom { key } = &filter {
1150 debug_assert!(!key.is_empty(), "custom event key must not be empty");
1151 }
1152 Self { sequence, subscription_id, task_id, filter, timestamp }
1153 }
1154
1155 pub fn sequence(&self) -> u64 {
1157 self.sequence
1158 }
1159
1160 pub fn subscription_id(&self) -> SubscriptionId {
1162 self.subscription_id
1163 }
1164
1165 pub fn task_id(&self) -> TaskId {
1167 self.task_id
1168 }
1169
1170 pub fn filter(&self) -> &EventFilter {
1172 &self.filter
1173 }
1174
1175 pub fn timestamp(&self) -> u64 {
1177 self.timestamp
1178 }
1179}
1180
1181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1183pub struct SubscriptionCancelCommand {
1184 sequence: u64,
1185 subscription_id: SubscriptionId,
1186 timestamp: u64,
1187}
1188
1189impl SubscriptionCancelCommand {
1190 pub fn new(sequence: u64, subscription_id: SubscriptionId, timestamp: u64) -> Self {
1192 Self { sequence, subscription_id, timestamp }
1193 }
1194
1195 pub fn sequence(&self) -> u64 {
1197 self.sequence
1198 }
1199
1200 pub fn subscription_id(&self) -> SubscriptionId {
1202 self.subscription_id
1203 }
1204
1205 pub fn timestamp(&self) -> u64 {
1207 self.timestamp
1208 }
1209}
1210
1211#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1213pub struct SubscriptionTriggerCommand {
1214 sequence: u64,
1215 subscription_id: SubscriptionId,
1216 timestamp: u64,
1217}
1218
1219impl SubscriptionTriggerCommand {
1220 pub fn new(sequence: u64, subscription_id: SubscriptionId, timestamp: u64) -> Self {
1222 Self { sequence, subscription_id, timestamp }
1223 }
1224
1225 pub fn sequence(&self) -> u64 {
1227 self.sequence
1228 }
1229
1230 pub fn subscription_id(&self) -> SubscriptionId {
1232 self.subscription_id
1233 }
1234
1235 pub fn timestamp(&self) -> u64 {
1237 self.timestamp
1238 }
1239}
1240
1241#[derive(Debug, Clone, PartialEq, Eq)]
1245pub struct ActorRegisterCommand {
1246 sequence: u64,
1247 registration: ActorRegistration,
1248 timestamp: u64,
1249}
1250
1251impl ActorRegisterCommand {
1252 pub fn new(sequence: u64, registration: ActorRegistration, timestamp: u64) -> Self {
1254 Self { sequence, registration, timestamp }
1255 }
1256
1257 pub fn sequence(&self) -> u64 {
1259 self.sequence
1260 }
1261 pub fn registration(&self) -> &ActorRegistration {
1263 &self.registration
1264 }
1265 pub fn timestamp(&self) -> u64 {
1267 self.timestamp
1268 }
1269}
1270
1271#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1273pub struct ActorDeregisterCommand {
1274 sequence: u64,
1275 actor_id: ActorId,
1276 timestamp: u64,
1277}
1278
1279impl ActorDeregisterCommand {
1280 pub fn new(sequence: u64, actor_id: ActorId, timestamp: u64) -> Self {
1282 Self { sequence, actor_id, timestamp }
1283 }
1284 pub fn sequence(&self) -> u64 {
1286 self.sequence
1287 }
1288 pub fn actor_id(&self) -> ActorId {
1290 self.actor_id
1291 }
1292 pub fn timestamp(&self) -> u64 {
1294 self.timestamp
1295 }
1296}
1297
1298#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1300pub struct ActorHeartbeatCommand {
1301 sequence: u64,
1302 actor_id: ActorId,
1303 timestamp: u64,
1304}
1305
1306impl ActorHeartbeatCommand {
1307 pub fn new(sequence: u64, actor_id: ActorId, timestamp: u64) -> Self {
1309 Self { sequence, actor_id, timestamp }
1310 }
1311 pub fn sequence(&self) -> u64 {
1313 self.sequence
1314 }
1315 pub fn actor_id(&self) -> ActorId {
1317 self.actor_id
1318 }
1319 pub fn timestamp(&self) -> u64 {
1321 self.timestamp
1322 }
1323}
1324
1325#[derive(Debug, Clone, PartialEq, Eq)]
1327pub struct TenantCreateCommand {
1328 sequence: u64,
1329 registration: TenantRegistration,
1330 timestamp: u64,
1331}
1332
1333impl TenantCreateCommand {
1334 pub fn new(sequence: u64, registration: TenantRegistration, timestamp: u64) -> Self {
1336 Self { sequence, registration, timestamp }
1337 }
1338 pub fn sequence(&self) -> u64 {
1340 self.sequence
1341 }
1342 pub fn registration(&self) -> &TenantRegistration {
1344 &self.registration
1345 }
1346 pub fn timestamp(&self) -> u64 {
1348 self.timestamp
1349 }
1350}
1351
1352#[derive(Debug, Clone, PartialEq, Eq)]
1354pub struct RoleAssignCommand {
1355 sequence: u64,
1356 actor_id: ActorId,
1357 role: Role,
1358 tenant_id: TenantId,
1359 timestamp: u64,
1360}
1361
1362impl RoleAssignCommand {
1363 pub fn new(
1365 sequence: u64,
1366 actor_id: ActorId,
1367 role: Role,
1368 tenant_id: TenantId,
1369 timestamp: u64,
1370 ) -> Self {
1371 Self { sequence, actor_id, role, tenant_id, timestamp }
1372 }
1373 pub fn sequence(&self) -> u64 {
1375 self.sequence
1376 }
1377 pub fn actor_id(&self) -> ActorId {
1379 self.actor_id
1380 }
1381 pub fn role(&self) -> &Role {
1383 &self.role
1384 }
1385 pub fn tenant_id(&self) -> TenantId {
1387 self.tenant_id
1388 }
1389 pub fn timestamp(&self) -> u64 {
1391 self.timestamp
1392 }
1393}
1394
1395#[derive(Debug, Clone, PartialEq, Eq)]
1397pub struct CapabilityGrantCommand {
1398 sequence: u64,
1399 actor_id: ActorId,
1400 capability: Capability,
1401 tenant_id: TenantId,
1402 timestamp: u64,
1403}
1404
1405impl CapabilityGrantCommand {
1406 pub fn new(
1408 sequence: u64,
1409 actor_id: ActorId,
1410 capability: Capability,
1411 tenant_id: TenantId,
1412 timestamp: u64,
1413 ) -> Self {
1414 Self { sequence, actor_id, capability, tenant_id, timestamp }
1415 }
1416 pub fn sequence(&self) -> u64 {
1418 self.sequence
1419 }
1420 pub fn actor_id(&self) -> ActorId {
1422 self.actor_id
1423 }
1424 pub fn capability(&self) -> &Capability {
1426 &self.capability
1427 }
1428 pub fn tenant_id(&self) -> TenantId {
1430 self.tenant_id
1431 }
1432 pub fn timestamp(&self) -> u64 {
1434 self.timestamp
1435 }
1436}
1437
1438#[derive(Debug, Clone, PartialEq, Eq)]
1440pub struct CapabilityRevokeCommand {
1441 sequence: u64,
1442 actor_id: ActorId,
1443 capability: Capability,
1444 tenant_id: TenantId,
1445 timestamp: u64,
1446}
1447
1448impl CapabilityRevokeCommand {
1449 pub fn new(
1451 sequence: u64,
1452 actor_id: ActorId,
1453 capability: Capability,
1454 tenant_id: TenantId,
1455 timestamp: u64,
1456 ) -> Self {
1457 Self { sequence, actor_id, capability, tenant_id, timestamp }
1458 }
1459 pub fn sequence(&self) -> u64 {
1461 self.sequence
1462 }
1463 pub fn actor_id(&self) -> ActorId {
1465 self.actor_id
1466 }
1467 pub fn capability(&self) -> &Capability {
1469 &self.capability
1470 }
1471 pub fn tenant_id(&self) -> TenantId {
1473 self.tenant_id
1474 }
1475 pub fn timestamp(&self) -> u64 {
1477 self.timestamp
1478 }
1479}
1480
1481#[derive(Debug, Clone, PartialEq, Eq)]
1483pub struct LedgerAppendCommand {
1484 sequence: u64,
1485 entry: LedgerEntry,
1486 timestamp: u64,
1487}
1488
1489impl LedgerAppendCommand {
1490 pub fn new(sequence: u64, entry: LedgerEntry, timestamp: u64) -> Self {
1492 Self { sequence, entry, timestamp }
1493 }
1494 pub fn sequence(&self) -> u64 {
1496 self.sequence
1497 }
1498 pub fn entry(&self) -> &LedgerEntry {
1500 &self.entry
1501 }
1502 pub fn timestamp(&self) -> u64 {
1504 self.timestamp
1505 }
1506}