KeiSeiKit-1.0/_primitives/_rust/kei-discover/src/error.rs
Parfii-bot 0be354a920 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

58 lines
1.8 KiB
Rust

//! `DiscoverError` — typed error for the kei-discover public API.
//!
//! The CLI maps validation-style errors (DuplicateSlug, NotFound,
//! InvalidInput) to exit 2 and storage / IO failures to exit 1,
//! matching the kei-entity-store convention.
use thiserror::Error;
#[derive(Debug, Error)]
pub enum DiscoverError {
#[error("DuplicateSlug: `{0}` is already registered")]
DuplicateSlug(String),
#[error("NotFound: discover entry id {0}")]
NotFound(i64),
#[error("InvalidInput: {0}")]
InvalidInput(String),
#[error("Storage: {0}")]
Storage(String),
}
impl DiscoverError {
/// Exit code contract — 2 for user-facing input errors, 1 for
/// storage / IO failures.
pub fn exit_code(&self) -> u8 {
match self {
Self::DuplicateSlug(_) | Self::NotFound(_) | Self::InvalidInput(_) => 2,
Self::Storage(_) => 1,
}
}
}
/// Map engine errors to kei-discover errors. SQLite unique-constraint
/// failures on the `slug` column are re-classified as `DuplicateSlug`
/// so callers get a typed signal instead of a raw SQL string.
impl From<kei_entity_store::VerbError> for DiscoverError {
fn from(e: kei_entity_store::VerbError) -> Self {
let msg = format!("{e}");
if msg.contains("UNIQUE constraint failed") && msg.contains("slug") {
// slug is carried by the caller — fill in at the call site
// via map_err when more context is available. Here we emit
// an empty marker that the caller overrides.
return Self::DuplicateSlug(String::new());
}
match e.exit_code() {
2 => Self::InvalidInput(msg),
_ => Self::Storage(msg),
}
}
}
impl From<rusqlite::Error> for DiscoverError {
fn from(e: rusqlite::Error) -> Self {
Self::Storage(e.to_string())
}
}