Skip to main content

wm_core/
error.rs

1//! Core error types for `WhiteMagic` v4.
2
3use thiserror::Error;
4
5/// Result type alias for `WhiteMagic` core operations.
6pub type Result<T> = std::result::Result<T, CoreError>;
7
8/// Core error type covering all `WhiteMagic` failure modes.
9#[derive(Debug, Error)]
10pub enum CoreError {
11    /// Tool execution failed
12    #[error("tool error: {0}")]
13    Tool(String),
14
15    /// Memory operation failed
16    #[error("memory error: {0}")]
17    Memory(String),
18
19    /// Governance rule violation
20    #[error("governance violation: {0}")]
21    Governance(String),
22
23    /// Rate limit exceeded
24    #[error("rate limited: {0}")]
25    RateLimited(String),
26
27    /// Circuit breaker open
28    #[error("circuit breaker open for: {0}")]
29    CircuitBreaker(String),
30
31    /// Invalid arguments
32    #[error("invalid args: {0}")]
33    InvalidArgs(String),
34
35    /// Resource not found
36    #[error("not found: {0}")]
37    NotFound(String),
38
39    /// Polyglot bridge error
40    #[error("polyglot error: {0}")]
41    Polyglot(String),
42
43    /// I/O error
44    #[error("io error: {0}")]
45    Io(#[from] std::io::Error),
46
47    /// Serialization error
48    #[error("serialization error: {0}")]
49    Serde(#[from] serde_json::Error),
50
51    /// Internal error (should not happen in normal operation)
52    #[error("internal error: {0}")]
53    Internal(String),
54}
55
56impl CoreError {
57    /// Whether this error is retryable.
58    #[must_use]
59    pub const fn is_retryable(&self) -> bool {
60        matches!(self, Self::RateLimited(_) | Self::CircuitBreaker(_))
61    }
62
63    /// Whether this error indicates a governance violation.
64    #[must_use]
65    pub const fn is_governance(&self) -> bool {
66        matches!(self, Self::Governance(_))
67    }
68
69    /// Whether this error should count against a tool's circuit breaker.
70    ///
71    /// Caller-caused failures (invalid arguments, governance refusals,
72    /// not-found lookups, rate limiting) say nothing about backend health.
73    /// Counting them let a handful of bad requests trip a breaker and block
74    /// VALID requests that followed (2026-09-15 audit: five invalid-galaxy
75    /// creates fast-failed the next correct call).
76    #[must_use]
77    pub const fn counts_as_breaker_failure(&self) -> bool {
78        matches!(
79            self,
80            Self::Tool(_)
81                | Self::Memory(_)
82                | Self::Internal(_)
83                | Self::Io(_)
84                | Self::Polyglot(_)
85                | Self::Serde(_)
86        )
87    }
88}