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 a recovery-origin incompatible store-format error.
663    pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
664        Self {
665            class: ErrorClass::IncompatiblePersistedFormat,
666            origin: ErrorOrigin::Recovery,
667            detail: Some(ErrorDetail::Recovery(
668                RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
669            )),
670        }
671    }
672
673    /// Construct a recovery-origin malformed store-format marker error.
674    pub(crate) fn recovery_malformed_database_format_marker(
675        reason: RecoveryFormatMarkerError,
676    ) -> Self {
677        Self {
678            class: ErrorClass::Corruption,
679            origin: ErrorOrigin::Recovery,
680            detail: Some(ErrorDetail::Recovery(
681                RecoveryErrorDetail::MalformedFormatMarker { reason },
682            )),
683        }
684    }
685
686    /// Construct a recovery-origin boot control-memory failure.
687    pub(crate) fn recovery_database_format_control_unavailable() -> Self {
688        Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
689    }
690
691    /// Construct a commit control-memory growth failure.
692    pub(crate) fn commit_control_memory_growth_failed() -> Self {
693        Self::store_internal()
694    }
695
696    /// Construct a store-format memory registration failure.
697    #[cfg(not(test))]
698    pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
699        Self::store_internal()
700    }
701
702    /// Construct the canonical missing rollback-row invariant for delete execution.
703    pub(crate) fn delete_rollback_row_required() -> Self {
704        Self::store_internal()
705    }
706
707    /// Construct the canonical recovery-integrity totals corruption error.
708    pub(crate) fn recovery_integrity_validation_failed(
709        _missing_index_entries: u64,
710        _divergent_index_entries: u64,
711        _orphan_index_references: u64,
712    ) -> Self {
713        Self::store_corruption()
714    }
715
716    /// Construct an index-origin internal error.
717    #[cold]
718    #[inline(never)]
719    pub(crate) fn index_internal() -> Self {
720        Self::new(ErrorClass::Internal, ErrorOrigin::Index)
721    }
722
723    /// Construct the canonical missing old entity-key internal error for structural index removal.
724    pub(crate) fn structural_index_removal_entity_key_required() -> Self {
725        Self::index_internal()
726    }
727
728    /// Construct the canonical missing new entity-key internal error for structural index insertion.
729    pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
730        Self::index_internal()
731    }
732
733    /// Construct the canonical missing old entity-key internal error for index commit-op removal.
734    pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
735        Self::index_internal()
736    }
737
738    /// Construct the canonical missing new entity-key internal error for index commit-op insertion.
739    pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
740        Self::index_internal()
741    }
742
743    /// Construct a query-origin internal error.
744    #[cfg(test)]
745    pub(crate) fn query_internal() -> Self {
746        Self::new(ErrorClass::Internal, ErrorOrigin::Query)
747    }
748
749    /// Construct a query-origin unsupported error.
750    #[cold]
751    #[inline(never)]
752    pub(crate) fn query_unsupported() -> Self {
753        Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
754    }
755
756    /// Construct a query-origin conflict for execution against a superseded
757    /// accepted schema revision.
758    #[cold]
759    #[inline(never)]
760    pub(crate) fn query_stale_accepted_schema_revision(
761        _expected_revision: u64,
762        _current_revision: Option<u64>,
763    ) -> Self {
764        Self {
765            class: ErrorClass::Conflict,
766            origin: ErrorOrigin::Query,
767            detail: Some(ErrorDetail::Query(QueryErrorDetail::StaleSchemaRevision)),
768        }
769    }
770
771    /// Construct a query-origin SQL DDL admission error with structured detail.
772    #[cold]
773    #[inline(never)]
774    #[cfg(feature = "sql")]
775    pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
776        Self {
777            class: ErrorClass::Unsupported,
778            origin: ErrorOrigin::Query,
779            detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
780                error,
781            })),
782        }
783    }
784
785    /// Construct a query-origin numeric overflow error with structured detail.
786    #[cold]
787    #[inline(never)]
788    pub(crate) fn query_numeric_overflow() -> Self {
789        Self {
790            class: ErrorClass::Unsupported,
791            origin: ErrorOrigin::Query,
792            detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
793        }
794    }
795
796    /// Construct a query-origin non-representable numeric result error with
797    /// structured detail.
798    #[cold]
799    #[inline(never)]
800    pub(crate) fn query_numeric_not_representable() -> Self {
801        Self {
802            class: ErrorClass::Unsupported,
803            origin: ErrorOrigin::Query,
804            detail: Some(ErrorDetail::Query(
805                QueryErrorDetail::NumericNotRepresentable,
806            )),
807        }
808    }
809
810    /// Construct a serialize-origin internal error.
811    #[cold]
812    #[inline(never)]
813    pub(crate) fn serialize_internal() -> Self {
814        Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
815    }
816
817    /// Construct the canonical persisted-row encode internal error.
818    pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
819        Self::persisted_row_encode_internal()
820    }
821
822    /// Construct the compact persisted-row encode internal error.
823    pub(crate) fn persisted_row_encode_internal() -> Self {
824        Self::serialize_internal()
825    }
826
827    /// Construct the canonical persisted-row field encode internal error.
828    pub(crate) fn persisted_row_field_encode_failed(field_name: &str, _detail: impl Sized) -> Self {
829        Self::persisted_row_field_encode_internal(field_name)
830    }
831
832    /// Construct the compact persisted-row field encode internal error.
833    pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
834        Self::persisted_row_encode_internal()
835    }
836
837    /// Construct the canonical bytes(field) value encode internal error.
838    pub(crate) fn bytes_field_value_encode_failed(_detail: impl Sized) -> Self {
839        Self::serialize_internal()
840    }
841
842    /// Construct a store-origin corruption error.
843    #[cold]
844    #[inline(never)]
845    pub(crate) fn store_corruption() -> Self {
846        Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
847    }
848
849    /// Construct a store-origin commit-marker corruption error.
850    pub(crate) fn commit_corruption() -> Self {
851        Self::store_corruption()
852    }
853
854    /// Construct a store-origin commit-marker component corruption error.
855    pub(crate) fn commit_component_corruption() -> Self {
856        Self::commit_corruption()
857    }
858
859    /// Construct the canonical commit-marker id generation internal error.
860    pub(crate) fn commit_id_generation_failed() -> Self {
861        Self::store_internal()
862    }
863
864    /// Construct the canonical commit-marker payload u32-length-limit error.
865    pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
866        Self::store_unsupported()
867    }
868
869    /// Construct the canonical commit-marker component invalid-length corruption error.
870    pub(crate) fn commit_component_length_invalid() -> Self {
871        Self::commit_corruption()
872    }
873
874    /// Construct the canonical commit-marker max-size corruption error.
875    pub(crate) fn commit_marker_exceeds_max_size() -> Self {
876        Self::commit_corruption()
877    }
878
879    /// Construct the canonical commit-control slot max-size unsupported error.
880    pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
881        Self::store_unsupported()
882    }
883
884    /// Construct the canonical commit-control marker-bytes length-limit error.
885    pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
886        Self::store_unsupported()
887    }
888
889    /// Construct the canonical startup index-rebuild invalid-data-key corruption error.
890    pub(crate) fn startup_index_rebuild_invalid_data_key() -> Self {
891        Self::store_corruption()
892    }
893
894    /// Construct an index-origin corruption error.
895    #[cold]
896    #[inline(never)]
897    pub(crate) fn index_corruption() -> Self {
898        Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
899    }
900
901    /// Construct the canonical unique-validation corruption wrapper.
902    pub(crate) fn index_unique_validation_corruption() -> Self {
903        Self::index_plan_index_corruption()
904    }
905
906    /// Construct the canonical structural index-entry corruption wrapper.
907    pub(crate) fn structural_index_entry_corruption() -> Self {
908        Self::index_plan_index_corruption()
909    }
910
911    /// Construct the canonical missing new entity-key invariant during unique validation.
912    pub(crate) fn index_unique_validation_entity_key_required() -> Self {
913        Self::index_invariant()
914    }
915
916    /// Construct the canonical unique-validation structural row-decode corruption error.
917    pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
918        Self::index_plan_serialize_corruption()
919    }
920
921    /// Construct the canonical unique-validation primary-key slot decode corruption error.
922    pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
923        Self::index_plan_serialize_corruption()
924    }
925
926    /// Construct the canonical unique-validation stored key rebuild corruption error.
927    pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
928        Self::index_plan_serialize_corruption()
929    }
930
931    /// Construct the canonical unique-validation missing-row corruption error.
932    pub(crate) fn index_unique_validation_row_required() -> Self {
933        Self::index_plan_store_corruption()
934    }
935
936    /// Construct the canonical index-only predicate missing-component invariant.
937    pub(crate) fn index_only_predicate_component_required() -> Self {
938        Self::index_invariant()
939    }
940
941    /// Construct the canonical index-scan continuation-envelope invariant.
942    pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
943        Self::index_invariant()
944    }
945
946    /// Construct the canonical index-scan continuation-advancement invariant.
947    pub(crate) fn index_scan_continuation_advancement_required() -> Self {
948        Self::index_invariant()
949    }
950
951    /// Construct the canonical index-scan key-decode corruption error.
952    pub(crate) fn index_scan_key_corrupted_during(
953        _context: &'static str,
954        _err: impl Sized,
955    ) -> Self {
956        Self::index_corruption()
957    }
958
959    /// Construct the canonical index-scan missing projection-component invariant.
960    pub(crate) fn index_projection_component_required(
961        _index_name: &str,
962        _component_index: usize,
963    ) -> Self {
964        Self::index_invariant()
965    }
966
967    /// Construct the canonical scan-time index-entry decode corruption error.
968    pub(crate) fn index_entry_decode_failed() -> Self {
969        Self::index_corruption()
970    }
971
972    /// Construct a serialize-origin corruption error.
973    pub(crate) fn serialize_corruption() -> Self {
974        Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
975    }
976
977    /// Construct the canonical persisted-row decode corruption error.
978    pub(crate) fn persisted_row_decode_failed(_detail: impl Sized) -> Self {
979        Self::persisted_row_decode_corruption()
980    }
981
982    /// Construct the compact persisted-row decode corruption error.
983    pub(crate) fn persisted_row_decode_corruption() -> Self {
984        Self::serialize_corruption()
985    }
986
987    /// Construct a persisted-row layout-window corruption error.
988    pub(crate) fn persisted_row_layout_outside_accepted_window() -> Self {
989        Self {
990            class: ErrorClass::Corruption,
991            origin: ErrorOrigin::Serialize,
992            detail: Some(ErrorDetail::Serialize(
993                SerializeErrorDetail::PersistedRowLayoutOutsideAcceptedWindow,
994            )),
995        }
996    }
997
998    /// Construct a persisted-row stamped-layout slot-count corruption error.
999    pub(crate) fn persisted_row_slot_count_mismatch() -> Self {
1000        Self {
1001            class: ErrorClass::Corruption,
1002            origin: ErrorOrigin::Serialize,
1003            detail: Some(ErrorDetail::Serialize(
1004                SerializeErrorDetail::PersistedRowSlotCountMismatch,
1005            )),
1006        }
1007    }
1008
1009    /// Construct the canonical persisted-row field decode corruption error.
1010    pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
1011        Self::persisted_row_field_decode_corruption(field_name)
1012    }
1013
1014    /// Construct the compact persisted-row field decode corruption error.
1015    pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
1016        Self::persisted_row_decode_corruption()
1017    }
1018
1019    /// Construct the canonical persisted-row field-kind decode corruption error.
1020    pub(crate) fn persisted_row_field_kind_decode_failed(
1021        field_name: &str,
1022        _field_kind: impl fmt::Debug,
1023        _detail: impl Sized,
1024    ) -> Self {
1025        Self::persisted_row_field_decode_corruption(field_name)
1026    }
1027
1028    /// Construct the canonical persisted-row scalar-payload length corruption error.
1029    pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
1030        Self::persisted_row_field_decode_corruption(field_name)
1031    }
1032
1033    /// Construct the canonical persisted-row scalar-payload empty-body corruption error.
1034    pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
1035        Self::persisted_row_field_decode_corruption(field_name)
1036    }
1037
1038    /// Construct the canonical persisted-row scalar-payload invalid-byte corruption error.
1039    pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
1040        Self::persisted_row_field_decode_corruption(field_name)
1041    }
1042
1043    /// Construct the canonical persisted-row scalar-payload non-finite corruption error.
1044    pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
1045        Self::persisted_row_field_decode_corruption(field_name)
1046    }
1047
1048    /// Construct the canonical persisted-row scalar-payload out-of-range corruption error.
1049    pub(crate) fn persisted_row_field_payload_out_of_range(field_name: &str) -> Self {
1050        Self::persisted_row_field_decode_corruption(field_name)
1051    }
1052
1053    /// Construct the canonical persisted-row invalid text payload corruption error.
1054    pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
1055        Self::persisted_row_field_decode_corruption(field_name)
1056    }
1057
1058    /// Construct the canonical persisted-row structural slot-lookup invariant.
1059    pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
1060        Self::index_invariant()
1061    }
1062
1063    /// Construct the canonical persisted-row structural slot-cache invariant.
1064    pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
1065        _model_path: &str,
1066        _slot: usize,
1067    ) -> Self {
1068        Self::index_invariant()
1069    }
1070
1071    /// Construct the canonical persisted-row primary-key decode corruption error.
1072    pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1073        _data_key: impl fmt::Debug,
1074        _detail: impl Sized,
1075    ) -> Self {
1076        Self::persisted_row_decode_corruption()
1077    }
1078
1079    /// Construct the canonical persisted-row missing primary-key slot corruption error.
1080    pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1081        Self::persisted_row_decode_corruption()
1082    }
1083
1084    /// Construct the canonical persisted-row key mismatch corruption error.
1085    pub(crate) fn persisted_row_key_mismatch() -> Self {
1086        Self::store_corruption()
1087    }
1088
1089    /// Construct the canonical persisted-row missing declared-field corruption error.
1090    pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1091        Self::persisted_row_field_decode_corruption(field_name)
1092    }
1093
1094    /// Construct the canonical data-key entity mismatch corruption error.
1095    pub(crate) fn data_key_entity_mismatch() -> Self {
1096        Self::store_corruption()
1097    }
1098
1099    /// Construct the canonical reverse-index ordinal overflow internal error.
1100    pub(crate) fn reverse_index_ordinal_overflow(
1101        _source_path: &str,
1102        _field_name: &str,
1103        _target_path: &str,
1104        _detail: impl Sized,
1105    ) -> Self {
1106        Self::index_internal()
1107    }
1108
1109    /// Construct the canonical reverse-index entry corruption error.
1110    pub(crate) fn reverse_index_entry_corrupted(
1111        _source_path: &str,
1112        _field_name: &str,
1113        _target_path: &str,
1114        _index_key: impl fmt::Debug,
1115        _detail: impl Sized,
1116    ) -> Self {
1117        Self::index_corruption()
1118    }
1119
1120    /// Construct the canonical relation-target store missing internal error.
1121    pub(crate) fn relation_target_store_missing(
1122        _source_path: &str,
1123        _field_name: &str,
1124        _target_path: &str,
1125        _store_path: &str,
1126        _detail: impl Sized,
1127    ) -> Self {
1128        Self::executor_internal()
1129    }
1130
1131    /// Construct the canonical relation-target key decode corruption error.
1132    pub(crate) fn relation_target_key_decode_failed(
1133        _context_label: &str,
1134        _source_path: &str,
1135        _field_name: &str,
1136        _target_path: &str,
1137        _detail: impl Sized,
1138    ) -> Self {
1139        Self::identity_corruption()
1140    }
1141
1142    /// Construct the canonical relation-target entity mismatch corruption error.
1143    pub(crate) fn relation_target_entity_mismatch(
1144        _context_label: &str,
1145        _source_path: &str,
1146        _field_name: &str,
1147        _target_path: &str,
1148        _target_entity_name: &str,
1149        _expected_tag: impl Sized,
1150        _actual_tag: impl Sized,
1151    ) -> Self {
1152        Self::store_corruption()
1153    }
1154
1155    /// Construct the canonical relation-source row decode corruption error.
1156    pub(crate) fn relation_source_row_decode_failed(
1157        _source_path: &str,
1158        _field_name: &str,
1159        _target_path: &str,
1160        _detail: impl Sized,
1161    ) -> Self {
1162        Self::persisted_row_decode_corruption()
1163    }
1164
1165    /// Construct the canonical relation-source unsupported scalar relation-key corruption error.
1166    pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1167        _source_path: &str,
1168        _field_name: &str,
1169        _target_path: &str,
1170    ) -> Self {
1171        Self::persisted_row_decode_corruption()
1172    }
1173
1174    /// Construct the canonical unsupported relation key-kind corruption error.
1175    pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1176        Self::persisted_row_decode_corruption()
1177    }
1178
1179    /// Construct the canonical reverse-index relation-target decode invariant failure.
1180    pub(crate) fn reverse_index_relation_target_decode_invariant_violated(
1181        _source_path: &str,
1182        _field_name: &str,
1183        _target_path: &str,
1184    ) -> Self {
1185        Self::executor_internal()
1186    }
1187
1188    /// Construct the canonical covering-component empty-payload corruption error.
1189    pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1190        Self::index_corruption()
1191    }
1192
1193    /// Construct the canonical covering-component truncated bool corruption error.
1194    pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1195        Self::index_corruption()
1196    }
1197
1198    /// Construct the canonical covering-component invalid-length corruption error.
1199    pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1200        Self::index_corruption()
1201    }
1202
1203    /// Construct the canonical covering-component invalid-bool corruption error.
1204    pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1205        Self::index_corruption()
1206    }
1207
1208    /// Construct the canonical covering-component invalid text terminator corruption error.
1209    pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1210        Self::index_corruption()
1211    }
1212
1213    /// Construct the canonical covering-component trailing-text corruption error.
1214    pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1215        Self::index_corruption()
1216    }
1217
1218    /// Construct the canonical covering-component invalid-UTF-8 text corruption error.
1219    pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1220        Self::index_corruption()
1221    }
1222
1223    /// Construct the canonical covering-component invalid text escape corruption error.
1224    pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1225        Self::index_corruption()
1226    }
1227
1228    /// Construct the canonical covering-component missing text terminator corruption error.
1229    pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1230        Self::index_corruption()
1231    }
1232
1233    /// Construct the canonical missing persisted-field decode error.
1234    #[must_use]
1235    pub fn missing_persisted_slot(field_name: &'static str) -> Self {
1236        Self::persisted_row_field_decode_corruption(field_name)
1237    }
1238
1239    /// Construct an identity-origin corruption error.
1240    pub(crate) fn identity_corruption() -> Self {
1241        Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1242    }
1243
1244    /// Construct a store-origin unsupported error.
1245    #[cold]
1246    #[inline(never)]
1247    pub(crate) fn store_unsupported() -> Self {
1248        Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1249    }
1250
1251    /// Construct the canonical schema DDL publication race error.
1252    #[cfg(any(test, feature = "sql"))]
1253    pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &'static str) -> Self {
1254        Self {
1255            class: ErrorClass::Unsupported,
1256            origin: ErrorOrigin::Store,
1257            detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1258        }
1259    }
1260
1261    /// Construct the canonical current physical-rewrite migration rejection.
1262    #[cfg(feature = "sql")]
1263    pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &'static str) -> Self {
1264        Self {
1265            class: ErrorClass::Unsupported,
1266            origin: ErrorOrigin::Store,
1267            detail: Some(ErrorDetail::Store(
1268                StoreError::SchemaDdlRewriteRequiresMigration,
1269            )),
1270        }
1271    }
1272
1273    /// Construct a schema-transition row-layout identity exhaustion error.
1274    pub(crate) fn schema_row_layout_version_exhausted() -> Self {
1275        Self {
1276            class: ErrorClass::Unsupported,
1277            origin: ErrorOrigin::Store,
1278            detail: Some(ErrorDetail::Store(
1279                StoreError::SchemaRowLayoutVersionExhausted,
1280            )),
1281        }
1282    }
1283
1284    /// Construct the fail-closed journal mutation-revision exhaustion error.
1285    pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1286        Self {
1287            class: ErrorClass::Unsupported,
1288            origin: ErrorOrigin::Store,
1289            detail: Some(ErrorDetail::Store(
1290                StoreError::JournalMutationRevisionExhausted,
1291            )),
1292        }
1293    }
1294
1295    /// Construct the hard-cut rejection for a generated field that would
1296    /// collide with an already accepted SQL-DDL-owned slot.
1297    pub(crate) fn schema_generated_field_after_ddl_field() -> Self {
1298        Self {
1299            class: ErrorClass::Unsupported,
1300            origin: ErrorOrigin::Store,
1301            detail: Some(ErrorDetail::Store(
1302                StoreError::SchemaGeneratedFieldAfterDdlField,
1303            )),
1304        }
1305    }
1306
1307    /// Construct the fail-closed conflict for a generated proposal that no
1308    /// longer matches its live accepted constraint activation.
1309    pub(crate) fn schema_generated_constraint_activation_stale() -> Self {
1310        Self {
1311            class: ErrorClass::Conflict,
1312            origin: ErrorOrigin::Store,
1313            detail: Some(ErrorDetail::Store(
1314                StoreError::SchemaGeneratedConstraintActivationStale,
1315            )),
1316        }
1317    }
1318
1319    /// Construct a bounded schema-transition resource rejection.
1320    pub(crate) fn schema_transition_budget_exceeded(
1321        resource: SchemaTransitionBudgetResource,
1322    ) -> Self {
1323        Self {
1324            class: ErrorClass::Unsupported,
1325            origin: ErrorOrigin::Store,
1326            detail: Some(ErrorDetail::Store(
1327                StoreError::SchemaTransitionBudgetExceeded { resource },
1328            )),
1329        }
1330    }
1331
1332    /// Construct the canonical unsupported persisted entity-tag store error.
1333    pub(crate) fn unsupported_entity_tag_in_data_store(
1334        _entity_tag: crate::types::EntityTag,
1335    ) -> Self {
1336        Self::store_unsupported()
1337    }
1338
1339    /// Construct the canonical commit-memory id registration failure.
1340    #[cfg(not(test))]
1341    pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1342        Self::store_internal()
1343    }
1344
1345    /// Construct an index-origin unsupported error.
1346    pub(crate) fn index_unsupported() -> Self {
1347        Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1348    }
1349
1350    /// Construct the canonical index-key component size-limit unsupported error.
1351    pub(crate) fn index_component_exceeds_max_size() -> Self {
1352        Self::index_unsupported()
1353    }
1354
1355    /// Construct a serialize-origin unsupported error.
1356    pub(crate) fn serialize_unsupported() -> Self {
1357        Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1358    }
1359
1360    /// Construct a cursor-origin invalid-continuation error.
1361    pub(crate) fn cursor_invalid_continuation() -> Self {
1362        Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1363    }
1364
1365    /// Construct a serialize-origin incompatible persisted-format error.
1366    pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1367        Self::new(
1368            ErrorClass::IncompatiblePersistedFormat,
1369            ErrorOrigin::Serialize,
1370        )
1371    }
1372
1373    /// Construct a query-origin unsupported error preserving one SQL parser
1374    /// unsupported-feature code in structured error detail.
1375    #[cfg(feature = "sql")]
1376    pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1377        Self {
1378            class: ErrorClass::Unsupported,
1379            origin: ErrorOrigin::Query,
1380            detail: Some(ErrorDetail::Query(
1381                QueryErrorDetail::UnsupportedSqlFeature { feature },
1382            )),
1383        }
1384    }
1385
1386    /// Construct a query-origin unsupported SQL lowering error preserving one
1387    /// compact lowering reason in structured error detail.
1388    #[cfg(feature = "sql")]
1389    pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1390        Self {
1391            class: ErrorClass::Unsupported,
1392            origin: ErrorOrigin::Query,
1393            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1394        }
1395    }
1396
1397    /// Construct a query-origin unsupported projection error preserving one
1398    /// compact projection reason in structured error detail.
1399    pub(crate) fn query_unsupported_projection(
1400        reason: diagnostic_code::QueryProjectionCode,
1401    ) -> Self {
1402        Self {
1403            class: ErrorClass::Unsupported,
1404            origin: ErrorOrigin::Query,
1405            detail: Some(ErrorDetail::Query(
1406                QueryErrorDetail::UnsupportedProjection { reason },
1407            )),
1408        }
1409    }
1410
1411    /// Construct a query-origin unsupported aggregate target-field error.
1412    pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1413        Self {
1414            class: ErrorClass::Unsupported,
1415            origin: ErrorOrigin::Query,
1416            detail: Some(ErrorDetail::Query(
1417                QueryErrorDetail::UnknownAggregateTargetField,
1418            )),
1419        }
1420    }
1421
1422    /// Construct a query-origin result-shape mismatch error preserving one
1423    /// compact result-shape reason in structured error detail.
1424    pub(crate) fn query_result_shape_mismatch(
1425        reason: diagnostic_code::QueryResultShapeCode,
1426    ) -> Self {
1427        Self {
1428            class: ErrorClass::Unsupported,
1429            origin: ErrorOrigin::Query,
1430            detail: Some(ErrorDetail::Query(QueryErrorDetail::ResultShapeMismatch {
1431                reason,
1432            })),
1433        }
1434    }
1435
1436    /// Construct a query-origin unsupported error preserving one SQL endpoint
1437    /// surface mismatch in structured error detail.
1438    #[cfg(feature = "sql")]
1439    pub(crate) fn query_sql_surface_mismatch(
1440        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1441    ) -> Self {
1442        Self {
1443            class: ErrorClass::Unsupported,
1444            origin: ErrorOrigin::Query,
1445            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1446                mismatch,
1447            })),
1448        }
1449    }
1450
1451    /// Construct a query-origin unsupported SQL write boundary error.
1452    pub(crate) fn query_sql_write_boundary(
1453        boundary: diagnostic_code::SqlWriteBoundaryCode,
1454    ) -> Self {
1455        Self {
1456            class: ErrorClass::Unsupported,
1457            origin: ErrorOrigin::Query,
1458            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1459                boundary,
1460            })),
1461        }
1462    }
1463
1464    pub fn store_not_found(_key: impl Sized) -> Self {
1465        Self {
1466            class: ErrorClass::NotFound,
1467            origin: ErrorOrigin::Store,
1468            detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1469        }
1470    }
1471
1472    /// Construct a standardized unsupported-entity-path error.
1473    pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1474        Self::store_unsupported()
1475    }
1476
1477    #[must_use]
1478    pub const fn is_not_found(&self) -> bool {
1479        matches!(self.detail, Some(ErrorDetail::Store(StoreError::NotFound)))
1480    }
1481
1482    /// Construct an index-plan corruption error with a canonical prefix.
1483    #[cold]
1484    #[inline(never)]
1485    pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1486        Self::new(ErrorClass::Corruption, origin)
1487    }
1488
1489    /// Construct an index-plan corruption error for index-origin failures.
1490    #[cold]
1491    #[inline(never)]
1492    pub(crate) fn index_plan_index_corruption() -> Self {
1493        Self::index_plan_corruption(ErrorOrigin::Index)
1494    }
1495
1496    /// Construct an index-plan corruption error for store-origin failures.
1497    #[cold]
1498    #[inline(never)]
1499    pub(crate) fn index_plan_store_corruption() -> Self {
1500        Self::index_plan_corruption(ErrorOrigin::Store)
1501    }
1502
1503    /// Construct an index-plan corruption error for serialize-origin failures.
1504    #[cold]
1505    #[inline(never)]
1506    pub(crate) fn index_plan_serialize_corruption() -> Self {
1507        Self::index_plan_corruption(ErrorOrigin::Serialize)
1508    }
1509
1510    /// Construct an index-plan invariant violation error with a canonical prefix.
1511    #[cfg(test)]
1512    pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1513        Self::new(ErrorClass::InvariantViolation, origin)
1514    }
1515
1516    /// Construct an index-plan invariant violation error for store-origin failures.
1517    #[cfg(test)]
1518    pub(crate) fn index_plan_store_invariant() -> Self {
1519        Self::index_plan_invariant(ErrorOrigin::Store)
1520    }
1521
1522    /// Construct an index uniqueness violation conflict error.
1523    pub(crate) fn index_violation(_path: &str, _index_fields: &[&str]) -> Self {
1524        Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1525    }
1526}
1527
1528impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1529    fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1530        Self {
1531            class: ErrorClass::Unsupported,
1532            origin: ErrorOrigin::Query,
1533            detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1534                reason,
1535            })),
1536        }
1537    }
1538}
1539
1540impl fmt::Debug for InternalError {
1541    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1542        fmt_compact_diagnostic(
1543            f,
1544            self.diagnostic_code(),
1545            self.detail
1546                .as_ref()
1547                .and_then(ErrorDetail::diagnostic_detail),
1548        )
1549    }
1550}
1551
1552impl fmt::Display for InternalError {
1553    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1554        f.write_str(self.message())
1555    }
1556}
1557
1558impl std::error::Error for InternalError {}
1559
1560///
1561/// ConstraintDiagnosticKind
1562///
1563/// Accepted constraint family attached to one bounded runtime diagnostic.
1564/// Accepted schema owns the identity; this enum is its error-boundary projection.
1565///
1566
1567#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1568pub enum ConstraintDiagnosticKind {
1569    /// One accepted canonical check expression.
1570    Check,
1571
1572    /// One accepted or activating not-null field contract.
1573    NotNull,
1574
1575    /// One accepted or activating relation contract.
1576    Relation,
1577
1578    /// One accepted or activating unique-index contract.
1579    Unique,
1580}
1581
1582impl ConstraintDiagnosticKind {
1583    /// Borrow the stable public label for this constraint family.
1584    #[must_use]
1585    pub const fn as_str(self) -> &'static str {
1586        match self {
1587            Self::Check => "check",
1588            Self::NotNull => "not_null",
1589            Self::Relation => "relation",
1590            Self::Unique => "unique",
1591        }
1592    }
1593}
1594
1595///
1596/// ConstraintDiagnosticContext
1597///
1598/// Boundary at which one accepted constraint failure was observed.
1599/// This distinguishes incoming write rejection from historical validation.
1600///
1601
1602#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1603pub enum ConstraintDiagnosticContext {
1604    /// Integrity verification found invalid already-accepted state.
1605    Integrity,
1606
1607    /// Bounded activation validation found an incompatible historical row.
1608    MigrationValidation,
1609
1610    /// A new mutation after-image violated accepted admission authority.
1611    WriteAdmission,
1612}
1613
1614impl ConstraintDiagnosticContext {
1615    /// Borrow the stable public label for this diagnostic context.
1616    #[must_use]
1617    pub const fn as_str(self) -> &'static str {
1618        match self {
1619            Self::Integrity => "integrity",
1620            Self::MigrationValidation => "migration_validation",
1621            Self::WriteAdmission => "write_admission",
1622        }
1623    }
1624}
1625
1626///
1627/// ConstraintDiagnostic
1628///
1629/// One bounded accepted-constraint failure carried through runtime and SQL
1630/// boundaries. It is a projection of accepted identity, not a second schema
1631/// authority, and its compact error code remains the classification owner.
1632///
1633
1634#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
1635pub struct ConstraintDiagnostic {
1636    constraint_id: u32,
1637    constraint_name: String,
1638    constraint_kind: ConstraintDiagnosticKind,
1639    entity: String,
1640    primary_key: Option<Vec<u8>>,
1641    field_paths: Vec<String>,
1642    context: ConstraintDiagnosticContext,
1643    error_code: u16,
1644}
1645
1646impl ConstraintDiagnostic {
1647    /// Build one incoming-write accepted constraint violation.
1648    #[must_use]
1649    pub(crate) const fn write_violation(
1650        constraint_id: u32,
1651        constraint_name: String,
1652        constraint_kind: ConstraintDiagnosticKind,
1653        entity: String,
1654        primary_key: Option<Vec<u8>>,
1655        field_paths: Vec<String>,
1656    ) -> Self {
1657        Self {
1658            constraint_id,
1659            constraint_name,
1660            constraint_kind,
1661            entity,
1662            primary_key,
1663            field_paths,
1664            context: ConstraintDiagnosticContext::WriteAdmission,
1665            error_code: diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_VIOLATION.raw(),
1666        }
1667    }
1668
1669    /// Build one incoming-write activation barrier rejection.
1670    #[must_use]
1671    pub(crate) const fn write_activation_blocked(
1672        constraint_id: u32,
1673        constraint_name: String,
1674        constraint_kind: ConstraintDiagnosticKind,
1675        entity: String,
1676        primary_key: Option<Vec<u8>>,
1677        field_paths: Vec<String>,
1678    ) -> Self {
1679        Self {
1680            constraint_id,
1681            constraint_name,
1682            constraint_kind,
1683            entity,
1684            primary_key,
1685            field_paths,
1686            context: ConstraintDiagnosticContext::WriteAdmission,
1687            error_code:
1688                diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_ACTIVATION_WRITE_BLOCKED
1689                    .raw(),
1690        }
1691    }
1692
1693    /// Build one historical activation finding from its durable compact code.
1694    #[cfg(feature = "sql")]
1695    #[must_use]
1696    pub(crate) const fn migration_validation(
1697        constraint_id: u32,
1698        constraint_name: String,
1699        constraint_kind: ConstraintDiagnosticKind,
1700        entity: String,
1701        primary_key: Vec<u8>,
1702        field_paths: Vec<String>,
1703        error_code: u16,
1704    ) -> Self {
1705        Self {
1706            constraint_id,
1707            constraint_name,
1708            constraint_kind,
1709            entity,
1710            primary_key: Some(primary_key),
1711            field_paths,
1712            context: ConstraintDiagnosticContext::MigrationValidation,
1713            error_code,
1714        }
1715    }
1716
1717    /// Return the stable accepted constraint identity.
1718    #[must_use]
1719    pub const fn constraint_id(&self) -> u32 {
1720        self.constraint_id
1721    }
1722
1723    /// Borrow the stable accepted constraint name.
1724    #[must_use]
1725    pub const fn constraint_name(&self) -> &str {
1726        self.constraint_name.as_str()
1727    }
1728
1729    /// Return the accepted constraint family.
1730    #[must_use]
1731    pub const fn constraint_kind(&self) -> ConstraintDiagnosticKind {
1732        self.constraint_kind
1733    }
1734
1735    /// Borrow the accepted entity identity.
1736    #[must_use]
1737    pub const fn entity(&self) -> &str {
1738        self.entity.as_str()
1739    }
1740
1741    /// Borrow the canonical persisted primary-key bytes when available.
1742    #[must_use]
1743    pub fn primary_key(&self) -> Option<&[u8]> {
1744        self.primary_key.as_deref()
1745    }
1746
1747    /// Borrow bounded accepted field paths implicated by the failure.
1748    #[must_use]
1749    pub const fn field_paths(&self) -> &[String] {
1750        self.field_paths.as_slice()
1751    }
1752
1753    /// Return the boundary that observed the failure.
1754    #[must_use]
1755    pub const fn context(&self) -> ConstraintDiagnosticContext {
1756        self.context
1757    }
1758
1759    /// Return the compact stable error code for this exact failure.
1760    #[must_use]
1761    pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
1762        diagnostic_code::ErrorCode::from_raw(self.error_code)
1763    }
1764
1765    /// Return the broad public error class derived from the compact code.
1766    #[must_use]
1767    pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
1768        self.error_code().class()
1769    }
1770}
1771
1772///
1773/// ErrorDetail
1774///
1775/// Structured, origin-specific error detail carried by [`InternalError`].
1776/// This enum is intentionally extensible.
1777///
1778
1779pub enum ErrorDetail {
1780    /// Executor-owned mutation and query execution details.
1781    Executor(ExecutorErrorDetail),
1782    Store(StoreError),
1783    Query(QueryErrorDetail),
1784    Recovery(RecoveryErrorDetail),
1785    /// Persisted-row serialization and decoding details.
1786    Serialize(SerializeErrorDetail),
1787    // Future-proofing:
1788    // Index(IndexError),
1789}
1790
1791/// Executor-specific structured error detail.
1792pub enum ExecutorErrorDetail {
1793    /// A complete insert or replacement omitted one or more required fields.
1794    MutationRequiredFieldMissing,
1795    /// A final canonical after-image violated one accepted constraint or activation gate.
1796    ConstraintViolation {
1797        diagnostic: Box<ConstraintDiagnostic>,
1798    },
1799    /// Accepted row-constraint metadata or compiled state was inconsistent.
1800    AcceptedRowConstraintProgramCorrupt,
1801    /// A write would rely on one incomplete activation-owned physical proof.
1802    ConstraintActivationWriteBlocked {
1803        diagnostic: Box<ConstraintDiagnostic>,
1804    },
1805}
1806
1807impl ExecutorErrorDetail {
1808    /// Borrow the accepted constraint diagnostic carried by this failure.
1809    #[must_use]
1810    pub fn constraint_diagnostic(&self) -> Option<&ConstraintDiagnostic> {
1811        match self {
1812            Self::ConstraintActivationWriteBlocked { diagnostic }
1813            | Self::ConstraintViolation { diagnostic } => Some(diagnostic.as_ref()),
1814            Self::MutationRequiredFieldMissing | Self::AcceptedRowConstraintProgramCorrupt => None,
1815        }
1816    }
1817}
1818
1819/// Persisted-row serialization and decoding error detail.
1820pub enum SerializeErrorDetail {
1821    /// The row stamp is older or newer than the accepted layout window.
1822    PersistedRowLayoutOutsideAcceptedWindow,
1823
1824    /// The physical slot count does not match the row's stamped layout.
1825    PersistedRowSlotCountMismatch,
1826}
1827
1828///
1829/// RecoveryErrorDetail
1830///
1831/// Recovery-origin structured error detail payload.
1832///
1833
1834pub enum RecoveryErrorDetail {
1835    UnsupportedFormatVersion { found: Option<u16>, required: u16 },
1836
1837    MalformedFormatMarker { reason: RecoveryFormatMarkerError },
1838}
1839
1840/// Store boot-marker corruption classification.
1841#[derive(Clone, Copy, Eq, PartialEq)]
1842pub enum RecoveryFormatMarkerError {
1843    Magic,
1844    Checksum,
1845    State,
1846}
1847
1848///
1849/// StoreError
1850///
1851/// Store-specific structured error detail.
1852/// Never returned directly; always wrapped in [`ErrorDetail::Store`].
1853///
1854
1855pub enum StoreError {
1856    NotFound,
1857
1858    Corrupt,
1859
1860    InvariantViolation,
1861
1862    SchemaDdlPublicationRaceLost,
1863
1864    SchemaDdlRewriteRequiresMigration,
1865
1866    SchemaRowLayoutVersionExhausted,
1867
1868    JournalMutationRevisionExhausted,
1869
1870    SchemaTransitionBudgetExceeded {
1871        resource: SchemaTransitionBudgetResource,
1872    },
1873
1874    /// A generated field would collide with an accepted DDL-owned slot.
1875    SchemaGeneratedFieldAfterDdlField,
1876
1877    /// A live generated constraint activation no longer matches its proposal.
1878    SchemaGeneratedConstraintActivationStale,
1879}
1880
1881///
1882/// QueryErrorDetail
1883///
1884/// Query-origin structured error detail payload.
1885///
1886
1887pub enum QueryErrorDetail {
1888    NumericOverflow,
1889
1890    NumericNotRepresentable,
1891
1892    UnsupportedSqlFeature {
1893        feature: diagnostic_code::SqlFeatureCode,
1894    },
1895
1896    SqlLowering {
1897        reason: diagnostic_code::SqlLoweringCode,
1898    },
1899
1900    UnsupportedProjection {
1901        reason: diagnostic_code::QueryProjectionCode,
1902    },
1903
1904    UnknownAggregateTargetField,
1905
1906    ResultShapeMismatch {
1907        reason: diagnostic_code::QueryResultShapeCode,
1908    },
1909
1910    QueryReadAdmission {
1911        reason: diagnostic_code::QueryReadAdmissionCode,
1912    },
1913
1914    SqlSurfaceMismatch {
1915        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1916    },
1917
1918    SqlWriteBoundary {
1919        boundary: diagnostic_code::SqlWriteBoundaryCode,
1920    },
1921
1922    SchemaDdlAdmission {
1923        error: SchemaDdlAdmissionError,
1924    },
1925
1926    StaleSchemaRevision,
1927}
1928
1929impl fmt::Display for QueryErrorDetail {
1930    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1931        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
1932    }
1933}
1934
1935impl std::error::Error for QueryErrorDetail {}
1936
1937///
1938/// SchemaTransitionBudgetResource
1939///
1940/// Query-visible identity of the exact schema-transition resource cap that
1941/// rejected a complete validation or derived-state stage.
1942///
1943
1944#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1945pub enum SchemaTransitionBudgetResource {
1946    /// Number of physical deletion keys retained for replacement.
1947    DeletionKeys,
1948    /// Number of row-derived projection entries retained for validation.
1949    ProjectionEntries,
1950    /// Deterministic projection and physical-classification work units.
1951    ProjectionWorkUnits,
1952    /// Number of authoritative source rows.
1953    SourceRows,
1954    /// Cumulative bytes of authoritative source rows.
1955    SourceRowBytes,
1956    /// Retained raw payloads plus deterministic-sort workspace bytes.
1957    StagedRawBytes,
1958}
1959
1960///
1961/// SchemaDdlAdmissionError
1962///
1963/// Stable query-visible SQL DDL admission reason. Human diagnostics may carry
1964/// extra version, fingerprint, and target facts beside this machine-readable
1965/// variant.
1966///
1967
1968#[derive(Clone, Copy, Eq, PartialEq)]
1969pub enum SchemaDdlAdmissionError {
1970    MissingExpectedSchemaVersion,
1971
1972    MissingNextSchemaVersion,
1973
1974    StaleExpectedSchemaVersion,
1975
1976    InvalidExpectedSchemaVersion,
1977
1978    InvalidNextSchemaVersion,
1979
1980    AcceptedSchemaChangeWithoutVersionBump,
1981
1982    EmptyVersionBump,
1983
1984    VersionGap,
1985
1986    VersionRollback,
1987
1988    FingerprintMethodMismatch,
1989
1990    UnsupportedTransitionClass,
1991
1992    PhysicalRunnerMissing,
1993
1994    ValidationFailed,
1995
1996    PublicationRaceLost,
1997
1998    InvalidAddColumnDefault,
1999
2000    InvalidAlterColumnDefault,
2001
2002    RowLayoutVersionExhausted,
2003
2004    GeneratedIndexDropRejected,
2005
2006    SchemaRewriteRequiresMigration,
2007
2008    SchemaTransitionBudgetExceeded {
2009        resource: SchemaTransitionBudgetResource,
2010    },
2011
2012    GeneratedFieldDefaultChangeRejected,
2013
2014    GeneratedFieldNullabilityChangeRejected,
2015}
2016
2017impl fmt::Display for SchemaDdlAdmissionError {
2018    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2019        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2020    }
2021}
2022
2023impl std::error::Error for SchemaDdlAdmissionError {}
2024
2025impl fmt::Debug for ErrorDetail {
2026    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2027        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2028    }
2029}
2030
2031impl fmt::Debug for ExecutorErrorDetail {
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 StoreError {
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 QueryErrorDetail {
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 RecoveryErrorDetail {
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 SerializeErrorDetail {
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 RecoveryFormatMarkerError {
2062    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2063        fmt_compact_diagnostic(
2064            f,
2065            diagnostic_code::DiagnosticCode::RuntimeCorruption,
2066            Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2067                kind: diagnostic_code::RuntimeErrorKind::Corruption,
2068            }),
2069        )
2070    }
2071}
2072
2073impl fmt::Debug for SchemaDdlAdmissionError {
2074    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2075        fmt_compact_diagnostic(
2076            f,
2077            diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2078            Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2079                reason: self.diagnostic_code(),
2080            }),
2081        )
2082    }
2083}
2084
2085fn fmt_compact_diagnostic(
2086    f: &mut fmt::Formatter<'_>,
2087    code: diagnostic_code::DiagnosticCode,
2088    detail: Option<diagnostic_code::DiagnosticDetail>,
2089) -> fmt::Result {
2090    write!(
2091        f,
2092        "{}",
2093        diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2094    )
2095}
2096
2097impl ErrorDetail {
2098    /// Return the compact diagnostic code for this structured detail.
2099    #[must_use]
2100    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2101        match self {
2102            Self::Executor(error) => error.diagnostic_code(),
2103            Self::Store(error) => error.diagnostic_code(),
2104            Self::Query(error) => error.diagnostic_code(),
2105            Self::Recovery(error) => error.diagnostic_code(),
2106            Self::Serialize(error) => error.diagnostic_code(),
2107        }
2108    }
2109
2110    /// Return compact structured diagnostic detail when the payload carries one.
2111    #[must_use]
2112    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2113        match self {
2114            Self::Executor(error) => error.diagnostic_detail(),
2115            Self::Store(error) => error.diagnostic_detail(),
2116            Self::Query(error) => error.diagnostic_detail(),
2117            Self::Recovery(error) => error.diagnostic_detail(),
2118            Self::Serialize(error) => error.diagnostic_detail(),
2119        }
2120    }
2121}
2122
2123impl ExecutorErrorDetail {
2124    /// Return the compact diagnostic code for this executor detail.
2125    #[must_use]
2126    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2127        match self {
2128            Self::MutationRequiredFieldMissing => {
2129                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2130            }
2131            Self::ConstraintViolation { diagnostic }
2132            | Self::ConstraintActivationWriteBlocked { diagnostic } => {
2133                diagnostic.error_code().diagnostic_code()
2134            }
2135            Self::AcceptedRowConstraintProgramCorrupt => {
2136                diagnostic_code::DiagnosticCode::RuntimeCorruption
2137            }
2138        }
2139    }
2140
2141    /// Return compact structured diagnostic detail for this executor detail.
2142    #[must_use]
2143    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2144        match self {
2145            Self::MutationRequiredFieldMissing => {
2146                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2147                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2148                })
2149            }
2150            Self::ConstraintViolation { diagnostic }
2151            | Self::ConstraintActivationWriteBlocked { diagnostic } => {
2152                diagnostic.error_code().diagnostic_detail()
2153            }
2154            Self::AcceptedRowConstraintProgramCorrupt => {
2155                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2156                    boundary:
2157                        diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2158                })
2159            }
2160        }
2161    }
2162}
2163
2164impl RecoveryErrorDetail {
2165    /// Return the compact diagnostic code for this recovery detail.
2166    #[must_use]
2167    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2168        match self {
2169            Self::UnsupportedFormatVersion { .. } => {
2170                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2171            }
2172            Self::MalformedFormatMarker { .. } => {
2173                diagnostic_code::DiagnosticCode::RuntimeCorruption
2174            }
2175        }
2176    }
2177
2178    /// Return compact structured diagnostic detail for this recovery detail.
2179    #[must_use]
2180    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2181        let kind = match self {
2182            Self::UnsupportedFormatVersion { .. } => {
2183                diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2184            }
2185            Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2186        };
2187
2188        Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2189    }
2190}
2191
2192impl SerializeErrorDetail {
2193    /// Return the compact diagnostic code for this serialization detail.
2194    #[must_use]
2195    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2196        match self {
2197            Self::PersistedRowLayoutOutsideAcceptedWindow | Self::PersistedRowSlotCountMismatch => {
2198                diagnostic_code::DiagnosticCode::RuntimeCorruption
2199            }
2200        }
2201    }
2202
2203    /// Return compact structured diagnostic detail for this serialization detail.
2204    #[must_use]
2205    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2206        let boundary = match self {
2207            Self::PersistedRowLayoutOutsideAcceptedWindow => {
2208                diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow
2209            }
2210            Self::PersistedRowSlotCountMismatch => {
2211                diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch
2212            }
2213        };
2214
2215        Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary })
2216    }
2217}
2218
2219impl StoreError {
2220    /// Return the compact diagnostic code for this store detail.
2221    #[must_use]
2222    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2223        match self {
2224            Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2225            Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2226            Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2227            Self::SchemaDdlPublicationRaceLost
2228            | Self::SchemaDdlRewriteRequiresMigration
2229            | Self::SchemaRowLayoutVersionExhausted
2230            | Self::SchemaTransitionBudgetExceeded { .. } => {
2231                diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2232            }
2233            Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2234                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2235            }
2236            Self::SchemaGeneratedConstraintActivationStale => {
2237                diagnostic_code::DiagnosticCode::RuntimeConflict
2238            }
2239        }
2240    }
2241
2242    /// Return compact structured diagnostic detail when the store error has one.
2243    #[must_use]
2244    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2245        match self {
2246            Self::SchemaDdlPublicationRaceLost => {
2247                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2248                    reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2249                })
2250            }
2251            Self::SchemaDdlRewriteRequiresMigration => {
2252                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2253                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2254                })
2255            }
2256            Self::SchemaRowLayoutVersionExhausted => {
2257                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2258                    reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2259                })
2260            }
2261            Self::JournalMutationRevisionExhausted => {
2262                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2263                    boundary:
2264                        diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2265                })
2266            }
2267            Self::SchemaTransitionBudgetExceeded { .. } => {
2268                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2269                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2270                })
2271            }
2272            Self::SchemaGeneratedFieldAfterDdlField => {
2273                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2274                    boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2275                })
2276            }
2277            Self::SchemaGeneratedConstraintActivationStale => {
2278                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2279                    boundary:
2280                        diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2281                })
2282            }
2283            Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2284        }
2285    }
2286}
2287
2288impl QueryErrorDetail {
2289    /// Return the compact diagnostic code for this query detail.
2290    #[must_use]
2291    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2292        match self {
2293            Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2294            Self::NumericNotRepresentable => {
2295                diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2296            }
2297            Self::UnsupportedSqlFeature { .. } => {
2298                diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2299            }
2300            Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2301            Self::UnsupportedProjection { .. } => {
2302                diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2303            }
2304            Self::UnknownAggregateTargetField => {
2305                diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2306            }
2307            Self::ResultShapeMismatch { .. } => {
2308                diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
2309            }
2310            Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2311            Self::SqlSurfaceMismatch { .. } => {
2312                diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2313            }
2314            Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2315            Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2316            Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2317        }
2318    }
2319
2320    /// Return compact structured diagnostic detail when the query detail has one.
2321    #[must_use]
2322    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2323        match self {
2324            Self::UnsupportedSqlFeature { feature } => {
2325                Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2326            }
2327            Self::SqlLowering { reason } => {
2328                Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2329            }
2330            Self::UnsupportedProjection { reason } => {
2331                Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2332            }
2333            Self::ResultShapeMismatch { reason } => {
2334                Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
2335            }
2336            Self::QueryReadAdmission { reason } => {
2337                Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2338            }
2339            Self::SqlSurfaceMismatch { mismatch } => {
2340                Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2341                    mismatch: *mismatch,
2342                })
2343            }
2344            Self::SqlWriteBoundary { boundary } => {
2345                Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2346                    boundary: *boundary,
2347                })
2348            }
2349            Self::SchemaDdlAdmission { error } => {
2350                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2351                    reason: error.diagnostic_code(),
2352                })
2353            }
2354            Self::NumericOverflow
2355            | Self::NumericNotRepresentable
2356            | Self::UnknownAggregateTargetField
2357            | Self::StaleSchemaRevision => None,
2358        }
2359    }
2360}
2361
2362impl SchemaDdlAdmissionError {
2363    /// Return the compact diagnostic code for this SQL DDL admission reason.
2364    #[must_use]
2365    pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
2366        match self {
2367            Self::MissingExpectedSchemaVersion => {
2368                diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
2369            }
2370            Self::MissingNextSchemaVersion => {
2371                diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
2372            }
2373            Self::StaleExpectedSchemaVersion => {
2374                diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
2375            }
2376            Self::InvalidExpectedSchemaVersion => {
2377                diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
2378            }
2379            Self::InvalidNextSchemaVersion => {
2380                diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
2381            }
2382            Self::AcceptedSchemaChangeWithoutVersionBump => {
2383                diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
2384            }
2385            Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
2386            Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
2387            Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
2388            Self::FingerprintMethodMismatch => {
2389                diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
2390            }
2391            Self::UnsupportedTransitionClass => {
2392                diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
2393            }
2394            Self::PhysicalRunnerMissing => {
2395                diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
2396            }
2397            Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
2398            Self::PublicationRaceLost => {
2399                diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
2400            }
2401            Self::InvalidAddColumnDefault => {
2402                diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
2403            }
2404            Self::InvalidAlterColumnDefault => {
2405                diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
2406            }
2407            Self::GeneratedIndexDropRejected => {
2408                diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
2409            }
2410            Self::SchemaRewriteRequiresMigration => {
2411                diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
2412            }
2413            Self::SchemaTransitionBudgetExceeded { .. } => {
2414                diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
2415            }
2416            Self::GeneratedFieldDefaultChangeRejected => {
2417                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
2418            }
2419            Self::GeneratedFieldNullabilityChangeRejected => {
2420                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
2421            }
2422            Self::RowLayoutVersionExhausted => {
2423                diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
2424            }
2425        }
2426    }
2427}
2428
2429///
2430/// ErrorClass
2431/// Internal error taxonomy for runtime classification.
2432/// Not a stable API; may change without notice.
2433///
2434
2435#[repr(u8)]
2436#[derive(Clone, Copy, Eq, PartialEq)]
2437pub enum ErrorClass {
2438    Corruption,
2439    IncompatiblePersistedFormat,
2440    NotFound,
2441    Internal,
2442    Conflict,
2443    Unsupported,
2444    InvariantViolation,
2445}
2446
2447impl ErrorClass {
2448    /// Return a compact diagnostic code for this broad class and origin pair.
2449    #[must_use]
2450    pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
2451        match self {
2452            Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
2453                diagnostic_code::DiagnosticCode::StoreCorruption
2454            }
2455            Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
2456            Self::IncompatiblePersistedFormat => {
2457                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2458            }
2459            Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
2460                diagnostic_code::DiagnosticCode::StoreNotFound
2461            }
2462            Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
2463            Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
2464            Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
2465            Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
2466                diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
2467            }
2468            Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
2469            Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
2470                diagnostic_code::DiagnosticCode::StoreInvariantViolation
2471            }
2472            Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
2473        }
2474    }
2475}
2476
2477impl fmt::Debug for ErrorClass {
2478    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2479        write!(f, "{}", *self as u8)
2480    }
2481}
2482
2483///
2484/// ErrorOrigin
2485/// Internal origin taxonomy for runtime classification.
2486/// Not a stable API; may change without notice.
2487///
2488
2489#[repr(u8)]
2490#[derive(Clone, Copy, Eq, PartialEq)]
2491pub enum ErrorOrigin {
2492    Serialize,
2493    Store,
2494    Index,
2495    Identity,
2496    Query,
2497    Planner,
2498    Cursor,
2499    Recovery,
2500    Response,
2501    Executor,
2502    Interface,
2503}
2504
2505impl ErrorOrigin {
2506    /// Return the compact diagnostic origin for this internal origin.
2507    #[must_use]
2508    pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
2509        match self {
2510            Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
2511            Self::Store => diagnostic_code::ErrorOrigin::Store,
2512            Self::Index => diagnostic_code::ErrorOrigin::Index,
2513            Self::Identity => diagnostic_code::ErrorOrigin::Identity,
2514            Self::Query => diagnostic_code::ErrorOrigin::Query,
2515            Self::Planner => diagnostic_code::ErrorOrigin::Planner,
2516            Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
2517            Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
2518            Self::Response => diagnostic_code::ErrorOrigin::Response,
2519            Self::Executor => diagnostic_code::ErrorOrigin::Executor,
2520            Self::Interface => diagnostic_code::ErrorOrigin::Interface,
2521        }
2522    }
2523}
2524
2525impl fmt::Debug for ErrorOrigin {
2526    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2527        write!(f, "{}", *self as u8)
2528    }
2529}