diff --git a/crates/omnigraph-compiler/src/lint/codes.rs b/crates/omnigraph-compiler/src/lint/codes.rs index e53bf31..b719236 100644 --- a/crates/omnigraph-compiler/src/lint/codes.rs +++ b/crates/omnigraph-compiler/src/lint/codes.rs @@ -98,9 +98,23 @@ pub const OG_MF_104: DiagnosticCode = DiagnosticCode { short: "tighten nullable to non-nullable", }; +/// Narrow an enum's value-set by removing one or more allowed values +/// (e.g. `enum(a, b, c)` → `enum(a, b)`). The physical column is +/// unchanged (enums are stored as `String`), but a pre-existing row may +/// hold a now-disallowed value. Validated tier: apply scans existing +/// rows and fails loudly (listing the offending value) rather than +/// silently dropping data. +pub const OG_MF_105: DiagnosticCode = DiagnosticCode { + code: "OG-MF-105", + family: Family::MF, + tier: SafetyTier::Validated, + default_severity: Severity::Error, + short: "narrow enum value set", +}; + /// Narrow a scalar (e.g. I64 → I32, F64 → F32). Lossy cast that may -/// truncate or overflow. Today emitted on any `prop_type` change since -/// the v1 planner doesn't yet distinguish widening from narrowing. +/// truncate or overflow. Emitted for a genuine scalar-type change +/// (enum value-set changes are handled by OG-MF-105 / OG-MF-107). pub const OG_MF_106: DiagnosticCode = DiagnosticCode { code: "OG-MF-106", family: Family::MF, @@ -109,14 +123,29 @@ pub const OG_MF_106: DiagnosticCode = DiagnosticCode { short: "narrowing scalar type", }; +/// Constrain a free `String` property to an `enum` (e.g. `status: String` +/// → `status: enum(open, closed)`). Tightening: existing rows may hold a +/// value outside the new set. Validated tier: apply scans existing rows +/// and fails loudly on the first out-of-set value. +pub const OG_MF_107: DiagnosticCode = DiagnosticCode { + code: "OG-MF-107", + family: Family::MF, + tier: SafetyTier::Validated, + default_severity: Severity::Error, + short: "constrain String to enum", +}; + /// All v0 catalog entries. Used for chassis-level invariants /// (uniqueness, family coverage). pub const ALL_CODES: &[DiagnosticCode] = &[ - OG_DS_101, OG_DS_102, OG_DS_103, OG_DS_104, OG_DS_105, OG_MF_103, OG_MF_104, OG_MF_106, + OG_DS_101, OG_DS_102, OG_DS_103, OG_DS_104, OG_DS_105, OG_MF_103, OG_MF_104, OG_MF_105, + OG_MF_106, OG_MF_107, ]; /// Codes actually emitted by the planner in v0 (i.e. not reserved). -pub const EMITTED_IN_V0: &[&str] = &["OG-DS-102", "OG-DS-103", "OG-DS-104", "OG-MF-103", "OG-MF-106"]; +pub const EMITTED_IN_V0: &[&str] = &[ + "OG-DS-102", "OG-DS-103", "OG-DS-104", "OG-MF-103", "OG-MF-105", "OG-MF-106", "OG-MF-107", +]; /// Look up a code by its string identifier. pub fn lookup(code: &str) -> Option<&'static DiagnosticCode> {