Skip to main content

runifold_core/
error.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use thiserror::Error;
6
7/// Whether retrying an operation is safe.
8#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
9#[non_exhaustive]
10pub enum RetrySafety {
11    /// The same operation can be retried safely.
12    Safe,
13    /// Retry is safe only when the external system honors an idempotency key.
14    RequiresIdempotency,
15    /// Visible output has been emitted, so retry may duplicate output.
16    UnsafeAfterVisibleOutput,
17    /// An external side effect may already have occurred.
18    UnsafeAfterSideEffect,
19    /// Safety cannot be determined.
20    Unknown,
21}
22
23/// A normalized run failure category.
24#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
25#[non_exhaustive]
26pub enum RunErrorKind {
27    /// Input or configuration is invalid.
28    InvalidInput,
29    /// A required capability was not granted.
30    CapabilityDenied,
31    /// A resource budget was exhausted.
32    BudgetExceeded,
33    /// A deadline elapsed.
34    DeadlineExceeded,
35    /// The run was cancelled.
36    Cancelled,
37    /// A transport failed.
38    Transport,
39    /// A remote protocol was malformed or violated its contract.
40    Protocol,
41    /// An invoked component failed.
42    Invocation,
43    /// A namespaced extension error.
44    Extension(String),
45}
46
47/// A structured run error suitable for policy decisions.
48#[derive(Clone, Debug, Deserialize, Error, PartialEq, Serialize)]
49#[error("{kind:?}: {message}")]
50pub struct RunError {
51    /// Normalized error category.
52    pub kind: RunErrorKind,
53    /// Safe human-readable explanation.
54    pub message: String,
55    /// Retry-safety classification.
56    pub retry_safety: RetrySafety,
57    /// Namespaced diagnostic metadata.
58    pub metadata: BTreeMap<String, Value>,
59}