termivar_scanner/decision_runner/
receipts.rs1use super::{
4 DecisionActionOrigin, DecisionExecutionFailureKind, DecisionExecutionLimits,
5 DecisionExecutionRequest, DecisionExecutionStage, DecisionLoopCommand, DecisionOutcomeReport,
6 DecisionPlanningReport, Evidence, KnowledgeSnapshot, KnowledgeWrite, RuntimeLimitExceeded,
7 Serialize, VerificationCase,
8};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
16pub struct DecisionExecutionFailureReceipt {
17 pub(super) request: DecisionExecutionRequest,
18 pub(super) executor_id: String,
19 pub(super) diagnostic: String,
20 pub(super) kind: DecisionExecutionFailureKind,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub(super) runtime_limit: Option<RuntimeLimitExceeded>,
23}
24
25impl DecisionExecutionFailureReceipt {
26 pub fn request(&self) -> &DecisionExecutionRequest {
28 &self.request
29 }
30
31 pub fn case(&self) -> &VerificationCase {
33 self.request.case()
34 }
35
36 pub fn action_id(&self) -> &str {
38 self.request.case().action_id()
39 }
40
41 pub fn stage(&self) -> DecisionExecutionStage {
43 self.request.stage()
44 }
45
46 pub fn origin(&self) -> Option<DecisionActionOrigin> {
48 self.request.origin()
49 }
50
51 pub fn delay_ms(&self) -> Option<u64> {
53 self.request.delay_ms()
54 }
55
56 pub fn limits(&self) -> DecisionExecutionLimits {
58 self.request.limits()
59 }
60
61 pub fn executor_id(&self) -> &str {
63 &self.executor_id
64 }
65
66 pub fn diagnostic(&self) -> &str {
68 &self.diagnostic
69 }
70
71 pub fn kind(&self) -> DecisionExecutionFailureKind {
73 self.kind
74 }
75
76 pub fn runtime_limit(&self) -> Option<&RuntimeLimitExceeded> {
78 self.runtime_limit.as_ref()
79 }
80}
81
82#[derive(Debug, Clone)]
84pub struct DecisionEvidenceReceipt {
85 pub(super) case: VerificationCase,
86 pub(super) stage: DecisionExecutionStage,
87 pub(super) executor_id: String,
88 pub(super) evidence: Vec<Evidence>,
89 pub(super) writes: Vec<KnowledgeWrite>,
90 pub(super) baseline: Option<KnowledgeSnapshot>,
91 pub(super) after_execution: KnowledgeSnapshot,
92}
93
94impl DecisionEvidenceReceipt {
95 pub fn case(&self) -> &VerificationCase {
97 &self.case
98 }
99
100 pub fn stage(&self) -> DecisionExecutionStage {
102 self.stage
103 }
104
105 pub fn executor_id(&self) -> &str {
107 &self.executor_id
108 }
109
110 pub fn evidence(&self) -> &[Evidence] {
112 &self.evidence
113 }
114
115 pub fn writes(&self) -> &[KnowledgeWrite] {
117 &self.writes
118 }
119
120 pub fn write_set(&self) -> impl ExactSizeIterator<Item = (&Evidence, KnowledgeWrite)> + '_ {
125 debug_assert_eq!(self.evidence.len(), self.writes.len());
126 self.evidence.iter().zip(self.writes.iter().copied())
127 }
128
129 pub fn baseline(&self) -> Option<&KnowledgeSnapshot> {
131 self.baseline.as_ref()
132 }
133
134 pub fn after_execution(&self) -> &KnowledgeSnapshot {
136 &self.after_execution
137 }
138
139 #[cfg(test)]
140 pub(crate) fn with_test_committed_batch(
141 &self,
142 evidence: Vec<Evidence>,
143 writes: Vec<KnowledgeWrite>,
144 after_execution: KnowledgeSnapshot,
145 ) -> Self {
146 Self {
147 case: self.case.clone(),
148 stage: self.stage,
149 executor_id: self.executor_id.clone(),
150 evidence,
151 writes,
152 baseline: self.baseline.clone(),
153 after_execution,
154 }
155 }
156}
157
158#[derive(Debug)]
160#[non_exhaustive]
161pub enum DecisionRunnerTurn {
162 Planning(Box<DecisionPlanningReport>),
164 Outcome {
166 evidence: Box<DecisionEvidenceReceipt>,
168 decision: Box<DecisionOutcomeReport>,
170 },
171 Terminal(DecisionLoopCommand),
173}