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
87
88
89
90
91
92
93
//! Crate-wide error type.
use thiserror::Error;
/// Top-level error type for the `cairn-mod` library.
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum Error {
/// Configuration loading or validation failed.
#[error("config error: {0}")]
Config(String),
/// I/O failure (filesystem, stdio, etc.).
#[error(transparent)]
Io(#[from] std::io::Error),
/// Figment config-source failure (TOML parse, env-var extraction).
#[error(transparent)]
Figment(Box<figment::Error>),
/// SQLx query or connection failure.
#[error(transparent)]
Sqlx(#[from] sqlx::Error),
/// Embedded migration runner failed.
#[error(transparent)]
Migrate(#[from] sqlx::migrate::MigrateError),
/// DAG-CBOR encode / decode failure from `proto-blue-lex-cbor`.
#[error(transparent)]
Cbor(#[from] proto_blue_lex_cbor::CborError),
/// Cryptographic primitive failure (signing, hashing, key parse).
#[error(transparent)]
Crypto(#[from] proto_blue_crypto::CryptoError),
/// Invariant violation specific to label signing (e.g. missing `sig`,
/// wrong algorithm in the multibase key, sig-length mismatch).
#[error("signing: {0}")]
Signing(String),
/// Another Cairn instance holds a fresh lease on the same SQLite file
/// (§F5 single-instance invariant). Refusing to start — the other
/// instance must shut down or its lease must age past 60s.
#[error(
"server_instance_lease held by another instance (instance_id={instance_id}, last heartbeat {age_secs}s ago)"
)]
LeaseHeld {
/// Instance identifier of the rival process holding the lease.
instance_id: String,
/// Seconds since that instance last heartbeated.
age_secs: u64,
},
/// Negating a label that does not currently apply. Either the tuple
/// `(src, uri, val)` has no apply events, or the most recent event for
/// the tuple is already a negation (§F6).
#[error("no applied label for ({src}, {uri}, {val}) — nothing to negate")]
LabelNotFound {
/// Labeler DID (Cairn's own service DID for emissions).
src: String,
/// Subject AT-URI or DID.
uri: String,
/// Label value.
val: String,
},
/// `resolveReport` (§F12) targeted a report id that doesn't exist.
/// Surface via the handler as `ReportNotFound` (declared lexicon error).
#[error("report not found: id={id}")]
ReportNotFound {
/// Report primary key that didn't resolve.
id: i64,
},
/// `resolveReport` (§F12) targeted a report that is already resolved.
/// Surface via the handler as `InvalidRequest` with a generic message
/// (no timestamps or resolver DID per the anti-leak principle).
#[error("report already resolved: id={id}")]
ReportAlreadyResolved {
/// Report primary key that was already resolved.
id: i64,
},
}
impl From<figment::Error> for Error {
fn from(e: figment::Error) -> Self {
Self::Figment(Box::new(e))
}
}
/// Crate-wide `Result` alias using [`enum@Error`] as the error type.
pub type Result<T> = std::result::Result<T, Error>;