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