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 fail-closed journal mutation-revision exhaustion error.
1229    pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1230        Self {
1231            class: ErrorClass::Unsupported,
1232            origin: ErrorOrigin::Store,
1233            detail: Some(ErrorDetail::Store(
1234                StoreError::JournalMutationRevisionExhausted,
1235            )),
1236        }
1237    }
1238
1239    /// Construct the hard-cut rejection for a generated field that would
1240    /// collide with an already accepted SQL-DDL-owned slot.
1241    pub(crate) fn schema_generated_field_after_ddl_field() -> Self {
1242        Self {
1243            class: ErrorClass::Unsupported,
1244            origin: ErrorOrigin::Store,
1245            detail: Some(ErrorDetail::Store(
1246                StoreError::SchemaGeneratedFieldAfterDdlField,
1247            )),
1248        }
1249    }
1250
1251    /// Construct a bounded schema-transition resource rejection.
1252    pub(crate) fn schema_transition_budget_exceeded(
1253        resource: SchemaTransitionBudgetResource,
1254    ) -> Self {
1255        Self {
1256            class: ErrorClass::Unsupported,
1257            origin: ErrorOrigin::Store,
1258            detail: Some(ErrorDetail::Store(
1259                StoreError::SchemaTransitionBudgetExceeded { resource },
1260            )),
1261        }
1262    }
1263
1264    /// Construct the canonical SQL DDL SET NOT NULL validation failure.
1265    #[cfg(feature = "sql")]
1266    pub(crate) fn schema_ddl_set_not_null_validation_failed(
1267        _entity_path: &'static str,
1268        _column_name: &str,
1269    ) -> Self {
1270        Self {
1271            class: ErrorClass::Unsupported,
1272            origin: ErrorOrigin::Store,
1273            detail: Some(ErrorDetail::Store(
1274                StoreError::SchemaDdlSetNotNullValidationFailed,
1275            )),
1276        }
1277    }
1278
1279    /// Construct the canonical unsupported persisted entity-tag store error.
1280    pub(crate) fn unsupported_entity_tag_in_data_store(
1281        _entity_tag: crate::types::EntityTag,
1282    ) -> Self {
1283        Self::store_unsupported()
1284    }
1285
1286    /// Construct the canonical commit-memory id registration failure.
1287    #[cfg(not(test))]
1288    pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1289        Self::store_internal()
1290    }
1291
1292    /// Construct an index-origin unsupported error.
1293    pub(crate) fn index_unsupported() -> Self {
1294        Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1295    }
1296
1297    /// Construct the canonical index-key component size-limit unsupported error.
1298    pub(crate) fn index_component_exceeds_max_size() -> Self {
1299        Self::index_unsupported()
1300    }
1301
1302    /// Construct a serialize-origin unsupported error.
1303    pub(crate) fn serialize_unsupported() -> Self {
1304        Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1305    }
1306
1307    /// Construct a cursor-origin invalid-continuation error.
1308    pub(crate) fn cursor_invalid_continuation() -> Self {
1309        Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1310    }
1311
1312    /// Construct a serialize-origin incompatible persisted-format error.
1313    pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1314        Self::new(
1315            ErrorClass::IncompatiblePersistedFormat,
1316            ErrorOrigin::Serialize,
1317        )
1318    }
1319
1320    /// Construct a query-origin unsupported error preserving one SQL parser
1321    /// unsupported-feature code in structured error detail.
1322    #[cfg(feature = "sql")]
1323    pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1324        Self {
1325            class: ErrorClass::Unsupported,
1326            origin: ErrorOrigin::Query,
1327            detail: Some(ErrorDetail::Query(
1328                QueryErrorDetail::UnsupportedSqlFeature { feature },
1329            )),
1330        }
1331    }
1332
1333    /// Construct a query-origin unsupported SQL lowering error preserving one
1334    /// compact lowering reason in structured error detail.
1335    #[cfg(feature = "sql")]
1336    pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1337        Self {
1338            class: ErrorClass::Unsupported,
1339            origin: ErrorOrigin::Query,
1340            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1341        }
1342    }
1343
1344    /// Construct a query-origin unsupported projection error preserving one
1345    /// compact projection reason in structured error detail.
1346    pub(crate) fn query_unsupported_projection(
1347        reason: diagnostic_code::QueryProjectionCode,
1348    ) -> Self {
1349        Self {
1350            class: ErrorClass::Unsupported,
1351            origin: ErrorOrigin::Query,
1352            detail: Some(ErrorDetail::Query(
1353                QueryErrorDetail::UnsupportedProjection { reason },
1354            )),
1355        }
1356    }
1357
1358    /// Construct a query-origin unsupported aggregate target-field error.
1359    pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1360        Self {
1361            class: ErrorClass::Unsupported,
1362            origin: ErrorOrigin::Query,
1363            detail: Some(ErrorDetail::Query(
1364                QueryErrorDetail::UnknownAggregateTargetField,
1365            )),
1366        }
1367    }
1368
1369    /// Construct a query-origin result-shape mismatch error preserving one
1370    /// compact result-shape reason in structured error detail.
1371    pub(crate) fn query_result_shape_mismatch(
1372        reason: diagnostic_code::QueryResultShapeCode,
1373    ) -> Self {
1374        Self {
1375            class: ErrorClass::Unsupported,
1376            origin: ErrorOrigin::Query,
1377            detail: Some(ErrorDetail::Query(QueryErrorDetail::ResultShapeMismatch {
1378                reason,
1379            })),
1380        }
1381    }
1382
1383    /// Construct a query-origin unsupported error preserving one SQL endpoint
1384    /// surface mismatch in structured error detail.
1385    #[cfg(feature = "sql")]
1386    pub(crate) fn query_sql_surface_mismatch(
1387        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1388    ) -> Self {
1389        Self {
1390            class: ErrorClass::Unsupported,
1391            origin: ErrorOrigin::Query,
1392            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1393                mismatch,
1394            })),
1395        }
1396    }
1397
1398    /// Construct a query-origin unsupported SQL write boundary error.
1399    pub(crate) fn query_sql_write_boundary(
1400        boundary: diagnostic_code::SqlWriteBoundaryCode,
1401    ) -> Self {
1402        Self {
1403            class: ErrorClass::Unsupported,
1404            origin: ErrorOrigin::Query,
1405            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1406                boundary,
1407            })),
1408        }
1409    }
1410
1411    pub fn store_not_found(_key: impl Sized) -> Self {
1412        Self {
1413            class: ErrorClass::NotFound,
1414            origin: ErrorOrigin::Store,
1415            detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1416        }
1417    }
1418
1419    /// Construct a standardized unsupported-entity-path error.
1420    pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1421        Self::store_unsupported()
1422    }
1423
1424    #[must_use]
1425    pub const fn is_not_found(&self) -> bool {
1426        matches!(self.detail, Some(ErrorDetail::Store(StoreError::NotFound)))
1427    }
1428
1429    /// Construct an index-plan corruption error with a canonical prefix.
1430    #[cold]
1431    #[inline(never)]
1432    pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1433        Self::new(ErrorClass::Corruption, origin)
1434    }
1435
1436    /// Construct an index-plan corruption error for index-origin failures.
1437    #[cold]
1438    #[inline(never)]
1439    pub(crate) fn index_plan_index_corruption() -> Self {
1440        Self::index_plan_corruption(ErrorOrigin::Index)
1441    }
1442
1443    /// Construct an index-plan corruption error for store-origin failures.
1444    #[cold]
1445    #[inline(never)]
1446    pub(crate) fn index_plan_store_corruption() -> Self {
1447        Self::index_plan_corruption(ErrorOrigin::Store)
1448    }
1449
1450    /// Construct an index-plan corruption error for serialize-origin failures.
1451    #[cold]
1452    #[inline(never)]
1453    pub(crate) fn index_plan_serialize_corruption() -> Self {
1454        Self::index_plan_corruption(ErrorOrigin::Serialize)
1455    }
1456
1457    /// Construct an index-plan invariant violation error with a canonical prefix.
1458    #[cfg(test)]
1459    pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1460        Self::new(ErrorClass::InvariantViolation, origin)
1461    }
1462
1463    /// Construct an index-plan invariant violation error for store-origin failures.
1464    #[cfg(test)]
1465    pub(crate) fn index_plan_store_invariant() -> Self {
1466        Self::index_plan_invariant(ErrorOrigin::Store)
1467    }
1468
1469    /// Construct an index uniqueness violation conflict error.
1470    pub(crate) fn index_violation(_path: &str, _index_fields: &[&str]) -> Self {
1471        Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1472    }
1473}
1474
1475impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1476    fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1477        Self {
1478            class: ErrorClass::Unsupported,
1479            origin: ErrorOrigin::Query,
1480            detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1481                reason,
1482            })),
1483        }
1484    }
1485}
1486
1487impl fmt::Debug for InternalError {
1488    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1489        fmt_compact_diagnostic(
1490            f,
1491            self.diagnostic_code(),
1492            self.detail
1493                .as_ref()
1494                .and_then(ErrorDetail::diagnostic_detail),
1495        )
1496    }
1497}
1498
1499impl fmt::Display for InternalError {
1500    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1501        f.write_str(self.message())
1502    }
1503}
1504
1505impl std::error::Error for InternalError {}
1506
1507///
1508/// ErrorDetail
1509///
1510/// Structured, origin-specific error detail carried by [`InternalError`].
1511/// This enum is intentionally extensible.
1512///
1513
1514pub enum ErrorDetail {
1515    /// Executor-owned mutation and query execution details.
1516    Executor(ExecutorErrorDetail),
1517    Store(StoreError),
1518    Query(QueryErrorDetail),
1519    Recovery(RecoveryErrorDetail),
1520    /// Persisted-row serialization and decoding details.
1521    Serialize(SerializeErrorDetail),
1522    // Future-proofing:
1523    // Index(IndexError),
1524}
1525
1526/// Executor-specific structured error detail.
1527pub enum ExecutorErrorDetail {
1528    /// A complete insert or replacement omitted one or more required fields.
1529    MutationRequiredFieldMissing,
1530}
1531
1532/// Persisted-row serialization and decoding error detail.
1533pub enum SerializeErrorDetail {
1534    /// The row stamp is older or newer than the accepted layout window.
1535    PersistedRowLayoutOutsideAcceptedWindow,
1536
1537    /// The physical slot count does not match the row's stamped layout.
1538    PersistedRowSlotCountMismatch,
1539}
1540
1541///
1542/// RecoveryErrorDetail
1543///
1544/// Recovery-origin structured error detail payload.
1545///
1546
1547pub enum RecoveryErrorDetail {
1548    UnsupportedFormatVersion { found: Option<u16>, required: u16 },
1549
1550    MalformedFormatMarker { reason: RecoveryFormatMarkerError },
1551}
1552
1553/// Store boot-marker corruption classification.
1554#[derive(Clone, Copy, Eq, PartialEq)]
1555pub enum RecoveryFormatMarkerError {
1556    Magic,
1557    Checksum,
1558    State,
1559}
1560
1561///
1562/// StoreError
1563///
1564/// Store-specific structured error detail.
1565/// Never returned directly; always wrapped in [`ErrorDetail::Store`].
1566///
1567
1568pub enum StoreError {
1569    NotFound,
1570
1571    Corrupt,
1572
1573    InvariantViolation,
1574
1575    SchemaDdlPublicationRaceLost,
1576
1577    SchemaDdlRewriteRequiresMigration,
1578
1579    SchemaRowLayoutVersionExhausted,
1580
1581    JournalMutationRevisionExhausted,
1582
1583    SchemaTransitionBudgetExceeded {
1584        resource: SchemaTransitionBudgetResource,
1585    },
1586
1587    SchemaDdlSetNotNullValidationFailed,
1588
1589    /// A generated field would collide with an accepted DDL-owned slot.
1590    SchemaGeneratedFieldAfterDdlField,
1591}
1592
1593///
1594/// QueryErrorDetail
1595///
1596/// Query-origin structured error detail payload.
1597///
1598
1599pub enum QueryErrorDetail {
1600    NumericOverflow,
1601
1602    NumericNotRepresentable,
1603
1604    UnsupportedSqlFeature {
1605        feature: diagnostic_code::SqlFeatureCode,
1606    },
1607
1608    SqlLowering {
1609        reason: diagnostic_code::SqlLoweringCode,
1610    },
1611
1612    UnsupportedProjection {
1613        reason: diagnostic_code::QueryProjectionCode,
1614    },
1615
1616    UnknownAggregateTargetField,
1617
1618    ResultShapeMismatch {
1619        reason: diagnostic_code::QueryResultShapeCode,
1620    },
1621
1622    QueryReadAdmission {
1623        reason: diagnostic_code::QueryReadAdmissionCode,
1624    },
1625
1626    SqlSurfaceMismatch {
1627        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1628    },
1629
1630    SqlWriteBoundary {
1631        boundary: diagnostic_code::SqlWriteBoundaryCode,
1632    },
1633
1634    SchemaDdlAdmission {
1635        error: SchemaDdlAdmissionError,
1636    },
1637
1638    StaleSchemaRevision,
1639}
1640
1641impl fmt::Display for QueryErrorDetail {
1642    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1643        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
1644    }
1645}
1646
1647impl std::error::Error for QueryErrorDetail {}
1648
1649///
1650/// SchemaTransitionBudgetResource
1651///
1652/// Query-visible identity of the exact schema-transition resource cap that
1653/// rejected a complete validation or derived-state stage.
1654///
1655
1656#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1657pub enum SchemaTransitionBudgetResource {
1658    /// Number of physical deletion keys retained for replacement.
1659    DeletionKeys,
1660    /// Number of row-derived projection entries retained for validation.
1661    ProjectionEntries,
1662    /// Deterministic projection and physical-classification work units.
1663    ProjectionWorkUnits,
1664    /// Number of authoritative source rows.
1665    SourceRows,
1666    /// Cumulative bytes of authoritative source rows.
1667    SourceRowBytes,
1668    /// Retained raw payloads plus deterministic-sort workspace bytes.
1669    StagedRawBytes,
1670}
1671
1672///
1673/// SchemaDdlAdmissionError
1674///
1675/// Stable query-visible SQL DDL admission reason. Human diagnostics may carry
1676/// extra version, fingerprint, and target facts beside this machine-readable
1677/// variant.
1678///
1679
1680#[derive(Clone, Copy, Eq, PartialEq)]
1681pub enum SchemaDdlAdmissionError {
1682    MissingExpectedSchemaVersion,
1683
1684    MissingNextSchemaVersion,
1685
1686    StaleExpectedSchemaVersion,
1687
1688    InvalidExpectedSchemaVersion,
1689
1690    InvalidNextSchemaVersion,
1691
1692    AcceptedSchemaChangeWithoutVersionBump,
1693
1694    EmptyVersionBump,
1695
1696    VersionGap,
1697
1698    VersionRollback,
1699
1700    FingerprintMethodMismatch,
1701
1702    UnsupportedTransitionClass,
1703
1704    PhysicalRunnerMissing,
1705
1706    ValidationFailed,
1707
1708    PublicationRaceLost,
1709
1710    InvalidAddColumnDefault,
1711
1712    InvalidAlterColumnDefault,
1713
1714    RowLayoutVersionExhausted,
1715
1716    GeneratedIndexDropRejected,
1717
1718    SchemaRewriteRequiresMigration,
1719
1720    SchemaTransitionBudgetExceeded {
1721        resource: SchemaTransitionBudgetResource,
1722    },
1723
1724    GeneratedFieldDefaultChangeRejected,
1725
1726    GeneratedFieldNullabilityChangeRejected,
1727
1728    SetNotNullValidationFailed,
1729}
1730
1731impl fmt::Display for SchemaDdlAdmissionError {
1732    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1733        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
1734    }
1735}
1736
1737impl std::error::Error for SchemaDdlAdmissionError {}
1738
1739impl fmt::Debug for ErrorDetail {
1740    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1741        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1742    }
1743}
1744
1745impl fmt::Debug for ExecutorErrorDetail {
1746    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1747        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1748    }
1749}
1750
1751impl fmt::Debug for StoreError {
1752    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1753        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1754    }
1755}
1756
1757impl fmt::Debug for QueryErrorDetail {
1758    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1759        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1760    }
1761}
1762
1763impl fmt::Debug for RecoveryErrorDetail {
1764    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1765        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1766    }
1767}
1768
1769impl fmt::Debug for SerializeErrorDetail {
1770    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1771        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
1772    }
1773}
1774
1775impl fmt::Debug for RecoveryFormatMarkerError {
1776    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1777        fmt_compact_diagnostic(
1778            f,
1779            diagnostic_code::DiagnosticCode::RuntimeCorruption,
1780            Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
1781                kind: diagnostic_code::RuntimeErrorKind::Corruption,
1782            }),
1783        )
1784    }
1785}
1786
1787impl fmt::Debug for SchemaDdlAdmissionError {
1788    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1789        fmt_compact_diagnostic(
1790            f,
1791            diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
1792            Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1793                reason: self.diagnostic_code(),
1794            }),
1795        )
1796    }
1797}
1798
1799fn fmt_compact_diagnostic(
1800    f: &mut fmt::Formatter<'_>,
1801    code: diagnostic_code::DiagnosticCode,
1802    detail: Option<diagnostic_code::DiagnosticDetail>,
1803) -> fmt::Result {
1804    write!(
1805        f,
1806        "{}",
1807        diagnostic_code::ErrorCode::from_parts(code, detail).raw()
1808    )
1809}
1810
1811impl ErrorDetail {
1812    /// Return the compact diagnostic code for this structured detail.
1813    #[must_use]
1814    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1815        match self {
1816            Self::Executor(error) => error.diagnostic_code(),
1817            Self::Store(error) => error.diagnostic_code(),
1818            Self::Query(error) => error.diagnostic_code(),
1819            Self::Recovery(error) => error.diagnostic_code(),
1820            Self::Serialize(error) => error.diagnostic_code(),
1821        }
1822    }
1823
1824    /// Return compact structured diagnostic detail when the payload carries one.
1825    #[must_use]
1826    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1827        match self {
1828            Self::Executor(error) => error.diagnostic_detail(),
1829            Self::Store(error) => error.diagnostic_detail(),
1830            Self::Query(error) => error.diagnostic_detail(),
1831            Self::Recovery(error) => error.diagnostic_detail(),
1832            Self::Serialize(error) => error.diagnostic_detail(),
1833        }
1834    }
1835}
1836
1837impl ExecutorErrorDetail {
1838    /// Return the compact diagnostic code for this executor detail.
1839    #[must_use]
1840    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1841        match self {
1842            Self::MutationRequiredFieldMissing => {
1843                diagnostic_code::DiagnosticCode::RuntimeUnsupported
1844            }
1845        }
1846    }
1847
1848    /// Return compact structured diagnostic detail for this executor detail.
1849    #[must_use]
1850    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1851        match self {
1852            Self::MutationRequiredFieldMissing => {
1853                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1854                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
1855                })
1856            }
1857        }
1858    }
1859}
1860
1861impl RecoveryErrorDetail {
1862    /// Return the compact diagnostic code for this recovery detail.
1863    #[must_use]
1864    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1865        match self {
1866            Self::UnsupportedFormatVersion { .. } => {
1867                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
1868            }
1869            Self::MalformedFormatMarker { .. } => {
1870                diagnostic_code::DiagnosticCode::RuntimeCorruption
1871            }
1872        }
1873    }
1874
1875    /// Return compact structured diagnostic detail for this recovery detail.
1876    #[must_use]
1877    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1878        let kind = match self {
1879            Self::UnsupportedFormatVersion { .. } => {
1880                diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
1881            }
1882            Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
1883        };
1884
1885        Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
1886    }
1887}
1888
1889impl SerializeErrorDetail {
1890    /// Return the compact diagnostic code for this serialization detail.
1891    #[must_use]
1892    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1893        match self {
1894            Self::PersistedRowLayoutOutsideAcceptedWindow | Self::PersistedRowSlotCountMismatch => {
1895                diagnostic_code::DiagnosticCode::RuntimeCorruption
1896            }
1897        }
1898    }
1899
1900    /// Return compact structured diagnostic detail for this serialization detail.
1901    #[must_use]
1902    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1903        let boundary = match self {
1904            Self::PersistedRowLayoutOutsideAcceptedWindow => {
1905                diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow
1906            }
1907            Self::PersistedRowSlotCountMismatch => {
1908                diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch
1909            }
1910        };
1911
1912        Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary })
1913    }
1914}
1915
1916impl StoreError {
1917    /// Return the compact diagnostic code for this store detail.
1918    #[must_use]
1919    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1920        match self {
1921            Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
1922            Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
1923            Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
1924            Self::SchemaDdlPublicationRaceLost
1925            | Self::SchemaDdlRewriteRequiresMigration
1926            | Self::SchemaRowLayoutVersionExhausted
1927            | Self::SchemaTransitionBudgetExceeded { .. }
1928            | Self::SchemaDdlSetNotNullValidationFailed => {
1929                diagnostic_code::DiagnosticCode::SchemaDdlAdmission
1930            }
1931            Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
1932                diagnostic_code::DiagnosticCode::RuntimeUnsupported
1933            }
1934        }
1935    }
1936
1937    /// Return compact structured diagnostic detail when the store error has one.
1938    #[must_use]
1939    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
1940        match self {
1941            Self::SchemaDdlPublicationRaceLost => {
1942                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1943                    reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
1944                })
1945            }
1946            Self::SchemaDdlRewriteRequiresMigration => {
1947                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1948                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
1949                })
1950            }
1951            Self::SchemaRowLayoutVersionExhausted => {
1952                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1953                    reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
1954                })
1955            }
1956            Self::JournalMutationRevisionExhausted => {
1957                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1958                    boundary:
1959                        diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
1960                })
1961            }
1962            Self::SchemaTransitionBudgetExceeded { .. } => {
1963                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1964                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
1965                })
1966            }
1967            Self::SchemaDdlSetNotNullValidationFailed => {
1968                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1969                    reason: diagnostic_code::SchemaDdlAdmissionCode::SetNotNullValidationFailed,
1970                })
1971            }
1972            Self::SchemaGeneratedFieldAfterDdlField => {
1973                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1974                    boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
1975                })
1976            }
1977            Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
1978        }
1979    }
1980}
1981
1982impl QueryErrorDetail {
1983    /// Return the compact diagnostic code for this query detail.
1984    #[must_use]
1985    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
1986        match self {
1987            Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
1988            Self::NumericNotRepresentable => {
1989                diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
1990            }
1991            Self::UnsupportedSqlFeature { .. } => {
1992                diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
1993            }
1994            Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
1995            Self::UnsupportedProjection { .. } => {
1996                diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
1997            }
1998            Self::UnknownAggregateTargetField => {
1999                diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2000            }
2001            Self::ResultShapeMismatch { .. } => {
2002                diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
2003            }
2004            Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2005            Self::SqlSurfaceMismatch { .. } => {
2006                diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2007            }
2008            Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2009            Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2010            Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2011        }
2012    }
2013
2014    /// Return compact structured diagnostic detail when the query detail has one.
2015    #[must_use]
2016    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2017        match self {
2018            Self::UnsupportedSqlFeature { feature } => {
2019                Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2020            }
2021            Self::SqlLowering { reason } => {
2022                Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2023            }
2024            Self::UnsupportedProjection { reason } => {
2025                Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2026            }
2027            Self::ResultShapeMismatch { reason } => {
2028                Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
2029            }
2030            Self::QueryReadAdmission { reason } => {
2031                Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2032            }
2033            Self::SqlSurfaceMismatch { mismatch } => {
2034                Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2035                    mismatch: *mismatch,
2036                })
2037            }
2038            Self::SqlWriteBoundary { boundary } => {
2039                Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2040                    boundary: *boundary,
2041                })
2042            }
2043            Self::SchemaDdlAdmission { error } => {
2044                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2045                    reason: error.diagnostic_code(),
2046                })
2047            }
2048            Self::NumericOverflow
2049            | Self::NumericNotRepresentable
2050            | Self::UnknownAggregateTargetField
2051            | Self::StaleSchemaRevision => None,
2052        }
2053    }
2054}
2055
2056impl SchemaDdlAdmissionError {
2057    /// Return the compact diagnostic code for this SQL DDL admission reason.
2058    #[must_use]
2059    pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
2060        match self {
2061            Self::MissingExpectedSchemaVersion => {
2062                diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
2063            }
2064            Self::MissingNextSchemaVersion => {
2065                diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
2066            }
2067            Self::StaleExpectedSchemaVersion => {
2068                diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
2069            }
2070            Self::InvalidExpectedSchemaVersion => {
2071                diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
2072            }
2073            Self::InvalidNextSchemaVersion => {
2074                diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
2075            }
2076            Self::AcceptedSchemaChangeWithoutVersionBump => {
2077                diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
2078            }
2079            Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
2080            Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
2081            Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
2082            Self::FingerprintMethodMismatch => {
2083                diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
2084            }
2085            Self::UnsupportedTransitionClass => {
2086                diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
2087            }
2088            Self::PhysicalRunnerMissing => {
2089                diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
2090            }
2091            Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
2092            Self::PublicationRaceLost => {
2093                diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
2094            }
2095            Self::InvalidAddColumnDefault => {
2096                diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
2097            }
2098            Self::InvalidAlterColumnDefault => {
2099                diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
2100            }
2101            Self::GeneratedIndexDropRejected => {
2102                diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
2103            }
2104            Self::SchemaRewriteRequiresMigration => {
2105                diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
2106            }
2107            Self::SchemaTransitionBudgetExceeded { .. } => {
2108                diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
2109            }
2110            Self::GeneratedFieldDefaultChangeRejected => {
2111                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
2112            }
2113            Self::GeneratedFieldNullabilityChangeRejected => {
2114                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
2115            }
2116            Self::SetNotNullValidationFailed => {
2117                diagnostic_code::SchemaDdlAdmissionCode::SetNotNullValidationFailed
2118            }
2119            Self::RowLayoutVersionExhausted => {
2120                diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
2121            }
2122        }
2123    }
2124}
2125
2126///
2127/// ErrorClass
2128/// Internal error taxonomy for runtime classification.
2129/// Not a stable API; may change without notice.
2130///
2131
2132#[repr(u8)]
2133#[derive(Clone, Copy, Eq, PartialEq)]
2134pub enum ErrorClass {
2135    Corruption,
2136    IncompatiblePersistedFormat,
2137    NotFound,
2138    Internal,
2139    Conflict,
2140    Unsupported,
2141    InvariantViolation,
2142}
2143
2144impl ErrorClass {
2145    /// Return a compact diagnostic code for this broad class and origin pair.
2146    #[must_use]
2147    pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
2148        match self {
2149            Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
2150                diagnostic_code::DiagnosticCode::StoreCorruption
2151            }
2152            Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
2153            Self::IncompatiblePersistedFormat => {
2154                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2155            }
2156            Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
2157                diagnostic_code::DiagnosticCode::StoreNotFound
2158            }
2159            Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
2160            Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
2161            Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
2162            Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
2163                diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
2164            }
2165            Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
2166            Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
2167                diagnostic_code::DiagnosticCode::StoreInvariantViolation
2168            }
2169            Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
2170        }
2171    }
2172}
2173
2174impl fmt::Debug for ErrorClass {
2175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2176        write!(f, "{}", *self as u8)
2177    }
2178}
2179
2180///
2181/// ErrorOrigin
2182/// Internal origin taxonomy for runtime classification.
2183/// Not a stable API; may change without notice.
2184///
2185
2186#[repr(u8)]
2187#[derive(Clone, Copy, Eq, PartialEq)]
2188pub enum ErrorOrigin {
2189    Serialize,
2190    Store,
2191    Index,
2192    Identity,
2193    Query,
2194    Planner,
2195    Cursor,
2196    Recovery,
2197    Response,
2198    Executor,
2199    Interface,
2200}
2201
2202impl ErrorOrigin {
2203    /// Return the compact diagnostic origin for this internal origin.
2204    #[must_use]
2205    pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
2206        match self {
2207            Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
2208            Self::Store => diagnostic_code::ErrorOrigin::Store,
2209            Self::Index => diagnostic_code::ErrorOrigin::Index,
2210            Self::Identity => diagnostic_code::ErrorOrigin::Identity,
2211            Self::Query => diagnostic_code::ErrorOrigin::Query,
2212            Self::Planner => diagnostic_code::ErrorOrigin::Planner,
2213            Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
2214            Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
2215            Self::Response => diagnostic_code::ErrorOrigin::Response,
2216            Self::Executor => diagnostic_code::ErrorOrigin::Executor,
2217            Self::Interface => diagnostic_code::ErrorOrigin::Interface,
2218        }
2219    }
2220}
2221
2222impl fmt::Debug for ErrorOrigin {
2223    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2224        write!(f, "{}", *self as u8)
2225    }
2226}