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 a query-origin exact-key item-bound rejection.
806    #[cold]
807    #[inline(never)]
808    pub(crate) fn exact_key_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
809        Self::exact_key_batch_boundary_with_facts(
810            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchTooManyItems,
811            vec![
812                (
813                    diagnostic_code::DiagnosticFactTag::ActualCount,
814                    actual_count as u64,
815                ),
816                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
817            ],
818        )
819    }
820
821    /// Construct a query-origin exact-key input-byte rejection.
822    #[cold]
823    #[inline(never)]
824    pub(crate) fn exact_key_batch_input_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
825        Self::exact_key_batch_bytes_exceeded(
826            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchInputBytesExceeded,
827            actual_bytes,
828            limit,
829        )
830    }
831
832    /// Construct a query-origin exact-key stored-row-byte rejection.
833    #[cold]
834    #[inline(never)]
835    pub(crate) fn exact_key_batch_stored_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
836        Self::exact_key_batch_bytes_exceeded(
837            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchStoredBytesExceeded,
838            actual_bytes,
839            limit,
840        )
841    }
842
843    /// Construct a query-origin exact-key result-byte rejection.
844    #[cold]
845    #[inline(never)]
846    pub(crate) fn exact_key_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
847        Self::exact_key_batch_bytes_exceeded(
848            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchResultBytesExceeded,
849            actual_bytes,
850            limit,
851        )
852    }
853
854    #[cold]
855    #[inline(never)]
856    fn exact_key_batch_bytes_exceeded(
857        boundary: diagnostic_code::RuntimeBoundaryCode,
858        actual_bytes: usize,
859        limit: usize,
860    ) -> Self {
861        Self::exact_key_batch_boundary_with_facts(
862            boundary,
863            vec![
864                (
865                    diagnostic_code::DiagnosticFactTag::ActualLength,
866                    actual_bytes as u64,
867                ),
868                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
869            ],
870        )
871    }
872
873    /// Construct an executor-origin mixed-entity batch rejection.
874    #[cold]
875    #[inline(never)]
876    pub(crate) fn mutation_batch_entity_mismatch(
877        batch_position: u32,
878        expected_entity_tag: u64,
879        actual_entity_tag: u64,
880    ) -> Self {
881        Self::mutation_boundary_with_facts(
882            ErrorClass::Conflict,
883            diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
884            vec![
885                (
886                    diagnostic_code::DiagnosticFactTag::BatchPosition,
887                    u64::from(batch_position),
888                ),
889                (
890                    diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
891                    expected_entity_tag,
892                ),
893                (
894                    diagnostic_code::DiagnosticFactTag::ActualEntityTag,
895                    actual_entity_tag,
896                ),
897            ],
898        )
899    }
900
901    /// Construct an executor-origin mutation invariant for index-store generation drift.
902    pub(crate) fn mutation_index_store_generation_changed(
903        _expected_generation: u64,
904        _observed_generation: u64,
905    ) -> Self {
906        Self::executor_invariant()
907    }
908
909    /// Construct a planner-origin invariant violation.
910    #[cold]
911    #[inline(never)]
912    pub(crate) fn planner_invariant() -> Self {
913        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
914    }
915
916    /// Construct a planner-origin invalid-logical-plan invariant.
917    pub(crate) fn query_invalid_logical_plan() -> Self {
918        Self::planner_invariant()
919    }
920
921    /// Construct a store-origin invariant violation.
922    pub(crate) fn store_invariant() -> Self {
923        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
924    }
925
926    /// Construct a store-origin internal error.
927    #[cold]
928    #[inline(never)]
929    pub(crate) fn store_internal() -> Self {
930        Self::new(ErrorClass::Internal, ErrorOrigin::Store)
931    }
932
933    /// Construct the canonical unconfigured commit-memory id internal error.
934    pub(crate) fn commit_memory_id_unconfigured() -> Self {
935        Self::store_internal()
936    }
937
938    /// Construct the canonical initialized commit-store lookup invariant.
939    pub(crate) fn commit_store_uninitialized() -> Self {
940        Self::store_invariant()
941    }
942
943    /// Construct the canonical commit-memory id mismatch internal error.
944    pub(crate) fn commit_memory_id_mismatch(cached_id: u8, configured_id: u8) -> Self {
945        Self::with_diagnostic_facts(
946            ErrorClass::Internal,
947            ErrorOrigin::Store,
948            None,
949            vec![
950                (
951                    diagnostic_code::DiagnosticFactTag::ExpectedMemoryId,
952                    u64::from(cached_id),
953                ),
954                (
955                    diagnostic_code::DiagnosticFactTag::ActualMemoryId,
956                    u64::from(configured_id),
957                ),
958            ],
959        )
960    }
961
962    /// Construct the canonical commit-memory stable-key mismatch internal error.
963    pub(crate) fn commit_memory_stable_key_mismatch(
964        _cached_key: &str,
965        _configured_key: &str,
966    ) -> Self {
967        Self::store_internal()
968    }
969
970    /// Construct the canonical database-incarnation generation failure.
971    pub(crate) fn database_incarnation_generation_failed() -> Self {
972        Self::store_internal()
973    }
974
975    /// Construct the canonical zero database-incarnation corruption error.
976    pub(crate) fn database_incarnation_invalid() -> Self {
977        Self::store_corruption()
978    }
979
980    /// Construct a recovery-origin incompatible store-format error.
981    pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
982        Self {
983            class: ErrorClass::IncompatiblePersistedFormat,
984            origin: ErrorOrigin::Recovery,
985            detail: Some(ErrorDetail::Recovery(
986                RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
987            )),
988        }
989    }
990
991    /// Construct a recovery-origin malformed store-format marker error.
992    pub(crate) fn recovery_malformed_database_format_marker(
993        reason: RecoveryFormatMarkerError,
994    ) -> Self {
995        Self {
996            class: ErrorClass::Corruption,
997            origin: ErrorOrigin::Recovery,
998            detail: Some(ErrorDetail::Recovery(
999                RecoveryErrorDetail::MalformedFormatMarker { reason },
1000            )),
1001        }
1002    }
1003
1004    /// Construct a recovery-origin boot control-memory failure.
1005    pub(crate) fn recovery_database_format_control_unavailable() -> Self {
1006        Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
1007    }
1008
1009    /// Construct the retryable internal boundary returned while bounded startup recovery remains.
1010    pub(crate) fn recovery_pending() -> Self {
1011        Self::with_diagnostic_facts(
1012            ErrorClass::Conflict,
1013            ErrorOrigin::Recovery,
1014            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1015                boundary: diagnostic_code::RuntimeBoundaryCode::DatabaseStartupRecoveryPending,
1016            }),
1017            Vec::new(),
1018        )
1019    }
1020
1021    /// Construct fail-closed corruption for the bounded startup control cell.
1022    pub(crate) fn startup_control_corruption() -> Self {
1023        Self::new(ErrorClass::Corruption, ErrorOrigin::Recovery)
1024    }
1025
1026    /// Construct a commit control-memory growth failure.
1027    pub(crate) fn commit_control_memory_growth_failed() -> Self {
1028        Self::store_internal()
1029    }
1030
1031    /// Construct a store-format memory registration failure.
1032    #[cfg(not(test))]
1033    pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
1034        Self::store_internal()
1035    }
1036
1037    /// Construct the canonical recovered-effect verification failure.
1038    pub(crate) fn recovery_effect_verification_failed() -> Self {
1039        Self::store_corruption()
1040    }
1041
1042    /// Construct an index-origin internal error.
1043    #[cold]
1044    #[inline(never)]
1045    pub(crate) fn index_internal() -> Self {
1046        Self::new(ErrorClass::Internal, ErrorOrigin::Index)
1047    }
1048
1049    /// Construct the canonical missing old entity-key internal error for structural index removal.
1050    pub(crate) fn structural_index_removal_entity_key_required() -> Self {
1051        Self::index_internal()
1052    }
1053
1054    /// Construct the canonical missing new entity-key internal error for structural index insertion.
1055    pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
1056        Self::index_internal()
1057    }
1058
1059    /// Construct the canonical missing old entity-key internal error for index commit-op removal.
1060    pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
1061        Self::index_internal()
1062    }
1063
1064    /// Construct the canonical missing new entity-key internal error for index commit-op insertion.
1065    pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
1066        Self::index_internal()
1067    }
1068
1069    /// Construct a query-origin internal error.
1070    #[cfg(test)]
1071    pub(crate) fn query_internal() -> Self {
1072        Self::new(ErrorClass::Internal, ErrorOrigin::Query)
1073    }
1074
1075    /// Construct a query-origin unsupported error.
1076    #[cold]
1077    #[inline(never)]
1078    pub(crate) fn query_unsupported() -> Self {
1079        Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
1080    }
1081
1082    /// Construct a query-origin conflict for execution against a superseded
1083    /// accepted schema revision.
1084    #[cold]
1085    #[inline(never)]
1086    pub(crate) fn query_stale_accepted_schema_revision(
1087        expected_revision: u64,
1088        current_revision: Option<u64>,
1089    ) -> Self {
1090        let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
1091        facts.push((
1092            diagnostic_code::DiagnosticFactTag::ExpectedRevision,
1093            expected_revision,
1094        ));
1095        if let Some(current_revision) = current_revision {
1096            facts.push((
1097                diagnostic_code::DiagnosticFactTag::CurrentRevision,
1098                current_revision,
1099            ));
1100        }
1101        Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
1102    }
1103
1104    /// Construct a query-origin SQL DDL admission error with structured detail.
1105    #[cold]
1106    #[inline(never)]
1107    #[cfg(feature = "sql")]
1108    pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
1109        Self {
1110            class: ErrorClass::Unsupported,
1111            origin: ErrorOrigin::Query,
1112            detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
1113                error,
1114            })),
1115        }
1116    }
1117
1118    /// Construct a query-origin numeric overflow error with structured detail.
1119    #[cold]
1120    #[inline(never)]
1121    pub(crate) fn query_numeric_overflow() -> Self {
1122        Self {
1123            class: ErrorClass::Unsupported,
1124            origin: ErrorOrigin::Query,
1125            detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
1126        }
1127    }
1128
1129    /// Construct a query-origin non-representable numeric result error with
1130    /// structured detail.
1131    #[cold]
1132    #[inline(never)]
1133    pub(crate) fn query_numeric_not_representable() -> Self {
1134        Self {
1135            class: ErrorClass::Unsupported,
1136            origin: ErrorOrigin::Query,
1137            detail: Some(ErrorDetail::Query(
1138                QueryErrorDetail::NumericNotRepresentable,
1139            )),
1140        }
1141    }
1142
1143    /// Construct a serialize-origin internal error.
1144    #[cold]
1145    #[inline(never)]
1146    pub(crate) fn serialize_internal() -> Self {
1147        Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
1148    }
1149
1150    /// Construct the canonical persisted-row encode internal error.
1151    pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
1152        Self::persisted_row_encode_internal()
1153    }
1154
1155    /// Construct the compact persisted-row encode internal error.
1156    pub(crate) fn persisted_row_encode_internal() -> Self {
1157        Self::serialize_internal()
1158    }
1159
1160    /// Construct the compact persisted-row field encode internal error.
1161    pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
1162        Self::persisted_row_encode_internal()
1163    }
1164
1165    /// Construct a store-origin corruption error.
1166    #[cold]
1167    #[inline(never)]
1168    pub(crate) fn store_corruption() -> Self {
1169        Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
1170    }
1171
1172    /// Construct a store-origin commit-marker corruption error.
1173    pub(crate) fn commit_corruption() -> Self {
1174        Self::store_corruption()
1175    }
1176
1177    /// Construct a store-origin commit-marker component corruption error.
1178    pub(crate) fn commit_component_corruption() -> Self {
1179        Self::commit_corruption()
1180    }
1181
1182    /// Construct the canonical commit-marker id generation internal error.
1183    pub(crate) fn commit_id_generation_failed() -> Self {
1184        Self::store_internal()
1185    }
1186
1187    /// Construct the canonical commit-marker payload u32-length-limit error.
1188    pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
1189        Self::store_unsupported()
1190    }
1191
1192    /// Construct the canonical commit-marker component invalid-length corruption error.
1193    pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
1194        Self::with_diagnostic_facts(
1195            ErrorClass::Corruption,
1196            ErrorOrigin::Store,
1197            None,
1198            vec![
1199                (
1200                    diagnostic_code::DiagnosticFactTag::ComponentKind,
1201                    diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
1202                ),
1203                (
1204                    diagnostic_code::DiagnosticFactTag::ActualLength,
1205                    actual_length as u64,
1206                ),
1207                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1208            ],
1209        )
1210    }
1211
1212    /// Construct the canonical commit-marker max-size corruption error.
1213    pub(crate) fn commit_marker_exceeds_max_size() -> Self {
1214        Self::commit_corruption()
1215    }
1216
1217    /// Construct the canonical commit-control slot max-size unsupported error.
1218    pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
1219        Self::store_unsupported()
1220    }
1221
1222    /// Construct the canonical commit-control marker-bytes length-limit error.
1223    pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
1224        Self::store_unsupported()
1225    }
1226
1227    /// Construct an index-origin corruption error.
1228    #[cold]
1229    #[inline(never)]
1230    pub(crate) fn index_corruption() -> Self {
1231        Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
1232    }
1233
1234    /// Construct the canonical unique-validation corruption wrapper.
1235    pub(crate) fn index_unique_validation_corruption() -> Self {
1236        Self::index_plan_index_corruption()
1237    }
1238
1239    /// Construct the canonical structural index-entry corruption wrapper.
1240    pub(crate) fn structural_index_entry_corruption() -> Self {
1241        Self::index_plan_index_corruption()
1242    }
1243
1244    /// Construct the canonical missing new entity-key invariant during unique validation.
1245    pub(crate) fn index_unique_validation_entity_key_required() -> Self {
1246        Self::index_invariant()
1247    }
1248
1249    /// Construct the canonical unique-validation structural row-decode corruption error.
1250    pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
1251        Self::index_plan_serialize_corruption()
1252    }
1253
1254    /// Construct the canonical unique-validation primary-key slot decode corruption error.
1255    pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
1256        Self::index_plan_serialize_corruption()
1257    }
1258
1259    /// Construct the canonical unique-validation stored key rebuild corruption error.
1260    pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
1261        Self::index_plan_serialize_corruption()
1262    }
1263
1264    /// Construct the canonical unique-validation missing-row corruption error.
1265    pub(crate) fn index_unique_validation_row_required() -> Self {
1266        Self::index_plan_store_corruption()
1267    }
1268
1269    /// Construct the canonical index-only predicate missing-component invariant.
1270    pub(crate) fn index_only_predicate_component_required() -> Self {
1271        Self::index_invariant()
1272    }
1273
1274    /// Construct the canonical index-scan continuation-envelope invariant.
1275    pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
1276        Self::index_invariant()
1277    }
1278
1279    /// Construct the canonical index-scan continuation-advancement invariant.
1280    pub(crate) fn index_scan_continuation_advancement_required() -> Self {
1281        Self::index_invariant()
1282    }
1283
1284    /// Construct the canonical index-scan key-decode corruption error.
1285    pub(crate) fn index_scan_key_corrupted_during(
1286        _context: &'static str,
1287        _err: impl Sized,
1288    ) -> Self {
1289        Self::index_corruption()
1290    }
1291
1292    /// Construct the canonical index-scan missing projection-component invariant.
1293    pub(crate) fn index_projection_component_required(
1294        _index_name: &str,
1295        _component_index: usize,
1296    ) -> Self {
1297        Self::index_invariant()
1298    }
1299
1300    /// Construct the canonical scan-time index-entry decode corruption error.
1301    pub(crate) fn index_entry_decode_failed() -> Self {
1302        Self::index_corruption()
1303    }
1304
1305    /// Construct a serialize-origin corruption error.
1306    pub(crate) fn serialize_corruption() -> Self {
1307        Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
1308    }
1309
1310    /// Construct the compact persisted-row decode corruption error.
1311    pub(crate) fn persisted_row_decode_corruption() -> Self {
1312        Self::serialize_corruption()
1313    }
1314
1315    /// Construct a persisted-row layout-window corruption error.
1316    pub(crate) fn persisted_row_layout_outside_accepted_window(
1317        row_layout: u32,
1318        history_floor: u32,
1319        current_layout: u32,
1320    ) -> Self {
1321        Self::with_diagnostic_facts(
1322            ErrorClass::Corruption,
1323            ErrorOrigin::Serialize,
1324            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1325                boundary:
1326                    diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
1327            }),
1328            vec![
1329                (
1330                    diagnostic_code::DiagnosticFactTag::RowLayout,
1331                    u64::from(row_layout),
1332                ),
1333                (
1334                    diagnostic_code::DiagnosticFactTag::HistoryFloor,
1335                    u64::from(history_floor),
1336                ),
1337                (
1338                    diagnostic_code::DiagnosticFactTag::CurrentLayout,
1339                    u64::from(current_layout),
1340                ),
1341            ],
1342        )
1343    }
1344
1345    /// Construct a persisted-row stamped-layout slot-count corruption error.
1346    pub(crate) fn persisted_row_slot_count_mismatch(
1347        row_layout: u32,
1348        expected_slot_count: usize,
1349        actual_slot_count: usize,
1350    ) -> Self {
1351        Self::with_diagnostic_facts(
1352            ErrorClass::Corruption,
1353            ErrorOrigin::Serialize,
1354            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1355                boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
1356            }),
1357            vec![
1358                (
1359                    diagnostic_code::DiagnosticFactTag::RowLayout,
1360                    u64::from(row_layout),
1361                ),
1362                (
1363                    diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
1364                    expected_slot_count as u64,
1365                ),
1366                (
1367                    diagnostic_code::DiagnosticFactTag::ActualSlotCount,
1368                    actual_slot_count as u64,
1369                ),
1370            ],
1371        )
1372    }
1373
1374    /// Construct the canonical persisted-row field decode corruption error.
1375    pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
1376        Self::persisted_row_field_decode_corruption(field_name)
1377    }
1378
1379    /// Construct the compact persisted-row field decode corruption error.
1380    pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
1381        Self::persisted_row_decode_corruption()
1382    }
1383
1384    /// Construct the canonical persisted-row field-kind decode corruption error.
1385    pub(crate) fn persisted_row_field_kind_decode_failed(
1386        field_name: &str,
1387        _field_kind: impl fmt::Debug,
1388        _detail: impl Sized,
1389    ) -> Self {
1390        Self::persisted_row_field_decode_corruption(field_name)
1391    }
1392
1393    /// Construct the canonical persisted-row scalar-payload length corruption error.
1394    pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
1395        Self::persisted_row_field_decode_corruption(field_name)
1396    }
1397
1398    /// Construct the canonical persisted-row scalar-payload empty-body corruption error.
1399    pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
1400        Self::persisted_row_field_decode_corruption(field_name)
1401    }
1402
1403    /// Construct the canonical persisted-row scalar-payload invalid-byte corruption error.
1404    pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
1405        Self::persisted_row_field_decode_corruption(field_name)
1406    }
1407
1408    /// Construct the canonical persisted-row scalar-payload non-finite corruption error.
1409    pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
1410        Self::persisted_row_field_decode_corruption(field_name)
1411    }
1412
1413    /// Construct the canonical persisted-row invalid text payload corruption error.
1414    pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
1415        Self::persisted_row_field_decode_corruption(field_name)
1416    }
1417
1418    /// Construct the canonical persisted-row structural slot-lookup invariant.
1419    pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
1420        Self::index_invariant()
1421    }
1422
1423    /// Construct the canonical persisted-row structural slot-cache invariant.
1424    pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
1425        _model_path: &str,
1426        _slot: usize,
1427    ) -> Self {
1428        Self::index_invariant()
1429    }
1430
1431    /// Construct the canonical persisted-row primary-key decode corruption error.
1432    pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1433        _data_key: impl fmt::Debug,
1434        _detail: impl Sized,
1435    ) -> Self {
1436        Self::persisted_row_decode_corruption()
1437    }
1438
1439    /// Construct the canonical persisted-row missing primary-key slot corruption error.
1440    pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1441        Self::persisted_row_decode_corruption()
1442    }
1443
1444    /// Construct the canonical persisted-row key mismatch corruption error.
1445    pub(crate) fn persisted_row_key_mismatch() -> Self {
1446        Self::store_corruption()
1447    }
1448
1449    /// Construct the canonical persisted-row missing declared-field corruption error.
1450    pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1451        Self::persisted_row_field_decode_corruption(field_name)
1452    }
1453
1454    /// Construct the canonical reverse-index ordinal overflow internal error.
1455    pub(crate) fn reverse_index_ordinal_overflow(
1456        _source_path: &str,
1457        _field_name: &str,
1458        _target_path: &str,
1459        _detail: impl Sized,
1460    ) -> Self {
1461        Self::index_internal()
1462    }
1463
1464    /// Construct the canonical reverse-index entry corruption error.
1465    pub(crate) fn reverse_index_entry_corrupted(
1466        _source_path: &str,
1467        _field_name: &str,
1468        _target_path: &str,
1469        _index_key: impl fmt::Debug,
1470        _detail: impl Sized,
1471    ) -> Self {
1472        Self::index_corruption()
1473    }
1474
1475    /// Construct the canonical relation-target store missing internal error.
1476    pub(crate) fn relation_target_store_missing(
1477        _source_path: &str,
1478        _field_name: &str,
1479        _target_path: &str,
1480        _store_path: &str,
1481        _detail: impl Sized,
1482    ) -> Self {
1483        Self::executor_internal()
1484    }
1485
1486    /// Construct one accepted relation target primary-key arity mismatch.
1487    pub(crate) fn relation_target_primary_key_arity_mismatch(
1488        expected_arity: usize,
1489        actual_arity: usize,
1490    ) -> Self {
1491        Self::with_diagnostic_facts(
1492            ErrorClass::Internal,
1493            ErrorOrigin::Executor,
1494            None,
1495            vec![
1496                (
1497                    diagnostic_code::DiagnosticFactTag::ComponentKind,
1498                    diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
1499                ),
1500                (
1501                    diagnostic_code::DiagnosticFactTag::ExpectedArity,
1502                    expected_arity as u64,
1503                ),
1504                (
1505                    diagnostic_code::DiagnosticFactTag::ActualArity,
1506                    actual_arity as u64,
1507                ),
1508            ],
1509        )
1510    }
1511
1512    /// Construct the canonical relation-target key decode corruption error.
1513    pub(crate) fn relation_target_key_decode_failed(
1514        _context_label: &str,
1515        _source_path: &str,
1516        _field_name: &str,
1517        _target_path: &str,
1518        _detail: impl Sized,
1519    ) -> Self {
1520        Self::identity_corruption()
1521    }
1522
1523    /// Construct the canonical relation-target entity mismatch corruption error.
1524    pub(crate) fn relation_target_entity_mismatch(
1525        _context_label: &str,
1526        _source_path: &str,
1527        _field_name: &str,
1528        _target_path: &str,
1529        _target_entity_name: &str,
1530        expected_tag: u64,
1531        actual_tag: u64,
1532    ) -> Self {
1533        Self::with_diagnostic_facts(
1534            ErrorClass::Corruption,
1535            ErrorOrigin::Store,
1536            None,
1537            vec![
1538                (
1539                    diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
1540                    expected_tag,
1541                ),
1542                (
1543                    diagnostic_code::DiagnosticFactTag::ActualEntityTag,
1544                    actual_tag,
1545                ),
1546            ],
1547        )
1548    }
1549
1550    /// Construct the canonical relation-source row decode corruption error.
1551    pub(crate) fn relation_source_row_decode_failed(
1552        _source_path: &str,
1553        _field_name: &str,
1554        _target_path: &str,
1555        _detail: impl Sized,
1556    ) -> Self {
1557        Self::persisted_row_decode_corruption()
1558    }
1559
1560    /// Construct the canonical relation-source unsupported scalar relation-key corruption error.
1561    pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1562        _source_path: &str,
1563        _field_name: &str,
1564        _target_path: &str,
1565    ) -> Self {
1566        Self::persisted_row_decode_corruption()
1567    }
1568
1569    /// Construct the canonical unsupported relation key-kind corruption error.
1570    pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1571        Self::persisted_row_decode_corruption()
1572    }
1573
1574    /// Construct the canonical covering-component empty-payload corruption error.
1575    pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1576        Self::index_corruption()
1577    }
1578
1579    /// Construct the canonical covering-component truncated bool corruption error.
1580    pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1581        Self::index_corruption()
1582    }
1583
1584    /// Construct the canonical covering-component invalid-length corruption error.
1585    pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1586        Self::index_corruption()
1587    }
1588
1589    /// Construct the canonical covering-component invalid-bool corruption error.
1590    pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1591        Self::index_corruption()
1592    }
1593
1594    /// Construct the canonical covering-component invalid text terminator corruption error.
1595    pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1596        Self::index_corruption()
1597    }
1598
1599    /// Construct the canonical covering-component trailing-text corruption error.
1600    pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1601        Self::index_corruption()
1602    }
1603
1604    /// Construct the canonical covering-component invalid-UTF-8 text corruption error.
1605    pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1606        Self::index_corruption()
1607    }
1608
1609    /// Construct the canonical covering-component invalid text escape corruption error.
1610    pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1611        Self::index_corruption()
1612    }
1613
1614    /// Construct the canonical covering-component missing text terminator corruption error.
1615    pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1616        Self::index_corruption()
1617    }
1618
1619    /// Construct an identity-origin corruption error.
1620    pub(crate) fn identity_corruption() -> Self {
1621        Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1622    }
1623
1624    /// Construct the canonical identity-control-state corruption error.
1625    pub(crate) fn identity_state_corruption() -> Self {
1626        Self::identity_corruption()
1627    }
1628
1629    /// Construct the typed stale high-water conflict for identity publication.
1630    pub(crate) fn identity_state_conflict() -> Self {
1631        Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1632    }
1633
1634    /// Construct the bounded identity-state inventory exhaustion error.
1635    pub(crate) fn identity_state_capacity_exhausted() -> Self {
1636        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1637    }
1638
1639    /// Construct the exact unsigned identity-domain exhaustion error.
1640    pub(crate) fn identity_exhausted() -> Self {
1641        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1642    }
1643
1644    /// Construct the bounded pre-key candidate-count exhaustion error.
1645    pub(crate) fn identity_candidate_count_exhausted() -> Self {
1646        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1647    }
1648
1649    /// Construct a store-origin unsupported error.
1650    #[cold]
1651    #[inline(never)]
1652    pub(crate) fn store_unsupported() -> Self {
1653        Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1654    }
1655
1656    /// Construct the typed optimistic/idempotency conflict for schema application.
1657    pub(crate) fn schema_application_conflict() -> Self {
1658        Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1659    }
1660
1661    /// Construct one typed source-migration lifecycle or planning result.
1662    pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1663        let class = match reason.diagnostic_code() {
1664            diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1665            diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1666            diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1667            _ => ErrorClass::Internal,
1668        };
1669        Self {
1670            class,
1671            origin: ErrorOrigin::Store,
1672            detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1673        }
1674    }
1675
1676    /// Construct the canonical schema DDL publication race error.
1677    pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1678        Self {
1679            class: ErrorClass::Unsupported,
1680            origin: ErrorOrigin::Store,
1681            detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1682        }
1683    }
1684
1685    /// Construct the canonical current physical-rewrite migration rejection.
1686    #[cfg(feature = "sql")]
1687    pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1688        Self {
1689            class: ErrorClass::Unsupported,
1690            origin: ErrorOrigin::Store,
1691            detail: Some(ErrorDetail::Store(
1692                StoreError::SchemaDdlRewriteRequiresMigration,
1693            )),
1694        }
1695    }
1696
1697    /// Construct the fail-closed journal mutation-revision exhaustion error.
1698    pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1699        Self {
1700            class: ErrorClass::Unsupported,
1701            origin: ErrorOrigin::Store,
1702            detail: Some(ErrorDetail::Store(
1703                StoreError::JournalMutationRevisionExhausted,
1704            )),
1705        }
1706    }
1707
1708    /// Construct a bounded schema-transition resource rejection.
1709    pub(crate) fn schema_transition_budget_exceeded(
1710        resource: SchemaTransitionBudgetResource,
1711    ) -> Self {
1712        Self {
1713            class: ErrorClass::Unsupported,
1714            origin: ErrorOrigin::Store,
1715            detail: Some(ErrorDetail::Store(
1716                StoreError::SchemaTransitionBudgetExceeded { resource },
1717            )),
1718        }
1719    }
1720
1721    /// Construct the canonical unsupported persisted entity-tag store error.
1722    pub(crate) fn unsupported_entity_tag_in_data_store(
1723        _entity_tag: crate::types::EntityTag,
1724    ) -> Self {
1725        Self::store_unsupported()
1726    }
1727
1728    /// Construct the canonical commit-memory id registration failure.
1729    #[cfg(not(test))]
1730    pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1731        Self::store_internal()
1732    }
1733
1734    /// Construct an index-origin unsupported error.
1735    pub(crate) fn index_unsupported() -> Self {
1736        Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1737    }
1738
1739    /// Construct the canonical index-key component size-limit unsupported error.
1740    pub(crate) fn index_component_exceeds_max_size_at(
1741        entity_tag: u64,
1742        physical_generation: u64,
1743        component_index: usize,
1744        actual_length: usize,
1745        limit: usize,
1746    ) -> Self {
1747        Self::with_diagnostic_facts(
1748            ErrorClass::Unsupported,
1749            ErrorOrigin::Index,
1750            None,
1751            vec![
1752                (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1753                (
1754                    diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1755                    physical_generation,
1756                ),
1757                (
1758                    diagnostic_code::DiagnosticFactTag::ComponentIndex,
1759                    component_index as u64,
1760                ),
1761                (
1762                    diagnostic_code::DiagnosticFactTag::ComponentKind,
1763                    diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
1764                ),
1765                (
1766                    diagnostic_code::DiagnosticFactTag::ActualLength,
1767                    actual_length as u64,
1768                ),
1769                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1770            ],
1771        )
1772    }
1773
1774    /// Construct the canonical index-key component size-limit error when the
1775    /// generic caller has not retained one accepted index identity.
1776    pub(crate) fn index_component_exceeds_max_size() -> Self {
1777        Self::index_unsupported()
1778    }
1779
1780    /// Construct a serialize-origin unsupported error.
1781    pub(crate) fn serialize_unsupported() -> Self {
1782        Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1783    }
1784
1785    /// Construct a cursor-origin invalid-continuation error.
1786    pub(crate) fn cursor_invalid_continuation() -> Self {
1787        Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1788    }
1789
1790    /// Construct a serialize-origin incompatible persisted-format error.
1791    pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1792        Self::new(
1793            ErrorClass::IncompatiblePersistedFormat,
1794            ErrorOrigin::Serialize,
1795        )
1796    }
1797
1798    /// Construct a query-origin unsupported error preserving one SQL parser
1799    /// unsupported-feature code in structured error detail.
1800    #[cfg(feature = "sql")]
1801    pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1802        Self {
1803            class: ErrorClass::Unsupported,
1804            origin: ErrorOrigin::Query,
1805            detail: Some(ErrorDetail::Query(
1806                QueryErrorDetail::UnsupportedSqlFeature { feature },
1807            )),
1808        }
1809    }
1810
1811    /// Construct a query-origin unsupported SQL lowering error preserving one
1812    /// compact lowering reason in structured error detail.
1813    #[cfg(feature = "sql")]
1814    pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1815        Self {
1816            class: ErrorClass::Unsupported,
1817            origin: ErrorOrigin::Query,
1818            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1819        }
1820    }
1821
1822    /// Construct one query-origin SQL lowering error with bounded numeric context.
1823    #[cfg(feature = "sql")]
1824    pub(crate) fn query_sql_lowering_with_facts(
1825        reason: diagnostic_code::SqlLoweringCode,
1826        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1827    ) -> Self {
1828        Self::with_diagnostic_facts(
1829            ErrorClass::Unsupported,
1830            ErrorOrigin::Query,
1831            Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
1832            facts,
1833        )
1834    }
1835
1836    /// Construct a query-origin unsupported projection error preserving one
1837    /// compact projection reason in structured error detail.
1838    pub(crate) fn query_unsupported_projection(
1839        reason: diagnostic_code::QueryProjectionCode,
1840    ) -> Self {
1841        Self {
1842            class: ErrorClass::Unsupported,
1843            origin: ErrorOrigin::Query,
1844            detail: Some(ErrorDetail::Query(
1845                QueryErrorDetail::UnsupportedProjection { reason },
1846            )),
1847        }
1848    }
1849
1850    /// Construct a query-origin unsupported aggregate target-field error.
1851    pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1852        Self {
1853            class: ErrorClass::Unsupported,
1854            origin: ErrorOrigin::Query,
1855            detail: Some(ErrorDetail::Query(
1856                QueryErrorDetail::UnknownAggregateTargetField,
1857            )),
1858        }
1859    }
1860
1861    /// Construct a query-origin unsupported error preserving one SQL endpoint
1862    /// surface mismatch in structured error detail.
1863    #[cfg(feature = "sql")]
1864    pub(crate) fn query_sql_surface_mismatch(
1865        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1866    ) -> Self {
1867        Self {
1868            class: ErrorClass::Unsupported,
1869            origin: ErrorOrigin::Query,
1870            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1871                mismatch,
1872            })),
1873        }
1874    }
1875
1876    /// Construct a query-origin unsupported SQL write boundary error.
1877    pub(crate) fn query_sql_write_boundary(
1878        boundary: diagnostic_code::SqlWriteBoundaryCode,
1879    ) -> Self {
1880        Self {
1881            class: ErrorClass::Unsupported,
1882            origin: ErrorOrigin::Query,
1883            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1884                boundary,
1885            })),
1886        }
1887    }
1888
1889    /// Construct one query-origin SQL write-boundary error with bounded numeric context.
1890    pub(crate) fn query_sql_write_boundary_with_facts(
1891        boundary: diagnostic_code::SqlWriteBoundaryCode,
1892        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1893    ) -> Self {
1894        Self::with_diagnostic_facts(
1895            ErrorClass::Unsupported,
1896            ErrorOrigin::Query,
1897            Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
1898            facts,
1899        )
1900    }
1901
1902    pub fn store_not_found(_key: impl Sized) -> Self {
1903        Self {
1904            class: ErrorClass::NotFound,
1905            origin: ErrorOrigin::Store,
1906            detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1907        }
1908    }
1909
1910    /// Construct a standardized unsupported-entity-path error.
1911    pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1912        Self::store_unsupported()
1913    }
1914
1915    /// Construct an index-plan corruption error with a canonical prefix.
1916    #[cold]
1917    #[inline(never)]
1918    pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1919        Self::new(ErrorClass::Corruption, origin)
1920    }
1921
1922    /// Construct an index-plan corruption error for index-origin failures.
1923    #[cold]
1924    #[inline(never)]
1925    pub(crate) fn index_plan_index_corruption() -> Self {
1926        Self::index_plan_corruption(ErrorOrigin::Index)
1927    }
1928
1929    /// Construct an index-plan corruption error for store-origin failures.
1930    #[cold]
1931    #[inline(never)]
1932    pub(crate) fn index_plan_store_corruption() -> Self {
1933        Self::index_plan_corruption(ErrorOrigin::Store)
1934    }
1935
1936    /// Construct an index-plan corruption error for serialize-origin failures.
1937    #[cold]
1938    #[inline(never)]
1939    pub(crate) fn index_plan_serialize_corruption() -> Self {
1940        Self::index_plan_corruption(ErrorOrigin::Serialize)
1941    }
1942
1943    /// Construct an index-plan invariant violation error with a canonical prefix.
1944    #[cfg(test)]
1945    pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1946        Self::new(ErrorClass::InvariantViolation, origin)
1947    }
1948
1949    /// Construct an index-plan invariant violation error for store-origin failures.
1950    #[cfg(test)]
1951    pub(crate) fn index_plan_store_invariant() -> Self {
1952        Self::index_plan_invariant(ErrorOrigin::Store)
1953    }
1954
1955    /// Construct an index-origin conflict without claiming accepted identity.
1956    ///
1957    /// Live accepted uniqueness violations use compact accepted-constraint facts.
1958    /// Schema-domain staging and activation findings use this compact
1959    /// classification before an accepted write-admission diagnostic exists.
1960    pub(crate) fn index_conflict() -> Self {
1961        Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1962    }
1963}
1964
1965impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1966    fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1967        Self {
1968            class: ErrorClass::Unsupported,
1969            origin: ErrorOrigin::Query,
1970            detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1971                reason,
1972            })),
1973        }
1974    }
1975}
1976
1977impl fmt::Debug for InternalError {
1978    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1979        fmt_compact_diagnostic(
1980            f,
1981            self.diagnostic_code(),
1982            self.detail
1983                .as_ref()
1984                .and_then(ErrorDetail::diagnostic_detail),
1985        )
1986    }
1987}
1988
1989impl fmt::Display for InternalError {
1990    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1991        f.write_str(self.message())
1992    }
1993}
1994
1995impl std::error::Error for InternalError {}
1996
1997///
1998/// ConstraintValuePathComponent
1999///
2000/// Stable accepted identity or finite-value coordinate in one targeted-rule
2001/// violation. Display names are deliberately absent so renames cannot change
2002/// the diagnostic identity.
2003///
2004
2005#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
2006pub enum ConstraintValuePathComponent {
2007    /// Persisted root field whose admitted value was traversed.
2008    RootField { field_id: u32 },
2009
2010    /// Accepted record member selected by immutable composite/member identity.
2011    RecordMember {
2012        composite_type_id: u32,
2013        member_id: u32,
2014    },
2015
2016    /// Tuple element selected by accepted composite identity and ordinal.
2017    TupleElement {
2018        composite_type_id: u32,
2019        ordinal: u32,
2020    },
2021
2022    /// Transparent accepted newtype boundary.
2023    Newtype { composite_type_id: u32 },
2024
2025    /// Selected accepted enum variant.
2026    EnumVariant { enum_type_id: u32, variant_id: u32 },
2027
2028    /// List element in admitted order.
2029    ListElement { index: u32 },
2030
2031    /// Set element in canonical admitted order.
2032    SetElement { index: u32 },
2033
2034    /// Map key in canonical entry order.
2035    MapEntryKey { index: u32 },
2036
2037    /// Map value in canonical entry order.
2038    MapEntryValue { index: u32 },
2039}
2040
2041impl fmt::Display for ConstraintValuePathComponent {
2042    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2043        match self {
2044            Self::RootField { field_id } => write!(f, "field#{field_id}"),
2045            Self::RecordMember {
2046                composite_type_id,
2047                member_id,
2048            } => write!(f, "record#{composite_type_id}.member#{member_id}"),
2049            Self::TupleElement {
2050                composite_type_id,
2051                ordinal,
2052            } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
2053            Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
2054            Self::EnumVariant {
2055                enum_type_id,
2056                variant_id,
2057            } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
2058            Self::ListElement { index } => write!(f, "list[{index}]"),
2059            Self::SetElement { index } => write!(f, "set[{index}]"),
2060            Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
2061            Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
2062        }
2063    }
2064}
2065
2066///
2067/// ConstraintValuePath
2068///
2069/// Bounded typed path to the first deterministic failing value occurrence.
2070///
2071
2072#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2073pub struct ConstraintValuePath {
2074    components: Vec<ConstraintValuePathComponent>,
2075}
2076
2077impl ConstraintValuePath {
2078    /// Build one already-bounded accepted occurrence path.
2079    #[must_use]
2080    pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
2081        Self { components }
2082    }
2083
2084    /// Borrow the stable accepted components.
2085    #[must_use]
2086    pub const fn components(&self) -> &[ConstraintValuePathComponent] {
2087        self.components.as_slice()
2088    }
2089}
2090
2091impl fmt::Display for ConstraintValuePath {
2092    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2093        for (ordinal, component) in self.components.iter().enumerate() {
2094            if ordinal != 0 {
2095                f.write_str("/")?;
2096            }
2097            component.fmt(f)?;
2098        }
2099        Ok(())
2100    }
2101}
2102
2103///
2104/// ConstraintValidationFindingOutput
2105///
2106/// Bounded historical validation evidence returned only by explicit schema
2107/// validation operations. Names are resolved by host tooling from the exact
2108/// accepted fingerprint and immutable numeric identities.
2109///
2110
2111#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2112pub struct ConstraintValidationFindingOutput {
2113    accepted_schema_fingerprint: [u8; 16],
2114    entity_tag: u64,
2115    constraint_id: u32,
2116    primary_key: Vec<u8>,
2117    field_ids: Vec<u32>,
2118    value_path: Option<ConstraintValuePath>,
2119    error_code: u16,
2120}
2121
2122impl ConstraintValidationFindingOutput {
2123    /// Build one already-bounded historical validation finding.
2124    #[must_use]
2125    pub(crate) const fn new(
2126        accepted_schema_fingerprint: [u8; 16],
2127        entity_tag: u64,
2128        constraint_id: u32,
2129        primary_key: Vec<u8>,
2130        field_ids: Vec<u32>,
2131        value_path: Option<ConstraintValuePath>,
2132        error_code: u16,
2133    ) -> Self {
2134        Self {
2135            accepted_schema_fingerprint,
2136            entity_tag,
2137            constraint_id,
2138            primary_key,
2139            field_ids,
2140            value_path,
2141            error_code,
2142        }
2143    }
2144
2145    /// Return the exact accepted-schema fingerprint that binds every numeric identity.
2146    #[must_use]
2147    pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
2148        self.accepted_schema_fingerprint
2149    }
2150
2151    /// Return the stable accepted entity identity.
2152    #[must_use]
2153    pub const fn entity_tag(&self) -> u64 {
2154        self.entity_tag
2155    }
2156
2157    /// Return the stable accepted constraint identity.
2158    #[must_use]
2159    pub const fn constraint_id(&self) -> u32 {
2160        self.constraint_id
2161    }
2162
2163    /// Borrow the bounded canonical persisted primary-key locator.
2164    #[must_use]
2165    pub const fn primary_key(&self) -> &[u8] {
2166        self.primary_key.as_slice()
2167    }
2168
2169    /// Borrow immutable accepted field identities implicated by the finding.
2170    #[must_use]
2171    pub const fn field_ids(&self) -> &[u32] {
2172        self.field_ids.as_slice()
2173    }
2174
2175    /// Borrow the typed concrete value path for a targeted-rule violation.
2176    #[must_use]
2177    pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2178        self.value_path.as_ref()
2179    }
2180
2181    /// Return the compact stable error code for this exact failure.
2182    #[must_use]
2183    pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2184        diagnostic_code::ErrorCode::from_raw(self.error_code)
2185    }
2186
2187    /// Return the broad public error class derived from the compact code.
2188    #[must_use]
2189    pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2190        self.error_code().class()
2191    }
2192}
2193
2194/// Complete bounded numeric authority needed to publish E223 or E225 facts.
2195#[derive(Clone)]
2196pub(crate) struct AcceptedConstraintFactContext {
2197    fingerprint_method: u8,
2198    accepted_schema_fingerprint: [u8; 16],
2199    entity_tag: u64,
2200    constraint_id: u32,
2201    constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2202    mutation: Option<MutationDiagnosticContext>,
2203    value_path: Option<ConstraintValuePath>,
2204}
2205
2206impl AcceptedConstraintFactContext {
2207    #[must_use]
2208    pub(crate) fn write_admission(
2209        fingerprint_method: u8,
2210        accepted_schema_fingerprint: [u8; 16],
2211        entity_tag: u64,
2212        constraint_id: u32,
2213        constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2214        mutation: Option<MutationDiagnosticContext>,
2215        value_path: Option<ConstraintValuePath>,
2216    ) -> Self {
2217        debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2218        Self {
2219            fingerprint_method,
2220            accepted_schema_fingerprint,
2221            entity_tag,
2222            constraint_id,
2223            constraint_kind,
2224            mutation,
2225            value_path,
2226        }
2227    }
2228
2229    fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2230        let high = u64::from_be_bytes([
2231            self.accepted_schema_fingerprint[0],
2232            self.accepted_schema_fingerprint[1],
2233            self.accepted_schema_fingerprint[2],
2234            self.accepted_schema_fingerprint[3],
2235            self.accepted_schema_fingerprint[4],
2236            self.accepted_schema_fingerprint[5],
2237            self.accepted_schema_fingerprint[6],
2238            self.accepted_schema_fingerprint[7],
2239        ]);
2240        let low = u64::from_be_bytes([
2241            self.accepted_schema_fingerprint[8],
2242            self.accepted_schema_fingerprint[9],
2243            self.accepted_schema_fingerprint[10],
2244            self.accepted_schema_fingerprint[11],
2245            self.accepted_schema_fingerprint[12],
2246            self.accepted_schema_fingerprint[13],
2247            self.accepted_schema_fingerprint[14],
2248            self.accepted_schema_fingerprint[15],
2249        ]);
2250        let path_len = self
2251            .value_path
2252            .as_ref()
2253            .map_or(0, |path| path.components().len());
2254        let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2255            1 + usize::from(mutation.batch_position.is_some())
2256        });
2257        let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2258        facts.push((
2259            diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2260            u64::from(self.fingerprint_method),
2261        ));
2262        facts.push((
2263            diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2264            high,
2265        ));
2266        facts.push((
2267            diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2268            low,
2269        ));
2270        facts.push((
2271            diagnostic_code::DiagnosticFactTag::EntityTag,
2272            self.entity_tag,
2273        ));
2274        facts.push((
2275            diagnostic_code::DiagnosticFactTag::ConstraintId,
2276            u64::from(self.constraint_id),
2277        ));
2278        facts.push((
2279            diagnostic_code::DiagnosticFactTag::ConstraintKind,
2280            self.constraint_kind.raw(),
2281        ));
2282        facts.push((
2283            diagnostic_code::DiagnosticFactTag::ConstraintContext,
2284            diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2285        ));
2286        if let Some(mutation) = self.mutation {
2287            mutation.append_operation_facts(&mut facts);
2288        }
2289        if let Some(path) = self.value_path {
2290            for component in path.components {
2291                facts.push(constraint_value_path_fact(component));
2292            }
2293        }
2294        debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2295        facts
2296    }
2297}
2298
2299fn constraint_value_path_fact(
2300    component: ConstraintValuePathComponent,
2301) -> (diagnostic_code::DiagnosticFactTag, u64) {
2302    use diagnostic_code::DiagnosticFactTag;
2303    match component {
2304        ConstraintValuePathComponent::RootField { field_id } => {
2305            (DiagnosticFactTag::RootField, u64::from(field_id))
2306        }
2307        ConstraintValuePathComponent::RecordMember {
2308            composite_type_id,
2309            member_id,
2310        } => (
2311            DiagnosticFactTag::RecordMember,
2312            diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2313        ),
2314        ConstraintValuePathComponent::TupleElement {
2315            composite_type_id,
2316            ordinal,
2317        } => (
2318            DiagnosticFactTag::TupleElement,
2319            diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2320        ),
2321        ConstraintValuePathComponent::Newtype { composite_type_id } => {
2322            (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2323        }
2324        ConstraintValuePathComponent::EnumVariant {
2325            enum_type_id,
2326            variant_id,
2327        } => (
2328            DiagnosticFactTag::EnumVariant,
2329            diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2330        ),
2331        ConstraintValuePathComponent::ListElement { index } => {
2332            (DiagnosticFactTag::ListElement, u64::from(index))
2333        }
2334        ConstraintValuePathComponent::SetElement { index } => {
2335            (DiagnosticFactTag::SetElement, u64::from(index))
2336        }
2337        ConstraintValuePathComponent::MapEntryKey { index } => {
2338            (DiagnosticFactTag::MapEntryKey, u64::from(index))
2339        }
2340        ConstraintValuePathComponent::MapEntryValue { index } => {
2341            (DiagnosticFactTag::MapEntryValue, u64::from(index))
2342        }
2343    }
2344}
2345
2346///
2347/// ErrorDetail
2348///
2349/// Structured, origin-specific error detail carried by [`InternalError`].
2350/// This enum is intentionally extensible.
2351///
2352
2353pub enum ErrorDetail {
2354    /// Compact code/detail plus safe numeric context for one public failure.
2355    DiagnosticFacts(Box<DiagnosticFactDetail>),
2356    /// Executor-owned mutation and query execution details.
2357    Executor(ExecutorErrorDetail),
2358    Store(StoreError),
2359    Query(QueryErrorDetail),
2360    Recovery(RecoveryErrorDetail),
2361    // Future-proofing:
2362    // Index(IndexError),
2363}
2364
2365/// Executor-specific structured error detail.
2366pub enum ExecutorErrorDetail {
2367    /// A complete insert or replacement omitted one or more required fields.
2368    MutationRequiredFieldMissing,
2369    /// A logical mutation would move accepted managed time backward.
2370    MutationManagedTimestampRegression,
2371    /// A caller explicitly authored a field owned by accepted database policy.
2372    MutationDatabaseOwnedFieldExplicit,
2373    /// A mixed structural mutation batch contained no operations.
2374    MutationBatchEmpty,
2375    /// A mixed structural mutation batch exceeded its operation-count bound.
2376    MutationBatchTooManyItems,
2377    /// A mixed structural mutation batch exceeded its staged-byte bound.
2378    MutationBatchStagedBytesExceeded,
2379    /// A mixed structural mutation result exceeded its encoded response bound.
2380    MutationBatchResultBytesExceeded,
2381    /// A mixed structural mutation batch resolved to more than one accepted entity.
2382    MutationBatchEntityMismatch,
2383    /// More than one mixed structural operation targeted the same accepted key.
2384    MutationBatchDuplicateKey,
2385    /// Accepted row-constraint metadata or compiled state was inconsistent.
2386    AcceptedRowConstraintProgramCorrupt,
2387}
2388
2389///
2390/// RecoveryErrorDetail
2391///
2392/// Recovery-origin structured error detail payload.
2393///
2394
2395pub enum RecoveryErrorDetail {
2396    UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2397
2398    MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2399}
2400
2401/// Store boot-marker corruption classification.
2402#[derive(Clone, Copy, Eq, PartialEq)]
2403pub enum RecoveryFormatMarkerError {
2404    Magic,
2405    Checksum,
2406    State,
2407}
2408
2409impl RecoveryFormatMarkerError {
2410    const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2411        match self {
2412            Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2413            Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2414            Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2415        }
2416    }
2417}
2418
2419///
2420/// StoreError
2421///
2422/// Store-specific structured error detail.
2423/// Never returned directly; always wrapped in [`ErrorDetail::Store`].
2424///
2425
2426pub enum StoreError {
2427    NotFound,
2428
2429    Corrupt,
2430
2431    InvariantViolation,
2432
2433    SchemaDdlPublicationRaceLost,
2434
2435    SchemaDdlRewriteRequiresMigration,
2436
2437    SchemaMigration {
2438        reason: diagnostic_code::SchemaMigrationCode,
2439    },
2440
2441    SchemaRowLayoutVersionExhausted,
2442
2443    JournalMutationRevisionExhausted,
2444
2445    SchemaTransitionBudgetExceeded {
2446        resource: SchemaTransitionBudgetResource,
2447    },
2448
2449    /// A generated field would collide with an accepted DDL-owned slot.
2450    SchemaGeneratedFieldAfterDdlField,
2451
2452    /// A live generated constraint activation no longer matches its proposal.
2453    SchemaGeneratedConstraintActivationStale,
2454}
2455
2456///
2457/// QueryErrorDetail
2458///
2459/// Query-origin structured error detail payload.
2460///
2461
2462pub enum QueryErrorDetail {
2463    NumericOverflow,
2464
2465    NumericNotRepresentable,
2466
2467    UnsupportedSqlFeature {
2468        feature: diagnostic_code::SqlFeatureCode,
2469    },
2470
2471    SqlLowering {
2472        reason: diagnostic_code::SqlLoweringCode,
2473    },
2474
2475    UnsupportedProjection {
2476        reason: diagnostic_code::QueryProjectionCode,
2477    },
2478
2479    UnknownAggregateTargetField,
2480
2481    ResultShapeMismatch {
2482        reason: diagnostic_code::QueryResultShapeCode,
2483    },
2484
2485    QueryReadAdmission {
2486        reason: diagnostic_code::QueryReadAdmissionCode,
2487    },
2488
2489    SqlSurfaceMismatch {
2490        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2491    },
2492
2493    SqlWriteBoundary {
2494        boundary: diagnostic_code::SqlWriteBoundaryCode,
2495    },
2496
2497    SchemaDdlAdmission {
2498        error: SchemaDdlAdmissionError,
2499    },
2500
2501    StaleSchemaRevision,
2502}
2503
2504impl fmt::Display for QueryErrorDetail {
2505    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2506        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2507    }
2508}
2509
2510impl std::error::Error for QueryErrorDetail {}
2511
2512///
2513/// SchemaTransitionBudgetResource
2514///
2515/// Query-visible identity of the exact schema-transition resource cap that
2516/// rejected a complete validation or derived-state stage.
2517///
2518
2519#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2520pub enum SchemaTransitionBudgetResource {
2521    /// Number of physical deletion keys retained for replacement.
2522    DeletionKeys,
2523    /// Number of row-derived projection entries retained for validation.
2524    ProjectionEntries,
2525    /// Deterministic projection and physical-classification work units.
2526    ProjectionWorkUnits,
2527    /// Number of authoritative source rows.
2528    SourceRows,
2529    /// Cumulative bytes of authoritative source rows.
2530    SourceRowBytes,
2531    /// Retained raw payloads plus deterministic-sort workspace bytes.
2532    StagedRawBytes,
2533}
2534
2535///
2536/// SchemaDdlAdmissionError
2537///
2538/// Stable query-visible SQL DDL admission reason. Human diagnostics may carry
2539/// extra version, fingerprint, and target facts beside this machine-readable
2540/// variant.
2541///
2542
2543#[derive(Clone, Copy, Eq, PartialEq)]
2544pub enum SchemaDdlAdmissionError {
2545    MissingExpectedSchemaVersion,
2546
2547    MissingNextSchemaVersion,
2548
2549    StaleExpectedSchemaVersion,
2550
2551    InvalidExpectedSchemaVersion,
2552
2553    InvalidNextSchemaVersion,
2554
2555    AcceptedSchemaChangeWithoutVersionBump,
2556
2557    EmptyVersionBump,
2558
2559    VersionGap,
2560
2561    VersionRollback,
2562
2563    FingerprintMethodMismatch,
2564
2565    UnsupportedTransitionClass,
2566
2567    PhysicalRunnerMissing,
2568
2569    ValidationFailed,
2570
2571    PublicationRaceLost,
2572
2573    InvalidAddColumnDefault,
2574
2575    InvalidAlterColumnDefault,
2576
2577    RowLayoutVersionExhausted,
2578
2579    GeneratedIndexDropRejected,
2580
2581    SchemaRewriteRequiresMigration,
2582
2583    SchemaTransitionBudgetExceeded {
2584        resource: SchemaTransitionBudgetResource,
2585    },
2586
2587    GeneratedFieldDefaultChangeRejected,
2588
2589    GeneratedFieldNullabilityChangeRejected,
2590}
2591
2592impl fmt::Display for SchemaDdlAdmissionError {
2593    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2594        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2595    }
2596}
2597
2598impl std::error::Error for SchemaDdlAdmissionError {}
2599
2600impl fmt::Debug for ErrorDetail {
2601    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2602        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2603    }
2604}
2605
2606impl fmt::Debug for ExecutorErrorDetail {
2607    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2608        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2609    }
2610}
2611
2612impl fmt::Debug for StoreError {
2613    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2614        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2615    }
2616}
2617
2618impl fmt::Debug for QueryErrorDetail {
2619    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2620        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2621    }
2622}
2623
2624impl fmt::Debug for RecoveryErrorDetail {
2625    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2626        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2627    }
2628}
2629
2630impl fmt::Debug for RecoveryFormatMarkerError {
2631    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2632        fmt_compact_diagnostic(
2633            f,
2634            diagnostic_code::DiagnosticCode::RuntimeCorruption,
2635            Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2636                kind: diagnostic_code::RuntimeErrorKind::Corruption,
2637            }),
2638        )
2639    }
2640}
2641
2642impl fmt::Debug for SchemaDdlAdmissionError {
2643    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2644        fmt_compact_diagnostic(
2645            f,
2646            diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2647            Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2648                reason: self.diagnostic_code(),
2649            }),
2650        )
2651    }
2652}
2653
2654fn fmt_compact_diagnostic(
2655    f: &mut fmt::Formatter<'_>,
2656    code: diagnostic_code::DiagnosticCode,
2657    detail: Option<diagnostic_code::DiagnosticDetail>,
2658) -> fmt::Result {
2659    write!(
2660        f,
2661        "{}",
2662        diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2663    )
2664}
2665
2666impl ErrorDetail {
2667    /// Return the compact diagnostic code for this structured detail.
2668    #[must_use]
2669    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2670        match self {
2671            Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2672            Self::Executor(error) => error.diagnostic_code(),
2673            Self::Store(error) => error.diagnostic_code(),
2674            Self::Query(error) => error.diagnostic_code(),
2675            Self::Recovery(error) => error.diagnostic_code(),
2676        }
2677    }
2678
2679    /// Return compact structured diagnostic detail when the payload carries one.
2680    #[must_use]
2681    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2682        match self {
2683            Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2684            Self::Executor(error) => error.diagnostic_detail(),
2685            Self::Store(error) => error.diagnostic_detail(),
2686            Self::Query(error) => error.diagnostic_detail(),
2687            Self::Recovery(error) => error.diagnostic_detail(),
2688        }
2689    }
2690
2691    /// Project safe typed detail into canonical public numeric facts.
2692    #[must_use]
2693    #[cold]
2694    #[inline(never)]
2695    pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2696        match self {
2697            Self::DiagnosticFacts(detail) => detail.facts.clone(),
2698            Self::Executor(error) => error.diagnostic_facts(),
2699            Self::Query(error) => error.diagnostic_facts(),
2700            Self::Recovery(error) => error.diagnostic_facts(),
2701            Self::Store(_) => Vec::new(),
2702        }
2703    }
2704}
2705
2706impl ExecutorErrorDetail {
2707    /// Return the compact diagnostic code for this executor detail.
2708    #[must_use]
2709    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2710        match self {
2711            Self::MutationRequiredFieldMissing
2712            | Self::MutationDatabaseOwnedFieldExplicit
2713            | Self::MutationBatchEmpty
2714            | Self::MutationBatchTooManyItems
2715            | Self::MutationBatchStagedBytesExceeded
2716            | Self::MutationBatchResultBytesExceeded => {
2717                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2718            }
2719            Self::MutationBatchEntityMismatch | Self::MutationBatchDuplicateKey => {
2720                diagnostic_code::DiagnosticCode::RuntimeConflict
2721            }
2722            Self::MutationManagedTimestampRegression => {
2723                diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2724            }
2725            Self::AcceptedRowConstraintProgramCorrupt => {
2726                diagnostic_code::DiagnosticCode::RuntimeCorruption
2727            }
2728        }
2729    }
2730
2731    /// Return compact structured diagnostic detail for this executor detail.
2732    #[must_use]
2733    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2734        match self {
2735            Self::MutationRequiredFieldMissing => {
2736                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2737                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2738                })
2739            }
2740            Self::MutationDatabaseOwnedFieldExplicit => {
2741                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2742                    boundary:
2743                        diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2744                })
2745            }
2746            Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2747                boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2748            }),
2749            Self::MutationBatchTooManyItems => {
2750                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2751                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2752                })
2753            }
2754            Self::MutationBatchStagedBytesExceeded => {
2755                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2756                    boundary:
2757                        diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2758                })
2759            }
2760            Self::MutationBatchResultBytesExceeded => {
2761                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2762                    boundary:
2763                        diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2764                })
2765            }
2766            Self::MutationBatchEntityMismatch => {
2767                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2768                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
2769                })
2770            }
2771            Self::MutationBatchDuplicateKey => {
2772                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2773                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2774                })
2775            }
2776            Self::MutationManagedTimestampRegression => {
2777                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2778                    boundary:
2779                        diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2780                })
2781            }
2782            Self::AcceptedRowConstraintProgramCorrupt => {
2783                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2784                    boundary:
2785                        diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2786                })
2787            }
2788        }
2789    }
2790
2791    /// Project safe mutation detail into canonical public numeric facts.
2792    #[must_use]
2793    #[cold]
2794    #[inline(never)]
2795    pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2796        Vec::new()
2797    }
2798}
2799
2800impl RecoveryErrorDetail {
2801    /// Return the compact diagnostic code for this recovery detail.
2802    #[must_use]
2803    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2804        match self {
2805            Self::UnsupportedFormatVersion { .. } => {
2806                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2807            }
2808            Self::MalformedFormatMarker { .. } => {
2809                diagnostic_code::DiagnosticCode::RuntimeCorruption
2810            }
2811        }
2812    }
2813
2814    /// Return compact structured diagnostic detail for this recovery detail.
2815    #[must_use]
2816    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2817        let kind = match self {
2818            Self::UnsupportedFormatVersion { .. } => {
2819                diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2820            }
2821            Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2822        };
2823
2824        Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2825    }
2826
2827    /// Project database-format recovery context without retaining marker bytes.
2828    #[must_use]
2829    pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2830        match self {
2831            Self::UnsupportedFormatVersion { found, required } => {
2832                let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2833                facts.push((
2834                    diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2835                    u64::from(*required),
2836                ));
2837                if let Some(found) = found {
2838                    facts.push((
2839                        diagnostic_code::DiagnosticFactTag::ActualVersion,
2840                        u64::from(*found),
2841                    ));
2842                }
2843                facts
2844            }
2845            Self::MalformedFormatMarker { reason } => vec![(
2846                diagnostic_code::DiagnosticFactTag::DecodeReason,
2847                reason.diagnostic_decode_reason().raw(),
2848            )],
2849        }
2850    }
2851}
2852
2853impl StoreError {
2854    /// Return the compact diagnostic code for this store detail.
2855    #[must_use]
2856    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2857        match self {
2858            Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2859            Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2860            Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2861            Self::SchemaDdlPublicationRaceLost
2862            | Self::SchemaDdlRewriteRequiresMigration
2863            | Self::SchemaRowLayoutVersionExhausted
2864            | Self::SchemaTransitionBudgetExceeded { .. } => {
2865                diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2866            }
2867            Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2868                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2869            }
2870            Self::SchemaGeneratedConstraintActivationStale => {
2871                diagnostic_code::DiagnosticCode::RuntimeConflict
2872            }
2873            Self::SchemaMigration { reason } => reason.diagnostic_code(),
2874        }
2875    }
2876
2877    /// Return compact structured diagnostic detail when the store error has one.
2878    #[must_use]
2879    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2880        match self {
2881            Self::SchemaDdlPublicationRaceLost => {
2882                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2883                    reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2884                })
2885            }
2886            Self::SchemaDdlRewriteRequiresMigration => {
2887                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2888                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2889                })
2890            }
2891            Self::SchemaMigration { reason } => {
2892                Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2893            }
2894            Self::SchemaRowLayoutVersionExhausted => {
2895                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2896                    reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2897                })
2898            }
2899            Self::JournalMutationRevisionExhausted => {
2900                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2901                    boundary:
2902                        diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2903                })
2904            }
2905            Self::SchemaTransitionBudgetExceeded { .. } => {
2906                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2907                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2908                })
2909            }
2910            Self::SchemaGeneratedFieldAfterDdlField => {
2911                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2912                    boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2913                })
2914            }
2915            Self::SchemaGeneratedConstraintActivationStale => {
2916                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2917                    boundary:
2918                        diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2919                })
2920            }
2921            Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2922        }
2923    }
2924}
2925
2926impl QueryErrorDetail {
2927    /// Return the compact diagnostic code for this query detail.
2928    #[must_use]
2929    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2930        match self {
2931            Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2932            Self::NumericNotRepresentable => {
2933                diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2934            }
2935            Self::UnsupportedSqlFeature { .. } => {
2936                diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2937            }
2938            Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2939            Self::UnsupportedProjection { .. } => {
2940                diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2941            }
2942            Self::UnknownAggregateTargetField => {
2943                diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2944            }
2945            Self::ResultShapeMismatch { .. } => {
2946                diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
2947            }
2948            Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2949            Self::SqlSurfaceMismatch { .. } => {
2950                diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2951            }
2952            Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2953            Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2954            Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2955        }
2956    }
2957
2958    /// Return compact structured diagnostic detail when the query detail has one.
2959    #[must_use]
2960    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2961        match self {
2962            Self::UnsupportedSqlFeature { feature } => {
2963                Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2964            }
2965            Self::SqlLowering { reason } => {
2966                Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2967            }
2968            Self::UnsupportedProjection { reason } => {
2969                Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2970            }
2971            Self::ResultShapeMismatch { reason } => {
2972                Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
2973            }
2974            Self::QueryReadAdmission { reason } => {
2975                Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2976            }
2977            Self::SqlSurfaceMismatch { mismatch } => {
2978                Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2979                    mismatch: *mismatch,
2980                })
2981            }
2982            Self::SqlWriteBoundary { boundary } => {
2983                Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2984                    boundary: *boundary,
2985                })
2986            }
2987            Self::SchemaDdlAdmission { error } => {
2988                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2989                    reason: error.diagnostic_code(),
2990                })
2991            }
2992            Self::NumericOverflow
2993            | Self::NumericNotRepresentable
2994            | Self::UnknownAggregateTargetField
2995            | Self::StaleSchemaRevision => None,
2996        }
2997    }
2998
2999    /// Project safe query detail into canonical public numeric facts.
3000    #[must_use]
3001    #[cold]
3002    #[inline(never)]
3003    pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
3004        Vec::new()
3005    }
3006}
3007
3008impl SchemaDdlAdmissionError {
3009    /// Return the compact diagnostic code for this SQL DDL admission reason.
3010    #[must_use]
3011    pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
3012        match self {
3013            Self::MissingExpectedSchemaVersion => {
3014                diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
3015            }
3016            Self::MissingNextSchemaVersion => {
3017                diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
3018            }
3019            Self::StaleExpectedSchemaVersion => {
3020                diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
3021            }
3022            Self::InvalidExpectedSchemaVersion => {
3023                diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
3024            }
3025            Self::InvalidNextSchemaVersion => {
3026                diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
3027            }
3028            Self::AcceptedSchemaChangeWithoutVersionBump => {
3029                diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
3030            }
3031            Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
3032            Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
3033            Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
3034            Self::FingerprintMethodMismatch => {
3035                diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
3036            }
3037            Self::UnsupportedTransitionClass => {
3038                diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
3039            }
3040            Self::PhysicalRunnerMissing => {
3041                diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
3042            }
3043            Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
3044            Self::PublicationRaceLost => {
3045                diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
3046            }
3047            Self::InvalidAddColumnDefault => {
3048                diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
3049            }
3050            Self::InvalidAlterColumnDefault => {
3051                diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
3052            }
3053            Self::GeneratedIndexDropRejected => {
3054                diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
3055            }
3056            Self::SchemaRewriteRequiresMigration => {
3057                diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
3058            }
3059            Self::SchemaTransitionBudgetExceeded { .. } => {
3060                diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
3061            }
3062            Self::GeneratedFieldDefaultChangeRejected => {
3063                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
3064            }
3065            Self::GeneratedFieldNullabilityChangeRejected => {
3066                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
3067            }
3068            Self::RowLayoutVersionExhausted => {
3069                diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
3070            }
3071        }
3072    }
3073}
3074
3075///
3076/// ErrorClass
3077/// Internal error taxonomy for runtime classification.
3078/// Not a stable API; may change without notice.
3079///
3080
3081#[repr(u8)]
3082#[derive(Clone, Copy, Eq, PartialEq)]
3083pub enum ErrorClass {
3084    Corruption,
3085    IncompatiblePersistedFormat,
3086    NotFound,
3087    Internal,
3088    Conflict,
3089    Unsupported,
3090    InvariantViolation,
3091}
3092
3093impl ErrorClass {
3094    /// Return a compact diagnostic code for this broad class and origin pair.
3095    #[must_use]
3096    pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
3097        match self {
3098            Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
3099                diagnostic_code::DiagnosticCode::StoreCorruption
3100            }
3101            Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
3102            Self::IncompatiblePersistedFormat => {
3103                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
3104            }
3105            Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
3106                diagnostic_code::DiagnosticCode::StoreNotFound
3107            }
3108            Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
3109            Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
3110            Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
3111            Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
3112                diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
3113            }
3114            Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
3115            Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
3116                diagnostic_code::DiagnosticCode::StoreInvariantViolation
3117            }
3118            Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3119        }
3120    }
3121}
3122
3123impl fmt::Debug for ErrorClass {
3124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3125        write!(f, "{}", *self as u8)
3126    }
3127}
3128
3129///
3130/// ErrorOrigin
3131/// Internal origin taxonomy for runtime classification.
3132/// Not a stable API; may change without notice.
3133///
3134
3135#[repr(u8)]
3136#[derive(Clone, Copy, Eq, PartialEq)]
3137pub enum ErrorOrigin {
3138    Serialize,
3139    Store,
3140    Index,
3141    Identity,
3142    Query,
3143    Planner,
3144    Cursor,
3145    Recovery,
3146    Response,
3147    Executor,
3148    Interface,
3149}
3150
3151impl ErrorOrigin {
3152    /// Return the compact diagnostic origin for this internal origin.
3153    #[must_use]
3154    pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3155        match self {
3156            Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3157            Self::Store => diagnostic_code::ErrorOrigin::Store,
3158            Self::Index => diagnostic_code::ErrorOrigin::Index,
3159            Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3160            Self::Query => diagnostic_code::ErrorOrigin::Query,
3161            Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3162            Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3163            Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3164            Self::Response => diagnostic_code::ErrorOrigin::Response,
3165            Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3166            Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3167        }
3168    }
3169}
3170
3171impl fmt::Debug for ErrorOrigin {
3172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3173        write!(f, "{}", *self as u8)
3174    }
3175}