Skip to main content

av_core/
error.rs

1//! Core error type shared across AgentVisor AI crates.
2
3/// Errors produced by core primitives.
4#[derive(Debug, thiserror::Error)]
5#[non_exhaustive]
6pub enum CoreError {
7    /// A numeric value exceeded the 2^53 safe-integer bound required for
8    /// RFC 8785 (JCS) canonicalization (IEEE-754 double mantissa limit).
9    #[error("integer {0} exceeds the 2^53 JCS-safe bound")]
10    UnsafeInteger(u64),
11    /// A counter or arithmetic operation would overflow.
12    #[error("arithmetic overflow in {context}")]
13    Overflow {
14        /// Human-readable operation description.
15        context: &'static str,
16    },
17    /// An identifier failed to parse.
18    #[error("invalid identifier: {0}")]
19    InvalidId(String),
20}
21
22/// Largest integer exactly representable as an IEEE-754 double (2^53).
23///
24/// JCS (RFC 8785) serializes all numbers as doubles; integers above this bound
25/// would silently lose precision, corrupting canonical hashes.
26pub const JCS_SAFE_MAX: u64 = 1 << 53;
27
28/// Validate that `n` is exactly representable in a JCS number.
29pub fn check_jcs_safe(n: u64) -> Result<u64, CoreError> {
30    if n > JCS_SAFE_MAX {
31        Err(CoreError::UnsafeInteger(n))
32    } else {
33        Ok(n)
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn jcs_bound_accepts_max() {
43        assert!(check_jcs_safe(JCS_SAFE_MAX).is_ok());
44        assert!(check_jcs_safe(0).is_ok());
45    }
46
47    #[test]
48    fn jcs_bound_rejects_above_max() {
49        assert!(check_jcs_safe(JCS_SAFE_MAX + 1).is_err());
50        assert!(check_jcs_safe(u64::MAX).is_err());
51    }
52}
53
54#[cfg(test)]
55mod const_tests {
56    /// Mutation-run hardening (round 12): `1 << 53` -> `1 >> 53` would
57    /// silently turn every overflow guard in the workspace into
58    /// "reject everything above 0". Pin the exact value.
59    #[test]
60    fn jcs_safe_max_is_two_to_the_53rd() {
61        assert_eq!(super::JCS_SAFE_MAX, 9_007_199_254_740_992);
62        assert_eq!(super::JCS_SAFE_MAX, 2u64.pow(53));
63    }
64}