1use crate::types::{EdgeIdx, Generation, NodeId};
4
5#[derive(Debug, thiserror::Error)]
8pub enum M1ndError {
9 #[error("dangling edge: edge {edge:?} references non-existent node {node:?}")]
12 DanglingEdge { edge: EdgeIdx, node: NodeId },
13
14 #[error("graph generation mismatch: expected {expected:?}, actual {actual:?}")]
16 GraphGenerationMismatch {
17 expected: Generation,
18 actual: Generation,
19 },
20
21 #[error("duplicate node: interned ID {0:?}")]
23 DuplicateNode(NodeId),
24
25 #[error("graph not finalised: call Graph::finalize() before queries")]
27 GraphNotFinalized,
28
29 #[error("graph is empty")]
31 EmptyGraph,
32
33 #[error("non-finite value at firewall: node={node:?}, value={value}")]
36 NonFiniteActivation { node: NodeId, value: f32 },
37
38 #[error("parameter out of range: {name} = {value} (expected {range})")]
40 ParameterOutOfRange {
41 name: &'static str,
42 value: f64,
43 range: &'static str,
44 },
45
46 #[error("non-positive resonance parameter: {name} = {value}")]
48 NonPositiveResonanceParam { name: &'static str, value: f32 },
49
50 #[error("pulse budget exhausted: {budget} pulses processed")]
53 PulseBudgetExhausted { budget: u64 },
54
55 #[error("chain budget exhausted: {budget} chains generated")]
57 ChainBudgetExhausted { budget: u64 },
58
59 #[error("matrix entry budget exhausted: {budget} entries")]
61 MatrixBudgetExhausted { budget: u64 },
62
63 #[error("ingestion timeout after {elapsed_s:.1}s")]
65 IngestionTimeout { elapsed_s: f64 },
66
67 #[error("ingestion cancelled")]
71 IngestionCancelled,
72
73 #[error("ingestion node budget exhausted: {budget} nodes")]
75 IngestionNodeBudget { budget: u64 },
76
77 #[error("fingerprint pair budget exhausted: {budget} pairs")]
79 FingerprintPairBudget { budget: u64 },
80
81 #[error("XLR over-cancellation: all signal cancelled")]
84 XlrOverCancellation,
85
86 #[error("Louvain non-convergence after {passes} passes")]
88 LouvainNonConvergence { passes: u32 },
89
90 #[error("spectral analysis: power iteration divergence suspected")]
92 SpectralDivergence,
93
94 #[error("resonance normalization: max amplitude is zero")]
96 ResonanceZeroAmplitude,
97
98 #[error("CAS retry limit ({limit}) exceeded at edge {edge:?}")]
100 CasRetryExhausted { edge: EdgeIdx, limit: u32 },
101
102 #[error("encoding detection failed for {path} (confidence={confidence:.2})")]
105 EncodingDetectionFailed { path: String, confidence: f32 },
106
107 #[error("binary file skipped: {path}")]
109 BinaryFileSkipped { path: String },
110
111 #[error("label collision: {label} maps to {count} nodes")]
113 LabelCollision { label: String, count: usize },
114
115 #[error("full reindex required: {reason}")]
119 FullReindexRequired { reason: String },
120
121 #[error("corrupt persistence state: {reason}")]
124 CorruptState { reason: String },
125
126 #[error("schema drift on import: {reason}")]
128 SchemaDrift { reason: String },
129
130 #[error("embed error: {0}")]
132 EmbedError(String),
133
134 #[error("counterfactual seed overlap: seed {node:?} is in the removal set")]
137 CounterfactualSeedOverlap { node: NodeId },
138
139 #[error("unknown tool: {name}")]
142 UnknownTool { name: String },
143
144 #[error("invalid params for {tool}: {detail}")]
146 InvalidParams { tool: String, detail: String },
147
148 #[error("perspective not found: {perspective_id} for agent {agent_id}")]
150 PerspectiveNotFound {
151 perspective_id: String,
152 agent_id: String,
153 },
154
155 #[error(
157 "perspective stale: {perspective_id} expected gen {expected_gen}, actual {actual_gen}"
158 )]
159 PerspectiveStale {
160 perspective_id: String,
161 expected_gen: u64,
162 actual_gen: u64,
163 },
164
165 #[error("perspective limit exceeded for agent {agent_id}: {current}/{limit}")]
167 PerspectiveLimitExceeded {
168 agent_id: String,
169 current: usize,
170 limit: usize,
171 },
172
173 #[error("route set stale: version {route_set_version}, current {current_version}")]
175 RouteSetStale {
176 route_set_version: u64,
177 current_version: u64,
178 },
179
180 #[error("route not found: {route_id} in perspective {perspective_id}")]
182 RouteNotFound {
183 route_id: String,
184 perspective_id: String,
185 },
186
187 #[error("navigation at root: perspective {perspective_id}")]
189 NavigationAtRoot { perspective_id: String },
190
191 #[error("branch depth exceeded in {perspective_id}: depth {depth}/{limit}")]
193 BranchDepthExceeded {
194 perspective_id: String,
195 depth: usize,
196 limit: usize,
197 },
198
199 #[error("lock not found: {lock_id}")]
201 LockNotFound { lock_id: String },
202
203 #[error("lock ownership violation: {lock_id} owned by {owner}, called by {caller}")]
205 LockOwnership {
206 lock_id: String,
207 owner: String,
208 caller: String,
209 },
210
211 #[error("lock scope too large: {node_count} nodes exceeds cap of {cap}")]
213 LockScopeTooLarge { node_count: usize, cap: usize },
214
215 #[error("lock limit exceeded for agent {agent_id}: {current}/{limit}")]
217 LockLimitExceeded {
218 agent_id: String,
219 current: usize,
220 limit: usize,
221 },
222
223 #[error("watch strategy not supported: {strategy}")]
225 WatchStrategyNotSupported { strategy: String },
226
227 #[error("affinity timeout: {elapsed_ms:.1}ms exceeded budget of {budget_ms:.1}ms")]
229 AffinityTimeout { elapsed_ms: f64, budget_ms: f64 },
230
231 #[error("pattern too broad: specificity {specificity:.2} below minimum {minimum:.2}")]
234 PatternTooBroad { specificity: f32, minimum: f32 },
235
236 #[error("antibody not found: {id}")]
238 AntibodyNotFound { id: String },
239
240 #[error("antibody limit exceeded: {current}/{limit}")]
242 AntibodyLimitExceeded { current: usize, limit: usize },
243
244 #[error("epidemic burnout: {infected_pct:.1}% infected in {iteration} iterations")]
247 EpidemicBurnout { infected_pct: f32, iteration: u32 },
248
249 #[error("no valid infected nodes")]
251 NoValidInfectedNodes,
252
253 #[error("no entry points found for flow simulation")]
256 NoEntryPoints,
257
258 #[error("layer not found: level {level}")]
261 LayerNotFound { level: u8 },
262
263 #[error("ingest error: {0}")]
266 IngestError(String),
267
268 #[error("I/O error: {0}")]
270 Io(#[from] std::io::Error),
271
272 #[error("serialization error: {0}")]
273 Serde(#[from] serde_json::Error),
274
275 #[error("persistence failed: {0}")]
276 PersistenceFailed(String),
277}
278
279pub type M1ndResult<T> = Result<T, M1ndError>;