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