Skip to main content

icydb_diagnostic_code/
fact.rs

1//! Module: fact
2//!
3//! Responsibility: production-safe numeric diagnostic-fact identities.
4//! Does not own: Candid records, rich labels, prose, or subsystem projections.
5//! Boundary: freezes the numeric vocabulary shared by public errors and host tooling.
6
7use std::fmt;
8
9use crate::ErrorCode;
10
11/// Maximum number of numeric facts carried by one public error.
12pub const MAX_PUBLIC_DIAGNOSTIC_FACTS: usize = 80;
13
14macro_rules! define_fact_tag_registry {
15    ($($name:ident = $raw:literal;)+) => {
16        /// Stable semantic identity for one numeric public diagnostic fact.
17        #[derive(Clone, Copy, Eq, Hash, PartialEq)]
18        pub enum DiagnosticFactTag {
19            $(
20                #[doc = concat!("Public fact tag ", stringify!($raw), ".")]
21                $name,
22            )+
23        }
24
25        impl DiagnosticFactTag {
26            /// Return the fixed public wire value.
27            #[must_use]
28            pub const fn raw(self) -> u8 {
29                match self {
30                    $(Self::$name => $raw,)+
31                }
32            }
33
34            /// Recover a known tag from its public wire value.
35            #[must_use]
36            pub const fn known(raw: u8) -> Option<Self> {
37                match raw {
38                    $($raw => Some(Self::$name),)+
39                    _ => None,
40                }
41            }
42        }
43
44        #[cfg(test)]
45        const ORDERED_FACT_TAGS: &[DiagnosticFactTag] = &[
46            $(DiagnosticFactTag::$name,)+
47        ];
48    };
49}
50
51// This table is a public numeric registry. Append only within a released
52// major-version contract; do not reuse or reinterpret an assigned value.
53define_fact_tag_registry! {
54    AcceptedSchemaFingerprintMethod = 1;
55    AcceptedSchemaFingerprintHigh = 2;
56    AcceptedSchemaFingerprintLow = 3;
57    ExpectedFingerprintPrefix = 4;
58    ActualFingerprintPrefix = 5;
59    EntityTag = 6;
60    ExpectedEntityTag = 7;
61    ActualEntityTag = 8;
62    ConstraintId = 9;
63    FieldId = 10;
64    IndexId = 11;
65    RelationId = 12;
66    MutationOperation = 13;
67    RowOperation = 14;
68    BatchPosition = 15;
69    FirstBatchPosition = 16;
70    DuplicateBatchPosition = 17;
71    ClauseIndex = 18;
72    TermIndex = 19;
73    FirstTermIndex = 20;
74    DuplicateTermIndex = 21;
75    ProjectionIndex = 22;
76    GroupIndex = 23;
77    AggregateIndex = 24;
78    ArgumentIndex = 25;
79    BranchIndex = 26;
80    ComponentIndex = 27;
81    ParameterIndex = 28;
82    SourceSpanStart = 29;
83    SourceSpanEnd = 30;
84    Expected = 31;
85    Actual = 32;
86    Minimum = 33;
87    Maximum = 34;
88    Limit = 35;
89    ExpectedCount = 36;
90    ActualCount = 37;
91    ExpectedRevision = 38;
92    ActualRevision = 39;
93    CurrentRevision = 40;
94    RequestedRevision = 41;
95    ExpectedVersion = 42;
96    ActualVersion = 43;
97    CurrentVersion = 44;
98    RequestedVersion = 45;
99    ExpectedOffset = 46;
100    ActualOffset = 47;
101    ExpectedArity = 48;
102    ActualArity = 49;
103    ExpectedLength = 50;
104    ActualLength = 51;
105    ExpectedSlotCount = 52;
106    ActualSlotCount = 53;
107    RowLayout = 54;
108    HistoryFloor = 55;
109    CurrentLayout = 56;
110    PhysicalSlot = 57;
111    PhysicalGeneration = 58;
112    ExpectedMemoryId = 59;
113    ActualMemoryId = 60;
114    ConstraintKind = 61;
115    ConstraintContext = 62;
116    FieldKind = 63;
117    ValueKind = 64;
118    TypeFamily = 65;
119    FunctionKind = 66;
120    OperatorKind = 67;
121    AggregateKind = 68;
122    KeyNamespaceKind = 69;
123    ComponentKind = 70;
124    MismatchKind = 71;
125    DecodeReason = 72;
126    BudgetResource = 73;
127    MigrationPhase = 74;
128    DatabaseControlRecordKind = 75;
129    StateKind = 76;
130    PayloadComponent = 77;
131    ExpectedSignaturePrefix = 78;
132    ActualSignaturePrefix = 79;
133    FindingPosition = 80;
134    RootField = 81;
135    RecordMember = 82;
136    TupleElement = 83;
137    Newtype = 84;
138    EnumVariant = 85;
139    ListElement = 86;
140    SetElement = 87;
141    MapEntryKey = 88;
142    MapEntryValue = 89;
143    ExecutionBudgetScope = 90;
144    ExecutionLane = 91;
145    QueryShapeFingerprintPrefix = 92;
146}
147
148/// Compact reason carried by [`DiagnosticFactTag::DecodeReason`].
149///
150/// Values are global within that fact tag. They identify only bounded decode
151/// or validation categories and never retain rejected payload bytes.
152#[derive(Clone, Copy, Eq, Hash, PartialEq)]
153pub enum DiagnosticDecodeReason {
154    CursorEmpty,
155    CursorTooLong,
156    CursorOddLength,
157    CursorInvalidHex,
158    CursorGroupedDirectionMismatch,
159    CursorTokenEncode,
160    CursorTokenDecode,
161    RecoveryMarkerMagic,
162    RecoveryMarkerChecksum,
163    RecoveryMarkerState,
164}
165
166/// Compact operation carried by [`DiagnosticFactTag::MutationOperation`].
167#[derive(Clone, Copy, Eq, Hash, PartialEq)]
168pub enum DiagnosticMutationOperation {
169    Insert,
170    Replace,
171    Update,
172    Delete,
173}
174
175macro_rules! define_numeric_fact_value_registry {
176    (
177        $(#[$enum_meta:meta])*
178        pub enum $name:ident {
179            $($variant:ident = $raw:literal;)+
180        }
181    ) => {
182        $(#[$enum_meta])*
183        #[derive(Clone, Copy, Eq, Hash, PartialEq)]
184        pub enum $name {
185            $(
186                #[doc = concat!("Compact diagnostic value ", stringify!($raw), ".")]
187                $variant,
188            )+
189        }
190
191        impl $name {
192            /// Return the fixed numeric fact value.
193            #[must_use]
194            pub const fn raw(self) -> u64 {
195                match self {
196                    $(Self::$variant => $raw,)+
197                }
198            }
199
200            /// Recover a known compact value from its public numeric identity.
201            #[must_use]
202            pub const fn known(raw: u64) -> Option<Self> {
203                match raw {
204                    $($raw => Some(Self::$variant),)+
205                    _ => None,
206                }
207            }
208        }
209
210        impl fmt::Debug for $name {
211            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212                write!(f, "{}", self.raw())
213            }
214        }
215    };
216}
217
218define_numeric_fact_value_registry! {
219    /// Compact hard-budget resource carried by [`DiagnosticFactTag::BudgetResource`].
220    pub enum DiagnosticExecutionBudgetResource {
221        QueryExecutions = 1;
222        PlanningSteps = 2;
223        PlanCompilations = 3;
224        KeyIndexEntriesVisited = 4;
225        RowsVisited = 5;
226        StoredBytesRead = 6;
227        PredicateExpressionSteps = 7;
228        NestedValueSteps = 8;
229        DecodedBytes = 9;
230        MaterializedBytes = 10;
231        SortEntries = 11;
232        SortComparisons = 12;
233        SortTemporaryBytes = 13;
234        GroupDistinctEntries = 14;
235        GroupDistinctStateBytes = 15;
236        CursorSteps = 16;
237        TemporaryBytes = 17;
238        DiagnosticSteps = 18;
239        ResultRows = 19;
240        ResultBytes = 20;
241        InstructionUnits = 21;
242    }
243}
244
245impl DiagnosticExecutionBudgetResource {
246    /// Every maintained hard-budget resource in stable numeric order.
247    pub const ALL: [Self; 21] = [
248        Self::QueryExecutions,
249        Self::PlanningSteps,
250        Self::PlanCompilations,
251        Self::KeyIndexEntriesVisited,
252        Self::RowsVisited,
253        Self::StoredBytesRead,
254        Self::PredicateExpressionSteps,
255        Self::NestedValueSteps,
256        Self::DecodedBytes,
257        Self::MaterializedBytes,
258        Self::SortEntries,
259        Self::SortComparisons,
260        Self::SortTemporaryBytes,
261        Self::GroupDistinctEntries,
262        Self::GroupDistinctStateBytes,
263        Self::CursorSteps,
264        Self::TemporaryBytes,
265        Self::DiagnosticSteps,
266        Self::ResultRows,
267        Self::ResultBytes,
268        Self::InstructionUnits,
269    ];
270}
271
272define_numeric_fact_value_registry! {
273    /// Compact counter owner carried by [`DiagnosticFactTag::ExecutionBudgetScope`].
274    pub enum DiagnosticExecutionBudgetScope {
275        Execution = 1;
276        Request = 2;
277    }
278}
279
280define_numeric_fact_value_registry! {
281    /// Compact execution lane carried by [`DiagnosticFactTag::ExecutionLane`].
282    pub enum DiagnosticExecutionLane {
283        PublicRead = 1;
284        TrustedRead = 2;
285        Diagnostic = 3;
286        Mutation = 4;
287        Recovery = 5;
288    }
289}
290
291define_numeric_fact_value_registry! {
292    /// Compact accepted constraint family carried by [`DiagnosticFactTag::ConstraintKind`].
293    pub enum DiagnosticConstraintKind {
294        Check = 1;
295        NotNull = 2;
296        Relation = 3;
297        TargetedRule = 4;
298        Unique = 5;
299    }
300}
301
302define_numeric_fact_value_registry! {
303    /// Compact enforcement boundary carried by [`DiagnosticFactTag::ConstraintContext`].
304    pub enum DiagnosticConstraintContext {
305        Integrity = 1;
306        MigrationValidation = 2;
307        WriteAdmission = 3;
308    }
309}
310
311define_numeric_fact_value_registry! {
312    /// Compact storage component carried by [`DiagnosticFactTag::ComponentKind`].
313    pub enum DiagnosticComponentKind {
314        CommitDataKey = 1;
315        IndexKey = 2;
316        IndexKeyComponent = 3;
317        RelationTargetPrimaryKey = 4;
318    }
319}
320
321define_numeric_fact_value_registry! {
322    /// Compact semantic family carried by [`DiagnosticFactTag::TypeFamily`].
323    pub enum DiagnosticTypeFamily {
324        Blob = 1;
325        Bool = 2;
326        Collection = 3;
327        Null = 4;
328        Numeric = 5;
329        Opaque = 6;
330        Structured = 7;
331        Text = 8;
332        Unknown = 9;
333    }
334}
335
336define_numeric_fact_value_registry! {
337    /// Compact function identity carried by [`DiagnosticFactTag::FunctionKind`].
338    pub enum DiagnosticFunctionKind {
339        Abs = 1;
340        Cbrt = 2;
341        Ceiling = 3;
342        Coalesce = 4;
343        CollectionContains = 5;
344        Contains = 6;
345        EndsWith = 7;
346        Exp = 8;
347        Floor = 9;
348        IsEmpty = 10;
349        IsMissing = 11;
350        IsNotEmpty = 12;
351        IsNotNull = 13;
352        IsNull = 14;
353        Left = 15;
354        Length = 16;
355        Ln = 17;
356        Log = 18;
357        Log2 = 19;
358        Log10 = 20;
359        Lower = 21;
360        Ltrim = 22;
361        Mod = 23;
362        NullIf = 24;
363        OctetLength = 25;
364        Position = 26;
365        Power = 27;
366        Replace = 28;
367        Right = 29;
368        Round = 30;
369        Rtrim = 31;
370        Sign = 32;
371        Sqrt = 33;
372        StartsWith = 34;
373        Substring = 35;
374        Trim = 36;
375        Trunc = 37;
376        Upper = 38;
377        InList = 39;
378    }
379}
380
381define_numeric_fact_value_registry! {
382    /// Compact operator identity carried by [`DiagnosticFactTag::OperatorKind`].
383    pub enum DiagnosticOperatorKind {
384        Not = 1;
385        Add = 2;
386        And = 3;
387        Div = 4;
388        Eq = 5;
389        Gt = 6;
390        Gte = 7;
391        Lt = 8;
392        Lte = 9;
393        Mul = 10;
394        Ne = 11;
395        Or = 12;
396        Sub = 13;
397        In = 14;
398        NotIn = 15;
399        Contains = 16;
400        StartsWith = 17;
401        EndsWith = 18;
402    }
403}
404
405define_numeric_fact_value_registry! {
406    /// Compact aggregate identity carried by [`DiagnosticFactTag::AggregateKind`].
407    pub enum DiagnosticAggregateKind {
408        Count = 1;
409        Sum = 2;
410        Avg = 3;
411        Exists = 4;
412        Min = 5;
413        Max = 6;
414        First = 7;
415        Last = 8;
416    }
417}
418
419impl DiagnosticDecodeReason {
420    /// Return the fixed numeric fact value.
421    #[must_use]
422    pub const fn raw(self) -> u64 {
423        match self {
424            Self::CursorEmpty => 1,
425            Self::CursorTooLong => 2,
426            Self::CursorOddLength => 3,
427            Self::CursorInvalidHex => 4,
428            Self::CursorGroupedDirectionMismatch => 5,
429            Self::CursorTokenEncode => 6,
430            Self::CursorTokenDecode => 7,
431            Self::RecoveryMarkerMagic => 8,
432            Self::RecoveryMarkerChecksum => 9,
433            Self::RecoveryMarkerState => 10,
434        }
435    }
436
437    /// Recover a known compact decode reason.
438    #[must_use]
439    pub const fn known(raw: u64) -> Option<Self> {
440        match raw {
441            1 => Some(Self::CursorEmpty),
442            2 => Some(Self::CursorTooLong),
443            3 => Some(Self::CursorOddLength),
444            4 => Some(Self::CursorInvalidHex),
445            5 => Some(Self::CursorGroupedDirectionMismatch),
446            6 => Some(Self::CursorTokenEncode),
447            7 => Some(Self::CursorTokenDecode),
448            8 => Some(Self::RecoveryMarkerMagic),
449            9 => Some(Self::RecoveryMarkerChecksum),
450            10 => Some(Self::RecoveryMarkerState),
451            _ => None,
452        }
453    }
454}
455
456impl DiagnosticMutationOperation {
457    /// Return the fixed numeric fact value.
458    #[must_use]
459    pub const fn raw(self) -> u64 {
460        match self {
461            Self::Insert => 1,
462            Self::Replace => 2,
463            Self::Update => 3,
464            Self::Delete => 4,
465        }
466    }
467
468    /// Recover a known compact mutation operation.
469    #[must_use]
470    pub const fn known(raw: u64) -> Option<Self> {
471        match raw {
472            1 => Some(Self::Insert),
473            2 => Some(Self::Replace),
474            3 => Some(Self::Update),
475            4 => Some(Self::Delete),
476            _ => None,
477        }
478    }
479}
480
481impl fmt::Debug for DiagnosticFactTag {
482    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
483        write!(f, "{}", self.raw())
484    }
485}
486
487impl fmt::Debug for DiagnosticDecodeReason {
488    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489        write!(f, "{}", self.raw())
490    }
491}
492
493impl fmt::Debug for DiagnosticMutationOperation {
494    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495        write!(f, "{}", self.raw())
496    }
497}
498
499/// Pack two accepted `u32` identities into one fact value without narrowing.
500#[must_use]
501pub const fn pack_u32_pair(high: u32, low: u32) -> u64 {
502    (high as u64) << 32 | low as u64
503}
504
505/// Recover the two accepted identities from one packed fact value.
506#[must_use]
507pub const fn unpack_u32_pair(value: u64) -> (u32, u32) {
508    let bytes = value.to_be_bytes();
509    (
510        u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
511        u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
512    )
513}
514
515/// Why one numeric fact sequence does not satisfy its owning E-code schema.
516///
517/// This taxonomy intentionally carries no prose. Host tooling owns rendering.
518#[derive(Clone, Copy, Debug, Eq, PartialEq)]
519pub enum DiagnosticFactSchemaMismatch {
520    /// The sequence exceeds the global public fact ceiling.
521    GlobalMaximumExceeded,
522    /// The sequence exceeds the tighter ceiling for its E-code.
523    CodeMaximumExceeded,
524    /// Required, allowed, repeated, or ordered tags do not match the E-code.
525    InvalidSequence,
526    /// One known compact tag carries a value outside its frozen numeric registry.
527    InvalidValue,
528}
529
530/// Validate facts already expressed with known production tag identities.
531///
532/// The validator allocates nothing. It is the runtime-side entry point used
533/// immediately before facts cross the public facade.
534pub fn validate_known_diagnostic_fact_schema(
535    code: ErrorCode,
536    facts: &[(DiagnosticFactTag, u64)],
537) -> Result<(), DiagnosticFactSchemaMismatch> {
538    validate_diagnostic_fact_schema(code, facts.len(), |index| {
539        let (tag, value) = facts[index];
540        (tag.raw(), value)
541    })
542}
543
544/// Validate raw host/tooling facts against their owning E-code schema.
545///
546/// Unknown tags remain renderable by callers, but make a known E-code context
547/// invalid instead of being heuristically reinterpreted.
548pub fn validate_raw_diagnostic_fact_schema(
549    code: ErrorCode,
550    facts: &[(u8, u64)],
551) -> Result<(), DiagnosticFactSchemaMismatch> {
552    validate_diagnostic_fact_schema(code, facts.len(), |index| facts[index])
553}
554
555#[expect(
556    clippy::too_many_lines,
557    reason = "the frozen E-code schema registry keeps every numeric owner visible in one exhaustive dispatch"
558)]
559fn validate_diagnostic_fact_schema(
560    code: ErrorCode,
561    fact_count: usize,
562    fact_at: impl Fn(usize) -> (u8, u64),
563) -> Result<(), DiagnosticFactSchemaMismatch> {
564    if fact_count > MAX_PUBLIC_DIAGNOSTIC_FACTS {
565        return Err(DiagnosticFactSchemaMismatch::GlobalMaximumExceeded);
566    }
567
568    let maximum = diagnostic_fact_maximum(code);
569    if fact_count > maximum {
570        return Err(DiagnosticFactSchemaMismatch::CodeMaximumExceeded);
571    }
572
573    let valid_sequence = match code.raw() {
574        3 => query_plan_schema(fact_count, &fact_at),
575        6 => cursor_schema(fact_count, &fact_at),
576        16 => store_corruption_schema(fact_count, &fact_at),
577        18 => runtime_corruption_schema(fact_count, &fact_at),
578        19 => incompatible_format_schema(fact_count, &fact_at),
579        20 => runtime_invariant_schema(fact_count, &fact_at),
580        21 => runtime_conflict_schema(fact_count, &fact_at),
581        23 => runtime_unsupported_schema(fact_count, &fact_at),
582        24 => runtime_internal_schema(fact_count, &fact_at),
583        138 => tags_match(
584            fact_count,
585            &fact_at,
586            &[
587                DiagnosticFactTag::ExpectedArity,
588                DiagnosticFactTag::ActualArity,
589            ],
590        ),
591        141 | 142 | 169 | 170 => {
592            tags_match(fact_count, &fact_at, &[DiagnosticFactTag::ProjectionIndex])
593        }
594        175 => tags_match(fact_count, &fact_at, &[DiagnosticFactTag::ParameterIndex]),
595        177 | 237 => {
596            tags_match(fact_count, &fact_at, &[DiagnosticFactTag::Limit])
597                || tags_match(
598                    fact_count,
599                    &fact_at,
600                    &[DiagnosticFactTag::ActualLength, DiagnosticFactTag::Limit],
601                )
602        }
603        178 | 180 | 202 | 203 | 205 | 236 | 269 => tags_match(
604            fact_count,
605            &fact_at,
606            &[DiagnosticFactTag::ActualCount, DiagnosticFactTag::Limit],
607        ),
608        283 => {
609            tags_match(fact_count, &fact_at, &[DiagnosticFactTag::Limit])
610                || tags_match(
611                    fact_count,
612                    &fact_at,
613                    &[DiagnosticFactTag::ActualCount, DiagnosticFactTag::Limit],
614                )
615        }
616        196 | 234 => tags_match(
617            fact_count,
618            &fact_at,
619            &[
620                DiagnosticFactTag::EntityTag,
621                DiagnosticFactTag::FieldId,
622                DiagnosticFactTag::MutationOperation,
623                DiagnosticFactTag::BatchPosition,
624            ],
625        ),
626        197 => tags_match(
627            fact_count,
628            &fact_at,
629            &[
630                DiagnosticFactTag::RowLayout,
631                DiagnosticFactTag::HistoryFloor,
632                DiagnosticFactTag::CurrentLayout,
633            ],
634        ),
635        198 => tags_match(
636            fact_count,
637            &fact_at,
638            &[
639                DiagnosticFactTag::RowLayout,
640                DiagnosticFactTag::ExpectedSlotCount,
641                DiagnosticFactTag::ActualSlotCount,
642            ],
643        ),
644        201 => tags_match(
645            fact_count,
646            &fact_at,
647            &[DiagnosticFactTag::ActualCount, DiagnosticFactTag::Minimum],
648        ),
649        223 => constraint_schema(fact_count, &fact_at, true),
650        225 => constraint_schema(fact_count, &fact_at, false),
651        233 => tags_match(
652            fact_count,
653            &fact_at,
654            &[
655                DiagnosticFactTag::EntityTag,
656                DiagnosticFactTag::MutationOperation,
657                DiagnosticFactTag::BatchPosition,
658            ],
659        ),
660        235 => {
661            tags_match(fact_count, &fact_at, &[DiagnosticFactTag::ActualCount]) && fact_at(0).1 == 0
662        }
663        238 | 270 | 271 | 272 => tags_match(
664            fact_count,
665            &fact_at,
666            &[DiagnosticFactTag::ActualLength, DiagnosticFactTag::Limit],
667        ),
668        273 => tags_match(
669            fact_count,
670            &fact_at,
671            &[
672                DiagnosticFactTag::BudgetResource,
673                DiagnosticFactTag::Limit,
674                DiagnosticFactTag::Actual,
675                DiagnosticFactTag::ExecutionBudgetScope,
676                DiagnosticFactTag::ExecutionLane,
677                DiagnosticFactTag::QueryShapeFingerprintPrefix,
678            ],
679        ),
680        274 => tags_match(
681            fact_count,
682            &fact_at,
683            &[
684                DiagnosticFactTag::BudgetResource,
685                DiagnosticFactTag::Limit,
686                DiagnosticFactTag::Actual,
687            ],
688        ),
689        239 => tags_match(
690            fact_count,
691            &fact_at,
692            &[
693                DiagnosticFactTag::BatchPosition,
694                DiagnosticFactTag::ExpectedEntityTag,
695                DiagnosticFactTag::ActualEntityTag,
696            ],
697        ),
698        240 => tags_match(
699            fact_count,
700            &fact_at,
701            &[
702                DiagnosticFactTag::EntityTag,
703                DiagnosticFactTag::FirstBatchPosition,
704                DiagnosticFactTag::DuplicateBatchPosition,
705            ],
706        ),
707        _ => fact_count == 0,
708    };
709    if !valid_sequence {
710        return Err(DiagnosticFactSchemaMismatch::InvalidSequence);
711    }
712
713    for index in 0..fact_count {
714        let (raw_tag, value) = fact_at(index);
715        let Some(tag) = DiagnosticFactTag::known(raw_tag) else {
716            return Err(DiagnosticFactSchemaMismatch::InvalidSequence);
717        };
718        if !diagnostic_fact_value_is_valid(tag, value) {
719            return Err(DiagnosticFactSchemaMismatch::InvalidValue);
720        }
721    }
722    Ok(())
723}
724
725const fn diagnostic_fact_maximum(code: ErrorCode) -> usize {
726    match code.raw() {
727        6 | 16 | 18 | 24 | 197 | 198 | 233 | 239 | 240 | 274 => 3,
728        141 | 142 | 169 | 170 | 175 | 235 => 1,
729        19 | 21 | 138 | 177 | 178 | 180 | 201 | 202 | 203 | 205 | 236 | 237 | 238 | 269 | 270
730        | 271 | 272 | 283 => 2,
731        3 | 20 => 5,
732        23 | 273 => 6,
733        196 | 234 => 4,
734        223 => 73,
735        225 => 9,
736        _ => 0,
737    }
738}
739
740#[expect(
741    clippy::too_many_lines,
742    reason = "the query-plan E-code deliberately owns several exact finite fact sequences"
743)]
744fn query_plan_schema(fact_count: usize, fact_at: &impl Fn(usize) -> (u8, u64)) -> bool {
745    fact_count == 0
746        || tags_match(fact_count, fact_at, &[DiagnosticFactTag::TermIndex])
747        || tags_match(fact_count, fact_at, &[DiagnosticFactTag::ComponentIndex])
748        || tags_match(fact_count, fact_at, &[DiagnosticFactTag::GroupIndex])
749        || tags_match(fact_count, fact_at, &[DiagnosticFactTag::ClauseIndex])
750        || tags_match(fact_count, fact_at, &[DiagnosticFactTag::AggregateIndex])
751        || tags_match(fact_count, fact_at, &[DiagnosticFactTag::AggregateKind])
752        || tags_match(fact_count, fact_at, &[DiagnosticFactTag::ProjectionIndex])
753        || tags_match(
754            fact_count,
755            fact_at,
756            &[
757                DiagnosticFactTag::FirstTermIndex,
758                DiagnosticFactTag::DuplicateTermIndex,
759            ],
760        )
761        || tags_match(
762            fact_count,
763            fact_at,
764            &[
765                DiagnosticFactTag::ClauseIndex,
766                DiagnosticFactTag::OperatorKind,
767            ],
768        )
769        || tags_match(
770            fact_count,
771            fact_at,
772            &[
773                DiagnosticFactTag::AggregateIndex,
774                DiagnosticFactTag::AggregateKind,
775            ],
776        )
777        || tags_match(
778            fact_count,
779            fact_at,
780            &[
781                DiagnosticFactTag::AggregateKind,
782                DiagnosticFactTag::TypeFamily,
783            ],
784        )
785        || tags_match(
786            fact_count,
787            fact_at,
788            &[
789                DiagnosticFactTag::OperatorKind,
790                DiagnosticFactTag::TypeFamily,
791            ],
792        )
793        || tags_match(
794            fact_count,
795            fact_at,
796            &[
797                DiagnosticFactTag::BranchIndex,
798                DiagnosticFactTag::TypeFamily,
799            ],
800        )
801        || tags_match(
802            fact_count,
803            fact_at,
804            &[DiagnosticFactTag::TypeFamily, DiagnosticFactTag::TypeFamily],
805        )
806        || tags_match(
807            fact_count,
808            fact_at,
809            &[
810                DiagnosticFactTag::ClauseIndex,
811                DiagnosticFactTag::AggregateIndex,
812                DiagnosticFactTag::ActualCount,
813            ],
814        )
815        || tags_match(
816            fact_count,
817            fact_at,
818            &[
819                DiagnosticFactTag::FunctionKind,
820                DiagnosticFactTag::ExpectedArity,
821                DiagnosticFactTag::ActualArity,
822            ],
823        )
824        || tags_match(
825            fact_count,
826            fact_at,
827            &[
828                DiagnosticFactTag::FunctionKind,
829                DiagnosticFactTag::ArgumentIndex,
830                DiagnosticFactTag::TypeFamily,
831            ],
832        )
833        || tags_match(
834            fact_count,
835            fact_at,
836            &[
837                DiagnosticFactTag::OperatorKind,
838                DiagnosticFactTag::TypeFamily,
839                DiagnosticFactTag::TypeFamily,
840            ],
841        )
842        || tags_match(
843            fact_count,
844            fact_at,
845            &[
846                DiagnosticFactTag::BranchIndex,
847                DiagnosticFactTag::TypeFamily,
848                DiagnosticFactTag::TypeFamily,
849            ],
850        )
851        || tags_match(
852            fact_count,
853            fact_at,
854            &[
855                DiagnosticFactTag::TypeFamily,
856                DiagnosticFactTag::BranchIndex,
857                DiagnosticFactTag::TypeFamily,
858            ],
859        )
860        || tags_match(
861            fact_count,
862            fact_at,
863            &[
864                DiagnosticFactTag::BranchIndex,
865                DiagnosticFactTag::TypeFamily,
866                DiagnosticFactTag::BranchIndex,
867                DiagnosticFactTag::TypeFamily,
868            ],
869        )
870        || tags_match(
871            fact_count,
872            fact_at,
873            &[
874                DiagnosticFactTag::FunctionKind,
875                DiagnosticFactTag::ArgumentIndex,
876                DiagnosticFactTag::TypeFamily,
877                DiagnosticFactTag::ArgumentIndex,
878                DiagnosticFactTag::TypeFamily,
879            ],
880        )
881}
882
883fn cursor_schema(fact_count: usize, fact_at: &impl Fn(usize) -> (u8, u64)) -> bool {
884    if fact_count == 0 {
885        return true;
886    }
887    if tags_match(fact_count, fact_at, &[DiagnosticFactTag::DecodeReason]) {
888        return matches!(fact_at(0).1, 1 | 3 | 5 | 6 | 7);
889    }
890    if tags_match(
891        fact_count,
892        fact_at,
893        &[
894            DiagnosticFactTag::ActualLength,
895            DiagnosticFactTag::Maximum,
896            DiagnosticFactTag::DecodeReason,
897        ],
898    ) {
899        return fact_at(2).1 == DiagnosticDecodeReason::CursorTooLong.raw();
900    }
901    if tags_match(
902        fact_count,
903        fact_at,
904        &[
905            DiagnosticFactTag::ComponentIndex,
906            DiagnosticFactTag::DecodeReason,
907        ],
908    ) {
909        return matches!(fact_at(1).1, 4 | 6 | 7);
910    }
911    tags_match(
912        fact_count,
913        fact_at,
914        &[
915            DiagnosticFactTag::ExpectedSignaturePrefix,
916            DiagnosticFactTag::ActualSignaturePrefix,
917        ],
918    ) || tags_match(
919        fact_count,
920        fact_at,
921        &[
922            DiagnosticFactTag::ExpectedOffset,
923            DiagnosticFactTag::ActualOffset,
924        ],
925    )
926}
927
928fn store_corruption_schema(fact_count: usize, fact_at: &impl Fn(usize) -> (u8, u64)) -> bool {
929    fact_count == 0
930        || (tags_match(
931            fact_count,
932            fact_at,
933            &[
934                DiagnosticFactTag::ComponentKind,
935                DiagnosticFactTag::ActualLength,
936                DiagnosticFactTag::Limit,
937            ],
938        ) && fact_at(0).1 == DiagnosticComponentKind::CommitDataKey.raw())
939        || tags_match(
940            fact_count,
941            fact_at,
942            &[
943                DiagnosticFactTag::ExpectedEntityTag,
944                DiagnosticFactTag::ActualEntityTag,
945            ],
946        )
947}
948
949fn runtime_corruption_schema(fact_count: usize, fact_at: &impl Fn(usize) -> (u8, u64)) -> bool {
950    store_corruption_schema(fact_count, fact_at)
951        || (tags_match(fact_count, fact_at, &[DiagnosticFactTag::DecodeReason])
952            && matches!(fact_at(0).1, 8..=10))
953}
954
955fn incompatible_format_schema(fact_count: usize, fact_at: &impl Fn(usize) -> (u8, u64)) -> bool {
956    fact_count == 0
957        || tags_match(fact_count, fact_at, &[DiagnosticFactTag::ExpectedVersion])
958        || tags_match(
959            fact_count,
960            fact_at,
961            &[
962                DiagnosticFactTag::ExpectedVersion,
963                DiagnosticFactTag::ActualVersion,
964            ],
965        )
966}
967
968fn runtime_invariant_schema(fact_count: usize, fact_at: &impl Fn(usize) -> (u8, u64)) -> bool {
969    fact_count == 0
970        || (tags_match(
971            fact_count,
972            fact_at,
973            &[
974                DiagnosticFactTag::EntityTag,
975                DiagnosticFactTag::PhysicalGeneration,
976                DiagnosticFactTag::ComponentKind,
977                DiagnosticFactTag::ActualArity,
978                DiagnosticFactTag::Maximum,
979            ],
980        ) && fact_at(2).1 == DiagnosticComponentKind::IndexKey.raw())
981}
982
983fn runtime_conflict_schema(fact_count: usize, fact_at: &impl Fn(usize) -> (u8, u64)) -> bool {
984    fact_count == 0
985        || tags_match(fact_count, fact_at, &[DiagnosticFactTag::ExpectedRevision])
986        || tags_match(
987            fact_count,
988            fact_at,
989            &[
990                DiagnosticFactTag::ExpectedRevision,
991                DiagnosticFactTag::CurrentRevision,
992            ],
993        )
994}
995
996fn runtime_unsupported_schema(fact_count: usize, fact_at: &impl Fn(usize) -> (u8, u64)) -> bool {
997    fact_count == 0
998        || (tags_match(
999            fact_count,
1000            fact_at,
1001            &[
1002                DiagnosticFactTag::EntityTag,
1003                DiagnosticFactTag::PhysicalGeneration,
1004                DiagnosticFactTag::ComponentIndex,
1005                DiagnosticFactTag::ComponentKind,
1006                DiagnosticFactTag::ActualLength,
1007                DiagnosticFactTag::Limit,
1008            ],
1009        ) && fact_at(3).1 == DiagnosticComponentKind::IndexKeyComponent.raw())
1010}
1011
1012fn runtime_internal_schema(fact_count: usize, fact_at: &impl Fn(usize) -> (u8, u64)) -> bool {
1013    fact_count == 0
1014        || tags_match(
1015            fact_count,
1016            fact_at,
1017            &[
1018                DiagnosticFactTag::ExpectedMemoryId,
1019                DiagnosticFactTag::ActualMemoryId,
1020            ],
1021        )
1022        || (tags_match(
1023            fact_count,
1024            fact_at,
1025            &[
1026                DiagnosticFactTag::ComponentKind,
1027                DiagnosticFactTag::ExpectedArity,
1028                DiagnosticFactTag::ActualArity,
1029            ],
1030        ) && fact_at(0).1 == DiagnosticComponentKind::RelationTargetPrimaryKey.raw())
1031}
1032
1033fn constraint_schema(
1034    fact_count: usize,
1035    fact_at: &impl Fn(usize) -> (u8, u64),
1036    allow_targeted_path: bool,
1037) -> bool {
1038    const COMMON: &[DiagnosticFactTag] = &[
1039        DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
1040        DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
1041        DiagnosticFactTag::AcceptedSchemaFingerprintLow,
1042        DiagnosticFactTag::EntityTag,
1043        DiagnosticFactTag::ConstraintId,
1044        DiagnosticFactTag::ConstraintKind,
1045        DiagnosticFactTag::ConstraintContext,
1046    ];
1047    if fact_count < COMMON.len()
1048        || !tags_prefix_matches(fact_count, fact_at, COMMON)
1049        || fact_at(6).1 != DiagnosticConstraintContext::WriteAdmission.raw()
1050    {
1051        return false;
1052    }
1053
1054    let constraint_kind = fact_at(5).1;
1055    if DiagnosticConstraintKind::known(constraint_kind).is_none() {
1056        return false;
1057    }
1058    let mut index = COMMON.len();
1059    if index < fact_count && fact_at(index).0 == DiagnosticFactTag::MutationOperation.raw() {
1060        index += 1;
1061        if index < fact_count && fact_at(index).0 == DiagnosticFactTag::BatchPosition.raw() {
1062            index += 1;
1063        }
1064    }
1065
1066    let path_len = fact_count - index;
1067    if path_len == 0 {
1068        return !allow_targeted_path
1069            || constraint_kind != DiagnosticConstraintKind::TargetedRule.raw();
1070    }
1071    allow_targeted_path
1072        && constraint_kind == DiagnosticConstraintKind::TargetedRule.raw()
1073        && path_len <= 64
1074        && (index..fact_count).all(|position| {
1075            DiagnosticFactTag::known(fact_at(position).0).is_some_and(is_value_path_tag)
1076        })
1077}
1078
1079fn tags_match(
1080    fact_count: usize,
1081    fact_at: &impl Fn(usize) -> (u8, u64),
1082    expected: &[DiagnosticFactTag],
1083) -> bool {
1084    fact_count == expected.len() && tags_prefix_matches(fact_count, fact_at, expected)
1085}
1086
1087fn tags_prefix_matches(
1088    fact_count: usize,
1089    fact_at: &impl Fn(usize) -> (u8, u64),
1090    expected: &[DiagnosticFactTag],
1091) -> bool {
1092    fact_count >= expected.len()
1093        && expected
1094            .iter()
1095            .enumerate()
1096            .all(|(index, tag)| fact_at(index).0 == tag.raw())
1097}
1098
1099const fn is_value_path_tag(tag: DiagnosticFactTag) -> bool {
1100    matches!(
1101        tag,
1102        DiagnosticFactTag::RootField
1103            | DiagnosticFactTag::RecordMember
1104            | DiagnosticFactTag::TupleElement
1105            | DiagnosticFactTag::Newtype
1106            | DiagnosticFactTag::EnumVariant
1107            | DiagnosticFactTag::ListElement
1108            | DiagnosticFactTag::SetElement
1109            | DiagnosticFactTag::MapEntryKey
1110            | DiagnosticFactTag::MapEntryValue
1111    )
1112}
1113
1114const fn diagnostic_fact_value_is_valid(tag: DiagnosticFactTag, value: u64) -> bool {
1115    match tag {
1116        DiagnosticFactTag::AcceptedSchemaFingerprintMethod
1117        | DiagnosticFactTag::ExpectedMemoryId
1118        | DiagnosticFactTag::ActualMemoryId => value <= u8::MAX as u64,
1119        DiagnosticFactTag::ConstraintId
1120        | DiagnosticFactTag::FieldId
1121        | DiagnosticFactTag::IndexId
1122        | DiagnosticFactTag::RelationId
1123        | DiagnosticFactTag::BatchPosition
1124        | DiagnosticFactTag::FirstBatchPosition
1125        | DiagnosticFactTag::DuplicateBatchPosition
1126        | DiagnosticFactTag::RowLayout
1127        | DiagnosticFactTag::HistoryFloor
1128        | DiagnosticFactTag::CurrentLayout
1129        | DiagnosticFactTag::RootField
1130        | DiagnosticFactTag::Newtype
1131        | DiagnosticFactTag::ListElement
1132        | DiagnosticFactTag::SetElement
1133        | DiagnosticFactTag::MapEntryKey
1134        | DiagnosticFactTag::MapEntryValue => value <= u32::MAX as u64,
1135        DiagnosticFactTag::ConstraintKind => DiagnosticConstraintKind::known(value).is_some(),
1136        DiagnosticFactTag::ConstraintContext => DiagnosticConstraintContext::known(value).is_some(),
1137        DiagnosticFactTag::TypeFamily => DiagnosticTypeFamily::known(value).is_some(),
1138        DiagnosticFactTag::FunctionKind => DiagnosticFunctionKind::known(value).is_some(),
1139        DiagnosticFactTag::OperatorKind => DiagnosticOperatorKind::known(value).is_some(),
1140        DiagnosticFactTag::AggregateKind => DiagnosticAggregateKind::known(value).is_some(),
1141        DiagnosticFactTag::ComponentKind => DiagnosticComponentKind::known(value).is_some(),
1142        DiagnosticFactTag::DecodeReason => DiagnosticDecodeReason::known(value).is_some(),
1143        DiagnosticFactTag::BudgetResource => {
1144            DiagnosticExecutionBudgetResource::known(value).is_some()
1145        }
1146        DiagnosticFactTag::ExecutionBudgetScope => {
1147            DiagnosticExecutionBudgetScope::known(value).is_some()
1148        }
1149        DiagnosticFactTag::ExecutionLane => DiagnosticExecutionLane::known(value).is_some(),
1150        DiagnosticFactTag::MutationOperation => DiagnosticMutationOperation::known(value).is_some(),
1151        _ => true,
1152    }
1153}
1154
1155#[cfg(test)]
1156mod tests {
1157    use super::{
1158        DiagnosticAggregateKind, DiagnosticComponentKind, DiagnosticConstraintContext,
1159        DiagnosticConstraintKind, DiagnosticDecodeReason, DiagnosticExecutionBudgetResource,
1160        DiagnosticExecutionBudgetScope, DiagnosticExecutionLane, DiagnosticFactSchemaMismatch,
1161        DiagnosticFactTag, DiagnosticFunctionKind, DiagnosticMutationOperation,
1162        DiagnosticOperatorKind, DiagnosticTypeFamily, ORDERED_FACT_TAGS, pack_u32_pair,
1163        unpack_u32_pair, validate_known_diagnostic_fact_schema,
1164        validate_raw_diagnostic_fact_schema,
1165    };
1166    use crate::ErrorCode;
1167
1168    #[test]
1169    fn fact_tag_registry_is_fixed_unique_and_contiguous() {
1170        for (index, tag) in ORDERED_FACT_TAGS.iter().copied().enumerate() {
1171            let expected = u8::try_from(index + 1).expect("fact-tag index fits u8");
1172            assert_eq!(tag.raw(), expected);
1173            assert_eq!(DiagnosticFactTag::known(expected), Some(tag));
1174        }
1175
1176        assert_eq!(DiagnosticFactTag::known(0), None);
1177        assert_eq!(DiagnosticFactTag::known(93), None);
1178        assert_eq!(DiagnosticFactTag::known(u8::MAX), None);
1179    }
1180
1181    #[test]
1182    fn execution_budget_fact_value_registries_are_fixed() {
1183        for (index, resource) in DiagnosticExecutionBudgetResource::ALL
1184            .iter()
1185            .copied()
1186            .enumerate()
1187        {
1188            let expected = u64::try_from(index + 1).expect("resource index fits u64");
1189            assert_eq!(resource.raw(), expected);
1190            assert_eq!(
1191                DiagnosticExecutionBudgetResource::known(expected),
1192                Some(resource)
1193            );
1194        }
1195        assert_eq!(DiagnosticExecutionBudgetResource::known(0), None);
1196        assert_eq!(DiagnosticExecutionBudgetResource::known(22), None);
1197
1198        assert_eq!(DiagnosticExecutionBudgetScope::Execution.raw(), 1);
1199        assert_eq!(DiagnosticExecutionBudgetScope::Request.raw(), 2);
1200        assert_eq!(DiagnosticExecutionBudgetScope::known(3), None);
1201
1202        assert_eq!(DiagnosticExecutionLane::PublicRead.raw(), 1);
1203        assert_eq!(DiagnosticExecutionLane::TrustedRead.raw(), 2);
1204        assert_eq!(DiagnosticExecutionLane::Diagnostic.raw(), 3);
1205        assert_eq!(DiagnosticExecutionLane::Mutation.raw(), 4);
1206        assert_eq!(DiagnosticExecutionLane::Recovery.raw(), 5);
1207        assert_eq!(DiagnosticExecutionLane::known(6), None);
1208    }
1209
1210    #[test]
1211    fn accepted_identity_pair_packing_is_exact() {
1212        for pair in [
1213            (0, 0),
1214            (1, 2),
1215            (u32::MAX, 0),
1216            (0, u32::MAX),
1217            (u32::MAX, u32::MAX),
1218        ] {
1219            assert_eq!(unpack_u32_pair(pack_u32_pair(pair.0, pair.1)), pair);
1220        }
1221    }
1222
1223    #[test]
1224    fn constraint_fact_value_registries_are_fixed() {
1225        assert_eq!(DiagnosticConstraintKind::Check.raw(), 1);
1226        assert_eq!(DiagnosticConstraintKind::NotNull.raw(), 2);
1227        assert_eq!(DiagnosticConstraintKind::Relation.raw(), 3);
1228        assert_eq!(DiagnosticConstraintKind::TargetedRule.raw(), 4);
1229        assert_eq!(DiagnosticConstraintKind::Unique.raw(), 5);
1230        assert_eq!(DiagnosticConstraintKind::known(0), None);
1231        assert_eq!(DiagnosticConstraintKind::known(6), None);
1232
1233        assert_eq!(DiagnosticConstraintContext::Integrity.raw(), 1);
1234        assert_eq!(DiagnosticConstraintContext::MigrationValidation.raw(), 2);
1235        assert_eq!(DiagnosticConstraintContext::WriteAdmission.raw(), 3);
1236        assert_eq!(DiagnosticConstraintContext::known(0), None);
1237        assert_eq!(DiagnosticConstraintContext::known(4), None);
1238    }
1239
1240    #[test]
1241    fn component_kind_registry_is_fixed_and_numeric() {
1242        let kinds = [
1243            DiagnosticComponentKind::CommitDataKey,
1244            DiagnosticComponentKind::IndexKey,
1245            DiagnosticComponentKind::IndexKeyComponent,
1246            DiagnosticComponentKind::RelationTargetPrimaryKey,
1247        ];
1248
1249        for (index, kind) in kinds.iter().copied().enumerate() {
1250            let expected = (index + 1) as u64;
1251            assert_eq!(kind.raw(), expected);
1252            assert_eq!(DiagnosticComponentKind::known(expected), Some(kind));
1253            assert_eq!(format!("{kind:?}"), expected.to_string());
1254        }
1255        assert_eq!(DiagnosticComponentKind::known(0), None);
1256        assert_eq!(DiagnosticComponentKind::known(5), None);
1257    }
1258
1259    #[test]
1260    fn decode_reason_registry_is_fixed_and_numeric() {
1261        let reasons = [
1262            DiagnosticDecodeReason::CursorEmpty,
1263            DiagnosticDecodeReason::CursorTooLong,
1264            DiagnosticDecodeReason::CursorOddLength,
1265            DiagnosticDecodeReason::CursorInvalidHex,
1266            DiagnosticDecodeReason::CursorGroupedDirectionMismatch,
1267            DiagnosticDecodeReason::CursorTokenEncode,
1268            DiagnosticDecodeReason::CursorTokenDecode,
1269            DiagnosticDecodeReason::RecoveryMarkerMagic,
1270            DiagnosticDecodeReason::RecoveryMarkerChecksum,
1271            DiagnosticDecodeReason::RecoveryMarkerState,
1272        ];
1273
1274        for (index, reason) in reasons.iter().copied().enumerate() {
1275            let expected = (index + 1) as u64;
1276            assert_eq!(reason.raw(), expected);
1277            assert_eq!(DiagnosticDecodeReason::known(expected), Some(reason));
1278            assert_eq!(format!("{reason:?}"), expected.to_string());
1279        }
1280
1281        assert_eq!(DiagnosticDecodeReason::known(0), None);
1282        assert_eq!(DiagnosticDecodeReason::known(11), None);
1283    }
1284
1285    #[test]
1286    fn mutation_operation_registry_is_fixed_and_numeric() {
1287        let operations = [
1288            DiagnosticMutationOperation::Insert,
1289            DiagnosticMutationOperation::Replace,
1290            DiagnosticMutationOperation::Update,
1291            DiagnosticMutationOperation::Delete,
1292        ];
1293
1294        for (index, operation) in operations.iter().copied().enumerate() {
1295            let expected = (index + 1) as u64;
1296            assert_eq!(operation.raw(), expected);
1297            assert_eq!(
1298                DiagnosticMutationOperation::known(expected),
1299                Some(operation)
1300            );
1301            assert_eq!(format!("{operation:?}"), expected.to_string());
1302        }
1303
1304        assert_eq!(DiagnosticMutationOperation::known(0), None);
1305        assert_eq!(DiagnosticMutationOperation::known(5), None);
1306    }
1307
1308    #[test]
1309    fn query_kind_registries_are_fixed_contiguous_and_numeric() {
1310        for raw in 1..=9 {
1311            let value = DiagnosticTypeFamily::known(raw).expect("type family should be known");
1312            assert_eq!(value.raw(), raw);
1313            assert_eq!(format!("{value:?}"), raw.to_string());
1314        }
1315        assert_eq!(DiagnosticTypeFamily::known(0), None);
1316        assert_eq!(DiagnosticTypeFamily::known(10), None);
1317
1318        for raw in 1..=39 {
1319            let value = DiagnosticFunctionKind::known(raw).expect("function kind should be known");
1320            assert_eq!(value.raw(), raw);
1321            assert_eq!(format!("{value:?}"), raw.to_string());
1322        }
1323        assert_eq!(DiagnosticFunctionKind::known(0), None);
1324        assert_eq!(DiagnosticFunctionKind::known(40), None);
1325
1326        for raw in 1..=18 {
1327            let value = DiagnosticOperatorKind::known(raw).expect("operator kind should be known");
1328            assert_eq!(value.raw(), raw);
1329            assert_eq!(format!("{value:?}"), raw.to_string());
1330        }
1331        assert_eq!(DiagnosticOperatorKind::known(0), None);
1332        assert_eq!(DiagnosticOperatorKind::known(19), None);
1333
1334        for raw in 1..=8 {
1335            let value =
1336                DiagnosticAggregateKind::known(raw).expect("aggregate kind should be known");
1337            assert_eq!(value.raw(), raw);
1338            assert_eq!(format!("{value:?}"), raw.to_string());
1339        }
1340        assert_eq!(DiagnosticAggregateKind::known(0), None);
1341        assert_eq!(DiagnosticAggregateKind::known(9), None);
1342    }
1343
1344    #[test]
1345    fn per_code_schema_rejects_missing_disallowed_and_noncanonical_tags() {
1346        let valid = [
1347            (DiagnosticFactTag::ActualCount, 5),
1348            (DiagnosticFactTag::Limit, 4),
1349        ];
1350        assert_eq!(
1351            validate_known_diagnostic_fact_schema(
1352                ErrorCode::RUNTIME_BOUNDARY_MUTATION_BATCH_TOO_MANY_ITEMS,
1353                &valid,
1354            ),
1355            Ok(())
1356        );
1357        assert_eq!(
1358            validate_known_diagnostic_fact_schema(
1359                ErrorCode::RUNTIME_BOUNDARY_MUTATION_BATCH_TOO_MANY_ITEMS,
1360                &valid[..1],
1361            ),
1362            Err(DiagnosticFactSchemaMismatch::InvalidSequence)
1363        );
1364        assert_eq!(
1365            validate_known_diagnostic_fact_schema(
1366                ErrorCode::RUNTIME_BOUNDARY_MUTATION_BATCH_TOO_MANY_ITEMS,
1367                &[valid[1], valid[0]],
1368            ),
1369            Err(DiagnosticFactSchemaMismatch::InvalidSequence)
1370        );
1371        assert_eq!(
1372            validate_known_diagnostic_fact_schema(ErrorCode::QUERY_VALIDATE, &valid),
1373            Err(DiagnosticFactSchemaMismatch::CodeMaximumExceeded)
1374        );
1375
1376        assert_eq!(
1377            validate_known_diagnostic_fact_schema(
1378                ErrorCode::RUNTIME_BOUNDARY_MUTATION_BATCH_COMMIT_WORK_EXCEEDED,
1379                &valid,
1380            ),
1381            Ok(())
1382        );
1383        assert_eq!(
1384            validate_known_diagnostic_fact_schema(
1385                ErrorCode::RUNTIME_BOUNDARY_MUTATION_BATCH_COMMIT_WORK_EXCEEDED,
1386                &valid[1..],
1387            ),
1388            Ok(())
1389        );
1390    }
1391
1392    #[test]
1393    fn execution_budget_schema_requires_complete_typed_attribution() {
1394        let valid = [
1395            (
1396                DiagnosticFactTag::BudgetResource,
1397                DiagnosticExecutionBudgetResource::StoredBytesRead.raw(),
1398            ),
1399            (DiagnosticFactTag::Limit, 4_096),
1400            (DiagnosticFactTag::Actual, 4_097),
1401            (
1402                DiagnosticFactTag::ExecutionBudgetScope,
1403                DiagnosticExecutionBudgetScope::Request.raw(),
1404            ),
1405            (
1406                DiagnosticFactTag::ExecutionLane,
1407                DiagnosticExecutionLane::TrustedRead.raw(),
1408            ),
1409            (DiagnosticFactTag::QueryShapeFingerprintPrefix, 17),
1410        ];
1411        assert_eq!(
1412            validate_known_diagnostic_fact_schema(
1413                ErrorCode::RUNTIME_BOUNDARY_EXECUTION_BUDGET_EXCEEDED,
1414                &valid,
1415            ),
1416            Ok(())
1417        );
1418        assert_eq!(
1419            validate_known_diagnostic_fact_schema(
1420                ErrorCode::RUNTIME_BOUNDARY_EXECUTION_BUDGET_EXCEEDED,
1421                &valid[..5],
1422            ),
1423            Err(DiagnosticFactSchemaMismatch::InvalidSequence)
1424        );
1425
1426        let mut invalid_resource = valid;
1427        invalid_resource[0].1 = 0;
1428        assert_eq!(
1429            validate_known_diagnostic_fact_schema(
1430                ErrorCode::RUNTIME_BOUNDARY_EXECUTION_BUDGET_EXCEEDED,
1431                &invalid_resource,
1432            ),
1433            Err(DiagnosticFactSchemaMismatch::InvalidValue)
1434        );
1435    }
1436
1437    #[test]
1438    fn raw_schema_keeps_unknown_context_numeric_but_marks_it_invalid() {
1439        assert_eq!(
1440            validate_raw_diagnostic_fact_schema(
1441                ErrorCode::QUERY_INVALID_CONTINUATION_CURSOR,
1442                &[(u8::MAX, 17)],
1443            ),
1444            Err(DiagnosticFactSchemaMismatch::InvalidSequence)
1445        );
1446        assert_eq!(
1447            validate_raw_diagnostic_fact_schema(
1448                ErrorCode::QUERY_INVALID_CONTINUATION_CURSOR,
1449                &[(DiagnosticFactTag::DecodeReason.raw(), u64::MAX)],
1450            ),
1451            Err(DiagnosticFactSchemaMismatch::InvalidSequence)
1452        );
1453    }
1454
1455    #[test]
1456    fn constraint_schema_enforces_authority_operation_and_bounded_path_suffix() {
1457        let mut targeted = vec![
1458            (DiagnosticFactTag::AcceptedSchemaFingerprintMethod, 1),
1459            (DiagnosticFactTag::AcceptedSchemaFingerprintHigh, 2),
1460            (DiagnosticFactTag::AcceptedSchemaFingerprintLow, 3),
1461            (DiagnosticFactTag::EntityTag, 17),
1462            (DiagnosticFactTag::ConstraintId, 4),
1463            (
1464                DiagnosticFactTag::ConstraintKind,
1465                DiagnosticConstraintKind::TargetedRule.raw(),
1466            ),
1467            (
1468                DiagnosticFactTag::ConstraintContext,
1469                DiagnosticConstraintContext::WriteAdmission.raw(),
1470            ),
1471            (
1472                DiagnosticFactTag::MutationOperation,
1473                DiagnosticMutationOperation::Insert.raw(),
1474            ),
1475            (DiagnosticFactTag::BatchPosition, 0),
1476        ];
1477        targeted.extend((0..64).map(|index| (DiagnosticFactTag::ListElement, index)));
1478        assert_eq!(targeted.len(), 73);
1479        assert_eq!(
1480            validate_known_diagnostic_fact_schema(
1481                ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_VIOLATION,
1482                targeted.as_slice(),
1483            ),
1484            Ok(())
1485        );
1486
1487        let mut overlong = targeted.clone();
1488        overlong.push((DiagnosticFactTag::ListElement, 64));
1489        assert_eq!(
1490            validate_known_diagnostic_fact_schema(
1491                ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_VIOLATION,
1492                overlong.as_slice(),
1493            ),
1494            Err(DiagnosticFactSchemaMismatch::CodeMaximumExceeded)
1495        );
1496
1497        let mut non_targeted_path = targeted;
1498        non_targeted_path[5].1 = DiagnosticConstraintKind::Unique.raw();
1499        assert_eq!(
1500            validate_known_diagnostic_fact_schema(
1501                ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_VIOLATION,
1502                non_targeted_path.as_slice(),
1503            ),
1504            Err(DiagnosticFactSchemaMismatch::InvalidSequence)
1505        );
1506    }
1507
1508    #[test]
1509    fn schema_enforces_global_ceiling_before_per_code_ceiling() {
1510        let facts = vec![(DiagnosticFactTag::ActualCount.raw(), 0); 81];
1511        assert_eq!(
1512            validate_raw_diagnostic_fact_schema(ErrorCode::QUERY_PLAN, facts.as_slice()),
1513            Err(DiagnosticFactSchemaMismatch::GlobalMaximumExceeded)
1514        );
1515    }
1516}