1use serde_json::json;
4
5use crate::coroutine::Fault;
6use crate::effect::{infer_effect_interface_and_operation, EffectTraceEntry};
7use crate::engine::ObsEvent;
8use crate::output_condition::{
9 verify_output_condition, OutputConditionCheck, OutputConditionHint, OutputConditionMeta,
10 OutputConditionPolicy,
11};
12
13pub(crate) fn apply_output_condition_gate<RecordCheck, RecordEvent>(
15 policy: &OutputConditionPolicy,
16 mut record_check: RecordCheck,
17 mut record_event: RecordEvent,
18 tick: u64,
19 output_hint: Option<OutputConditionHint>,
20) -> Result<(), Fault>
21where
22 RecordCheck: FnMut(OutputConditionCheck),
23 RecordEvent: FnMut(ObsEvent),
24{
25 let digest = "machine.output_digest.unspecified".to_string();
26 let meta = match output_hint {
27 Some(h) => OutputConditionMeta::from_hint(h, digest),
28 None => OutputConditionMeta::default_observable(digest),
29 };
30 let passed = verify_output_condition(policy, &meta);
31 record_check(OutputConditionCheck {
32 meta: meta.clone(),
33 passed,
34 });
35 record_event(ObsEvent::OutputConditionChecked {
36 tick,
37 predicate_ref: meta.predicate_ref.clone(),
38 witness_ref: meta.witness_ref.clone(),
39 output_digest: meta.output_digest.clone(),
40 passed,
41 });
42 if passed {
43 Ok(())
44 } else {
45 Err(Fault::OutputCondition {
46 predicate_ref: meta.predicate_ref,
47 })
48 }
49}
50
51#[allow(clippy::too_many_lines)]
53pub(crate) fn effect_trace_entry_for_event(
54 ev: &ObsEvent,
55 effect_id: u64,
56 handler_identity: &str,
57 ordering_key: u64,
58) -> Option<EffectTraceEntry> {
59 match ev {
60 ObsEvent::Sent {
61 session,
62 from,
63 to,
64 label,
65 ..
66 } => {
67 let effect_kind = "send_decision".to_string();
68 let (effect_interface, effect_operation) =
69 infer_effect_interface_and_operation(&effect_kind);
70 Some(EffectTraceEntry {
71 effect_id,
72 effect_kind,
73 inputs: json!({
74 "session": session,
75 "from": from,
76 "to": to,
77 "label": label,
78 }),
79 outputs: json!({"committed": true}),
80 handler_identity: handler_identity.to_string(),
81 effect_interface,
82 effect_operation,
83 ordering_key,
84 topology: None,
85 })
86 }
87 ObsEvent::Received {
88 session,
89 from,
90 to,
91 label,
92 ..
93 } => {
94 let effect_kind = "handle_recv".to_string();
95 let (effect_interface, effect_operation) =
96 infer_effect_interface_and_operation(&effect_kind);
97 Some(EffectTraceEntry {
98 effect_id,
99 effect_kind,
100 inputs: json!({
101 "session": session,
102 "from": from,
103 "to": to,
104 "label": label,
105 }),
106 outputs: json!({"committed": true}),
107 handler_identity: handler_identity.to_string(),
108 effect_interface,
109 effect_operation,
110 ordering_key,
111 topology: None,
112 })
113 }
114 ObsEvent::Invoked { coro_id, role, .. } => {
115 let effect_kind = "invoke_step".to_string();
116 let (effect_interface, effect_operation) =
117 infer_effect_interface_and_operation(&effect_kind);
118 Some(EffectTraceEntry {
119 effect_id,
120 effect_kind,
121 inputs: json!({
122 "coro_id": coro_id,
123 "role": role,
124 }),
125 outputs: json!({"ok": true}),
126 handler_identity: handler_identity.to_string(),
127 effect_interface,
128 effect_operation,
129 ordering_key,
130 topology: None,
131 })
132 }
133 ObsEvent::Acquired {
134 session,
135 role,
136 layer,
137 ..
138 } => {
139 let effect_kind = "handle_acquire".to_string();
140 let (effect_interface, effect_operation) =
141 infer_effect_interface_and_operation(&effect_kind);
142 Some(EffectTraceEntry {
143 effect_id,
144 effect_kind,
145 inputs: json!({
146 "session": session,
147 "role": role,
148 "layer": layer,
149 }),
150 outputs: json!({"granted": true}),
151 handler_identity: handler_identity.to_string(),
152 effect_interface,
153 effect_operation,
154 ordering_key,
155 topology: None,
156 })
157 }
158 ObsEvent::Released {
159 session,
160 role,
161 layer,
162 ..
163 } => {
164 let effect_kind = "handle_release".to_string();
165 let (effect_interface, effect_operation) =
166 infer_effect_interface_and_operation(&effect_kind);
167 Some(EffectTraceEntry {
168 effect_id,
169 effect_kind,
170 inputs: json!({
171 "session": session,
172 "role": role,
173 "layer": layer,
174 }),
175 outputs: json!({"ok": true}),
176 handler_identity: handler_identity.to_string(),
177 effect_interface,
178 effect_operation,
179 ordering_key,
180 topology: None,
181 })
182 }
183 _ => None,
184 }
185}