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 the canonical missing persisted-field decode error.
1115    #[must_use]
1116    pub fn missing_persisted_slot(field_name: &'static str) -> Self {
1117        Self::persisted_row_field_decode_corruption(field_name)
1118    }
1119
1120    /// Construct an identity-origin corruption error.
1121    pub(crate) fn identity_corruption() -> Self {
1122        Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1123    }
1124
1125    /// Construct the canonical identity-control-state corruption error.
1126    pub(crate) fn identity_state_corruption() -> Self {
1127        Self::identity_corruption()
1128    }
1129
1130    /// Construct the typed stale high-water conflict for identity publication.
1131    pub(crate) fn identity_state_conflict() -> Self {
1132        Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1133    }
1134
1135    /// Construct the bounded identity-state inventory exhaustion error.
1136    pub(crate) fn identity_state_capacity_exhausted() -> Self {
1137        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1138    }
1139
1140    /// Construct the exact unsigned identity-domain exhaustion error.
1141    pub(crate) fn identity_exhausted() -> Self {
1142        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1143    }
1144
1145    /// Construct the bounded pre-key candidate-count exhaustion error.
1146    pub(crate) fn identity_candidate_count_exhausted() -> Self {
1147        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1148    }
1149
1150    /// Construct a store-origin unsupported error.
1151    #[cold]
1152    #[inline(never)]
1153    pub(crate) fn store_unsupported() -> Self {
1154        Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1155    }
1156
1157    /// Construct the typed optimistic/idempotency conflict for schema application.
1158    pub(crate) fn schema_application_conflict() -> Self {
1159        Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1160    }
1161
1162    /// Construct the canonical schema DDL publication race error.
1163    #[cfg(any(test, feature = "query"))]
1164    pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1165        Self {
1166            class: ErrorClass::Unsupported,
1167            origin: ErrorOrigin::Store,
1168            detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1169        }
1170    }
1171
1172    /// Construct the canonical current physical-rewrite migration rejection.
1173    #[cfg(feature = "sql")]
1174    pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1175        Self {
1176            class: ErrorClass::Unsupported,
1177            origin: ErrorOrigin::Store,
1178            detail: Some(ErrorDetail::Store(
1179                StoreError::SchemaDdlRewriteRequiresMigration,
1180            )),
1181        }
1182    }
1183
1184    /// Construct the fail-closed journal mutation-revision exhaustion error.
1185    pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1186        Self {
1187            class: ErrorClass::Unsupported,
1188            origin: ErrorOrigin::Store,
1189            detail: Some(ErrorDetail::Store(
1190                StoreError::JournalMutationRevisionExhausted,
1191            )),
1192        }
1193    }
1194
1195    /// Construct a bounded schema-transition resource rejection.
1196    pub(crate) fn schema_transition_budget_exceeded(
1197        resource: SchemaTransitionBudgetResource,
1198    ) -> Self {
1199        Self {
1200            class: ErrorClass::Unsupported,
1201            origin: ErrorOrigin::Store,
1202            detail: Some(ErrorDetail::Store(
1203                StoreError::SchemaTransitionBudgetExceeded { resource },
1204            )),
1205        }
1206    }
1207
1208    /// Construct the canonical unsupported persisted entity-tag store error.
1209    pub(crate) fn unsupported_entity_tag_in_data_store(
1210        _entity_tag: crate::types::EntityTag,
1211    ) -> Self {
1212        Self::store_unsupported()
1213    }
1214
1215    /// Construct the canonical commit-memory id registration failure.
1216    #[cfg(not(test))]
1217    pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1218        Self::store_internal()
1219    }
1220
1221    /// Construct an index-origin unsupported error.
1222    pub(crate) fn index_unsupported() -> Self {
1223        Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1224    }
1225
1226    /// Construct the canonical index-key component size-limit unsupported error.
1227    pub(crate) fn index_component_exceeds_max_size() -> Self {
1228        Self::index_unsupported()
1229    }
1230
1231    /// Construct a serialize-origin unsupported error.
1232    pub(crate) fn serialize_unsupported() -> Self {
1233        Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1234    }
1235
1236    /// Construct a cursor-origin invalid-continuation error.
1237    #[cfg(any(test, feature = "query"))]
1238    pub(crate) fn cursor_invalid_continuation() -> Self {
1239        Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1240    }
1241
1242    /// Construct a serialize-origin incompatible persisted-format error.
1243    pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1244        Self::new(
1245            ErrorClass::IncompatiblePersistedFormat,
1246            ErrorOrigin::Serialize,
1247        )
1248    }
1249
1250    /// Construct a query-origin unsupported error preserving one SQL parser
1251    /// unsupported-feature code in structured error detail.
1252    #[cfg(feature = "sql")]
1253    pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1254        Self {
1255            class: ErrorClass::Unsupported,
1256            origin: ErrorOrigin::Query,
1257            detail: Some(ErrorDetail::Query(
1258                QueryErrorDetail::UnsupportedSqlFeature { feature },
1259            )),
1260        }
1261    }
1262
1263    /// Construct a query-origin unsupported SQL lowering error preserving one
1264    /// compact lowering reason in structured error detail.
1265    #[cfg(feature = "sql")]
1266    pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1267        Self {
1268            class: ErrorClass::Unsupported,
1269            origin: ErrorOrigin::Query,
1270            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1271        }
1272    }
1273
1274    /// Construct a query-origin unsupported projection error preserving one
1275    /// compact projection reason in structured error detail.
1276    #[cfg(any(test, feature = "query"))]
1277    pub(crate) fn query_unsupported_projection(
1278        reason: diagnostic_code::QueryProjectionCode,
1279    ) -> Self {
1280        Self {
1281            class: ErrorClass::Unsupported,
1282            origin: ErrorOrigin::Query,
1283            detail: Some(ErrorDetail::Query(
1284                QueryErrorDetail::UnsupportedProjection { reason },
1285            )),
1286        }
1287    }
1288
1289    /// Construct a query-origin unsupported aggregate target-field error.
1290    #[cfg(any(test, feature = "query"))]
1291    pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1292        Self {
1293            class: ErrorClass::Unsupported,
1294            origin: ErrorOrigin::Query,
1295            detail: Some(ErrorDetail::Query(
1296                QueryErrorDetail::UnknownAggregateTargetField,
1297            )),
1298        }
1299    }
1300
1301    /// Construct a query-origin unsupported error preserving one SQL endpoint
1302    /// surface mismatch in structured error detail.
1303    #[cfg(feature = "sql")]
1304    pub(crate) fn query_sql_surface_mismatch(
1305        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1306    ) -> Self {
1307        Self {
1308            class: ErrorClass::Unsupported,
1309            origin: ErrorOrigin::Query,
1310            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1311                mismatch,
1312            })),
1313        }
1314    }
1315
1316    /// Construct a query-origin unsupported SQL write boundary error.
1317    pub(crate) fn query_sql_write_boundary(
1318        boundary: diagnostic_code::SqlWriteBoundaryCode,
1319    ) -> Self {
1320        Self {
1321            class: ErrorClass::Unsupported,
1322            origin: ErrorOrigin::Query,
1323            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1324                boundary,
1325            })),
1326        }
1327    }
1328
1329    pub fn store_not_found(_key: impl Sized) -> Self {
1330        Self {
1331            class: ErrorClass::NotFound,
1332            origin: ErrorOrigin::Store,
1333            detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1334        }
1335    }
1336
1337    /// Construct a standardized unsupported-entity-path error.
1338    pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1339        Self::store_unsupported()
1340    }
1341
1342    #[must_use]
1343    pub const fn is_not_found(&self) -> bool {
1344        matches!(self.detail, Some(ErrorDetail::Store(StoreError::NotFound)))
1345    }
1346
1347    /// Construct an index-plan corruption error with a canonical prefix.
1348    #[cold]
1349    #[inline(never)]
1350    pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1351        Self::new(ErrorClass::Corruption, origin)
1352    }
1353
1354    /// Construct an index-plan corruption error for index-origin failures.
1355    #[cold]
1356    #[inline(never)]
1357    pub(crate) fn index_plan_index_corruption() -> Self {
1358        Self::index_plan_corruption(ErrorOrigin::Index)
1359    }
1360
1361    /// Construct an index-plan corruption error for store-origin failures.
1362    #[cold]
1363    #[inline(never)]
1364    pub(crate) fn index_plan_store_corruption() -> Self {
1365        Self::index_plan_corruption(ErrorOrigin::Store)
1366    }
1367
1368    /// Construct an index-plan corruption error for serialize-origin failures.
1369    #[cold]
1370    #[inline(never)]
1371    pub(crate) fn index_plan_serialize_corruption() -> Self {
1372        Self::index_plan_corruption(ErrorOrigin::Serialize)
1373    }
1374
1375    /// Construct an index-plan invariant violation error with a canonical prefix.
1376    #[cfg(test)]
1377    pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1378        Self::new(ErrorClass::InvariantViolation, origin)
1379    }
1380
1381    /// Construct an index-plan invariant violation error for store-origin failures.
1382    #[cfg(test)]
1383    pub(crate) fn index_plan_store_invariant() -> Self {
1384        Self::index_plan_invariant(ErrorOrigin::Store)
1385    }
1386
1387    /// Construct an index-origin conflict without claiming accepted identity.
1388    ///
1389    /// Live accepted uniqueness violations use `ConstraintDiagnostic`.
1390    /// Schema-domain staging and activation findings use this compact
1391    /// classification before an accepted write-admission diagnostic exists.
1392    pub(crate) fn index_conflict() -> Self {
1393        Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1394    }
1395}
1396
1397impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1398    fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1399        Self {
1400            class: ErrorClass::Unsupported,
1401            origin: ErrorOrigin::Query,
1402            detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1403                reason,
1404            })),
1405        }
1406    }
1407}
1408
1409impl fmt::Debug for InternalError {
1410    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1411        fmt_compact_diagnostic(
1412            f,
1413            self.diagnostic_code(),
1414            self.detail
1415                .as_ref()
1416                .and_then(ErrorDetail::diagnostic_detail),
1417        )
1418    }
1419}
1420
1421impl fmt::Display for InternalError {
1422    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1423        f.write_str(self.message())
1424    }
1425}
1426
1427impl std::error::Error for InternalError {}
1428
1429///
1430/// ConstraintDiagnosticKind
1431///
1432/// Accepted constraint family attached to one bounded runtime diagnostic.
1433/// Accepted schema owns the identity; this enum is its error-boundary projection.
1434///
1435
1436#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1437pub enum ConstraintDiagnosticKind {
1438    /// One accepted canonical check expression.
1439    Check,
1440
1441    /// One accepted or activating not-null field contract.
1442    NotNull,
1443
1444    /// One accepted or activating relation contract.
1445    Relation,
1446
1447    /// One accepted durable rule over a nominal value below a persisted root.
1448    TargetedRule,
1449
1450    /// One accepted or activating unique-index contract.
1451    Unique,
1452}
1453
1454impl ConstraintDiagnosticKind {
1455    /// Borrow the stable public label for this constraint family.
1456    #[must_use]
1457    pub const fn as_str(self) -> &'static str {
1458        match self {
1459            Self::Check => "check",
1460            Self::NotNull => "not_null",
1461            Self::Relation => "relation",
1462            Self::TargetedRule => "targeted_rule",
1463            Self::Unique => "unique",
1464        }
1465    }
1466}
1467
1468///
1469/// ConstraintValuePathComponent
1470///
1471/// Stable accepted identity or finite-value coordinate in one targeted-rule
1472/// violation. Display names are deliberately absent so renames cannot change
1473/// the diagnostic identity.
1474///
1475
1476#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1477pub enum ConstraintValuePathComponent {
1478    /// Persisted root field whose admitted value was traversed.
1479    RootField { field_id: u32 },
1480
1481    /// Accepted record member selected by immutable composite/member identity.
1482    RecordMember {
1483        composite_type_id: u32,
1484        member_id: u32,
1485    },
1486
1487    /// Tuple element selected by accepted composite identity and ordinal.
1488    TupleElement {
1489        composite_type_id: u32,
1490        ordinal: u32,
1491    },
1492
1493    /// Transparent accepted newtype boundary.
1494    Newtype { composite_type_id: u32 },
1495
1496    /// Selected accepted enum variant.
1497    EnumVariant { enum_type_id: u32, variant_id: u32 },
1498
1499    /// List element in admitted order.
1500    ListElement { index: u32 },
1501
1502    /// Set element in canonical admitted order.
1503    SetElement { index: u32 },
1504
1505    /// Map key in canonical entry order.
1506    MapEntryKey { index: u32 },
1507
1508    /// Map value in canonical entry order.
1509    MapEntryValue { index: u32 },
1510}
1511
1512impl fmt::Display for ConstraintValuePathComponent {
1513    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1514        match self {
1515            Self::RootField { field_id } => write!(f, "field#{field_id}"),
1516            Self::RecordMember {
1517                composite_type_id,
1518                member_id,
1519            } => write!(f, "record#{composite_type_id}.member#{member_id}"),
1520            Self::TupleElement {
1521                composite_type_id,
1522                ordinal,
1523            } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
1524            Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
1525            Self::EnumVariant {
1526                enum_type_id,
1527                variant_id,
1528            } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
1529            Self::ListElement { index } => write!(f, "list[{index}]"),
1530            Self::SetElement { index } => write!(f, "set[{index}]"),
1531            Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
1532            Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
1533        }
1534    }
1535}
1536
1537///
1538/// ConstraintValuePath
1539///
1540/// Bounded typed path to the first deterministic failing value occurrence.
1541///
1542
1543#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
1544pub struct ConstraintValuePath {
1545    components: Vec<ConstraintValuePathComponent>,
1546}
1547
1548impl ConstraintValuePath {
1549    /// Build one already-bounded accepted occurrence path.
1550    #[must_use]
1551    pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
1552        Self { components }
1553    }
1554
1555    /// Borrow the stable accepted components.
1556    #[must_use]
1557    pub const fn components(&self) -> &[ConstraintValuePathComponent] {
1558        self.components.as_slice()
1559    }
1560}
1561
1562impl fmt::Display for ConstraintValuePath {
1563    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1564        for (ordinal, component) in self.components.iter().enumerate() {
1565            if ordinal != 0 {
1566                f.write_str("/")?;
1567            }
1568            component.fmt(f)?;
1569        }
1570        Ok(())
1571    }
1572}
1573
1574///
1575/// ConstraintDiagnosticContext
1576///
1577/// Boundary at which one accepted constraint failure was observed.
1578/// This distinguishes incoming write rejection from historical validation.
1579///
1580
1581#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1582pub enum ConstraintDiagnosticContext {
1583    /// Integrity verification found invalid already-accepted state.
1584    Integrity,
1585
1586    /// Bounded activation validation found an incompatible historical row.
1587    MigrationValidation,
1588
1589    /// A new mutation after-image violated accepted admission authority.
1590    WriteAdmission,
1591}
1592
1593impl ConstraintDiagnosticContext {
1594    /// Borrow the stable public label for this diagnostic context.
1595    #[must_use]
1596    pub const fn as_str(self) -> &'static str {
1597        match self {
1598            Self::Integrity => "integrity",
1599            Self::MigrationValidation => "migration_validation",
1600            Self::WriteAdmission => "write_admission",
1601        }
1602    }
1603}
1604
1605///
1606/// ConstraintDiagnostic
1607///
1608/// One bounded accepted-constraint failure carried through runtime and SQL
1609/// boundaries. It is a projection of accepted identity, not a second schema
1610/// authority, and its compact error code remains the classification owner.
1611///
1612
1613#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
1614pub struct ConstraintDiagnostic {
1615    constraint_id: u32,
1616    constraint_name: String,
1617    constraint_kind: ConstraintDiagnosticKind,
1618    entity: String,
1619    primary_key: Option<Vec<u8>>,
1620    field_paths: Vec<String>,
1621    value_path: Option<Box<ConstraintValuePath>>,
1622    context: ConstraintDiagnosticContext,
1623    error_code: u16,
1624}
1625
1626impl ConstraintDiagnostic {
1627    /// Build one incoming-write accepted constraint violation.
1628    #[must_use]
1629    pub(crate) const fn write_violation(
1630        constraint_id: u32,
1631        constraint_name: String,
1632        constraint_kind: ConstraintDiagnosticKind,
1633        entity: String,
1634        primary_key: Option<Vec<u8>>,
1635        field_paths: Vec<String>,
1636    ) -> Self {
1637        Self {
1638            constraint_id,
1639            constraint_name,
1640            constraint_kind,
1641            entity,
1642            primary_key,
1643            field_paths,
1644            value_path: None,
1645            context: ConstraintDiagnosticContext::WriteAdmission,
1646            error_code: diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_VIOLATION.raw(),
1647        }
1648    }
1649
1650    /// Build one incoming-write targeted-rule violation.
1651    #[must_use]
1652    pub(crate) fn write_targeted_rule_violation(
1653        constraint_id: u32,
1654        constraint_name: String,
1655        entity: String,
1656        primary_key: Option<Vec<u8>>,
1657        field_paths: Vec<String>,
1658        value_path: ConstraintValuePath,
1659    ) -> Self {
1660        Self {
1661            constraint_id,
1662            constraint_name,
1663            constraint_kind: ConstraintDiagnosticKind::TargetedRule,
1664            entity,
1665            primary_key,
1666            field_paths,
1667            value_path: Some(Box::new(value_path)),
1668            context: ConstraintDiagnosticContext::WriteAdmission,
1669            error_code: diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_VIOLATION.raw(),
1670        }
1671    }
1672
1673    /// Build one incoming-write activation barrier rejection.
1674    #[must_use]
1675    pub(crate) const fn write_activation_blocked(
1676        constraint_id: u32,
1677        constraint_name: String,
1678        constraint_kind: ConstraintDiagnosticKind,
1679        entity: String,
1680        primary_key: Option<Vec<u8>>,
1681        field_paths: Vec<String>,
1682    ) -> Self {
1683        Self {
1684            constraint_id,
1685            constraint_name,
1686            constraint_kind,
1687            entity,
1688            primary_key,
1689            field_paths,
1690            value_path: None,
1691            context: ConstraintDiagnosticContext::WriteAdmission,
1692            error_code:
1693                diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_ACTIVATION_WRITE_BLOCKED
1694                    .raw(),
1695        }
1696    }
1697
1698    /// Build one historical activation finding from its durable compact code.
1699    #[must_use]
1700    pub(crate) const fn migration_validation(
1701        constraint_id: u32,
1702        constraint_name: String,
1703        constraint_kind: ConstraintDiagnosticKind,
1704        entity: String,
1705        primary_key: Vec<u8>,
1706        field_paths: Vec<String>,
1707        error_code: u16,
1708    ) -> Self {
1709        Self {
1710            constraint_id,
1711            constraint_name,
1712            constraint_kind,
1713            entity,
1714            primary_key: Some(primary_key),
1715            field_paths,
1716            value_path: None,
1717            context: ConstraintDiagnosticContext::MigrationValidation,
1718            error_code,
1719        }
1720    }
1721
1722    /// Build one historical targeted-rule finding with durable path evidence.
1723    #[must_use]
1724    pub(crate) fn migration_targeted_rule_validation(
1725        constraint_id: u32,
1726        constraint_name: String,
1727        entity: String,
1728        primary_key: Vec<u8>,
1729        field_paths: Vec<String>,
1730        value_path: ConstraintValuePath,
1731        error_code: u16,
1732    ) -> Self {
1733        Self {
1734            constraint_id,
1735            constraint_name,
1736            constraint_kind: ConstraintDiagnosticKind::TargetedRule,
1737            entity,
1738            primary_key: Some(primary_key),
1739            field_paths,
1740            value_path: Some(Box::new(value_path)),
1741            context: ConstraintDiagnosticContext::MigrationValidation,
1742            error_code,
1743        }
1744    }
1745
1746    /// Return the stable accepted constraint identity.
1747    #[must_use]
1748    pub const fn constraint_id(&self) -> u32 {
1749        self.constraint_id
1750    }
1751
1752    /// Borrow the stable accepted constraint name.
1753    #[must_use]
1754    pub const fn constraint_name(&self) -> &str {
1755        self.constraint_name.as_str()
1756    }
1757
1758    /// Return the accepted constraint family.
1759    #[must_use]
1760    pub const fn constraint_kind(&self) -> ConstraintDiagnosticKind {
1761        self.constraint_kind
1762    }
1763
1764    /// Borrow the accepted entity identity.
1765    #[must_use]
1766    pub const fn entity(&self) -> &str {
1767        self.entity.as_str()
1768    }
1769
1770    /// Borrow the canonical persisted primary-key bytes when available.
1771    #[must_use]
1772    pub fn primary_key(&self) -> Option<&[u8]> {
1773        self.primary_key.as_deref()
1774    }
1775
1776    /// Borrow bounded accepted field paths implicated by the failure.
1777    #[must_use]
1778    pub const fn field_paths(&self) -> &[String] {
1779        self.field_paths.as_slice()
1780    }
1781
1782    /// Borrow the typed concrete value path for a targeted-rule violation.
1783    #[must_use]
1784    pub fn value_path(&self) -> Option<&ConstraintValuePath> {
1785        self.value_path.as_deref()
1786    }
1787
1788    /// Return the boundary that observed the failure.
1789    #[must_use]
1790    pub const fn context(&self) -> ConstraintDiagnosticContext {
1791        self.context
1792    }
1793
1794    /// Return the compact stable error code for this exact failure.
1795    #[must_use]
1796    pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
1797        diagnostic_code::ErrorCode::from_raw(self.error_code)
1798    }
1799
1800    /// Return the broad public error class derived from the compact code.
1801    #[must_use]
1802    pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
1803        self.error_code().class()
1804    }
1805}
1806
1807///
1808/// ErrorDetail
1809///
1810/// Structured, origin-specific error detail carried by [`InternalError`].
1811/// This enum is intentionally extensible.
1812///
1813
1814pub enum ErrorDetail {
1815    /// Executor-owned mutation and query execution details.
1816    Executor(ExecutorErrorDetail),
1817    Store(StoreError),
1818    Query(QueryErrorDetail),
1819    Recovery(RecoveryErrorDetail),
1820    /// Persisted-row serialization and decoding details.
1821    Serialize(SerializeErrorDetail),
1822    // Future-proofing:
1823    // Index(IndexError),
1824}
1825
1826/// Executor-specific structured error detail.
1827pub enum ExecutorErrorDetail {
1828    /// A complete insert or replacement omitted one or more required fields.
1829    MutationRequiredFieldMissing,
1830    /// A logical mutation would move accepted managed time backward.
1831    MutationManagedTimestampRegression,
1832    /// A caller explicitly authored a field owned by accepted database policy.
1833    MutationDatabaseOwnedFieldExplicit,
1834    /// A mixed structural mutation batch contained no operations.
1835    MutationBatchEmpty,
1836    /// A mixed structural mutation batch exceeded its operation-count bound.
1837    MutationBatchTooManyItems,
1838    /// A mixed structural mutation batch exceeded its staged-byte bound.
1839    MutationBatchStagedBytesExceeded,
1840    /// A mixed structural mutation result exceeded its encoded response bound.
1841    MutationBatchResultBytesExceeded,
1842    /// A mixed structural mutation batch resolved to more than one accepted entity.
1843    MutationBatchEntityMismatch,
1844    /// More than one mixed structural operation targeted the same accepted key.
1845    MutationBatchDuplicateKey,
1846    /// A final canonical after-image violated one accepted constraint or activation gate.
1847    ConstraintViolation {
1848        diagnostic: Box<ConstraintDiagnostic>,
1849    },
1850    /// Accepted row-constraint metadata or compiled state was inconsistent.
1851    AcceptedRowConstraintProgramCorrupt,
1852    /// A write would rely on one incomplete activation-owned physical proof.
1853    ConstraintActivationWriteBlocked {
1854        diagnostic: Box<ConstraintDiagnostic>,
1855    },
1856}
1857
1858impl ExecutorErrorDetail {
1859    /// Borrow the accepted constraint diagnostic carried by this failure.
1860    #[must_use]
1861    pub fn constraint_diagnostic(&self) -> Option<&ConstraintDiagnostic> {
1862        match self {
1863            Self::ConstraintActivationWriteBlocked { diagnostic }
1864            | Self::ConstraintViolation { diagnostic } => Some(diagnostic.as_ref()),
1865            Self::MutationRequiredFieldMissing
1866            | Self::MutationManagedTimestampRegression
1867            | Self::MutationDatabaseOwnedFieldExplicit
1868            | Self::MutationBatchEmpty
1869            | Self::MutationBatchTooManyItems
1870            | Self::MutationBatchStagedBytesExceeded
1871            | Self::MutationBatchResultBytesExceeded
1872            | Self::MutationBatchEntityMismatch
1873            | Self::MutationBatchDuplicateKey
1874            | Self::AcceptedRowConstraintProgramCorrupt => None,
1875        }
1876    }
1877}
1878
1879/// Persisted-row serialization and decoding error detail.
1880pub enum SerializeErrorDetail {
1881    /// The row stamp is older or newer than the accepted layout window.
1882    PersistedRowLayoutOutsideAcceptedWindow,
1883
1884    /// The physical slot count does not match the row's stamped layout.
1885    PersistedRowSlotCountMismatch,
1886}
1887
1888///
1889/// RecoveryErrorDetail
1890///
1891/// Recovery-origin structured error detail payload.
1892///
1893
1894pub enum RecoveryErrorDetail {
1895    UnsupportedFormatVersion { found: Option<u16>, required: u16 },
1896
1897    MalformedFormatMarker { reason: RecoveryFormatMarkerError },
1898}
1899
1900/// Store boot-marker corruption classification.
1901#[derive(Clone, Copy, Eq, PartialEq)]
1902pub enum RecoveryFormatMarkerError {
1903    Magic,
1904    Checksum,
1905    State,
1906}
1907
1908///
1909/// StoreError
1910///
1911/// Store-specific structured error detail.
1912/// Never returned directly; always wrapped in [`ErrorDetail::Store`].
1913///
1914
1915pub enum StoreError {
1916    NotFound,
1917
1918    Corrupt,
1919
1920    InvariantViolation,
1921
1922    SchemaDdlPublicationRaceLost,
1923
1924    SchemaDdlRewriteRequiresMigration,
1925
1926    SchemaRowLayoutVersionExhausted,
1927
1928    JournalMutationRevisionExhausted,
1929
1930    SchemaTransitionBudgetExceeded {
1931        resource: SchemaTransitionBudgetResource,
1932    },
1933
1934    /// A generated field would collide with an accepted DDL-owned slot.
1935    SchemaGeneratedFieldAfterDdlField,
1936
1937    /// A live generated constraint activation no longer matches its proposal.
1938    SchemaGeneratedConstraintActivationStale,
1939}
1940
1941///
1942/// QueryErrorDetail
1943///
1944/// Query-origin structured error detail payload.
1945///
1946
1947pub enum QueryErrorDetail {
1948    NumericOverflow,
1949
1950    NumericNotRepresentable,
1951
1952    UnsupportedSqlFeature {
1953        feature: diagnostic_code::SqlFeatureCode,
1954    },
1955
1956    SqlLowering {
1957        reason: diagnostic_code::SqlLoweringCode,
1958    },
1959
1960    UnsupportedProjection {
1961        reason: diagnostic_code::QueryProjectionCode,
1962    },
1963
1964    UnknownAggregateTargetField,
1965
1966    ResultShapeMismatch {
1967        reason: diagnostic_code::QueryResultShapeCode,
1968    },
1969
1970    QueryReadAdmission {
1971        reason: diagnostic_code::QueryReadAdmissionCode,
1972    },
1973
1974    SqlSurfaceMismatch {
1975        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1976    },
1977
1978    SqlWriteBoundary {
1979        boundary: diagnostic_code::SqlWriteBoundaryCode,
1980    },
1981
1982    SchemaDdlAdmission {
1983        error: SchemaDdlAdmissionError,
1984    },
1985
1986    StaleSchemaRevision,
1987}
1988
1989impl fmt::Display for QueryErrorDetail {
1990    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1991        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
1992    }
1993}
1994
1995impl std::error::Error for QueryErrorDetail {}
1996
1997///
1998/// SchemaTransitionBudgetResource
1999///
2000/// Query-visible identity of the exact schema-transition resource cap that
2001/// rejected a complete validation or derived-state stage.
2002///
2003
2004#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2005pub enum SchemaTransitionBudgetResource {
2006    /// Number of physical deletion keys retained for replacement.
2007    DeletionKeys,
2008    /// Number of row-derived projection entries retained for validation.
2009    ProjectionEntries,
2010    /// Deterministic projection and physical-classification work units.
2011    ProjectionWorkUnits,
2012    /// Number of authoritative source rows.
2013    SourceRows,
2014    /// Cumulative bytes of authoritative source rows.
2015    SourceRowBytes,
2016    /// Retained raw payloads plus deterministic-sort workspace bytes.
2017    StagedRawBytes,
2018}
2019
2020///
2021/// SchemaDdlAdmissionError
2022///
2023/// Stable query-visible SQL DDL admission reason. Human diagnostics may carry
2024/// extra version, fingerprint, and target facts beside this machine-readable
2025/// variant.
2026///
2027
2028#[derive(Clone, Copy, Eq, PartialEq)]
2029pub enum SchemaDdlAdmissionError {
2030    MissingExpectedSchemaVersion,
2031
2032    MissingNextSchemaVersion,
2033
2034    StaleExpectedSchemaVersion,
2035
2036    InvalidExpectedSchemaVersion,
2037
2038    InvalidNextSchemaVersion,
2039
2040    AcceptedSchemaChangeWithoutVersionBump,
2041
2042    EmptyVersionBump,
2043
2044    VersionGap,
2045
2046    VersionRollback,
2047
2048    FingerprintMethodMismatch,
2049
2050    UnsupportedTransitionClass,
2051
2052    PhysicalRunnerMissing,
2053
2054    ValidationFailed,
2055
2056    PublicationRaceLost,
2057
2058    InvalidAddColumnDefault,
2059
2060    InvalidAlterColumnDefault,
2061
2062    RowLayoutVersionExhausted,
2063
2064    GeneratedIndexDropRejected,
2065
2066    SchemaRewriteRequiresMigration,
2067
2068    SchemaTransitionBudgetExceeded {
2069        resource: SchemaTransitionBudgetResource,
2070    },
2071
2072    GeneratedFieldDefaultChangeRejected,
2073
2074    GeneratedFieldNullabilityChangeRejected,
2075}
2076
2077impl fmt::Display for SchemaDdlAdmissionError {
2078    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2079        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2080    }
2081}
2082
2083impl std::error::Error for SchemaDdlAdmissionError {}
2084
2085impl fmt::Debug for ErrorDetail {
2086    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2087        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2088    }
2089}
2090
2091impl fmt::Debug for ExecutorErrorDetail {
2092    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2093        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2094    }
2095}
2096
2097impl fmt::Debug for StoreError {
2098    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2099        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2100    }
2101}
2102
2103impl fmt::Debug for QueryErrorDetail {
2104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2105        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2106    }
2107}
2108
2109impl fmt::Debug for RecoveryErrorDetail {
2110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2111        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2112    }
2113}
2114
2115impl fmt::Debug for SerializeErrorDetail {
2116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2117        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2118    }
2119}
2120
2121impl fmt::Debug for RecoveryFormatMarkerError {
2122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2123        fmt_compact_diagnostic(
2124            f,
2125            diagnostic_code::DiagnosticCode::RuntimeCorruption,
2126            Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2127                kind: diagnostic_code::RuntimeErrorKind::Corruption,
2128            }),
2129        )
2130    }
2131}
2132
2133impl fmt::Debug for SchemaDdlAdmissionError {
2134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2135        fmt_compact_diagnostic(
2136            f,
2137            diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2138            Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2139                reason: self.diagnostic_code(),
2140            }),
2141        )
2142    }
2143}
2144
2145fn fmt_compact_diagnostic(
2146    f: &mut fmt::Formatter<'_>,
2147    code: diagnostic_code::DiagnosticCode,
2148    detail: Option<diagnostic_code::DiagnosticDetail>,
2149) -> fmt::Result {
2150    write!(
2151        f,
2152        "{}",
2153        diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2154    )
2155}
2156
2157impl ErrorDetail {
2158    /// Return the compact diagnostic code for this structured detail.
2159    #[must_use]
2160    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2161        match self {
2162            Self::Executor(error) => error.diagnostic_code(),
2163            Self::Store(error) => error.diagnostic_code(),
2164            Self::Query(error) => error.diagnostic_code(),
2165            Self::Recovery(error) => error.diagnostic_code(),
2166            Self::Serialize(error) => error.diagnostic_code(),
2167        }
2168    }
2169
2170    /// Return compact structured diagnostic detail when the payload carries one.
2171    #[must_use]
2172    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2173        match self {
2174            Self::Executor(error) => error.diagnostic_detail(),
2175            Self::Store(error) => error.diagnostic_detail(),
2176            Self::Query(error) => error.diagnostic_detail(),
2177            Self::Recovery(error) => error.diagnostic_detail(),
2178            Self::Serialize(error) => error.diagnostic_detail(),
2179        }
2180    }
2181}
2182
2183impl ExecutorErrorDetail {
2184    /// Return the compact diagnostic code for this executor detail.
2185    #[must_use]
2186    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2187        match self {
2188            Self::MutationRequiredFieldMissing
2189            | Self::MutationDatabaseOwnedFieldExplicit
2190            | Self::MutationBatchEmpty
2191            | Self::MutationBatchTooManyItems
2192            | Self::MutationBatchStagedBytesExceeded
2193            | Self::MutationBatchResultBytesExceeded => {
2194                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2195            }
2196            Self::MutationBatchEntityMismatch | Self::MutationBatchDuplicateKey => {
2197                diagnostic_code::DiagnosticCode::RuntimeConflict
2198            }
2199            Self::MutationManagedTimestampRegression => {
2200                diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2201            }
2202            Self::ConstraintViolation { diagnostic }
2203            | Self::ConstraintActivationWriteBlocked { diagnostic } => {
2204                diagnostic.error_code().diagnostic_code()
2205            }
2206            Self::AcceptedRowConstraintProgramCorrupt => {
2207                diagnostic_code::DiagnosticCode::RuntimeCorruption
2208            }
2209        }
2210    }
2211
2212    /// Return compact structured diagnostic detail for this executor detail.
2213    #[must_use]
2214    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2215        match self {
2216            Self::MutationRequiredFieldMissing => {
2217                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2218                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2219                })
2220            }
2221            Self::MutationDatabaseOwnedFieldExplicit => {
2222                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2223                    boundary:
2224                        diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2225                })
2226            }
2227            Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2228                boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2229            }),
2230            Self::MutationBatchTooManyItems => {
2231                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2232                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2233                })
2234            }
2235            Self::MutationBatchStagedBytesExceeded => {
2236                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2237                    boundary:
2238                        diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2239                })
2240            }
2241            Self::MutationBatchResultBytesExceeded => {
2242                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2243                    boundary:
2244                        diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2245                })
2246            }
2247            Self::MutationBatchEntityMismatch => {
2248                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2249                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
2250                })
2251            }
2252            Self::MutationBatchDuplicateKey => {
2253                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2254                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2255                })
2256            }
2257            Self::MutationManagedTimestampRegression => {
2258                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2259                    boundary:
2260                        diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2261                })
2262            }
2263            Self::ConstraintViolation { diagnostic }
2264            | Self::ConstraintActivationWriteBlocked { diagnostic } => {
2265                diagnostic.error_code().diagnostic_detail()
2266            }
2267            Self::AcceptedRowConstraintProgramCorrupt => {
2268                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2269                    boundary:
2270                        diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2271                })
2272            }
2273        }
2274    }
2275}
2276
2277impl RecoveryErrorDetail {
2278    /// Return the compact diagnostic code for this recovery detail.
2279    #[must_use]
2280    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2281        match self {
2282            Self::UnsupportedFormatVersion { .. } => {
2283                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2284            }
2285            Self::MalformedFormatMarker { .. } => {
2286                diagnostic_code::DiagnosticCode::RuntimeCorruption
2287            }
2288        }
2289    }
2290
2291    /// Return compact structured diagnostic detail for this recovery detail.
2292    #[must_use]
2293    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2294        let kind = match self {
2295            Self::UnsupportedFormatVersion { .. } => {
2296                diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2297            }
2298            Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2299        };
2300
2301        Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2302    }
2303}
2304
2305impl SerializeErrorDetail {
2306    /// Return the compact diagnostic code for this serialization detail.
2307    #[must_use]
2308    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2309        match self {
2310            Self::PersistedRowLayoutOutsideAcceptedWindow | Self::PersistedRowSlotCountMismatch => {
2311                diagnostic_code::DiagnosticCode::RuntimeCorruption
2312            }
2313        }
2314    }
2315
2316    /// Return compact structured diagnostic detail for this serialization detail.
2317    #[must_use]
2318    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2319        let boundary = match self {
2320            Self::PersistedRowLayoutOutsideAcceptedWindow => {
2321                diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow
2322            }
2323            Self::PersistedRowSlotCountMismatch => {
2324                diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch
2325            }
2326        };
2327
2328        Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary })
2329    }
2330}
2331
2332impl StoreError {
2333    /// Return the compact diagnostic code for this store detail.
2334    #[must_use]
2335    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2336        match self {
2337            Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2338            Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2339            Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2340            Self::SchemaDdlPublicationRaceLost
2341            | Self::SchemaDdlRewriteRequiresMigration
2342            | Self::SchemaRowLayoutVersionExhausted
2343            | Self::SchemaTransitionBudgetExceeded { .. } => {
2344                diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2345            }
2346            Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2347                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2348            }
2349            Self::SchemaGeneratedConstraintActivationStale => {
2350                diagnostic_code::DiagnosticCode::RuntimeConflict
2351            }
2352        }
2353    }
2354
2355    /// Return compact structured diagnostic detail when the store error has one.
2356    #[must_use]
2357    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2358        match self {
2359            Self::SchemaDdlPublicationRaceLost => {
2360                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2361                    reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2362                })
2363            }
2364            Self::SchemaDdlRewriteRequiresMigration => {
2365                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2366                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2367                })
2368            }
2369            Self::SchemaRowLayoutVersionExhausted => {
2370                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2371                    reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2372                })
2373            }
2374            Self::JournalMutationRevisionExhausted => {
2375                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2376                    boundary:
2377                        diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2378                })
2379            }
2380            Self::SchemaTransitionBudgetExceeded { .. } => {
2381                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2382                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2383                })
2384            }
2385            Self::SchemaGeneratedFieldAfterDdlField => {
2386                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2387                    boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2388                })
2389            }
2390            Self::SchemaGeneratedConstraintActivationStale => {
2391                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2392                    boundary:
2393                        diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2394                })
2395            }
2396            Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2397        }
2398    }
2399}
2400
2401impl QueryErrorDetail {
2402    /// Return the compact diagnostic code for this query detail.
2403    #[must_use]
2404    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2405        match self {
2406            Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2407            Self::NumericNotRepresentable => {
2408                diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2409            }
2410            Self::UnsupportedSqlFeature { .. } => {
2411                diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2412            }
2413            Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2414            Self::UnsupportedProjection { .. } => {
2415                diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2416            }
2417            Self::UnknownAggregateTargetField => {
2418                diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2419            }
2420            Self::ResultShapeMismatch { .. } => {
2421                diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
2422            }
2423            Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2424            Self::SqlSurfaceMismatch { .. } => {
2425                diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2426            }
2427            Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2428            Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2429            Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2430        }
2431    }
2432
2433    /// Return compact structured diagnostic detail when the query detail has one.
2434    #[must_use]
2435    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2436        match self {
2437            Self::UnsupportedSqlFeature { feature } => {
2438                Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2439            }
2440            Self::SqlLowering { reason } => {
2441                Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2442            }
2443            Self::UnsupportedProjection { reason } => {
2444                Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2445            }
2446            Self::ResultShapeMismatch { reason } => {
2447                Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
2448            }
2449            Self::QueryReadAdmission { reason } => {
2450                Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2451            }
2452            Self::SqlSurfaceMismatch { mismatch } => {
2453                Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2454                    mismatch: *mismatch,
2455                })
2456            }
2457            Self::SqlWriteBoundary { boundary } => {
2458                Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2459                    boundary: *boundary,
2460                })
2461            }
2462            Self::SchemaDdlAdmission { error } => {
2463                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2464                    reason: error.diagnostic_code(),
2465                })
2466            }
2467            Self::NumericOverflow
2468            | Self::NumericNotRepresentable
2469            | Self::UnknownAggregateTargetField
2470            | Self::StaleSchemaRevision => None,
2471        }
2472    }
2473}
2474
2475impl SchemaDdlAdmissionError {
2476    /// Return the compact diagnostic code for this SQL DDL admission reason.
2477    #[must_use]
2478    pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
2479        match self {
2480            Self::MissingExpectedSchemaVersion => {
2481                diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
2482            }
2483            Self::MissingNextSchemaVersion => {
2484                diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
2485            }
2486            Self::StaleExpectedSchemaVersion => {
2487                diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
2488            }
2489            Self::InvalidExpectedSchemaVersion => {
2490                diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
2491            }
2492            Self::InvalidNextSchemaVersion => {
2493                diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
2494            }
2495            Self::AcceptedSchemaChangeWithoutVersionBump => {
2496                diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
2497            }
2498            Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
2499            Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
2500            Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
2501            Self::FingerprintMethodMismatch => {
2502                diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
2503            }
2504            Self::UnsupportedTransitionClass => {
2505                diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
2506            }
2507            Self::PhysicalRunnerMissing => {
2508                diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
2509            }
2510            Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
2511            Self::PublicationRaceLost => {
2512                diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
2513            }
2514            Self::InvalidAddColumnDefault => {
2515                diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
2516            }
2517            Self::InvalidAlterColumnDefault => {
2518                diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
2519            }
2520            Self::GeneratedIndexDropRejected => {
2521                diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
2522            }
2523            Self::SchemaRewriteRequiresMigration => {
2524                diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
2525            }
2526            Self::SchemaTransitionBudgetExceeded { .. } => {
2527                diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
2528            }
2529            Self::GeneratedFieldDefaultChangeRejected => {
2530                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
2531            }
2532            Self::GeneratedFieldNullabilityChangeRejected => {
2533                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
2534            }
2535            Self::RowLayoutVersionExhausted => {
2536                diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
2537            }
2538        }
2539    }
2540}
2541
2542///
2543/// ErrorClass
2544/// Internal error taxonomy for runtime classification.
2545/// Not a stable API; may change without notice.
2546///
2547
2548#[repr(u8)]
2549#[derive(Clone, Copy, Eq, PartialEq)]
2550pub enum ErrorClass {
2551    Corruption,
2552    IncompatiblePersistedFormat,
2553    NotFound,
2554    Internal,
2555    Conflict,
2556    Unsupported,
2557    InvariantViolation,
2558}
2559
2560impl ErrorClass {
2561    /// Return a compact diagnostic code for this broad class and origin pair.
2562    #[must_use]
2563    pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
2564        match self {
2565            Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
2566                diagnostic_code::DiagnosticCode::StoreCorruption
2567            }
2568            Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
2569            Self::IncompatiblePersistedFormat => {
2570                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2571            }
2572            Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
2573                diagnostic_code::DiagnosticCode::StoreNotFound
2574            }
2575            Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
2576            Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
2577            Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
2578            Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
2579                diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
2580            }
2581            Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
2582            Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
2583                diagnostic_code::DiagnosticCode::StoreInvariantViolation
2584            }
2585            Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
2586        }
2587    }
2588}
2589
2590impl fmt::Debug for ErrorClass {
2591    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2592        write!(f, "{}", *self as u8)
2593    }
2594}
2595
2596///
2597/// ErrorOrigin
2598/// Internal origin taxonomy for runtime classification.
2599/// Not a stable API; may change without notice.
2600///
2601
2602#[repr(u8)]
2603#[derive(Clone, Copy, Eq, PartialEq)]
2604pub enum ErrorOrigin {
2605    Serialize,
2606    Store,
2607    Index,
2608    Identity,
2609    Query,
2610    Planner,
2611    Cursor,
2612    Recovery,
2613    Response,
2614    Executor,
2615    Interface,
2616}
2617
2618impl ErrorOrigin {
2619    /// Return the compact diagnostic origin for this internal origin.
2620    #[must_use]
2621    pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
2622        match self {
2623            Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
2624            Self::Store => diagnostic_code::ErrorOrigin::Store,
2625            Self::Index => diagnostic_code::ErrorOrigin::Index,
2626            Self::Identity => diagnostic_code::ErrorOrigin::Identity,
2627            Self::Query => diagnostic_code::ErrorOrigin::Query,
2628            Self::Planner => diagnostic_code::ErrorOrigin::Planner,
2629            Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
2630            Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
2631            Self::Response => diagnostic_code::ErrorOrigin::Response,
2632            Self::Executor => diagnostic_code::ErrorOrigin::Executor,
2633            Self::Interface => diagnostic_code::ErrorOrigin::Interface,
2634        }
2635    }
2636}
2637
2638impl fmt::Debug for ErrorOrigin {
2639    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2640        write!(f, "{}", *self as u8)
2641    }
2642}