arcature 2026.2.1

Arcature application framework: a high-level Application facade over the certified Arcature subsystems, with the low-level Axum/Tower escape hatch preserved.
Documentation
//! `CheckId` — a stable, greppable system-check identifier (AP2.1-7).
//!
//! Check IDs follow the form `ARC<NNNN>` (four digits, zero-padded), e.g.
//! `ARC0001`. The ID is **stable**: a check that ships with ID `ARC0001`
//! keeps that ID for its lifetime. Renaming or renumbering a check is a
//! breaking change to the diagnostic surface (operators and CI filter by
//! ID) and requires a change fragment.
//!
//! IDs are validated at construction so a typo'd or malformed ID is caught
//! at the `&'static` registration site rather than surfacing as a broken
//! filter downstream.

use std::fmt;

/// A validated system-check ID of the form `ARC<NNNN>`.
///
/// Construct via [`CheckId::new`] (validating) or, where a constant is
/// required and the value is known correct by construction, via
/// [`CheckId::new_unchecked`] — the latter is `const` so framework checks
/// can declare their IDs as `const` items.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CheckId(&'static str);

/// The number of digits after the `ARC` prefix.
const ID_DIGITS: usize = 4;
/// The full length of a valid ID: `ARC` + 4 digits.
const ID_LEN: usize = 3 + ID_DIGITS;

/// Error returned when a check ID is malformed.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CheckIdError {
    /// The ID is not `ARC` followed by exactly four digits.
    Malformed,
}

impl fmt::Display for CheckIdError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Malformed => {
                f.write_str("check id must be `ARC` followed by 4 digits (e.g. `ARC0001`)")
            }
        }
    }
}

impl std::error::Error for CheckIdError {}

impl CheckId {
    /// Validate `id` and return a [`CheckId`].
    ///
    /// Returns [`CheckIdError::Malformed`] unless `id` is exactly `ARC`
    /// followed by four ASCII digits.
    pub fn new(id: &'static str) -> Result<Self, CheckIdError> {
        if is_valid(id) {
            Ok(Self(id))
        } else {
            Err(CheckIdError::Malformed)
        }
    }

    /// Construct a [`CheckId`] without validating.
    ///
    /// `const` so framework checks can declare `const MY_ID: CheckId =
    /// CheckId::new_unchecked("ARC0001");`. The caller asserts the value is
    /// well-formed; the [`SystemCheck`](crate::system_check::check::SystemCheck)
    /// impl should prefer [`CheckId::new`] at non-const construction sites so
    /// a typo is caught at runtime.
    #[must_use]
    pub const fn new_unchecked(id: &'static str) -> Self {
        Self(id)
    }

    /// The raw `ARC<NNNN>` string.
    #[must_use]
    pub fn as_str(&self) -> &'static str {
        self.0
    }
}

impl fmt::Display for CheckId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.0)
    }
}

/// Returns `true` iff `id` is `ARC` followed by exactly four ASCII digits.
fn is_valid(id: &str) -> bool {
    id.len() == ID_LEN
        && id.as_bytes().starts_with(b"ARC")
        && id.as_bytes()[3..].iter().all(|b| b.is_ascii_digit())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn accepts_well_formed_ids() {
        assert!(CheckId::new("ARC0001").is_ok());
        assert!(CheckId::new("ARC9999").is_ok());
        assert!(CheckId::new("ARC0042").is_ok());
    }

    #[test]
    fn rejects_malformed_ids() {
        assert_eq!(CheckId::new("ARC001"), Err(CheckIdError::Malformed));
        assert_eq!(CheckId::new("ARC00001"), Err(CheckIdError::Malformed));
        assert_eq!(CheckId::new("arc0001"), Err(CheckIdError::Malformed));
        assert_eq!(CheckId::new("ARCabcd"), Err(CheckIdError::Malformed));
        assert_eq!(CheckId::new("ARC123"), Err(CheckIdError::Malformed));
        assert_eq!(CheckId::new(""), Err(CheckIdError::Malformed));
        assert_eq!(CheckId::new("ARC0001 "), Err(CheckIdError::Malformed));
    }

    #[test]
    fn unchecked_is_const_and_round_trips() {
        const ID: CheckId = CheckId::new_unchecked("ARC0001");
        assert_eq!(ID.as_str(), "ARC0001");
        assert_eq!(ID.to_string(), "ARC0001");
    }

    #[test]
    fn ids_are_eq_and_hash_stable() {
        use std::collections::hash_map::DefaultHasher;
        use std::hash::{Hash, Hasher};

        let a = CheckId::new("ARC0001").unwrap();
        let b = CheckId::new("ARC0001").unwrap();
        assert_eq!(a, b);
        // Equal IDs must hash equal so a HashMap<CheckId, _> keys them together.
        let hash_of = |id: CheckId| {
            let mut h = DefaultHasher::new();
            id.hash(&mut h);
            h.finish()
        };
        assert_eq!(hash_of(a), hash_of(b));
    }

    #[test]
    fn error_displays_helpfully() {
        assert_eq!(
            CheckIdError::Malformed.to_string(),
            "check id must be `ARC` followed by 4 digits (e.g. `ARC0001`)"
        );
    }
}