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