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