shepherd-registry 6.6.0

The shepherd registry: the SQLite schema, migration runner, and query surface that every harness reads directly.
/*
    Appellation: error <module>
    Created At: 2026.08.12:16:20:00
    Contrib: @FL03
*/
//! Typed registry errors.
//!
//! `rusqlite::Error` is wrapped rather than leaked so that a consumer can match
//! on registry semantics (a migration failed, the schema is ahead of this
//! binary) without matching on SQLite internals.
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::string::{String, ToString};

/// The result type returned throughout the registry.
pub type Result<T = (), E = Error> = core::result::Result<T, E>;

/// Every failure the registry itself can produce.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
    /// The engine reported a domain failure.
    #[error(transparent)]
    Core(#[from] shepherd_core::Error),
    /// SQLite reported a failure.
    #[error(transparent)]
    Sqlite(#[from] rusqlite::Error),
    /// A migration failed to apply; carries the version that broke.
    #[error("migration {version} failed: {message}")]
    Migration { version: i64, message: String },
    /// A recorded migration checksum no longer matches the embedded SQL.
    #[error("migration {version} checksum mismatch: expected {expected}, found {found}")]
    MigrationChecksum {
        version: i64,
        expected: String,
        found: String,
    },
    /// A migration row exists but its required catalog postcondition is absent.
    #[error("migration {version} postcondition failed: {object}")]
    MigrationPostcondition { version: i64, object: String },
    /// A singleton publication request is malformed or cannot be replayed safely.
    #[error("invalid singleton publication: {0}")]
    InvalidSingletonPublication(String),
    /// A singleton publication was found in a conflicting durable state.
    #[error("singleton publication conflict for nonce `{nonce}`: {reason}")]
    SingletonPublicationConflict { nonce: String, reason: String },
    /// The database schema is newer than this binary understands.
    #[error("registry schema version {found} is ahead of the supported {supported}")]
    SchemaAhead { found: i64, supported: i64 },
    /// A mutating operation was requested through a read-only registry.
    #[error("registry is read-only")]
    ReadOnly,
    /// A run/lane singleton already has a different native owner.
    #[error(
        "dispatch singleton claim conflict for {project_id}/{run_id}/{role}/{lane_key}; existing agent `{agent_id}`"
    )]
    DispatchClaimConflict {
        project_id: String,
        run_id: String,
        role: String,
        lane_key: String,
        agent_id: String,
    },
    /// A singleton claim request does not describe a valid logical identity.
    #[error("invalid dispatch singleton claim: {0}")]
    InvalidDispatchClaim(String),
    /// The registry path would cross a symbolic-link boundary.
    #[error("unsafe registry path: {0}")]
    UnsafePath(String),
    /// Rolling back a failed transaction also failed.
    #[error("transaction failed ({cause}) and rollback failed ({rollback})")]
    TransactionRollback { cause: String, rollback: String },
    /// A catch-all for registry failures that do not yet warrant a variant.
    #[error("{0}")]
    Unknown(String),
}

impl Error {
    /// Build an [`Error::Unknown`] from anything displayable.
    pub fn unknown(message: impl core::fmt::Display) -> Self {
        Self::Unknown(message.to_string())
    }
}