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