Skip to main content

lsp_max_protocol/
hooks.rs

1use crate::{
2    ConformanceVector, InstanceId, LawAxis, MaxDiagnostic, PolicyState, Receipt, RepairAction,
3    SnapshotId,
4};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8pub struct HookDescriptor {
9    pub hook_id: String,
10    pub name: String,
11    pub description: String,
12    pub axes: Vec<LawAxis>,
13    pub trigger_law: LawAxis,
14    pub input_type: String,
15    pub output_type: String,
16    pub failure_mode: String,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize, Default)]
20pub struct HookGraphNode {
21    pub node_id: String,
22    pub hook: HookDescriptor,
23    pub predecessors: Vec<String>,
24    pub successors: Vec<String>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize, Default)]
28pub struct ChainDescriptor {
29    pub chain_id: String,
30    pub nodes: Vec<HookGraphNode>,
31    pub law_axis: LawAxis,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize, Default)]
35pub struct PropagationResult {
36    pub propagation_id: String,
37    pub affected_nodes: Vec<String>,
38    pub receipts: Vec<Receipt>,
39    pub success: bool,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize, Default)]
43pub struct AutonomicLoopStatus {
44    pub loop_id: String,
45    pub active: bool,
46    pub iteration_count: u64,
47    pub last_receipt: Option<Receipt>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct ManifoldSnapshot {
52    pub snapshot_id: SnapshotId,
53    pub conformance: ConformanceVector,
54    pub hooks: Vec<HookDescriptor>,
55    pub chains: Vec<ChainDescriptor>,
56    pub receipts: Vec<Receipt>,
57}
58
59impl Default for ManifoldSnapshot {
60    fn default() -> Self {
61        Self {
62            snapshot_id: SnapshotId(String::new()),
63            conformance: ConformanceVector::default(),
64            hooks: Vec::new(),
65            chains: Vec::new(),
66            receipts: Vec::new(),
67        }
68    }
69}
70
71/// Admission decision — must be Admitted, Refused, or Unknown. Never a bool.
72#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
73pub enum AdmissionDecision {
74    Admitted,
75    Refused,
76    #[default]
77    Unknown,
78}
79
80impl From<bool> for AdmissionDecision {
81    fn from(b: bool) -> Self {
82        if b {
83            AdmissionDecision::Admitted
84        } else {
85            AdmissionDecision::Refused
86        }
87    }
88}
89
90impl From<AdmissionDecision> for bool {
91    fn from(d: AdmissionDecision) -> bool {
92        matches!(d, AdmissionDecision::Admitted)
93    }
94}
95
96impl std::fmt::Display for AdmissionDecision {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        write!(f, "{:?}", self)
99    }
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize, Default)]
103pub struct AdmissionResult {
104    pub decision: AdmissionDecision,
105    pub law_axis: LawAxis,
106    pub rationale: String,
107    pub receipt: Option<Receipt>,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct RefusalResult {
112    pub law_axis: LawAxis,
113    pub rationale: String,
114    pub receipt: Receipt,
115    pub repair_actions: Vec<RepairAction>,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize, Default)]
119pub struct LawfulTransitionResult {
120    pub from_phase: String,
121    pub to_phase: String,
122    pub lawful: bool,
123    pub violated_laws: Vec<LawAxis>,
124    pub receipt: Option<Receipt>,
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize, Default)]
128pub struct ReplayResult {
129    pub replay_id: String,
130    pub events_replayed: u64,
131    pub conformance: ConformanceVector,
132    pub receipts: Vec<Receipt>,
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize, Default)]
136pub struct ReleaseActuationResult {
137    pub released: bool,
138    pub conformance: ConformanceVector,
139    pub blocking_axes: Vec<LawAxis>,
140    pub receipt: Option<Receipt>,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
144pub enum HookEvent {
145    StateTransition {
146        instance_id: InstanceId,
147        from_phase: String,
148        to_phase: String,
149    },
150    DiagnosticEmitted {
151        instance_id: InstanceId,
152        diagnostic: Box<MaxDiagnostic>,
153    },
154    DiagnosticCleared {
155        instance_id: InstanceId,
156        diagnostic_id: String,
157    },
158    ReceiptEmitted {
159        instance_id: InstanceId,
160        receipt: Receipt,
161    },
162    PolicyStateChanged {
163        instance_id: InstanceId,
164        from_state: PolicyState,
165        to_state: PolicyState,
166    },
167    BoundedActionExecuted {
168        instance_id: InstanceId,
169        action_id: String,
170        description: String,
171    },
172    InstanceReset {
173        instance_id: InstanceId,
174    },
175}
176
177#[cfg(test)]
178mod tests {
179    use super::*;
180
181    #[test]
182    fn admission_decision_from_bool() {
183        assert_eq!(AdmissionDecision::from(true), AdmissionDecision::Admitted);
184        assert_eq!(AdmissionDecision::from(false), AdmissionDecision::Refused);
185    }
186
187    #[test]
188    fn admission_decision_into_bool() {
189        assert!(bool::from(AdmissionDecision::Admitted));
190        assert!(!bool::from(AdmissionDecision::Refused));
191        assert!(!bool::from(AdmissionDecision::Unknown));
192    }
193}