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}