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 conflict.
310    #[cold]
311    #[inline(never)]
312    pub(crate) fn executor_conflict() -> Self {
313        Self::new(ErrorClass::Conflict, ErrorOrigin::Executor)
314    }
315
316    /// Construct an executor-origin internal error.
317    #[cold]
318    #[inline(never)]
319    pub(crate) fn executor_internal() -> Self {
320        Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
321    }
322
323    /// Construct an executor-origin unsupported error.
324    #[cold]
325    #[inline(never)]
326    pub(crate) fn executor_unsupported() -> Self {
327        Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
328    }
329
330    /// Construct an executor-origin save-preflight primary-key missing invariant.
331    pub(crate) fn mutation_entity_primary_key_missing(
332        _entity_path: &str,
333        _field_name: &str,
334    ) -> Self {
335        Self::executor_invariant()
336    }
337
338    /// Construct an executor-origin save-preflight primary-key invalid-value invariant.
339    pub(crate) fn mutation_entity_primary_key_invalid_value(
340        _entity_path: &str,
341        _field_name: &str,
342        _value: &crate::value::Value,
343    ) -> Self {
344        Self::executor_invariant()
345    }
346
347    /// Construct an executor-origin save-preflight primary-key type mismatch invariant.
348    pub(crate) fn mutation_entity_primary_key_type_mismatch(
349        _entity_path: &str,
350        _field_name: &str,
351        _value: &crate::value::Value,
352    ) -> Self {
353        Self::executor_invariant()
354    }
355
356    /// Construct an executor-origin save-preflight primary-key identity mismatch invariant.
357    pub(crate) fn mutation_entity_primary_key_mismatch(
358        _entity_path: &str,
359        _field_name: &str,
360        _field_value: &crate::value::Value,
361        _identity_key: &crate::value::Value,
362    ) -> Self {
363        Self::executor_invariant()
364    }
365
366    /// Construct an executor-origin save-preflight field-missing invariant.
367    pub(crate) fn mutation_entity_field_missing(
368        _entity_path: &str,
369        _field_name: &str,
370        _indexed: bool,
371    ) -> Self {
372        Self::executor_invariant()
373    }
374
375    /// Construct an executor-origin sparse structural patch required-field invariant.
376    pub(crate) fn mutation_structural_patch_required_field_missing(
377        _entity_path: &str,
378        _field_name: &str,
379    ) -> Self {
380        Self::executor_invariant()
381    }
382
383    /// Construct an executor-origin save-preflight field-type mismatch invariant.
384    pub(crate) fn mutation_entity_field_type_mismatch(
385        _entity_path: &str,
386        _field_name: &str,
387        _value: &crate::value::Value,
388    ) -> Self {
389        Self::executor_invariant()
390    }
391
392    /// Construct an executor-origin generated-field authored-write rejection.
393    pub(crate) fn mutation_generated_field_explicit(_entity_path: &str, _field_name: &str) -> Self {
394        Self::executor_unsupported()
395    }
396
397    /// Construct an executor-origin typed create omission rejection.
398    #[must_use]
399    pub fn mutation_create_missing_authored_fields(_entity_path: &str, _field_names: &str) -> Self {
400        Self::executor_unsupported()
401    }
402
403    /// Construct an executor-origin mutation result invariant.
404    ///
405    /// This constructor lands ahead of the public structural mutation surface,
406    /// so the library target may not route through it until that caller exists.
407    pub(crate) fn mutation_structural_after_image_invalid(
408        _entity_path: &str,
409        _data_key: impl Sized,
410        _detail: impl Sized,
411    ) -> Self {
412        Self::executor_invariant()
413    }
414
415    /// Construct an executor-origin mutation unknown-field invariant.
416    pub(crate) fn mutation_structural_field_unknown(_entity_path: &str, _field_name: &str) -> Self {
417        Self::executor_invariant()
418    }
419
420    /// Construct an executor-origin save-preflight decimal-scale unsupported error.
421    pub(crate) fn mutation_decimal_scale_mismatch(
422        _entity_path: &str,
423        _field_name: &str,
424        _expected_scale: impl Sized,
425        _actual_scale: impl Sized,
426    ) -> Self {
427        Self::executor_unsupported()
428    }
429
430    /// Construct an executor-origin save-preflight text-length unsupported error.
431    pub(crate) fn mutation_text_max_len_exceeded(
432        _entity_path: &str,
433        _field_name: &str,
434        _max_len: impl Sized,
435        _actual_len: impl Sized,
436    ) -> Self {
437        Self::executor_unsupported()
438    }
439
440    /// Construct an executor-origin save-preflight set-encoding invariant.
441    pub(crate) fn mutation_set_field_list_required(_entity_path: &str, _field_name: &str) -> Self {
442        Self::executor_invariant()
443    }
444
445    /// Construct an executor-origin save-preflight set-canonicality invariant.
446    pub(crate) fn mutation_set_field_not_canonical(_entity_path: &str, _field_name: &str) -> Self {
447        Self::executor_invariant()
448    }
449
450    /// Construct an executor-origin save-preflight map-encoding invariant.
451    pub(crate) fn mutation_map_field_map_required(_entity_path: &str, _field_name: &str) -> Self {
452        Self::executor_invariant()
453    }
454
455    /// Construct an executor-origin save-preflight map-entry invariant.
456    pub(crate) fn mutation_map_field_entries_invalid(
457        _entity_path: &str,
458        _field_name: &str,
459        _detail: impl Sized,
460    ) -> Self {
461        Self::executor_invariant()
462    }
463
464    /// Construct an executor-origin save-preflight map-canonicality invariant.
465    pub(crate) fn mutation_map_field_entries_not_canonical(
466        _entity_path: &str,
467        _field_name: &str,
468    ) -> Self {
469        Self::executor_invariant()
470    }
471
472    /// Construct a query-origin scalar page invariant for missing order at the cursor boundary.
473    pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
474        Self::query_executor_invariant()
475    }
476
477    /// Construct a query-origin scalar page invariant for cursor-before-ordering drift.
478    pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
479        Self::query_executor_invariant()
480    }
481
482    /// Construct a query-origin scalar page invariant for pagination-before-ordering drift.
483    pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
484        Self::query_executor_invariant()
485    }
486
487    /// Construct a query-origin load-runtime invariant for scalar-mode payload mismatch.
488    pub(crate) fn load_runtime_scalar_payload_required() -> Self {
489        Self::query_executor_invariant()
490    }
491
492    /// Construct a query-origin load-runtime invariant for grouped-mode payload mismatch.
493    pub(crate) fn load_runtime_grouped_payload_required() -> Self {
494        Self::query_executor_invariant()
495    }
496
497    /// Construct a query-origin load-surface invariant for scalar-page payload mismatch.
498    pub(crate) fn load_runtime_scalar_surface_payload_required() -> Self {
499        Self::query_executor_invariant()
500    }
501
502    /// Construct a query-origin load-surface invariant for grouped-page payload mismatch.
503    pub(crate) fn load_runtime_grouped_surface_payload_required() -> Self {
504        Self::query_executor_invariant()
505    }
506
507    /// Construct a query-origin load-entrypoint invariant for non-load plans.
508    pub(crate) fn load_executor_load_plan_required() -> Self {
509        Self::query_executor_invariant()
510    }
511
512    /// Construct an executor-origin delete-entrypoint unsupported grouped-mode error.
513    pub(crate) fn delete_executor_grouped_unsupported() -> Self {
514        Self::executor_unsupported()
515    }
516
517    /// Construct a query-origin delete-entrypoint invariant for non-delete plans.
518    pub(crate) fn delete_executor_delete_plan_required() -> Self {
519        Self::query_executor_invariant()
520    }
521
522    /// Construct a query-origin aggregate kernel invariant for fold-mode contract drift.
523    pub(crate) fn aggregate_fold_mode_terminal_contract_required() -> Self {
524        Self::query_executor_invariant()
525    }
526
527    /// Construct a query-origin fast-stream invariant for route kind/request mismatch.
528    pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
529        Self::query_executor_invariant()
530    }
531
532    /// Construct a query-origin scan invariant for missing index-prefix executable specs.
533    pub(crate) fn secondary_index_prefix_spec_required() -> Self {
534        Self::query_executor_invariant()
535    }
536
537    /// Construct a query-origin scan invariant for missing index-range executable specs.
538    pub(crate) fn index_range_limit_spec_required() -> Self {
539        Self::query_executor_invariant()
540    }
541
542    /// Construct an executor-origin mutation conflict for duplicate atomic save keys.
543    pub(crate) fn mutation_atomic_save_duplicate_key(_entity_path: &str, _key: impl Sized) -> Self {
544        Self::executor_conflict()
545    }
546
547    /// Construct an executor-origin mutation invariant for index-store generation drift.
548    pub(crate) fn mutation_index_store_generation_changed(
549        _expected_generation: u64,
550        _observed_generation: u64,
551    ) -> Self {
552        Self::executor_invariant()
553    }
554
555    /// Construct a planner-origin invariant violation.
556    #[cold]
557    #[inline(never)]
558    pub(crate) fn planner_invariant() -> Self {
559        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
560    }
561
562    /// Construct a planner-origin invalid-logical-plan invariant.
563    pub(crate) fn query_invalid_logical_plan() -> Self {
564        Self::planner_invariant()
565    }
566
567    /// Construct a store-origin invariant violation.
568    pub(crate) fn store_invariant() -> Self {
569        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
570    }
571
572    /// Construct the canonical duplicate runtime-hook entity-tag invariant.
573    pub(crate) fn duplicate_runtime_hooks_for_entity_tag(
574        _entity_tag: crate::types::EntityTag,
575    ) -> Self {
576        Self::store_invariant()
577    }
578
579    /// Construct the canonical duplicate runtime-hook entity-path invariant.
580    pub(crate) fn duplicate_runtime_hooks_for_entity_path(_entity_path: &str) -> Self {
581        Self::store_invariant()
582    }
583
584    /// Construct a store-origin internal error.
585    #[cold]
586    #[inline(never)]
587    pub(crate) fn store_internal() -> Self {
588        Self::new(ErrorClass::Internal, ErrorOrigin::Store)
589    }
590
591    /// Construct the canonical unconfigured commit-memory id internal error.
592    pub(crate) fn commit_memory_id_unconfigured() -> Self {
593        Self::store_internal()
594    }
595
596    /// Construct the canonical commit-memory id mismatch internal error.
597    pub(crate) fn commit_memory_id_mismatch(_cached_id: u8, _configured_id: u8) -> Self {
598        Self::store_internal()
599    }
600
601    /// Construct the canonical commit-memory stable-key mismatch internal error.
602    pub(crate) fn commit_memory_stable_key_mismatch(
603        _cached_key: &str,
604        _configured_key: &str,
605    ) -> Self {
606        Self::store_internal()
607    }
608
609    /// Construct a recovery-origin incompatible store-format error.
610    pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
611        Self {
612            class: ErrorClass::IncompatiblePersistedFormat,
613            origin: ErrorOrigin::Recovery,
614            detail: Some(ErrorDetail::Recovery(
615                RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
616            )),
617        }
618    }
619
620    /// Construct a recovery-origin malformed store-format marker error.
621    pub(crate) fn recovery_malformed_database_format_marker(
622        reason: RecoveryFormatMarkerError,
623    ) -> Self {
624        Self {
625            class: ErrorClass::Corruption,
626            origin: ErrorOrigin::Recovery,
627            detail: Some(ErrorDetail::Recovery(
628                RecoveryErrorDetail::MalformedFormatMarker { reason },
629            )),
630        }
631    }
632
633    /// Construct a recovery-origin boot control-memory failure.
634    pub(crate) fn recovery_database_format_control_unavailable() -> Self {
635        Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
636    }
637
638    /// Construct a commit control-memory growth failure.
639    pub(crate) fn commit_control_memory_growth_failed() -> Self {
640        Self::store_internal()
641    }
642
643    /// Construct a store-format memory registration failure.
644    #[cfg(not(test))]
645    pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
646        Self::store_internal()
647    }
648
649    /// Construct the canonical missing rollback-row invariant for delete execution.
650    pub(crate) fn delete_rollback_row_required() -> Self {
651        Self::store_internal()
652    }
653
654    /// Construct the canonical recovery-integrity totals corruption error.
655    pub(crate) fn recovery_integrity_validation_failed(
656        _missing_index_entries: u64,
657        _divergent_index_entries: u64,
658        _orphan_index_references: u64,
659    ) -> Self {
660        Self::store_corruption()
661    }
662
663    /// Construct an index-origin internal error.
664    #[cold]
665    #[inline(never)]
666    pub(crate) fn index_internal() -> Self {
667        Self::new(ErrorClass::Internal, ErrorOrigin::Index)
668    }
669
670    /// Construct the canonical missing old entity-key internal error for structural index removal.
671    pub(crate) fn structural_index_removal_entity_key_required() -> Self {
672        Self::index_internal()
673    }
674
675    /// Construct the canonical missing new entity-key internal error for structural index insertion.
676    pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
677        Self::index_internal()
678    }
679
680    /// Construct the canonical missing old entity-key internal error for index commit-op removal.
681    pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
682        Self::index_internal()
683    }
684
685    /// Construct the canonical missing new entity-key internal error for index commit-op insertion.
686    pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
687        Self::index_internal()
688    }
689
690    /// Construct a query-origin internal error.
691    #[cfg(test)]
692    pub(crate) fn query_internal() -> Self {
693        Self::new(ErrorClass::Internal, ErrorOrigin::Query)
694    }
695
696    /// Construct a query-origin unsupported error.
697    #[cold]
698    #[inline(never)]
699    pub(crate) fn query_unsupported() -> Self {
700        Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
701    }
702
703    /// Construct a query-origin conflict for execution against a superseded
704    /// accepted schema revision.
705    #[cold]
706    #[inline(never)]
707    pub(crate) fn query_stale_accepted_schema_revision(
708        _expected_revision: u64,
709        _current_revision: Option<u64>,
710    ) -> Self {
711        Self {
712            class: ErrorClass::Conflict,
713            origin: ErrorOrigin::Query,
714            detail: Some(ErrorDetail::Query(QueryErrorDetail::StaleSchemaRevision)),
715        }
716    }
717
718    /// Construct a query-origin SQL DDL admission error with structured detail.
719    #[cold]
720    #[inline(never)]
721    #[cfg(feature = "sql")]
722    pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
723        Self {
724            class: ErrorClass::Unsupported,
725            origin: ErrorOrigin::Query,
726            detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
727                error,
728            })),
729        }
730    }
731
732    /// Construct a query-origin numeric overflow error with structured detail.
733    #[cold]
734    #[inline(never)]
735    pub(crate) fn query_numeric_overflow() -> Self {
736        Self {
737            class: ErrorClass::Unsupported,
738            origin: ErrorOrigin::Query,
739            detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
740        }
741    }
742
743    /// Construct a query-origin non-representable numeric result error with
744    /// structured detail.
745    #[cold]
746    #[inline(never)]
747    pub(crate) fn query_numeric_not_representable() -> Self {
748        Self {
749            class: ErrorClass::Unsupported,
750            origin: ErrorOrigin::Query,
751            detail: Some(ErrorDetail::Query(
752                QueryErrorDetail::NumericNotRepresentable,
753            )),
754        }
755    }
756
757    /// Construct a serialize-origin internal error.
758    #[cold]
759    #[inline(never)]
760    pub(crate) fn serialize_internal() -> Self {
761        Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
762    }
763
764    /// Construct the canonical persisted-row encode internal error.
765    pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
766        Self::persisted_row_encode_internal()
767    }
768
769    /// Construct the compact persisted-row encode internal error.
770    pub(crate) fn persisted_row_encode_internal() -> Self {
771        Self::serialize_internal()
772    }
773
774    /// Construct the canonical persisted-row field encode internal error.
775    pub(crate) fn persisted_row_field_encode_failed(field_name: &str, _detail: impl Sized) -> Self {
776        Self::persisted_row_field_encode_internal(field_name)
777    }
778
779    /// Construct the compact persisted-row field encode internal error.
780    pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
781        Self::persisted_row_encode_internal()
782    }
783
784    /// Construct the canonical bytes(field) value encode internal error.
785    pub(crate) fn bytes_field_value_encode_failed(_detail: impl Sized) -> Self {
786        Self::serialize_internal()
787    }
788
789    /// Construct a store-origin corruption error.
790    #[cold]
791    #[inline(never)]
792    pub(crate) fn store_corruption() -> Self {
793        Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
794    }
795
796    /// Construct a store-origin commit-marker corruption error.
797    pub(crate) fn commit_corruption() -> Self {
798        Self::store_corruption()
799    }
800
801    /// Construct a store-origin commit-marker component corruption error.
802    pub(crate) fn commit_component_corruption() -> Self {
803        Self::commit_corruption()
804    }
805
806    /// Construct the canonical commit-marker id generation internal error.
807    pub(crate) fn commit_id_generation_failed() -> Self {
808        Self::store_internal()
809    }
810
811    /// Construct the canonical commit-marker payload u32-length-limit error.
812    pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
813        Self::store_unsupported()
814    }
815
816    /// Construct the canonical commit-marker component invalid-length corruption error.
817    pub(crate) fn commit_component_length_invalid() -> Self {
818        Self::commit_corruption()
819    }
820
821    /// Construct the canonical commit-marker max-size corruption error.
822    pub(crate) fn commit_marker_exceeds_max_size() -> Self {
823        Self::commit_corruption()
824    }
825
826    /// Construct the canonical commit-control slot max-size unsupported error.
827    pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
828        Self::store_unsupported()
829    }
830
831    /// Construct the canonical commit-control marker-bytes length-limit error.
832    pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
833        Self::store_unsupported()
834    }
835
836    /// Construct the canonical startup index-rebuild invalid-data-key corruption error.
837    pub(crate) fn startup_index_rebuild_invalid_data_key() -> Self {
838        Self::store_corruption()
839    }
840
841    /// Construct an index-origin corruption error.
842    #[cold]
843    #[inline(never)]
844    pub(crate) fn index_corruption() -> Self {
845        Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
846    }
847
848    /// Construct the canonical unique-validation corruption wrapper.
849    pub(crate) fn index_unique_validation_corruption() -> Self {
850        Self::index_plan_index_corruption()
851    }
852
853    /// Construct the canonical structural index-entry corruption wrapper.
854    pub(crate) fn structural_index_entry_corruption() -> Self {
855        Self::index_plan_index_corruption()
856    }
857
858    /// Construct the canonical missing new entity-key invariant during unique validation.
859    pub(crate) fn index_unique_validation_entity_key_required() -> Self {
860        Self::index_invariant()
861    }
862
863    /// Construct the canonical unique-validation structural row-decode corruption error.
864    pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
865        Self::index_plan_serialize_corruption()
866    }
867
868    /// Construct the canonical unique-validation primary-key slot decode corruption error.
869    pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
870        Self::index_plan_serialize_corruption()
871    }
872
873    /// Construct the canonical unique-validation stored key rebuild corruption error.
874    pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
875        Self::index_plan_serialize_corruption()
876    }
877
878    /// Construct the canonical unique-validation missing-row corruption error.
879    pub(crate) fn index_unique_validation_row_required() -> Self {
880        Self::index_plan_store_corruption()
881    }
882
883    /// Construct the canonical index-only predicate missing-component invariant.
884    pub(crate) fn index_only_predicate_component_required() -> Self {
885        Self::index_invariant()
886    }
887
888    /// Construct the canonical index-scan continuation-envelope invariant.
889    pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
890        Self::index_invariant()
891    }
892
893    /// Construct the canonical index-scan continuation-advancement invariant.
894    pub(crate) fn index_scan_continuation_advancement_required() -> Self {
895        Self::index_invariant()
896    }
897
898    /// Construct the canonical index-scan key-decode corruption error.
899    pub(crate) fn index_scan_key_corrupted_during(
900        _context: &'static str,
901        _err: impl Sized,
902    ) -> Self {
903        Self::index_corruption()
904    }
905
906    /// Construct the canonical index-scan missing projection-component invariant.
907    pub(crate) fn index_projection_component_required(
908        _index_name: &str,
909        _component_index: usize,
910    ) -> Self {
911        Self::index_invariant()
912    }
913
914    /// Construct the canonical scan-time index-entry decode corruption error.
915    pub(crate) fn index_entry_decode_failed() -> Self {
916        Self::index_corruption()
917    }
918
919    /// Construct a serialize-origin corruption error.
920    pub(crate) fn serialize_corruption() -> Self {
921        Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
922    }
923
924    /// Construct the canonical persisted-row decode corruption error.
925    pub(crate) fn persisted_row_decode_failed(_detail: impl Sized) -> Self {
926        Self::persisted_row_decode_corruption()
927    }
928
929    /// Construct the compact persisted-row decode corruption error.
930    pub(crate) fn persisted_row_decode_corruption() -> Self {
931        Self::serialize_corruption()
932    }
933
934    /// Construct the canonical persisted-row field decode corruption error.
935    pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
936        Self::persisted_row_field_decode_corruption(field_name)
937    }
938
939    /// Construct the compact persisted-row field decode corruption error.
940    pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
941        Self::persisted_row_decode_corruption()
942    }
943
944    /// Construct the canonical persisted-row field-kind decode corruption error.
945    pub(crate) fn persisted_row_field_kind_decode_failed(
946        field_name: &str,
947        _field_kind: impl fmt::Debug,
948        _detail: impl Sized,
949    ) -> Self {
950        Self::persisted_row_field_decode_corruption(field_name)
951    }
952
953    /// Construct the canonical persisted-row scalar-payload length corruption error.
954    pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
955        Self::persisted_row_field_decode_corruption(field_name)
956    }
957
958    /// Construct the canonical persisted-row scalar-payload empty-body corruption error.
959    pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
960        Self::persisted_row_field_decode_corruption(field_name)
961    }
962
963    /// Construct the canonical persisted-row scalar-payload invalid-byte corruption error.
964    pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
965        Self::persisted_row_field_decode_corruption(field_name)
966    }
967
968    /// Construct the canonical persisted-row scalar-payload non-finite corruption error.
969    pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
970        Self::persisted_row_field_decode_corruption(field_name)
971    }
972
973    /// Construct the canonical persisted-row scalar-payload out-of-range corruption error.
974    pub(crate) fn persisted_row_field_payload_out_of_range(field_name: &str) -> Self {
975        Self::persisted_row_field_decode_corruption(field_name)
976    }
977
978    /// Construct the canonical persisted-row invalid text payload corruption error.
979    pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
980        Self::persisted_row_field_decode_corruption(field_name)
981    }
982
983    /// Construct the canonical persisted-row structural slot-lookup invariant.
984    pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
985        Self::index_invariant()
986    }
987
988    /// Construct the canonical persisted-row structural slot-cache invariant.
989    pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
990        _model_path: &str,
991        _slot: usize,
992    ) -> Self {
993        Self::index_invariant()
994    }
995
996    /// Construct the canonical persisted-row primary-key decode corruption error.
997    pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
998        _data_key: impl fmt::Debug,
999        _detail: impl Sized,
1000    ) -> Self {
1001        Self::persisted_row_decode_corruption()
1002    }
1003
1004    /// Construct the canonical persisted-row missing primary-key slot corruption error.
1005    pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1006        Self::persisted_row_decode_corruption()
1007    }
1008
1009    /// Construct the canonical persisted-row key mismatch corruption error.
1010    pub(crate) fn persisted_row_key_mismatch() -> Self {
1011        Self::store_corruption()
1012    }
1013
1014    /// Construct the canonical persisted-row missing declared-field corruption error.
1015    pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1016        Self::persisted_row_field_decode_corruption(field_name)
1017    }
1018
1019    /// Construct the canonical data-key entity mismatch corruption error.
1020    pub(crate) fn data_key_entity_mismatch() -> Self {
1021        Self::store_corruption()
1022    }
1023
1024    /// Construct the canonical reverse-index ordinal overflow internal error.
1025    pub(crate) fn reverse_index_ordinal_overflow(
1026        _source_path: &str,
1027        _field_name: &str,
1028        _target_path: &str,
1029        _detail: impl Sized,
1030    ) -> Self {
1031        Self::index_internal()
1032    }
1033
1034    /// Construct the canonical reverse-index entry corruption error.
1035    pub(crate) fn reverse_index_entry_corrupted(
1036        _source_path: &str,
1037        _field_name: &str,
1038        _target_path: &str,
1039        _index_key: impl fmt::Debug,
1040        _detail: impl Sized,
1041    ) -> Self {
1042        Self::index_corruption()
1043    }
1044
1045    /// Construct the canonical relation-target store missing internal error.
1046    pub(crate) fn relation_target_store_missing(
1047        _source_path: &str,
1048        _field_name: &str,
1049        _target_path: &str,
1050        _store_path: &str,
1051        _detail: impl Sized,
1052    ) -> Self {
1053        Self::executor_internal()
1054    }
1055
1056    /// Construct the canonical relation-target key decode corruption error.
1057    pub(crate) fn relation_target_key_decode_failed(
1058        _context_label: &str,
1059        _source_path: &str,
1060        _field_name: &str,
1061        _target_path: &str,
1062        _detail: impl Sized,
1063    ) -> Self {
1064        Self::identity_corruption()
1065    }
1066
1067    /// Construct the canonical relation-target entity mismatch corruption error.
1068    pub(crate) fn relation_target_entity_mismatch(
1069        _context_label: &str,
1070        _source_path: &str,
1071        _field_name: &str,
1072        _target_path: &str,
1073        _target_entity_name: &str,
1074        _expected_tag: impl Sized,
1075        _actual_tag: impl Sized,
1076    ) -> Self {
1077        Self::store_corruption()
1078    }
1079
1080    /// Construct the canonical relation-source row decode corruption error.
1081    pub(crate) fn relation_source_row_decode_failed(
1082        _source_path: &str,
1083        _field_name: &str,
1084        _target_path: &str,
1085        _detail: impl Sized,
1086    ) -> Self {
1087        Self::persisted_row_decode_corruption()
1088    }
1089
1090    /// Construct the canonical relation-source unsupported scalar relation-key corruption error.
1091    pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1092        _source_path: &str,
1093        _field_name: &str,
1094        _target_path: &str,
1095    ) -> Self {
1096        Self::persisted_row_decode_corruption()
1097    }
1098
1099    /// Construct the canonical unsupported relation key-kind corruption error.
1100    pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1101        Self::persisted_row_decode_corruption()
1102    }
1103
1104    /// Construct the canonical reverse-index relation-target decode invariant failure.
1105    pub(crate) fn reverse_index_relation_target_decode_invariant_violated(
1106        _source_path: &str,
1107        _field_name: &str,
1108        _target_path: &str,
1109    ) -> Self {
1110        Self::executor_internal()
1111    }
1112
1113    /// Construct the canonical covering-component empty-payload corruption error.
1114    pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1115        Self::index_corruption()
1116    }
1117
1118    /// Construct the canonical covering-component truncated bool corruption error.
1119    pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1120        Self::index_corruption()
1121    }
1122
1123    /// Construct the canonical covering-component invalid-length corruption error.
1124    pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1125        Self::index_corruption()
1126    }
1127
1128    /// Construct the canonical covering-component invalid-bool corruption error.
1129    pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1130        Self::index_corruption()
1131    }
1132
1133    /// Construct the canonical covering-component invalid text terminator corruption error.
1134    pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1135        Self::index_corruption()
1136    }
1137
1138    /// Construct the canonical covering-component trailing-text corruption error.
1139    pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1140        Self::index_corruption()
1141    }
1142
1143    /// Construct the canonical covering-component invalid-UTF-8 text corruption error.
1144    pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1145        Self::index_corruption()
1146    }
1147
1148    /// Construct the canonical covering-component invalid text escape corruption error.
1149    pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1150        Self::index_corruption()
1151    }
1152
1153    /// Construct the canonical covering-component missing text terminator corruption error.
1154    pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1155        Self::index_corruption()
1156    }
1157
1158    /// Construct the canonical missing persisted-field decode error.
1159    #[must_use]
1160    pub fn missing_persisted_slot(field_name: &'static str) -> Self {
1161        Self::persisted_row_field_decode_corruption(field_name)
1162    }
1163
1164    /// Construct an identity-origin corruption error.
1165    pub(crate) fn identity_corruption() -> Self {
1166        Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1167    }
1168
1169    /// Construct a store-origin unsupported error.
1170    #[cold]
1171    #[inline(never)]
1172    pub(crate) fn store_unsupported() -> Self {
1173        Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1174    }
1175
1176    /// Construct the canonical schema DDL publication race error.
1177    #[cfg(any(test, feature = "sql"))]
1178    pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &'static str) -> Self {
1179        Self {
1180            class: ErrorClass::Unsupported,
1181            origin: ErrorOrigin::Store,
1182            detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1183        }
1184    }
1185
1186    /// Construct the canonical SQL DDL SET NOT NULL validation failure.
1187    #[cfg(feature = "sql")]
1188    pub(crate) fn schema_ddl_set_not_null_validation_failed(
1189        _entity_path: &'static str,
1190        _column_name: &str,
1191    ) -> Self {
1192        Self {
1193            class: ErrorClass::Unsupported,
1194            origin: ErrorOrigin::Store,
1195            detail: Some(ErrorDetail::Store(
1196                StoreError::SchemaDdlSetNotNullValidationFailed,
1197            )),
1198        }
1199    }
1200
1201    /// Construct the canonical unsupported persisted entity-tag store error.
1202    pub(crate) fn unsupported_entity_tag_in_data_store(
1203        _entity_tag: crate::types::EntityTag,
1204    ) -> Self {
1205        Self::store_unsupported()
1206    }
1207
1208    /// Construct the canonical commit-memory id registration failure.
1209    #[cfg(not(test))]
1210    pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1211        Self::store_internal()
1212    }
1213
1214    /// Construct an index-origin unsupported error.
1215    pub(crate) fn index_unsupported() -> Self {
1216        Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1217    }
1218
1219    /// Construct the canonical index-key component size-limit unsupported error.
1220    pub(crate) fn index_component_exceeds_max_size() -> Self {
1221        Self::index_unsupported()
1222    }
1223
1224    /// Construct a serialize-origin unsupported error.
1225    pub(crate) fn serialize_unsupported() -> Self {
1226        Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1227    }
1228
1229    /// Construct a cursor-origin invalid-continuation error.
1230    pub(crate) fn cursor_invalid_continuation() -> Self {
1231        Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1232    }
1233
1234    /// Construct a serialize-origin incompatible persisted-format error.
1235    pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1236        Self::new(
1237            ErrorClass::IncompatiblePersistedFormat,
1238            ErrorOrigin::Serialize,
1239        )
1240    }
1241
1242    /// Construct a query-origin unsupported error preserving one SQL parser
1243    /// unsupported-feature code in structured error detail.
1244    #[cfg(feature = "sql")]
1245    pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1246        Self {
1247            class: ErrorClass::Unsupported,
1248            origin: ErrorOrigin::Query,
1249            detail: Some(ErrorDetail::Query(
1250                QueryErrorDetail::UnsupportedSqlFeature { feature },
1251            )),
1252        }
1253    }
1254
1255    /// Construct a query-origin unsupported SQL lowering error preserving one
1256    /// compact lowering reason in structured error detail.
1257    #[cfg(feature = "sql")]
1258    pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1259        Self {
1260            class: ErrorClass::Unsupported,
1261            origin: ErrorOrigin::Query,
1262            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1263        }
1264    }
1265
1266    /// Construct a query-origin unsupported projection error preserving one
1267    /// compact projection reason in structured error detail.
1268    pub(crate) fn query_unsupported_projection(
1269        reason: diagnostic_code::QueryProjectionCode,
1270    ) -> Self {
1271        Self {
1272            class: ErrorClass::Unsupported,
1273            origin: ErrorOrigin::Query,
1274            detail: Some(ErrorDetail::Query(
1275                QueryErrorDetail::UnsupportedProjection { reason },
1276            )),
1277        }
1278    }
1279
1280    /// Construct a query-origin unsupported aggregate target-field error.
1281    pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1282        Self {
1283            class: ErrorClass::Unsupported,
1284            origin: ErrorOrigin::Query,
1285            detail: Some(ErrorDetail::Query(
1286                QueryErrorDetail::UnknownAggregateTargetField,
1287            )),
1288        }
1289    }
1290
1291    /// Construct a query-origin result-shape mismatch error preserving one
1292    /// compact result-shape reason in structured error detail.
1293    pub(crate) fn query_result_shape_mismatch(
1294        reason: diagnostic_code::QueryResultShapeCode,
1295    ) -> Self {
1296        Self {
1297            class: ErrorClass::Unsupported,
1298            origin: ErrorOrigin::Query,
1299            detail: Some(ErrorDetail::Query(QueryErrorDetail::ResultShapeMismatch {
1300                reason,
1301            })),
1302        }
1303    }
1304
1305    /// Construct a query-origin unsupported error preserving one SQL endpoint
1306    /// surface mismatch in structured error detail.
1307    #[cfg(feature = "sql")]
1308    pub(crate) fn query_sql_surface_mismatch(
1309        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1310    ) -> Self {
1311        Self {
1312            class: ErrorClass::Unsupported,
1313            origin: ErrorOrigin::Query,
1314            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1315                mismatch,
1316            })),
1317        }
1318    }
1319
1320    /// Construct a query-origin unsupported SQL write boundary error.
1321    #[cfg(feature = "sql")]
1322    pub(crate) fn query_sql_write_boundary(
1323        boundary: diagnostic_code::SqlWriteBoundaryCode,
1324    ) -> Self {
1325        Self {
1326            class: ErrorClass::Unsupported,
1327            origin: ErrorOrigin::Query,
1328            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1329                boundary,
1330            })),
1331        }
1332    }
1333
1334    pub fn store_not_found(_key: impl Sized) -> Self {
1335        Self {
1336            class: ErrorClass::NotFound,
1337            origin: ErrorOrigin::Store,
1338            detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1339        }
1340    }
1341
1342    /// Construct a standardized unsupported-entity-path error.
1343    pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1344        Self::store_unsupported()
1345    }
1346
1347    #[must_use]
1348    pub const fn is_not_found(&self) -> bool {
1349        matches!(self.detail, Some(ErrorDetail::Store(StoreError::NotFound)))
1350    }
1351
1352    /// Construct an index-plan corruption error with a canonical prefix.
1353    #[cold]
1354    #[inline(never)]
1355    pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1356        Self::new(ErrorClass::Corruption, origin)
1357    }
1358
1359    /// Construct an index-plan corruption error for index-origin failures.
1360    #[cold]
1361    #[inline(never)]
1362    pub(crate) fn index_plan_index_corruption() -> Self {
1363        Self::index_plan_corruption(ErrorOrigin::Index)
1364    }
1365
1366    /// Construct an index-plan corruption error for store-origin failures.
1367    #[cold]
1368    #[inline(never)]
1369    pub(crate) fn index_plan_store_corruption() -> Self {
1370        Self::index_plan_corruption(ErrorOrigin::Store)
1371    }
1372
1373    /// Construct an index-plan corruption error for serialize-origin failures.
1374    #[cold]
1375    #[inline(never)]
1376    pub(crate) fn index_plan_serialize_corruption() -> Self {
1377        Self::index_plan_corruption(ErrorOrigin::Serialize)
1378    }
1379
1380    /// Construct an index-plan invariant violation error with a canonical prefix.
1381    #[cfg(test)]
1382    pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1383        Self::new(ErrorClass::InvariantViolation, origin)
1384    }
1385
1386    /// Construct an index-plan invariant violation error for store-origin failures.
1387    #[cfg(test)]
1388    pub(crate) fn index_plan_store_invariant() -> Self {
1389        Self::index_plan_invariant(ErrorOrigin::Store)
1390    }
1391
1392    /// Construct an index uniqueness violation conflict error.
1393    pub(crate) fn index_violation(_path: &str, _index_fields: &[&str]) -> Self {
1394        Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1395    }
1396}
1397
1398impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1399    fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1400        Self {
1401            class: ErrorClass::Unsupported,
1402            origin: ErrorOrigin::Query,
1403            detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1404                reason,
1405            })),
1406        }
1407    }
1408}
1409
1410impl fmt::Debug for InternalError {
1411    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1412        fmt_compact_diagnostic(
1413            f,
1414            self.diagnostic_code(),
1415            self.detail
1416                .as_ref()
1417                .and_then(ErrorDetail::diagnostic_detail),
1418        )
1419    }
1420}
1421
1422impl fmt::Display for InternalError {
1423    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1424        f.write_str(self.message())
1425    }
1426}
1427
1428impl std::error::Error for InternalError {}
1429
1430///
1431/// ErrorDetail
1432///
1433/// Structured, origin-specific error detail carried by [`InternalError`].
1434/// This enum is intentionally extensible.
1435///
1436
1437pub enum ErrorDetail {
1438    Store(StoreError),
1439    Query(QueryErrorDetail),
1440    Recovery(RecoveryErrorDetail),
1441    // Future-proofing:
1442    // Index(IndexError),
1443    //
1444    // Executor(ExecutorErrorDetail),
1445}
1446
1447///
1448/// RecoveryErrorDetail
1449///
1450/// Recovery-origin structured error detail payload.
1451///
1452
1453pub enum RecoveryErrorDetail {
1454    UnsupportedFormatVersion { found: Option<u16>, required: u16 },
1455
1456    MalformedFormatMarker { reason: RecoveryFormatMarkerError },
1457}
1458
1459/// Store boot-marker corruption classification.
1460#[derive(Clone, Copy, Eq, PartialEq)]
1461pub enum RecoveryFormatMarkerError {
1462    Magic,
1463    Checksum,
1464    State,
1465}
1466
1467///
1468/// StoreError
1469///
1470/// Store-specific structured error detail.
1471/// Never returned directly; always wrapped in [`ErrorDetail::Store`].
1472///
1473
1474pub enum StoreError {
1475    NotFound,
1476
1477    Corrupt,
1478
1479    InvariantViolation,
1480
1481    SchemaDdlPublicationRaceLost,
1482
1483    SchemaDdlSetNotNullValidationFailed,
1484}
1485
1486///
1487/// QueryErrorDetail
1488///
1489/// Query-origin structured error detail payload.
1490///
1491
1492pub enum QueryErrorDetail {
1493    NumericOverflow,
1494
1495    NumericNotRepresentable,
1496
1497    UnsupportedSqlFeature {
1498        feature: diagnostic_code::SqlFeatureCode,
1499    },
1500
1501    SqlLowering {
1502        reason: diagnostic_code::SqlLoweringCode,
1503    },
1504
1505    UnsupportedProjection {
1506        reason: diagnostic_code::QueryProjectionCode,
1507    },
1508
1509    UnknownAggregateTargetField,
1510
1511    ResultShapeMismatch {
1512        reason: diagnostic_code::QueryResultShapeCode,
1513    },
1514
1515    QueryReadAdmission {
1516        reason: diagnostic_code::QueryReadAdmissionCode,
1517    },
1518
1519    SqlSurfaceMismatch {
1520        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1521    },
1522
1523    SqlWriteBoundary {
1524        boundary: diagnostic_code::SqlWriteBoundaryCode,
1525    },
1526
1527    SchemaDdlAdmission {
1528        error: SchemaDdlAdmissionError,
1529    },
1530
1531    StaleSchemaRevision,
1532}
1533
1534impl fmt::Display for QueryErrorDetail {
1535    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1536        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
1537    }
1538}
1539
1540impl std::error::Error for QueryErrorDetail {}
1541
1542///
1543/// SchemaDdlAdmissionError
1544///
1545/// Stable query-visible SQL DDL admission reason. Human diagnostics may carry
1546/// extra version, fingerprint, and target facts beside this machine-readable
1547/// variant.
1548///
1549
1550#[derive(Clone, Copy, Eq, PartialEq)]
1551pub enum SchemaDdlAdmissionError {
1552    MissingExpectedSchemaVersion,
1553
1554    MissingNextSchemaVersion,
1555
1556    StaleExpectedSchemaVersion,
1557
1558    InvalidExpectedSchemaVersion,
1559
1560    InvalidNextSchemaVersion,
1561
1562    AcceptedSchemaChangeWithoutVersionBump,
1563
1564    EmptyVersionBump,
1565
1566    VersionGap,
1567
1568    VersionRollback,
1569
1570    FingerprintMethodMismatch,
1571
1572    UnsupportedTransitionClass,
1573
1574    PhysicalRunnerMissing,
1575
1576    ValidationFailed,
1577
1578    PublicationRaceLost,
1579
1580    InvalidAddColumnDefault,
1581
1582    InvalidAlterColumnDefault,
1583
1584    GeneratedIndexDropRejected,
1585
1586    RequiredDropDefaultUnsupported,
1587
1588    GeneratedFieldDefaultChangeRejected,
1589
1590    GeneratedFieldNullabilityChangeRejected,
1591
1592    SetNotNullValidationFailed,
1593}
1594
1595impl fmt::Display for SchemaDdlAdmissionError {
1596    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1597        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
1598    }
1599}
1600
1601impl std::error::Error for SchemaDdlAdmissionError {}
1602
1603impl fmt::Debug for ErrorDetail {
1604    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1605        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1606    }
1607}
1608
1609impl fmt::Debug for StoreError {
1610    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1611        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1612    }
1613}
1614
1615impl fmt::Debug for QueryErrorDetail {
1616    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1617        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1618    }
1619}
1620
1621impl fmt::Debug for RecoveryErrorDetail {
1622    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1623        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1624    }
1625}
1626
1627impl fmt::Debug for RecoveryFormatMarkerError {
1628    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1629        fmt_compact_diagnostic(
1630            f,
1631            diagnostic_code::DiagnosticCode::RuntimeCorruption,
1632            Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
1633                kind: diagnostic_code::RuntimeErrorKind::Corruption,
1634            }),
1635        )
1636    }
1637}
1638
1639impl fmt::Debug for SchemaDdlAdmissionError {
1640    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1641        fmt_compact_diagnostic(
1642            f,
1643            diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
1644            Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1645                reason: self.diagnostic_code(),
1646            }),
1647        )
1648    }
1649}
1650
1651fn fmt_compact_diagnostic(
1652    f: &mut fmt::Formatter<'_>,
1653    code: diagnostic_code::DiagnosticCode,
1654    detail: Option<diagnostic_code::DiagnosticDetail>,
1655) -> fmt::Result {
1656    write!(
1657        f,
1658        "{}",
1659        diagnostic_code::ErrorCode::from_parts(code, detail).raw()
1660    )
1661}
1662
1663impl ErrorDetail {
1664    /// Return the compact diagnostic code for this structured detail.
1665    #[must_use]
1666    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1667        match self {
1668            Self::Store(error) => error.diagnostic_code(),
1669            Self::Query(error) => error.diagnostic_code(),
1670            Self::Recovery(error) => error.diagnostic_code(),
1671        }
1672    }
1673
1674    /// Return compact structured diagnostic detail when the payload carries one.
1675    #[must_use]
1676    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1677        match self {
1678            Self::Store(error) => error.diagnostic_detail(),
1679            Self::Query(error) => error.diagnostic_detail(),
1680            Self::Recovery(error) => error.diagnostic_detail(),
1681        }
1682    }
1683}
1684
1685impl RecoveryErrorDetail {
1686    /// Return the compact diagnostic code for this recovery detail.
1687    #[must_use]
1688    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1689        match self {
1690            Self::UnsupportedFormatVersion { .. } => {
1691                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
1692            }
1693            Self::MalformedFormatMarker { .. } => {
1694                diagnostic_code::DiagnosticCode::RuntimeCorruption
1695            }
1696        }
1697    }
1698
1699    /// Return compact structured diagnostic detail for this recovery detail.
1700    #[must_use]
1701    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1702        let kind = match self {
1703            Self::UnsupportedFormatVersion { .. } => {
1704                diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
1705            }
1706            Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
1707        };
1708
1709        Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
1710    }
1711}
1712
1713impl StoreError {
1714    /// Return the compact diagnostic code for this store detail.
1715    #[must_use]
1716    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1717        match self {
1718            Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
1719            Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
1720            Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
1721            Self::SchemaDdlPublicationRaceLost | Self::SchemaDdlSetNotNullValidationFailed => {
1722                diagnostic_code::DiagnosticCode::SchemaDdlAdmission
1723            }
1724        }
1725    }
1726
1727    /// Return compact structured diagnostic detail when the store error has one.
1728    #[must_use]
1729    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1730        match self {
1731            Self::SchemaDdlPublicationRaceLost => {
1732                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1733                    reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
1734                })
1735            }
1736            Self::SchemaDdlSetNotNullValidationFailed => {
1737                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1738                    reason: diagnostic_code::SchemaDdlAdmissionCode::SetNotNullValidationFailed,
1739                })
1740            }
1741            Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
1742        }
1743    }
1744}
1745
1746impl QueryErrorDetail {
1747    /// Return the compact diagnostic code for this query detail.
1748    #[must_use]
1749    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1750        match self {
1751            Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
1752            Self::NumericNotRepresentable => {
1753                diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
1754            }
1755            Self::UnsupportedSqlFeature { .. } => {
1756                diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
1757            }
1758            Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
1759            Self::UnsupportedProjection { .. } => {
1760                diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
1761            }
1762            Self::UnknownAggregateTargetField => {
1763                diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
1764            }
1765            Self::ResultShapeMismatch { .. } => {
1766                diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
1767            }
1768            Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
1769            Self::SqlSurfaceMismatch { .. } => {
1770                diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
1771            }
1772            Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
1773            Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
1774            Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
1775        }
1776    }
1777
1778    /// Return compact structured diagnostic detail when the query detail has one.
1779    #[must_use]
1780    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1781        match self {
1782            Self::UnsupportedSqlFeature { feature } => {
1783                Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
1784            }
1785            Self::SqlLowering { reason } => {
1786                Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
1787            }
1788            Self::UnsupportedProjection { reason } => {
1789                Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
1790            }
1791            Self::ResultShapeMismatch { reason } => {
1792                Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
1793            }
1794            Self::QueryReadAdmission { reason } => {
1795                Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
1796            }
1797            Self::SqlSurfaceMismatch { mismatch } => {
1798                Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
1799                    mismatch: *mismatch,
1800                })
1801            }
1802            Self::SqlWriteBoundary { boundary } => {
1803                Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
1804                    boundary: *boundary,
1805                })
1806            }
1807            Self::SchemaDdlAdmission { error } => {
1808                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1809                    reason: error.diagnostic_code(),
1810                })
1811            }
1812            Self::NumericOverflow
1813            | Self::NumericNotRepresentable
1814            | Self::UnknownAggregateTargetField
1815            | Self::StaleSchemaRevision => None,
1816        }
1817    }
1818}
1819
1820impl SchemaDdlAdmissionError {
1821    /// Return the compact diagnostic code for this SQL DDL admission reason.
1822    #[must_use]
1823    pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
1824        match self {
1825            Self::MissingExpectedSchemaVersion => {
1826                diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
1827            }
1828            Self::MissingNextSchemaVersion => {
1829                diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
1830            }
1831            Self::StaleExpectedSchemaVersion => {
1832                diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
1833            }
1834            Self::InvalidExpectedSchemaVersion => {
1835                diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
1836            }
1837            Self::InvalidNextSchemaVersion => {
1838                diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
1839            }
1840            Self::AcceptedSchemaChangeWithoutVersionBump => {
1841                diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
1842            }
1843            Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
1844            Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
1845            Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
1846            Self::FingerprintMethodMismatch => {
1847                diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
1848            }
1849            Self::UnsupportedTransitionClass => {
1850                diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
1851            }
1852            Self::PhysicalRunnerMissing => {
1853                diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
1854            }
1855            Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
1856            Self::PublicationRaceLost => {
1857                diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
1858            }
1859            Self::InvalidAddColumnDefault => {
1860                diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
1861            }
1862            Self::InvalidAlterColumnDefault => {
1863                diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
1864            }
1865            Self::GeneratedIndexDropRejected => {
1866                diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
1867            }
1868            Self::RequiredDropDefaultUnsupported => {
1869                diagnostic_code::SchemaDdlAdmissionCode::RequiredDropDefaultUnsupported
1870            }
1871            Self::GeneratedFieldDefaultChangeRejected => {
1872                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
1873            }
1874            Self::GeneratedFieldNullabilityChangeRejected => {
1875                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
1876            }
1877            Self::SetNotNullValidationFailed => {
1878                diagnostic_code::SchemaDdlAdmissionCode::SetNotNullValidationFailed
1879            }
1880        }
1881    }
1882}
1883
1884///
1885/// ErrorClass
1886/// Internal error taxonomy for runtime classification.
1887/// Not a stable API; may change without notice.
1888///
1889
1890#[repr(u16)]
1891#[derive(Clone, Copy, Eq, PartialEq)]
1892pub enum ErrorClass {
1893    Corruption,
1894    IncompatiblePersistedFormat,
1895    NotFound,
1896    Internal,
1897    Conflict,
1898    Unsupported,
1899    InvariantViolation,
1900}
1901
1902impl ErrorClass {
1903    /// Return a compact diagnostic code for this broad class and origin pair.
1904    #[must_use]
1905    pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
1906        match self {
1907            Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
1908                diagnostic_code::DiagnosticCode::StoreCorruption
1909            }
1910            Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
1911            Self::IncompatiblePersistedFormat => {
1912                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
1913            }
1914            Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
1915                diagnostic_code::DiagnosticCode::StoreNotFound
1916            }
1917            Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
1918            Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
1919            Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
1920            Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
1921                diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
1922            }
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}