Skip to main content

perspt_sdk/
error.rs

1//! SDK error type.
2//!
3//! The SDK refuses to silently accept a malformed residual, weight, or
4//! stability constant. Every numerical contract in PSP-8 (finite non-negative
5//! residual scores, strictly positive edge weights, `alpha > beta`, `mu > 0`)
6//! is enforced as a typed error rather than a soft pass.
7
8use thiserror::Error;
9
10/// Errors produced by the SRBN agent SDK.
11#[derive(Debug, Error, Clone, PartialEq)]
12pub enum SdkError {
13    /// A residual score was negative, NaN, or infinite.
14    #[error("invalid residual score: {0}")]
15    InvalidScore(String),
16
17    /// An energy weight was non-positive, NaN, or infinite.
18    #[error("invalid energy weight: {0}")]
19    InvalidWeight(String),
20
21    /// A descent tolerance, energy, or other gate input was out of range.
22    #[error("invalid gate parameter: {0}")]
23    InvalidGate(String),
24
25    /// A declared analytic stability constant violated its precondition.
26    #[error("invalid stability claim: {0}")]
27    InvalidStability(String),
28
29    /// The spectral energy-slope computation could not be completed.
30    #[error("spectral computation error: {0}")]
31    Spectral(String),
32
33    /// The underlying `srbn` kernel reported an error.
34    #[error("srbn kernel error: {0}")]
35    Kernel(String),
36
37    /// A domain package produced an inconsistent contract.
38    #[error("domain error: {0}")]
39    Domain(String),
40}
41
42impl From<srbn::Error> for SdkError {
43    fn from(err: srbn::Error) -> Self {
44        SdkError::Kernel(err.to_string())
45    }
46}
47
48/// SDK result alias.
49pub type Result<T> = std::result::Result<T, SdkError>;
50
51/// Validate that a value is finite and non-negative (PSP-8 residual contract).
52pub(crate) fn check_non_negative_finite(value: f64, what: &str) -> Result<()> {
53    if !value.is_finite() {
54        return Err(SdkError::InvalidScore(format!(
55            "{what} is not finite: {value}"
56        )));
57    }
58    if value < 0.0 {
59        return Err(SdkError::InvalidScore(format!(
60            "{what} is negative: {value}"
61        )));
62    }
63    Ok(())
64}
65
66/// Validate that a weight is finite and strictly positive (PSP-8 `w_e > 0`).
67pub(crate) fn check_positive_finite(value: f64, what: &str) -> Result<()> {
68    if !value.is_finite() {
69        return Err(SdkError::InvalidWeight(format!(
70            "{what} is not finite: {value}"
71        )));
72    }
73    if value <= 0.0 {
74        return Err(SdkError::InvalidWeight(format!(
75            "{what} must be strictly positive: {value}"
76        )));
77    }
78    Ok(())
79}