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