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-expression source-type mismatch invariant.
276    pub(crate) fn index_expression_source_type_mismatch(
277        _index_name: &str,
278        _expression: impl Sized,
279        _expected: impl Sized,
280        _source_label: &str,
281    ) -> Self {
282        Self::index_invariant()
283    }
284
285    /// Construct a planner-origin invariant violation for executor-boundary
286    /// contract drift.
287    #[cold]
288    #[inline(never)]
289    pub(crate) fn planner_executor_invariant() -> Self {
290        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
291    }
292
293    /// Construct a query-origin invariant violation for executor-boundary
294    /// contract drift.
295    #[cold]
296    #[inline(never)]
297    pub(crate) fn query_executor_invariant() -> Self {
298        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
299    }
300
301    /// Construct a cursor-origin invariant violation for executor-boundary
302    /// contract drift.
303    #[cold]
304    #[inline(never)]
305    pub(crate) fn cursor_executor_invariant() -> Self {
306        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
307    }
308
309    /// Construct an executor-origin invariant violation.
310    #[cold]
311    #[inline(never)]
312    pub(crate) fn executor_invariant() -> Self {
313        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
314    }
315
316    /// Construct an executor-origin internal error.
317    #[cold]
318    #[inline(never)]
319    pub(crate) fn executor_internal() -> Self {
320        Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
321    }
322
323    /// Construct an executor-origin unsupported error.
324    #[cold]
325    #[inline(never)]
326    pub(crate) fn executor_unsupported() -> Self {
327        Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
328    }
329
330    /// Construct an executor-origin database-owned-field authorship rejection.
331    pub(crate) fn mutation_database_owned_field_explicit(
332        _entity_path: &str,
333        _field_name: &str,
334    ) -> Self {
335        Self {
336            class: ErrorClass::Unsupported,
337            origin: ErrorOrigin::Executor,
338            detail: Some(ErrorDetail::Executor(
339                ExecutorErrorDetail::MutationDatabaseOwnedFieldExplicit,
340            )),
341        }
342    }
343
344    /// Construct an executor-origin required-field omission rejection.
345    #[must_use]
346    pub fn mutation_required_field_missing(_entity_path: &str, _field_names: &str) -> Self {
347        Self {
348            class: ErrorClass::Unsupported,
349            origin: ErrorOrigin::Executor,
350            detail: Some(ErrorDetail::Executor(
351                ExecutorErrorDetail::MutationRequiredFieldMissing,
352            )),
353        }
354    }
355
356    /// Construct an executor-origin managed-timestamp clock regression.
357    #[must_use]
358    pub(crate) fn mutation_managed_timestamp_regression() -> Self {
359        Self {
360            class: ErrorClass::InvariantViolation,
361            origin: ErrorOrigin::Executor,
362            detail: Some(ErrorDetail::Executor(
363                ExecutorErrorDetail::MutationManagedTimestampRegression,
364            )),
365        }
366    }
367
368    /// Construct an executor-origin accepted constraint or activation-gate violation.
369    pub(crate) fn mutation_constraint_violation(diagnostic: ConstraintDiagnostic) -> Self {
370        Self {
371            class: ErrorClass::InvariantViolation,
372            origin: ErrorOrigin::Executor,
373            detail: Some(ErrorDetail::Executor(
374                ExecutorErrorDetail::ConstraintViolation {
375                    diagnostic: Box::new(diagnostic),
376                },
377            )),
378        }
379    }
380
381    /// Construct an executor-origin corruption failure for row-constraint authority.
382    pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
383        Self {
384            class: ErrorClass::Corruption,
385            origin: ErrorOrigin::Executor,
386            detail: Some(ErrorDetail::Executor(
387                ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
388            )),
389        }
390    }
391
392    /// Construct one typed migration conflict for an incomplete activation gate.
393    pub(crate) fn mutation_constraint_activation_write_blocked(
394        diagnostic: ConstraintDiagnostic,
395    ) -> Self {
396        Self {
397            class: ErrorClass::Conflict,
398            origin: ErrorOrigin::Executor,
399            detail: Some(ErrorDetail::Executor(
400                ExecutorErrorDetail::ConstraintActivationWriteBlocked {
401                    diagnostic: Box::new(diagnostic),
402                },
403            )),
404        }
405    }
406
407    /// Construct an executor-origin mutation unknown-field invariant.
408    pub(crate) fn mutation_structural_field_unknown(_entity_path: &str, _field_name: &str) -> Self {
409        Self::executor_invariant()
410    }
411
412    /// Construct a query-origin scalar page invariant for missing order at the cursor boundary.
413    pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
414        Self::query_executor_invariant()
415    }
416
417    /// Construct a query-origin scalar page invariant for cursor-before-ordering drift.
418    pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
419        Self::query_executor_invariant()
420    }
421
422    /// Construct a query-origin scalar page invariant for pagination-before-ordering drift.
423    pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
424        Self::query_executor_invariant()
425    }
426
427    /// Construct a query-origin fast-stream invariant for route kind/request mismatch.
428    pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
429        Self::query_executor_invariant()
430    }
431
432    /// Construct a query-origin scan invariant for missing index-prefix executable specs.
433    pub(crate) fn secondary_index_prefix_spec_required() -> Self {
434        Self::query_executor_invariant()
435    }
436
437    /// Construct a query-origin scan invariant for missing index-range executable specs.
438    pub(crate) fn index_range_limit_spec_required() -> Self {
439        Self::query_executor_invariant()
440    }
441
442    /// Construct an executor-origin mutation conflict for duplicate atomic save keys.
443    pub(crate) fn mutation_atomic_save_duplicate_key(_entity_path: &str, _key: impl Sized) -> Self {
444        Self {
445            class: ErrorClass::Conflict,
446            origin: ErrorOrigin::Executor,
447            detail: Some(ErrorDetail::Executor(
448                ExecutorErrorDetail::MutationBatchDuplicateKey,
449            )),
450        }
451    }
452
453    /// Construct an executor-origin empty mixed-mutation batch rejection.
454    pub(crate) fn mutation_batch_empty() -> Self {
455        Self::mutation_batch_unsupported(ExecutorErrorDetail::MutationBatchEmpty)
456    }
457
458    /// Construct an executor-origin mixed-mutation item-bound rejection.
459    pub(crate) fn mutation_batch_too_many_items() -> Self {
460        Self::mutation_batch_unsupported(ExecutorErrorDetail::MutationBatchTooManyItems)
461    }
462
463    /// Construct an executor-origin mixed-mutation staged-byte-bound rejection.
464    pub(crate) fn mutation_batch_staged_bytes_exceeded() -> Self {
465        Self::mutation_batch_unsupported(ExecutorErrorDetail::MutationBatchStagedBytesExceeded)
466    }
467
468    /// Construct an executor-origin mixed-mutation result-byte-bound rejection.
469    pub(crate) fn mutation_batch_result_bytes_exceeded() -> Self {
470        Self::mutation_batch_unsupported(ExecutorErrorDetail::MutationBatchResultBytesExceeded)
471    }
472
473    /// Construct an executor-origin mixed-entity batch rejection.
474    pub(crate) fn mutation_batch_entity_mismatch() -> Self {
475        Self {
476            class: ErrorClass::Conflict,
477            origin: ErrorOrigin::Executor,
478            detail: Some(ErrorDetail::Executor(
479                ExecutorErrorDetail::MutationBatchEntityMismatch,
480            )),
481        }
482    }
483
484    fn mutation_batch_unsupported(detail: ExecutorErrorDetail) -> Self {
485        Self {
486            class: ErrorClass::Unsupported,
487            origin: ErrorOrigin::Executor,
488            detail: Some(ErrorDetail::Executor(detail)),
489        }
490    }
491
492    /// Construct an executor-origin mutation invariant for index-store generation drift.
493    pub(crate) fn mutation_index_store_generation_changed(
494        _expected_generation: u64,
495        _observed_generation: u64,
496    ) -> Self {
497        Self::executor_invariant()
498    }
499
500    /// Construct a planner-origin invariant violation.
501    #[cold]
502    #[inline(never)]
503    pub(crate) fn planner_invariant() -> Self {
504        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
505    }
506
507    /// Construct a planner-origin invalid-logical-plan invariant.
508    pub(crate) fn query_invalid_logical_plan() -> Self {
509        Self::planner_invariant()
510    }
511
512    /// Construct a store-origin invariant violation.
513    pub(crate) fn store_invariant() -> Self {
514        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
515    }
516
517    /// Construct a store-origin internal error.
518    #[cold]
519    #[inline(never)]
520    pub(crate) fn store_internal() -> Self {
521        Self::new(ErrorClass::Internal, ErrorOrigin::Store)
522    }
523
524    /// Construct the canonical unconfigured commit-memory id internal error.
525    pub(crate) fn commit_memory_id_unconfigured() -> Self {
526        Self::store_internal()
527    }
528
529    /// Construct the canonical initialized commit-store lookup invariant.
530    pub(crate) fn commit_store_uninitialized() -> Self {
531        Self::store_invariant()
532    }
533
534    /// Construct the canonical commit-memory id mismatch internal error.
535    pub(crate) fn commit_memory_id_mismatch(_cached_id: u8, _configured_id: u8) -> Self {
536        Self::store_internal()
537    }
538
539    /// Construct the canonical commit-memory stable-key mismatch internal error.
540    pub(crate) fn commit_memory_stable_key_mismatch(
541        _cached_key: &str,
542        _configured_key: &str,
543    ) -> Self {
544        Self::store_internal()
545    }
546
547    /// Construct the canonical database-incarnation generation failure.
548    pub(crate) fn database_incarnation_generation_failed() -> Self {
549        Self::store_internal()
550    }
551
552    /// Construct the canonical zero database-incarnation corruption error.
553    pub(crate) fn database_incarnation_invalid() -> Self {
554        Self::store_corruption()
555    }
556
557    /// Construct a recovery-origin incompatible store-format error.
558    pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
559        Self {
560            class: ErrorClass::IncompatiblePersistedFormat,
561            origin: ErrorOrigin::Recovery,
562            detail: Some(ErrorDetail::Recovery(
563                RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
564            )),
565        }
566    }
567
568    /// Construct a recovery-origin malformed store-format marker error.
569    pub(crate) fn recovery_malformed_database_format_marker(
570        reason: RecoveryFormatMarkerError,
571    ) -> Self {
572        Self {
573            class: ErrorClass::Corruption,
574            origin: ErrorOrigin::Recovery,
575            detail: Some(ErrorDetail::Recovery(
576                RecoveryErrorDetail::MalformedFormatMarker { reason },
577            )),
578        }
579    }
580
581    /// Construct a recovery-origin boot control-memory failure.
582    pub(crate) fn recovery_database_format_control_unavailable() -> Self {
583        Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
584    }
585
586    /// Construct a commit control-memory growth failure.
587    pub(crate) fn commit_control_memory_growth_failed() -> Self {
588        Self::store_internal()
589    }
590
591    /// Construct a store-format memory registration failure.
592    #[cfg(not(test))]
593    pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
594        Self::store_internal()
595    }
596
597    /// Construct the canonical recovered-effect verification failure.
598    pub(crate) fn recovery_effect_verification_failed() -> Self {
599        Self::store_corruption()
600    }
601
602    /// Construct an index-origin internal error.
603    #[cold]
604    #[inline(never)]
605    pub(crate) fn index_internal() -> Self {
606        Self::new(ErrorClass::Internal, ErrorOrigin::Index)
607    }
608
609    /// Construct the canonical missing old entity-key internal error for structural index removal.
610    pub(crate) fn structural_index_removal_entity_key_required() -> Self {
611        Self::index_internal()
612    }
613
614    /// Construct the canonical missing new entity-key internal error for structural index insertion.
615    pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
616        Self::index_internal()
617    }
618
619    /// Construct the canonical missing old entity-key internal error for index commit-op removal.
620    pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
621        Self::index_internal()
622    }
623
624    /// Construct the canonical missing new entity-key internal error for index commit-op insertion.
625    pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
626        Self::index_internal()
627    }
628
629    /// Construct a query-origin internal error.
630    #[cfg(test)]
631    pub(crate) fn query_internal() -> Self {
632        Self::new(ErrorClass::Internal, ErrorOrigin::Query)
633    }
634
635    /// Construct a query-origin unsupported error.
636    #[cold]
637    #[inline(never)]
638    pub(crate) fn query_unsupported() -> Self {
639        Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
640    }
641
642    /// Construct a query-origin conflict for execution against a superseded
643    /// accepted schema revision.
644    #[cold]
645    #[inline(never)]
646    pub(crate) fn query_stale_accepted_schema_revision(
647        _expected_revision: u64,
648        _current_revision: Option<u64>,
649    ) -> Self {
650        Self {
651            class: ErrorClass::Conflict,
652            origin: ErrorOrigin::Query,
653            detail: Some(ErrorDetail::Query(QueryErrorDetail::StaleSchemaRevision)),
654        }
655    }
656
657    /// Construct a query-origin SQL DDL admission error with structured detail.
658    #[cold]
659    #[inline(never)]
660    #[cfg(feature = "sql")]
661    pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
662        Self {
663            class: ErrorClass::Unsupported,
664            origin: ErrorOrigin::Query,
665            detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
666                error,
667            })),
668        }
669    }
670
671    /// Construct a query-origin numeric overflow error with structured detail.
672    #[cold]
673    #[inline(never)]
674    pub(crate) fn query_numeric_overflow() -> Self {
675        Self {
676            class: ErrorClass::Unsupported,
677            origin: ErrorOrigin::Query,
678            detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
679        }
680    }
681
682    /// Construct a query-origin non-representable numeric result error with
683    /// structured detail.
684    #[cold]
685    #[inline(never)]
686    pub(crate) fn query_numeric_not_representable() -> Self {
687        Self {
688            class: ErrorClass::Unsupported,
689            origin: ErrorOrigin::Query,
690            detail: Some(ErrorDetail::Query(
691                QueryErrorDetail::NumericNotRepresentable,
692            )),
693        }
694    }
695
696    /// Construct a serialize-origin internal error.
697    #[cold]
698    #[inline(never)]
699    pub(crate) fn serialize_internal() -> Self {
700        Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
701    }
702
703    /// Construct the canonical persisted-row encode internal error.
704    pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
705        Self::persisted_row_encode_internal()
706    }
707
708    /// Construct the compact persisted-row encode internal error.
709    pub(crate) fn persisted_row_encode_internal() -> Self {
710        Self::serialize_internal()
711    }
712
713    /// Construct the compact persisted-row field encode internal error.
714    pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
715        Self::persisted_row_encode_internal()
716    }
717
718    /// Construct a store-origin corruption error.
719    #[cold]
720    #[inline(never)]
721    pub(crate) fn store_corruption() -> Self {
722        Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
723    }
724
725    /// Construct a store-origin commit-marker corruption error.
726    pub(crate) fn commit_corruption() -> Self {
727        Self::store_corruption()
728    }
729
730    /// Construct a store-origin commit-marker component corruption error.
731    pub(crate) fn commit_component_corruption() -> Self {
732        Self::commit_corruption()
733    }
734
735    /// Construct the canonical commit-marker id generation internal error.
736    pub(crate) fn commit_id_generation_failed() -> Self {
737        Self::store_internal()
738    }
739
740    /// Construct the canonical commit-marker payload u32-length-limit error.
741    pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
742        Self::store_unsupported()
743    }
744
745    /// Construct the canonical commit-marker component invalid-length corruption error.
746    pub(crate) fn commit_component_length_invalid() -> Self {
747        Self::commit_corruption()
748    }
749
750    /// Construct the canonical commit-marker max-size corruption error.
751    pub(crate) fn commit_marker_exceeds_max_size() -> Self {
752        Self::commit_corruption()
753    }
754
755    /// Construct the canonical commit-control slot max-size unsupported error.
756    pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
757        Self::store_unsupported()
758    }
759
760    /// Construct the canonical commit-control marker-bytes length-limit error.
761    pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
762        Self::store_unsupported()
763    }
764
765    /// Construct the canonical startup index-rebuild invalid-data-key corruption error.
766    pub(crate) fn startup_index_rebuild_invalid_data_key() -> Self {
767        Self::store_corruption()
768    }
769
770    /// Construct an index-origin corruption error.
771    #[cold]
772    #[inline(never)]
773    pub(crate) fn index_corruption() -> Self {
774        Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
775    }
776
777    /// Construct the canonical unique-validation corruption wrapper.
778    pub(crate) fn index_unique_validation_corruption() -> Self {
779        Self::index_plan_index_corruption()
780    }
781
782    /// Construct the canonical structural index-entry corruption wrapper.
783    pub(crate) fn structural_index_entry_corruption() -> Self {
784        Self::index_plan_index_corruption()
785    }
786
787    /// Construct the canonical missing new entity-key invariant during unique validation.
788    pub(crate) fn index_unique_validation_entity_key_required() -> Self {
789        Self::index_invariant()
790    }
791
792    /// Construct the canonical unique-validation structural row-decode corruption error.
793    pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
794        Self::index_plan_serialize_corruption()
795    }
796
797    /// Construct the canonical unique-validation primary-key slot decode corruption error.
798    pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
799        Self::index_plan_serialize_corruption()
800    }
801
802    /// Construct the canonical unique-validation stored key rebuild corruption error.
803    pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
804        Self::index_plan_serialize_corruption()
805    }
806
807    /// Construct the canonical unique-validation missing-row corruption error.
808    pub(crate) fn index_unique_validation_row_required() -> Self {
809        Self::index_plan_store_corruption()
810    }
811
812    /// Construct the canonical index-only predicate missing-component invariant.
813    pub(crate) fn index_only_predicate_component_required() -> Self {
814        Self::index_invariant()
815    }
816
817    /// Construct the canonical index-scan continuation-envelope invariant.
818    pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
819        Self::index_invariant()
820    }
821
822    /// Construct the canonical index-scan continuation-advancement invariant.
823    pub(crate) fn index_scan_continuation_advancement_required() -> Self {
824        Self::index_invariant()
825    }
826
827    /// Construct the canonical index-scan key-decode corruption error.
828    pub(crate) fn index_scan_key_corrupted_during(
829        _context: &'static str,
830        _err: impl Sized,
831    ) -> Self {
832        Self::index_corruption()
833    }
834
835    /// Construct the canonical index-scan missing projection-component invariant.
836    pub(crate) fn index_projection_component_required(
837        _index_name: &str,
838        _component_index: usize,
839    ) -> Self {
840        Self::index_invariant()
841    }
842
843    /// Construct the canonical scan-time index-entry decode corruption error.
844    pub(crate) fn index_entry_decode_failed() -> Self {
845        Self::index_corruption()
846    }
847
848    /// Construct a serialize-origin corruption error.
849    pub(crate) fn serialize_corruption() -> Self {
850        Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
851    }
852
853    /// Construct the compact persisted-row decode corruption error.
854    pub(crate) fn persisted_row_decode_corruption() -> Self {
855        Self::serialize_corruption()
856    }
857
858    /// Construct a persisted-row layout-window corruption error.
859    pub(crate) fn persisted_row_layout_outside_accepted_window() -> Self {
860        Self {
861            class: ErrorClass::Corruption,
862            origin: ErrorOrigin::Serialize,
863            detail: Some(ErrorDetail::Serialize(
864                SerializeErrorDetail::PersistedRowLayoutOutsideAcceptedWindow,
865            )),
866        }
867    }
868
869    /// Construct a persisted-row stamped-layout slot-count corruption error.
870    pub(crate) fn persisted_row_slot_count_mismatch() -> Self {
871        Self {
872            class: ErrorClass::Corruption,
873            origin: ErrorOrigin::Serialize,
874            detail: Some(ErrorDetail::Serialize(
875                SerializeErrorDetail::PersistedRowSlotCountMismatch,
876            )),
877        }
878    }
879
880    /// Construct the canonical persisted-row field decode corruption error.
881    pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
882        Self::persisted_row_field_decode_corruption(field_name)
883    }
884
885    /// Construct the compact persisted-row field decode corruption error.
886    pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
887        Self::persisted_row_decode_corruption()
888    }
889
890    /// Construct the canonical persisted-row field-kind decode corruption error.
891    pub(crate) fn persisted_row_field_kind_decode_failed(
892        field_name: &str,
893        _field_kind: impl fmt::Debug,
894        _detail: impl Sized,
895    ) -> Self {
896        Self::persisted_row_field_decode_corruption(field_name)
897    }
898
899    /// Construct the canonical persisted-row scalar-payload length corruption error.
900    pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
901        Self::persisted_row_field_decode_corruption(field_name)
902    }
903
904    /// Construct the canonical persisted-row scalar-payload empty-body corruption error.
905    pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
906        Self::persisted_row_field_decode_corruption(field_name)
907    }
908
909    /// Construct the canonical persisted-row scalar-payload invalid-byte corruption error.
910    pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
911        Self::persisted_row_field_decode_corruption(field_name)
912    }
913
914    /// Construct the canonical persisted-row scalar-payload non-finite corruption error.
915    pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
916        Self::persisted_row_field_decode_corruption(field_name)
917    }
918
919    /// Construct the canonical persisted-row invalid text payload corruption error.
920    pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
921        Self::persisted_row_field_decode_corruption(field_name)
922    }
923
924    /// Construct the canonical persisted-row structural slot-lookup invariant.
925    pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
926        Self::index_invariant()
927    }
928
929    /// Construct the canonical persisted-row structural slot-cache invariant.
930    pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
931        _model_path: &str,
932        _slot: usize,
933    ) -> Self {
934        Self::index_invariant()
935    }
936
937    /// Construct the canonical persisted-row primary-key decode corruption error.
938    pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
939        _data_key: impl fmt::Debug,
940        _detail: impl Sized,
941    ) -> Self {
942        Self::persisted_row_decode_corruption()
943    }
944
945    /// Construct the canonical persisted-row missing primary-key slot corruption error.
946    pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
947        Self::persisted_row_decode_corruption()
948    }
949
950    /// Construct the canonical persisted-row key mismatch corruption error.
951    pub(crate) fn persisted_row_key_mismatch() -> Self {
952        Self::store_corruption()
953    }
954
955    /// Construct the canonical persisted-row missing declared-field corruption error.
956    pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
957        Self::persisted_row_field_decode_corruption(field_name)
958    }
959
960    /// Construct the canonical reverse-index ordinal overflow internal error.
961    pub(crate) fn reverse_index_ordinal_overflow(
962        _source_path: &str,
963        _field_name: &str,
964        _target_path: &str,
965        _detail: impl Sized,
966    ) -> Self {
967        Self::index_internal()
968    }
969
970    /// Construct the canonical reverse-index entry corruption error.
971    pub(crate) fn reverse_index_entry_corrupted(
972        _source_path: &str,
973        _field_name: &str,
974        _target_path: &str,
975        _index_key: impl fmt::Debug,
976        _detail: impl Sized,
977    ) -> Self {
978        Self::index_corruption()
979    }
980
981    /// Construct the canonical relation-target store missing internal error.
982    pub(crate) fn relation_target_store_missing(
983        _source_path: &str,
984        _field_name: &str,
985        _target_path: &str,
986        _store_path: &str,
987        _detail: impl Sized,
988    ) -> Self {
989        Self::executor_internal()
990    }
991
992    /// Construct the canonical relation-target key decode corruption error.
993    pub(crate) fn relation_target_key_decode_failed(
994        _context_label: &str,
995        _source_path: &str,
996        _field_name: &str,
997        _target_path: &str,
998        _detail: impl Sized,
999    ) -> Self {
1000        Self::identity_corruption()
1001    }
1002
1003    /// Construct the canonical relation-target entity mismatch corruption error.
1004    pub(crate) fn relation_target_entity_mismatch(
1005        _context_label: &str,
1006        _source_path: &str,
1007        _field_name: &str,
1008        _target_path: &str,
1009        _target_entity_name: &str,
1010        _expected_tag: impl Sized,
1011        _actual_tag: impl Sized,
1012    ) -> Self {
1013        Self::store_corruption()
1014    }
1015
1016    /// Construct the canonical relation-source row decode corruption error.
1017    pub(crate) fn relation_source_row_decode_failed(
1018        _source_path: &str,
1019        _field_name: &str,
1020        _target_path: &str,
1021        _detail: impl Sized,
1022    ) -> Self {
1023        Self::persisted_row_decode_corruption()
1024    }
1025
1026    /// Construct the canonical relation-source unsupported scalar relation-key corruption error.
1027    pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1028        _source_path: &str,
1029        _field_name: &str,
1030        _target_path: &str,
1031    ) -> Self {
1032        Self::persisted_row_decode_corruption()
1033    }
1034
1035    /// Construct the canonical unsupported relation key-kind corruption error.
1036    pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1037        Self::persisted_row_decode_corruption()
1038    }
1039
1040    /// Construct the canonical covering-component empty-payload corruption error.
1041    pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1042        Self::index_corruption()
1043    }
1044
1045    /// Construct the canonical covering-component truncated bool corruption error.
1046    pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1047        Self::index_corruption()
1048    }
1049
1050    /// Construct the canonical covering-component invalid-length corruption error.
1051    pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1052        Self::index_corruption()
1053    }
1054
1055    /// Construct the canonical covering-component invalid-bool corruption error.
1056    pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1057        Self::index_corruption()
1058    }
1059
1060    /// Construct the canonical covering-component invalid text terminator corruption error.
1061    pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1062        Self::index_corruption()
1063    }
1064
1065    /// Construct the canonical covering-component trailing-text corruption error.
1066    pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1067        Self::index_corruption()
1068    }
1069
1070    /// Construct the canonical covering-component invalid-UTF-8 text corruption error.
1071    pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1072        Self::index_corruption()
1073    }
1074
1075    /// Construct the canonical covering-component invalid text escape corruption error.
1076    pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1077        Self::index_corruption()
1078    }
1079
1080    /// Construct the canonical covering-component missing text terminator corruption error.
1081    pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1082        Self::index_corruption()
1083    }
1084
1085    /// Construct an identity-origin corruption error.
1086    pub(crate) fn identity_corruption() -> Self {
1087        Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1088    }
1089
1090    /// Construct the canonical identity-control-state corruption error.
1091    pub(crate) fn identity_state_corruption() -> Self {
1092        Self::identity_corruption()
1093    }
1094
1095    /// Construct the typed stale high-water conflict for identity publication.
1096    pub(crate) fn identity_state_conflict() -> Self {
1097        Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1098    }
1099
1100    /// Construct the bounded identity-state inventory exhaustion error.
1101    pub(crate) fn identity_state_capacity_exhausted() -> Self {
1102        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1103    }
1104
1105    /// Construct the exact unsigned identity-domain exhaustion error.
1106    pub(crate) fn identity_exhausted() -> Self {
1107        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1108    }
1109
1110    /// Construct the bounded pre-key candidate-count exhaustion error.
1111    pub(crate) fn identity_candidate_count_exhausted() -> Self {
1112        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1113    }
1114
1115    /// Construct a store-origin unsupported error.
1116    #[cold]
1117    #[inline(never)]
1118    pub(crate) fn store_unsupported() -> Self {
1119        Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1120    }
1121
1122    /// Construct the typed optimistic/idempotency conflict for schema application.
1123    pub(crate) fn schema_application_conflict() -> Self {
1124        Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1125    }
1126
1127    /// Construct one typed source-migration lifecycle or planning result.
1128    pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1129        let class = match reason.diagnostic_code() {
1130            diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1131            diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1132            diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1133            _ => ErrorClass::Internal,
1134        };
1135        Self {
1136            class,
1137            origin: ErrorOrigin::Store,
1138            detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1139        }
1140    }
1141
1142    /// Construct the canonical schema DDL publication race error.
1143    pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1144        Self {
1145            class: ErrorClass::Unsupported,
1146            origin: ErrorOrigin::Store,
1147            detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1148        }
1149    }
1150
1151    /// Construct the canonical current physical-rewrite migration rejection.
1152    #[cfg(feature = "sql")]
1153    pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1154        Self {
1155            class: ErrorClass::Unsupported,
1156            origin: ErrorOrigin::Store,
1157            detail: Some(ErrorDetail::Store(
1158                StoreError::SchemaDdlRewriteRequiresMigration,
1159            )),
1160        }
1161    }
1162
1163    /// Construct the fail-closed journal mutation-revision exhaustion error.
1164    pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1165        Self {
1166            class: ErrorClass::Unsupported,
1167            origin: ErrorOrigin::Store,
1168            detail: Some(ErrorDetail::Store(
1169                StoreError::JournalMutationRevisionExhausted,
1170            )),
1171        }
1172    }
1173
1174    /// Construct a bounded schema-transition resource rejection.
1175    pub(crate) fn schema_transition_budget_exceeded(
1176        resource: SchemaTransitionBudgetResource,
1177    ) -> Self {
1178        Self {
1179            class: ErrorClass::Unsupported,
1180            origin: ErrorOrigin::Store,
1181            detail: Some(ErrorDetail::Store(
1182                StoreError::SchemaTransitionBudgetExceeded { resource },
1183            )),
1184        }
1185    }
1186
1187    /// Construct the canonical unsupported persisted entity-tag store error.
1188    pub(crate) fn unsupported_entity_tag_in_data_store(
1189        _entity_tag: crate::types::EntityTag,
1190    ) -> Self {
1191        Self::store_unsupported()
1192    }
1193
1194    /// Construct the canonical commit-memory id registration failure.
1195    #[cfg(not(test))]
1196    pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1197        Self::store_internal()
1198    }
1199
1200    /// Construct an index-origin unsupported error.
1201    pub(crate) fn index_unsupported() -> Self {
1202        Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1203    }
1204
1205    /// Construct the canonical index-key component size-limit unsupported error.
1206    pub(crate) fn index_component_exceeds_max_size() -> Self {
1207        Self::index_unsupported()
1208    }
1209
1210    /// Construct a serialize-origin unsupported error.
1211    pub(crate) fn serialize_unsupported() -> Self {
1212        Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1213    }
1214
1215    /// Construct a cursor-origin invalid-continuation error.
1216    pub(crate) fn cursor_invalid_continuation() -> Self {
1217        Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1218    }
1219
1220    /// Construct a serialize-origin incompatible persisted-format error.
1221    pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1222        Self::new(
1223            ErrorClass::IncompatiblePersistedFormat,
1224            ErrorOrigin::Serialize,
1225        )
1226    }
1227
1228    /// Construct a query-origin unsupported error preserving one SQL parser
1229    /// unsupported-feature code in structured error detail.
1230    #[cfg(feature = "sql")]
1231    pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1232        Self {
1233            class: ErrorClass::Unsupported,
1234            origin: ErrorOrigin::Query,
1235            detail: Some(ErrorDetail::Query(
1236                QueryErrorDetail::UnsupportedSqlFeature { feature },
1237            )),
1238        }
1239    }
1240
1241    /// Construct a query-origin unsupported SQL lowering error preserving one
1242    /// compact lowering reason in structured error detail.
1243    #[cfg(feature = "sql")]
1244    pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1245        Self {
1246            class: ErrorClass::Unsupported,
1247            origin: ErrorOrigin::Query,
1248            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1249        }
1250    }
1251
1252    /// Construct a query-origin unsupported projection error preserving one
1253    /// compact projection reason in structured error detail.
1254    pub(crate) fn query_unsupported_projection(
1255        reason: diagnostic_code::QueryProjectionCode,
1256    ) -> Self {
1257        Self {
1258            class: ErrorClass::Unsupported,
1259            origin: ErrorOrigin::Query,
1260            detail: Some(ErrorDetail::Query(
1261                QueryErrorDetail::UnsupportedProjection { reason },
1262            )),
1263        }
1264    }
1265
1266    /// Construct a query-origin unsupported aggregate target-field error.
1267    pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1268        Self {
1269            class: ErrorClass::Unsupported,
1270            origin: ErrorOrigin::Query,
1271            detail: Some(ErrorDetail::Query(
1272                QueryErrorDetail::UnknownAggregateTargetField,
1273            )),
1274        }
1275    }
1276
1277    /// Construct a query-origin unsupported error preserving one SQL endpoint
1278    /// surface mismatch in structured error detail.
1279    #[cfg(feature = "sql")]
1280    pub(crate) fn query_sql_surface_mismatch(
1281        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1282    ) -> Self {
1283        Self {
1284            class: ErrorClass::Unsupported,
1285            origin: ErrorOrigin::Query,
1286            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1287                mismatch,
1288            })),
1289        }
1290    }
1291
1292    /// Construct a query-origin unsupported SQL write boundary error.
1293    pub(crate) fn query_sql_write_boundary(
1294        boundary: diagnostic_code::SqlWriteBoundaryCode,
1295    ) -> Self {
1296        Self {
1297            class: ErrorClass::Unsupported,
1298            origin: ErrorOrigin::Query,
1299            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1300                boundary,
1301            })),
1302        }
1303    }
1304
1305    pub fn store_not_found(_key: impl Sized) -> Self {
1306        Self {
1307            class: ErrorClass::NotFound,
1308            origin: ErrorOrigin::Store,
1309            detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1310        }
1311    }
1312
1313    /// Construct a standardized unsupported-entity-path error.
1314    pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1315        Self::store_unsupported()
1316    }
1317
1318    /// Construct an index-plan corruption error with a canonical prefix.
1319    #[cold]
1320    #[inline(never)]
1321    pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1322        Self::new(ErrorClass::Corruption, origin)
1323    }
1324
1325    /// Construct an index-plan corruption error for index-origin failures.
1326    #[cold]
1327    #[inline(never)]
1328    pub(crate) fn index_plan_index_corruption() -> Self {
1329        Self::index_plan_corruption(ErrorOrigin::Index)
1330    }
1331
1332    /// Construct an index-plan corruption error for store-origin failures.
1333    #[cold]
1334    #[inline(never)]
1335    pub(crate) fn index_plan_store_corruption() -> Self {
1336        Self::index_plan_corruption(ErrorOrigin::Store)
1337    }
1338
1339    /// Construct an index-plan corruption error for serialize-origin failures.
1340    #[cold]
1341    #[inline(never)]
1342    pub(crate) fn index_plan_serialize_corruption() -> Self {
1343        Self::index_plan_corruption(ErrorOrigin::Serialize)
1344    }
1345
1346    /// Construct an index-plan invariant violation error with a canonical prefix.
1347    #[cfg(test)]
1348    pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1349        Self::new(ErrorClass::InvariantViolation, origin)
1350    }
1351
1352    /// Construct an index-plan invariant violation error for store-origin failures.
1353    #[cfg(test)]
1354    pub(crate) fn index_plan_store_invariant() -> Self {
1355        Self::index_plan_invariant(ErrorOrigin::Store)
1356    }
1357
1358    /// Construct an index-origin conflict without claiming accepted identity.
1359    ///
1360    /// Live accepted uniqueness violations use `ConstraintDiagnostic`.
1361    /// Schema-domain staging and activation findings use this compact
1362    /// classification before an accepted write-admission diagnostic exists.
1363    pub(crate) fn index_conflict() -> Self {
1364        Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1365    }
1366}
1367
1368impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1369    fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1370        Self {
1371            class: ErrorClass::Unsupported,
1372            origin: ErrorOrigin::Query,
1373            detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1374                reason,
1375            })),
1376        }
1377    }
1378}
1379
1380impl fmt::Debug for InternalError {
1381    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1382        fmt_compact_diagnostic(
1383            f,
1384            self.diagnostic_code(),
1385            self.detail
1386                .as_ref()
1387                .and_then(ErrorDetail::diagnostic_detail),
1388        )
1389    }
1390}
1391
1392impl fmt::Display for InternalError {
1393    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1394        f.write_str(self.message())
1395    }
1396}
1397
1398impl std::error::Error for InternalError {}
1399
1400///
1401/// ConstraintDiagnosticKind
1402///
1403/// Accepted constraint family attached to one bounded runtime diagnostic.
1404/// Accepted schema owns the identity; this enum is its error-boundary projection.
1405///
1406
1407#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1408pub enum ConstraintDiagnosticKind {
1409    /// One accepted canonical check expression.
1410    Check,
1411
1412    /// One accepted or activating not-null field contract.
1413    NotNull,
1414
1415    /// One accepted or activating relation contract.
1416    Relation,
1417
1418    /// One accepted durable rule over a nominal value below a persisted root.
1419    TargetedRule,
1420
1421    /// One accepted or activating unique-index contract.
1422    Unique,
1423}
1424
1425impl ConstraintDiagnosticKind {
1426    /// Borrow the stable public label for this constraint family.
1427    #[must_use]
1428    pub const fn as_str(self) -> &'static str {
1429        match self {
1430            Self::Check => "check",
1431            Self::NotNull => "not_null",
1432            Self::Relation => "relation",
1433            Self::TargetedRule => "targeted_rule",
1434            Self::Unique => "unique",
1435        }
1436    }
1437}
1438
1439///
1440/// ConstraintValuePathComponent
1441///
1442/// Stable accepted identity or finite-value coordinate in one targeted-rule
1443/// violation. Display names are deliberately absent so renames cannot change
1444/// the diagnostic identity.
1445///
1446
1447#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1448pub enum ConstraintValuePathComponent {
1449    /// Persisted root field whose admitted value was traversed.
1450    RootField { field_id: u32 },
1451
1452    /// Accepted record member selected by immutable composite/member identity.
1453    RecordMember {
1454        composite_type_id: u32,
1455        member_id: u32,
1456    },
1457
1458    /// Tuple element selected by accepted composite identity and ordinal.
1459    TupleElement {
1460        composite_type_id: u32,
1461        ordinal: u32,
1462    },
1463
1464    /// Transparent accepted newtype boundary.
1465    Newtype { composite_type_id: u32 },
1466
1467    /// Selected accepted enum variant.
1468    EnumVariant { enum_type_id: u32, variant_id: u32 },
1469
1470    /// List element in admitted order.
1471    ListElement { index: u32 },
1472
1473    /// Set element in canonical admitted order.
1474    SetElement { index: u32 },
1475
1476    /// Map key in canonical entry order.
1477    MapEntryKey { index: u32 },
1478
1479    /// Map value in canonical entry order.
1480    MapEntryValue { index: u32 },
1481}
1482
1483impl fmt::Display for ConstraintValuePathComponent {
1484    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1485        match self {
1486            Self::RootField { field_id } => write!(f, "field#{field_id}"),
1487            Self::RecordMember {
1488                composite_type_id,
1489                member_id,
1490            } => write!(f, "record#{composite_type_id}.member#{member_id}"),
1491            Self::TupleElement {
1492                composite_type_id,
1493                ordinal,
1494            } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
1495            Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
1496            Self::EnumVariant {
1497                enum_type_id,
1498                variant_id,
1499            } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
1500            Self::ListElement { index } => write!(f, "list[{index}]"),
1501            Self::SetElement { index } => write!(f, "set[{index}]"),
1502            Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
1503            Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
1504        }
1505    }
1506}
1507
1508///
1509/// ConstraintValuePath
1510///
1511/// Bounded typed path to the first deterministic failing value occurrence.
1512///
1513
1514#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
1515pub struct ConstraintValuePath {
1516    components: Vec<ConstraintValuePathComponent>,
1517}
1518
1519impl ConstraintValuePath {
1520    /// Build one already-bounded accepted occurrence path.
1521    #[must_use]
1522    pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
1523        Self { components }
1524    }
1525
1526    /// Borrow the stable accepted components.
1527    #[must_use]
1528    pub const fn components(&self) -> &[ConstraintValuePathComponent] {
1529        self.components.as_slice()
1530    }
1531}
1532
1533impl fmt::Display for ConstraintValuePath {
1534    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1535        for (ordinal, component) in self.components.iter().enumerate() {
1536            if ordinal != 0 {
1537                f.write_str("/")?;
1538            }
1539            component.fmt(f)?;
1540        }
1541        Ok(())
1542    }
1543}
1544
1545///
1546/// ConstraintDiagnosticContext
1547///
1548/// Boundary at which one accepted constraint failure was observed.
1549/// This distinguishes incoming write rejection from historical validation.
1550///
1551
1552#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1553pub enum ConstraintDiagnosticContext {
1554    /// Integrity verification found invalid already-accepted state.
1555    Integrity,
1556
1557    /// Bounded activation validation found an incompatible historical row.
1558    MigrationValidation,
1559
1560    /// A new mutation after-image violated accepted admission authority.
1561    WriteAdmission,
1562}
1563
1564impl ConstraintDiagnosticContext {
1565    /// Borrow the stable public label for this diagnostic context.
1566    #[must_use]
1567    pub const fn as_str(self) -> &'static str {
1568        match self {
1569            Self::Integrity => "integrity",
1570            Self::MigrationValidation => "migration_validation",
1571            Self::WriteAdmission => "write_admission",
1572        }
1573    }
1574}
1575
1576///
1577/// ConstraintDiagnostic
1578///
1579/// One bounded accepted-constraint failure carried through runtime and SQL
1580/// boundaries. It is a projection of accepted identity, not a second schema
1581/// authority, and its compact error code remains the classification owner.
1582///
1583
1584#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
1585pub struct ConstraintDiagnostic {
1586    constraint_id: u32,
1587    constraint_name: String,
1588    constraint_kind: ConstraintDiagnosticKind,
1589    entity: String,
1590    primary_key: Option<Vec<u8>>,
1591    field_paths: Vec<String>,
1592    value_path: Option<Box<ConstraintValuePath>>,
1593    context: ConstraintDiagnosticContext,
1594    error_code: u16,
1595}
1596
1597impl ConstraintDiagnostic {
1598    /// Build one incoming-write accepted constraint violation.
1599    #[must_use]
1600    pub(crate) const fn write_violation(
1601        constraint_id: u32,
1602        constraint_name: String,
1603        constraint_kind: ConstraintDiagnosticKind,
1604        entity: String,
1605        primary_key: Option<Vec<u8>>,
1606        field_paths: Vec<String>,
1607    ) -> Self {
1608        Self {
1609            constraint_id,
1610            constraint_name,
1611            constraint_kind,
1612            entity,
1613            primary_key,
1614            field_paths,
1615            value_path: None,
1616            context: ConstraintDiagnosticContext::WriteAdmission,
1617            error_code: diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_VIOLATION.raw(),
1618        }
1619    }
1620
1621    /// Build one incoming-write targeted-rule violation.
1622    #[must_use]
1623    pub(crate) fn write_targeted_rule_violation(
1624        constraint_id: u32,
1625        constraint_name: String,
1626        entity: String,
1627        primary_key: Option<Vec<u8>>,
1628        field_paths: Vec<String>,
1629        value_path: ConstraintValuePath,
1630    ) -> Self {
1631        Self {
1632            constraint_id,
1633            constraint_name,
1634            constraint_kind: ConstraintDiagnosticKind::TargetedRule,
1635            entity,
1636            primary_key,
1637            field_paths,
1638            value_path: Some(Box::new(value_path)),
1639            context: ConstraintDiagnosticContext::WriteAdmission,
1640            error_code: diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_VIOLATION.raw(),
1641        }
1642    }
1643
1644    /// Build one incoming-write activation barrier rejection.
1645    #[must_use]
1646    pub(crate) const fn write_activation_blocked(
1647        constraint_id: u32,
1648        constraint_name: String,
1649        constraint_kind: ConstraintDiagnosticKind,
1650        entity: String,
1651        primary_key: Option<Vec<u8>>,
1652        field_paths: Vec<String>,
1653    ) -> Self {
1654        Self {
1655            constraint_id,
1656            constraint_name,
1657            constraint_kind,
1658            entity,
1659            primary_key,
1660            field_paths,
1661            value_path: None,
1662            context: ConstraintDiagnosticContext::WriteAdmission,
1663            error_code:
1664                diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_ACTIVATION_WRITE_BLOCKED
1665                    .raw(),
1666        }
1667    }
1668
1669    /// Build one historical activation finding from its durable compact code.
1670    #[must_use]
1671    pub(crate) const fn migration_validation(
1672        constraint_id: u32,
1673        constraint_name: String,
1674        constraint_kind: ConstraintDiagnosticKind,
1675        entity: String,
1676        primary_key: Vec<u8>,
1677        field_paths: Vec<String>,
1678        error_code: u16,
1679    ) -> Self {
1680        Self {
1681            constraint_id,
1682            constraint_name,
1683            constraint_kind,
1684            entity,
1685            primary_key: Some(primary_key),
1686            field_paths,
1687            value_path: None,
1688            context: ConstraintDiagnosticContext::MigrationValidation,
1689            error_code,
1690        }
1691    }
1692
1693    /// Build one historical targeted-rule finding with durable path evidence.
1694    #[must_use]
1695    pub(crate) fn migration_targeted_rule_validation(
1696        constraint_id: u32,
1697        constraint_name: String,
1698        entity: String,
1699        primary_key: Vec<u8>,
1700        field_paths: Vec<String>,
1701        value_path: ConstraintValuePath,
1702        error_code: u16,
1703    ) -> Self {
1704        Self {
1705            constraint_id,
1706            constraint_name,
1707            constraint_kind: ConstraintDiagnosticKind::TargetedRule,
1708            entity,
1709            primary_key: Some(primary_key),
1710            field_paths,
1711            value_path: Some(Box::new(value_path)),
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    /// Borrow the typed concrete value path for a targeted-rule violation.
1754    #[must_use]
1755    pub fn value_path(&self) -> Option<&ConstraintValuePath> {
1756        self.value_path.as_deref()
1757    }
1758
1759    /// Return the boundary that observed the failure.
1760    #[must_use]
1761    pub const fn context(&self) -> ConstraintDiagnosticContext {
1762        self.context
1763    }
1764
1765    /// Return the compact stable error code for this exact failure.
1766    #[must_use]
1767    pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
1768        diagnostic_code::ErrorCode::from_raw(self.error_code)
1769    }
1770
1771    /// Return the broad public error class derived from the compact code.
1772    #[must_use]
1773    pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
1774        self.error_code().class()
1775    }
1776}
1777
1778///
1779/// ErrorDetail
1780///
1781/// Structured, origin-specific error detail carried by [`InternalError`].
1782/// This enum is intentionally extensible.
1783///
1784
1785pub enum ErrorDetail {
1786    /// Executor-owned mutation and query execution details.
1787    Executor(ExecutorErrorDetail),
1788    Store(StoreError),
1789    Query(QueryErrorDetail),
1790    Recovery(RecoveryErrorDetail),
1791    /// Persisted-row serialization and decoding details.
1792    Serialize(SerializeErrorDetail),
1793    // Future-proofing:
1794    // Index(IndexError),
1795}
1796
1797/// Executor-specific structured error detail.
1798pub enum ExecutorErrorDetail {
1799    /// A complete insert or replacement omitted one or more required fields.
1800    MutationRequiredFieldMissing,
1801    /// A logical mutation would move accepted managed time backward.
1802    MutationManagedTimestampRegression,
1803    /// A caller explicitly authored a field owned by accepted database policy.
1804    MutationDatabaseOwnedFieldExplicit,
1805    /// A mixed structural mutation batch contained no operations.
1806    MutationBatchEmpty,
1807    /// A mixed structural mutation batch exceeded its operation-count bound.
1808    MutationBatchTooManyItems,
1809    /// A mixed structural mutation batch exceeded its staged-byte bound.
1810    MutationBatchStagedBytesExceeded,
1811    /// A mixed structural mutation result exceeded its encoded response bound.
1812    MutationBatchResultBytesExceeded,
1813    /// A mixed structural mutation batch resolved to more than one accepted entity.
1814    MutationBatchEntityMismatch,
1815    /// More than one mixed structural operation targeted the same accepted key.
1816    MutationBatchDuplicateKey,
1817    /// A final canonical after-image violated one accepted constraint or activation gate.
1818    ConstraintViolation {
1819        diagnostic: Box<ConstraintDiagnostic>,
1820    },
1821    /// Accepted row-constraint metadata or compiled state was inconsistent.
1822    AcceptedRowConstraintProgramCorrupt,
1823    /// A write would rely on one incomplete activation-owned physical proof.
1824    ConstraintActivationWriteBlocked {
1825        diagnostic: Box<ConstraintDiagnostic>,
1826    },
1827}
1828
1829impl ExecutorErrorDetail {
1830    /// Borrow the accepted constraint diagnostic carried by this failure.
1831    #[must_use]
1832    pub fn constraint_diagnostic(&self) -> Option<&ConstraintDiagnostic> {
1833        match self {
1834            Self::ConstraintActivationWriteBlocked { diagnostic }
1835            | Self::ConstraintViolation { diagnostic } => Some(diagnostic.as_ref()),
1836            Self::MutationRequiredFieldMissing
1837            | Self::MutationManagedTimestampRegression
1838            | Self::MutationDatabaseOwnedFieldExplicit
1839            | Self::MutationBatchEmpty
1840            | Self::MutationBatchTooManyItems
1841            | Self::MutationBatchStagedBytesExceeded
1842            | Self::MutationBatchResultBytesExceeded
1843            | Self::MutationBatchEntityMismatch
1844            | Self::MutationBatchDuplicateKey
1845            | Self::AcceptedRowConstraintProgramCorrupt => None,
1846        }
1847    }
1848}
1849
1850/// Persisted-row serialization and decoding error detail.
1851pub enum SerializeErrorDetail {
1852    /// The row stamp is older or newer than the accepted layout window.
1853    PersistedRowLayoutOutsideAcceptedWindow,
1854
1855    /// The physical slot count does not match the row's stamped layout.
1856    PersistedRowSlotCountMismatch,
1857}
1858
1859///
1860/// RecoveryErrorDetail
1861///
1862/// Recovery-origin structured error detail payload.
1863///
1864
1865pub enum RecoveryErrorDetail {
1866    UnsupportedFormatVersion { found: Option<u16>, required: u16 },
1867
1868    MalformedFormatMarker { reason: RecoveryFormatMarkerError },
1869}
1870
1871/// Store boot-marker corruption classification.
1872#[derive(Clone, Copy, Eq, PartialEq)]
1873pub enum RecoveryFormatMarkerError {
1874    Magic,
1875    Checksum,
1876    State,
1877}
1878
1879///
1880/// StoreError
1881///
1882/// Store-specific structured error detail.
1883/// Never returned directly; always wrapped in [`ErrorDetail::Store`].
1884///
1885
1886pub enum StoreError {
1887    NotFound,
1888
1889    Corrupt,
1890
1891    InvariantViolation,
1892
1893    SchemaDdlPublicationRaceLost,
1894
1895    SchemaDdlRewriteRequiresMigration,
1896
1897    SchemaMigration {
1898        reason: diagnostic_code::SchemaMigrationCode,
1899    },
1900
1901    SchemaRowLayoutVersionExhausted,
1902
1903    JournalMutationRevisionExhausted,
1904
1905    SchemaTransitionBudgetExceeded {
1906        resource: SchemaTransitionBudgetResource,
1907    },
1908
1909    /// A generated field would collide with an accepted DDL-owned slot.
1910    SchemaGeneratedFieldAfterDdlField,
1911
1912    /// A live generated constraint activation no longer matches its proposal.
1913    SchemaGeneratedConstraintActivationStale,
1914}
1915
1916///
1917/// QueryErrorDetail
1918///
1919/// Query-origin structured error detail payload.
1920///
1921
1922pub enum QueryErrorDetail {
1923    NumericOverflow,
1924
1925    NumericNotRepresentable,
1926
1927    UnsupportedSqlFeature {
1928        feature: diagnostic_code::SqlFeatureCode,
1929    },
1930
1931    SqlLowering {
1932        reason: diagnostic_code::SqlLoweringCode,
1933    },
1934
1935    UnsupportedProjection {
1936        reason: diagnostic_code::QueryProjectionCode,
1937    },
1938
1939    UnknownAggregateTargetField,
1940
1941    ResultShapeMismatch {
1942        reason: diagnostic_code::QueryResultShapeCode,
1943    },
1944
1945    QueryReadAdmission {
1946        reason: diagnostic_code::QueryReadAdmissionCode,
1947    },
1948
1949    SqlSurfaceMismatch {
1950        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1951    },
1952
1953    SqlWriteBoundary {
1954        boundary: diagnostic_code::SqlWriteBoundaryCode,
1955    },
1956
1957    SchemaDdlAdmission {
1958        error: SchemaDdlAdmissionError,
1959    },
1960
1961    StaleSchemaRevision,
1962}
1963
1964impl fmt::Display for QueryErrorDetail {
1965    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1966        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
1967    }
1968}
1969
1970impl std::error::Error for QueryErrorDetail {}
1971
1972///
1973/// SchemaTransitionBudgetResource
1974///
1975/// Query-visible identity of the exact schema-transition resource cap that
1976/// rejected a complete validation or derived-state stage.
1977///
1978
1979#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1980pub enum SchemaTransitionBudgetResource {
1981    /// Number of physical deletion keys retained for replacement.
1982    DeletionKeys,
1983    /// Number of row-derived projection entries retained for validation.
1984    ProjectionEntries,
1985    /// Deterministic projection and physical-classification work units.
1986    ProjectionWorkUnits,
1987    /// Number of authoritative source rows.
1988    SourceRows,
1989    /// Cumulative bytes of authoritative source rows.
1990    SourceRowBytes,
1991    /// Retained raw payloads plus deterministic-sort workspace bytes.
1992    StagedRawBytes,
1993}
1994
1995///
1996/// SchemaDdlAdmissionError
1997///
1998/// Stable query-visible SQL DDL admission reason. Human diagnostics may carry
1999/// extra version, fingerprint, and target facts beside this machine-readable
2000/// variant.
2001///
2002
2003#[derive(Clone, Copy, Eq, PartialEq)]
2004pub enum SchemaDdlAdmissionError {
2005    MissingExpectedSchemaVersion,
2006
2007    MissingNextSchemaVersion,
2008
2009    StaleExpectedSchemaVersion,
2010
2011    InvalidExpectedSchemaVersion,
2012
2013    InvalidNextSchemaVersion,
2014
2015    AcceptedSchemaChangeWithoutVersionBump,
2016
2017    EmptyVersionBump,
2018
2019    VersionGap,
2020
2021    VersionRollback,
2022
2023    FingerprintMethodMismatch,
2024
2025    UnsupportedTransitionClass,
2026
2027    PhysicalRunnerMissing,
2028
2029    ValidationFailed,
2030
2031    PublicationRaceLost,
2032
2033    InvalidAddColumnDefault,
2034
2035    InvalidAlterColumnDefault,
2036
2037    RowLayoutVersionExhausted,
2038
2039    GeneratedIndexDropRejected,
2040
2041    SchemaRewriteRequiresMigration,
2042
2043    SchemaTransitionBudgetExceeded {
2044        resource: SchemaTransitionBudgetResource,
2045    },
2046
2047    GeneratedFieldDefaultChangeRejected,
2048
2049    GeneratedFieldNullabilityChangeRejected,
2050}
2051
2052impl fmt::Display for SchemaDdlAdmissionError {
2053    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2054        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2055    }
2056}
2057
2058impl std::error::Error for SchemaDdlAdmissionError {}
2059
2060impl fmt::Debug for ErrorDetail {
2061    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2062        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2063    }
2064}
2065
2066impl fmt::Debug for ExecutorErrorDetail {
2067    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2068        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2069    }
2070}
2071
2072impl fmt::Debug for StoreError {
2073    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2074        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2075    }
2076}
2077
2078impl fmt::Debug for QueryErrorDetail {
2079    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2080        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2081    }
2082}
2083
2084impl fmt::Debug for RecoveryErrorDetail {
2085    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2086        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2087    }
2088}
2089
2090impl fmt::Debug for SerializeErrorDetail {
2091    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2092        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2093    }
2094}
2095
2096impl fmt::Debug for RecoveryFormatMarkerError {
2097    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2098        fmt_compact_diagnostic(
2099            f,
2100            diagnostic_code::DiagnosticCode::RuntimeCorruption,
2101            Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2102                kind: diagnostic_code::RuntimeErrorKind::Corruption,
2103            }),
2104        )
2105    }
2106}
2107
2108impl fmt::Debug for SchemaDdlAdmissionError {
2109    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2110        fmt_compact_diagnostic(
2111            f,
2112            diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2113            Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2114                reason: self.diagnostic_code(),
2115            }),
2116        )
2117    }
2118}
2119
2120fn fmt_compact_diagnostic(
2121    f: &mut fmt::Formatter<'_>,
2122    code: diagnostic_code::DiagnosticCode,
2123    detail: Option<diagnostic_code::DiagnosticDetail>,
2124) -> fmt::Result {
2125    write!(
2126        f,
2127        "{}",
2128        diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2129    )
2130}
2131
2132impl ErrorDetail {
2133    /// Return the compact diagnostic code for this structured detail.
2134    #[must_use]
2135    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2136        match self {
2137            Self::Executor(error) => error.diagnostic_code(),
2138            Self::Store(error) => error.diagnostic_code(),
2139            Self::Query(error) => error.diagnostic_code(),
2140            Self::Recovery(error) => error.diagnostic_code(),
2141            Self::Serialize(error) => error.diagnostic_code(),
2142        }
2143    }
2144
2145    /// Return compact structured diagnostic detail when the payload carries one.
2146    #[must_use]
2147    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2148        match self {
2149            Self::Executor(error) => error.diagnostic_detail(),
2150            Self::Store(error) => error.diagnostic_detail(),
2151            Self::Query(error) => error.diagnostic_detail(),
2152            Self::Recovery(error) => error.diagnostic_detail(),
2153            Self::Serialize(error) => error.diagnostic_detail(),
2154        }
2155    }
2156}
2157
2158impl ExecutorErrorDetail {
2159    /// Return the compact diagnostic code for this executor detail.
2160    #[must_use]
2161    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2162        match self {
2163            Self::MutationRequiredFieldMissing
2164            | Self::MutationDatabaseOwnedFieldExplicit
2165            | Self::MutationBatchEmpty
2166            | Self::MutationBatchTooManyItems
2167            | Self::MutationBatchStagedBytesExceeded
2168            | Self::MutationBatchResultBytesExceeded => {
2169                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2170            }
2171            Self::MutationBatchEntityMismatch | Self::MutationBatchDuplicateKey => {
2172                diagnostic_code::DiagnosticCode::RuntimeConflict
2173            }
2174            Self::MutationManagedTimestampRegression => {
2175                diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2176            }
2177            Self::ConstraintViolation { diagnostic }
2178            | Self::ConstraintActivationWriteBlocked { diagnostic } => {
2179                diagnostic.error_code().diagnostic_code()
2180            }
2181            Self::AcceptedRowConstraintProgramCorrupt => {
2182                diagnostic_code::DiagnosticCode::RuntimeCorruption
2183            }
2184        }
2185    }
2186
2187    /// Return compact structured diagnostic detail for this executor detail.
2188    #[must_use]
2189    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2190        match self {
2191            Self::MutationRequiredFieldMissing => {
2192                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2193                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2194                })
2195            }
2196            Self::MutationDatabaseOwnedFieldExplicit => {
2197                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2198                    boundary:
2199                        diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2200                })
2201            }
2202            Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2203                boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2204            }),
2205            Self::MutationBatchTooManyItems => {
2206                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2207                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2208                })
2209            }
2210            Self::MutationBatchStagedBytesExceeded => {
2211                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2212                    boundary:
2213                        diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2214                })
2215            }
2216            Self::MutationBatchResultBytesExceeded => {
2217                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2218                    boundary:
2219                        diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2220                })
2221            }
2222            Self::MutationBatchEntityMismatch => {
2223                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2224                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
2225                })
2226            }
2227            Self::MutationBatchDuplicateKey => {
2228                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2229                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2230                })
2231            }
2232            Self::MutationManagedTimestampRegression => {
2233                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2234                    boundary:
2235                        diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2236                })
2237            }
2238            Self::ConstraintViolation { diagnostic }
2239            | Self::ConstraintActivationWriteBlocked { diagnostic } => {
2240                diagnostic.error_code().diagnostic_detail()
2241            }
2242            Self::AcceptedRowConstraintProgramCorrupt => {
2243                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2244                    boundary:
2245                        diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2246                })
2247            }
2248        }
2249    }
2250}
2251
2252impl RecoveryErrorDetail {
2253    /// Return the compact diagnostic code for this recovery detail.
2254    #[must_use]
2255    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2256        match self {
2257            Self::UnsupportedFormatVersion { .. } => {
2258                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2259            }
2260            Self::MalformedFormatMarker { .. } => {
2261                diagnostic_code::DiagnosticCode::RuntimeCorruption
2262            }
2263        }
2264    }
2265
2266    /// Return compact structured diagnostic detail for this recovery detail.
2267    #[must_use]
2268    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2269        let kind = match self {
2270            Self::UnsupportedFormatVersion { .. } => {
2271                diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2272            }
2273            Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2274        };
2275
2276        Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2277    }
2278}
2279
2280impl SerializeErrorDetail {
2281    /// Return the compact diagnostic code for this serialization detail.
2282    #[must_use]
2283    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2284        match self {
2285            Self::PersistedRowLayoutOutsideAcceptedWindow | Self::PersistedRowSlotCountMismatch => {
2286                diagnostic_code::DiagnosticCode::RuntimeCorruption
2287            }
2288        }
2289    }
2290
2291    /// Return compact structured diagnostic detail for this serialization detail.
2292    #[must_use]
2293    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2294        let boundary = match self {
2295            Self::PersistedRowLayoutOutsideAcceptedWindow => {
2296                diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow
2297            }
2298            Self::PersistedRowSlotCountMismatch => {
2299                diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch
2300            }
2301        };
2302
2303        Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary })
2304    }
2305}
2306
2307impl StoreError {
2308    /// Return the compact diagnostic code for this store detail.
2309    #[must_use]
2310    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2311        match self {
2312            Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2313            Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2314            Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2315            Self::SchemaDdlPublicationRaceLost
2316            | Self::SchemaDdlRewriteRequiresMigration
2317            | Self::SchemaRowLayoutVersionExhausted
2318            | Self::SchemaTransitionBudgetExceeded { .. } => {
2319                diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2320            }
2321            Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2322                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2323            }
2324            Self::SchemaGeneratedConstraintActivationStale => {
2325                diagnostic_code::DiagnosticCode::RuntimeConflict
2326            }
2327            Self::SchemaMigration { reason } => reason.diagnostic_code(),
2328        }
2329    }
2330
2331    /// Return compact structured diagnostic detail when the store error has one.
2332    #[must_use]
2333    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2334        match self {
2335            Self::SchemaDdlPublicationRaceLost => {
2336                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2337                    reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2338                })
2339            }
2340            Self::SchemaDdlRewriteRequiresMigration => {
2341                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2342                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2343                })
2344            }
2345            Self::SchemaMigration { reason } => {
2346                Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2347            }
2348            Self::SchemaRowLayoutVersionExhausted => {
2349                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2350                    reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2351                })
2352            }
2353            Self::JournalMutationRevisionExhausted => {
2354                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2355                    boundary:
2356                        diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2357                })
2358            }
2359            Self::SchemaTransitionBudgetExceeded { .. } => {
2360                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2361                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2362                })
2363            }
2364            Self::SchemaGeneratedFieldAfterDdlField => {
2365                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2366                    boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2367                })
2368            }
2369            Self::SchemaGeneratedConstraintActivationStale => {
2370                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2371                    boundary:
2372                        diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2373                })
2374            }
2375            Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2376        }
2377    }
2378}
2379
2380impl QueryErrorDetail {
2381    /// Return the compact diagnostic code for this query detail.
2382    #[must_use]
2383    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2384        match self {
2385            Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2386            Self::NumericNotRepresentable => {
2387                diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2388            }
2389            Self::UnsupportedSqlFeature { .. } => {
2390                diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2391            }
2392            Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2393            Self::UnsupportedProjection { .. } => {
2394                diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2395            }
2396            Self::UnknownAggregateTargetField => {
2397                diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2398            }
2399            Self::ResultShapeMismatch { .. } => {
2400                diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
2401            }
2402            Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2403            Self::SqlSurfaceMismatch { .. } => {
2404                diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2405            }
2406            Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2407            Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2408            Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2409        }
2410    }
2411
2412    /// Return compact structured diagnostic detail when the query detail has one.
2413    #[must_use]
2414    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2415        match self {
2416            Self::UnsupportedSqlFeature { feature } => {
2417                Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2418            }
2419            Self::SqlLowering { reason } => {
2420                Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2421            }
2422            Self::UnsupportedProjection { reason } => {
2423                Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2424            }
2425            Self::ResultShapeMismatch { reason } => {
2426                Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
2427            }
2428            Self::QueryReadAdmission { reason } => {
2429                Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2430            }
2431            Self::SqlSurfaceMismatch { mismatch } => {
2432                Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2433                    mismatch: *mismatch,
2434                })
2435            }
2436            Self::SqlWriteBoundary { boundary } => {
2437                Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2438                    boundary: *boundary,
2439                })
2440            }
2441            Self::SchemaDdlAdmission { error } => {
2442                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2443                    reason: error.diagnostic_code(),
2444                })
2445            }
2446            Self::NumericOverflow
2447            | Self::NumericNotRepresentable
2448            | Self::UnknownAggregateTargetField
2449            | Self::StaleSchemaRevision => None,
2450        }
2451    }
2452}
2453
2454impl SchemaDdlAdmissionError {
2455    /// Return the compact diagnostic code for this SQL DDL admission reason.
2456    #[must_use]
2457    pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
2458        match self {
2459            Self::MissingExpectedSchemaVersion => {
2460                diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
2461            }
2462            Self::MissingNextSchemaVersion => {
2463                diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
2464            }
2465            Self::StaleExpectedSchemaVersion => {
2466                diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
2467            }
2468            Self::InvalidExpectedSchemaVersion => {
2469                diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
2470            }
2471            Self::InvalidNextSchemaVersion => {
2472                diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
2473            }
2474            Self::AcceptedSchemaChangeWithoutVersionBump => {
2475                diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
2476            }
2477            Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
2478            Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
2479            Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
2480            Self::FingerprintMethodMismatch => {
2481                diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
2482            }
2483            Self::UnsupportedTransitionClass => {
2484                diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
2485            }
2486            Self::PhysicalRunnerMissing => {
2487                diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
2488            }
2489            Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
2490            Self::PublicationRaceLost => {
2491                diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
2492            }
2493            Self::InvalidAddColumnDefault => {
2494                diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
2495            }
2496            Self::InvalidAlterColumnDefault => {
2497                diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
2498            }
2499            Self::GeneratedIndexDropRejected => {
2500                diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
2501            }
2502            Self::SchemaRewriteRequiresMigration => {
2503                diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
2504            }
2505            Self::SchemaTransitionBudgetExceeded { .. } => {
2506                diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
2507            }
2508            Self::GeneratedFieldDefaultChangeRejected => {
2509                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
2510            }
2511            Self::GeneratedFieldNullabilityChangeRejected => {
2512                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
2513            }
2514            Self::RowLayoutVersionExhausted => {
2515                diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
2516            }
2517        }
2518    }
2519}
2520
2521///
2522/// ErrorClass
2523/// Internal error taxonomy for runtime classification.
2524/// Not a stable API; may change without notice.
2525///
2526
2527#[repr(u8)]
2528#[derive(Clone, Copy, Eq, PartialEq)]
2529pub enum ErrorClass {
2530    Corruption,
2531    IncompatiblePersistedFormat,
2532    NotFound,
2533    Internal,
2534    Conflict,
2535    Unsupported,
2536    InvariantViolation,
2537}
2538
2539impl ErrorClass {
2540    /// Return a compact diagnostic code for this broad class and origin pair.
2541    #[must_use]
2542    pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
2543        match self {
2544            Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
2545                diagnostic_code::DiagnosticCode::StoreCorruption
2546            }
2547            Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
2548            Self::IncompatiblePersistedFormat => {
2549                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2550            }
2551            Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
2552                diagnostic_code::DiagnosticCode::StoreNotFound
2553            }
2554            Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
2555            Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
2556            Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
2557            Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
2558                diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
2559            }
2560            Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
2561            Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
2562                diagnostic_code::DiagnosticCode::StoreInvariantViolation
2563            }
2564            Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
2565        }
2566    }
2567}
2568
2569impl fmt::Debug for ErrorClass {
2570    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2571        write!(f, "{}", *self as u8)
2572    }
2573}
2574
2575///
2576/// ErrorOrigin
2577/// Internal origin taxonomy for runtime classification.
2578/// Not a stable API; may change without notice.
2579///
2580
2581#[repr(u8)]
2582#[derive(Clone, Copy, Eq, PartialEq)]
2583pub enum ErrorOrigin {
2584    Serialize,
2585    Store,
2586    Index,
2587    Identity,
2588    Query,
2589    Planner,
2590    Cursor,
2591    Recovery,
2592    Response,
2593    Executor,
2594    Interface,
2595}
2596
2597impl ErrorOrigin {
2598    /// Return the compact diagnostic origin for this internal origin.
2599    #[must_use]
2600    pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
2601        match self {
2602            Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
2603            Self::Store => diagnostic_code::ErrorOrigin::Store,
2604            Self::Index => diagnostic_code::ErrorOrigin::Index,
2605            Self::Identity => diagnostic_code::ErrorOrigin::Identity,
2606            Self::Query => diagnostic_code::ErrorOrigin::Query,
2607            Self::Planner => diagnostic_code::ErrorOrigin::Planner,
2608            Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
2609            Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
2610            Self::Response => diagnostic_code::ErrorOrigin::Response,
2611            Self::Executor => diagnostic_code::ErrorOrigin::Executor,
2612            Self::Interface => diagnostic_code::ErrorOrigin::Interface,
2613        }
2614    }
2615}
2616
2617impl fmt::Debug for ErrorOrigin {
2618    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2619        write!(f, "{}", *self as u8)
2620    }
2621}