Skip to main content

klieo_runlog/
error.rs

1//! `RunLogError` — the only error surface for this crate.
2
3use crate::types::StepKind;
4use klieo_core::ids::RunId;
5use thiserror::Error;
6
7/// Errors raised by `klieo-runlog` operations.
8#[non_exhaustive]
9#[derive(Debug, Error)]
10pub enum RunLogError {
11    /// Backend store failure (I/O, serialisation, SQL).
12    #[error("runlog store error: {0}")]
13    Store(String),
14
15    /// `get`/`delete` requested a `run_id` that does not exist.
16    #[error("runlog not found for run_id {0}")]
17    NotFound(RunId),
18
19    /// Projection from `Episode` stream into a `RunLog` aggregate failed.
20    #[error("runlog projection error: {0}")]
21    Projection(String),
22
23    /// Free-form structural replay failure retained for back-compat; all
24    /// in-crate paths now emit a typed variant instead.
25    #[deprecated(note = "use ReplayMismatch, ReplayStep, or NoLlmCall")]
26    #[error("runlog replay error: {0}")]
27    Replay(String),
28
29    /// The `RunLog` carried no `LlmCall` step, so strict `replay` has no final
30    /// assistant text to return.
31    #[error("runlog replay found no LlmCall step")]
32    NoLlmCall,
33
34    /// A replay double produced output that differs from the recording — the
35    /// strict `replay` path's stop condition. Carries both sides so callers
36    /// inspect the divergence without parsing the `Display` string.
37    #[error("runlog replay mismatch at step {step} ({kind:?})")]
38    ReplayMismatch {
39        /// Zero-based index into the source `RunLog.steps`.
40        step: u32,
41        /// Copied from the diverging step; only `LlmCall`/`ToolCall` reach here,
42        /// since other kinds re-issue no I/O on replay.
43        kind: StepKind,
44        /// Recorded output, normalized for comparison (see `flatten_output`).
45        expected: String,
46        /// Replayed output, normalized the same way as `expected`.
47        actual: String,
48    },
49
50    /// A replay double failed to produce output for a step (the LLM/tool call
51    /// errored or a scripted double exhausted) — distinct from a value
52    /// mismatch, which surfaces as `ReplayMismatch` rather than an error.
53    #[error("runlog replay step {step} failed")]
54    ReplayStep {
55        /// Zero-based index into the source `RunLog.steps`.
56        step: u32,
57        /// The `LlmError` or `ToolError` the double returned, boxed so the
58        /// typed cause stays reachable via [`std::error::Error::source`].
59        #[source]
60        source: Box<dyn std::error::Error + Send + Sync>,
61    },
62
63    /// Compaction policy failed (e.g. LLM summariser returned non-text).
64    #[error("runlog compaction error: {0}")]
65    Compaction(String),
66
67    /// A capture-persistence backend operation (`KvStore` put/get/keys/delete)
68    /// failed. Carries the backend error as a typed source.
69    #[error("capture persistence backend error")]
70    CaptureBackend {
71        /// Downcast to `klieo_core::BusError` to branch on the backend failure
72        /// kind (unsupported, conflict, transport).
73        #[source]
74        source: Box<dyn std::error::Error + Send + Sync>,
75    },
76
77    /// A capture blob failed to serialize on persist or deserialize on load
78    /// (e.g. a corrupt or truncated stored value).
79    #[error("capture codec error")]
80    CaptureCodec {
81        /// Downcast to `serde_json::Error` for the byte offset of the
82        /// malformed blob.
83        #[source]
84        source: Box<dyn std::error::Error + Send + Sync>,
85    },
86}