Skip to main content

brainwires_autonomy/
error.rs

1//! Error types for the autonomy crate.
2
3use thiserror::Error;
4
5/// Top-level error type for autonomous operations.
6#[derive(Error, Debug)]
7pub enum AutonomyError {
8    /// Safety constraint triggered a stop.
9    #[error("Safety stop: {0}")]
10    SafetyStop(String),
11
12    /// Budget limit exceeded.
13    #[error("Budget exceeded: ${0:.2}")]
14    BudgetExceeded(f64),
15
16    /// Circuit breaker tripped after consecutive failures.
17    #[error("Circuit breaker tripped after {0} consecutive failures")]
18    CircuitBreakerTripped(u32),
19
20    /// Diff size limit exceeded.
21    #[error("Diff limit exceeded: {0} lines")]
22    DiffLimitExceeded(u32),
23
24    /// Maximum cycle count reached.
25    #[error("Cycle limit reached: {0}")]
26    CycleLimitReached(u32),
27
28    /// Git operation error.
29    #[error("Git error: {0}")]
30    GitError(String),
31
32    /// Forge (GitHub/GitLab) operation error.
33    #[error("Forge error: {0}")]
34    ForgeError(String),
35
36    /// Webhook delivery or parsing error.
37    #[error("Webhook error: {0}")]
38    WebhookError(String),
39
40    /// Configuration error.
41    #[error("Configuration error: {0}")]
42    ConfigError(String),
43
44    /// Agent execution error.
45    #[error("Agent error: {0}")]
46    AgentError(String),
47
48    /// Investigation/analysis error.
49    #[error("Investigation error: {0}")]
50    InvestigationError(String),
51
52    /// Merge policy violation.
53    #[error("Merge policy error: {0}")]
54    MergePolicyError(String),
55
56    /// Crash recovery error.
57    #[error("Crash recovery error: {0}")]
58    CrashRecoveryError(String),
59
60    /// GPIO hardware access error.
61    #[error("GPIO error: {0}")]
62    GpioError(String),
63
64    /// Scheduler error.
65    #[error("Scheduler error: {0}")]
66    SchedulerError(String),
67
68    /// File system reactor error.
69    #[error("Reactor error: {0}")]
70    ReactorError(String),
71
72    /// System service management error.
73    #[error("Service error: {0}")]
74    ServiceError(String),
75
76    /// Other unclassified error.
77    #[error("{0}")]
78    Other(#[from] anyhow::Error),
79}
80
81/// Convenience result alias.
82pub 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}