Skip to main content

icydb_core/error/
mod.rs

1//! Module: error
2//!
3//! Defines the canonical runtime error taxonomy for `icydb-core`.
4//! This module owns the shared error classes, origins, details, and
5//! constructor entry points used across storage, planning, execution, and
6//! serialization boundaries.
7
8#[cfg(test)]
9mod tests;
10
11use candid::CandidType;
12use icydb_diagnostic_code as diagnostic_code;
13use serde::Deserialize;
14use std::fmt;
15
16pub(crate) const COMPACT_QUERY_DIAGNOSTIC_MESSAGE: &str = "query diagnostic";
17const COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE: &str = "runtime diagnostic";
18const COMPACT_STORE_DIAGNOSTIC_MESSAGE: &str = "store diagnostic";
19const COMPACT_INDEX_DIAGNOSTIC_MESSAGE: &str = "index diagnostic";
20const COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE: &str = "serialize diagnostic";
21const COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE: &str = "identity diagnostic";
22
23const fn compact_message_for(_class: ErrorClass, origin: ErrorOrigin) -> &'static str {
24    match origin {
25        ErrorOrigin::Serialize => COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE,
26        ErrorOrigin::Store => COMPACT_STORE_DIAGNOSTIC_MESSAGE,
27        ErrorOrigin::Index => COMPACT_INDEX_DIAGNOSTIC_MESSAGE,
28        ErrorOrigin::Identity => COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE,
29        ErrorOrigin::Query | ErrorOrigin::Planner | ErrorOrigin::Response => {
30            COMPACT_QUERY_DIAGNOSTIC_MESSAGE
31        }
32        ErrorOrigin::Cursor
33        | ErrorOrigin::Recovery
34        | ErrorOrigin::Executor
35        | ErrorOrigin::Interface => COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE,
36    }
37}
38
39// ============================================================================
40// INTERNAL ERROR TAXONOMY — ARCHITECTURAL CONTRACT
41// ============================================================================
42//
43// This file defines the canonical runtime error classification system for
44// icydb-core. It is the single source of truth for:
45//
46//   • ErrorClass   (semantic domain)
47//   • ErrorOrigin  (subsystem boundary)
48//   • Structured detail payloads
49//   • Canonical constructor entry points
50//
51// -----------------------------------------------------------------------------
52// DESIGN INTENT
53// -----------------------------------------------------------------------------
54//
55// 1. InternalError is a *taxonomy carrier*, not a formatting utility.
56//
57//    - ErrorClass represents semantic meaning (corruption, invariant_violation,
58//      unsupported, etc).
59//    - ErrorOrigin represents the subsystem boundary (store, index, query,
60//      executor, serialize, interface, etc).
61//    - The (class, origin) pair must remain stable and intentional.
62//
63// 2. Call sites MUST prefer canonical constructors.
64//
65//    Do NOT construct errors manually via:
66//        InternalError::new(class, origin)
67//    unless you are defining a new canonical helper here.
68//
69//    If a pattern appears more than once, centralize it here.
70//
71// 3. Constructors in this file must represent real architectural boundaries.
72//
73//    Add a new helper ONLY if it:
74//
75//      • Encodes a cross-cutting invariant,
76//      • Represents a subsystem boundary,
77//      • Or prevents taxonomy drift across call sites.
78//
79//    Do NOT add feature-specific helpers.
80//    Do NOT add one-off formatting helpers.
81//    Do NOT turn this file into a generic message factory.
82//
83// 4. ErrorDetail must align with ErrorOrigin.
84//
85//    If detail is present, it MUST correspond to the origin.
86//    Do not attach mismatched detail variants.
87//
88// 5. Plan-layer errors are NOT runtime failures.
89//
90//    PlanError and CursorPlanError must be translated into
91//    executor/query invariants via the canonical mapping functions.
92//    Do not leak plan-layer error types across execution boundaries.
93//
94// 6. Preserve taxonomy stability.
95//
96//    Do NOT:
97//      • Merge error classes.
98//      • Reclassify corruption as internal.
99//      • Downgrade invariant violations.
100//      • Introduce ambiguous class/origin combinations.
101//
102//    Any change to ErrorClass or ErrorOrigin is an architectural change
103//    and must be reviewed accordingly.
104//
105// -----------------------------------------------------------------------------
106// NON-GOALS
107// -----------------------------------------------------------------------------
108//
109// This is NOT:
110//
111//   • A public API contract.
112//   • A generic error abstraction layer.
113//   • A feature-specific message builder.
114//   • A dumping ground for temporary error conversions.
115//
116// -----------------------------------------------------------------------------
117// MAINTENANCE GUIDELINES
118// -----------------------------------------------------------------------------
119//
120// When modifying this file:
121//
122//   1. Ensure classification semantics remain consistent.
123//   2. Avoid constructor proliferation.
124//   3. Prefer narrow, origin-specific helpers over ad-hoc new(...).
125//   4. Keep formatting minimal and standardized.
126//   5. Keep this file boring and stable.
127//
128// If this file grows rapidly, something is wrong at the call sites.
129//
130// ============================================================================
131
132///
133/// InternalError
134///
135/// Structured runtime error with a stable internal classification.
136/// Not a stable API; intended for internal use and may change without notice.
137///
138
139pub struct InternalError {
140    pub(crate) class: ErrorClass,
141    pub(crate) origin: ErrorOrigin,
142
143    /// Optional structured error detail.
144    /// The variant (if present) must correspond to `origin`.
145    pub(crate) detail: Option<ErrorDetail>,
146}
147
148#[expect(
149    clippy::missing_const_for_fn,
150    reason = "internal error constructors stay non-const so compact diagnostic construction does not force const churn across subsystem helper seams"
151)]
152impl InternalError {
153    /// Construct an InternalError with optional origin-specific detail.
154    /// This constructor provides default StoreError details for certain
155    /// (class, origin) combinations but does not guarantee a detail payload.
156    #[must_use]
157    #[cold]
158    #[inline(never)]
159    pub fn new(class: ErrorClass, origin: ErrorOrigin) -> Self {
160        let detail = match (class, origin) {
161            (ErrorClass::Corruption, ErrorOrigin::Store) => {
162                Some(ErrorDetail::Store(StoreError::Corrupt))
163            }
164            (ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
165                Some(ErrorDetail::Store(StoreError::InvariantViolation))
166            }
167            _ => None,
168        };
169
170        Self {
171            class,
172            origin,
173            detail,
174        }
175    }
176
177    /// Return the internal error class taxonomy.
178    #[must_use]
179    pub const fn class(&self) -> ErrorClass {
180        self.class
181    }
182
183    /// Return the internal error origin taxonomy.
184    #[must_use]
185    pub const fn origin(&self) -> ErrorOrigin {
186        self.origin
187    }
188
189    /// Return the rendered internal error message.
190    #[must_use]
191    pub const fn message(&self) -> &'static str {
192        compact_message_for(self.class, self.origin)
193    }
194
195    /// Return the optional structured detail payload.
196    #[must_use]
197    pub const fn detail(&self) -> Option<&ErrorDetail> {
198        self.detail.as_ref()
199    }
200
201    /// Borrow the accepted constraint diagnostic carried by this error.
202    #[must_use]
203    pub fn constraint_diagnostic(&self) -> Option<&ConstraintDiagnostic> {
204        match self.detail.as_ref() {
205            Some(ErrorDetail::Executor(detail)) => detail.constraint_diagnostic(),
206            Some(
207                ErrorDetail::Store(_)
208                | ErrorDetail::Query(_)
209                | ErrorDetail::Recovery(_)
210                | ErrorDetail::Serialize(_),
211            )
212            | None => None,
213        }
214    }
215
216    /// Return compact diagnostic identity for this internal error.
217    #[must_use]
218    pub fn diagnostic(&self) -> diagnostic_code::Diagnostic {
219        diagnostic_code::Diagnostic::new(
220            self.diagnostic_code(),
221            self.origin.diagnostic_origin(),
222            self.detail
223                .as_ref()
224                .and_then(ErrorDetail::diagnostic_detail),
225        )
226    }
227
228    /// Return the compact diagnostic code for this internal error.
229    #[must_use]
230    pub fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
231        self.detail.as_ref().map_or_else(
232            || self.class.diagnostic_code(self.origin),
233            ErrorDetail::diagnostic_code,
234        )
235    }
236
237    /// Consume and return the rendered internal error message.
238    #[must_use]
239    pub fn into_message(self) -> String {
240        self.message().to_string()
241    }
242
243    /// Construct an error while preserving an explicit class/origin taxonomy pair.
244    #[cold]
245    #[inline(never)]
246    pub(crate) fn classified(class: ErrorClass, origin: ErrorOrigin) -> Self {
247        Self::new(class, origin)
248    }
249
250    /// Rebuild this error with a new origin while preserving class taxonomy.
251    ///
252    /// Origin-scoped detail payloads are intentionally dropped when re-origining.
253    #[cold]
254    #[inline(never)]
255    pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
256        Self::classified(self.class, origin)
257    }
258
259    /// Construct an index-origin invariant violation.
260    #[cold]
261    #[inline(never)]
262    pub(crate) fn index_invariant() -> Self {
263        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
264    }
265
266    /// Construct the canonical index field-count invariant for key building.
267    pub(crate) fn index_key_field_count_exceeds_max(
268        _index_name: &str,
269        _field_count: usize,
270        _max_fields: usize,
271    ) -> Self {
272        Self::index_invariant()
273    }
274
275    /// Construct the canonical index-key source-field-missing-on-model invariant.
276    pub(crate) fn index_key_item_field_missing_on_entity_model(_field: &str) -> Self {
277        Self::index_invariant()
278    }
279
280    /// Construct the canonical index-key source-field-missing-on-row invariant.
281    pub(crate) fn index_key_item_field_missing_on_lookup_row(_field: &str) -> Self {
282        Self::index_invariant()
283    }
284
285    /// Construct the canonical index-expression source-type mismatch invariant.
286    pub(crate) fn index_expression_source_type_mismatch(
287        _index_name: &str,
288        _expression: impl Sized,
289        _expected: impl Sized,
290        _source_label: &str,
291    ) -> Self {
292        Self::index_invariant()
293    }
294
295    /// Construct a planner-origin invariant violation for executor-boundary
296    /// contract drift.
297    #[cold]
298    #[inline(never)]
299    pub(crate) fn planner_executor_invariant() -> Self {
300        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
301    }
302
303    /// Construct a query-origin invariant violation for executor-boundary
304    /// contract drift.
305    #[cold]
306    #[inline(never)]
307    pub(crate) fn query_executor_invariant() -> Self {
308        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
309    }
310
311    /// Construct a cursor-origin invariant violation for executor-boundary
312    /// contract drift.
313    #[cold]
314    #[inline(never)]
315    pub(crate) fn cursor_executor_invariant() -> Self {
316        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
317    }
318
319    /// Construct an executor-origin invariant violation.
320    #[cold]
321    #[inline(never)]
322    pub(crate) fn executor_invariant() -> Self {
323        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
324    }
325
326    /// Construct an executor-origin conflict.
327    #[cold]
328    #[inline(never)]
329    pub(crate) fn executor_conflict() -> Self {
330        Self::new(ErrorClass::Conflict, ErrorOrigin::Executor)
331    }
332
333    /// Construct an executor-origin internal error.
334    #[cold]
335    #[inline(never)]
336    pub(crate) fn executor_internal() -> Self {
337        Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
338    }
339
340    /// Construct an executor-origin unsupported error.
341    #[cold]
342    #[inline(never)]
343    pub(crate) fn executor_unsupported() -> Self {
344        Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
345    }
346
347    /// Construct an executor-origin save-preflight primary-key missing invariant.
348    pub(crate) fn mutation_entity_primary_key_missing(
349        _entity_path: &str,
350        _field_name: &str,
351    ) -> Self {
352        Self::executor_invariant()
353    }
354
355    /// Construct an executor-origin save-preflight primary-key invalid-value invariant.
356    pub(crate) fn mutation_entity_primary_key_invalid_value(
357        _entity_path: &str,
358        _field_name: &str,
359        _value: &crate::value::Value,
360    ) -> Self {
361        Self::executor_invariant()
362    }
363
364    /// Construct an executor-origin save-preflight primary-key type mismatch invariant.
365    pub(crate) fn mutation_entity_primary_key_type_mismatch(
366        _entity_path: &str,
367        _field_name: &str,
368        _value: &crate::value::Value,
369    ) -> Self {
370        Self::executor_invariant()
371    }
372
373    /// Construct an executor-origin save-preflight primary-key identity mismatch invariant.
374    pub(crate) fn mutation_entity_primary_key_mismatch(
375        _entity_path: &str,
376        _field_name: &str,
377        _field_value: &crate::value::Value,
378        _identity_key: &crate::value::Value,
379    ) -> Self {
380        Self::executor_invariant()
381    }
382
383    /// Construct an executor-origin save-preflight field-missing invariant.
384    pub(crate) fn mutation_entity_field_missing(
385        _entity_path: &str,
386        _field_name: &str,
387        _indexed: bool,
388    ) -> Self {
389        Self::executor_invariant()
390    }
391
392    /// Construct an executor-origin sparse structural patch required-field rejection.
393    pub(crate) fn mutation_structural_patch_required_field_missing(
394        entity_path: &str,
395        field_name: &str,
396    ) -> Self {
397        Self::mutation_required_field_missing(entity_path, field_name)
398    }
399
400    /// Construct an executor-origin save-preflight field-type mismatch invariant.
401    pub(crate) fn mutation_entity_field_type_mismatch(
402        _entity_path: &str,
403        _field_name: &str,
404        _value: &crate::value::Value,
405    ) -> Self {
406        Self::executor_invariant()
407    }
408
409    /// Construct an executor-origin database-owned-field authorship rejection.
410    pub(crate) fn mutation_database_owned_field_explicit(
411        _entity_path: &str,
412        _field_name: &str,
413    ) -> Self {
414        Self::executor_unsupported()
415    }
416
417    /// Construct an executor-origin protected-field sanitizer rejection.
418    pub(crate) fn mutation_sanitizer_protected_field_changed(
419        _entity_path: &str,
420        _field_name: &str,
421    ) -> Self {
422        Self::executor_unsupported()
423    }
424
425    /// Construct an executor-origin required-field omission rejection.
426    #[must_use]
427    pub fn mutation_required_field_missing(_entity_path: &str, _field_names: &str) -> Self {
428        Self {
429            class: ErrorClass::Unsupported,
430            origin: ErrorOrigin::Executor,
431            detail: Some(ErrorDetail::Executor(
432                ExecutorErrorDetail::MutationRequiredFieldMissing,
433            )),
434        }
435    }
436
437    /// Construct an executor-origin accepted constraint or activation-gate violation.
438    pub(crate) fn mutation_constraint_violation(diagnostic: ConstraintDiagnostic) -> Self {
439        Self {
440            class: ErrorClass::InvariantViolation,
441            origin: ErrorOrigin::Executor,
442            detail: Some(ErrorDetail::Executor(
443                ExecutorErrorDetail::ConstraintViolation {
444                    diagnostic: Box::new(diagnostic),
445                },
446            )),
447        }
448    }
449
450    /// Construct an executor-origin corruption failure for row-constraint authority.
451    pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
452        Self {
453            class: ErrorClass::Corruption,
454            origin: ErrorOrigin::Executor,
455            detail: Some(ErrorDetail::Executor(
456                ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
457            )),
458        }
459    }
460
461    /// Construct one typed migration conflict for an incomplete activation gate.
462    pub(crate) fn mutation_constraint_activation_write_blocked(
463        diagnostic: ConstraintDiagnostic,
464    ) -> Self {
465        Self {
466            class: ErrorClass::Conflict,
467            origin: ErrorOrigin::Executor,
468            detail: Some(ErrorDetail::Executor(
469                ExecutorErrorDetail::ConstraintActivationWriteBlocked {
470                    diagnostic: Box::new(diagnostic),
471                },
472            )),
473        }
474    }
475
476    /// Construct an executor-origin mutation result invariant.
477    ///
478    /// This constructor lands ahead of the public structural mutation surface,
479    /// so the library target may not route through it until that caller exists.
480    pub(crate) fn mutation_structural_after_image_invalid(
481        _entity_path: &str,
482        _data_key: impl Sized,
483        _detail: impl Sized,
484    ) -> Self {
485        Self::executor_invariant()
486    }
487
488    /// Construct an executor-origin mutation unknown-field invariant.
489    pub(crate) fn mutation_structural_field_unknown(_entity_path: &str, _field_name: &str) -> Self {
490        Self::executor_invariant()
491    }
492
493    /// Construct an executor-origin save-preflight decimal-scale unsupported error.
494    pub(crate) fn mutation_decimal_scale_mismatch(
495        _entity_path: &str,
496        _field_name: &str,
497        _expected_scale: impl Sized,
498        _actual_scale: impl Sized,
499    ) -> Self {
500        Self::executor_unsupported()
501    }
502
503    /// Construct an executor-origin save-preflight text-length unsupported error.
504    pub(crate) fn mutation_text_max_len_exceeded(
505        _entity_path: &str,
506        _field_name: &str,
507        _max_len: impl Sized,
508        _actual_len: impl Sized,
509    ) -> Self {
510        Self::executor_unsupported()
511    }
512
513    /// Construct an executor-origin save-preflight set-encoding invariant.
514    pub(crate) fn mutation_set_field_list_required(_entity_path: &str, _field_name: &str) -> Self {
515        Self::executor_invariant()
516    }
517
518    /// Construct an executor-origin save-preflight set-canonicality invariant.
519    pub(crate) fn mutation_set_field_not_canonical(_entity_path: &str, _field_name: &str) -> Self {
520        Self::executor_invariant()
521    }
522
523    /// Construct an executor-origin save-preflight map-encoding invariant.
524    pub(crate) fn mutation_map_field_map_required(_entity_path: &str, _field_name: &str) -> Self {
525        Self::executor_invariant()
526    }
527
528    /// Construct an executor-origin save-preflight map-entry invariant.
529    pub(crate) fn mutation_map_field_entries_invalid(
530        _entity_path: &str,
531        _field_name: &str,
532        _detail: impl Sized,
533    ) -> Self {
534        Self::executor_invariant()
535    }
536
537    /// Construct an executor-origin save-preflight map-canonicality invariant.
538    pub(crate) fn mutation_map_field_entries_not_canonical(
539        _entity_path: &str,
540        _field_name: &str,
541    ) -> Self {
542        Self::executor_invariant()
543    }
544
545    /// Construct a query-origin scalar page invariant for missing order at the cursor boundary.
546    pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
547        Self::query_executor_invariant()
548    }
549
550    /// Construct a query-origin scalar page invariant for cursor-before-ordering drift.
551    pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
552        Self::query_executor_invariant()
553    }
554
555    /// Construct a query-origin scalar page invariant for pagination-before-ordering drift.
556    pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
557        Self::query_executor_invariant()
558    }
559
560    /// Construct a query-origin load-entrypoint invariant for non-load plans.
561    pub(crate) fn load_executor_load_plan_required() -> Self {
562        Self::query_executor_invariant()
563    }
564
565    /// Construct an executor-origin delete-entrypoint unsupported grouped-mode error.
566    pub(crate) fn delete_executor_grouped_unsupported() -> Self {
567        Self::executor_unsupported()
568    }
569
570    /// Construct a query-origin delete-entrypoint invariant for non-delete plans.
571    pub(crate) fn delete_executor_delete_plan_required() -> Self {
572        Self::query_executor_invariant()
573    }
574
575    /// Construct a query-origin aggregate kernel invariant for fold-mode contract drift.
576    pub(crate) fn aggregate_fold_mode_terminal_contract_required() -> Self {
577        Self::query_executor_invariant()
578    }
579
580    /// Construct a query-origin fast-stream invariant for route kind/request mismatch.
581    pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
582        Self::query_executor_invariant()
583    }
584
585    /// Construct a query-origin scan invariant for missing index-prefix executable specs.
586    pub(crate) fn secondary_index_prefix_spec_required() -> Self {
587        Self::query_executor_invariant()
588    }
589
590    /// Construct a query-origin scan invariant for missing index-range executable specs.
591    pub(crate) fn index_range_limit_spec_required() -> Self {
592        Self::query_executor_invariant()
593    }
594
595    /// Construct an executor-origin mutation conflict for duplicate atomic save keys.
596    pub(crate) fn mutation_atomic_save_duplicate_key(_entity_path: &str, _key: impl Sized) -> Self {
597        Self::executor_conflict()
598    }
599
600    /// Construct an executor-origin mutation invariant for index-store generation drift.
601    pub(crate) fn mutation_index_store_generation_changed(
602        _expected_generation: u64,
603        _observed_generation: u64,
604    ) -> Self {
605        Self::executor_invariant()
606    }
607
608    /// Construct a planner-origin invariant violation.
609    #[cold]
610    #[inline(never)]
611    pub(crate) fn planner_invariant() -> Self {
612        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
613    }
614
615    /// Construct a planner-origin invalid-logical-plan invariant.
616    pub(crate) fn query_invalid_logical_plan() -> Self {
617        Self::planner_invariant()
618    }
619
620    /// Construct a store-origin invariant violation.
621    pub(crate) fn store_invariant() -> Self {
622        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
623    }
624
625    /// Construct the canonical duplicate runtime-hook entity-tag invariant.
626    pub(crate) fn duplicate_runtime_hooks_for_entity_tag(
627        _entity_tag: crate::types::EntityTag,
628    ) -> Self {
629        Self::store_invariant()
630    }
631
632    /// Construct the canonical duplicate runtime-hook entity-path invariant.
633    pub(crate) fn duplicate_runtime_hooks_for_entity_path(_entity_path: &str) -> Self {
634        Self::store_invariant()
635    }
636
637    /// Construct a store-origin internal error.
638    #[cold]
639    #[inline(never)]
640    pub(crate) fn store_internal() -> Self {
641        Self::new(ErrorClass::Internal, ErrorOrigin::Store)
642    }
643
644    /// Construct the canonical unconfigured commit-memory id internal error.
645    pub(crate) fn commit_memory_id_unconfigured() -> Self {
646        Self::store_internal()
647    }
648
649    /// Construct the canonical commit-memory id mismatch internal error.
650    pub(crate) fn commit_memory_id_mismatch(_cached_id: u8, _configured_id: u8) -> Self {
651        Self::store_internal()
652    }
653
654    /// Construct the canonical commit-memory stable-key mismatch internal error.
655    pub(crate) fn commit_memory_stable_key_mismatch(
656        _cached_key: &str,
657        _configured_key: &str,
658    ) -> Self {
659        Self::store_internal()
660    }
661
662    /// Construct the canonical database-incarnation generation failure.
663    pub(crate) fn database_incarnation_generation_failed() -> Self {
664        Self::store_internal()
665    }
666
667    /// Construct the canonical zero database-incarnation corruption error.
668    pub(crate) fn database_incarnation_invalid() -> Self {
669        Self::store_corruption()
670    }
671
672    /// Construct a recovery-origin incompatible store-format error.
673    pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
674        Self {
675            class: ErrorClass::IncompatiblePersistedFormat,
676            origin: ErrorOrigin::Recovery,
677            detail: Some(ErrorDetail::Recovery(
678                RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
679            )),
680        }
681    }
682
683    /// Construct a recovery-origin malformed store-format marker error.
684    pub(crate) fn recovery_malformed_database_format_marker(
685        reason: RecoveryFormatMarkerError,
686    ) -> Self {
687        Self {
688            class: ErrorClass::Corruption,
689            origin: ErrorOrigin::Recovery,
690            detail: Some(ErrorDetail::Recovery(
691                RecoveryErrorDetail::MalformedFormatMarker { reason },
692            )),
693        }
694    }
695
696    /// Construct a recovery-origin boot control-memory failure.
697    pub(crate) fn recovery_database_format_control_unavailable() -> Self {
698        Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
699    }
700
701    /// Construct a commit control-memory growth failure.
702    pub(crate) fn commit_control_memory_growth_failed() -> Self {
703        Self::store_internal()
704    }
705
706    /// Construct a store-format memory registration failure.
707    #[cfg(not(test))]
708    pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
709        Self::store_internal()
710    }
711
712    /// Construct the canonical missing rollback-row invariant for delete execution.
713    pub(crate) fn delete_rollback_row_required() -> Self {
714        Self::store_internal()
715    }
716
717    /// Construct the canonical recovered-effect verification failure.
718    pub(crate) fn recovery_effect_verification_failed() -> Self {
719        Self::store_corruption()
720    }
721
722    /// Construct an index-origin internal error.
723    #[cold]
724    #[inline(never)]
725    pub(crate) fn index_internal() -> Self {
726        Self::new(ErrorClass::Internal, ErrorOrigin::Index)
727    }
728
729    /// Construct the canonical missing old entity-key internal error for structural index removal.
730    pub(crate) fn structural_index_removal_entity_key_required() -> Self {
731        Self::index_internal()
732    }
733
734    /// Construct the canonical missing new entity-key internal error for structural index insertion.
735    pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
736        Self::index_internal()
737    }
738
739    /// Construct the canonical missing old entity-key internal error for index commit-op removal.
740    pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
741        Self::index_internal()
742    }
743
744    /// Construct the canonical missing new entity-key internal error for index commit-op insertion.
745    pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
746        Self::index_internal()
747    }
748
749    /// Construct a query-origin internal error.
750    #[cfg(test)]
751    pub(crate) fn query_internal() -> Self {
752        Self::new(ErrorClass::Internal, ErrorOrigin::Query)
753    }
754
755    /// Construct a query-origin unsupported error.
756    #[cold]
757    #[inline(never)]
758    pub(crate) fn query_unsupported() -> Self {
759        Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
760    }
761
762    /// Construct a query-origin conflict for execution against a superseded
763    /// accepted schema revision.
764    #[cold]
765    #[inline(never)]
766    pub(crate) fn query_stale_accepted_schema_revision(
767        _expected_revision: u64,
768        _current_revision: Option<u64>,
769    ) -> Self {
770        Self {
771            class: ErrorClass::Conflict,
772            origin: ErrorOrigin::Query,
773            detail: Some(ErrorDetail::Query(QueryErrorDetail::StaleSchemaRevision)),
774        }
775    }
776
777    /// Construct a query-origin SQL DDL admission error with structured detail.
778    #[cold]
779    #[inline(never)]
780    #[cfg(feature = "sql")]
781    pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
782        Self {
783            class: ErrorClass::Unsupported,
784            origin: ErrorOrigin::Query,
785            detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
786                error,
787            })),
788        }
789    }
790
791    /// Construct a query-origin numeric overflow error with structured detail.
792    #[cold]
793    #[inline(never)]
794    pub(crate) fn query_numeric_overflow() -> Self {
795        Self {
796            class: ErrorClass::Unsupported,
797            origin: ErrorOrigin::Query,
798            detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
799        }
800    }
801
802    /// Construct a query-origin non-representable numeric result error with
803    /// structured detail.
804    #[cold]
805    #[inline(never)]
806    pub(crate) fn query_numeric_not_representable() -> Self {
807        Self {
808            class: ErrorClass::Unsupported,
809            origin: ErrorOrigin::Query,
810            detail: Some(ErrorDetail::Query(
811                QueryErrorDetail::NumericNotRepresentable,
812            )),
813        }
814    }
815
816    /// Construct a serialize-origin internal error.
817    #[cold]
818    #[inline(never)]
819    pub(crate) fn serialize_internal() -> Self {
820        Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
821    }
822
823    /// Construct the canonical persisted-row encode internal error.
824    pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
825        Self::persisted_row_encode_internal()
826    }
827
828    /// Construct the compact persisted-row encode internal error.
829    pub(crate) fn persisted_row_encode_internal() -> Self {
830        Self::serialize_internal()
831    }
832
833    /// Construct the canonical persisted-row field encode internal error.
834    pub(crate) fn persisted_row_field_encode_failed(field_name: &str, _detail: impl Sized) -> Self {
835        Self::persisted_row_field_encode_internal(field_name)
836    }
837
838    /// Construct the compact persisted-row field encode internal error.
839    pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
840        Self::persisted_row_encode_internal()
841    }
842
843    /// Construct the canonical bytes(field) value encode internal error.
844    pub(crate) fn bytes_field_value_encode_failed(_detail: impl Sized) -> Self {
845        Self::serialize_internal()
846    }
847
848    /// Construct a store-origin corruption error.
849    #[cold]
850    #[inline(never)]
851    pub(crate) fn store_corruption() -> Self {
852        Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
853    }
854
855    /// Construct a store-origin commit-marker corruption error.
856    pub(crate) fn commit_corruption() -> Self {
857        Self::store_corruption()
858    }
859
860    /// Construct a store-origin commit-marker component corruption error.
861    pub(crate) fn commit_component_corruption() -> Self {
862        Self::commit_corruption()
863    }
864
865    /// Construct the canonical commit-marker id generation internal error.
866    pub(crate) fn commit_id_generation_failed() -> Self {
867        Self::store_internal()
868    }
869
870    /// Construct the canonical commit-marker payload u32-length-limit error.
871    pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
872        Self::store_unsupported()
873    }
874
875    /// Construct the canonical commit-marker component invalid-length corruption error.
876    pub(crate) fn commit_component_length_invalid() -> Self {
877        Self::commit_corruption()
878    }
879
880    /// Construct the canonical commit-marker max-size corruption error.
881    pub(crate) fn commit_marker_exceeds_max_size() -> Self {
882        Self::commit_corruption()
883    }
884
885    /// Construct the canonical commit-control slot max-size unsupported error.
886    pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
887        Self::store_unsupported()
888    }
889
890    /// Construct the canonical commit-control marker-bytes length-limit error.
891    pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
892        Self::store_unsupported()
893    }
894
895    /// Construct the canonical startup index-rebuild invalid-data-key corruption error.
896    pub(crate) fn startup_index_rebuild_invalid_data_key() -> Self {
897        Self::store_corruption()
898    }
899
900    /// Construct an index-origin corruption error.
901    #[cold]
902    #[inline(never)]
903    pub(crate) fn index_corruption() -> Self {
904        Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
905    }
906
907    /// Construct the canonical unique-validation corruption wrapper.
908    pub(crate) fn index_unique_validation_corruption() -> Self {
909        Self::index_plan_index_corruption()
910    }
911
912    /// Construct the canonical structural index-entry corruption wrapper.
913    pub(crate) fn structural_index_entry_corruption() -> Self {
914        Self::index_plan_index_corruption()
915    }
916
917    /// Construct the canonical missing new entity-key invariant during unique validation.
918    pub(crate) fn index_unique_validation_entity_key_required() -> Self {
919        Self::index_invariant()
920    }
921
922    /// Construct the canonical unique-validation structural row-decode corruption error.
923    pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
924        Self::index_plan_serialize_corruption()
925    }
926
927    /// Construct the canonical unique-validation primary-key slot decode corruption error.
928    pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
929        Self::index_plan_serialize_corruption()
930    }
931
932    /// Construct the canonical unique-validation stored key rebuild corruption error.
933    pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
934        Self::index_plan_serialize_corruption()
935    }
936
937    /// Construct the canonical unique-validation missing-row corruption error.
938    pub(crate) fn index_unique_validation_row_required() -> Self {
939        Self::index_plan_store_corruption()
940    }
941
942    /// Construct the canonical index-only predicate missing-component invariant.
943    pub(crate) fn index_only_predicate_component_required() -> Self {
944        Self::index_invariant()
945    }
946
947    /// Construct the canonical index-scan continuation-envelope invariant.
948    pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
949        Self::index_invariant()
950    }
951
952    /// Construct the canonical index-scan continuation-advancement invariant.
953    pub(crate) fn index_scan_continuation_advancement_required() -> Self {
954        Self::index_invariant()
955    }
956
957    /// Construct the canonical index-scan key-decode corruption error.
958    pub(crate) fn index_scan_key_corrupted_during(
959        _context: &'static str,
960        _err: impl Sized,
961    ) -> Self {
962        Self::index_corruption()
963    }
964
965    /// Construct the canonical index-scan missing projection-component invariant.
966    pub(crate) fn index_projection_component_required(
967        _index_name: &str,
968        _component_index: usize,
969    ) -> Self {
970        Self::index_invariant()
971    }
972
973    /// Construct the canonical scan-time index-entry decode corruption error.
974    pub(crate) fn index_entry_decode_failed() -> Self {
975        Self::index_corruption()
976    }
977
978    /// Construct a serialize-origin corruption error.
979    pub(crate) fn serialize_corruption() -> Self {
980        Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
981    }
982
983    /// Construct the canonical persisted-row decode corruption error.
984    pub(crate) fn persisted_row_decode_failed(_detail: impl Sized) -> Self {
985        Self::persisted_row_decode_corruption()
986    }
987
988    /// Construct the compact persisted-row decode corruption error.
989    pub(crate) fn persisted_row_decode_corruption() -> Self {
990        Self::serialize_corruption()
991    }
992
993    /// Construct a persisted-row layout-window corruption error.
994    pub(crate) fn persisted_row_layout_outside_accepted_window() -> Self {
995        Self {
996            class: ErrorClass::Corruption,
997            origin: ErrorOrigin::Serialize,
998            detail: Some(ErrorDetail::Serialize(
999                SerializeErrorDetail::PersistedRowLayoutOutsideAcceptedWindow,
1000            )),
1001        }
1002    }
1003
1004    /// Construct a persisted-row stamped-layout slot-count corruption error.
1005    pub(crate) fn persisted_row_slot_count_mismatch() -> Self {
1006        Self {
1007            class: ErrorClass::Corruption,
1008            origin: ErrorOrigin::Serialize,
1009            detail: Some(ErrorDetail::Serialize(
1010                SerializeErrorDetail::PersistedRowSlotCountMismatch,
1011            )),
1012        }
1013    }
1014
1015    /// Construct the canonical persisted-row field decode corruption error.
1016    pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
1017        Self::persisted_row_field_decode_corruption(field_name)
1018    }
1019
1020    /// Construct the compact persisted-row field decode corruption error.
1021    pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
1022        Self::persisted_row_decode_corruption()
1023    }
1024
1025    /// Construct the canonical persisted-row field-kind decode corruption error.
1026    pub(crate) fn persisted_row_field_kind_decode_failed(
1027        field_name: &str,
1028        _field_kind: impl fmt::Debug,
1029        _detail: impl Sized,
1030    ) -> Self {
1031        Self::persisted_row_field_decode_corruption(field_name)
1032    }
1033
1034    /// Construct the canonical persisted-row scalar-payload length corruption error.
1035    pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
1036        Self::persisted_row_field_decode_corruption(field_name)
1037    }
1038
1039    /// Construct the canonical persisted-row scalar-payload empty-body corruption error.
1040    pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
1041        Self::persisted_row_field_decode_corruption(field_name)
1042    }
1043
1044    /// Construct the canonical persisted-row scalar-payload invalid-byte corruption error.
1045    pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
1046        Self::persisted_row_field_decode_corruption(field_name)
1047    }
1048
1049    /// Construct the canonical persisted-row scalar-payload non-finite corruption error.
1050    pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
1051        Self::persisted_row_field_decode_corruption(field_name)
1052    }
1053
1054    /// Construct the canonical persisted-row scalar-payload out-of-range corruption error.
1055    pub(crate) fn persisted_row_field_payload_out_of_range(field_name: &str) -> Self {
1056        Self::persisted_row_field_decode_corruption(field_name)
1057    }
1058
1059    /// Construct the canonical persisted-row invalid text payload corruption error.
1060    pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
1061        Self::persisted_row_field_decode_corruption(field_name)
1062    }
1063
1064    /// Construct the canonical persisted-row structural slot-lookup invariant.
1065    pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
1066        Self::index_invariant()
1067    }
1068
1069    /// Construct the canonical persisted-row structural slot-cache invariant.
1070    pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
1071        _model_path: &str,
1072        _slot: usize,
1073    ) -> Self {
1074        Self::index_invariant()
1075    }
1076
1077    /// Construct the canonical persisted-row primary-key decode corruption error.
1078    pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1079        _data_key: impl fmt::Debug,
1080        _detail: impl Sized,
1081    ) -> Self {
1082        Self::persisted_row_decode_corruption()
1083    }
1084
1085    /// Construct the canonical persisted-row missing primary-key slot corruption error.
1086    pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1087        Self::persisted_row_decode_corruption()
1088    }
1089
1090    /// Construct the canonical persisted-row key mismatch corruption error.
1091    pub(crate) fn persisted_row_key_mismatch() -> Self {
1092        Self::store_corruption()
1093    }
1094
1095    /// Construct the canonical persisted-row missing declared-field corruption error.
1096    pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1097        Self::persisted_row_field_decode_corruption(field_name)
1098    }
1099
1100    /// Construct the canonical data-key entity mismatch corruption error.
1101    pub(crate) fn data_key_entity_mismatch() -> Self {
1102        Self::store_corruption()
1103    }
1104
1105    /// Construct the canonical reverse-index ordinal overflow internal error.
1106    pub(crate) fn reverse_index_ordinal_overflow(
1107        _source_path: &str,
1108        _field_name: &str,
1109        _target_path: &str,
1110        _detail: impl Sized,
1111    ) -> Self {
1112        Self::index_internal()
1113    }
1114
1115    /// Construct the canonical reverse-index entry corruption error.
1116    pub(crate) fn reverse_index_entry_corrupted(
1117        _source_path: &str,
1118        _field_name: &str,
1119        _target_path: &str,
1120        _index_key: impl fmt::Debug,
1121        _detail: impl Sized,
1122    ) -> Self {
1123        Self::index_corruption()
1124    }
1125
1126    /// Construct the canonical relation-target store missing internal error.
1127    pub(crate) fn relation_target_store_missing(
1128        _source_path: &str,
1129        _field_name: &str,
1130        _target_path: &str,
1131        _store_path: &str,
1132        _detail: impl Sized,
1133    ) -> Self {
1134        Self::executor_internal()
1135    }
1136
1137    /// Construct the canonical relation-target key decode corruption error.
1138    pub(crate) fn relation_target_key_decode_failed(
1139        _context_label: &str,
1140        _source_path: &str,
1141        _field_name: &str,
1142        _target_path: &str,
1143        _detail: impl Sized,
1144    ) -> Self {
1145        Self::identity_corruption()
1146    }
1147
1148    /// Construct the canonical relation-target entity mismatch corruption error.
1149    pub(crate) fn relation_target_entity_mismatch(
1150        _context_label: &str,
1151        _source_path: &str,
1152        _field_name: &str,
1153        _target_path: &str,
1154        _target_entity_name: &str,
1155        _expected_tag: impl Sized,
1156        _actual_tag: impl Sized,
1157    ) -> Self {
1158        Self::store_corruption()
1159    }
1160
1161    /// Construct the canonical relation-source row decode corruption error.
1162    pub(crate) fn relation_source_row_decode_failed(
1163        _source_path: &str,
1164        _field_name: &str,
1165        _target_path: &str,
1166        _detail: impl Sized,
1167    ) -> Self {
1168        Self::persisted_row_decode_corruption()
1169    }
1170
1171    /// Construct the canonical relation-source unsupported scalar relation-key corruption error.
1172    pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1173        _source_path: &str,
1174        _field_name: &str,
1175        _target_path: &str,
1176    ) -> Self {
1177        Self::persisted_row_decode_corruption()
1178    }
1179
1180    /// Construct the canonical unsupported relation key-kind corruption error.
1181    pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1182        Self::persisted_row_decode_corruption()
1183    }
1184
1185    /// Construct the canonical reverse-index relation-target decode invariant failure.
1186    pub(crate) fn reverse_index_relation_target_decode_invariant_violated(
1187        _source_path: &str,
1188        _field_name: &str,
1189        _target_path: &str,
1190    ) -> Self {
1191        Self::executor_internal()
1192    }
1193
1194    /// Construct the canonical covering-component empty-payload corruption error.
1195    pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1196        Self::index_corruption()
1197    }
1198
1199    /// Construct the canonical covering-component truncated bool corruption error.
1200    pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1201        Self::index_corruption()
1202    }
1203
1204    /// Construct the canonical covering-component invalid-length corruption error.
1205    pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1206        Self::index_corruption()
1207    }
1208
1209    /// Construct the canonical covering-component invalid-bool corruption error.
1210    pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1211        Self::index_corruption()
1212    }
1213
1214    /// Construct the canonical covering-component invalid text terminator corruption error.
1215    pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1216        Self::index_corruption()
1217    }
1218
1219    /// Construct the canonical covering-component trailing-text corruption error.
1220    pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1221        Self::index_corruption()
1222    }
1223
1224    /// Construct the canonical covering-component invalid-UTF-8 text corruption error.
1225    pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1226        Self::index_corruption()
1227    }
1228
1229    /// Construct the canonical covering-component invalid text escape corruption error.
1230    pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1231        Self::index_corruption()
1232    }
1233
1234    /// Construct the canonical covering-component missing text terminator corruption error.
1235    pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1236        Self::index_corruption()
1237    }
1238
1239    /// Construct the canonical missing persisted-field decode error.
1240    #[must_use]
1241    pub fn missing_persisted_slot(field_name: &'static str) -> Self {
1242        Self::persisted_row_field_decode_corruption(field_name)
1243    }
1244
1245    /// Construct an identity-origin corruption error.
1246    pub(crate) fn identity_corruption() -> Self {
1247        Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1248    }
1249
1250    /// Construct a store-origin unsupported error.
1251    #[cold]
1252    #[inline(never)]
1253    pub(crate) fn store_unsupported() -> Self {
1254        Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1255    }
1256
1257    /// Construct the canonical schema DDL publication race error.
1258    #[cfg(any(test, feature = "sql"))]
1259    pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &'static str) -> Self {
1260        Self {
1261            class: ErrorClass::Unsupported,
1262            origin: ErrorOrigin::Store,
1263            detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1264        }
1265    }
1266
1267    /// Construct the canonical current physical-rewrite migration rejection.
1268    #[cfg(feature = "sql")]
1269    pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &'static str) -> Self {
1270        Self {
1271            class: ErrorClass::Unsupported,
1272            origin: ErrorOrigin::Store,
1273            detail: Some(ErrorDetail::Store(
1274                StoreError::SchemaDdlRewriteRequiresMigration,
1275            )),
1276        }
1277    }
1278
1279    /// Construct a schema-transition row-layout identity exhaustion error.
1280    pub(crate) fn schema_row_layout_version_exhausted() -> Self {
1281        Self {
1282            class: ErrorClass::Unsupported,
1283            origin: ErrorOrigin::Store,
1284            detail: Some(ErrorDetail::Store(
1285                StoreError::SchemaRowLayoutVersionExhausted,
1286            )),
1287        }
1288    }
1289
1290    /// Construct the fail-closed journal mutation-revision exhaustion error.
1291    pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1292        Self {
1293            class: ErrorClass::Unsupported,
1294            origin: ErrorOrigin::Store,
1295            detail: Some(ErrorDetail::Store(
1296                StoreError::JournalMutationRevisionExhausted,
1297            )),
1298        }
1299    }
1300
1301    /// Construct the hard-cut rejection for a generated field that would
1302    /// collide with an already accepted SQL-DDL-owned slot.
1303    pub(crate) fn schema_generated_field_after_ddl_field() -> Self {
1304        Self {
1305            class: ErrorClass::Unsupported,
1306            origin: ErrorOrigin::Store,
1307            detail: Some(ErrorDetail::Store(
1308                StoreError::SchemaGeneratedFieldAfterDdlField,
1309            )),
1310        }
1311    }
1312
1313    /// Construct the fail-closed conflict for a generated proposal that no
1314    /// longer matches its live accepted constraint activation.
1315    pub(crate) fn schema_generated_constraint_activation_stale() -> Self {
1316        Self {
1317            class: ErrorClass::Conflict,
1318            origin: ErrorOrigin::Store,
1319            detail: Some(ErrorDetail::Store(
1320                StoreError::SchemaGeneratedConstraintActivationStale,
1321            )),
1322        }
1323    }
1324
1325    /// Construct a bounded schema-transition resource rejection.
1326    pub(crate) fn schema_transition_budget_exceeded(
1327        resource: SchemaTransitionBudgetResource,
1328    ) -> Self {
1329        Self {
1330            class: ErrorClass::Unsupported,
1331            origin: ErrorOrigin::Store,
1332            detail: Some(ErrorDetail::Store(
1333                StoreError::SchemaTransitionBudgetExceeded { resource },
1334            )),
1335        }
1336    }
1337
1338    /// Construct the canonical unsupported persisted entity-tag store error.
1339    pub(crate) fn unsupported_entity_tag_in_data_store(
1340        _entity_tag: crate::types::EntityTag,
1341    ) -> Self {
1342        Self::store_unsupported()
1343    }
1344
1345    /// Construct the canonical commit-memory id registration failure.
1346    #[cfg(not(test))]
1347    pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1348        Self::store_internal()
1349    }
1350
1351    /// Construct an index-origin unsupported error.
1352    pub(crate) fn index_unsupported() -> Self {
1353        Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1354    }
1355
1356    /// Construct the canonical index-key component size-limit unsupported error.
1357    pub(crate) fn index_component_exceeds_max_size() -> Self {
1358        Self::index_unsupported()
1359    }
1360
1361    /// Construct a serialize-origin unsupported error.
1362    pub(crate) fn serialize_unsupported() -> Self {
1363        Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1364    }
1365
1366    /// Construct a cursor-origin invalid-continuation error.
1367    pub(crate) fn cursor_invalid_continuation() -> Self {
1368        Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1369    }
1370
1371    /// Construct a serialize-origin incompatible persisted-format error.
1372    pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1373        Self::new(
1374            ErrorClass::IncompatiblePersistedFormat,
1375            ErrorOrigin::Serialize,
1376        )
1377    }
1378
1379    /// Construct a query-origin unsupported error preserving one SQL parser
1380    /// unsupported-feature code in structured error detail.
1381    #[cfg(feature = "sql")]
1382    pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1383        Self {
1384            class: ErrorClass::Unsupported,
1385            origin: ErrorOrigin::Query,
1386            detail: Some(ErrorDetail::Query(
1387                QueryErrorDetail::UnsupportedSqlFeature { feature },
1388            )),
1389        }
1390    }
1391
1392    /// Construct a query-origin unsupported SQL lowering error preserving one
1393    /// compact lowering reason in structured error detail.
1394    #[cfg(feature = "sql")]
1395    pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1396        Self {
1397            class: ErrorClass::Unsupported,
1398            origin: ErrorOrigin::Query,
1399            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1400        }
1401    }
1402
1403    /// Construct a query-origin unsupported projection error preserving one
1404    /// compact projection reason in structured error detail.
1405    pub(crate) fn query_unsupported_projection(
1406        reason: diagnostic_code::QueryProjectionCode,
1407    ) -> Self {
1408        Self {
1409            class: ErrorClass::Unsupported,
1410            origin: ErrorOrigin::Query,
1411            detail: Some(ErrorDetail::Query(
1412                QueryErrorDetail::UnsupportedProjection { reason },
1413            )),
1414        }
1415    }
1416
1417    /// Construct a query-origin unsupported aggregate target-field error.
1418    pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1419        Self {
1420            class: ErrorClass::Unsupported,
1421            origin: ErrorOrigin::Query,
1422            detail: Some(ErrorDetail::Query(
1423                QueryErrorDetail::UnknownAggregateTargetField,
1424            )),
1425        }
1426    }
1427
1428    /// Construct a query-origin result-shape mismatch error preserving one
1429    /// compact result-shape reason in structured error detail.
1430    pub(crate) fn query_result_shape_mismatch(
1431        reason: diagnostic_code::QueryResultShapeCode,
1432    ) -> Self {
1433        Self {
1434            class: ErrorClass::Unsupported,
1435            origin: ErrorOrigin::Query,
1436            detail: Some(ErrorDetail::Query(QueryErrorDetail::ResultShapeMismatch {
1437                reason,
1438            })),
1439        }
1440    }
1441
1442    /// Construct a query-origin unsupported error preserving one SQL endpoint
1443    /// surface mismatch in structured error detail.
1444    #[cfg(feature = "sql")]
1445    pub(crate) fn query_sql_surface_mismatch(
1446        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1447    ) -> Self {
1448        Self {
1449            class: ErrorClass::Unsupported,
1450            origin: ErrorOrigin::Query,
1451            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1452                mismatch,
1453            })),
1454        }
1455    }
1456
1457    /// Construct a query-origin unsupported SQL write boundary error.
1458    pub(crate) fn query_sql_write_boundary(
1459        boundary: diagnostic_code::SqlWriteBoundaryCode,
1460    ) -> Self {
1461        Self {
1462            class: ErrorClass::Unsupported,
1463            origin: ErrorOrigin::Query,
1464            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1465                boundary,
1466            })),
1467        }
1468    }
1469
1470    pub fn store_not_found(_key: impl Sized) -> Self {
1471        Self {
1472            class: ErrorClass::NotFound,
1473            origin: ErrorOrigin::Store,
1474            detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1475        }
1476    }
1477
1478    /// Construct a standardized unsupported-entity-path error.
1479    pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1480        Self::store_unsupported()
1481    }
1482
1483    #[must_use]
1484    pub const fn is_not_found(&self) -> bool {
1485        matches!(self.detail, Some(ErrorDetail::Store(StoreError::NotFound)))
1486    }
1487
1488    /// Construct an index-plan corruption error with a canonical prefix.
1489    #[cold]
1490    #[inline(never)]
1491    pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1492        Self::new(ErrorClass::Corruption, origin)
1493    }
1494
1495    /// Construct an index-plan corruption error for index-origin failures.
1496    #[cold]
1497    #[inline(never)]
1498    pub(crate) fn index_plan_index_corruption() -> Self {
1499        Self::index_plan_corruption(ErrorOrigin::Index)
1500    }
1501
1502    /// Construct an index-plan corruption error for store-origin failures.
1503    #[cold]
1504    #[inline(never)]
1505    pub(crate) fn index_plan_store_corruption() -> Self {
1506        Self::index_plan_corruption(ErrorOrigin::Store)
1507    }
1508
1509    /// Construct an index-plan corruption error for serialize-origin failures.
1510    #[cold]
1511    #[inline(never)]
1512    pub(crate) fn index_plan_serialize_corruption() -> Self {
1513        Self::index_plan_corruption(ErrorOrigin::Serialize)
1514    }
1515
1516    /// Construct an index-plan invariant violation error with a canonical prefix.
1517    #[cfg(test)]
1518    pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1519        Self::new(ErrorClass::InvariantViolation, origin)
1520    }
1521
1522    /// Construct an index-plan invariant violation error for store-origin failures.
1523    #[cfg(test)]
1524    pub(crate) fn index_plan_store_invariant() -> Self {
1525        Self::index_plan_invariant(ErrorOrigin::Store)
1526    }
1527
1528    /// Construct an index uniqueness violation conflict error.
1529    pub(crate) fn index_violation(_path: &str, _index_fields: &[&str]) -> Self {
1530        Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1531    }
1532}
1533
1534impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1535    fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1536        Self {
1537            class: ErrorClass::Unsupported,
1538            origin: ErrorOrigin::Query,
1539            detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1540                reason,
1541            })),
1542        }
1543    }
1544}
1545
1546impl fmt::Debug for InternalError {
1547    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1548        fmt_compact_diagnostic(
1549            f,
1550            self.diagnostic_code(),
1551            self.detail
1552                .as_ref()
1553                .and_then(ErrorDetail::diagnostic_detail),
1554        )
1555    }
1556}
1557
1558impl fmt::Display for InternalError {
1559    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1560        f.write_str(self.message())
1561    }
1562}
1563
1564impl std::error::Error for InternalError {}
1565
1566///
1567/// ConstraintDiagnosticKind
1568///
1569/// Accepted constraint family attached to one bounded runtime diagnostic.
1570/// Accepted schema owns the identity; this enum is its error-boundary projection.
1571///
1572
1573#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1574pub enum ConstraintDiagnosticKind {
1575    /// One accepted canonical check expression.
1576    Check,
1577
1578    /// One accepted or activating not-null field contract.
1579    NotNull,
1580
1581    /// One accepted or activating relation contract.
1582    Relation,
1583
1584    /// One accepted or activating unique-index contract.
1585    Unique,
1586}
1587
1588impl ConstraintDiagnosticKind {
1589    /// Borrow the stable public label for this constraint family.
1590    #[must_use]
1591    pub const fn as_str(self) -> &'static str {
1592        match self {
1593            Self::Check => "check",
1594            Self::NotNull => "not_null",
1595            Self::Relation => "relation",
1596            Self::Unique => "unique",
1597        }
1598    }
1599}
1600
1601///
1602/// ConstraintDiagnosticContext
1603///
1604/// Boundary at which one accepted constraint failure was observed.
1605/// This distinguishes incoming write rejection from historical validation.
1606///
1607
1608#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1609pub enum ConstraintDiagnosticContext {
1610    /// Integrity verification found invalid already-accepted state.
1611    Integrity,
1612
1613    /// Bounded activation validation found an incompatible historical row.
1614    MigrationValidation,
1615
1616    /// A new mutation after-image violated accepted admission authority.
1617    WriteAdmission,
1618}
1619
1620impl ConstraintDiagnosticContext {
1621    /// Borrow the stable public label for this diagnostic context.
1622    #[must_use]
1623    pub const fn as_str(self) -> &'static str {
1624        match self {
1625            Self::Integrity => "integrity",
1626            Self::MigrationValidation => "migration_validation",
1627            Self::WriteAdmission => "write_admission",
1628        }
1629    }
1630}
1631
1632///
1633/// ConstraintDiagnostic
1634///
1635/// One bounded accepted-constraint failure carried through runtime and SQL
1636/// boundaries. It is a projection of accepted identity, not a second schema
1637/// authority, and its compact error code remains the classification owner.
1638///
1639
1640#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
1641pub struct ConstraintDiagnostic {
1642    constraint_id: u32,
1643    constraint_name: String,
1644    constraint_kind: ConstraintDiagnosticKind,
1645    entity: String,
1646    primary_key: Option<Vec<u8>>,
1647    field_paths: Vec<String>,
1648    context: ConstraintDiagnosticContext,
1649    error_code: u16,
1650}
1651
1652impl ConstraintDiagnostic {
1653    /// Build one incoming-write accepted constraint violation.
1654    #[must_use]
1655    pub(crate) const fn write_violation(
1656        constraint_id: u32,
1657        constraint_name: String,
1658        constraint_kind: ConstraintDiagnosticKind,
1659        entity: String,
1660        primary_key: Option<Vec<u8>>,
1661        field_paths: Vec<String>,
1662    ) -> Self {
1663        Self {
1664            constraint_id,
1665            constraint_name,
1666            constraint_kind,
1667            entity,
1668            primary_key,
1669            field_paths,
1670            context: ConstraintDiagnosticContext::WriteAdmission,
1671            error_code: diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_VIOLATION.raw(),
1672        }
1673    }
1674
1675    /// Build one incoming-write activation barrier rejection.
1676    #[must_use]
1677    pub(crate) const fn write_activation_blocked(
1678        constraint_id: u32,
1679        constraint_name: String,
1680        constraint_kind: ConstraintDiagnosticKind,
1681        entity: String,
1682        primary_key: Option<Vec<u8>>,
1683        field_paths: Vec<String>,
1684    ) -> Self {
1685        Self {
1686            constraint_id,
1687            constraint_name,
1688            constraint_kind,
1689            entity,
1690            primary_key,
1691            field_paths,
1692            context: ConstraintDiagnosticContext::WriteAdmission,
1693            error_code:
1694                diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_ACTIVATION_WRITE_BLOCKED
1695                    .raw(),
1696        }
1697    }
1698
1699    /// Build one historical activation finding from its durable compact code.
1700    #[cfg(feature = "sql")]
1701    #[must_use]
1702    pub(crate) const fn migration_validation(
1703        constraint_id: u32,
1704        constraint_name: String,
1705        constraint_kind: ConstraintDiagnosticKind,
1706        entity: String,
1707        primary_key: Vec<u8>,
1708        field_paths: Vec<String>,
1709        error_code: u16,
1710    ) -> Self {
1711        Self {
1712            constraint_id,
1713            constraint_name,
1714            constraint_kind,
1715            entity,
1716            primary_key: Some(primary_key),
1717            field_paths,
1718            context: ConstraintDiagnosticContext::MigrationValidation,
1719            error_code,
1720        }
1721    }
1722
1723    /// Return the stable accepted constraint identity.
1724    #[must_use]
1725    pub const fn constraint_id(&self) -> u32 {
1726        self.constraint_id
1727    }
1728
1729    /// Borrow the stable accepted constraint name.
1730    #[must_use]
1731    pub const fn constraint_name(&self) -> &str {
1732        self.constraint_name.as_str()
1733    }
1734
1735    /// Return the accepted constraint family.
1736    #[must_use]
1737    pub const fn constraint_kind(&self) -> ConstraintDiagnosticKind {
1738        self.constraint_kind
1739    }
1740
1741    /// Borrow the accepted entity identity.
1742    #[must_use]
1743    pub const fn entity(&self) -> &str {
1744        self.entity.as_str()
1745    }
1746
1747    /// Borrow the canonical persisted primary-key bytes when available.
1748    #[must_use]
1749    pub fn primary_key(&self) -> Option<&[u8]> {
1750        self.primary_key.as_deref()
1751    }
1752
1753    /// Borrow bounded accepted field paths implicated by the failure.
1754    #[must_use]
1755    pub const fn field_paths(&self) -> &[String] {
1756        self.field_paths.as_slice()
1757    }
1758
1759    /// Return the boundary that observed the failure.
1760    #[must_use]
1761    pub const fn context(&self) -> ConstraintDiagnosticContext {
1762        self.context
1763    }
1764
1765    /// Return the compact stable error code for this exact failure.
1766    #[must_use]
1767    pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
1768        diagnostic_code::ErrorCode::from_raw(self.error_code)
1769    }
1770
1771    /// Return the broad public error class derived from the compact code.
1772    #[must_use]
1773    pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
1774        self.error_code().class()
1775    }
1776}
1777
1778///
1779/// ErrorDetail
1780///
1781/// Structured, origin-specific error detail carried by [`InternalError`].
1782/// This enum is intentionally extensible.
1783///
1784
1785pub enum ErrorDetail {
1786    /// Executor-owned mutation and query execution details.
1787    Executor(ExecutorErrorDetail),
1788    Store(StoreError),
1789    Query(QueryErrorDetail),
1790    Recovery(RecoveryErrorDetail),
1791    /// Persisted-row serialization and decoding details.
1792    Serialize(SerializeErrorDetail),
1793    // Future-proofing:
1794    // Index(IndexError),
1795}
1796
1797/// Executor-specific structured error detail.
1798pub enum ExecutorErrorDetail {
1799    /// A complete insert or replacement omitted one or more required fields.
1800    MutationRequiredFieldMissing,
1801    /// A final canonical after-image violated one accepted constraint or activation gate.
1802    ConstraintViolation {
1803        diagnostic: Box<ConstraintDiagnostic>,
1804    },
1805    /// Accepted row-constraint metadata or compiled state was inconsistent.
1806    AcceptedRowConstraintProgramCorrupt,
1807    /// A write would rely on one incomplete activation-owned physical proof.
1808    ConstraintActivationWriteBlocked {
1809        diagnostic: Box<ConstraintDiagnostic>,
1810    },
1811}
1812
1813impl ExecutorErrorDetail {
1814    /// Borrow the accepted constraint diagnostic carried by this failure.
1815    #[must_use]
1816    pub fn constraint_diagnostic(&self) -> Option<&ConstraintDiagnostic> {
1817        match self {
1818            Self::ConstraintActivationWriteBlocked { diagnostic }
1819            | Self::ConstraintViolation { diagnostic } => Some(diagnostic.as_ref()),
1820            Self::MutationRequiredFieldMissing | Self::AcceptedRowConstraintProgramCorrupt => None,
1821        }
1822    }
1823}
1824
1825/// Persisted-row serialization and decoding error detail.
1826pub enum SerializeErrorDetail {
1827    /// The row stamp is older or newer than the accepted layout window.
1828    PersistedRowLayoutOutsideAcceptedWindow,
1829
1830    /// The physical slot count does not match the row's stamped layout.
1831    PersistedRowSlotCountMismatch,
1832}
1833
1834///
1835/// RecoveryErrorDetail
1836///
1837/// Recovery-origin structured error detail payload.
1838///
1839
1840pub enum RecoveryErrorDetail {
1841    UnsupportedFormatVersion { found: Option<u16>, required: u16 },
1842
1843    MalformedFormatMarker { reason: RecoveryFormatMarkerError },
1844}
1845
1846/// Store boot-marker corruption classification.
1847#[derive(Clone, Copy, Eq, PartialEq)]
1848pub enum RecoveryFormatMarkerError {
1849    Magic,
1850    Checksum,
1851    State,
1852}
1853
1854///
1855/// StoreError
1856///
1857/// Store-specific structured error detail.
1858/// Never returned directly; always wrapped in [`ErrorDetail::Store`].
1859///
1860
1861pub enum StoreError {
1862    NotFound,
1863
1864    Corrupt,
1865
1866    InvariantViolation,
1867
1868    SchemaDdlPublicationRaceLost,
1869
1870    SchemaDdlRewriteRequiresMigration,
1871
1872    SchemaRowLayoutVersionExhausted,
1873
1874    JournalMutationRevisionExhausted,
1875
1876    SchemaTransitionBudgetExceeded {
1877        resource: SchemaTransitionBudgetResource,
1878    },
1879
1880    /// A generated field would collide with an accepted DDL-owned slot.
1881    SchemaGeneratedFieldAfterDdlField,
1882
1883    /// A live generated constraint activation no longer matches its proposal.
1884    SchemaGeneratedConstraintActivationStale,
1885}
1886
1887///
1888/// QueryErrorDetail
1889///
1890/// Query-origin structured error detail payload.
1891///
1892
1893pub enum QueryErrorDetail {
1894    NumericOverflow,
1895
1896    NumericNotRepresentable,
1897
1898    UnsupportedSqlFeature {
1899        feature: diagnostic_code::SqlFeatureCode,
1900    },
1901
1902    SqlLowering {
1903        reason: diagnostic_code::SqlLoweringCode,
1904    },
1905
1906    UnsupportedProjection {
1907        reason: diagnostic_code::QueryProjectionCode,
1908    },
1909
1910    UnknownAggregateTargetField,
1911
1912    ResultShapeMismatch {
1913        reason: diagnostic_code::QueryResultShapeCode,
1914    },
1915
1916    QueryReadAdmission {
1917        reason: diagnostic_code::QueryReadAdmissionCode,
1918    },
1919
1920    SqlSurfaceMismatch {
1921        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1922    },
1923
1924    SqlWriteBoundary {
1925        boundary: diagnostic_code::SqlWriteBoundaryCode,
1926    },
1927
1928    SchemaDdlAdmission {
1929        error: SchemaDdlAdmissionError,
1930    },
1931
1932    StaleSchemaRevision,
1933}
1934
1935impl fmt::Display for QueryErrorDetail {
1936    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1937        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
1938    }
1939}
1940
1941impl std::error::Error for QueryErrorDetail {}
1942
1943///
1944/// SchemaTransitionBudgetResource
1945///
1946/// Query-visible identity of the exact schema-transition resource cap that
1947/// rejected a complete validation or derived-state stage.
1948///
1949
1950#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1951pub enum SchemaTransitionBudgetResource {
1952    /// Number of physical deletion keys retained for replacement.
1953    DeletionKeys,
1954    /// Number of row-derived projection entries retained for validation.
1955    ProjectionEntries,
1956    /// Deterministic projection and physical-classification work units.
1957    ProjectionWorkUnits,
1958    /// Number of authoritative source rows.
1959    SourceRows,
1960    /// Cumulative bytes of authoritative source rows.
1961    SourceRowBytes,
1962    /// Retained raw payloads plus deterministic-sort workspace bytes.
1963    StagedRawBytes,
1964}
1965
1966///
1967/// SchemaDdlAdmissionError
1968///
1969/// Stable query-visible SQL DDL admission reason. Human diagnostics may carry
1970/// extra version, fingerprint, and target facts beside this machine-readable
1971/// variant.
1972///
1973
1974#[derive(Clone, Copy, Eq, PartialEq)]
1975pub enum SchemaDdlAdmissionError {
1976    MissingExpectedSchemaVersion,
1977
1978    MissingNextSchemaVersion,
1979
1980    StaleExpectedSchemaVersion,
1981
1982    InvalidExpectedSchemaVersion,
1983
1984    InvalidNextSchemaVersion,
1985
1986    AcceptedSchemaChangeWithoutVersionBump,
1987
1988    EmptyVersionBump,
1989
1990    VersionGap,
1991
1992    VersionRollback,
1993
1994    FingerprintMethodMismatch,
1995
1996    UnsupportedTransitionClass,
1997
1998    PhysicalRunnerMissing,
1999
2000    ValidationFailed,
2001
2002    PublicationRaceLost,
2003
2004    InvalidAddColumnDefault,
2005
2006    InvalidAlterColumnDefault,
2007
2008    RowLayoutVersionExhausted,
2009
2010    GeneratedIndexDropRejected,
2011
2012    SchemaRewriteRequiresMigration,
2013
2014    SchemaTransitionBudgetExceeded {
2015        resource: SchemaTransitionBudgetResource,
2016    },
2017
2018    GeneratedFieldDefaultChangeRejected,
2019
2020    GeneratedFieldNullabilityChangeRejected,
2021}
2022
2023impl fmt::Display for SchemaDdlAdmissionError {
2024    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2025        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2026    }
2027}
2028
2029impl std::error::Error for SchemaDdlAdmissionError {}
2030
2031impl fmt::Debug for ErrorDetail {
2032    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2033        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2034    }
2035}
2036
2037impl fmt::Debug for ExecutorErrorDetail {
2038    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2039        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2040    }
2041}
2042
2043impl fmt::Debug for StoreError {
2044    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2045        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2046    }
2047}
2048
2049impl fmt::Debug for QueryErrorDetail {
2050    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2051        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2052    }
2053}
2054
2055impl fmt::Debug for RecoveryErrorDetail {
2056    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2057        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2058    }
2059}
2060
2061impl fmt::Debug for SerializeErrorDetail {
2062    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2063        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2064    }
2065}
2066
2067impl fmt::Debug for RecoveryFormatMarkerError {
2068    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2069        fmt_compact_diagnostic(
2070            f,
2071            diagnostic_code::DiagnosticCode::RuntimeCorruption,
2072            Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2073                kind: diagnostic_code::RuntimeErrorKind::Corruption,
2074            }),
2075        )
2076    }
2077}
2078
2079impl fmt::Debug for SchemaDdlAdmissionError {
2080    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2081        fmt_compact_diagnostic(
2082            f,
2083            diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2084            Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2085                reason: self.diagnostic_code(),
2086            }),
2087        )
2088    }
2089}
2090
2091fn fmt_compact_diagnostic(
2092    f: &mut fmt::Formatter<'_>,
2093    code: diagnostic_code::DiagnosticCode,
2094    detail: Option<diagnostic_code::DiagnosticDetail>,
2095) -> fmt::Result {
2096    write!(
2097        f,
2098        "{}",
2099        diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2100    )
2101}
2102
2103impl ErrorDetail {
2104    /// Return the compact diagnostic code for this structured detail.
2105    #[must_use]
2106    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2107        match self {
2108            Self::Executor(error) => error.diagnostic_code(),
2109            Self::Store(error) => error.diagnostic_code(),
2110            Self::Query(error) => error.diagnostic_code(),
2111            Self::Recovery(error) => error.diagnostic_code(),
2112            Self::Serialize(error) => error.diagnostic_code(),
2113        }
2114    }
2115
2116    /// Return compact structured diagnostic detail when the payload carries one.
2117    #[must_use]
2118    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2119        match self {
2120            Self::Executor(error) => error.diagnostic_detail(),
2121            Self::Store(error) => error.diagnostic_detail(),
2122            Self::Query(error) => error.diagnostic_detail(),
2123            Self::Recovery(error) => error.diagnostic_detail(),
2124            Self::Serialize(error) => error.diagnostic_detail(),
2125        }
2126    }
2127}
2128
2129impl ExecutorErrorDetail {
2130    /// Return the compact diagnostic code for this executor detail.
2131    #[must_use]
2132    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2133        match self {
2134            Self::MutationRequiredFieldMissing => {
2135                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2136            }
2137            Self::ConstraintViolation { diagnostic }
2138            | Self::ConstraintActivationWriteBlocked { diagnostic } => {
2139                diagnostic.error_code().diagnostic_code()
2140            }
2141            Self::AcceptedRowConstraintProgramCorrupt => {
2142                diagnostic_code::DiagnosticCode::RuntimeCorruption
2143            }
2144        }
2145    }
2146
2147    /// Return compact structured diagnostic detail for this executor detail.
2148    #[must_use]
2149    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2150        match self {
2151            Self::MutationRequiredFieldMissing => {
2152                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2153                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2154                })
2155            }
2156            Self::ConstraintViolation { diagnostic }
2157            | Self::ConstraintActivationWriteBlocked { diagnostic } => {
2158                diagnostic.error_code().diagnostic_detail()
2159            }
2160            Self::AcceptedRowConstraintProgramCorrupt => {
2161                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2162                    boundary:
2163                        diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2164                })
2165            }
2166        }
2167    }
2168}
2169
2170impl RecoveryErrorDetail {
2171    /// Return the compact diagnostic code for this recovery detail.
2172    #[must_use]
2173    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2174        match self {
2175            Self::UnsupportedFormatVersion { .. } => {
2176                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2177            }
2178            Self::MalformedFormatMarker { .. } => {
2179                diagnostic_code::DiagnosticCode::RuntimeCorruption
2180            }
2181        }
2182    }
2183
2184    /// Return compact structured diagnostic detail for this recovery detail.
2185    #[must_use]
2186    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2187        let kind = match self {
2188            Self::UnsupportedFormatVersion { .. } => {
2189                diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2190            }
2191            Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2192        };
2193
2194        Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2195    }
2196}
2197
2198impl SerializeErrorDetail {
2199    /// Return the compact diagnostic code for this serialization detail.
2200    #[must_use]
2201    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2202        match self {
2203            Self::PersistedRowLayoutOutsideAcceptedWindow | Self::PersistedRowSlotCountMismatch => {
2204                diagnostic_code::DiagnosticCode::RuntimeCorruption
2205            }
2206        }
2207    }
2208
2209    /// Return compact structured diagnostic detail for this serialization detail.
2210    #[must_use]
2211    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2212        let boundary = match self {
2213            Self::PersistedRowLayoutOutsideAcceptedWindow => {
2214                diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow
2215            }
2216            Self::PersistedRowSlotCountMismatch => {
2217                diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch
2218            }
2219        };
2220
2221        Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary })
2222    }
2223}
2224
2225impl StoreError {
2226    /// Return the compact diagnostic code for this store detail.
2227    #[must_use]
2228    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2229        match self {
2230            Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2231            Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2232            Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2233            Self::SchemaDdlPublicationRaceLost
2234            | Self::SchemaDdlRewriteRequiresMigration
2235            | Self::SchemaRowLayoutVersionExhausted
2236            | Self::SchemaTransitionBudgetExceeded { .. } => {
2237                diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2238            }
2239            Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2240                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2241            }
2242            Self::SchemaGeneratedConstraintActivationStale => {
2243                diagnostic_code::DiagnosticCode::RuntimeConflict
2244            }
2245        }
2246    }
2247
2248    /// Return compact structured diagnostic detail when the store error has one.
2249    #[must_use]
2250    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2251        match self {
2252            Self::SchemaDdlPublicationRaceLost => {
2253                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2254                    reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2255                })
2256            }
2257            Self::SchemaDdlRewriteRequiresMigration => {
2258                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2259                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2260                })
2261            }
2262            Self::SchemaRowLayoutVersionExhausted => {
2263                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2264                    reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2265                })
2266            }
2267            Self::JournalMutationRevisionExhausted => {
2268                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2269                    boundary:
2270                        diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2271                })
2272            }
2273            Self::SchemaTransitionBudgetExceeded { .. } => {
2274                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2275                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2276                })
2277            }
2278            Self::SchemaGeneratedFieldAfterDdlField => {
2279                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2280                    boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2281                })
2282            }
2283            Self::SchemaGeneratedConstraintActivationStale => {
2284                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2285                    boundary:
2286                        diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2287                })
2288            }
2289            Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2290        }
2291    }
2292}
2293
2294impl QueryErrorDetail {
2295    /// Return the compact diagnostic code for this query detail.
2296    #[must_use]
2297    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2298        match self {
2299            Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2300            Self::NumericNotRepresentable => {
2301                diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2302            }
2303            Self::UnsupportedSqlFeature { .. } => {
2304                diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2305            }
2306            Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2307            Self::UnsupportedProjection { .. } => {
2308                diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2309            }
2310            Self::UnknownAggregateTargetField => {
2311                diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2312            }
2313            Self::ResultShapeMismatch { .. } => {
2314                diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
2315            }
2316            Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2317            Self::SqlSurfaceMismatch { .. } => {
2318                diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2319            }
2320            Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2321            Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2322            Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2323        }
2324    }
2325
2326    /// Return compact structured diagnostic detail when the query detail has one.
2327    #[must_use]
2328    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2329        match self {
2330            Self::UnsupportedSqlFeature { feature } => {
2331                Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2332            }
2333            Self::SqlLowering { reason } => {
2334                Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2335            }
2336            Self::UnsupportedProjection { reason } => {
2337                Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2338            }
2339            Self::ResultShapeMismatch { reason } => {
2340                Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
2341            }
2342            Self::QueryReadAdmission { reason } => {
2343                Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2344            }
2345            Self::SqlSurfaceMismatch { mismatch } => {
2346                Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2347                    mismatch: *mismatch,
2348                })
2349            }
2350            Self::SqlWriteBoundary { boundary } => {
2351                Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2352                    boundary: *boundary,
2353                })
2354            }
2355            Self::SchemaDdlAdmission { error } => {
2356                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2357                    reason: error.diagnostic_code(),
2358                })
2359            }
2360            Self::NumericOverflow
2361            | Self::NumericNotRepresentable
2362            | Self::UnknownAggregateTargetField
2363            | Self::StaleSchemaRevision => None,
2364        }
2365    }
2366}
2367
2368impl SchemaDdlAdmissionError {
2369    /// Return the compact diagnostic code for this SQL DDL admission reason.
2370    #[must_use]
2371    pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
2372        match self {
2373            Self::MissingExpectedSchemaVersion => {
2374                diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
2375            }
2376            Self::MissingNextSchemaVersion => {
2377                diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
2378            }
2379            Self::StaleExpectedSchemaVersion => {
2380                diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
2381            }
2382            Self::InvalidExpectedSchemaVersion => {
2383                diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
2384            }
2385            Self::InvalidNextSchemaVersion => {
2386                diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
2387            }
2388            Self::AcceptedSchemaChangeWithoutVersionBump => {
2389                diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
2390            }
2391            Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
2392            Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
2393            Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
2394            Self::FingerprintMethodMismatch => {
2395                diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
2396            }
2397            Self::UnsupportedTransitionClass => {
2398                diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
2399            }
2400            Self::PhysicalRunnerMissing => {
2401                diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
2402            }
2403            Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
2404            Self::PublicationRaceLost => {
2405                diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
2406            }
2407            Self::InvalidAddColumnDefault => {
2408                diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
2409            }
2410            Self::InvalidAlterColumnDefault => {
2411                diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
2412            }
2413            Self::GeneratedIndexDropRejected => {
2414                diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
2415            }
2416            Self::SchemaRewriteRequiresMigration => {
2417                diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
2418            }
2419            Self::SchemaTransitionBudgetExceeded { .. } => {
2420                diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
2421            }
2422            Self::GeneratedFieldDefaultChangeRejected => {
2423                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
2424            }
2425            Self::GeneratedFieldNullabilityChangeRejected => {
2426                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
2427            }
2428            Self::RowLayoutVersionExhausted => {
2429                diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
2430            }
2431        }
2432    }
2433}
2434
2435///
2436/// ErrorClass
2437/// Internal error taxonomy for runtime classification.
2438/// Not a stable API; may change without notice.
2439///
2440
2441#[repr(u8)]
2442#[derive(Clone, Copy, Eq, PartialEq)]
2443pub enum ErrorClass {
2444    Corruption,
2445    IncompatiblePersistedFormat,
2446    NotFound,
2447    Internal,
2448    Conflict,
2449    Unsupported,
2450    InvariantViolation,
2451}
2452
2453impl ErrorClass {
2454    /// Return a compact diagnostic code for this broad class and origin pair.
2455    #[must_use]
2456    pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
2457        match self {
2458            Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
2459                diagnostic_code::DiagnosticCode::StoreCorruption
2460            }
2461            Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
2462            Self::IncompatiblePersistedFormat => {
2463                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2464            }
2465            Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
2466                diagnostic_code::DiagnosticCode::StoreNotFound
2467            }
2468            Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
2469            Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
2470            Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
2471            Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
2472                diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
2473            }
2474            Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
2475            Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
2476                diagnostic_code::DiagnosticCode::StoreInvariantViolation
2477            }
2478            Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
2479        }
2480    }
2481}
2482
2483impl fmt::Debug for ErrorClass {
2484    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2485        write!(f, "{}", *self as u8)
2486    }
2487}
2488
2489///
2490/// ErrorOrigin
2491/// Internal origin taxonomy for runtime classification.
2492/// Not a stable API; may change without notice.
2493///
2494
2495#[repr(u8)]
2496#[derive(Clone, Copy, Eq, PartialEq)]
2497pub enum ErrorOrigin {
2498    Serialize,
2499    Store,
2500    Index,
2501    Identity,
2502    Query,
2503    Planner,
2504    Cursor,
2505    Recovery,
2506    Response,
2507    Executor,
2508    Interface,
2509}
2510
2511impl ErrorOrigin {
2512    /// Return the compact diagnostic origin for this internal origin.
2513    #[must_use]
2514    pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
2515        match self {
2516            Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
2517            Self::Store => diagnostic_code::ErrorOrigin::Store,
2518            Self::Index => diagnostic_code::ErrorOrigin::Index,
2519            Self::Identity => diagnostic_code::ErrorOrigin::Identity,
2520            Self::Query => diagnostic_code::ErrorOrigin::Query,
2521            Self::Planner => diagnostic_code::ErrorOrigin::Planner,
2522            Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
2523            Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
2524            Self::Response => diagnostic_code::ErrorOrigin::Response,
2525            Self::Executor => diagnostic_code::ErrorOrigin::Executor,
2526            Self::Interface => diagnostic_code::ErrorOrigin::Interface,
2527        }
2528    }
2529}
2530
2531impl fmt::Debug for ErrorOrigin {
2532    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2533        write!(f, "{}", *self as u8)
2534    }
2535}