Skip to main content

icydb_core/error/
mod.rs

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