brainwires_autonomy/
error.rs1use thiserror::Error;
4
5#[derive(Error, Debug)]
7pub enum AutonomyError {
8 #[error("Safety stop: {0}")]
10 SafetyStop(String),
11
12 #[error("Budget exceeded: ${0:.2}")]
14 BudgetExceeded(f64),
15
16 #[error("Circuit breaker tripped after {0} consecutive failures")]
18 CircuitBreakerTripped(u32),
19
20 #[error("Diff limit exceeded: {0} lines")]
22 DiffLimitExceeded(u32),
23
24 #[error("Cycle limit reached: {0}")]
26 CycleLimitReached(u32),
27
28 #[error("Git error: {0}")]
30 GitError(String),
31
32 #[error("Forge error: {0}")]
34 ForgeError(String),
35
36 #[error("Webhook error: {0}")]
38 WebhookError(String),
39
40 #[error("Configuration error: {0}")]
42 ConfigError(String),
43
44 #[error("Agent error: {0}")]
46 AgentError(String),
47
48 #[error("Investigation error: {0}")]
50 InvestigationError(String),
51
52 #[error("Merge policy error: {0}")]
54 MergePolicyError(String),
55
56 #[error("Crash recovery error: {0}")]
58 CrashRecoveryError(String),
59
60 #[error("GPIO error: {0}")]
62 GpioError(String),
63
64 #[error("Scheduler error: {0}")]
66 SchedulerError(String),
67
68 #[error("Reactor error: {0}")]
70 ReactorError(String),
71
72 #[error("Service error: {0}")]
74 ServiceError(String),
75
76 #[error("{0}")]
78 Other(#[from] anyhow::Error),
79}
80
81pub type AutonomyResult<T> = Result<T, AutonomyError>;
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn display_safety_stop() {
90 let err = AutonomyError::SafetyStop("test reason".to_string());
91 assert_eq!(err.to_string(), "Safety stop: test reason");
92 }
93
94 #[test]
95 fn display_budget_exceeded() {
96 let err = AutonomyError::BudgetExceeded(12.5);
97 assert_eq!(err.to_string(), "Budget exceeded: $12.50");
98 }
99
100 #[test]
101 fn display_circuit_breaker_tripped() {
102 let err = AutonomyError::CircuitBreakerTripped(5);
103 assert_eq!(
104 err.to_string(),
105 "Circuit breaker tripped after 5 consecutive failures"
106 );
107 }
108
109 #[test]
110 fn display_diff_limit_exceeded() {
111 let err = AutonomyError::DiffLimitExceeded(300);
112 assert_eq!(err.to_string(), "Diff limit exceeded: 300 lines");
113 }
114
115 #[test]
116 fn display_remaining_variants() {
117 assert_eq!(
118 AutonomyError::CycleLimitReached(10).to_string(),
119 "Cycle limit reached: 10"
120 );
121 assert_eq!(
122 AutonomyError::GitError("bad ref".to_string()).to_string(),
123 "Git error: bad ref"
124 );
125 assert_eq!(
126 AutonomyError::ForgeError("404".to_string()).to_string(),
127 "Forge error: 404"
128 );
129 assert_eq!(
130 AutonomyError::WebhookError("bad sig".to_string()).to_string(),
131 "Webhook error: bad sig"
132 );
133 assert_eq!(
134 AutonomyError::ConfigError("missing".to_string()).to_string(),
135 "Configuration error: missing"
136 );
137 assert_eq!(
138 AutonomyError::AgentError("timeout".to_string()).to_string(),
139 "Agent error: timeout"
140 );
141 assert_eq!(
142 AutonomyError::InvestigationError("parse".to_string()).to_string(),
143 "Investigation error: parse"
144 );
145 assert_eq!(
146 AutonomyError::MergePolicyError("blocked".to_string()).to_string(),
147 "Merge policy error: blocked"
148 );
149 }
150
151 #[test]
152 fn display_new_error_variants() {
153 assert_eq!(
154 AutonomyError::CrashRecoveryError("meta-crash".to_string()).to_string(),
155 "Crash recovery error: meta-crash"
156 );
157 assert_eq!(
158 AutonomyError::GpioError("pin busy".to_string()).to_string(),
159 "GPIO error: pin busy"
160 );
161 assert_eq!(
162 AutonomyError::SchedulerError("bad cron".to_string()).to_string(),
163 "Scheduler error: bad cron"
164 );
165 assert_eq!(
166 AutonomyError::ReactorError("watch failed".to_string()).to_string(),
167 "Reactor error: watch failed"
168 );
169 assert_eq!(
170 AutonomyError::ServiceError("denied".to_string()).to_string(),
171 "Service error: denied"
172 );
173 }
174}