use crate::types::{EdgeIdx, Generation, NodeId};
#[derive(Debug, thiserror::Error)]
pub enum M1ndError {
#[error("dangling edge: edge {edge:?} references non-existent node {node:?}")]
DanglingEdge { edge: EdgeIdx, node: NodeId },
#[error("graph generation mismatch: expected {expected:?}, actual {actual:?}")]
GraphGenerationMismatch {
expected: Generation,
actual: Generation,
},
#[error("duplicate node: interned ID {0:?}")]
DuplicateNode(NodeId),
#[error("graph not finalised: call Graph::finalize() before queries")]
GraphNotFinalized,
#[error("graph is empty")]
EmptyGraph,
#[error("non-finite value at firewall: node={node:?}, value={value}")]
NonFiniteActivation { node: NodeId, value: f32 },
#[error("parameter out of range: {name} = {value} (expected {range})")]
ParameterOutOfRange {
name: &'static str,
value: f64,
range: &'static str,
},
#[error("non-positive resonance parameter: {name} = {value}")]
NonPositiveResonanceParam { name: &'static str, value: f32 },
#[error("pulse budget exhausted: {budget} pulses processed")]
PulseBudgetExhausted { budget: u64 },
#[error("chain budget exhausted: {budget} chains generated")]
ChainBudgetExhausted { budget: u64 },
#[error("matrix entry budget exhausted: {budget} entries")]
MatrixBudgetExhausted { budget: u64 },
#[error("ingestion timeout after {elapsed_s:.1}s")]
IngestionTimeout { elapsed_s: f64 },
#[error("ingestion node budget exhausted: {budget} nodes")]
IngestionNodeBudget { budget: u64 },
#[error("fingerprint pair budget exhausted: {budget} pairs")]
FingerprintPairBudget { budget: u64 },
#[error("XLR over-cancellation: all signal cancelled")]
XlrOverCancellation,
#[error("Louvain non-convergence after {passes} passes")]
LouvainNonConvergence { passes: u32 },
#[error("spectral analysis: power iteration divergence suspected")]
SpectralDivergence,
#[error("resonance normalization: max amplitude is zero")]
ResonanceZeroAmplitude,
#[error("CAS retry limit ({limit}) exceeded at edge {edge:?}")]
CasRetryExhausted { edge: EdgeIdx, limit: u32 },
#[error("encoding detection failed for {path} (confidence={confidence:.2})")]
EncodingDetectionFailed { path: String, confidence: f32 },
#[error("binary file skipped: {path}")]
BinaryFileSkipped { path: String },
#[error("label collision: {label} maps to {count} nodes")]
LabelCollision { label: String, count: usize },
#[error("corrupt persistence state: {reason}")]
CorruptState { reason: String },
#[error("schema drift on import: {reason}")]
SchemaDrift { reason: String },
#[error("counterfactual seed overlap: seed {node:?} is in the removal set")]
CounterfactualSeedOverlap { node: NodeId },
#[error("unknown tool: {name}")]
UnknownTool { name: String },
#[error("invalid params for {tool}: {detail}")]
InvalidParams { tool: String, detail: String },
#[error("perspective not found: {perspective_id} for agent {agent_id}")]
PerspectiveNotFound {
perspective_id: String,
agent_id: String,
},
#[error(
"perspective stale: {perspective_id} expected gen {expected_gen}, actual {actual_gen}"
)]
PerspectiveStale {
perspective_id: String,
expected_gen: u64,
actual_gen: u64,
},
#[error("perspective limit exceeded for agent {agent_id}: {current}/{limit}")]
PerspectiveLimitExceeded {
agent_id: String,
current: usize,
limit: usize,
},
#[error("route set stale: version {route_set_version}, current {current_version}")]
RouteSetStale {
route_set_version: u64,
current_version: u64,
},
#[error("route not found: {route_id} in perspective {perspective_id}")]
RouteNotFound {
route_id: String,
perspective_id: String,
},
#[error("navigation at root: perspective {perspective_id}")]
NavigationAtRoot { perspective_id: String },
#[error("branch depth exceeded in {perspective_id}: depth {depth}/{limit}")]
BranchDepthExceeded {
perspective_id: String,
depth: usize,
limit: usize,
},
#[error("lock not found: {lock_id}")]
LockNotFound { lock_id: String },
#[error("lock ownership violation: {lock_id} owned by {owner}, called by {caller}")]
LockOwnership {
lock_id: String,
owner: String,
caller: String,
},
#[error("lock scope too large: {node_count} nodes exceeds cap of {cap}")]
LockScopeTooLarge { node_count: usize, cap: usize },
#[error("lock limit exceeded for agent {agent_id}: {current}/{limit}")]
LockLimitExceeded {
agent_id: String,
current: usize,
limit: usize,
},
#[error("watch strategy not supported: {strategy}")]
WatchStrategyNotSupported { strategy: String },
#[error("affinity timeout: {elapsed_ms:.1}ms exceeded budget of {budget_ms:.1}ms")]
AffinityTimeout { elapsed_ms: f64, budget_ms: f64 },
#[error("pattern too broad: specificity {specificity:.2} below minimum {minimum:.2}")]
PatternTooBroad { specificity: f32, minimum: f32 },
#[error("antibody not found: {id}")]
AntibodyNotFound { id: String },
#[error("antibody limit exceeded: {current}/{limit}")]
AntibodyLimitExceeded { current: usize, limit: usize },
#[error("epidemic burnout: {infected_pct:.1}% infected in {iteration} iterations")]
EpidemicBurnout { infected_pct: f32, iteration: u32 },
#[error("no valid infected nodes")]
NoValidInfectedNodes,
#[error("no entry points found for flow simulation")]
NoEntryPoints,
#[error("layer not found: level {level}")]
LayerNotFound { level: u8 },
#[error("ingest error: {0}")]
IngestError(String),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("serialization error: {0}")]
Serde(#[from] serde_json::Error),
#[error("persistence failed: {0}")]
PersistenceFailed(String),
}
pub type M1ndResult<T> = Result<T, M1ndError>;