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
//! `CheckCategory` (AP2.1-7).
//!
//! The area a system check inspects. A small, fixed, low-cardinality
//! enumeration serialized as a lowercase string so the Inspector / CI /
//! MCP `system_checks` tool can group checks by subsystem without reading
//! free-text descriptions. A new category is an additive, change-fragmented
//! change to the diagnostic surface. See `severity` for the dual
//! classification.

use std::fmt;

/// The area a system check inspects.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CheckCategory {
    /// Toolchain / environment (rustc, node, pnpm versions).
    Toolchain,
    /// Certified-stack matrix compliance.
    CertifiedStack,
    /// Database / migrations.
    Database,
    /// Cache subsystem configuration.
    Cache,
    /// Storage subsystem configuration.
    Storage,
    /// Mail subsystem configuration.
    Mail,
    /// Jobs / scheduler configuration.
    Jobs,
    /// Observability configuration (tracing, spans, OTel).
    Observability,
    /// Security posture (secrets, CORS, CSRF, TLS).
    Security,
    /// Cross-stack / frontend integration (Inertia, Vite, routes).
    CrossStack,
    /// The application graph / module wiring.
    ApplicationGraph,
    /// Framework-internal / general configuration.
    Framework,
}

impl CheckCategory {
    /// The stable lowercase string used in JSON output.
    #[must_use]
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::Toolchain => "toolchain",
            Self::CertifiedStack => "certified_stack",
            Self::Database => "database",
            Self::Cache => "cache",
            Self::Storage => "storage",
            Self::Mail => "mail",
            Self::Jobs => "jobs",
            Self::Observability => "observability",
            Self::Security => "security",
            Self::CrossStack => "cross_stack",
            Self::ApplicationGraph => "application_graph",
            Self::Framework => "framework",
        }
    }
}

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

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

    #[test]
    fn categories_are_stable_lowercase_single_token_strings() {
        let all = [
            CheckCategory::Toolchain,
            CheckCategory::CertifiedStack,
            CheckCategory::Database,
            CheckCategory::Cache,
            CheckCategory::Storage,
            CheckCategory::Mail,
            CheckCategory::Jobs,
            CheckCategory::Observability,
            CheckCategory::Security,
            CheckCategory::CrossStack,
            CheckCategory::ApplicationGraph,
            CheckCategory::Framework,
        ];
        let names: Vec<&str> = all.iter().map(|c| c.as_str()).collect();
        let mut unique = names.clone();
        unique.sort();
        unique.dedup();
        assert_eq!(unique.len(), all.len(), "categories must be distinct");
        for n in &names {
            assert!(!n.contains(' '), "category must be a single token: {n}");
            assert_eq!(*n, n.to_lowercase(), "category must be lowercase: {n}");
        }
    }
}