Skip to main content

monoloop_contracts/
error.rs

1//! Closed connector and interpreter error families (safe diagnostics only).
2
3use thiserror::Error;
4
5/// High-level connector error classification.
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum ConnectorErrorKind {
8    /// Invalid open/config parameters.
9    ConfigurationInvalid,
10    /// Required dialect unavailable or ambiguous.
11    DialectUnavailable,
12    /// Credential reference could not be resolved (no secret material in error).
13    CredentialUnavailable,
14    /// Transport open/connect failed.
15    ConnectionFailed,
16    /// Write path failed.
17    WriteFailed,
18    /// Read path failed.
19    ReadFailed,
20    /// Remote closed the connection.
21    RemoteClosed,
22    /// Deadline exceeded.
23    DeadlineExceeded,
24    /// Cooperative cancellation.
25    Cancelled,
26    /// Forced termination.
27    Terminated,
28    /// Local resource (queue/task) failure or limit.
29    LocalResourceFailed,
30    /// Internal invariant broken.
31    InvariantViolation,
32    /// Session create/load/routing failure (profile-specific).
33    SessionFailed,
34    /// Protocol/JSON-RPC framing failure (bounded classification).
35    ProtocolFailed,
36}
37
38/// Connector error with safe, bounded diagnostics.
39#[derive(Clone, Debug, Error, PartialEq, Eq)]
40#[error("{kind:?}: {message}")]
41pub struct ConnectorError {
42    /// Closed error family.
43    pub kind: ConnectorErrorKind,
44    /// Bounded human-safe message (no secrets).
45    pub message: String,
46    /// Optional connection correlation (may be absent during open failures).
47    pub connection_id: Option<String>,
48}
49
50impl ConnectorError {
51    /// Construct a typed error.
52    pub fn new(kind: ConnectorErrorKind, message: impl Into<String>) -> Self {
53        Self {
54            kind,
55            message: message.into(),
56            connection_id: None,
57        }
58    }
59
60    /// Attach a connection id for correlation (not a secret).
61    pub fn with_connection_id(mut self, id: impl Into<String>) -> Self {
62        self.connection_id = Some(id.into());
63        self
64    }
65
66    /// Configuration invalid.
67    pub fn configuration_invalid(message: impl Into<String>) -> Self {
68        Self::new(ConnectorErrorKind::ConfigurationInvalid, message)
69    }
70
71    /// Cancelled.
72    pub fn cancelled() -> Self {
73        Self::new(ConnectorErrorKind::Cancelled, "connection cancelled")
74    }
75
76    /// Terminated.
77    pub fn terminated() -> Self {
78        Self::new(ConnectorErrorKind::Terminated, "connection terminated")
79    }
80
81    /// Resource / bound exceeded.
82    pub fn resource(message: impl Into<String>) -> Self {
83        Self::new(ConnectorErrorKind::LocalResourceFailed, message)
84    }
85
86    /// Protocol failure.
87    pub fn protocol(message: impl Into<String>) -> Self {
88        Self::new(ConnectorErrorKind::ProtocolFailed, message)
89    }
90
91    /// Connection failed.
92    pub fn connection_failed(message: impl Into<String>) -> Self {
93        Self::new(ConnectorErrorKind::ConnectionFailed, message)
94    }
95
96    /// Session operation failed.
97    pub fn session_failed(message: impl Into<String>) -> Self {
98        Self::new(ConnectorErrorKind::SessionFailed, message)
99    }
100}
101
102/// Interpreter error classification.
103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104pub enum InterpreterErrorKind {
105    /// Unsupported dialect.
106    UnsupportedDialect,
107    /// Dialect binding mismatch.
108    DialectBindingMismatch,
109    /// Malformed frame.
110    MalformedFrame,
111    /// Frame/buffer limit exceeded.
112    FrameLimitExceeded,
113    /// Unsupported semantic event.
114    UnsupportedSemanticEvent,
115    /// Malformed semantic payload.
116    MalformedSemanticPayload,
117    /// Sentence assembly limit.
118    SentenceLimitExceeded,
119    /// Structure limit.
120    StructureLimitExceeded,
121    /// Tool identity missing/conflict.
122    ToolIdentityError,
123    /// Tool limit exceeded.
124    ToolLimitExceeded,
125    /// Output backpressure exceeded.
126    OutputBackpressureExceeded,
127    /// Connector ended unexpectedly.
128    ConnectorEndedUnexpectedly,
129    /// Cancelled.
130    Cancelled,
131    /// Invariant violation.
132    InvariantViolation,
133    /// Configuration invalid.
134    ConfigurationInvalid,
135}
136
137/// Interpreter error with safe diagnostics.
138#[derive(Clone, Debug, Error, PartialEq, Eq)]
139#[error("{kind:?}: {message}")]
140pub struct InterpreterError {
141    /// Closed error family.
142    pub kind: InterpreterErrorKind,
143    /// Bounded safe message.
144    pub message: String,
145}
146
147impl InterpreterError {
148    /// Construct a typed error.
149    pub fn new(kind: InterpreterErrorKind, message: impl Into<String>) -> Self {
150        Self {
151            kind,
152            message: message.into(),
153        }
154    }
155
156    /// Unsupported dialect.
157    pub fn unsupported_dialect(message: impl Into<String>) -> Self {
158        Self::new(InterpreterErrorKind::UnsupportedDialect, message)
159    }
160
161    /// Malformed frame.
162    pub fn malformed_frame(message: impl Into<String>) -> Self {
163        Self::new(InterpreterErrorKind::MalformedFrame, message)
164    }
165
166    /// Limit exceeded.
167    pub fn limit(message: impl Into<String>) -> Self {
168        Self::new(InterpreterErrorKind::FrameLimitExceeded, message)
169    }
170
171    /// Cancelled.
172    pub fn cancelled() -> Self {
173        Self::new(InterpreterErrorKind::Cancelled, "interpretation cancelled")
174    }
175
176    /// Output backpressure.
177    pub fn backpressure() -> Self {
178        Self::new(
179            InterpreterErrorKind::OutputBackpressureExceeded,
180            "canonical output queue full",
181        )
182    }
183}