use serde::{Deserialize, Serialize};
use crate::identifiers::PolicyVersion;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum ApplyMode {
StageRunStart,
StageRunBoundary,
InjectNow,
Ignore,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum WakeMode {
WakeIfIdle,
None,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum QueueMode {
None,
Fifo,
Coalesce,
Supersede,
Priority,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum ConsumePoint {
OnAccept,
OnApply,
OnRunStart,
OnRunComplete,
ExplicitAck,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum DrainPolicy {
#[default]
QueueNextTurn,
SteerBatch,
Immediate,
Ignore,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum RoutingDisposition {
#[default]
Queue,
Steer,
Immediate,
Drop,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PolicyDecision {
pub apply_mode: ApplyMode,
pub wake_mode: WakeMode,
pub queue_mode: QueueMode,
pub consume_point: ConsumePoint,
#[serde(default)]
pub drain_policy: DrainPolicy,
#[serde(default)]
pub routing_disposition: RoutingDisposition,
#[serde(default = "default_true")]
pub record_transcript: bool,
#[serde(default = "default_true")]
pub emit_operator_content: bool,
pub policy_version: PolicyVersion,
}
fn default_true() -> bool {
true
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn apply_mode_serde() {
for mode in [
ApplyMode::StageRunStart,
ApplyMode::StageRunBoundary,
ApplyMode::InjectNow,
ApplyMode::Ignore,
] {
let json = serde_json::to_value(mode).unwrap();
let parsed: ApplyMode = serde_json::from_value(json).unwrap();
assert_eq!(mode, parsed);
}
}
#[test]
fn wake_mode_serde() {
for mode in [WakeMode::WakeIfIdle, WakeMode::None] {
let json = serde_json::to_value(mode).unwrap();
let parsed: WakeMode = serde_json::from_value(json).unwrap();
assert_eq!(mode, parsed);
}
}
#[test]
fn queue_mode_serde() {
for mode in [
QueueMode::None,
QueueMode::Fifo,
QueueMode::Coalesce,
QueueMode::Supersede,
QueueMode::Priority,
] {
let json = serde_json::to_value(mode).unwrap();
let parsed: QueueMode = serde_json::from_value(json).unwrap();
assert_eq!(mode, parsed);
}
}
#[test]
fn consume_point_serde() {
for point in [
ConsumePoint::OnAccept,
ConsumePoint::OnApply,
ConsumePoint::OnRunStart,
ConsumePoint::OnRunComplete,
ConsumePoint::ExplicitAck,
] {
let json = serde_json::to_value(point).unwrap();
let parsed: ConsumePoint = serde_json::from_value(json).unwrap();
assert_eq!(point, parsed);
}
}
#[test]
fn drain_policy_serde() {
for policy in [
DrainPolicy::QueueNextTurn,
DrainPolicy::SteerBatch,
DrainPolicy::Immediate,
DrainPolicy::Ignore,
] {
let json = serde_json::to_value(policy).unwrap();
let parsed: DrainPolicy = serde_json::from_value(json).unwrap();
assert_eq!(policy, parsed);
}
}
#[test]
fn routing_disposition_serde() {
for disposition in [
RoutingDisposition::Queue,
RoutingDisposition::Steer,
RoutingDisposition::Immediate,
RoutingDisposition::Drop,
] {
let json = serde_json::to_value(disposition).unwrap();
let parsed: RoutingDisposition = serde_json::from_value(json).unwrap();
assert_eq!(disposition, parsed);
}
}
#[test]
fn policy_decision_serde_roundtrip() {
let decision = PolicyDecision {
apply_mode: ApplyMode::StageRunStart,
wake_mode: WakeMode::WakeIfIdle,
queue_mode: QueueMode::Fifo,
consume_point: ConsumePoint::OnRunComplete,
drain_policy: DrainPolicy::QueueNextTurn,
routing_disposition: RoutingDisposition::Queue,
record_transcript: true,
emit_operator_content: true,
policy_version: PolicyVersion(1),
};
let json = serde_json::to_value(&decision).unwrap();
let parsed: PolicyDecision = serde_json::from_value(json).unwrap();
assert_eq!(decision, parsed);
}
#[test]
fn policy_decision_ignore_on_accept() {
let decision = PolicyDecision {
apply_mode: ApplyMode::Ignore,
wake_mode: WakeMode::None,
queue_mode: QueueMode::None,
consume_point: ConsumePoint::OnAccept,
drain_policy: DrainPolicy::Ignore,
routing_disposition: RoutingDisposition::Drop,
record_transcript: false,
emit_operator_content: false,
policy_version: PolicyVersion(1),
};
let json = serde_json::to_value(&decision).unwrap();
let parsed: PolicyDecision = serde_json::from_value(json).unwrap();
assert_eq!(decision, parsed);
}
#[test]
fn record_transcript_defaults_true() {
let json = serde_json::json!({
"apply_mode": "stage_run_start",
"wake_mode": "wake_if_idle",
"queue_mode": "fifo",
"consume_point": "on_run_complete",
"policy_version": 1
});
let parsed: PolicyDecision = serde_json::from_value(json).unwrap();
assert!(parsed.record_transcript);
assert!(parsed.emit_operator_content);
}
}