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