Skip to main content

icydb_core/error/
mod.rs

1//! Module: error
2//!
3//! Defines the canonical runtime error taxonomy for `icydb-core`.
4//! This module owns the shared error classes, origins, details, and
5//! constructor entry points used across storage, planning, execution, and
6//! serialization boundaries.
7
8#[cfg(test)]
9mod tests;
10
11use candid::CandidType;
12use icydb_diagnostic_code as diagnostic_code;
13use serde::Deserialize;
14use std::fmt;
15
16pub(crate) const COMPACT_QUERY_DIAGNOSTIC_MESSAGE: &str = "query diagnostic";
17const COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE: &str = "runtime diagnostic";
18const COMPACT_STORE_DIAGNOSTIC_MESSAGE: &str = "store diagnostic";
19const COMPACT_INDEX_DIAGNOSTIC_MESSAGE: &str = "index diagnostic";
20const COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE: &str = "serialize diagnostic";
21const COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE: &str = "identity diagnostic";
22
23const fn compact_message_for(_class: ErrorClass, origin: ErrorOrigin) -> &'static str {
24    match origin {
25        ErrorOrigin::Serialize => COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE,
26        ErrorOrigin::Store => COMPACT_STORE_DIAGNOSTIC_MESSAGE,
27        ErrorOrigin::Index => COMPACT_INDEX_DIAGNOSTIC_MESSAGE,
28        ErrorOrigin::Identity => COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE,
29        ErrorOrigin::Query | ErrorOrigin::Planner | ErrorOrigin::Response => {
30            COMPACT_QUERY_DIAGNOSTIC_MESSAGE
31        }
32        ErrorOrigin::Cursor
33        | ErrorOrigin::Recovery
34        | ErrorOrigin::Executor
35        | ErrorOrigin::Interface => COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE,
36    }
37}
38
39// ============================================================================
40// INTERNAL ERROR TAXONOMY — ARCHITECTURAL CONTRACT
41// ============================================================================
42//
43// This file defines the canonical runtime error classification system for
44// icydb-core. It is the single source of truth for:
45//
46//   • ErrorClass   (semantic domain)
47//   • ErrorOrigin  (subsystem boundary)
48//   • Structured detail payloads
49//   • Canonical constructor entry points
50//
51// -----------------------------------------------------------------------------
52// DESIGN INTENT
53// -----------------------------------------------------------------------------
54//
55// 1. InternalError is a *taxonomy carrier*, not a formatting utility.
56//
57//    - ErrorClass represents semantic meaning (corruption, invariant_violation,
58//      unsupported, etc).
59//    - ErrorOrigin represents the subsystem boundary (store, index, query,
60//      executor, serialize, interface, etc).
61//    - The (class, origin) pair must remain stable and intentional.
62//
63// 2. Call sites MUST prefer canonical constructors.
64//
65//    Do NOT construct errors manually via:
66//        InternalError::new(class, origin)
67//    unless you are defining a new canonical helper here.
68//
69//    If a pattern appears more than once, centralize it here.
70//
71// 3. Constructors in this file must represent real architectural boundaries.
72//
73//    Add a new helper ONLY if it:
74//
75//      • Encodes a cross-cutting invariant,
76//      • Represents a subsystem boundary,
77//      • Or prevents taxonomy drift across call sites.
78//
79//    Do NOT add feature-specific helpers.
80//    Do NOT add one-off formatting helpers.
81//    Do NOT turn this file into a generic message factory.
82//
83// 4. ErrorDetail must align with ErrorOrigin.
84//
85//    If detail is present, it MUST correspond to the origin.
86//    Do not attach mismatched detail variants.
87//
88// 5. Plan-layer errors are NOT runtime failures.
89//
90//    PlanError and CursorPlanError must be translated into
91//    executor/query invariants via the canonical mapping functions.
92//    Do not leak plan-layer error types across execution boundaries.
93//
94// 6. Preserve taxonomy stability.
95//
96//    Do NOT:
97//      • Merge error classes.
98//      • Reclassify corruption as internal.
99//      • Downgrade invariant violations.
100//      • Introduce ambiguous class/origin combinations.
101//
102//    Any change to ErrorClass or ErrorOrigin is an architectural change
103//    and must be reviewed accordingly.
104//
105// -----------------------------------------------------------------------------
106// NON-GOALS
107// -----------------------------------------------------------------------------
108//
109// This is NOT:
110//
111//   • A public API contract.
112//   • A generic error abstraction layer.
113//   • A feature-specific message builder.
114//   • A dumping ground for temporary error conversions.
115//
116// -----------------------------------------------------------------------------
117// MAINTENANCE GUIDELINES
118// -----------------------------------------------------------------------------
119//
120// When modifying this file:
121//
122//   1. Ensure classification semantics remain consistent.
123//   2. Avoid constructor proliferation.
124//   3. Prefer narrow, origin-specific helpers over ad-hoc new(...).
125//   4. Keep formatting minimal and standardized.
126//   5. Keep this file boring and stable.
127//
128// If this file grows rapidly, something is wrong at the call sites.
129//
130// ============================================================================
131
132/// Safe accepted mutation identity retained only when constructing a failure.
133#[derive(Clone, Copy, Debug)]
134pub(crate) struct MutationDiagnosticContext {
135    entity_tag: u64,
136    operation: diagnostic_code::DiagnosticMutationOperation,
137    batch_position: Option<u32>,
138}
139
140impl MutationDiagnosticContext {
141    /// Bind one mutation failure to its accepted entity, operation, and input.
142    #[must_use]
143    pub(crate) const fn new(
144        entity_tag: u64,
145        operation: diagnostic_code::DiagnosticMutationOperation,
146        batch_position: u32,
147    ) -> Self {
148        Self {
149            entity_tag,
150            operation,
151            batch_position: Some(batch_position),
152        }
153    }
154
155    /// Bind a failure to an operation before any concrete input row is selected.
156    #[must_use]
157    pub(crate) const fn operation_only(
158        entity_tag: u64,
159        operation: diagnostic_code::DiagnosticMutationOperation,
160    ) -> Self {
161        Self {
162            entity_tag,
163            operation,
164            batch_position: None,
165        }
166    }
167
168    fn facts(self, field_id: Option<u32>) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
169        let mut facts = Vec::with_capacity(
170            2 + usize::from(field_id.is_some()) + usize::from(self.batch_position.is_some()),
171        );
172        facts.push((
173            diagnostic_code::DiagnosticFactTag::EntityTag,
174            self.entity_tag,
175        ));
176        if let Some(field_id) = field_id {
177            facts.push((
178                diagnostic_code::DiagnosticFactTag::FieldId,
179                u64::from(field_id),
180            ));
181        }
182        facts.push((
183            diagnostic_code::DiagnosticFactTag::MutationOperation,
184            self.operation.raw(),
185        ));
186        if let Some(batch_position) = self.batch_position {
187            facts.push((
188                diagnostic_code::DiagnosticFactTag::BatchPosition,
189                u64::from(batch_position),
190            ));
191        }
192        facts
193    }
194
195    #[must_use]
196    pub(crate) const fn entity_tag(self) -> u64 {
197        self.entity_tag
198    }
199
200    fn append_operation_facts(self, facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>) {
201        facts.push((
202            diagnostic_code::DiagnosticFactTag::MutationOperation,
203            self.operation.raw(),
204        ));
205        if let Some(batch_position) = self.batch_position {
206            facts.push((
207                diagnostic_code::DiagnosticFactTag::BatchPosition,
208                u64::from(batch_position),
209            ));
210        }
211    }
212}
213
214/// Numeric context retained behind one thin error-only allocation.
215pub struct DiagnosticFactDetail {
216    diagnostic: diagnostic_code::Diagnostic,
217    facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
218}
219
220///
221/// InternalError
222///
223/// Structured runtime error with a stable internal classification.
224/// Not a stable API; intended for internal use and may change without notice.
225///
226
227pub struct InternalError {
228    pub(crate) class: ErrorClass,
229    pub(crate) origin: ErrorOrigin,
230
231    /// Optional structured error detail.
232    /// The variant (if present) must correspond to `origin`.
233    pub(crate) detail: Option<ErrorDetail>,
234}
235
236#[expect(
237    clippy::missing_const_for_fn,
238    reason = "internal error constructors stay non-const so compact diagnostic construction does not force const churn across subsystem helper seams"
239)]
240impl InternalError {
241    /// Construct an InternalError with optional origin-specific detail.
242    /// This constructor provides default StoreError details for certain
243    /// (class, origin) combinations but does not guarantee a detail payload.
244    #[must_use]
245    #[cold]
246    #[inline(never)]
247    pub fn new(class: ErrorClass, origin: ErrorOrigin) -> Self {
248        let detail = match (class, origin) {
249            (ErrorClass::Corruption, ErrorOrigin::Store) => {
250                Some(ErrorDetail::Store(StoreError::Corrupt))
251            }
252            (ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
253                Some(ErrorDetail::Store(StoreError::InvariantViolation))
254            }
255            _ => None,
256        };
257
258        Self {
259            class,
260            origin,
261            detail,
262        }
263    }
264
265    /// Return the internal error class taxonomy.
266    #[must_use]
267    pub const fn class(&self) -> ErrorClass {
268        self.class
269    }
270
271    /// Return the internal error origin taxonomy.
272    #[must_use]
273    pub const fn origin(&self) -> ErrorOrigin {
274        self.origin
275    }
276
277    /// Return the rendered internal error message.
278    #[must_use]
279    pub const fn message(&self) -> &'static str {
280        compact_message_for(self.class, self.origin)
281    }
282
283    /// Return the optional structured detail payload.
284    #[must_use]
285    pub const fn detail(&self) -> Option<&ErrorDetail> {
286        self.detail.as_ref()
287    }
288
289    /// Return compact diagnostic identity for this internal error.
290    #[must_use]
291    pub fn diagnostic(&self) -> diagnostic_code::Diagnostic {
292        diagnostic_code::Diagnostic::new(
293            self.diagnostic_code(),
294            self.origin.diagnostic_origin(),
295            self.detail
296                .as_ref()
297                .and_then(ErrorDetail::diagnostic_detail),
298        )
299    }
300
301    /// Project typed internal context into canonical public numeric facts.
302    #[must_use]
303    #[cold]
304    #[inline(never)]
305    pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
306        self.detail
307            .as_ref()
308            .map_or_else(Vec::new, ErrorDetail::diagnostic_facts)
309    }
310
311    /// Return the compact diagnostic code for this internal error.
312    #[must_use]
313    pub fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
314        self.detail.as_ref().map_or_else(
315            || self.class.diagnostic_code(self.origin),
316            ErrorDetail::diagnostic_code,
317        )
318    }
319
320    /// Consume and return the rendered internal error message.
321    #[must_use]
322    pub fn into_message(self) -> String {
323        self.message().to_string()
324    }
325
326    /// Construct an error while preserving an explicit class/origin taxonomy pair.
327    #[cold]
328    #[inline(never)]
329    pub(crate) fn classified(class: ErrorClass, origin: ErrorOrigin) -> Self {
330        Self::new(class, origin)
331    }
332
333    #[cold]
334    #[inline(never)]
335    fn with_diagnostic_facts(
336        class: ErrorClass,
337        origin: ErrorOrigin,
338        detail: Option<diagnostic_code::DiagnosticDetail>,
339        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
340    ) -> Self {
341        let code = match detail {
342            Some(detail) => detail.diagnostic_code(),
343            None => class.diagnostic_code(origin),
344        };
345        let diagnostic = diagnostic_code::Diagnostic::new(code, origin.diagnostic_origin(), detail);
346        if diagnostic_code::validate_known_diagnostic_fact_schema(
347            diagnostic.error_code(),
348            facts.as_slice(),
349        )
350        .is_err()
351        {
352            return Self::new(ErrorClass::InvariantViolation, origin);
353        }
354        Self {
355            class,
356            origin,
357            detail: Some(ErrorDetail::DiagnosticFacts(Box::new(
358                DiagnosticFactDetail { diagnostic, facts },
359            ))),
360        }
361    }
362
363    #[cold]
364    #[inline(never)]
365    fn mutation_boundary_with_facts(
366        class: ErrorClass,
367        boundary: diagnostic_code::RuntimeBoundaryCode,
368        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
369    ) -> Self {
370        Self::with_diagnostic_facts(
371            class,
372            ErrorOrigin::Executor,
373            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
374            facts,
375        )
376    }
377
378    #[cold]
379    #[inline(never)]
380    fn exact_key_batch_boundary_with_facts(
381        boundary: diagnostic_code::RuntimeBoundaryCode,
382        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
383    ) -> Self {
384        Self::with_diagnostic_facts(
385            ErrorClass::Unsupported,
386            ErrorOrigin::Query,
387            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
388            facts,
389        )
390    }
391
392    /// Construct a query-boundary error for a named entity absent from accepted schema authority.
393    pub(crate) fn sql_query_entity_not_found() -> Self {
394        Self::with_diagnostic_facts(
395            ErrorClass::NotFound,
396            ErrorOrigin::Interface,
397            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
398                boundary: diagnostic_code::RuntimeBoundaryCode::SqlQueryEntityNotFound,
399            }),
400            Vec::new(),
401        )
402    }
403
404    /// Construct an executor-origin hard execution-budget rejection.
405    #[cold]
406    #[inline(never)]
407    pub(crate) fn execution_budget_exceeded(
408        resource: diagnostic_code::DiagnosticExecutionBudgetResource,
409        limit: u64,
410        observed: u64,
411        scope: diagnostic_code::DiagnosticExecutionBudgetScope,
412        lane: diagnostic_code::DiagnosticExecutionLane,
413        normalized_shape_fingerprint_prefix: u64,
414    ) -> Self {
415        Self::with_diagnostic_facts(
416            ErrorClass::Unsupported,
417            ErrorOrigin::Executor,
418            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
419                boundary: diagnostic_code::RuntimeBoundaryCode::ExecutionBudgetExceeded,
420            }),
421            vec![
422                (
423                    diagnostic_code::DiagnosticFactTag::BudgetResource,
424                    resource.raw(),
425                ),
426                (diagnostic_code::DiagnosticFactTag::Limit, limit),
427                (diagnostic_code::DiagnosticFactTag::Actual, observed),
428                (
429                    diagnostic_code::DiagnosticFactTag::ExecutionBudgetScope,
430                    scope.raw(),
431                ),
432                (
433                    diagnostic_code::DiagnosticFactTag::ExecutionLane,
434                    lane.raw(),
435                ),
436                (
437                    diagnostic_code::DiagnosticFactTag::QueryShapeFingerprintPrefix,
438                    normalized_shape_fingerprint_prefix,
439                ),
440            ],
441        )
442    }
443
444    /// Construct an executor-origin rejection for one indivisible page unit.
445    #[cold]
446    #[inline(never)]
447    pub(crate) fn page_unit_too_large(
448        resource: diagnostic_code::DiagnosticExecutionBudgetResource,
449        limit: u64,
450        attempted: u64,
451    ) -> Self {
452        Self::with_diagnostic_facts(
453            ErrorClass::Unsupported,
454            ErrorOrigin::Executor,
455            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
456                boundary: diagnostic_code::RuntimeBoundaryCode::PageUnitTooLarge,
457            }),
458            vec![
459                (
460                    diagnostic_code::DiagnosticFactTag::BudgetResource,
461                    resource.raw(),
462                ),
463                (diagnostic_code::DiagnosticFactTag::Limit, limit),
464                (diagnostic_code::DiagnosticFactTag::Actual, attempted),
465            ],
466        )
467    }
468
469    /// Rebuild this error with a new origin while preserving class taxonomy.
470    ///
471    /// Numeric facts are origin-independent and remain safe after recovery
472    /// relabeling. Other origin-scoped detail payloads are dropped.
473    #[cold]
474    #[inline(never)]
475    pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
476        match self.detail {
477            Some(ErrorDetail::DiagnosticFacts(detail)) => Self::with_diagnostic_facts(
478                self.class,
479                origin,
480                detail.diagnostic.detail().copied(),
481                detail.facts,
482            ),
483            _ => Self::classified(self.class, origin),
484        }
485    }
486
487    /// Construct an index-origin invariant violation.
488    #[cold]
489    #[inline(never)]
490    pub(crate) fn index_invariant() -> Self {
491        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
492    }
493
494    /// Construct the canonical index field-count invariant for key building.
495    pub(crate) fn index_key_field_count_exceeds_max(
496        entity_tag: u64,
497        physical_generation: u64,
498        field_count: usize,
499        max_fields: usize,
500    ) -> Self {
501        Self::with_diagnostic_facts(
502            ErrorClass::InvariantViolation,
503            ErrorOrigin::Index,
504            None,
505            vec![
506                (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
507                (
508                    diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
509                    physical_generation,
510                ),
511                (
512                    diagnostic_code::DiagnosticFactTag::ComponentKind,
513                    diagnostic_code::DiagnosticComponentKind::IndexKey.raw(),
514                ),
515                (
516                    diagnostic_code::DiagnosticFactTag::ActualArity,
517                    field_count as u64,
518                ),
519                (
520                    diagnostic_code::DiagnosticFactTag::Maximum,
521                    max_fields as u64,
522                ),
523            ],
524        )
525    }
526
527    /// Construct the canonical index-expression source-type mismatch invariant.
528    pub(crate) fn index_expression_source_type_mismatch(
529        _index_name: &str,
530        _expression: impl Sized,
531        _expected: impl Sized,
532        _source_label: &str,
533    ) -> Self {
534        Self::index_invariant()
535    }
536
537    /// Construct a planner-origin invariant violation for executor-boundary
538    /// contract drift.
539    #[cold]
540    #[inline(never)]
541    pub(crate) fn planner_executor_invariant() -> Self {
542        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
543    }
544
545    /// Construct a query-origin invariant violation for executor-boundary
546    /// contract drift.
547    #[cold]
548    #[inline(never)]
549    pub(crate) fn query_executor_invariant() -> Self {
550        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
551    }
552
553    /// Construct a cursor-origin invariant violation for executor-boundary
554    /// contract drift.
555    #[cold]
556    #[inline(never)]
557    pub(crate) fn cursor_executor_invariant() -> Self {
558        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
559    }
560
561    /// Construct an executor-origin invariant violation.
562    #[cold]
563    #[inline(never)]
564    pub(crate) fn executor_invariant() -> Self {
565        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
566    }
567
568    /// Construct an executor-origin internal error.
569    #[cold]
570    #[inline(never)]
571    pub(crate) fn executor_internal() -> Self {
572        Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
573    }
574
575    /// Construct an executor-origin unsupported error.
576    #[cold]
577    #[inline(never)]
578    pub(crate) fn executor_unsupported() -> Self {
579        Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
580    }
581
582    /// Construct an executor-origin database-owned-field authorship rejection.
583    #[cold]
584    #[inline(never)]
585    pub(crate) fn mutation_database_owned_field_explicit(
586        context: MutationDiagnosticContext,
587        field_id: u32,
588    ) -> Self {
589        Self::mutation_boundary_with_facts(
590            ErrorClass::Unsupported,
591            diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
592            context.facts(Some(field_id)),
593        )
594    }
595
596    /// Construct an executor-origin required-field omission rejection.
597    #[must_use]
598    #[cold]
599    #[inline(never)]
600    pub(crate) fn mutation_required_field_missing(
601        context: MutationDiagnosticContext,
602        field_id: u32,
603    ) -> Self {
604        Self::mutation_boundary_with_facts(
605            ErrorClass::Unsupported,
606            diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
607            context.facts(Some(field_id)),
608        )
609    }
610
611    /// Construct an executor-origin managed-timestamp clock regression.
612    #[must_use]
613    #[cold]
614    #[inline(never)]
615    pub(crate) fn mutation_managed_timestamp_regression(
616        context: MutationDiagnosticContext,
617    ) -> Self {
618        Self::mutation_boundary_with_facts(
619            ErrorClass::InvariantViolation,
620            diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
621            context.facts(None),
622        )
623    }
624
625    /// Construct an executor-origin accepted constraint or activation-gate violation.
626    pub(crate) fn mutation_constraint_violation(context: AcceptedConstraintFactContext) -> Self {
627        Self::mutation_boundary_with_facts(
628            ErrorClass::InvariantViolation,
629            diagnostic_code::RuntimeBoundaryCode::ConstraintViolation,
630            context.facts(),
631        )
632    }
633
634    /// Construct an executor-origin corruption failure for row-constraint authority.
635    pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
636        Self {
637            class: ErrorClass::Corruption,
638            origin: ErrorOrigin::Executor,
639            detail: Some(ErrorDetail::Executor(
640                ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
641            )),
642        }
643    }
644
645    /// Construct one typed migration conflict for an incomplete activation gate.
646    pub(crate) fn mutation_constraint_activation_write_blocked(
647        context: AcceptedConstraintFactContext,
648    ) -> Self {
649        Self::mutation_boundary_with_facts(
650            ErrorClass::Conflict,
651            diagnostic_code::RuntimeBoundaryCode::ConstraintActivationWriteBlocked,
652            context.facts(),
653        )
654    }
655
656    /// Construct an executor-origin mutation unknown-field invariant.
657    pub(crate) fn mutation_structural_field_unknown(_entity_path: &str, _field_name: &str) -> Self {
658        Self::executor_invariant()
659    }
660
661    /// Construct a query-origin scalar page invariant for missing order at the cursor boundary.
662    pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
663        Self::query_executor_invariant()
664    }
665
666    /// Construct a query-origin scalar page invariant for cursor-before-ordering drift.
667    pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
668        Self::query_executor_invariant()
669    }
670
671    /// Construct a query-origin scalar page invariant for pagination-before-ordering drift.
672    pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
673        Self::query_executor_invariant()
674    }
675
676    /// Construct a query-origin fast-stream invariant for route kind/request mismatch.
677    pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
678        Self::query_executor_invariant()
679    }
680
681    /// Construct a query-origin scan invariant for missing index-prefix executable specs.
682    pub(crate) fn secondary_index_prefix_spec_required() -> Self {
683        Self::query_executor_invariant()
684    }
685
686    /// Construct a query-origin scan invariant for missing index-range executable specs.
687    pub(crate) fn index_range_limit_spec_required() -> Self {
688        Self::query_executor_invariant()
689    }
690
691    /// Construct an executor-origin mutation conflict for duplicate atomic save keys.
692    #[cold]
693    #[inline(never)]
694    pub(crate) fn mutation_atomic_save_duplicate_key(
695        entity_tag: u64,
696        first_position: u32,
697        duplicate_position: u32,
698    ) -> Self {
699        Self::mutation_boundary_with_facts(
700            ErrorClass::Conflict,
701            diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
702            vec![
703                (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
704                (
705                    diagnostic_code::DiagnosticFactTag::FirstBatchPosition,
706                    u64::from(first_position),
707                ),
708                (
709                    diagnostic_code::DiagnosticFactTag::DuplicateBatchPosition,
710                    u64::from(duplicate_position),
711                ),
712            ],
713        )
714    }
715
716    /// Construct an executor-origin empty mixed-mutation batch rejection.
717    #[cold]
718    #[inline(never)]
719    pub(crate) fn mutation_batch_empty() -> Self {
720        Self::mutation_boundary_with_facts(
721            ErrorClass::Unsupported,
722            diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
723            vec![(diagnostic_code::DiagnosticFactTag::ActualCount, 0)],
724        )
725    }
726
727    /// Construct an executor-origin mixed-mutation item-bound rejection.
728    #[cold]
729    #[inline(never)]
730    pub(crate) fn mutation_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
731        Self::mutation_boundary_with_facts(
732            ErrorClass::Unsupported,
733            diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
734            vec![
735                (
736                    diagnostic_code::DiagnosticFactTag::ActualCount,
737                    actual_count as u64,
738                ),
739                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
740            ],
741        )
742    }
743
744    /// Construct an executor-origin mixed-mutation staged-byte-bound rejection.
745    #[cold]
746    #[inline(never)]
747    pub(crate) fn mutation_batch_staged_bytes_exceeded(
748        actual_bytes: Option<usize>,
749        limit: usize,
750    ) -> Self {
751        let mut facts = Vec::with_capacity(1 + usize::from(actual_bytes.is_some()));
752        if let Some(actual_bytes) = actual_bytes {
753            facts.push((
754                diagnostic_code::DiagnosticFactTag::ActualLength,
755                actual_bytes as u64,
756            ));
757        }
758        facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
759        Self::mutation_boundary_with_facts(
760            ErrorClass::Unsupported,
761            diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
762            facts,
763        )
764    }
765
766    /// Construct an executor-origin mixed-mutation result-byte-bound rejection.
767    #[cold]
768    #[inline(never)]
769    pub(crate) fn mutation_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
770        Self::mutation_boundary_with_facts(
771            ErrorClass::Unsupported,
772            diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
773            vec![
774                (
775                    diagnostic_code::DiagnosticFactTag::ActualLength,
776                    actual_bytes as u64,
777                ),
778                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
779            ],
780        )
781    }
782
783    /// Construct an executor-origin prepared-commit work-bound rejection.
784    #[cold]
785    #[inline(never)]
786    pub(crate) fn mutation_batch_commit_work_exceeded(
787        actual_units: Option<usize>,
788        limit: usize,
789    ) -> Self {
790        let mut facts = Vec::with_capacity(1 + usize::from(actual_units.is_some()));
791        if let Some(actual_units) = actual_units {
792            facts.push((
793                diagnostic_code::DiagnosticFactTag::ActualCount,
794                actual_units as u64,
795            ));
796        }
797        facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
798        Self::mutation_boundary_with_facts(
799            ErrorClass::Unsupported,
800            diagnostic_code::RuntimeBoundaryCode::MutationBatchCommitWorkExceeded,
801            facts,
802        )
803    }
804
805    /// Construct the retryable cumulative journal-backlog pressure boundary.
806    pub(crate) fn convergence_backlog_pressure(
807        resource: diagnostic_code::DiagnosticBacklogResource,
808        current: u64,
809        proposed: u64,
810        limit: u64,
811    ) -> Self {
812        Self::mutation_boundary_with_facts(
813            ErrorClass::Conflict,
814            diagnostic_code::RuntimeBoundaryCode::ConvergenceBacklogPressure,
815            vec![
816                (
817                    diagnostic_code::DiagnosticFactTag::BacklogResource,
818                    resource.raw(),
819                ),
820                (diagnostic_code::DiagnosticFactTag::CurrentCount, current),
821                (diagnostic_code::DiagnosticFactTag::ProposedCount, proposed),
822                (diagnostic_code::DiagnosticFactTag::Limit, limit),
823            ],
824        )
825    }
826
827    /// Construct a query-origin exact-key item-bound rejection.
828    #[cold]
829    #[inline(never)]
830    pub(crate) fn exact_key_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
831        Self::exact_key_batch_boundary_with_facts(
832            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchTooManyItems,
833            vec![
834                (
835                    diagnostic_code::DiagnosticFactTag::ActualCount,
836                    actual_count as u64,
837                ),
838                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
839            ],
840        )
841    }
842
843    /// Construct a query-origin exact-key input-byte rejection.
844    #[cold]
845    #[inline(never)]
846    pub(crate) fn exact_key_batch_input_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
847        Self::exact_key_batch_bytes_exceeded(
848            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchInputBytesExceeded,
849            actual_bytes,
850            limit,
851        )
852    }
853
854    /// Construct a query-origin exact-key stored-row-byte rejection.
855    #[cold]
856    #[inline(never)]
857    pub(crate) fn exact_key_batch_stored_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
858        Self::exact_key_batch_bytes_exceeded(
859            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchStoredBytesExceeded,
860            actual_bytes,
861            limit,
862        )
863    }
864
865    /// Construct a query-origin exact-key result-byte rejection.
866    #[cold]
867    #[inline(never)]
868    pub(crate) fn exact_key_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
869        Self::exact_key_batch_bytes_exceeded(
870            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchResultBytesExceeded,
871            actual_bytes,
872            limit,
873        )
874    }
875
876    #[cold]
877    #[inline(never)]
878    fn exact_key_batch_bytes_exceeded(
879        boundary: diagnostic_code::RuntimeBoundaryCode,
880        actual_bytes: usize,
881        limit: usize,
882    ) -> Self {
883        Self::exact_key_batch_boundary_with_facts(
884            boundary,
885            vec![
886                (
887                    diagnostic_code::DiagnosticFactTag::ActualLength,
888                    actual_bytes as u64,
889                ),
890                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
891            ],
892        )
893    }
894
895    /// Construct an executor-origin cross-store batch rejection.
896    #[cold]
897    #[inline(never)]
898    pub(crate) fn mutation_batch_store_mismatch(
899        batch_position: u32,
900        expected_entity_tag: u64,
901        actual_entity_tag: u64,
902    ) -> Self {
903        Self::mutation_boundary_with_facts(
904            ErrorClass::Conflict,
905            diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
906            vec![
907                (
908                    diagnostic_code::DiagnosticFactTag::BatchPosition,
909                    u64::from(batch_position),
910                ),
911                (
912                    diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
913                    expected_entity_tag,
914                ),
915                (
916                    diagnostic_code::DiagnosticFactTag::ActualEntityTag,
917                    actual_entity_tag,
918                ),
919            ],
920        )
921    }
922
923    /// Construct an executor-origin distinct-entity-bound rejection.
924    #[cold]
925    #[inline(never)]
926    pub(crate) fn mutation_batch_too_many_entities(actual_count: usize, limit: usize) -> Self {
927        Self::mutation_boundary_with_facts(
928            ErrorClass::Unsupported,
929            diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
930            vec![
931                (
932                    diagnostic_code::DiagnosticFactTag::ActualCount,
933                    actual_count as u64,
934                ),
935                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
936            ],
937        )
938    }
939
940    /// Construct an executor-origin mutation invariant for index-store generation drift.
941    pub(crate) fn mutation_index_store_generation_changed(
942        _expected_generation: u64,
943        _observed_generation: u64,
944    ) -> Self {
945        Self::executor_invariant()
946    }
947
948    /// Construct a planner-origin invariant violation.
949    #[cold]
950    #[inline(never)]
951    pub(crate) fn planner_invariant() -> Self {
952        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
953    }
954
955    /// Construct a planner-origin invalid-logical-plan invariant.
956    pub(crate) fn query_invalid_logical_plan() -> Self {
957        Self::planner_invariant()
958    }
959
960    /// Construct a store-origin invariant violation.
961    pub(crate) fn store_invariant() -> Self {
962        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
963    }
964
965    /// Construct a store-origin internal error.
966    #[cold]
967    #[inline(never)]
968    pub(crate) fn store_internal() -> Self {
969        Self::new(ErrorClass::Internal, ErrorOrigin::Store)
970    }
971
972    /// Construct the canonical unconfigured commit-memory id internal error.
973    pub(crate) fn commit_memory_id_unconfigured() -> Self {
974        Self::store_internal()
975    }
976
977    /// Construct the canonical initialized commit-store lookup invariant.
978    pub(crate) fn commit_store_uninitialized() -> Self {
979        Self::store_invariant()
980    }
981
982    /// Construct the canonical commit-memory id mismatch internal error.
983    pub(crate) fn commit_memory_id_mismatch(cached_id: u8, configured_id: u8) -> Self {
984        Self::with_diagnostic_facts(
985            ErrorClass::Internal,
986            ErrorOrigin::Store,
987            None,
988            vec![
989                (
990                    diagnostic_code::DiagnosticFactTag::ExpectedMemoryId,
991                    u64::from(cached_id),
992                ),
993                (
994                    diagnostic_code::DiagnosticFactTag::ActualMemoryId,
995                    u64::from(configured_id),
996                ),
997            ],
998        )
999    }
1000
1001    /// Construct the canonical commit-memory stable-key mismatch internal error.
1002    pub(crate) fn commit_memory_stable_key_mismatch(
1003        _cached_key: &str,
1004        _configured_key: &str,
1005    ) -> Self {
1006        Self::store_internal()
1007    }
1008
1009    /// Construct the canonical database-incarnation generation failure.
1010    pub(crate) fn database_incarnation_generation_failed() -> Self {
1011        Self::store_internal()
1012    }
1013
1014    /// Construct the canonical zero database-incarnation corruption error.
1015    pub(crate) fn database_incarnation_invalid() -> Self {
1016        Self::store_corruption()
1017    }
1018
1019    /// Construct a recovery-origin incompatible store-format error.
1020    pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
1021        Self {
1022            class: ErrorClass::IncompatiblePersistedFormat,
1023            origin: ErrorOrigin::Recovery,
1024            detail: Some(ErrorDetail::Recovery(
1025                RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
1026            )),
1027        }
1028    }
1029
1030    /// Construct a recovery-origin malformed store-format marker error.
1031    pub(crate) fn recovery_malformed_database_format_marker(
1032        reason: RecoveryFormatMarkerError,
1033    ) -> Self {
1034        Self {
1035            class: ErrorClass::Corruption,
1036            origin: ErrorOrigin::Recovery,
1037            detail: Some(ErrorDetail::Recovery(
1038                RecoveryErrorDetail::MalformedFormatMarker { reason },
1039            )),
1040        }
1041    }
1042
1043    /// Construct a recovery-origin boot control-memory failure.
1044    pub(crate) fn recovery_database_format_control_unavailable() -> Self {
1045        Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
1046    }
1047
1048    /// Construct the retryable internal boundary returned while bounded startup recovery remains.
1049    pub(crate) fn recovery_pending() -> Self {
1050        Self::with_diagnostic_facts(
1051            ErrorClass::Conflict,
1052            ErrorOrigin::Recovery,
1053            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1054                boundary: diagnostic_code::RuntimeBoundaryCode::DatabaseStartupRecoveryPending,
1055            }),
1056            Vec::new(),
1057        )
1058    }
1059
1060    /// Construct fail-closed corruption for the bounded startup control cell.
1061    pub(crate) fn startup_control_corruption() -> Self {
1062        Self::new(ErrorClass::Corruption, ErrorOrigin::Recovery)
1063    }
1064
1065    /// Construct a commit control-memory growth failure.
1066    pub(crate) fn commit_control_memory_growth_failed() -> Self {
1067        Self::store_internal()
1068    }
1069
1070    /// Construct a store-format memory registration failure.
1071    #[cfg(not(test))]
1072    pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
1073        Self::store_internal()
1074    }
1075
1076    /// Construct the canonical recovered-effect verification failure.
1077    pub(crate) fn recovery_effect_verification_failed() -> Self {
1078        Self::store_corruption()
1079    }
1080
1081    /// Construct an index-origin internal error.
1082    #[cold]
1083    #[inline(never)]
1084    pub(crate) fn index_internal() -> Self {
1085        Self::new(ErrorClass::Internal, ErrorOrigin::Index)
1086    }
1087
1088    /// Construct the canonical missing old entity-key internal error for structural index removal.
1089    pub(crate) fn structural_index_removal_entity_key_required() -> Self {
1090        Self::index_internal()
1091    }
1092
1093    /// Construct the canonical missing new entity-key internal error for structural index insertion.
1094    pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
1095        Self::index_internal()
1096    }
1097
1098    /// Construct the canonical missing old entity-key internal error for index commit-op removal.
1099    pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
1100        Self::index_internal()
1101    }
1102
1103    /// Construct the canonical missing new entity-key internal error for index commit-op insertion.
1104    pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
1105        Self::index_internal()
1106    }
1107
1108    /// Construct a query-origin internal error.
1109    #[cfg(test)]
1110    pub(crate) fn query_internal() -> Self {
1111        Self::new(ErrorClass::Internal, ErrorOrigin::Query)
1112    }
1113
1114    /// Construct a query-origin unsupported error.
1115    #[cold]
1116    #[inline(never)]
1117    pub(crate) fn query_unsupported() -> Self {
1118        Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
1119    }
1120
1121    /// Construct a query-origin conflict for execution against a superseded
1122    /// accepted schema revision.
1123    #[cold]
1124    #[inline(never)]
1125    pub(crate) fn query_stale_accepted_schema_revision(
1126        expected_revision: u64,
1127        current_revision: Option<u64>,
1128    ) -> Self {
1129        let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
1130        facts.push((
1131            diagnostic_code::DiagnosticFactTag::ExpectedRevision,
1132            expected_revision,
1133        ));
1134        if let Some(current_revision) = current_revision {
1135            facts.push((
1136                diagnostic_code::DiagnosticFactTag::CurrentRevision,
1137                current_revision,
1138            ));
1139        }
1140        Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
1141    }
1142
1143    /// Construct a query-origin SQL DDL admission error with structured detail.
1144    #[cold]
1145    #[inline(never)]
1146    #[cfg(feature = "sql")]
1147    pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
1148        Self {
1149            class: ErrorClass::Unsupported,
1150            origin: ErrorOrigin::Query,
1151            detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
1152                error,
1153            })),
1154        }
1155    }
1156
1157    /// Construct a query-origin numeric overflow error with structured detail.
1158    #[cold]
1159    #[inline(never)]
1160    pub(crate) fn query_numeric_overflow() -> Self {
1161        Self {
1162            class: ErrorClass::Unsupported,
1163            origin: ErrorOrigin::Query,
1164            detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
1165        }
1166    }
1167
1168    /// Construct a query-origin non-representable numeric result error with
1169    /// structured detail.
1170    #[cold]
1171    #[inline(never)]
1172    pub(crate) fn query_numeric_not_representable() -> Self {
1173        Self {
1174            class: ErrorClass::Unsupported,
1175            origin: ErrorOrigin::Query,
1176            detail: Some(ErrorDetail::Query(
1177                QueryErrorDetail::NumericNotRepresentable,
1178            )),
1179        }
1180    }
1181
1182    /// Construct a serialize-origin internal error.
1183    #[cold]
1184    #[inline(never)]
1185    pub(crate) fn serialize_internal() -> Self {
1186        Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
1187    }
1188
1189    /// Construct the canonical persisted-row encode internal error.
1190    pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
1191        Self::persisted_row_encode_internal()
1192    }
1193
1194    /// Construct the compact persisted-row encode internal error.
1195    pub(crate) fn persisted_row_encode_internal() -> Self {
1196        Self::serialize_internal()
1197    }
1198
1199    /// Construct the compact persisted-row field encode internal error.
1200    pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
1201        Self::persisted_row_encode_internal()
1202    }
1203
1204    /// Construct a store-origin corruption error.
1205    #[cold]
1206    #[inline(never)]
1207    pub(crate) fn store_corruption() -> Self {
1208        Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
1209    }
1210
1211    /// Construct a store-origin commit-marker corruption error.
1212    pub(crate) fn commit_corruption() -> Self {
1213        Self::store_corruption()
1214    }
1215
1216    /// Construct a store-origin commit-marker component corruption error.
1217    pub(crate) fn commit_component_corruption() -> Self {
1218        Self::commit_corruption()
1219    }
1220
1221    /// Construct the canonical commit-marker id generation internal error.
1222    pub(crate) fn commit_id_generation_failed() -> Self {
1223        Self::store_internal()
1224    }
1225
1226    /// Construct the canonical commit-marker payload u32-length-limit error.
1227    pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
1228        Self::store_unsupported()
1229    }
1230
1231    /// Construct the canonical commit-marker component invalid-length corruption error.
1232    pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
1233        Self::with_diagnostic_facts(
1234            ErrorClass::Corruption,
1235            ErrorOrigin::Store,
1236            None,
1237            vec![
1238                (
1239                    diagnostic_code::DiagnosticFactTag::ComponentKind,
1240                    diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
1241                ),
1242                (
1243                    diagnostic_code::DiagnosticFactTag::ActualLength,
1244                    actual_length as u64,
1245                ),
1246                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1247            ],
1248        )
1249    }
1250
1251    /// Construct the canonical commit-marker max-size corruption error.
1252    pub(crate) fn commit_marker_exceeds_max_size() -> Self {
1253        Self::commit_corruption()
1254    }
1255
1256    /// Construct the canonical commit-control slot max-size unsupported error.
1257    pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
1258        Self::store_unsupported()
1259    }
1260
1261    /// Construct the canonical commit-control marker-bytes length-limit error.
1262    pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
1263        Self::store_unsupported()
1264    }
1265
1266    /// Construct an index-origin corruption error.
1267    #[cold]
1268    #[inline(never)]
1269    pub(crate) fn index_corruption() -> Self {
1270        Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
1271    }
1272
1273    /// Construct the canonical unique-validation corruption wrapper.
1274    pub(crate) fn index_unique_validation_corruption() -> Self {
1275        Self::index_plan_index_corruption()
1276    }
1277
1278    /// Construct the canonical structural index-entry corruption wrapper.
1279    pub(crate) fn structural_index_entry_corruption() -> Self {
1280        Self::index_plan_index_corruption()
1281    }
1282
1283    /// Construct the canonical missing new entity-key invariant during unique validation.
1284    pub(crate) fn index_unique_validation_entity_key_required() -> Self {
1285        Self::index_invariant()
1286    }
1287
1288    /// Construct the canonical unique-validation structural row-decode corruption error.
1289    pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
1290        Self::index_plan_serialize_corruption()
1291    }
1292
1293    /// Construct the canonical unique-validation primary-key slot decode corruption error.
1294    pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
1295        Self::index_plan_serialize_corruption()
1296    }
1297
1298    /// Construct the canonical unique-validation stored key rebuild corruption error.
1299    pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
1300        Self::index_plan_serialize_corruption()
1301    }
1302
1303    /// Construct the canonical unique-validation missing-row corruption error.
1304    pub(crate) fn index_unique_validation_row_required() -> Self {
1305        Self::index_plan_store_corruption()
1306    }
1307
1308    /// Construct the canonical index-only predicate missing-component invariant.
1309    pub(crate) fn index_only_predicate_component_required() -> Self {
1310        Self::index_invariant()
1311    }
1312
1313    /// Construct the canonical index-scan continuation-envelope invariant.
1314    pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
1315        Self::index_invariant()
1316    }
1317
1318    /// Construct the canonical index-scan continuation-advancement invariant.
1319    pub(crate) fn index_scan_continuation_advancement_required() -> Self {
1320        Self::index_invariant()
1321    }
1322
1323    /// Construct the canonical index-scan key-decode corruption error.
1324    pub(crate) fn index_scan_key_corrupted_during(
1325        _context: &'static str,
1326        _err: impl Sized,
1327    ) -> Self {
1328        Self::index_corruption()
1329    }
1330
1331    /// Construct the canonical index-scan missing projection-component invariant.
1332    pub(crate) fn index_projection_component_required(
1333        _index_name: &str,
1334        _component_index: usize,
1335    ) -> Self {
1336        Self::index_invariant()
1337    }
1338
1339    /// Construct the canonical scan-time index-entry decode corruption error.
1340    pub(crate) fn index_entry_decode_failed() -> Self {
1341        Self::index_corruption()
1342    }
1343
1344    /// Construct a serialize-origin corruption error.
1345    pub(crate) fn serialize_corruption() -> Self {
1346        Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
1347    }
1348
1349    /// Construct the compact persisted-row decode corruption error.
1350    pub(crate) fn persisted_row_decode_corruption() -> Self {
1351        Self::serialize_corruption()
1352    }
1353
1354    /// Construct a persisted-row layout-window corruption error.
1355    pub(crate) fn persisted_row_layout_outside_accepted_window(
1356        row_layout: u32,
1357        history_floor: u32,
1358        current_layout: u32,
1359    ) -> Self {
1360        Self::with_diagnostic_facts(
1361            ErrorClass::Corruption,
1362            ErrorOrigin::Serialize,
1363            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1364                boundary:
1365                    diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
1366            }),
1367            vec![
1368                (
1369                    diagnostic_code::DiagnosticFactTag::RowLayout,
1370                    u64::from(row_layout),
1371                ),
1372                (
1373                    diagnostic_code::DiagnosticFactTag::HistoryFloor,
1374                    u64::from(history_floor),
1375                ),
1376                (
1377                    diagnostic_code::DiagnosticFactTag::CurrentLayout,
1378                    u64::from(current_layout),
1379                ),
1380            ],
1381        )
1382    }
1383
1384    /// Construct a persisted-row stamped-layout slot-count corruption error.
1385    pub(crate) fn persisted_row_slot_count_mismatch(
1386        row_layout: u32,
1387        expected_slot_count: usize,
1388        actual_slot_count: usize,
1389    ) -> Self {
1390        Self::with_diagnostic_facts(
1391            ErrorClass::Corruption,
1392            ErrorOrigin::Serialize,
1393            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1394                boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
1395            }),
1396            vec![
1397                (
1398                    diagnostic_code::DiagnosticFactTag::RowLayout,
1399                    u64::from(row_layout),
1400                ),
1401                (
1402                    diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
1403                    expected_slot_count as u64,
1404                ),
1405                (
1406                    diagnostic_code::DiagnosticFactTag::ActualSlotCount,
1407                    actual_slot_count as u64,
1408                ),
1409            ],
1410        )
1411    }
1412
1413    /// Construct the canonical persisted-row field decode corruption error.
1414    pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
1415        Self::persisted_row_field_decode_corruption(field_name)
1416    }
1417
1418    /// Construct the compact persisted-row field decode corruption error.
1419    pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
1420        Self::persisted_row_decode_corruption()
1421    }
1422
1423    /// Construct the canonical persisted-row field-kind decode corruption error.
1424    pub(crate) fn persisted_row_field_kind_decode_failed(
1425        field_name: &str,
1426        _field_kind: impl fmt::Debug,
1427        _detail: impl Sized,
1428    ) -> Self {
1429        Self::persisted_row_field_decode_corruption(field_name)
1430    }
1431
1432    /// Construct the canonical persisted-row scalar-payload length corruption error.
1433    pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
1434        Self::persisted_row_field_decode_corruption(field_name)
1435    }
1436
1437    /// Construct the canonical persisted-row scalar-payload empty-body corruption error.
1438    pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
1439        Self::persisted_row_field_decode_corruption(field_name)
1440    }
1441
1442    /// Construct the canonical persisted-row scalar-payload invalid-byte corruption error.
1443    pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
1444        Self::persisted_row_field_decode_corruption(field_name)
1445    }
1446
1447    /// Construct the canonical persisted-row scalar-payload non-finite corruption error.
1448    pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
1449        Self::persisted_row_field_decode_corruption(field_name)
1450    }
1451
1452    /// Construct the canonical persisted-row invalid text payload corruption error.
1453    pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
1454        Self::persisted_row_field_decode_corruption(field_name)
1455    }
1456
1457    /// Construct the canonical persisted-row structural slot-lookup invariant.
1458    pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
1459        Self::index_invariant()
1460    }
1461
1462    /// Construct the canonical persisted-row structural slot-cache invariant.
1463    pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
1464        _model_path: &str,
1465        _slot: usize,
1466    ) -> Self {
1467        Self::index_invariant()
1468    }
1469
1470    /// Construct the canonical persisted-row primary-key decode corruption error.
1471    pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1472        _data_key: impl fmt::Debug,
1473        _detail: impl Sized,
1474    ) -> Self {
1475        Self::persisted_row_decode_corruption()
1476    }
1477
1478    /// Construct the canonical persisted-row missing primary-key slot corruption error.
1479    pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1480        Self::persisted_row_decode_corruption()
1481    }
1482
1483    /// Construct the canonical persisted-row key mismatch corruption error.
1484    pub(crate) fn persisted_row_key_mismatch() -> Self {
1485        Self::store_corruption()
1486    }
1487
1488    /// Construct the canonical persisted-row missing declared-field corruption error.
1489    pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1490        Self::persisted_row_field_decode_corruption(field_name)
1491    }
1492
1493    /// Construct the canonical reverse-index ordinal overflow internal error.
1494    pub(crate) fn reverse_index_ordinal_overflow(
1495        _source_path: &str,
1496        _field_name: &str,
1497        _target_path: &str,
1498        _detail: impl Sized,
1499    ) -> Self {
1500        Self::index_internal()
1501    }
1502
1503    /// Construct the canonical reverse-index entry corruption error.
1504    pub(crate) fn reverse_index_entry_corrupted(
1505        _source_path: &str,
1506        _field_name: &str,
1507        _target_path: &str,
1508        _index_key: impl fmt::Debug,
1509        _detail: impl Sized,
1510    ) -> Self {
1511        Self::index_corruption()
1512    }
1513
1514    /// Construct the canonical relation-target store missing internal error.
1515    pub(crate) fn relation_target_store_missing(
1516        _source_path: &str,
1517        _field_name: &str,
1518        _target_path: &str,
1519        _store_path: &str,
1520        _detail: impl Sized,
1521    ) -> Self {
1522        Self::executor_internal()
1523    }
1524
1525    /// Construct one accepted relation target primary-key arity mismatch.
1526    pub(crate) fn relation_target_primary_key_arity_mismatch(
1527        expected_arity: usize,
1528        actual_arity: usize,
1529    ) -> Self {
1530        Self::with_diagnostic_facts(
1531            ErrorClass::Internal,
1532            ErrorOrigin::Executor,
1533            None,
1534            vec![
1535                (
1536                    diagnostic_code::DiagnosticFactTag::ComponentKind,
1537                    diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
1538                ),
1539                (
1540                    diagnostic_code::DiagnosticFactTag::ExpectedArity,
1541                    expected_arity as u64,
1542                ),
1543                (
1544                    diagnostic_code::DiagnosticFactTag::ActualArity,
1545                    actual_arity as u64,
1546                ),
1547            ],
1548        )
1549    }
1550
1551    /// Construct the canonical relation-target key decode corruption error.
1552    pub(crate) fn relation_target_key_decode_failed(
1553        _context_label: &str,
1554        _source_path: &str,
1555        _field_name: &str,
1556        _target_path: &str,
1557        _detail: impl Sized,
1558    ) -> Self {
1559        Self::identity_corruption()
1560    }
1561
1562    /// Construct the canonical relation-target entity mismatch corruption error.
1563    pub(crate) fn relation_target_entity_mismatch(
1564        _context_label: &str,
1565        _source_path: &str,
1566        _field_name: &str,
1567        _target_path: &str,
1568        _target_entity_name: &str,
1569        expected_tag: u64,
1570        actual_tag: u64,
1571    ) -> Self {
1572        Self::with_diagnostic_facts(
1573            ErrorClass::Corruption,
1574            ErrorOrigin::Store,
1575            None,
1576            vec![
1577                (
1578                    diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
1579                    expected_tag,
1580                ),
1581                (
1582                    diagnostic_code::DiagnosticFactTag::ActualEntityTag,
1583                    actual_tag,
1584                ),
1585            ],
1586        )
1587    }
1588
1589    /// Construct the canonical relation-source row decode corruption error.
1590    pub(crate) fn relation_source_row_decode_failed(
1591        _source_path: &str,
1592        _field_name: &str,
1593        _target_path: &str,
1594        _detail: impl Sized,
1595    ) -> Self {
1596        Self::persisted_row_decode_corruption()
1597    }
1598
1599    /// Construct the canonical relation-source unsupported scalar relation-key corruption error.
1600    pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1601        _source_path: &str,
1602        _field_name: &str,
1603        _target_path: &str,
1604    ) -> Self {
1605        Self::persisted_row_decode_corruption()
1606    }
1607
1608    /// Construct the canonical unsupported relation key-kind corruption error.
1609    pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1610        Self::persisted_row_decode_corruption()
1611    }
1612
1613    /// Construct the canonical covering-component empty-payload corruption error.
1614    pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1615        Self::index_corruption()
1616    }
1617
1618    /// Construct the canonical covering-component truncated bool corruption error.
1619    pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1620        Self::index_corruption()
1621    }
1622
1623    /// Construct the canonical covering-component invalid-length corruption error.
1624    pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1625        Self::index_corruption()
1626    }
1627
1628    /// Construct the canonical covering-component invalid-bool corruption error.
1629    pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1630        Self::index_corruption()
1631    }
1632
1633    /// Construct the canonical covering-component invalid text terminator corruption error.
1634    pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1635        Self::index_corruption()
1636    }
1637
1638    /// Construct the canonical covering-component trailing-text corruption error.
1639    pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1640        Self::index_corruption()
1641    }
1642
1643    /// Construct the canonical covering-component invalid-UTF-8 text corruption error.
1644    pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1645        Self::index_corruption()
1646    }
1647
1648    /// Construct the canonical covering-component invalid text escape corruption error.
1649    pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1650        Self::index_corruption()
1651    }
1652
1653    /// Construct the canonical covering-component missing text terminator corruption error.
1654    pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1655        Self::index_corruption()
1656    }
1657
1658    /// Construct an identity-origin corruption error.
1659    pub(crate) fn identity_corruption() -> Self {
1660        Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1661    }
1662
1663    /// Construct the canonical identity-control-state corruption error.
1664    pub(crate) fn identity_state_corruption() -> Self {
1665        Self::identity_corruption()
1666    }
1667
1668    /// Construct the typed stale high-water conflict for identity publication.
1669    pub(crate) fn identity_state_conflict() -> Self {
1670        Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1671    }
1672
1673    /// Construct the bounded identity-state inventory exhaustion error.
1674    pub(crate) fn identity_state_capacity_exhausted() -> Self {
1675        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1676    }
1677
1678    /// Construct the exact unsigned identity-domain exhaustion error.
1679    pub(crate) fn identity_exhausted() -> Self {
1680        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1681    }
1682
1683    /// Construct the bounded pre-key candidate-count exhaustion error.
1684    pub(crate) fn identity_candidate_count_exhausted() -> Self {
1685        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1686    }
1687
1688    /// Construct a store-origin unsupported error.
1689    #[cold]
1690    #[inline(never)]
1691    pub(crate) fn store_unsupported() -> Self {
1692        Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1693    }
1694
1695    /// Construct the typed optimistic/idempotency conflict for schema application.
1696    pub(crate) fn schema_application_conflict() -> Self {
1697        Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1698    }
1699
1700    /// Construct one typed source-migration lifecycle or planning result.
1701    pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1702        let class = match reason.diagnostic_code() {
1703            diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1704            diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1705            diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1706            _ => ErrorClass::Internal,
1707        };
1708        Self {
1709            class,
1710            origin: ErrorOrigin::Store,
1711            detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1712        }
1713    }
1714
1715    /// Construct the canonical schema DDL publication race error.
1716    pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1717        Self {
1718            class: ErrorClass::Unsupported,
1719            origin: ErrorOrigin::Store,
1720            detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1721        }
1722    }
1723
1724    /// Construct the canonical current physical-rewrite migration rejection.
1725    #[cfg(feature = "sql")]
1726    pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1727        Self {
1728            class: ErrorClass::Unsupported,
1729            origin: ErrorOrigin::Store,
1730            detail: Some(ErrorDetail::Store(
1731                StoreError::SchemaDdlRewriteRequiresMigration,
1732            )),
1733        }
1734    }
1735
1736    /// Construct the fail-closed journal mutation-revision exhaustion error.
1737    pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1738        Self {
1739            class: ErrorClass::Unsupported,
1740            origin: ErrorOrigin::Store,
1741            detail: Some(ErrorDetail::Store(
1742                StoreError::JournalMutationRevisionExhausted,
1743            )),
1744        }
1745    }
1746
1747    /// Construct a bounded schema-transition resource rejection.
1748    pub(crate) fn schema_transition_budget_exceeded(
1749        resource: SchemaTransitionBudgetResource,
1750    ) -> Self {
1751        Self {
1752            class: ErrorClass::Unsupported,
1753            origin: ErrorOrigin::Store,
1754            detail: Some(ErrorDetail::Store(
1755                StoreError::SchemaTransitionBudgetExceeded { resource },
1756            )),
1757        }
1758    }
1759
1760    /// Construct the canonical unsupported persisted entity-tag store error.
1761    pub(crate) fn unsupported_entity_tag_in_data_store(
1762        _entity_tag: crate::types::EntityTag,
1763    ) -> Self {
1764        Self::store_unsupported()
1765    }
1766
1767    /// Construct the canonical commit-memory id registration failure.
1768    #[cfg(not(test))]
1769    pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1770        Self::store_internal()
1771    }
1772
1773    /// Construct an index-origin unsupported error.
1774    pub(crate) fn index_unsupported() -> Self {
1775        Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1776    }
1777
1778    /// Construct the canonical index-key component size-limit unsupported error.
1779    pub(crate) fn index_component_exceeds_max_size_at(
1780        entity_tag: u64,
1781        physical_generation: u64,
1782        component_index: usize,
1783        actual_length: usize,
1784        limit: usize,
1785    ) -> Self {
1786        Self::with_diagnostic_facts(
1787            ErrorClass::Unsupported,
1788            ErrorOrigin::Index,
1789            None,
1790            vec![
1791                (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1792                (
1793                    diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1794                    physical_generation,
1795                ),
1796                (
1797                    diagnostic_code::DiagnosticFactTag::ComponentIndex,
1798                    component_index as u64,
1799                ),
1800                (
1801                    diagnostic_code::DiagnosticFactTag::ComponentKind,
1802                    diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
1803                ),
1804                (
1805                    diagnostic_code::DiagnosticFactTag::ActualLength,
1806                    actual_length as u64,
1807                ),
1808                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1809            ],
1810        )
1811    }
1812
1813    /// Construct the canonical index-key component size-limit error when the
1814    /// generic caller has not retained one accepted index identity.
1815    pub(crate) fn index_component_exceeds_max_size() -> Self {
1816        Self::index_unsupported()
1817    }
1818
1819    /// Construct a serialize-origin unsupported error.
1820    pub(crate) fn serialize_unsupported() -> Self {
1821        Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1822    }
1823
1824    /// Construct a cursor-origin invalid-continuation error.
1825    pub(crate) fn cursor_invalid_continuation() -> Self {
1826        Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1827    }
1828
1829    /// Construct a serialize-origin incompatible persisted-format error.
1830    pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1831        Self::new(
1832            ErrorClass::IncompatiblePersistedFormat,
1833            ErrorOrigin::Serialize,
1834        )
1835    }
1836
1837    /// Construct a query-origin unsupported error preserving one SQL parser
1838    /// unsupported-feature code in structured error detail.
1839    #[cfg(feature = "sql")]
1840    pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1841        Self {
1842            class: ErrorClass::Unsupported,
1843            origin: ErrorOrigin::Query,
1844            detail: Some(ErrorDetail::Query(
1845                QueryErrorDetail::UnsupportedSqlFeature { feature },
1846            )),
1847        }
1848    }
1849
1850    /// Construct a query-origin unsupported SQL lowering error preserving one
1851    /// compact lowering reason in structured error detail.
1852    #[cfg(feature = "sql")]
1853    pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1854        Self {
1855            class: ErrorClass::Unsupported,
1856            origin: ErrorOrigin::Query,
1857            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1858        }
1859    }
1860
1861    /// Construct one query-origin SQL lowering error with bounded numeric context.
1862    #[cfg(feature = "sql")]
1863    pub(crate) fn query_sql_lowering_with_facts(
1864        reason: diagnostic_code::SqlLoweringCode,
1865        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1866    ) -> Self {
1867        Self::with_diagnostic_facts(
1868            ErrorClass::Unsupported,
1869            ErrorOrigin::Query,
1870            Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
1871            facts,
1872        )
1873    }
1874
1875    /// Construct a query-origin unsupported projection error preserving one
1876    /// compact projection reason in structured error detail.
1877    pub(crate) fn query_unsupported_projection(
1878        reason: diagnostic_code::QueryProjectionCode,
1879    ) -> Self {
1880        Self {
1881            class: ErrorClass::Unsupported,
1882            origin: ErrorOrigin::Query,
1883            detail: Some(ErrorDetail::Query(
1884                QueryErrorDetail::UnsupportedProjection { reason },
1885            )),
1886        }
1887    }
1888
1889    /// Construct a query-origin unsupported error preserving one SQL endpoint
1890    /// surface mismatch in structured error detail.
1891    #[cfg(feature = "sql")]
1892    pub(crate) fn query_sql_surface_mismatch(
1893        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1894    ) -> Self {
1895        Self {
1896            class: ErrorClass::Unsupported,
1897            origin: ErrorOrigin::Query,
1898            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1899                mismatch,
1900            })),
1901        }
1902    }
1903
1904    /// Construct a query-origin unsupported SQL write boundary error.
1905    pub(crate) fn query_sql_write_boundary(
1906        boundary: diagnostic_code::SqlWriteBoundaryCode,
1907    ) -> Self {
1908        Self {
1909            class: ErrorClass::Unsupported,
1910            origin: ErrorOrigin::Query,
1911            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1912                boundary,
1913            })),
1914        }
1915    }
1916
1917    /// Construct one query-origin SQL write-boundary error with bounded numeric context.
1918    pub(crate) fn query_sql_write_boundary_with_facts(
1919        boundary: diagnostic_code::SqlWriteBoundaryCode,
1920        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1921    ) -> Self {
1922        Self::with_diagnostic_facts(
1923            ErrorClass::Unsupported,
1924            ErrorOrigin::Query,
1925            Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
1926            facts,
1927        )
1928    }
1929
1930    pub fn store_not_found(_key: impl Sized) -> Self {
1931        Self {
1932            class: ErrorClass::NotFound,
1933            origin: ErrorOrigin::Store,
1934            detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1935        }
1936    }
1937
1938    /// Construct a standardized unsupported-entity-path error.
1939    pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1940        Self::store_unsupported()
1941    }
1942
1943    /// Construct an index-plan corruption error with a canonical prefix.
1944    #[cold]
1945    #[inline(never)]
1946    pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1947        Self::new(ErrorClass::Corruption, origin)
1948    }
1949
1950    /// Construct an index-plan corruption error for index-origin failures.
1951    #[cold]
1952    #[inline(never)]
1953    pub(crate) fn index_plan_index_corruption() -> Self {
1954        Self::index_plan_corruption(ErrorOrigin::Index)
1955    }
1956
1957    /// Construct an index-plan corruption error for store-origin failures.
1958    #[cold]
1959    #[inline(never)]
1960    pub(crate) fn index_plan_store_corruption() -> Self {
1961        Self::index_plan_corruption(ErrorOrigin::Store)
1962    }
1963
1964    /// Construct an index-plan corruption error for serialize-origin failures.
1965    #[cold]
1966    #[inline(never)]
1967    pub(crate) fn index_plan_serialize_corruption() -> Self {
1968        Self::index_plan_corruption(ErrorOrigin::Serialize)
1969    }
1970
1971    /// Construct an index-plan invariant violation error with a canonical prefix.
1972    #[cfg(test)]
1973    pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1974        Self::new(ErrorClass::InvariantViolation, origin)
1975    }
1976
1977    /// Construct an index-plan invariant violation error for store-origin failures.
1978    #[cfg(test)]
1979    pub(crate) fn index_plan_store_invariant() -> Self {
1980        Self::index_plan_invariant(ErrorOrigin::Store)
1981    }
1982
1983    /// Construct an index-origin conflict without claiming accepted identity.
1984    ///
1985    /// Live accepted uniqueness violations use compact accepted-constraint facts.
1986    /// Schema-domain staging and activation findings use this compact
1987    /// classification before an accepted write-admission diagnostic exists.
1988    pub(crate) fn index_conflict() -> Self {
1989        Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1990    }
1991}
1992
1993impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1994    fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1995        Self {
1996            class: ErrorClass::Unsupported,
1997            origin: ErrorOrigin::Query,
1998            detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1999                reason,
2000            })),
2001        }
2002    }
2003}
2004
2005impl fmt::Debug for InternalError {
2006    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2007        fmt_compact_diagnostic(
2008            f,
2009            self.diagnostic_code(),
2010            self.detail
2011                .as_ref()
2012                .and_then(ErrorDetail::diagnostic_detail),
2013        )
2014    }
2015}
2016
2017impl fmt::Display for InternalError {
2018    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2019        f.write_str(self.message())
2020    }
2021}
2022
2023impl std::error::Error for InternalError {}
2024
2025///
2026/// ConstraintValuePathComponent
2027///
2028/// Stable accepted identity or finite-value coordinate in one targeted-rule
2029/// violation. Display names are deliberately absent so renames cannot change
2030/// the diagnostic identity.
2031///
2032
2033#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
2034pub enum ConstraintValuePathComponent {
2035    /// Persisted root field whose admitted value was traversed.
2036    RootField { field_id: u32 },
2037
2038    /// Accepted record member selected by immutable composite/member identity.
2039    RecordMember {
2040        composite_type_id: u32,
2041        member_id: u32,
2042    },
2043
2044    /// Tuple element selected by accepted composite identity and ordinal.
2045    TupleElement {
2046        composite_type_id: u32,
2047        ordinal: u32,
2048    },
2049
2050    /// Transparent accepted newtype boundary.
2051    Newtype { composite_type_id: u32 },
2052
2053    /// Selected accepted enum variant.
2054    EnumVariant { enum_type_id: u32, variant_id: u32 },
2055
2056    /// List element in admitted order.
2057    ListElement { index: u32 },
2058
2059    /// Set element in canonical admitted order.
2060    SetElement { index: u32 },
2061
2062    /// Map key in canonical entry order.
2063    MapEntryKey { index: u32 },
2064
2065    /// Map value in canonical entry order.
2066    MapEntryValue { index: u32 },
2067}
2068
2069impl fmt::Display for ConstraintValuePathComponent {
2070    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2071        match self {
2072            Self::RootField { field_id } => write!(f, "field#{field_id}"),
2073            Self::RecordMember {
2074                composite_type_id,
2075                member_id,
2076            } => write!(f, "record#{composite_type_id}.member#{member_id}"),
2077            Self::TupleElement {
2078                composite_type_id,
2079                ordinal,
2080            } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
2081            Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
2082            Self::EnumVariant {
2083                enum_type_id,
2084                variant_id,
2085            } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
2086            Self::ListElement { index } => write!(f, "list[{index}]"),
2087            Self::SetElement { index } => write!(f, "set[{index}]"),
2088            Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
2089            Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
2090        }
2091    }
2092}
2093
2094///
2095/// ConstraintValuePath
2096///
2097/// Bounded typed path to the first deterministic failing value occurrence.
2098///
2099
2100#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2101pub struct ConstraintValuePath {
2102    components: Vec<ConstraintValuePathComponent>,
2103}
2104
2105impl ConstraintValuePath {
2106    /// Build one already-bounded accepted occurrence path.
2107    #[must_use]
2108    pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
2109        Self { components }
2110    }
2111
2112    /// Borrow the stable accepted components.
2113    #[must_use]
2114    pub const fn components(&self) -> &[ConstraintValuePathComponent] {
2115        self.components.as_slice()
2116    }
2117}
2118
2119impl fmt::Display for ConstraintValuePath {
2120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2121        for (ordinal, component) in self.components.iter().enumerate() {
2122            if ordinal != 0 {
2123                f.write_str("/")?;
2124            }
2125            component.fmt(f)?;
2126        }
2127        Ok(())
2128    }
2129}
2130
2131///
2132/// ConstraintValidationFindingOutput
2133///
2134/// Bounded historical validation evidence returned only by explicit schema
2135/// validation operations. Names are resolved by host tooling from the exact
2136/// accepted fingerprint and immutable numeric identities.
2137///
2138
2139#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2140pub struct ConstraintValidationFindingOutput {
2141    accepted_schema_fingerprint: [u8; 16],
2142    entity_tag: u64,
2143    constraint_id: u32,
2144    primary_key: Vec<u8>,
2145    field_ids: Vec<u32>,
2146    value_path: Option<ConstraintValuePath>,
2147    error_code: u16,
2148}
2149
2150impl ConstraintValidationFindingOutput {
2151    /// Build one already-bounded historical validation finding.
2152    #[must_use]
2153    pub(crate) const fn new(
2154        accepted_schema_fingerprint: [u8; 16],
2155        entity_tag: u64,
2156        constraint_id: u32,
2157        primary_key: Vec<u8>,
2158        field_ids: Vec<u32>,
2159        value_path: Option<ConstraintValuePath>,
2160        error_code: u16,
2161    ) -> Self {
2162        Self {
2163            accepted_schema_fingerprint,
2164            entity_tag,
2165            constraint_id,
2166            primary_key,
2167            field_ids,
2168            value_path,
2169            error_code,
2170        }
2171    }
2172
2173    /// Return the exact accepted-schema fingerprint that binds every numeric identity.
2174    #[must_use]
2175    pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
2176        self.accepted_schema_fingerprint
2177    }
2178
2179    /// Return the stable accepted entity identity.
2180    #[must_use]
2181    pub const fn entity_tag(&self) -> u64 {
2182        self.entity_tag
2183    }
2184
2185    /// Return the stable accepted constraint identity.
2186    #[must_use]
2187    pub const fn constraint_id(&self) -> u32 {
2188        self.constraint_id
2189    }
2190
2191    /// Borrow the bounded canonical persisted primary-key locator.
2192    #[must_use]
2193    pub const fn primary_key(&self) -> &[u8] {
2194        self.primary_key.as_slice()
2195    }
2196
2197    /// Borrow immutable accepted field identities implicated by the finding.
2198    #[must_use]
2199    pub const fn field_ids(&self) -> &[u32] {
2200        self.field_ids.as_slice()
2201    }
2202
2203    /// Borrow the typed concrete value path for a targeted-rule violation.
2204    #[must_use]
2205    pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2206        self.value_path.as_ref()
2207    }
2208
2209    /// Return the compact stable error code for this exact failure.
2210    #[must_use]
2211    pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2212        diagnostic_code::ErrorCode::from_raw(self.error_code)
2213    }
2214
2215    /// Return the broad public error class derived from the compact code.
2216    #[must_use]
2217    pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2218        self.error_code().class()
2219    }
2220}
2221
2222/// Complete bounded numeric authority needed to publish E223 or E225 facts.
2223#[derive(Clone)]
2224pub(crate) struct AcceptedConstraintFactContext {
2225    fingerprint_method: u8,
2226    accepted_schema_fingerprint: [u8; 16],
2227    entity_tag: u64,
2228    constraint_id: u32,
2229    constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2230    mutation: Option<MutationDiagnosticContext>,
2231    value_path: Option<ConstraintValuePath>,
2232}
2233
2234impl AcceptedConstraintFactContext {
2235    #[must_use]
2236    pub(crate) fn write_admission(
2237        fingerprint_method: u8,
2238        accepted_schema_fingerprint: [u8; 16],
2239        entity_tag: u64,
2240        constraint_id: u32,
2241        constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2242        mutation: Option<MutationDiagnosticContext>,
2243        value_path: Option<ConstraintValuePath>,
2244    ) -> Self {
2245        debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2246        Self {
2247            fingerprint_method,
2248            accepted_schema_fingerprint,
2249            entity_tag,
2250            constraint_id,
2251            constraint_kind,
2252            mutation,
2253            value_path,
2254        }
2255    }
2256
2257    fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2258        let high = u64::from_be_bytes([
2259            self.accepted_schema_fingerprint[0],
2260            self.accepted_schema_fingerprint[1],
2261            self.accepted_schema_fingerprint[2],
2262            self.accepted_schema_fingerprint[3],
2263            self.accepted_schema_fingerprint[4],
2264            self.accepted_schema_fingerprint[5],
2265            self.accepted_schema_fingerprint[6],
2266            self.accepted_schema_fingerprint[7],
2267        ]);
2268        let low = u64::from_be_bytes([
2269            self.accepted_schema_fingerprint[8],
2270            self.accepted_schema_fingerprint[9],
2271            self.accepted_schema_fingerprint[10],
2272            self.accepted_schema_fingerprint[11],
2273            self.accepted_schema_fingerprint[12],
2274            self.accepted_schema_fingerprint[13],
2275            self.accepted_schema_fingerprint[14],
2276            self.accepted_schema_fingerprint[15],
2277        ]);
2278        let path_len = self
2279            .value_path
2280            .as_ref()
2281            .map_or(0, |path| path.components().len());
2282        let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2283            1 + usize::from(mutation.batch_position.is_some())
2284        });
2285        let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2286        facts.push((
2287            diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2288            u64::from(self.fingerprint_method),
2289        ));
2290        facts.push((
2291            diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2292            high,
2293        ));
2294        facts.push((
2295            diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2296            low,
2297        ));
2298        facts.push((
2299            diagnostic_code::DiagnosticFactTag::EntityTag,
2300            self.entity_tag,
2301        ));
2302        facts.push((
2303            diagnostic_code::DiagnosticFactTag::ConstraintId,
2304            u64::from(self.constraint_id),
2305        ));
2306        facts.push((
2307            diagnostic_code::DiagnosticFactTag::ConstraintKind,
2308            self.constraint_kind.raw(),
2309        ));
2310        facts.push((
2311            diagnostic_code::DiagnosticFactTag::ConstraintContext,
2312            diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2313        ));
2314        if let Some(mutation) = self.mutation {
2315            mutation.append_operation_facts(&mut facts);
2316        }
2317        if let Some(path) = self.value_path {
2318            for component in path.components {
2319                facts.push(constraint_value_path_fact(component));
2320            }
2321        }
2322        debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2323        facts
2324    }
2325}
2326
2327fn constraint_value_path_fact(
2328    component: ConstraintValuePathComponent,
2329) -> (diagnostic_code::DiagnosticFactTag, u64) {
2330    use diagnostic_code::DiagnosticFactTag;
2331    match component {
2332        ConstraintValuePathComponent::RootField { field_id } => {
2333            (DiagnosticFactTag::RootField, u64::from(field_id))
2334        }
2335        ConstraintValuePathComponent::RecordMember {
2336            composite_type_id,
2337            member_id,
2338        } => (
2339            DiagnosticFactTag::RecordMember,
2340            diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2341        ),
2342        ConstraintValuePathComponent::TupleElement {
2343            composite_type_id,
2344            ordinal,
2345        } => (
2346            DiagnosticFactTag::TupleElement,
2347            diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2348        ),
2349        ConstraintValuePathComponent::Newtype { composite_type_id } => {
2350            (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2351        }
2352        ConstraintValuePathComponent::EnumVariant {
2353            enum_type_id,
2354            variant_id,
2355        } => (
2356            DiagnosticFactTag::EnumVariant,
2357            diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2358        ),
2359        ConstraintValuePathComponent::ListElement { index } => {
2360            (DiagnosticFactTag::ListElement, u64::from(index))
2361        }
2362        ConstraintValuePathComponent::SetElement { index } => {
2363            (DiagnosticFactTag::SetElement, u64::from(index))
2364        }
2365        ConstraintValuePathComponent::MapEntryKey { index } => {
2366            (DiagnosticFactTag::MapEntryKey, u64::from(index))
2367        }
2368        ConstraintValuePathComponent::MapEntryValue { index } => {
2369            (DiagnosticFactTag::MapEntryValue, u64::from(index))
2370        }
2371    }
2372}
2373
2374///
2375/// ErrorDetail
2376///
2377/// Structured, origin-specific error detail carried by [`InternalError`].
2378/// This enum is intentionally extensible.
2379///
2380
2381pub enum ErrorDetail {
2382    /// Compact code/detail plus safe numeric context for one public failure.
2383    DiagnosticFacts(Box<DiagnosticFactDetail>),
2384    /// Executor-owned mutation and query execution details.
2385    Executor(ExecutorErrorDetail),
2386    Store(StoreError),
2387    Query(QueryErrorDetail),
2388    Recovery(RecoveryErrorDetail),
2389    // Future-proofing:
2390    // Index(IndexError),
2391}
2392
2393/// Executor-specific structured error detail.
2394pub enum ExecutorErrorDetail {
2395    /// A complete insert or replacement omitted one or more required fields.
2396    MutationRequiredFieldMissing,
2397    /// A logical mutation would move accepted managed time backward.
2398    MutationManagedTimestampRegression,
2399    /// A caller explicitly authored a field owned by accepted database policy.
2400    MutationDatabaseOwnedFieldExplicit,
2401    /// A mixed structural mutation batch contained no operations.
2402    MutationBatchEmpty,
2403    /// A mixed structural mutation batch exceeded its operation-count bound.
2404    MutationBatchTooManyItems,
2405    /// A mixed structural mutation batch exceeded its staged-byte bound.
2406    MutationBatchStagedBytesExceeded,
2407    /// A mixed structural mutation result exceeded its encoded response bound.
2408    MutationBatchResultBytesExceeded,
2409    /// A mixed structural mutation batch crossed an accepted store boundary.
2410    MutationBatchStoreMismatch,
2411    /// A mixed structural mutation batch exceeded its distinct-entity bound.
2412    MutationBatchTooManyEntities,
2413    /// More than one mixed structural operation targeted the same accepted key.
2414    MutationBatchDuplicateKey,
2415    /// Accepted row-constraint metadata or compiled state was inconsistent.
2416    AcceptedRowConstraintProgramCorrupt,
2417}
2418
2419///
2420/// RecoveryErrorDetail
2421///
2422/// Recovery-origin structured error detail payload.
2423///
2424
2425pub enum RecoveryErrorDetail {
2426    UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2427
2428    MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2429}
2430
2431/// Store boot-marker corruption classification.
2432#[derive(Clone, Copy, Eq, PartialEq)]
2433pub enum RecoveryFormatMarkerError {
2434    Magic,
2435    Checksum,
2436    State,
2437}
2438
2439impl RecoveryFormatMarkerError {
2440    const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2441        match self {
2442            Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2443            Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2444            Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2445        }
2446    }
2447}
2448
2449///
2450/// StoreError
2451///
2452/// Store-specific structured error detail.
2453/// Never returned directly; always wrapped in [`ErrorDetail::Store`].
2454///
2455
2456pub enum StoreError {
2457    NotFound,
2458
2459    Corrupt,
2460
2461    InvariantViolation,
2462
2463    SchemaDdlPublicationRaceLost,
2464
2465    SchemaDdlRewriteRequiresMigration,
2466
2467    SchemaMigration {
2468        reason: diagnostic_code::SchemaMigrationCode,
2469    },
2470
2471    SchemaRowLayoutVersionExhausted,
2472
2473    JournalMutationRevisionExhausted,
2474
2475    SchemaTransitionBudgetExceeded {
2476        resource: SchemaTransitionBudgetResource,
2477    },
2478
2479    /// A generated field would collide with an accepted DDL-owned slot.
2480    SchemaGeneratedFieldAfterDdlField,
2481
2482    /// A live generated constraint activation no longer matches its proposal.
2483    SchemaGeneratedConstraintActivationStale,
2484}
2485
2486///
2487/// QueryErrorDetail
2488///
2489/// Query-origin structured error detail payload.
2490///
2491
2492pub enum QueryErrorDetail {
2493    NumericOverflow,
2494
2495    NumericNotRepresentable,
2496
2497    UnsupportedSqlFeature {
2498        feature: diagnostic_code::SqlFeatureCode,
2499    },
2500
2501    SqlLowering {
2502        reason: diagnostic_code::SqlLoweringCode,
2503    },
2504
2505    UnsupportedProjection {
2506        reason: diagnostic_code::QueryProjectionCode,
2507    },
2508
2509    UnknownAggregateTargetField,
2510
2511    ResultShapeMismatch {
2512        reason: diagnostic_code::QueryResultShapeCode,
2513    },
2514
2515    QueryReadAdmission {
2516        reason: diagnostic_code::QueryReadAdmissionCode,
2517    },
2518
2519    SqlSurfaceMismatch {
2520        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2521    },
2522
2523    SqlWriteBoundary {
2524        boundary: diagnostic_code::SqlWriteBoundaryCode,
2525    },
2526
2527    SchemaDdlAdmission {
2528        error: SchemaDdlAdmissionError,
2529    },
2530
2531    StaleSchemaRevision,
2532}
2533
2534impl fmt::Display for QueryErrorDetail {
2535    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2536        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2537    }
2538}
2539
2540impl std::error::Error for QueryErrorDetail {}
2541
2542///
2543/// SchemaTransitionBudgetResource
2544///
2545/// Query-visible identity of the exact schema-transition resource cap that
2546/// rejected a complete validation or derived-state stage.
2547///
2548
2549#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2550pub enum SchemaTransitionBudgetResource {
2551    /// Number of physical deletion keys retained for replacement.
2552    DeletionKeys,
2553    /// Number of row-derived projection entries retained for validation.
2554    ProjectionEntries,
2555    /// Deterministic projection and physical-classification work units.
2556    ProjectionWorkUnits,
2557    /// Number of authoritative source rows.
2558    SourceRows,
2559    /// Cumulative bytes of authoritative source rows.
2560    SourceRowBytes,
2561    /// Retained raw payloads plus deterministic-sort workspace bytes.
2562    StagedRawBytes,
2563}
2564
2565///
2566/// SchemaDdlAdmissionError
2567///
2568/// Stable query-visible SQL DDL admission reason. Human diagnostics may carry
2569/// extra version, fingerprint, and target facts beside this machine-readable
2570/// variant.
2571///
2572
2573#[derive(Clone, Copy, Eq, PartialEq)]
2574pub enum SchemaDdlAdmissionError {
2575    MissingExpectedSchemaVersion,
2576
2577    MissingNextSchemaVersion,
2578
2579    StaleExpectedSchemaVersion,
2580
2581    InvalidExpectedSchemaVersion,
2582
2583    InvalidNextSchemaVersion,
2584
2585    AcceptedSchemaChangeWithoutVersionBump,
2586
2587    EmptyVersionBump,
2588
2589    VersionGap,
2590
2591    VersionRollback,
2592
2593    FingerprintMethodMismatch,
2594
2595    UnsupportedTransitionClass,
2596
2597    PhysicalRunnerMissing,
2598
2599    ValidationFailed,
2600
2601    PublicationRaceLost,
2602
2603    InvalidAddColumnDefault,
2604
2605    InvalidAlterColumnDefault,
2606
2607    RowLayoutVersionExhausted,
2608
2609    GeneratedIndexDropRejected,
2610
2611    SchemaRewriteRequiresMigration,
2612
2613    SchemaTransitionBudgetExceeded {
2614        resource: SchemaTransitionBudgetResource,
2615    },
2616
2617    GeneratedFieldDefaultChangeRejected,
2618
2619    GeneratedFieldNullabilityChangeRejected,
2620}
2621
2622impl fmt::Display for SchemaDdlAdmissionError {
2623    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2624        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2625    }
2626}
2627
2628impl std::error::Error for SchemaDdlAdmissionError {}
2629
2630impl fmt::Debug for ErrorDetail {
2631    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2632        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2633    }
2634}
2635
2636impl fmt::Debug for ExecutorErrorDetail {
2637    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2638        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2639    }
2640}
2641
2642impl fmt::Debug for StoreError {
2643    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2644        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2645    }
2646}
2647
2648impl fmt::Debug for QueryErrorDetail {
2649    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2650        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2651    }
2652}
2653
2654impl fmt::Debug for RecoveryErrorDetail {
2655    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2656        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2657    }
2658}
2659
2660impl fmt::Debug for RecoveryFormatMarkerError {
2661    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2662        fmt_compact_diagnostic(
2663            f,
2664            diagnostic_code::DiagnosticCode::RuntimeCorruption,
2665            Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2666                kind: diagnostic_code::RuntimeErrorKind::Corruption,
2667            }),
2668        )
2669    }
2670}
2671
2672impl fmt::Debug for SchemaDdlAdmissionError {
2673    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2674        fmt_compact_diagnostic(
2675            f,
2676            diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2677            Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2678                reason: self.diagnostic_code(),
2679            }),
2680        )
2681    }
2682}
2683
2684fn fmt_compact_diagnostic(
2685    f: &mut fmt::Formatter<'_>,
2686    code: diagnostic_code::DiagnosticCode,
2687    detail: Option<diagnostic_code::DiagnosticDetail>,
2688) -> fmt::Result {
2689    write!(
2690        f,
2691        "{}",
2692        diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2693    )
2694}
2695
2696impl ErrorDetail {
2697    /// Return the compact diagnostic code for this structured detail.
2698    #[must_use]
2699    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2700        match self {
2701            Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2702            Self::Executor(error) => error.diagnostic_code(),
2703            Self::Store(error) => error.diagnostic_code(),
2704            Self::Query(error) => error.diagnostic_code(),
2705            Self::Recovery(error) => error.diagnostic_code(),
2706        }
2707    }
2708
2709    /// Return compact structured diagnostic detail when the payload carries one.
2710    #[must_use]
2711    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2712        match self {
2713            Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2714            Self::Executor(error) => error.diagnostic_detail(),
2715            Self::Store(error) => error.diagnostic_detail(),
2716            Self::Query(error) => error.diagnostic_detail(),
2717            Self::Recovery(error) => error.diagnostic_detail(),
2718        }
2719    }
2720
2721    /// Project safe typed detail into canonical public numeric facts.
2722    #[must_use]
2723    #[cold]
2724    #[inline(never)]
2725    pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2726        match self {
2727            Self::DiagnosticFacts(detail) => detail.facts.clone(),
2728            Self::Executor(error) => error.diagnostic_facts(),
2729            Self::Query(error) => error.diagnostic_facts(),
2730            Self::Recovery(error) => error.diagnostic_facts(),
2731            Self::Store(_) => Vec::new(),
2732        }
2733    }
2734}
2735
2736impl ExecutorErrorDetail {
2737    /// Return the compact diagnostic code for this executor detail.
2738    #[must_use]
2739    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2740        match self {
2741            Self::MutationRequiredFieldMissing
2742            | Self::MutationDatabaseOwnedFieldExplicit
2743            | Self::MutationBatchEmpty
2744            | Self::MutationBatchTooManyItems
2745            | Self::MutationBatchTooManyEntities
2746            | Self::MutationBatchStagedBytesExceeded
2747            | Self::MutationBatchResultBytesExceeded => {
2748                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2749            }
2750            Self::MutationBatchStoreMismatch | Self::MutationBatchDuplicateKey => {
2751                diagnostic_code::DiagnosticCode::RuntimeConflict
2752            }
2753            Self::MutationManagedTimestampRegression => {
2754                diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2755            }
2756            Self::AcceptedRowConstraintProgramCorrupt => {
2757                diagnostic_code::DiagnosticCode::RuntimeCorruption
2758            }
2759        }
2760    }
2761
2762    /// Return compact structured diagnostic detail for this executor detail.
2763    #[must_use]
2764    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2765        match self {
2766            Self::MutationRequiredFieldMissing => {
2767                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2768                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2769                })
2770            }
2771            Self::MutationDatabaseOwnedFieldExplicit => {
2772                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2773                    boundary:
2774                        diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2775                })
2776            }
2777            Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2778                boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2779            }),
2780            Self::MutationBatchTooManyItems => {
2781                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2782                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2783                })
2784            }
2785            Self::MutationBatchStagedBytesExceeded => {
2786                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2787                    boundary:
2788                        diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2789                })
2790            }
2791            Self::MutationBatchResultBytesExceeded => {
2792                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2793                    boundary:
2794                        diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2795                })
2796            }
2797            Self::MutationBatchStoreMismatch => {
2798                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2799                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
2800                })
2801            }
2802            Self::MutationBatchTooManyEntities => {
2803                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2804                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
2805                })
2806            }
2807            Self::MutationBatchDuplicateKey => {
2808                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2809                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2810                })
2811            }
2812            Self::MutationManagedTimestampRegression => {
2813                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2814                    boundary:
2815                        diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2816                })
2817            }
2818            Self::AcceptedRowConstraintProgramCorrupt => {
2819                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2820                    boundary:
2821                        diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2822                })
2823            }
2824        }
2825    }
2826
2827    /// Project safe mutation detail into canonical public numeric facts.
2828    #[must_use]
2829    #[cold]
2830    #[inline(never)]
2831    pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2832        Vec::new()
2833    }
2834}
2835
2836impl RecoveryErrorDetail {
2837    /// Return the compact diagnostic code for this recovery detail.
2838    #[must_use]
2839    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2840        match self {
2841            Self::UnsupportedFormatVersion { .. } => {
2842                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2843            }
2844            Self::MalformedFormatMarker { .. } => {
2845                diagnostic_code::DiagnosticCode::RuntimeCorruption
2846            }
2847        }
2848    }
2849
2850    /// Return compact structured diagnostic detail for this recovery detail.
2851    #[must_use]
2852    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2853        let kind = match self {
2854            Self::UnsupportedFormatVersion { .. } => {
2855                diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2856            }
2857            Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2858        };
2859
2860        Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2861    }
2862
2863    /// Project database-format recovery context without retaining marker bytes.
2864    #[must_use]
2865    pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2866        match self {
2867            Self::UnsupportedFormatVersion { found, required } => {
2868                let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2869                facts.push((
2870                    diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2871                    u64::from(*required),
2872                ));
2873                if let Some(found) = found {
2874                    facts.push((
2875                        diagnostic_code::DiagnosticFactTag::ActualVersion,
2876                        u64::from(*found),
2877                    ));
2878                }
2879                facts
2880            }
2881            Self::MalformedFormatMarker { reason } => vec![(
2882                diagnostic_code::DiagnosticFactTag::DecodeReason,
2883                reason.diagnostic_decode_reason().raw(),
2884            )],
2885        }
2886    }
2887}
2888
2889impl StoreError {
2890    /// Return the compact diagnostic code for this store detail.
2891    #[must_use]
2892    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2893        match self {
2894            Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2895            Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2896            Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2897            Self::SchemaDdlPublicationRaceLost
2898            | Self::SchemaDdlRewriteRequiresMigration
2899            | Self::SchemaRowLayoutVersionExhausted
2900            | Self::SchemaTransitionBudgetExceeded { .. } => {
2901                diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2902            }
2903            Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2904                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2905            }
2906            Self::SchemaGeneratedConstraintActivationStale => {
2907                diagnostic_code::DiagnosticCode::RuntimeConflict
2908            }
2909            Self::SchemaMigration { reason } => reason.diagnostic_code(),
2910        }
2911    }
2912
2913    /// Return compact structured diagnostic detail when the store error has one.
2914    #[must_use]
2915    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2916        match self {
2917            Self::SchemaDdlPublicationRaceLost => {
2918                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2919                    reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2920                })
2921            }
2922            Self::SchemaDdlRewriteRequiresMigration => {
2923                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2924                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2925                })
2926            }
2927            Self::SchemaMigration { reason } => {
2928                Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2929            }
2930            Self::SchemaRowLayoutVersionExhausted => {
2931                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2932                    reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2933                })
2934            }
2935            Self::JournalMutationRevisionExhausted => {
2936                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2937                    boundary:
2938                        diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2939                })
2940            }
2941            Self::SchemaTransitionBudgetExceeded { .. } => {
2942                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2943                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2944                })
2945            }
2946            Self::SchemaGeneratedFieldAfterDdlField => {
2947                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2948                    boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2949                })
2950            }
2951            Self::SchemaGeneratedConstraintActivationStale => {
2952                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2953                    boundary:
2954                        diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2955                })
2956            }
2957            Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2958        }
2959    }
2960}
2961
2962impl QueryErrorDetail {
2963    /// Return the compact diagnostic code for this query detail.
2964    #[must_use]
2965    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2966        match self {
2967            Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2968            Self::NumericNotRepresentable => {
2969                diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2970            }
2971            Self::UnsupportedSqlFeature { .. } => {
2972                diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2973            }
2974            Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2975            Self::UnsupportedProjection { .. } => {
2976                diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2977            }
2978            Self::UnknownAggregateTargetField => {
2979                diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2980            }
2981            Self::ResultShapeMismatch { .. } => {
2982                diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
2983            }
2984            Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2985            Self::SqlSurfaceMismatch { .. } => {
2986                diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2987            }
2988            Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2989            Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2990            Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2991        }
2992    }
2993
2994    /// Return compact structured diagnostic detail when the query detail has one.
2995    #[must_use]
2996    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2997        match self {
2998            Self::UnsupportedSqlFeature { feature } => {
2999                Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
3000            }
3001            Self::SqlLowering { reason } => {
3002                Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
3003            }
3004            Self::UnsupportedProjection { reason } => {
3005                Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
3006            }
3007            Self::ResultShapeMismatch { reason } => {
3008                Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
3009            }
3010            Self::QueryReadAdmission { reason } => {
3011                Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
3012            }
3013            Self::SqlSurfaceMismatch { mismatch } => {
3014                Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
3015                    mismatch: *mismatch,
3016                })
3017            }
3018            Self::SqlWriteBoundary { boundary } => {
3019                Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
3020                    boundary: *boundary,
3021                })
3022            }
3023            Self::SchemaDdlAdmission { error } => {
3024                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
3025                    reason: error.diagnostic_code(),
3026                })
3027            }
3028            Self::NumericOverflow
3029            | Self::NumericNotRepresentable
3030            | Self::UnknownAggregateTargetField
3031            | Self::StaleSchemaRevision => None,
3032        }
3033    }
3034
3035    /// Project safe query detail into canonical public numeric facts.
3036    #[must_use]
3037    #[cold]
3038    #[inline(never)]
3039    pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
3040        Vec::new()
3041    }
3042}
3043
3044impl SchemaDdlAdmissionError {
3045    /// Return the compact diagnostic code for this SQL DDL admission reason.
3046    #[must_use]
3047    pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
3048        match self {
3049            Self::MissingExpectedSchemaVersion => {
3050                diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
3051            }
3052            Self::MissingNextSchemaVersion => {
3053                diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
3054            }
3055            Self::StaleExpectedSchemaVersion => {
3056                diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
3057            }
3058            Self::InvalidExpectedSchemaVersion => {
3059                diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
3060            }
3061            Self::InvalidNextSchemaVersion => {
3062                diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
3063            }
3064            Self::AcceptedSchemaChangeWithoutVersionBump => {
3065                diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
3066            }
3067            Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
3068            Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
3069            Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
3070            Self::FingerprintMethodMismatch => {
3071                diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
3072            }
3073            Self::UnsupportedTransitionClass => {
3074                diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
3075            }
3076            Self::PhysicalRunnerMissing => {
3077                diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
3078            }
3079            Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
3080            Self::PublicationRaceLost => {
3081                diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
3082            }
3083            Self::InvalidAddColumnDefault => {
3084                diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
3085            }
3086            Self::InvalidAlterColumnDefault => {
3087                diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
3088            }
3089            Self::GeneratedIndexDropRejected => {
3090                diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
3091            }
3092            Self::SchemaRewriteRequiresMigration => {
3093                diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
3094            }
3095            Self::SchemaTransitionBudgetExceeded { .. } => {
3096                diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
3097            }
3098            Self::GeneratedFieldDefaultChangeRejected => {
3099                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
3100            }
3101            Self::GeneratedFieldNullabilityChangeRejected => {
3102                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
3103            }
3104            Self::RowLayoutVersionExhausted => {
3105                diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
3106            }
3107        }
3108    }
3109}
3110
3111///
3112/// ErrorClass
3113/// Internal error taxonomy for runtime classification.
3114/// Not a stable API; may change without notice.
3115///
3116
3117#[repr(u8)]
3118#[derive(Clone, Copy, Eq, PartialEq)]
3119pub enum ErrorClass {
3120    Corruption,
3121    IncompatiblePersistedFormat,
3122    NotFound,
3123    Internal,
3124    Conflict,
3125    Unsupported,
3126    InvariantViolation,
3127}
3128
3129impl ErrorClass {
3130    /// Return a compact diagnostic code for this broad class and origin pair.
3131    #[must_use]
3132    pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
3133        match self {
3134            Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
3135                diagnostic_code::DiagnosticCode::StoreCorruption
3136            }
3137            Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
3138            Self::IncompatiblePersistedFormat => {
3139                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
3140            }
3141            Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
3142                diagnostic_code::DiagnosticCode::StoreNotFound
3143            }
3144            Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
3145            Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
3146            Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
3147            Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
3148                diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
3149            }
3150            Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
3151            Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
3152                diagnostic_code::DiagnosticCode::StoreInvariantViolation
3153            }
3154            Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3155        }
3156    }
3157}
3158
3159impl fmt::Debug for ErrorClass {
3160    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3161        write!(f, "{}", *self as u8)
3162    }
3163}
3164
3165///
3166/// ErrorOrigin
3167/// Internal origin taxonomy for runtime classification.
3168/// Not a stable API; may change without notice.
3169///
3170
3171#[repr(u8)]
3172#[derive(Clone, Copy, Eq, PartialEq)]
3173pub enum ErrorOrigin {
3174    Serialize,
3175    Store,
3176    Index,
3177    Identity,
3178    Query,
3179    Planner,
3180    Cursor,
3181    Recovery,
3182    Response,
3183    Executor,
3184    Interface,
3185}
3186
3187impl ErrorOrigin {
3188    /// Return the compact diagnostic origin for this internal origin.
3189    #[must_use]
3190    pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3191        match self {
3192            Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3193            Self::Store => diagnostic_code::ErrorOrigin::Store,
3194            Self::Index => diagnostic_code::ErrorOrigin::Index,
3195            Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3196            Self::Query => diagnostic_code::ErrorOrigin::Query,
3197            Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3198            Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3199            Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3200            Self::Response => diagnostic_code::ErrorOrigin::Response,
3201            Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3202            Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3203        }
3204    }
3205}
3206
3207impl fmt::Debug for ErrorOrigin {
3208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3209        write!(f, "{}", *self as u8)
3210    }
3211}