1use serde::{Deserialize, Serialize};
8
9use crate::identifiers::PolicyVersion;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14#[non_exhaustive]
15pub enum ApplyMode {
16 StageRunStart,
18 StageRunBoundary,
20 InjectNow,
22 Ignore,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
28#[serde(rename_all = "snake_case")]
29#[non_exhaustive]
30pub enum WakeMode {
31 WakeIfIdle,
33 InterruptYielding,
36 None,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
42#[serde(rename_all = "snake_case")]
43#[non_exhaustive]
44pub enum QueueMode {
45 None,
47 Fifo,
49 Coalesce,
51 Supersede,
53 Priority,
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
59#[serde(rename_all = "snake_case")]
60#[non_exhaustive]
61pub enum ConsumePoint {
62 OnAccept,
64 OnApply,
66 OnRunStart,
68 OnRunComplete,
70 ExplicitAck,
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
76pub struct PolicyDecision {
77 pub apply_mode: ApplyMode,
79 pub wake_mode: WakeMode,
81 pub queue_mode: QueueMode,
83 pub consume_point: ConsumePoint,
85 #[serde(default = "default_true")]
87 pub record_transcript: bool,
88 #[serde(default = "default_true")]
90 pub emit_operator_content: bool,
91 pub policy_version: PolicyVersion,
93}
94
95fn default_true() -> bool {
96 true
97}
98
99#[cfg(test)]
100#[allow(clippy::unwrap_used)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn apply_mode_serde() {
106 for mode in [
107 ApplyMode::StageRunStart,
108 ApplyMode::StageRunBoundary,
109 ApplyMode::InjectNow,
110 ApplyMode::Ignore,
111 ] {
112 let json = serde_json::to_value(mode).unwrap();
113 let parsed: ApplyMode = serde_json::from_value(json).unwrap();
114 assert_eq!(mode, parsed);
115 }
116 }
117
118 #[test]
119 fn wake_mode_serde() {
120 for mode in [
121 WakeMode::WakeIfIdle,
122 WakeMode::InterruptYielding,
123 WakeMode::None,
124 ] {
125 let json = serde_json::to_value(mode).unwrap();
126 let parsed: WakeMode = serde_json::from_value(json).unwrap();
127 assert_eq!(mode, parsed);
128 }
129 }
130
131 #[test]
132 fn queue_mode_serde() {
133 for mode in [
134 QueueMode::None,
135 QueueMode::Fifo,
136 QueueMode::Coalesce,
137 QueueMode::Supersede,
138 QueueMode::Priority,
139 ] {
140 let json = serde_json::to_value(mode).unwrap();
141 let parsed: QueueMode = serde_json::from_value(json).unwrap();
142 assert_eq!(mode, parsed);
143 }
144 }
145
146 #[test]
147 fn consume_point_serde() {
148 for point in [
149 ConsumePoint::OnAccept,
150 ConsumePoint::OnApply,
151 ConsumePoint::OnRunStart,
152 ConsumePoint::OnRunComplete,
153 ConsumePoint::ExplicitAck,
154 ] {
155 let json = serde_json::to_value(point).unwrap();
156 let parsed: ConsumePoint = serde_json::from_value(json).unwrap();
157 assert_eq!(point, parsed);
158 }
159 }
160
161 #[test]
162 fn policy_decision_serde_roundtrip() {
163 let decision = PolicyDecision {
164 apply_mode: ApplyMode::StageRunStart,
165 wake_mode: WakeMode::WakeIfIdle,
166 queue_mode: QueueMode::Fifo,
167 consume_point: ConsumePoint::OnRunComplete,
168 record_transcript: true,
169 emit_operator_content: true,
170 policy_version: PolicyVersion(1),
171 };
172 let json = serde_json::to_value(&decision).unwrap();
173 let parsed: PolicyDecision = serde_json::from_value(json).unwrap();
174 assert_eq!(decision, parsed);
175 }
176
177 #[test]
178 fn policy_decision_ignore_on_accept() {
179 let decision = PolicyDecision {
180 apply_mode: ApplyMode::Ignore,
181 wake_mode: WakeMode::None,
182 queue_mode: QueueMode::None,
183 consume_point: ConsumePoint::OnAccept,
184 record_transcript: false,
185 emit_operator_content: false,
186 policy_version: PolicyVersion(1),
187 };
188 let json = serde_json::to_value(&decision).unwrap();
189 let parsed: PolicyDecision = serde_json::from_value(json).unwrap();
190 assert_eq!(decision, parsed);
191 }
192
193 #[test]
194 fn record_transcript_defaults_true() {
195 let json = serde_json::json!({
196 "apply_mode": "stage_run_start",
197 "wake_mode": "wake_if_idle",
198 "queue_mode": "fifo",
199 "consume_point": "on_run_complete",
200 "policy_version": 1
201 });
202 let parsed: PolicyDecision = serde_json::from_value(json).unwrap();
203 assert!(parsed.record_transcript);
204 assert!(parsed.emit_operator_content);
205 }
206}