Skip to main content

ferro_json_ui/design/
types.rs

1//! Public types for the design lint engine: [`Severity`], [`Finding`], [`DesignRule`].
2
3use crate::spec::Spec;
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7/// Severity level for a design lint finding.
8///
9/// `Warning` is the actionable level — it trips `--deny` in CI mode.
10/// `Info` is advisory only and never causes a non-zero exit.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
12#[serde(rename_all = "snake_case")]
13pub enum Severity {
14    /// Advisory: inference notices, undeclared-intent notes.
15    Info,
16    /// Actionable: trips `--deny` in CI mode.
17    Warning,
18}
19
20/// A single design lint finding from [`super::lint`].
21///
22/// The `--json` CLI output is a flat array of `FileFinding` (this struct
23/// wrapped with a `file` field). This serialization is the stable contract
24/// consumed by gestiscilo Phase 232 CI.
25#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
26pub struct Finding {
27    /// Rule id (e.g. `"page-header"`, `"prefer-data-table"`).
28    pub rule: &'static str,
29    /// Element ID where the finding originates, when identifiable.
30    pub element_id: Option<String>,
31    /// Severity level of this finding.
32    pub severity: Severity,
33    /// Human-readable description of what is wrong.
34    pub message: String,
35    /// Concrete fix suggestion.
36    pub suggestion: String,
37}
38
39/// A single entry in the static rule registry. All fields are `'static`
40/// for zero-cost iteration and Phase 253 MCP/doc derivation.
41pub struct DesignRule {
42    /// Stable rule id used in `allow` lists and finding `rule` fields.
43    pub id: &'static str,
44    /// Short human title for docs/MCP catalog.
45    pub title: &'static str,
46    /// Why this rule exists (one sentence).
47    pub rationale: &'static str,
48    /// Intents this rule applies to. Empty slice = all intents.
49    pub intents: &'static [&'static str],
50    /// Pure check function. Receives the raw [`Spec`] and the resolved intent
51    /// (may be `None` when intent is completely undeclared and inference found
52    /// no signal). Returns zero or more findings.
53    pub check: fn(&Spec, Option<&str>) -> Vec<Finding>,
54}