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 icydb_diagnostic_code as diagnostic_code;
12use std::fmt;
13
14pub(crate) const COMPACT_QUERY_DIAGNOSTIC_MESSAGE: &str = "query diagnostic";
15const COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE: &str = "runtime diagnostic";
16const COMPACT_STORE_DIAGNOSTIC_MESSAGE: &str = "store diagnostic";
17const COMPACT_INDEX_DIAGNOSTIC_MESSAGE: &str = "index diagnostic";
18const COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE: &str = "serialize diagnostic";
19const COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE: &str = "identity diagnostic";
20
21const fn compact_message_for(_class: ErrorClass, origin: ErrorOrigin) -> &'static str {
22    match origin {
23        ErrorOrigin::Serialize => COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE,
24        ErrorOrigin::Store => COMPACT_STORE_DIAGNOSTIC_MESSAGE,
25        ErrorOrigin::Index => COMPACT_INDEX_DIAGNOSTIC_MESSAGE,
26        ErrorOrigin::Identity => COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE,
27        ErrorOrigin::Query | ErrorOrigin::Planner | ErrorOrigin::Response => {
28            COMPACT_QUERY_DIAGNOSTIC_MESSAGE
29        }
30        ErrorOrigin::Cursor
31        | ErrorOrigin::Recovery
32        | ErrorOrigin::Executor
33        | ErrorOrigin::Interface => COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE,
34    }
35}
36
37// ============================================================================
38// INTERNAL ERROR TAXONOMY — ARCHITECTURAL CONTRACT
39// ============================================================================
40//
41// This file defines the canonical runtime error classification system for
42// icydb-core. It is the single source of truth for:
43//
44//   • ErrorClass   (semantic domain)
45//   • ErrorOrigin  (subsystem boundary)
46//   • Structured detail payloads
47//   • Canonical constructor entry points
48//
49// -----------------------------------------------------------------------------
50// DESIGN INTENT
51// -----------------------------------------------------------------------------
52//
53// 1. InternalError is a *taxonomy carrier*, not a formatting utility.
54//
55//    - ErrorClass represents semantic meaning (corruption, invariant_violation,
56//      unsupported, etc).
57//    - ErrorOrigin represents the subsystem boundary (store, index, query,
58//      executor, serialize, interface, etc).
59//    - The (class, origin) pair must remain stable and intentional.
60//
61// 2. Call sites MUST prefer canonical constructors.
62//
63//    Do NOT construct errors manually via:
64//        InternalError::new(class, origin)
65//    unless you are defining a new canonical helper here.
66//
67//    If a pattern appears more than once, centralize it here.
68//
69// 3. Constructors in this file must represent real architectural boundaries.
70//
71//    Add a new helper ONLY if it:
72//
73//      • Encodes a cross-cutting invariant,
74//      • Represents a subsystem boundary,
75//      • Or prevents taxonomy drift across call sites.
76//
77//    Do NOT add feature-specific helpers.
78//    Do NOT add one-off formatting helpers.
79//    Do NOT turn this file into a generic message factory.
80//
81// 4. ErrorDetail must align with ErrorOrigin.
82//
83//    If detail is present, it MUST correspond to the origin.
84//    Do not attach mismatched detail variants.
85//
86// 5. Plan-layer errors are NOT runtime failures.
87//
88//    PlanError and CursorPlanError must be translated into
89//    executor/query invariants via the canonical mapping functions.
90//    Do not leak plan-layer error types across execution boundaries.
91//
92// 6. Preserve taxonomy stability.
93//
94//    Do NOT:
95//      • Merge error classes.
96//      • Reclassify corruption as internal.
97//      • Downgrade invariant violations.
98//      • Introduce ambiguous class/origin combinations.
99//
100//    Any change to ErrorClass or ErrorOrigin is an architectural change
101//    and must be reviewed accordingly.
102//
103// -----------------------------------------------------------------------------
104// NON-GOALS
105// -----------------------------------------------------------------------------
106//
107// This is NOT:
108//
109//   • A public API contract.
110//   • A generic error abstraction layer.
111//   • A feature-specific message builder.
112//   • A dumping ground for temporary error conversions.
113//
114// -----------------------------------------------------------------------------
115// MAINTENANCE GUIDELINES
116// -----------------------------------------------------------------------------
117//
118// When modifying this file:
119//
120//   1. Ensure classification semantics remain consistent.
121//   2. Avoid constructor proliferation.
122//   3. Prefer narrow, origin-specific helpers over ad-hoc new(...).
123//   4. Keep formatting minimal and standardized.
124//   5. Keep this file boring and stable.
125//
126// If this file grows rapidly, something is wrong at the call sites.
127//
128// ============================================================================
129
130///
131/// InternalError
132///
133/// Structured runtime error with a stable internal classification.
134/// Not a stable API; intended for internal use and may change without notice.
135///
136
137pub struct InternalError {
138    pub(crate) class: ErrorClass,
139    pub(crate) origin: ErrorOrigin,
140
141    /// Optional structured error detail.
142    /// The variant (if present) must correspond to `origin`.
143    pub(crate) detail: Option<ErrorDetail>,
144}
145
146#[expect(
147    clippy::missing_const_for_fn,
148    reason = "internal error constructors stay non-const so compact diagnostic construction does not force const churn across subsystem helper seams"
149)]
150impl InternalError {
151    /// Construct an InternalError with optional origin-specific detail.
152    /// This constructor provides default StoreError details for certain
153    /// (class, origin) combinations but does not guarantee a detail payload.
154    #[must_use]
155    #[cold]
156    #[inline(never)]
157    pub fn new(class: ErrorClass, origin: ErrorOrigin) -> Self {
158        let detail = match (class, origin) {
159            (ErrorClass::Corruption, ErrorOrigin::Store) => {
160                Some(ErrorDetail::Store(StoreError::Corrupt))
161            }
162            (ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
163                Some(ErrorDetail::Store(StoreError::InvariantViolation))
164            }
165            _ => None,
166        };
167
168        Self {
169            class,
170            origin,
171            detail,
172        }
173    }
174
175    /// Return the internal error class taxonomy.
176    #[must_use]
177    pub const fn class(&self) -> ErrorClass {
178        self.class
179    }
180
181    /// Return the internal error origin taxonomy.
182    #[must_use]
183    pub const fn origin(&self) -> ErrorOrigin {
184        self.origin
185    }
186
187    /// Return the rendered internal error message.
188    #[must_use]
189    pub const fn message(&self) -> &'static str {
190        compact_message_for(self.class, self.origin)
191    }
192
193    /// Return the optional structured detail payload.
194    #[must_use]
195    pub const fn detail(&self) -> Option<&ErrorDetail> {
196        self.detail.as_ref()
197    }
198
199    /// Return compact diagnostic identity for this internal error.
200    #[must_use]
201    pub fn diagnostic(&self) -> diagnostic_code::Diagnostic {
202        diagnostic_code::Diagnostic::new(
203            self.diagnostic_code(),
204            self.origin.diagnostic_origin(),
205            self.detail
206                .as_ref()
207                .and_then(ErrorDetail::diagnostic_detail),
208        )
209    }
210
211    /// Return the compact diagnostic code for this internal error.
212    #[must_use]
213    pub fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
214        self.detail.as_ref().map_or_else(
215            || self.class.diagnostic_code(self.origin),
216            ErrorDetail::diagnostic_code,
217        )
218    }
219
220    /// Consume and return the rendered internal error message.
221    #[must_use]
222    pub fn into_message(self) -> String {
223        self.message().to_string()
224    }
225
226    /// Construct an error while preserving an explicit class/origin taxonomy pair.
227    #[cold]
228    #[inline(never)]
229    pub(crate) fn classified(class: ErrorClass, origin: ErrorOrigin) -> Self {
230        Self::new(class, origin)
231    }
232
233    /// Rebuild this error with a new origin while preserving class taxonomy.
234    ///
235    /// Origin-scoped detail payloads are intentionally dropped when re-origining.
236    #[cold]
237    #[inline(never)]
238    pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
239        Self::classified(self.class, origin)
240    }
241
242    /// Construct an index-origin invariant violation.
243    #[cold]
244    #[inline(never)]
245    pub(crate) fn index_invariant() -> Self {
246        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
247    }
248
249    /// Construct the canonical index field-count invariant for key building.
250    pub(crate) fn index_key_field_count_exceeds_max(
251        _index_name: &str,
252        _field_count: usize,
253        _max_fields: usize,
254    ) -> Self {
255        Self::index_invariant()
256    }
257
258    /// Construct the canonical index-key source-field-missing-on-model invariant.
259    pub(crate) fn index_key_item_field_missing_on_entity_model(_field: &str) -> Self {
260        Self::index_invariant()
261    }
262
263    /// Construct the canonical index-key source-field-missing-on-row invariant.
264    pub(crate) fn index_key_item_field_missing_on_lookup_row(_field: &str) -> Self {
265        Self::index_invariant()
266    }
267
268    /// Construct the canonical index-expression source-type mismatch invariant.
269    pub(crate) fn index_expression_source_type_mismatch(
270        _index_name: &str,
271        _expression: impl Sized,
272        _expected: impl Sized,
273        _source_label: &str,
274    ) -> Self {
275        Self::index_invariant()
276    }
277
278    /// Construct a planner-origin invariant violation for executor-boundary
279    /// contract drift.
280    #[cold]
281    #[inline(never)]
282    pub(crate) fn planner_executor_invariant() -> Self {
283        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
284    }
285
286    /// Construct a query-origin invariant violation for executor-boundary
287    /// contract drift.
288    #[cold]
289    #[inline(never)]
290    pub(crate) fn query_executor_invariant() -> Self {
291        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
292    }
293
294    /// Construct a cursor-origin invariant violation for executor-boundary
295    /// contract drift.
296    #[cold]
297    #[inline(never)]
298    pub(crate) fn cursor_executor_invariant() -> Self {
299        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
300    }
301
302    /// Construct an executor-origin invariant violation.
303    #[cold]
304    #[inline(never)]
305    pub(crate) fn executor_invariant() -> Self {
306        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
307    }
308
309    /// Construct an executor-origin internal error.
310    #[cold]
311    #[inline(never)]
312    pub(crate) fn executor_internal() -> Self {
313        Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
314    }
315
316    /// Construct an executor-origin unsupported error.
317    #[cold]
318    #[inline(never)]
319    pub(crate) fn executor_unsupported() -> Self {
320        Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
321    }
322
323    /// Construct an executor-origin save-preflight primary-key missing invariant.
324    pub(crate) fn mutation_entity_primary_key_missing(
325        _entity_path: &str,
326        _field_name: &str,
327    ) -> Self {
328        Self::executor_invariant()
329    }
330
331    /// Construct an executor-origin save-preflight primary-key invalid-value invariant.
332    pub(crate) fn mutation_entity_primary_key_invalid_value(
333        _entity_path: &str,
334        _field_name: &str,
335        _value: &crate::value::Value,
336    ) -> Self {
337        Self::executor_invariant()
338    }
339
340    /// Construct an executor-origin save-preflight primary-key type mismatch invariant.
341    pub(crate) fn mutation_entity_primary_key_type_mismatch(
342        _entity_path: &str,
343        _field_name: &str,
344        _value: &crate::value::Value,
345    ) -> Self {
346        Self::executor_invariant()
347    }
348
349    /// Construct an executor-origin save-preflight primary-key identity mismatch invariant.
350    pub(crate) fn mutation_entity_primary_key_mismatch(
351        _entity_path: &str,
352        _field_name: &str,
353        _field_value: &crate::value::Value,
354        _identity_key: &crate::value::Value,
355    ) -> Self {
356        Self::executor_invariant()
357    }
358
359    /// Construct an executor-origin save-preflight field-missing invariant.
360    pub(crate) fn mutation_entity_field_missing(
361        _entity_path: &str,
362        _field_name: &str,
363        _indexed: bool,
364    ) -> Self {
365        Self::executor_invariant()
366    }
367
368    /// Construct an executor-origin sparse structural patch required-field invariant.
369    pub(crate) fn mutation_structural_patch_required_field_missing(
370        _entity_path: &str,
371        _field_name: &str,
372    ) -> Self {
373        Self::executor_invariant()
374    }
375
376    /// Construct an executor-origin save-preflight field-type mismatch invariant.
377    pub(crate) fn mutation_entity_field_type_mismatch(
378        _entity_path: &str,
379        _field_name: &str,
380        _value: &crate::value::Value,
381    ) -> Self {
382        Self::executor_invariant()
383    }
384
385    /// Construct an executor-origin generated-field authored-write rejection.
386    pub(crate) fn mutation_generated_field_explicit(_entity_path: &str, _field_name: &str) -> Self {
387        Self::executor_unsupported()
388    }
389
390    /// Construct an executor-origin typed create omission rejection.
391    #[must_use]
392    pub fn mutation_create_missing_authored_fields(_entity_path: &str, _field_names: &str) -> Self {
393        Self::executor_unsupported()
394    }
395
396    /// Construct an executor-origin mutation result invariant.
397    ///
398    /// This constructor lands ahead of the public structural mutation surface,
399    /// so the library target may not route through it until that caller exists.
400    pub(crate) fn mutation_structural_after_image_invalid(
401        _entity_path: &str,
402        _data_key: impl Sized,
403        _detail: impl Sized,
404    ) -> Self {
405        Self::executor_invariant()
406    }
407
408    /// Construct an executor-origin mutation unknown-field invariant.
409    pub(crate) fn mutation_structural_field_unknown(_entity_path: &str, _field_name: &str) -> Self {
410        Self::executor_invariant()
411    }
412
413    /// Construct an executor-origin save-preflight decimal-scale unsupported error.
414    pub(crate) fn mutation_decimal_scale_mismatch(
415        _entity_path: &str,
416        _field_name: &str,
417        _expected_scale: impl Sized,
418        _actual_scale: impl Sized,
419    ) -> Self {
420        Self::executor_unsupported()
421    }
422
423    /// Construct an executor-origin save-preflight text-length unsupported error.
424    pub(crate) fn mutation_text_max_len_exceeded(
425        _entity_path: &str,
426        _field_name: &str,
427        _max_len: impl Sized,
428        _actual_len: impl Sized,
429    ) -> Self {
430        Self::executor_unsupported()
431    }
432
433    /// Construct an executor-origin save-preflight set-encoding invariant.
434    pub(crate) fn mutation_set_field_list_required(_entity_path: &str, _field_name: &str) -> Self {
435        Self::executor_invariant()
436    }
437
438    /// Construct an executor-origin save-preflight set-canonicality invariant.
439    pub(crate) fn mutation_set_field_not_canonical(_entity_path: &str, _field_name: &str) -> Self {
440        Self::executor_invariant()
441    }
442
443    /// Construct an executor-origin save-preflight map-encoding invariant.
444    pub(crate) fn mutation_map_field_map_required(_entity_path: &str, _field_name: &str) -> Self {
445        Self::executor_invariant()
446    }
447
448    /// Construct an executor-origin save-preflight map-entry invariant.
449    pub(crate) fn mutation_map_field_entries_invalid(
450        _entity_path: &str,
451        _field_name: &str,
452        _detail: impl Sized,
453    ) -> Self {
454        Self::executor_invariant()
455    }
456
457    /// Construct an executor-origin save-preflight map-canonicality invariant.
458    pub(crate) fn mutation_map_field_entries_not_canonical(
459        _entity_path: &str,
460        _field_name: &str,
461    ) -> Self {
462        Self::executor_invariant()
463    }
464
465    /// Construct a query-origin scalar page invariant for ordering before filtering.
466    pub(crate) fn scalar_page_ordering_after_filtering_required() -> Self {
467        Self::query_executor_invariant()
468    }
469
470    /// Construct a query-origin scalar page invariant for missing order at the cursor boundary.
471    pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
472        Self::query_executor_invariant()
473    }
474
475    /// Construct a query-origin scalar page invariant for cursor-before-ordering drift.
476    pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
477        Self::query_executor_invariant()
478    }
479
480    /// Construct a query-origin scalar page invariant for pagination-before-ordering drift.
481    pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
482        Self::query_executor_invariant()
483    }
484
485    /// Construct a query-origin scalar page invariant for delete-limit-before-ordering drift.
486    pub(crate) fn scalar_page_delete_limit_after_ordering_required() -> Self {
487        Self::query_executor_invariant()
488    }
489
490    /// Construct a query-origin load-runtime invariant for scalar-mode payload mismatch.
491    pub(crate) fn load_runtime_scalar_payload_required() -> Self {
492        Self::query_executor_invariant()
493    }
494
495    /// Construct a query-origin load-runtime invariant for grouped-mode payload mismatch.
496    pub(crate) fn load_runtime_grouped_payload_required() -> Self {
497        Self::query_executor_invariant()
498    }
499
500    /// Construct a query-origin load-surface invariant for scalar-page payload mismatch.
501    pub(crate) fn load_runtime_scalar_surface_payload_required() -> Self {
502        Self::query_executor_invariant()
503    }
504
505    /// Construct a query-origin load-surface invariant for grouped-page payload mismatch.
506    pub(crate) fn load_runtime_grouped_surface_payload_required() -> Self {
507        Self::query_executor_invariant()
508    }
509
510    /// Construct a query-origin load-entrypoint invariant for non-load plans.
511    pub(crate) fn load_executor_load_plan_required() -> Self {
512        Self::query_executor_invariant()
513    }
514
515    /// Construct an executor-origin delete-entrypoint unsupported grouped-mode error.
516    pub(crate) fn delete_executor_grouped_unsupported() -> Self {
517        Self::executor_unsupported()
518    }
519
520    /// Construct a query-origin delete-entrypoint invariant for non-delete plans.
521    pub(crate) fn delete_executor_delete_plan_required() -> Self {
522        Self::query_executor_invariant()
523    }
524
525    /// Construct a query-origin aggregate kernel invariant for fold-mode contract drift.
526    pub(crate) fn aggregate_fold_mode_terminal_contract_required() -> Self {
527        Self::query_executor_invariant()
528    }
529
530    /// Construct a query-origin fast-stream invariant for route kind/request mismatch.
531    pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
532        Self::query_executor_invariant()
533    }
534
535    /// Construct a query-origin scan invariant for missing index-prefix executable specs.
536    pub(crate) fn secondary_index_prefix_spec_required() -> Self {
537        Self::query_executor_invariant()
538    }
539
540    /// Construct a query-origin scan invariant for missing index-range executable specs.
541    pub(crate) fn index_range_limit_spec_required() -> Self {
542        Self::query_executor_invariant()
543    }
544
545    /// Construct an executor-origin mutation unsupported error for duplicate atomic save keys.
546    pub(crate) fn mutation_atomic_save_duplicate_key(_entity_path: &str, _key: impl Sized) -> Self {
547        Self::executor_unsupported()
548    }
549
550    /// Construct an executor-origin mutation invariant for index-store generation drift.
551    pub(crate) fn mutation_index_store_generation_changed(
552        _expected_generation: u64,
553        _observed_generation: u64,
554    ) -> Self {
555        Self::executor_invariant()
556    }
557
558    /// Construct a planner-origin invariant violation.
559    #[cold]
560    #[inline(never)]
561    pub(crate) fn planner_invariant() -> Self {
562        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
563    }
564
565    /// Construct a planner-origin invalid-logical-plan invariant.
566    pub(crate) fn query_invalid_logical_plan() -> Self {
567        Self::planner_invariant()
568    }
569
570    /// Construct a store-origin invariant violation.
571    pub(crate) fn store_invariant() -> Self {
572        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
573    }
574
575    /// Construct the canonical duplicate runtime-hook entity-tag invariant.
576    pub(crate) fn duplicate_runtime_hooks_for_entity_tag(
577        _entity_tag: crate::types::EntityTag,
578    ) -> Self {
579        Self::store_invariant()
580    }
581
582    /// Construct the canonical duplicate runtime-hook entity-path invariant.
583    pub(crate) fn duplicate_runtime_hooks_for_entity_path(_entity_path: &str) -> Self {
584        Self::store_invariant()
585    }
586
587    /// Construct a store-origin internal error.
588    #[cold]
589    #[inline(never)]
590    pub(crate) fn store_internal() -> Self {
591        Self::new(ErrorClass::Internal, ErrorOrigin::Store)
592    }
593
594    /// Construct the canonical unconfigured commit-memory id internal error.
595    pub(crate) fn commit_memory_id_unconfigured() -> Self {
596        Self::store_internal()
597    }
598
599    /// Construct the canonical commit-memory id mismatch internal error.
600    pub(crate) fn commit_memory_id_mismatch(_cached_id: u8, _configured_id: u8) -> Self {
601        Self::store_internal()
602    }
603
604    /// Construct the canonical commit-memory stable-key mismatch internal error.
605    pub(crate) fn commit_memory_stable_key_mismatch(
606        _cached_key: &str,
607        _configured_key: &str,
608    ) -> Self {
609        Self::store_internal()
610    }
611
612    /// Construct a recovery-origin incompatible store-format error.
613    pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
614        Self {
615            class: ErrorClass::IncompatiblePersistedFormat,
616            origin: ErrorOrigin::Recovery,
617            detail: Some(ErrorDetail::Recovery(
618                RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
619            )),
620        }
621    }
622
623    /// Construct a recovery-origin malformed store-format marker error.
624    pub(crate) fn recovery_malformed_database_format_marker(
625        reason: RecoveryFormatMarkerError,
626    ) -> Self {
627        Self {
628            class: ErrorClass::Corruption,
629            origin: ErrorOrigin::Recovery,
630            detail: Some(ErrorDetail::Recovery(
631                RecoveryErrorDetail::MalformedFormatMarker { reason },
632            )),
633        }
634    }
635
636    /// Construct a recovery-origin boot control-memory failure.
637    pub(crate) fn recovery_database_format_control_unavailable() -> Self {
638        Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
639    }
640
641    /// Construct a commit control-memory growth failure.
642    pub(crate) fn commit_control_memory_growth_failed() -> Self {
643        Self::store_internal()
644    }
645
646    /// Construct a store-format memory registration failure.
647    #[cfg(not(test))]
648    pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
649        Self::store_internal()
650    }
651
652    /// Construct the canonical missing rollback-row invariant for delete execution.
653    pub(crate) fn delete_rollback_row_required() -> Self {
654        Self::store_internal()
655    }
656
657    /// Construct the canonical recovery-integrity totals corruption error.
658    pub(crate) fn recovery_integrity_validation_failed(
659        _missing_index_entries: u64,
660        _divergent_index_entries: u64,
661        _orphan_index_references: u64,
662    ) -> Self {
663        Self::store_corruption()
664    }
665
666    /// Construct an index-origin internal error.
667    #[cold]
668    #[inline(never)]
669    pub(crate) fn index_internal() -> Self {
670        Self::new(ErrorClass::Internal, ErrorOrigin::Index)
671    }
672
673    /// Construct the canonical missing old entity-key internal error for structural index removal.
674    pub(crate) fn structural_index_removal_entity_key_required() -> Self {
675        Self::index_internal()
676    }
677
678    /// Construct the canonical missing new entity-key internal error for structural index insertion.
679    pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
680        Self::index_internal()
681    }
682
683    /// Construct the canonical missing old entity-key internal error for index commit-op removal.
684    pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
685        Self::index_internal()
686    }
687
688    /// Construct the canonical missing new entity-key internal error for index commit-op insertion.
689    pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
690        Self::index_internal()
691    }
692
693    /// Construct a query-origin internal error.
694    #[cfg(test)]
695    pub(crate) fn query_internal() -> Self {
696        Self::new(ErrorClass::Internal, ErrorOrigin::Query)
697    }
698
699    /// Construct a query-origin unsupported error.
700    #[cold]
701    #[inline(never)]
702    pub(crate) fn query_unsupported() -> Self {
703        Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
704    }
705
706    /// Construct a query-origin conflict for execution against a superseded
707    /// accepted schema revision.
708    #[cold]
709    #[inline(never)]
710    pub(crate) fn query_stale_accepted_schema_revision(
711        _expected_revision: u64,
712        _current_revision: Option<u64>,
713    ) -> Self {
714        Self {
715            class: ErrorClass::Conflict,
716            origin: ErrorOrigin::Query,
717            detail: Some(ErrorDetail::Query(QueryErrorDetail::StaleSchemaRevision)),
718        }
719    }
720
721    /// Construct a query-origin SQL DDL admission error with structured detail.
722    #[cold]
723    #[inline(never)]
724    #[cfg(feature = "sql")]
725    pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
726        Self {
727            class: ErrorClass::Unsupported,
728            origin: ErrorOrigin::Query,
729            detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
730                error,
731            })),
732        }
733    }
734
735    /// Construct a query-origin numeric overflow error with structured detail.
736    #[cold]
737    #[inline(never)]
738    pub(crate) fn query_numeric_overflow() -> Self {
739        Self {
740            class: ErrorClass::Unsupported,
741            origin: ErrorOrigin::Query,
742            detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
743        }
744    }
745
746    /// Construct a query-origin non-representable numeric result error with
747    /// structured detail.
748    #[cold]
749    #[inline(never)]
750    pub(crate) fn query_numeric_not_representable() -> Self {
751        Self {
752            class: ErrorClass::Unsupported,
753            origin: ErrorOrigin::Query,
754            detail: Some(ErrorDetail::Query(
755                QueryErrorDetail::NumericNotRepresentable,
756            )),
757        }
758    }
759
760    /// Construct a serialize-origin internal error.
761    #[cold]
762    #[inline(never)]
763    pub(crate) fn serialize_internal() -> Self {
764        Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
765    }
766
767    /// Construct the canonical persisted-row encode internal error.
768    pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
769        Self::persisted_row_encode_internal()
770    }
771
772    /// Construct the compact persisted-row encode internal error.
773    pub(crate) fn persisted_row_encode_internal() -> Self {
774        Self::serialize_internal()
775    }
776
777    /// Construct the canonical persisted-row field encode internal error.
778    pub(crate) fn persisted_row_field_encode_failed(field_name: &str, _detail: impl Sized) -> Self {
779        Self::persisted_row_field_encode_internal(field_name)
780    }
781
782    /// Construct the compact persisted-row field encode internal error.
783    pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
784        Self::persisted_row_encode_internal()
785    }
786
787    /// Construct the canonical bytes(field) value encode internal error.
788    pub(crate) fn bytes_field_value_encode_failed(_detail: impl Sized) -> Self {
789        Self::serialize_internal()
790    }
791
792    /// Construct a store-origin corruption error.
793    #[cold]
794    #[inline(never)]
795    pub(crate) fn store_corruption() -> Self {
796        Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
797    }
798
799    /// Construct a store-origin commit-marker corruption error.
800    pub(crate) fn commit_corruption() -> Self {
801        Self::store_corruption()
802    }
803
804    /// Construct a store-origin commit-marker component corruption error.
805    pub(crate) fn commit_component_corruption() -> Self {
806        Self::commit_corruption()
807    }
808
809    /// Construct the canonical commit-marker id generation internal error.
810    pub(crate) fn commit_id_generation_failed() -> Self {
811        Self::store_internal()
812    }
813
814    /// Construct the canonical commit-marker payload u32-length-limit error.
815    pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
816        Self::store_unsupported()
817    }
818
819    /// Construct the canonical commit-marker component invalid-length corruption error.
820    pub(crate) fn commit_component_length_invalid() -> Self {
821        Self::commit_corruption()
822    }
823
824    /// Construct the canonical commit-marker max-size corruption error.
825    pub(crate) fn commit_marker_exceeds_max_size() -> Self {
826        Self::commit_corruption()
827    }
828
829    /// Construct the canonical commit-control slot max-size unsupported error.
830    pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
831        Self::store_unsupported()
832    }
833
834    /// Construct the canonical commit-control marker-bytes length-limit error.
835    pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
836        Self::store_unsupported()
837    }
838
839    /// Construct the canonical startup index-rebuild invalid-data-key corruption error.
840    pub(crate) fn startup_index_rebuild_invalid_data_key() -> Self {
841        Self::store_corruption()
842    }
843
844    /// Construct an index-origin corruption error.
845    #[cold]
846    #[inline(never)]
847    pub(crate) fn index_corruption() -> Self {
848        Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
849    }
850
851    /// Construct the canonical unique-validation corruption wrapper.
852    pub(crate) fn index_unique_validation_corruption() -> Self {
853        Self::index_plan_index_corruption()
854    }
855
856    /// Construct the canonical structural index-entry corruption wrapper.
857    pub(crate) fn structural_index_entry_corruption() -> Self {
858        Self::index_plan_index_corruption()
859    }
860
861    /// Construct the canonical missing new entity-key invariant during unique validation.
862    pub(crate) fn index_unique_validation_entity_key_required() -> Self {
863        Self::index_invariant()
864    }
865
866    /// Construct the canonical unique-validation structural row-decode corruption error.
867    pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
868        Self::index_plan_serialize_corruption()
869    }
870
871    /// Construct the canonical unique-validation primary-key slot decode corruption error.
872    pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
873        Self::index_plan_serialize_corruption()
874    }
875
876    /// Construct the canonical unique-validation stored key rebuild corruption error.
877    pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
878        Self::index_plan_serialize_corruption()
879    }
880
881    /// Construct the canonical unique-validation missing-row corruption error.
882    pub(crate) fn index_unique_validation_row_required() -> Self {
883        Self::index_plan_store_corruption()
884    }
885
886    /// Construct the canonical index-only predicate missing-component invariant.
887    pub(crate) fn index_only_predicate_component_required() -> Self {
888        Self::index_invariant()
889    }
890
891    /// Construct the canonical index-scan continuation-envelope invariant.
892    pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
893        Self::index_invariant()
894    }
895
896    /// Construct the canonical index-scan continuation-advancement invariant.
897    pub(crate) fn index_scan_continuation_advancement_required() -> Self {
898        Self::index_invariant()
899    }
900
901    /// Construct the canonical index-scan key-decode corruption error.
902    pub(crate) fn index_scan_key_corrupted_during(
903        _context: &'static str,
904        _err: impl Sized,
905    ) -> Self {
906        Self::index_corruption()
907    }
908
909    /// Construct the canonical index-scan missing projection-component invariant.
910    pub(crate) fn index_projection_component_required(
911        _index_name: &str,
912        _component_index: usize,
913    ) -> Self {
914        Self::index_invariant()
915    }
916
917    /// Construct the canonical scan-time index-entry decode corruption error.
918    pub(crate) fn index_entry_decode_failed() -> Self {
919        Self::index_corruption()
920    }
921
922    /// Construct a serialize-origin corruption error.
923    pub(crate) fn serialize_corruption() -> Self {
924        Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
925    }
926
927    /// Construct the canonical persisted-row decode corruption error.
928    pub(crate) fn persisted_row_decode_failed(_detail: impl Sized) -> Self {
929        Self::persisted_row_decode_corruption()
930    }
931
932    /// Construct the compact persisted-row decode corruption error.
933    pub(crate) fn persisted_row_decode_corruption() -> Self {
934        Self::serialize_corruption()
935    }
936
937    /// Construct the canonical persisted-row field decode corruption error.
938    pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
939        Self::persisted_row_field_decode_corruption(field_name)
940    }
941
942    /// Construct the compact persisted-row field decode corruption error.
943    pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
944        Self::persisted_row_decode_corruption()
945    }
946
947    /// Construct the canonical persisted-row field-kind decode corruption error.
948    pub(crate) fn persisted_row_field_kind_decode_failed(
949        field_name: &str,
950        _field_kind: impl fmt::Debug,
951        _detail: impl Sized,
952    ) -> Self {
953        Self::persisted_row_field_decode_corruption(field_name)
954    }
955
956    /// Construct the canonical persisted-row scalar-payload length corruption error.
957    pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
958        Self::persisted_row_field_decode_corruption(field_name)
959    }
960
961    /// Construct the canonical persisted-row scalar-payload empty-body corruption error.
962    pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
963        Self::persisted_row_field_decode_corruption(field_name)
964    }
965
966    /// Construct the canonical persisted-row scalar-payload invalid-byte corruption error.
967    pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
968        Self::persisted_row_field_decode_corruption(field_name)
969    }
970
971    /// Construct the canonical persisted-row scalar-payload non-finite corruption error.
972    pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
973        Self::persisted_row_field_decode_corruption(field_name)
974    }
975
976    /// Construct the canonical persisted-row scalar-payload out-of-range corruption error.
977    pub(crate) fn persisted_row_field_payload_out_of_range(field_name: &str) -> Self {
978        Self::persisted_row_field_decode_corruption(field_name)
979    }
980
981    /// Construct the canonical persisted-row invalid text payload corruption error.
982    pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
983        Self::persisted_row_field_decode_corruption(field_name)
984    }
985
986    /// Construct the canonical persisted-row structural slot-lookup invariant.
987    pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
988        Self::index_invariant()
989    }
990
991    /// Construct the canonical persisted-row structural slot-cache invariant.
992    pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
993        _model_path: &str,
994        _slot: usize,
995    ) -> Self {
996        Self::index_invariant()
997    }
998
999    /// Construct the canonical persisted-row primary-key decode corruption error.
1000    pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1001        _data_key: impl fmt::Debug,
1002        _detail: impl Sized,
1003    ) -> Self {
1004        Self::persisted_row_decode_corruption()
1005    }
1006
1007    /// Construct the canonical persisted-row missing primary-key slot corruption error.
1008    pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1009        Self::persisted_row_decode_corruption()
1010    }
1011
1012    /// Construct the canonical persisted-row key mismatch corruption error.
1013    pub(crate) fn persisted_row_key_mismatch() -> Self {
1014        Self::store_corruption()
1015    }
1016
1017    /// Construct the canonical persisted-row missing declared-field corruption error.
1018    pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1019        Self::persisted_row_field_decode_corruption(field_name)
1020    }
1021
1022    /// Construct the canonical data-key entity mismatch corruption error.
1023    pub(crate) fn data_key_entity_mismatch() -> Self {
1024        Self::store_corruption()
1025    }
1026
1027    /// Construct the canonical reverse-index ordinal overflow internal error.
1028    pub(crate) fn reverse_index_ordinal_overflow(
1029        _source_path: &str,
1030        _field_name: &str,
1031        _target_path: &str,
1032        _detail: impl Sized,
1033    ) -> Self {
1034        Self::index_internal()
1035    }
1036
1037    /// Construct the canonical reverse-index entry corruption error.
1038    pub(crate) fn reverse_index_entry_corrupted(
1039        _source_path: &str,
1040        _field_name: &str,
1041        _target_path: &str,
1042        _index_key: impl fmt::Debug,
1043        _detail: impl Sized,
1044    ) -> Self {
1045        Self::index_corruption()
1046    }
1047
1048    /// Construct the canonical relation-target store missing internal error.
1049    pub(crate) fn relation_target_store_missing(
1050        _source_path: &str,
1051        _field_name: &str,
1052        _target_path: &str,
1053        _store_path: &str,
1054        _detail: impl Sized,
1055    ) -> Self {
1056        Self::executor_internal()
1057    }
1058
1059    /// Construct the canonical relation-target key decode corruption error.
1060    pub(crate) fn relation_target_key_decode_failed(
1061        _context_label: &str,
1062        _source_path: &str,
1063        _field_name: &str,
1064        _target_path: &str,
1065        _detail: impl Sized,
1066    ) -> Self {
1067        Self::identity_corruption()
1068    }
1069
1070    /// Construct the canonical relation-target entity mismatch corruption error.
1071    pub(crate) fn relation_target_entity_mismatch(
1072        _context_label: &str,
1073        _source_path: &str,
1074        _field_name: &str,
1075        _target_path: &str,
1076        _target_entity_name: &str,
1077        _expected_tag: impl Sized,
1078        _actual_tag: impl Sized,
1079    ) -> Self {
1080        Self::store_corruption()
1081    }
1082
1083    /// Construct the canonical relation-source row decode corruption error.
1084    pub(crate) fn relation_source_row_decode_failed(
1085        _source_path: &str,
1086        _field_name: &str,
1087        _target_path: &str,
1088        _detail: impl Sized,
1089    ) -> Self {
1090        Self::persisted_row_decode_corruption()
1091    }
1092
1093    /// Construct the canonical relation-source unsupported scalar relation-key corruption error.
1094    pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1095        _source_path: &str,
1096        _field_name: &str,
1097        _target_path: &str,
1098    ) -> Self {
1099        Self::persisted_row_decode_corruption()
1100    }
1101
1102    /// Construct the canonical unsupported strong-relation key-kind corruption error.
1103    pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1104        Self::persisted_row_decode_corruption()
1105    }
1106
1107    /// Construct the canonical reverse-index relation-target decode invariant failure.
1108    pub(crate) fn reverse_index_relation_target_decode_invariant_violated(
1109        _source_path: &str,
1110        _field_name: &str,
1111        _target_path: &str,
1112    ) -> Self {
1113        Self::executor_internal()
1114    }
1115
1116    /// Construct the canonical covering-component empty-payload corruption error.
1117    pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1118        Self::index_corruption()
1119    }
1120
1121    /// Construct the canonical covering-component truncated bool corruption error.
1122    pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1123        Self::index_corruption()
1124    }
1125
1126    /// Construct the canonical covering-component invalid-length corruption error.
1127    pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1128        Self::index_corruption()
1129    }
1130
1131    /// Construct the canonical covering-component invalid-bool corruption error.
1132    pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1133        Self::index_corruption()
1134    }
1135
1136    /// Construct the canonical covering-component invalid text terminator corruption error.
1137    pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1138        Self::index_corruption()
1139    }
1140
1141    /// Construct the canonical covering-component trailing-text corruption error.
1142    pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1143        Self::index_corruption()
1144    }
1145
1146    /// Construct the canonical covering-component invalid-UTF-8 text corruption error.
1147    pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1148        Self::index_corruption()
1149    }
1150
1151    /// Construct the canonical covering-component invalid text escape corruption error.
1152    pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1153        Self::index_corruption()
1154    }
1155
1156    /// Construct the canonical covering-component missing text terminator corruption error.
1157    pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1158        Self::index_corruption()
1159    }
1160
1161    /// Construct the canonical missing persisted-field decode error.
1162    #[must_use]
1163    pub fn missing_persisted_slot(field_name: &'static str) -> Self {
1164        Self::persisted_row_field_decode_corruption(field_name)
1165    }
1166
1167    /// Construct an identity-origin corruption error.
1168    pub(crate) fn identity_corruption() -> Self {
1169        Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1170    }
1171
1172    /// Construct a store-origin unsupported error.
1173    #[cold]
1174    #[inline(never)]
1175    pub(crate) fn store_unsupported() -> Self {
1176        Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1177    }
1178
1179    /// Construct the canonical schema DDL publication race error.
1180    #[cfg(any(test, feature = "sql"))]
1181    pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &'static str) -> Self {
1182        Self {
1183            class: ErrorClass::Unsupported,
1184            origin: ErrorOrigin::Store,
1185            detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1186        }
1187    }
1188
1189    /// Construct the canonical SQL DDL SET NOT NULL validation failure.
1190    #[cfg(feature = "sql")]
1191    pub(crate) fn schema_ddl_set_not_null_validation_failed(
1192        _entity_path: &'static str,
1193        _column_name: &str,
1194    ) -> Self {
1195        Self {
1196            class: ErrorClass::Unsupported,
1197            origin: ErrorOrigin::Store,
1198            detail: Some(ErrorDetail::Store(
1199                StoreError::SchemaDdlSetNotNullValidationFailed,
1200            )),
1201        }
1202    }
1203
1204    /// Construct the canonical unsupported persisted entity-tag store error.
1205    pub(crate) fn unsupported_entity_tag_in_data_store(
1206        _entity_tag: crate::types::EntityTag,
1207    ) -> Self {
1208        Self::store_unsupported()
1209    }
1210
1211    /// Construct the canonical commit-memory id registration failure.
1212    #[cfg(not(test))]
1213    pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1214        Self::store_internal()
1215    }
1216
1217    /// Construct an index-origin unsupported error.
1218    pub(crate) fn index_unsupported() -> Self {
1219        Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1220    }
1221
1222    /// Construct the canonical index-key component size-limit unsupported error.
1223    pub(crate) fn index_component_exceeds_max_size() -> Self {
1224        Self::index_unsupported()
1225    }
1226
1227    /// Construct a serialize-origin unsupported error.
1228    pub(crate) fn serialize_unsupported() -> Self {
1229        Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1230    }
1231
1232    /// Construct a cursor-origin unsupported error.
1233    pub(crate) fn cursor_unsupported() -> Self {
1234        Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1235    }
1236
1237    /// Construct a serialize-origin incompatible persisted-format error.
1238    pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1239        Self::new(
1240            ErrorClass::IncompatiblePersistedFormat,
1241            ErrorOrigin::Serialize,
1242        )
1243    }
1244
1245    /// Construct a query-origin unsupported error preserving one SQL parser
1246    /// unsupported-feature code in structured error detail.
1247    #[cfg(feature = "sql")]
1248    pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1249        Self {
1250            class: ErrorClass::Unsupported,
1251            origin: ErrorOrigin::Query,
1252            detail: Some(ErrorDetail::Query(
1253                QueryErrorDetail::UnsupportedSqlFeature { feature },
1254            )),
1255        }
1256    }
1257
1258    /// Construct a query-origin unsupported SQL lowering error preserving one
1259    /// compact lowering reason in structured error detail.
1260    #[cfg(feature = "sql")]
1261    pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1262        Self {
1263            class: ErrorClass::Unsupported,
1264            origin: ErrorOrigin::Query,
1265            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1266        }
1267    }
1268
1269    /// Construct a query-origin unsupported projection error preserving one
1270    /// compact projection reason in structured error detail.
1271    pub(crate) fn query_unsupported_projection(
1272        reason: diagnostic_code::QueryProjectionCode,
1273    ) -> Self {
1274        Self {
1275            class: ErrorClass::Unsupported,
1276            origin: ErrorOrigin::Query,
1277            detail: Some(ErrorDetail::Query(
1278                QueryErrorDetail::UnsupportedProjection { reason },
1279            )),
1280        }
1281    }
1282
1283    /// Construct a query-origin unsupported aggregate target-field error.
1284    pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1285        Self {
1286            class: ErrorClass::Unsupported,
1287            origin: ErrorOrigin::Query,
1288            detail: Some(ErrorDetail::Query(
1289                QueryErrorDetail::UnknownAggregateTargetField,
1290            )),
1291        }
1292    }
1293
1294    /// Construct a query-origin result-shape mismatch error preserving one
1295    /// compact result-shape reason in structured error detail.
1296    pub(crate) fn query_result_shape_mismatch(
1297        reason: diagnostic_code::QueryResultShapeCode,
1298    ) -> Self {
1299        Self {
1300            class: ErrorClass::Unsupported,
1301            origin: ErrorOrigin::Query,
1302            detail: Some(ErrorDetail::Query(QueryErrorDetail::ResultShapeMismatch {
1303                reason,
1304            })),
1305        }
1306    }
1307
1308    /// Construct a query-origin unsupported error preserving one SQL endpoint
1309    /// surface mismatch in structured error detail.
1310    #[cfg(feature = "sql")]
1311    pub(crate) fn query_sql_surface_mismatch(
1312        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1313    ) -> Self {
1314        Self {
1315            class: ErrorClass::Unsupported,
1316            origin: ErrorOrigin::Query,
1317            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1318                mismatch,
1319            })),
1320        }
1321    }
1322
1323    /// Construct a query-origin unsupported SQL write boundary error.
1324    #[cfg(feature = "sql")]
1325    pub(crate) fn query_sql_write_boundary(
1326        boundary: diagnostic_code::SqlWriteBoundaryCode,
1327    ) -> Self {
1328        Self {
1329            class: ErrorClass::Unsupported,
1330            origin: ErrorOrigin::Query,
1331            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1332                boundary,
1333            })),
1334        }
1335    }
1336
1337    pub fn store_not_found(_key: impl Sized) -> Self {
1338        Self {
1339            class: ErrorClass::NotFound,
1340            origin: ErrorOrigin::Store,
1341            detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1342        }
1343    }
1344
1345    /// Construct a standardized unsupported-entity-path error.
1346    pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1347        Self::store_unsupported()
1348    }
1349
1350    #[must_use]
1351    pub const fn is_not_found(&self) -> bool {
1352        matches!(self.detail, Some(ErrorDetail::Store(StoreError::NotFound)))
1353    }
1354
1355    /// Construct an index-plan corruption error with a canonical prefix.
1356    #[cold]
1357    #[inline(never)]
1358    pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1359        Self::new(ErrorClass::Corruption, origin)
1360    }
1361
1362    /// Construct an index-plan corruption error for index-origin failures.
1363    #[cold]
1364    #[inline(never)]
1365    pub(crate) fn index_plan_index_corruption() -> Self {
1366        Self::index_plan_corruption(ErrorOrigin::Index)
1367    }
1368
1369    /// Construct an index-plan corruption error for store-origin failures.
1370    #[cold]
1371    #[inline(never)]
1372    pub(crate) fn index_plan_store_corruption() -> Self {
1373        Self::index_plan_corruption(ErrorOrigin::Store)
1374    }
1375
1376    /// Construct an index-plan corruption error for serialize-origin failures.
1377    #[cold]
1378    #[inline(never)]
1379    pub(crate) fn index_plan_serialize_corruption() -> Self {
1380        Self::index_plan_corruption(ErrorOrigin::Serialize)
1381    }
1382
1383    /// Construct an index-plan invariant violation error with a canonical prefix.
1384    #[cfg(test)]
1385    pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1386        Self::new(ErrorClass::InvariantViolation, origin)
1387    }
1388
1389    /// Construct an index-plan invariant violation error for store-origin failures.
1390    #[cfg(test)]
1391    pub(crate) fn index_plan_store_invariant() -> Self {
1392        Self::index_plan_invariant(ErrorOrigin::Store)
1393    }
1394
1395    /// Construct an index uniqueness violation conflict error.
1396    pub(crate) fn index_violation(_path: &str, _index_fields: &[&str]) -> Self {
1397        Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1398    }
1399}
1400
1401impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1402    fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1403        Self {
1404            class: ErrorClass::Unsupported,
1405            origin: ErrorOrigin::Query,
1406            detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1407                reason,
1408            })),
1409        }
1410    }
1411}
1412
1413impl fmt::Debug for InternalError {
1414    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1415        fmt_compact_diagnostic(
1416            f,
1417            self.diagnostic_code(),
1418            self.detail
1419                .as_ref()
1420                .and_then(ErrorDetail::diagnostic_detail),
1421        )
1422    }
1423}
1424
1425impl fmt::Display for InternalError {
1426    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1427        f.write_str(self.message())
1428    }
1429}
1430
1431impl std::error::Error for InternalError {}
1432
1433///
1434/// ErrorDetail
1435///
1436/// Structured, origin-specific error detail carried by [`InternalError`].
1437/// This enum is intentionally extensible.
1438///
1439
1440pub enum ErrorDetail {
1441    Store(StoreError),
1442    Query(QueryErrorDetail),
1443    Recovery(RecoveryErrorDetail),
1444    // Future-proofing:
1445    // Index(IndexError),
1446    //
1447    // Executor(ExecutorErrorDetail),
1448}
1449
1450///
1451/// RecoveryErrorDetail
1452///
1453/// Recovery-origin structured error detail payload.
1454///
1455
1456pub enum RecoveryErrorDetail {
1457    UnsupportedFormatVersion { found: Option<u16>, required: u16 },
1458
1459    MalformedFormatMarker { reason: RecoveryFormatMarkerError },
1460}
1461
1462/// Store boot-marker corruption classification.
1463#[derive(Clone, Copy, Eq, PartialEq)]
1464pub enum RecoveryFormatMarkerError {
1465    Magic,
1466    Checksum,
1467    State,
1468}
1469
1470///
1471/// StoreError
1472///
1473/// Store-specific structured error detail.
1474/// Never returned directly; always wrapped in [`ErrorDetail::Store`].
1475///
1476
1477pub enum StoreError {
1478    NotFound,
1479
1480    Corrupt,
1481
1482    InvariantViolation,
1483
1484    SchemaDdlPublicationRaceLost,
1485
1486    SchemaDdlSetNotNullValidationFailed,
1487}
1488
1489///
1490/// QueryErrorDetail
1491///
1492/// Query-origin structured error detail payload.
1493///
1494
1495pub enum QueryErrorDetail {
1496    NumericOverflow,
1497
1498    NumericNotRepresentable,
1499
1500    UnsupportedSqlFeature {
1501        feature: diagnostic_code::SqlFeatureCode,
1502    },
1503
1504    SqlLowering {
1505        reason: diagnostic_code::SqlLoweringCode,
1506    },
1507
1508    UnsupportedProjection {
1509        reason: diagnostic_code::QueryProjectionCode,
1510    },
1511
1512    UnknownAggregateTargetField,
1513
1514    ResultShapeMismatch {
1515        reason: diagnostic_code::QueryResultShapeCode,
1516    },
1517
1518    QueryReadAdmission {
1519        reason: diagnostic_code::QueryReadAdmissionCode,
1520    },
1521
1522    SqlSurfaceMismatch {
1523        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1524    },
1525
1526    SqlWriteBoundary {
1527        boundary: diagnostic_code::SqlWriteBoundaryCode,
1528    },
1529
1530    SchemaDdlAdmission {
1531        error: SchemaDdlAdmissionError,
1532    },
1533
1534    StaleSchemaRevision,
1535}
1536
1537impl fmt::Display for QueryErrorDetail {
1538    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1539        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
1540    }
1541}
1542
1543impl std::error::Error for QueryErrorDetail {}
1544
1545///
1546/// SchemaDdlAdmissionError
1547///
1548/// Stable query-visible SQL DDL admission reason. Human diagnostics may carry
1549/// extra version, fingerprint, and target facts beside this machine-readable
1550/// variant.
1551///
1552
1553#[derive(Clone, Copy, Eq, PartialEq)]
1554pub enum SchemaDdlAdmissionError {
1555    MissingExpectedSchemaVersion,
1556
1557    MissingNextSchemaVersion,
1558
1559    StaleExpectedSchemaVersion,
1560
1561    InvalidExpectedSchemaVersion,
1562
1563    InvalidNextSchemaVersion,
1564
1565    AcceptedSchemaChangeWithoutVersionBump,
1566
1567    EmptyVersionBump,
1568
1569    VersionGap,
1570
1571    VersionRollback,
1572
1573    FingerprintMethodMismatch,
1574
1575    UnsupportedTransitionClass,
1576
1577    PhysicalRunnerMissing,
1578
1579    ValidationFailed,
1580
1581    PublicationRaceLost,
1582
1583    InvalidAddColumnDefault,
1584
1585    InvalidAlterColumnDefault,
1586
1587    GeneratedIndexDropRejected,
1588
1589    RequiredDropDefaultUnsupported,
1590
1591    GeneratedFieldDefaultChangeRejected,
1592
1593    GeneratedFieldNullabilityChangeRejected,
1594
1595    SetNotNullValidationFailed,
1596}
1597
1598impl fmt::Display for SchemaDdlAdmissionError {
1599    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1600        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
1601    }
1602}
1603
1604impl std::error::Error for SchemaDdlAdmissionError {}
1605
1606impl fmt::Debug for ErrorDetail {
1607    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1608        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1609    }
1610}
1611
1612impl fmt::Debug for StoreError {
1613    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1614        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1615    }
1616}
1617
1618impl fmt::Debug for QueryErrorDetail {
1619    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1620        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1621    }
1622}
1623
1624impl fmt::Debug for RecoveryErrorDetail {
1625    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1626        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1627    }
1628}
1629
1630impl fmt::Debug for RecoveryFormatMarkerError {
1631    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1632        fmt_compact_diagnostic(
1633            f,
1634            diagnostic_code::DiagnosticCode::RuntimeCorruption,
1635            Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
1636                kind: diagnostic_code::RuntimeErrorKind::Corruption,
1637            }),
1638        )
1639    }
1640}
1641
1642impl fmt::Debug for SchemaDdlAdmissionError {
1643    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1644        fmt_compact_diagnostic(
1645            f,
1646            diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
1647            Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1648                reason: self.diagnostic_code(),
1649            }),
1650        )
1651    }
1652}
1653
1654fn fmt_compact_diagnostic(
1655    f: &mut fmt::Formatter<'_>,
1656    code: diagnostic_code::DiagnosticCode,
1657    detail: Option<diagnostic_code::DiagnosticDetail>,
1658) -> fmt::Result {
1659    write!(
1660        f,
1661        "{}",
1662        diagnostic_code::ErrorCode::from_parts(code, detail).raw()
1663    )
1664}
1665
1666impl ErrorDetail {
1667    /// Return the compact diagnostic code for this structured detail.
1668    #[must_use]
1669    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1670        match self {
1671            Self::Store(error) => error.diagnostic_code(),
1672            Self::Query(error) => error.diagnostic_code(),
1673            Self::Recovery(error) => error.diagnostic_code(),
1674        }
1675    }
1676
1677    /// Return compact structured diagnostic detail when the payload carries one.
1678    #[must_use]
1679    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1680        match self {
1681            Self::Store(error) => error.diagnostic_detail(),
1682            Self::Query(error) => error.diagnostic_detail(),
1683            Self::Recovery(error) => error.diagnostic_detail(),
1684        }
1685    }
1686}
1687
1688impl RecoveryErrorDetail {
1689    /// Return the compact diagnostic code for this recovery detail.
1690    #[must_use]
1691    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1692        match self {
1693            Self::UnsupportedFormatVersion { .. } => {
1694                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
1695            }
1696            Self::MalformedFormatMarker { .. } => {
1697                diagnostic_code::DiagnosticCode::RuntimeCorruption
1698            }
1699        }
1700    }
1701
1702    /// Return compact structured diagnostic detail for this recovery detail.
1703    #[must_use]
1704    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1705        let kind = match self {
1706            Self::UnsupportedFormatVersion { .. } => {
1707                diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
1708            }
1709            Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
1710        };
1711
1712        Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
1713    }
1714}
1715
1716impl StoreError {
1717    /// Return the compact diagnostic code for this store detail.
1718    #[must_use]
1719    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1720        match self {
1721            Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
1722            Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
1723            Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
1724            Self::SchemaDdlPublicationRaceLost | Self::SchemaDdlSetNotNullValidationFailed => {
1725                diagnostic_code::DiagnosticCode::SchemaDdlAdmission
1726            }
1727        }
1728    }
1729
1730    /// Return compact structured diagnostic detail when the store error has one.
1731    #[must_use]
1732    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1733        match self {
1734            Self::SchemaDdlPublicationRaceLost => {
1735                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1736                    reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
1737                })
1738            }
1739            Self::SchemaDdlSetNotNullValidationFailed => {
1740                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1741                    reason: diagnostic_code::SchemaDdlAdmissionCode::SetNotNullValidationFailed,
1742                })
1743            }
1744            Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
1745        }
1746    }
1747}
1748
1749impl QueryErrorDetail {
1750    /// Return the compact diagnostic code for this query detail.
1751    #[must_use]
1752    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1753        match self {
1754            Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
1755            Self::NumericNotRepresentable => {
1756                diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
1757            }
1758            Self::UnsupportedSqlFeature { .. } => {
1759                diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
1760            }
1761            Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
1762            Self::UnsupportedProjection { .. } => {
1763                diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
1764            }
1765            Self::UnknownAggregateTargetField => {
1766                diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
1767            }
1768            Self::ResultShapeMismatch { .. } => {
1769                diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
1770            }
1771            Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
1772            Self::SqlSurfaceMismatch { .. } => {
1773                diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
1774            }
1775            Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
1776            Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
1777            Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
1778        }
1779    }
1780
1781    /// Return compact structured diagnostic detail when the query detail has one.
1782    #[must_use]
1783    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1784        match self {
1785            Self::UnsupportedSqlFeature { feature } => {
1786                Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
1787            }
1788            Self::SqlLowering { reason } => {
1789                Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
1790            }
1791            Self::UnsupportedProjection { reason } => {
1792                Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
1793            }
1794            Self::ResultShapeMismatch { reason } => {
1795                Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
1796            }
1797            Self::QueryReadAdmission { reason } => {
1798                Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
1799            }
1800            Self::SqlSurfaceMismatch { mismatch } => {
1801                Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
1802                    mismatch: *mismatch,
1803                })
1804            }
1805            Self::SqlWriteBoundary { boundary } => {
1806                Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
1807                    boundary: *boundary,
1808                })
1809            }
1810            Self::SchemaDdlAdmission { error } => {
1811                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1812                    reason: error.diagnostic_code(),
1813                })
1814            }
1815            Self::NumericOverflow
1816            | Self::NumericNotRepresentable
1817            | Self::UnknownAggregateTargetField
1818            | Self::StaleSchemaRevision => None,
1819        }
1820    }
1821}
1822
1823impl SchemaDdlAdmissionError {
1824    /// Return the compact diagnostic code for this SQL DDL admission reason.
1825    #[must_use]
1826    pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
1827        match self {
1828            Self::MissingExpectedSchemaVersion => {
1829                diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
1830            }
1831            Self::MissingNextSchemaVersion => {
1832                diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
1833            }
1834            Self::StaleExpectedSchemaVersion => {
1835                diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
1836            }
1837            Self::InvalidExpectedSchemaVersion => {
1838                diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
1839            }
1840            Self::InvalidNextSchemaVersion => {
1841                diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
1842            }
1843            Self::AcceptedSchemaChangeWithoutVersionBump => {
1844                diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
1845            }
1846            Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
1847            Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
1848            Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
1849            Self::FingerprintMethodMismatch => {
1850                diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
1851            }
1852            Self::UnsupportedTransitionClass => {
1853                diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
1854            }
1855            Self::PhysicalRunnerMissing => {
1856                diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
1857            }
1858            Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
1859            Self::PublicationRaceLost => {
1860                diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
1861            }
1862            Self::InvalidAddColumnDefault => {
1863                diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
1864            }
1865            Self::InvalidAlterColumnDefault => {
1866                diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
1867            }
1868            Self::GeneratedIndexDropRejected => {
1869                diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
1870            }
1871            Self::RequiredDropDefaultUnsupported => {
1872                diagnostic_code::SchemaDdlAdmissionCode::RequiredDropDefaultUnsupported
1873            }
1874            Self::GeneratedFieldDefaultChangeRejected => {
1875                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
1876            }
1877            Self::GeneratedFieldNullabilityChangeRejected => {
1878                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
1879            }
1880            Self::SetNotNullValidationFailed => {
1881                diagnostic_code::SchemaDdlAdmissionCode::SetNotNullValidationFailed
1882            }
1883        }
1884    }
1885}
1886
1887///
1888/// ErrorClass
1889/// Internal error taxonomy for runtime classification.
1890/// Not a stable API; may change without notice.
1891///
1892
1893#[repr(u16)]
1894#[derive(Clone, Copy, Eq, PartialEq)]
1895pub enum ErrorClass {
1896    Corruption,
1897    IncompatiblePersistedFormat,
1898    NotFound,
1899    Internal,
1900    Conflict,
1901    Unsupported,
1902    InvariantViolation,
1903}
1904
1905impl ErrorClass {
1906    /// Return a compact diagnostic code for this broad class and origin pair.
1907    #[must_use]
1908    pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
1909        match self {
1910            Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
1911                diagnostic_code::DiagnosticCode::StoreCorruption
1912            }
1913            Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
1914            Self::IncompatiblePersistedFormat => {
1915                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
1916            }
1917            Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
1918                diagnostic_code::DiagnosticCode::StoreNotFound
1919            }
1920            Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
1921            Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
1922            Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
1923            Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
1924            Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
1925                diagnostic_code::DiagnosticCode::StoreInvariantViolation
1926            }
1927            Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
1928        }
1929    }
1930}
1931
1932impl fmt::Debug for ErrorClass {
1933    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1934        write!(f, "{}", *self as u16)
1935    }
1936}
1937
1938///
1939/// ErrorOrigin
1940/// Internal origin taxonomy for runtime classification.
1941/// Not a stable API; may change without notice.
1942///
1943
1944#[repr(u16)]
1945#[derive(Clone, Copy, Eq, PartialEq)]
1946pub enum ErrorOrigin {
1947    Serialize,
1948    Store,
1949    Index,
1950    Identity,
1951    Query,
1952    Planner,
1953    Cursor,
1954    Recovery,
1955    Response,
1956    Executor,
1957    Interface,
1958}
1959
1960impl ErrorOrigin {
1961    /// Return the compact diagnostic origin for this internal origin.
1962    #[must_use]
1963    pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
1964        match self {
1965            Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
1966            Self::Store => diagnostic_code::ErrorOrigin::Store,
1967            Self::Index => diagnostic_code::ErrorOrigin::Index,
1968            Self::Identity => diagnostic_code::ErrorOrigin::Identity,
1969            Self::Query => diagnostic_code::ErrorOrigin::Query,
1970            Self::Planner => diagnostic_code::ErrorOrigin::Planner,
1971            Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
1972            Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
1973            Self::Response => diagnostic_code::ErrorOrigin::Response,
1974            Self::Executor => diagnostic_code::ErrorOrigin::Executor,
1975            Self::Interface => diagnostic_code::ErrorOrigin::Interface,
1976        }
1977    }
1978}
1979
1980impl fmt::Debug for ErrorOrigin {
1981    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1982        write!(f, "{}", *self as u16)
1983    }
1984}