Skip to main content

scud/attractor/
events.rs

1//! Pipeline execution events for observability.
2
3use serde::{Deserialize, Serialize};
4
5use super::outcome::StageStatus;
6
7/// Events emitted during pipeline execution.
8#[derive(Debug, Clone, Serialize, Deserialize)]
9#[serde(tag = "type", rename_all = "snake_case")]
10pub enum PipelineEvent {
11    /// Pipeline execution started.
12    PipelineStarted {
13        pipeline_name: String,
14        run_id: String,
15    },
16
17    /// A node has started executing.
18    NodeStarted {
19        node_id: String,
20        handler_type: String,
21    },
22
23    /// A node has completed.
24    NodeCompleted {
25        node_id: String,
26        status: StageStatus,
27        duration_ms: u64,
28    },
29
30    /// An edge was selected for traversal.
31    EdgeSelected {
32        from_node: String,
33        to_node: String,
34        edge_label: String,
35        selection_step: u8,
36    },
37
38    /// A retry is about to happen.
39    RetryScheduled {
40        node_id: String,
41        attempt: u32,
42        max_retries: u32,
43        delay_ms: u64,
44    },
45
46    /// A goal gate check was performed.
47    GoalGateCheck { node_id: String, satisfied: bool },
48
49    /// A checkpoint was saved.
50    CheckpointSaved { node_id: String },
51
52    /// Pipeline execution completed.
53    PipelineCompleted {
54        status: StageStatus,
55        total_duration_ms: u64,
56        nodes_executed: usize,
57    },
58
59    /// An error occurred.
60    Error {
61        node_id: Option<String>,
62        message: String,
63    },
64
65    /// Human input requested.
66    HumanInputRequested {
67        node_id: String,
68        question: String,
69        choices: Vec<String>,
70    },
71
72    /// Human input received.
73    HumanInputReceived { node_id: String, answer: String },
74}
75
76impl PipelineEvent {
77    pub fn pipeline_started(name: &str, run_id: &str) -> Self {
78        Self::PipelineStarted {
79            pipeline_name: name.to_string(),
80            run_id: run_id.to_string(),
81        }
82    }
83
84    pub fn node_started(id: &str, handler: &str) -> Self {
85        Self::NodeStarted {
86            node_id: id.to_string(),
87            handler_type: handler.to_string(),
88        }
89    }
90
91    pub fn node_completed(id: &str, status: StageStatus, duration_ms: u64) -> Self {
92        Self::NodeCompleted {
93            node_id: id.to_string(),
94            status,
95            duration_ms,
96        }
97    }
98
99    pub fn edge_selected(from: &str, to: &str, label: &str, step: u8) -> Self {
100        Self::EdgeSelected {
101            from_node: from.to_string(),
102            to_node: to.to_string(),
103            edge_label: label.to_string(),
104            selection_step: step,
105        }
106    }
107
108    pub fn error(node_id: Option<&str>, message: &str) -> Self {
109        Self::Error {
110            node_id: node_id.map(String::from),
111            message: message.to_string(),
112        }
113    }
114}