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 None,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
39#[serde(rename_all = "snake_case")]
40#[non_exhaustive]
41pub enum QueueMode {
42 None,
44 Fifo,
46 Coalesce,
48 Supersede,
50 Priority,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
56#[serde(rename_all = "snake_case")]
57#[non_exhaustive]
58pub enum ConsumePoint {
59 OnAccept,
61 OnApply,
63 OnRunStart,
65 OnRunComplete,
67 ExplicitAck,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73pub struct PolicyDecision {
74 pub apply_mode: ApplyMode,
76 pub wake_mode: WakeMode,
78 pub queue_mode: QueueMode,
80 pub consume_point: ConsumePoint,
82 #[serde(default = "default_true")]
84 pub record_transcript: bool,
85 #[serde(default = "default_true")]
87 pub emit_operator_content: bool,
88 pub policy_version: PolicyVersion,
90}
91
92fn default_true() -> bool {
93 true
94}
95
96#[cfg(test)]
97#[allow(clippy::unwrap_used)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn apply_mode_serde() {
103 for mode in [
104 ApplyMode::StageRunStart,
105 ApplyMode::StageRunBoundary,
106 ApplyMode::InjectNow,
107 ApplyMode::Ignore,
108 ] {
109 let json = serde_json::to_value(mode).unwrap();
110 let parsed: ApplyMode = serde_json::from_value(json).unwrap();
111 assert_eq!(mode, parsed);
112 }
113 }
114
115 #[test]
116 fn wake_mode_serde() {
117 for mode in [WakeMode::WakeIfIdle, WakeMode::None] {
118 let json = serde_json::to_value(mode).unwrap();
119 let parsed: WakeMode = serde_json::from_value(json).unwrap();
120 assert_eq!(mode, parsed);
121 }
122 }
123
124 #[test]
125 fn queue_mode_serde() {
126 for mode in [
127 QueueMode::None,
128 QueueMode::Fifo,
129 QueueMode::Coalesce,
130 QueueMode::Supersede,
131 QueueMode::Priority,
132 ] {
133 let json = serde_json::to_value(mode).unwrap();
134 let parsed: QueueMode = serde_json::from_value(json).unwrap();
135 assert_eq!(mode, parsed);
136 }
137 }
138
139 #[test]
140 fn consume_point_serde() {
141 for point in [
142 ConsumePoint::OnAccept,
143 ConsumePoint::OnApply,
144 ConsumePoint::OnRunStart,
145 ConsumePoint::OnRunComplete,
146 ConsumePoint::ExplicitAck,
147 ] {
148 let json = serde_json::to_value(point).unwrap();
149 let parsed: ConsumePoint = serde_json::from_value(json).unwrap();
150 assert_eq!(point, parsed);
151 }
152 }
153
154 #[test]
155 fn policy_decision_serde_roundtrip() {
156 let decision = PolicyDecision {
157 apply_mode: ApplyMode::StageRunStart,
158 wake_mode: WakeMode::WakeIfIdle,
159 queue_mode: QueueMode::Fifo,
160 consume_point: ConsumePoint::OnRunComplete,
161 record_transcript: true,
162 emit_operator_content: true,
163 policy_version: PolicyVersion(1),
164 };
165 let json = serde_json::to_value(&decision).unwrap();
166 let parsed: PolicyDecision = serde_json::from_value(json).unwrap();
167 assert_eq!(decision, parsed);
168 }
169
170 #[test]
171 fn policy_decision_ignore_on_accept() {
172 let decision = PolicyDecision {
173 apply_mode: ApplyMode::Ignore,
174 wake_mode: WakeMode::None,
175 queue_mode: QueueMode::None,
176 consume_point: ConsumePoint::OnAccept,
177 record_transcript: false,
178 emit_operator_content: false,
179 policy_version: PolicyVersion(1),
180 };
181 let json = serde_json::to_value(&decision).unwrap();
182 let parsed: PolicyDecision = serde_json::from_value(json).unwrap();
183 assert_eq!(decision, parsed);
184 }
185
186 #[test]
187 fn record_transcript_defaults_true() {
188 let json = serde_json::json!({
189 "apply_mode": "stage_run_start",
190 "wake_mode": "wake_if_idle",
191 "queue_mode": "fifo",
192 "consume_point": "on_run_complete",
193 "policy_version": 1
194 });
195 let parsed: PolicyDecision = serde_json::from_value(json).unwrap();
196 assert!(parsed.record_transcript);
197 assert!(parsed.emit_operator_content);
198 }
199}