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/// Fixed-size accepted mutation identity carried through admission and staging.
133/// Numeric fact vectors are allocated only when constructing a failure.
134#[derive(Clone, Copy, Debug)]
135pub(crate) struct MutationDiagnosticContext {
136    fingerprint_method: u8,
137    accepted_schema_fingerprint: [u8; 16],
138    entity_tag: u64,
139    operation: diagnostic_code::DiagnosticMutationOperation,
140    batch_position: Option<u32>,
141}
142
143impl MutationDiagnosticContext {
144    /// Bind a mutation to its accepted schema, entity, operation, and input.
145    #[must_use]
146    pub(crate) const fn new(
147        fingerprint_method: u8,
148        accepted_schema_fingerprint: [u8; 16],
149        entity_tag: u64,
150        operation: diagnostic_code::DiagnosticMutationOperation,
151        batch_position: u32,
152    ) -> Self {
153        Self {
154            fingerprint_method,
155            accepted_schema_fingerprint,
156            entity_tag,
157            operation,
158            batch_position: Some(batch_position),
159        }
160    }
161
162    /// Bind a failure to an operation before any concrete input row is selected.
163    #[must_use]
164    pub(crate) const fn operation_only(
165        fingerprint_method: u8,
166        accepted_schema_fingerprint: [u8; 16],
167        entity_tag: u64,
168        operation: diagnostic_code::DiagnosticMutationOperation,
169    ) -> Self {
170        Self {
171            fingerprint_method,
172            accepted_schema_fingerprint,
173            entity_tag,
174            operation,
175            batch_position: None,
176        }
177    }
178
179    fn facts(self, field_id: Option<u32>) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
180        let mut facts = Vec::with_capacity(
181            5 + usize::from(field_id.is_some()) + usize::from(self.batch_position.is_some()),
182        );
183        append_accepted_schema_facts(
184            &mut facts,
185            self.fingerprint_method,
186            self.accepted_schema_fingerprint,
187        );
188        facts.push((
189            diagnostic_code::DiagnosticFactTag::EntityTag,
190            self.entity_tag,
191        ));
192        if let Some(field_id) = field_id {
193            facts.push((
194                diagnostic_code::DiagnosticFactTag::FieldId,
195                u64::from(field_id),
196            ));
197        }
198        self.append_operation_facts(&mut facts);
199        facts
200    }
201
202    #[must_use]
203    pub(crate) const fn entity_tag(self) -> u64 {
204        self.entity_tag
205    }
206
207    fn append_operation_facts(self, facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>) {
208        facts.push((
209            diagnostic_code::DiagnosticFactTag::MutationOperation,
210            self.operation.raw(),
211        ));
212        if let Some(batch_position) = self.batch_position {
213            facts.push((
214                diagnostic_code::DiagnosticFactTag::BatchPosition,
215                u64::from(batch_position),
216            ));
217        }
218    }
219}
220
221/// Numeric context retained behind one thin error-only allocation.
222pub struct DiagnosticFactDetail {
223    diagnostic: diagnostic_code::Diagnostic,
224    facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
225}
226
227///
228/// InternalError
229///
230/// Structured runtime error with a stable internal classification.
231/// Not a stable API; intended for internal use and may change without notice.
232///
233
234pub struct InternalError {
235    pub(crate) class: ErrorClass,
236    pub(crate) origin: ErrorOrigin,
237
238    /// Optional structured error detail.
239    /// The variant (if present) must correspond to `origin`.
240    pub(crate) detail: Option<ErrorDetail>,
241}
242
243#[expect(
244    clippy::missing_const_for_fn,
245    reason = "internal error constructors stay non-const so compact diagnostic construction does not force const churn across subsystem helper seams"
246)]
247impl InternalError {
248    /// Construct an InternalError with optional origin-specific detail.
249    /// This constructor provides default StoreError details for certain
250    /// (class, origin) combinations but does not guarantee a detail payload.
251    #[must_use]
252    #[cold]
253    #[inline(never)]
254    pub fn new(class: ErrorClass, origin: ErrorOrigin) -> Self {
255        let detail = match (class, origin) {
256            (ErrorClass::Corruption, ErrorOrigin::Store) => {
257                Some(ErrorDetail::Store(StoreError::Corrupt))
258            }
259            (ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
260                Some(ErrorDetail::Store(StoreError::InvariantViolation))
261            }
262            _ => None,
263        };
264
265        Self {
266            class,
267            origin,
268            detail,
269        }
270    }
271
272    /// Return the internal error class taxonomy.
273    #[must_use]
274    pub const fn class(&self) -> ErrorClass {
275        self.class
276    }
277
278    /// Return the internal error origin taxonomy.
279    #[must_use]
280    pub const fn origin(&self) -> ErrorOrigin {
281        self.origin
282    }
283
284    /// Return the rendered internal error message.
285    #[must_use]
286    pub const fn message(&self) -> &'static str {
287        compact_message_for(self.class, self.origin)
288    }
289
290    /// Return the optional structured detail payload.
291    #[must_use]
292    pub const fn detail(&self) -> Option<&ErrorDetail> {
293        self.detail.as_ref()
294    }
295
296    /// Return compact diagnostic identity for this internal error.
297    #[must_use]
298    pub fn diagnostic(&self) -> diagnostic_code::Diagnostic {
299        diagnostic_code::Diagnostic::new(
300            self.diagnostic_code(),
301            self.origin.diagnostic_origin(),
302            self.detail
303                .as_ref()
304                .and_then(ErrorDetail::diagnostic_detail),
305        )
306    }
307
308    /// Project typed internal context into canonical public numeric facts.
309    #[must_use]
310    #[cold]
311    #[inline(never)]
312    pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
313        self.detail
314            .as_ref()
315            .map_or_else(Vec::new, ErrorDetail::diagnostic_facts)
316    }
317
318    /// Return the compact diagnostic code for this internal error.
319    #[must_use]
320    pub fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
321        self.detail.as_ref().map_or_else(
322            || self.class.diagnostic_code(self.origin),
323            ErrorDetail::diagnostic_code,
324        )
325    }
326
327    /// Consume and return the rendered internal error message.
328    #[must_use]
329    pub fn into_message(self) -> String {
330        self.message().to_string()
331    }
332
333    /// Construct an error while preserving an explicit class/origin taxonomy pair.
334    #[cold]
335    #[inline(never)]
336    pub(crate) fn classified(class: ErrorClass, origin: ErrorOrigin) -> Self {
337        Self::new(class, origin)
338    }
339
340    #[cold]
341    #[inline(never)]
342    fn with_diagnostic_facts(
343        class: ErrorClass,
344        origin: ErrorOrigin,
345        detail: Option<diagnostic_code::DiagnosticDetail>,
346        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
347    ) -> Self {
348        let code = match detail {
349            Some(detail) => detail.diagnostic_code(),
350            None => class.diagnostic_code(origin),
351        };
352        let diagnostic = diagnostic_code::Diagnostic::new(code, origin.diagnostic_origin(), detail);
353        if diagnostic_code::validate_known_diagnostic_fact_schema(
354            diagnostic.error_code(),
355            facts.as_slice(),
356        )
357        .is_err()
358        {
359            return Self::new(ErrorClass::InvariantViolation, origin);
360        }
361        Self {
362            class,
363            origin,
364            detail: Some(ErrorDetail::DiagnosticFacts(Box::new(
365                DiagnosticFactDetail { diagnostic, facts },
366            ))),
367        }
368    }
369
370    #[cold]
371    #[inline(never)]
372    fn mutation_boundary_with_facts(
373        class: ErrorClass,
374        boundary: diagnostic_code::RuntimeBoundaryCode,
375        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
376    ) -> Self {
377        Self::with_diagnostic_facts(
378            class,
379            ErrorOrigin::Executor,
380            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
381            facts,
382        )
383    }
384
385    #[cold]
386    #[inline(never)]
387    fn exact_key_batch_boundary_with_facts(
388        boundary: diagnostic_code::RuntimeBoundaryCode,
389        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
390    ) -> Self {
391        Self::with_diagnostic_facts(
392            ErrorClass::Unsupported,
393            ErrorOrigin::Query,
394            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
395            facts,
396        )
397    }
398
399    /// Construct a query-boundary error for a named entity absent from accepted schema authority.
400    pub(crate) fn sql_query_entity_not_found() -> Self {
401        Self::with_diagnostic_facts(
402            ErrorClass::NotFound,
403            ErrorOrigin::Interface,
404            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
405                boundary: diagnostic_code::RuntimeBoundaryCode::SqlQueryEntityNotFound,
406            }),
407            Vec::new(),
408        )
409    }
410
411    /// Construct an executor-origin hard execution-budget rejection.
412    #[cold]
413    #[inline(never)]
414    pub(crate) fn execution_budget_exceeded(
415        resource: diagnostic_code::DiagnosticExecutionBudgetResource,
416        limit: u64,
417        observed: u64,
418        scope: diagnostic_code::DiagnosticExecutionBudgetScope,
419        lane: diagnostic_code::DiagnosticExecutionLane,
420        normalized_shape_fingerprint_prefix: u64,
421    ) -> Self {
422        Self::with_diagnostic_facts(
423            ErrorClass::Unsupported,
424            ErrorOrigin::Executor,
425            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
426                boundary: diagnostic_code::RuntimeBoundaryCode::ExecutionBudgetExceeded,
427            }),
428            vec![
429                (
430                    diagnostic_code::DiagnosticFactTag::BudgetResource,
431                    resource.raw(),
432                ),
433                (diagnostic_code::DiagnosticFactTag::Limit, limit),
434                (diagnostic_code::DiagnosticFactTag::Actual, observed),
435                (
436                    diagnostic_code::DiagnosticFactTag::ExecutionBudgetScope,
437                    scope.raw(),
438                ),
439                (
440                    diagnostic_code::DiagnosticFactTag::ExecutionLane,
441                    lane.raw(),
442                ),
443                (
444                    diagnostic_code::DiagnosticFactTag::QueryShapeFingerprintPrefix,
445                    normalized_shape_fingerprint_prefix,
446                ),
447            ],
448        )
449    }
450
451    /// Construct a deterministic mutation relation-budget rejection.
452    #[cold]
453    #[inline(never)]
454    pub(crate) fn relation_budget_exceeded(
455        resource: diagnostic_code::DiagnosticExecutionBudgetResource,
456        limit: u64,
457        observed: u64,
458    ) -> Self {
459        Self::execution_budget_exceeded(
460            resource,
461            limit,
462            observed,
463            diagnostic_code::DiagnosticExecutionBudgetScope::Execution,
464            diagnostic_code::DiagnosticExecutionLane::Mutation,
465            0,
466        )
467    }
468
469    /// Construct an executor-origin rejection for one indivisible page unit.
470    #[cold]
471    #[inline(never)]
472    pub(crate) fn page_unit_too_large(
473        resource: diagnostic_code::DiagnosticExecutionBudgetResource,
474        limit: u64,
475        attempted: u64,
476    ) -> Self {
477        Self::with_diagnostic_facts(
478            ErrorClass::Unsupported,
479            ErrorOrigin::Executor,
480            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
481                boundary: diagnostic_code::RuntimeBoundaryCode::PageUnitTooLarge,
482            }),
483            vec![
484                (
485                    diagnostic_code::DiagnosticFactTag::BudgetResource,
486                    resource.raw(),
487                ),
488                (diagnostic_code::DiagnosticFactTag::Limit, limit),
489                (diagnostic_code::DiagnosticFactTag::Actual, attempted),
490            ],
491        )
492    }
493
494    /// Rebuild this error with a new origin while preserving class taxonomy.
495    ///
496    /// Numeric facts are origin-independent and remain safe after recovery
497    /// relabeling. Other origin-scoped detail payloads are dropped.
498    #[cold]
499    #[inline(never)]
500    pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
501        match self.detail {
502            Some(ErrorDetail::DiagnosticFacts(detail)) => Self::with_diagnostic_facts(
503                self.class,
504                origin,
505                detail.diagnostic.detail().copied(),
506                detail.facts,
507            ),
508            _ => Self::classified(self.class, origin),
509        }
510    }
511
512    /// Construct an index-origin invariant violation.
513    #[cold]
514    #[inline(never)]
515    pub(crate) fn index_invariant() -> Self {
516        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
517    }
518
519    /// Construct the canonical index field-count invariant for key building.
520    pub(crate) fn index_key_field_count_exceeds_max(
521        entity_tag: u64,
522        physical_generation: u64,
523        field_count: usize,
524        max_fields: usize,
525    ) -> Self {
526        Self::with_diagnostic_facts(
527            ErrorClass::InvariantViolation,
528            ErrorOrigin::Index,
529            None,
530            vec![
531                (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
532                (
533                    diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
534                    physical_generation,
535                ),
536                (
537                    diagnostic_code::DiagnosticFactTag::ComponentKind,
538                    diagnostic_code::DiagnosticComponentKind::IndexKey.raw(),
539                ),
540                (
541                    diagnostic_code::DiagnosticFactTag::ActualArity,
542                    field_count as u64,
543                ),
544                (
545                    diagnostic_code::DiagnosticFactTag::Maximum,
546                    max_fields as u64,
547                ),
548            ],
549        )
550    }
551
552    /// Construct the canonical index-expression source-type mismatch invariant.
553    pub(crate) fn index_expression_source_type_mismatch(
554        _index_name: &str,
555        _expression: impl Sized,
556        _expected: impl Sized,
557        _source_label: &str,
558    ) -> Self {
559        Self::index_invariant()
560    }
561
562    /// Construct a planner-origin invariant violation for executor-boundary
563    /// contract drift.
564    #[cold]
565    #[inline(never)]
566    pub(crate) fn planner_executor_invariant() -> Self {
567        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
568    }
569
570    /// Construct a query-origin invariant violation for executor-boundary
571    /// contract drift.
572    #[cold]
573    #[inline(never)]
574    pub(crate) fn query_executor_invariant() -> Self {
575        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
576    }
577
578    /// Construct a cursor-origin invariant violation for executor-boundary
579    /// contract drift.
580    #[cold]
581    #[inline(never)]
582    pub(crate) fn cursor_executor_invariant() -> Self {
583        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
584    }
585
586    /// Construct an executor-origin invariant violation.
587    #[cold]
588    #[inline(never)]
589    pub(crate) fn executor_invariant() -> Self {
590        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
591    }
592
593    /// Construct an executor-origin internal error.
594    #[cold]
595    #[inline(never)]
596    pub(crate) fn executor_internal() -> Self {
597        Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
598    }
599
600    /// Construct an executor-origin unsupported error.
601    #[cold]
602    #[inline(never)]
603    pub(crate) fn executor_unsupported() -> Self {
604        Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
605    }
606
607    /// Construct an executor-origin database-owned-field authorship rejection.
608    #[cold]
609    #[inline(never)]
610    pub(crate) fn mutation_database_owned_field_explicit(
611        context: MutationDiagnosticContext,
612        field_id: u32,
613    ) -> Self {
614        Self::mutation_boundary_with_facts(
615            ErrorClass::Unsupported,
616            diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
617            context.facts(Some(field_id)),
618        )
619    }
620
621    /// Construct an executor-origin required-field omission rejection.
622    #[must_use]
623    #[cold]
624    #[inline(never)]
625    pub(crate) fn mutation_required_field_missing(
626        context: MutationDiagnosticContext,
627        field_id: u32,
628    ) -> Self {
629        Self::mutation_boundary_with_facts(
630            ErrorClass::Unsupported,
631            diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
632            context.facts(Some(field_id)),
633        )
634    }
635
636    /// Construct an executor-origin managed-timestamp clock regression.
637    #[must_use]
638    #[cold]
639    #[inline(never)]
640    pub(crate) fn mutation_managed_timestamp_regression(
641        context: MutationDiagnosticContext,
642    ) -> Self {
643        Self::mutation_boundary_with_facts(
644            ErrorClass::InvariantViolation,
645            diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
646            context.facts(None),
647        )
648    }
649
650    /// Construct an executor-origin accepted constraint or activation-gate violation.
651    pub(crate) fn mutation_constraint_violation(context: AcceptedConstraintFactContext) -> Self {
652        Self::mutation_boundary_with_facts(
653            ErrorClass::InvariantViolation,
654            diagnostic_code::RuntimeBoundaryCode::ConstraintViolation,
655            context.facts(),
656        )
657    }
658
659    /// Construct an executor-origin corruption failure for row-constraint authority.
660    pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
661        Self {
662            class: ErrorClass::Corruption,
663            origin: ErrorOrigin::Executor,
664            detail: Some(ErrorDetail::Executor(
665                ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
666            )),
667        }
668    }
669
670    /// Construct one typed migration conflict for an incomplete activation gate.
671    pub(crate) fn mutation_constraint_activation_write_blocked(
672        context: AcceptedConstraintFactContext,
673    ) -> Self {
674        Self::mutation_boundary_with_facts(
675            ErrorClass::Conflict,
676            diagnostic_code::RuntimeBoundaryCode::ConstraintActivationWriteBlocked,
677            context.facts(),
678        )
679    }
680
681    /// Construct a query-origin scalar page invariant for missing order at the cursor boundary.
682    pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
683        Self::query_executor_invariant()
684    }
685
686    /// Construct a query-origin scalar page invariant for cursor-before-ordering drift.
687    pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
688        Self::query_executor_invariant()
689    }
690
691    /// Construct a query-origin scalar page invariant for pagination-before-ordering drift.
692    pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
693        Self::query_executor_invariant()
694    }
695
696    /// Construct a query-origin fast-stream invariant for route kind/request mismatch.
697    pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
698        Self::query_executor_invariant()
699    }
700
701    /// Construct a query-origin scan invariant for missing index-prefix executable specs.
702    pub(crate) fn secondary_index_prefix_spec_required() -> Self {
703        Self::query_executor_invariant()
704    }
705
706    /// Construct a query-origin scan invariant for missing index-range executable specs.
707    pub(crate) fn index_range_limit_spec_required() -> Self {
708        Self::query_executor_invariant()
709    }
710
711    /// Construct an executor-origin mutation conflict for duplicate atomic save keys.
712    #[cold]
713    #[inline(never)]
714    pub(crate) fn mutation_atomic_save_duplicate_key(
715        entity_tag: u64,
716        first_position: u32,
717        duplicate_position: u32,
718    ) -> Self {
719        Self::mutation_boundary_with_facts(
720            ErrorClass::Conflict,
721            diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
722            vec![
723                (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
724                (
725                    diagnostic_code::DiagnosticFactTag::FirstBatchPosition,
726                    u64::from(first_position),
727                ),
728                (
729                    diagnostic_code::DiagnosticFactTag::DuplicateBatchPosition,
730                    u64::from(duplicate_position),
731                ),
732            ],
733        )
734    }
735
736    /// Construct an executor-origin empty mixed-mutation batch rejection.
737    #[cold]
738    #[inline(never)]
739    pub(crate) fn mutation_batch_empty() -> Self {
740        Self::mutation_boundary_with_facts(
741            ErrorClass::Unsupported,
742            diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
743            vec![(diagnostic_code::DiagnosticFactTag::ActualCount, 0)],
744        )
745    }
746
747    /// Construct an executor-origin mixed-mutation item-bound rejection.
748    #[cold]
749    #[inline(never)]
750    pub(crate) fn mutation_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
751        Self::mutation_boundary_with_facts(
752            ErrorClass::Unsupported,
753            diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
754            vec![
755                (
756                    diagnostic_code::DiagnosticFactTag::ActualCount,
757                    actual_count as u64,
758                ),
759                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
760            ],
761        )
762    }
763
764    /// Construct an executor-origin mixed-mutation staged-byte-bound rejection.
765    #[cold]
766    #[inline(never)]
767    pub(crate) fn mutation_batch_staged_bytes_exceeded(
768        actual_bytes: Option<usize>,
769        limit: usize,
770    ) -> Self {
771        let mut facts = Vec::with_capacity(1 + usize::from(actual_bytes.is_some()));
772        if let Some(actual_bytes) = actual_bytes {
773            facts.push((
774                diagnostic_code::DiagnosticFactTag::ActualLength,
775                actual_bytes as u64,
776            ));
777        }
778        facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
779        Self::mutation_boundary_with_facts(
780            ErrorClass::Unsupported,
781            diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
782            facts,
783        )
784    }
785
786    /// Construct an executor-origin mixed-mutation result-byte-bound rejection.
787    #[cold]
788    #[inline(never)]
789    pub(crate) fn mutation_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
790        Self::mutation_boundary_with_facts(
791            ErrorClass::Unsupported,
792            diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
793            vec![
794                (
795                    diagnostic_code::DiagnosticFactTag::ActualLength,
796                    actual_bytes as u64,
797                ),
798                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
799            ],
800        )
801    }
802
803    /// Construct an executor-origin prepared-commit work-bound rejection.
804    #[cold]
805    #[inline(never)]
806    pub(crate) fn mutation_batch_commit_work_exceeded(
807        actual_units: Option<usize>,
808        limit: usize,
809    ) -> Self {
810        let mut facts = Vec::with_capacity(1 + usize::from(actual_units.is_some()));
811        if let Some(actual_units) = actual_units {
812            facts.push((
813                diagnostic_code::DiagnosticFactTag::ActualCount,
814                actual_units as u64,
815            ));
816        }
817        facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
818        Self::mutation_boundary_with_facts(
819            ErrorClass::Unsupported,
820            diagnostic_code::RuntimeBoundaryCode::MutationBatchCommitWorkExceeded,
821            facts,
822        )
823    }
824
825    /// Construct the retryable cumulative journal-backlog pressure boundary.
826    pub(crate) fn convergence_backlog_pressure(
827        resource: diagnostic_code::DiagnosticBacklogResource,
828        current: u64,
829        proposed: u64,
830        limit: u64,
831    ) -> Self {
832        Self::mutation_boundary_with_facts(
833            ErrorClass::Conflict,
834            diagnostic_code::RuntimeBoundaryCode::ConvergenceBacklogPressure,
835            vec![
836                (
837                    diagnostic_code::DiagnosticFactTag::BacklogResource,
838                    resource.raw(),
839                ),
840                (diagnostic_code::DiagnosticFactTag::CurrentCount, current),
841                (diagnostic_code::DiagnosticFactTag::ProposedCount, proposed),
842                (diagnostic_code::DiagnosticFactTag::Limit, limit),
843            ],
844        )
845    }
846
847    /// Construct a query-origin exact-key item-bound rejection.
848    #[cold]
849    #[inline(never)]
850    pub(crate) fn exact_key_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
851        Self::exact_key_batch_boundary_with_facts(
852            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchTooManyItems,
853            vec![
854                (
855                    diagnostic_code::DiagnosticFactTag::ActualCount,
856                    actual_count as u64,
857                ),
858                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
859            ],
860        )
861    }
862
863    /// Construct a query-origin exact-key input-byte rejection.
864    #[cold]
865    #[inline(never)]
866    pub(crate) fn exact_key_batch_input_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
867        Self::exact_key_batch_bytes_exceeded(
868            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchInputBytesExceeded,
869            actual_bytes,
870            limit,
871        )
872    }
873
874    /// Construct a query-origin exact-key stored-row-byte rejection.
875    #[cold]
876    #[inline(never)]
877    pub(crate) fn exact_key_batch_stored_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
878        Self::exact_key_batch_bytes_exceeded(
879            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchStoredBytesExceeded,
880            actual_bytes,
881            limit,
882        )
883    }
884
885    /// Construct a query-origin exact-key result-byte rejection.
886    #[cold]
887    #[inline(never)]
888    pub(crate) fn exact_key_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
889        Self::exact_key_batch_bytes_exceeded(
890            diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchResultBytesExceeded,
891            actual_bytes,
892            limit,
893        )
894    }
895
896    #[cold]
897    #[inline(never)]
898    fn exact_key_batch_bytes_exceeded(
899        boundary: diagnostic_code::RuntimeBoundaryCode,
900        actual_bytes: usize,
901        limit: usize,
902    ) -> Self {
903        Self::exact_key_batch_boundary_with_facts(
904            boundary,
905            vec![
906                (
907                    diagnostic_code::DiagnosticFactTag::ActualLength,
908                    actual_bytes as u64,
909                ),
910                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
911            ],
912        )
913    }
914
915    /// Construct an executor-origin cross-store batch rejection.
916    #[cold]
917    #[inline(never)]
918    pub(crate) fn mutation_batch_store_mismatch(
919        batch_position: u32,
920        expected_entity_tag: u64,
921        actual_entity_tag: u64,
922    ) -> Self {
923        Self::mutation_boundary_with_facts(
924            ErrorClass::Conflict,
925            diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
926            vec![
927                (
928                    diagnostic_code::DiagnosticFactTag::BatchPosition,
929                    u64::from(batch_position),
930                ),
931                (
932                    diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
933                    expected_entity_tag,
934                ),
935                (
936                    diagnostic_code::DiagnosticFactTag::ActualEntityTag,
937                    actual_entity_tag,
938                ),
939            ],
940        )
941    }
942
943    /// Construct an executor-origin distinct-entity-bound rejection.
944    #[cold]
945    #[inline(never)]
946    pub(crate) fn mutation_batch_too_many_entities(actual_count: usize, limit: usize) -> Self {
947        Self::mutation_boundary_with_facts(
948            ErrorClass::Unsupported,
949            diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
950            vec![
951                (
952                    diagnostic_code::DiagnosticFactTag::ActualCount,
953                    actual_count as u64,
954                ),
955                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
956            ],
957        )
958    }
959
960    /// Construct an executor-origin mutation invariant for index-store generation drift.
961    pub(crate) fn mutation_index_store_generation_changed(
962        _expected_generation: u64,
963        _observed_generation: u64,
964    ) -> Self {
965        Self::executor_invariant()
966    }
967
968    /// Construct a planner-origin invariant violation.
969    #[cold]
970    #[inline(never)]
971    pub(crate) fn planner_invariant() -> Self {
972        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
973    }
974
975    /// Construct a planner-origin invalid-logical-plan invariant.
976    pub(crate) fn query_invalid_logical_plan() -> Self {
977        Self::planner_invariant()
978    }
979
980    /// Construct a store-origin invariant violation.
981    pub(crate) fn store_invariant() -> Self {
982        Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
983    }
984
985    /// Construct a store-origin internal error.
986    #[cold]
987    #[inline(never)]
988    pub(crate) fn store_internal() -> Self {
989        Self::new(ErrorClass::Internal, ErrorOrigin::Store)
990    }
991
992    /// Construct the canonical unconfigured commit-memory id internal error.
993    pub(crate) fn commit_memory_id_unconfigured() -> Self {
994        Self::store_internal()
995    }
996
997    /// Construct the canonical initialized commit-store lookup invariant.
998    pub(crate) fn commit_store_uninitialized() -> Self {
999        Self::store_invariant()
1000    }
1001
1002    /// Construct the canonical commit-memory id mismatch internal error.
1003    pub(crate) fn commit_memory_id_mismatch(cached_id: u8, configured_id: u8) -> Self {
1004        Self::with_diagnostic_facts(
1005            ErrorClass::Internal,
1006            ErrorOrigin::Store,
1007            None,
1008            vec![
1009                (
1010                    diagnostic_code::DiagnosticFactTag::ExpectedMemoryId,
1011                    u64::from(cached_id),
1012                ),
1013                (
1014                    diagnostic_code::DiagnosticFactTag::ActualMemoryId,
1015                    u64::from(configured_id),
1016                ),
1017            ],
1018        )
1019    }
1020
1021    /// Construct the canonical commit-memory stable-key mismatch internal error.
1022    pub(crate) fn commit_memory_stable_key_mismatch(
1023        _cached_key: &str,
1024        _configured_key: &str,
1025    ) -> Self {
1026        Self::store_internal()
1027    }
1028
1029    /// Construct the canonical database-incarnation generation failure.
1030    pub(crate) fn database_incarnation_generation_failed() -> Self {
1031        Self::store_internal()
1032    }
1033
1034    /// Construct the canonical zero database-incarnation corruption error.
1035    pub(crate) fn database_incarnation_invalid() -> Self {
1036        Self::store_corruption()
1037    }
1038
1039    /// Construct a recovery-origin incompatible store-format error.
1040    pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
1041        Self {
1042            class: ErrorClass::IncompatiblePersistedFormat,
1043            origin: ErrorOrigin::Recovery,
1044            detail: Some(ErrorDetail::Recovery(
1045                RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
1046            )),
1047        }
1048    }
1049
1050    /// Construct a recovery-origin malformed store-format marker error.
1051    pub(crate) fn recovery_malformed_database_format_marker(
1052        reason: RecoveryFormatMarkerError,
1053    ) -> Self {
1054        Self {
1055            class: ErrorClass::Corruption,
1056            origin: ErrorOrigin::Recovery,
1057            detail: Some(ErrorDetail::Recovery(
1058                RecoveryErrorDetail::MalformedFormatMarker { reason },
1059            )),
1060        }
1061    }
1062
1063    /// Construct a recovery-origin boot control-memory failure.
1064    pub(crate) fn recovery_database_format_control_unavailable() -> Self {
1065        Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
1066    }
1067
1068    /// Construct the retryable internal boundary returned while bounded startup recovery remains.
1069    pub(crate) fn recovery_pending() -> Self {
1070        Self::with_diagnostic_facts(
1071            ErrorClass::Conflict,
1072            ErrorOrigin::Recovery,
1073            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1074                boundary: diagnostic_code::RuntimeBoundaryCode::DatabaseStartupRecoveryPending,
1075            }),
1076            Vec::new(),
1077        )
1078    }
1079
1080    /// Construct fail-closed corruption for the bounded startup control cell.
1081    pub(crate) fn startup_control_corruption() -> Self {
1082        Self::new(ErrorClass::Corruption, ErrorOrigin::Recovery)
1083    }
1084
1085    /// Construct a commit control-memory growth failure.
1086    pub(crate) fn commit_control_memory_growth_failed() -> Self {
1087        Self::store_internal()
1088    }
1089
1090    /// Construct a store-format memory registration failure.
1091    #[cfg(not(test))]
1092    pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
1093        Self::store_internal()
1094    }
1095
1096    /// Construct the canonical recovered-effect verification failure.
1097    pub(crate) fn recovery_effect_verification_failed() -> Self {
1098        Self::store_corruption()
1099    }
1100
1101    /// Construct an index-origin internal error.
1102    #[cold]
1103    #[inline(never)]
1104    pub(crate) fn index_internal() -> Self {
1105        Self::new(ErrorClass::Internal, ErrorOrigin::Index)
1106    }
1107
1108    /// Construct the canonical missing old entity-key internal error for structural index removal.
1109    pub(crate) fn structural_index_removal_entity_key_required() -> Self {
1110        Self::index_internal()
1111    }
1112
1113    /// Construct the canonical missing new entity-key internal error for structural index insertion.
1114    pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
1115        Self::index_internal()
1116    }
1117
1118    /// Construct the canonical missing old entity-key internal error for index commit-op removal.
1119    pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
1120        Self::index_internal()
1121    }
1122
1123    /// Construct the canonical missing new entity-key internal error for index commit-op insertion.
1124    pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
1125        Self::index_internal()
1126    }
1127
1128    /// Construct a query-origin internal error.
1129    #[cfg(test)]
1130    pub(crate) fn query_internal() -> Self {
1131        Self::new(ErrorClass::Internal, ErrorOrigin::Query)
1132    }
1133
1134    /// Construct a query-origin unsupported error.
1135    #[cold]
1136    #[inline(never)]
1137    pub(crate) fn query_unsupported() -> Self {
1138        Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
1139    }
1140
1141    /// Detached explain rendering exceeded its fixed output policy, not a
1142    /// request/execution budget. Retain numeric facts without report contents.
1143    pub(crate) fn query_explain_output_exceeded(limit: u64, observed: u64) -> Self {
1144        Self::with_diagnostic_facts(
1145            ErrorClass::Unsupported,
1146            ErrorOrigin::Query,
1147            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1148                boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainOutputExceeded,
1149            }),
1150            vec![
1151                (diagnostic_code::DiagnosticFactTag::Limit, limit),
1152                (diagnostic_code::DiagnosticFactTag::Actual, observed),
1153            ],
1154        )
1155    }
1156
1157    /// Derived diagnostic access depth exceeded its fixed projection policy.
1158    /// This does not reject or change the identity of an ordinary query.
1159    pub(crate) fn query_explain_depth_exceeded(limit: u64, observed: u64) -> Self {
1160        Self::with_diagnostic_facts(
1161            ErrorClass::Unsupported,
1162            ErrorOrigin::Query,
1163            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1164                boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainDepthExceeded,
1165            }),
1166            vec![
1167                (diagnostic_code::DiagnosticFactTag::Limit, limit),
1168                (diagnostic_code::DiagnosticFactTag::Actual, observed),
1169            ],
1170        )
1171    }
1172
1173    /// Construct a query-origin conflict for execution against a superseded
1174    /// accepted schema revision.
1175    #[cold]
1176    #[inline(never)]
1177    pub(crate) fn query_stale_accepted_schema_revision(
1178        expected_revision: u64,
1179        current_revision: Option<u64>,
1180    ) -> Self {
1181        let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
1182        facts.push((
1183            diagnostic_code::DiagnosticFactTag::ExpectedRevision,
1184            expected_revision,
1185        ));
1186        if let Some(current_revision) = current_revision {
1187            facts.push((
1188                diagnostic_code::DiagnosticFactTag::CurrentRevision,
1189                current_revision,
1190            ));
1191        }
1192        Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
1193    }
1194
1195    /// Construct a query-origin SQL DDL admission error with structured detail.
1196    #[cold]
1197    #[inline(never)]
1198    #[cfg(feature = "sql")]
1199    pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
1200        Self {
1201            class: ErrorClass::Unsupported,
1202            origin: ErrorOrigin::Query,
1203            detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
1204                error,
1205            })),
1206        }
1207    }
1208
1209    /// Construct a query-origin numeric overflow error with structured detail.
1210    #[cold]
1211    #[inline(never)]
1212    pub(crate) fn query_numeric_overflow() -> Self {
1213        Self {
1214            class: ErrorClass::Unsupported,
1215            origin: ErrorOrigin::Query,
1216            detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
1217        }
1218    }
1219
1220    /// Construct a query-origin non-representable numeric result error with
1221    /// structured detail.
1222    #[cold]
1223    #[inline(never)]
1224    pub(crate) fn query_numeric_not_representable() -> Self {
1225        Self {
1226            class: ErrorClass::Unsupported,
1227            origin: ErrorOrigin::Query,
1228            detail: Some(ErrorDetail::Query(
1229                QueryErrorDetail::NumericNotRepresentable,
1230            )),
1231        }
1232    }
1233
1234    /// Construct a serialize-origin internal error.
1235    #[cold]
1236    #[inline(never)]
1237    pub(crate) fn serialize_internal() -> Self {
1238        Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
1239    }
1240
1241    /// Construct the canonical persisted-row encode internal error.
1242    pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
1243        Self::persisted_row_encode_internal()
1244    }
1245
1246    /// Construct the compact persisted-row encode internal error.
1247    pub(crate) fn persisted_row_encode_internal() -> Self {
1248        Self::serialize_internal()
1249    }
1250
1251    /// Construct the compact persisted-row field encode internal error.
1252    pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
1253        Self::persisted_row_encode_internal()
1254    }
1255
1256    /// Construct a store-origin corruption error.
1257    #[cold]
1258    #[inline(never)]
1259    pub(crate) fn store_corruption() -> Self {
1260        Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
1261    }
1262
1263    /// Construct a store-origin commit-marker corruption error.
1264    pub(crate) fn commit_corruption() -> Self {
1265        Self::store_corruption()
1266    }
1267
1268    /// Construct a store-origin commit-marker component corruption error.
1269    pub(crate) fn commit_component_corruption() -> Self {
1270        Self::commit_corruption()
1271    }
1272
1273    /// Construct the canonical commit-marker id generation internal error.
1274    pub(crate) fn commit_id_generation_failed() -> Self {
1275        Self::store_internal()
1276    }
1277
1278    /// Construct the canonical commit-marker payload u32-length-limit error.
1279    pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
1280        Self::store_unsupported()
1281    }
1282
1283    /// Construct the canonical commit-marker component invalid-length corruption error.
1284    pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
1285        Self::with_diagnostic_facts(
1286            ErrorClass::Corruption,
1287            ErrorOrigin::Store,
1288            None,
1289            vec![
1290                (
1291                    diagnostic_code::DiagnosticFactTag::ComponentKind,
1292                    diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
1293                ),
1294                (
1295                    diagnostic_code::DiagnosticFactTag::ActualLength,
1296                    actual_length as u64,
1297                ),
1298                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1299            ],
1300        )
1301    }
1302
1303    /// Construct the canonical commit-marker max-size corruption error.
1304    pub(crate) fn commit_marker_exceeds_max_size() -> Self {
1305        Self::commit_corruption()
1306    }
1307
1308    /// Construct the canonical commit-control slot max-size unsupported error.
1309    pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
1310        Self::store_unsupported()
1311    }
1312
1313    /// Construct the canonical commit-control marker-bytes length-limit error.
1314    pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
1315        Self::store_unsupported()
1316    }
1317
1318    /// Construct an index-origin corruption error.
1319    #[cold]
1320    #[inline(never)]
1321    pub(crate) fn index_corruption() -> Self {
1322        Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
1323    }
1324
1325    /// Construct the canonical unique-validation corruption wrapper.
1326    pub(crate) fn index_unique_validation_corruption() -> Self {
1327        Self::index_plan_index_corruption()
1328    }
1329
1330    /// Construct the canonical structural index-entry corruption wrapper.
1331    pub(crate) fn structural_index_entry_corruption() -> Self {
1332        Self::index_plan_index_corruption()
1333    }
1334
1335    /// Construct the canonical missing new entity-key invariant during unique validation.
1336    pub(crate) fn index_unique_validation_entity_key_required() -> Self {
1337        Self::index_invariant()
1338    }
1339
1340    /// Construct the canonical unique-validation structural row-decode corruption error.
1341    pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
1342        Self::index_plan_serialize_corruption()
1343    }
1344
1345    /// Construct the canonical unique-validation primary-key slot decode corruption error.
1346    pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
1347        Self::index_plan_serialize_corruption()
1348    }
1349
1350    /// Construct the canonical unique-validation stored key rebuild corruption error.
1351    pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
1352        Self::index_plan_serialize_corruption()
1353    }
1354
1355    /// Construct the canonical unique-validation missing-row corruption error.
1356    pub(crate) fn index_unique_validation_row_required() -> Self {
1357        Self::index_plan_store_corruption()
1358    }
1359
1360    /// Construct the canonical index-only predicate missing-component invariant.
1361    pub(crate) fn index_only_predicate_component_required() -> Self {
1362        Self::index_invariant()
1363    }
1364
1365    /// Construct the canonical index-scan continuation-envelope invariant.
1366    pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
1367        Self::index_invariant()
1368    }
1369
1370    /// Construct the canonical index-scan continuation-advancement invariant.
1371    pub(crate) fn index_scan_continuation_advancement_required() -> Self {
1372        Self::index_invariant()
1373    }
1374
1375    /// Construct the canonical index-scan key-decode corruption error.
1376    pub(crate) fn index_scan_key_corrupted_during(
1377        _context: &'static str,
1378        _err: impl Sized,
1379    ) -> Self {
1380        Self::index_corruption()
1381    }
1382
1383    /// Construct the canonical index-scan missing projection-component invariant.
1384    pub(crate) fn index_projection_component_required(
1385        _index_name: &str,
1386        _component_index: usize,
1387    ) -> Self {
1388        Self::index_invariant()
1389    }
1390
1391    /// Construct the canonical scan-time index-entry decode corruption error.
1392    pub(crate) fn index_entry_decode_failed() -> Self {
1393        Self::index_corruption()
1394    }
1395
1396    /// Construct a serialize-origin corruption error.
1397    pub(crate) fn serialize_corruption() -> Self {
1398        Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
1399    }
1400
1401    /// Construct the compact persisted-row decode corruption error.
1402    pub(crate) fn persisted_row_decode_corruption() -> Self {
1403        Self::serialize_corruption()
1404    }
1405
1406    /// Construct a persisted-row layout-window corruption error.
1407    pub(crate) fn persisted_row_layout_outside_accepted_window(
1408        row_layout: u32,
1409        history_floor: u32,
1410        current_layout: u32,
1411    ) -> Self {
1412        Self::with_diagnostic_facts(
1413            ErrorClass::Corruption,
1414            ErrorOrigin::Serialize,
1415            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1416                boundary:
1417                    diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
1418            }),
1419            vec![
1420                (
1421                    diagnostic_code::DiagnosticFactTag::RowLayout,
1422                    u64::from(row_layout),
1423                ),
1424                (
1425                    diagnostic_code::DiagnosticFactTag::HistoryFloor,
1426                    u64::from(history_floor),
1427                ),
1428                (
1429                    diagnostic_code::DiagnosticFactTag::CurrentLayout,
1430                    u64::from(current_layout),
1431                ),
1432            ],
1433        )
1434    }
1435
1436    /// Construct a persisted-row stamped-layout slot-count corruption error.
1437    pub(crate) fn persisted_row_slot_count_mismatch(
1438        row_layout: u32,
1439        expected_slot_count: usize,
1440        actual_slot_count: usize,
1441    ) -> Self {
1442        Self::with_diagnostic_facts(
1443            ErrorClass::Corruption,
1444            ErrorOrigin::Serialize,
1445            Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1446                boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
1447            }),
1448            vec![
1449                (
1450                    diagnostic_code::DiagnosticFactTag::RowLayout,
1451                    u64::from(row_layout),
1452                ),
1453                (
1454                    diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
1455                    expected_slot_count as u64,
1456                ),
1457                (
1458                    diagnostic_code::DiagnosticFactTag::ActualSlotCount,
1459                    actual_slot_count as u64,
1460                ),
1461            ],
1462        )
1463    }
1464
1465    /// Construct the canonical persisted-row field decode corruption error.
1466    pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
1467        Self::persisted_row_field_decode_corruption(field_name)
1468    }
1469
1470    /// Construct the compact persisted-row field decode corruption error.
1471    pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
1472        Self::persisted_row_decode_corruption()
1473    }
1474
1475    /// Construct the canonical persisted-row field-kind decode corruption error.
1476    pub(crate) fn persisted_row_field_kind_decode_failed(
1477        field_name: &str,
1478        _field_kind: impl fmt::Debug,
1479        _detail: impl Sized,
1480    ) -> Self {
1481        Self::persisted_row_field_decode_corruption(field_name)
1482    }
1483
1484    /// Construct the canonical persisted-row scalar-payload length corruption error.
1485    pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
1486        Self::persisted_row_field_decode_corruption(field_name)
1487    }
1488
1489    /// Construct the canonical persisted-row scalar-payload empty-body corruption error.
1490    pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
1491        Self::persisted_row_field_decode_corruption(field_name)
1492    }
1493
1494    /// Construct the canonical persisted-row scalar-payload invalid-byte corruption error.
1495    pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
1496        Self::persisted_row_field_decode_corruption(field_name)
1497    }
1498
1499    /// Construct the canonical persisted-row scalar-payload non-finite corruption error.
1500    pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
1501        Self::persisted_row_field_decode_corruption(field_name)
1502    }
1503
1504    /// Construct the canonical persisted-row invalid text payload corruption error.
1505    pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
1506        Self::persisted_row_field_decode_corruption(field_name)
1507    }
1508
1509    /// Construct the canonical persisted-row structural slot-lookup invariant.
1510    pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
1511        Self::index_invariant()
1512    }
1513
1514    /// Construct the canonical persisted-row structural slot-cache invariant.
1515    pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
1516        _model_path: &str,
1517        _slot: usize,
1518    ) -> Self {
1519        Self::index_invariant()
1520    }
1521
1522    /// Construct the canonical persisted-row primary-key decode corruption error.
1523    pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1524        _data_key: impl fmt::Debug,
1525        _detail: impl Sized,
1526    ) -> Self {
1527        Self::persisted_row_decode_corruption()
1528    }
1529
1530    /// Construct the canonical persisted-row missing primary-key slot corruption error.
1531    pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1532        Self::persisted_row_decode_corruption()
1533    }
1534
1535    /// Construct the canonical persisted-row key mismatch corruption error.
1536    pub(crate) fn persisted_row_key_mismatch() -> Self {
1537        Self::store_corruption()
1538    }
1539
1540    /// Construct the canonical persisted-row missing declared-field corruption error.
1541    pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1542        Self::persisted_row_field_decode_corruption(field_name)
1543    }
1544
1545    /// Construct the canonical reverse-index entry corruption error.
1546    pub(crate) fn reverse_index_entry_corrupted(
1547        _source_path: &str,
1548        _field_name: &str,
1549        _target_path: &str,
1550        _index_key: impl fmt::Debug,
1551        _detail: impl Sized,
1552    ) -> Self {
1553        Self::index_corruption()
1554    }
1555
1556    /// Construct the canonical relation-target store missing internal error.
1557    pub(crate) fn relation_target_store_missing(
1558        _source_path: &str,
1559        _field_name: &str,
1560        _target_path: &str,
1561        _store_path: &str,
1562        _detail: impl Sized,
1563    ) -> Self {
1564        Self::executor_internal()
1565    }
1566
1567    /// Identify the accepted source and relation when runtime contract compilation fails.
1568    pub(crate) fn with_relation_identity(self, entity_tag: u64, relation_id: u32) -> Self {
1569        if self.diagnostic().error_code() != diagnostic_code::ErrorCode::RUNTIME_INTERNAL {
1570            return self;
1571        }
1572        let mut facts = vec![
1573            (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1574            (
1575                diagnostic_code::DiagnosticFactTag::RelationId,
1576                u64::from(relation_id),
1577            ),
1578        ];
1579        facts.extend(self.diagnostic_facts());
1580        Self::with_diagnostic_facts(self.class, self.origin, None, facts)
1581    }
1582
1583    /// Construct one accepted relation target primary-key arity mismatch.
1584    pub(crate) fn relation_target_primary_key_arity_mismatch(
1585        expected_arity: usize,
1586        actual_arity: usize,
1587    ) -> Self {
1588        Self::with_diagnostic_facts(
1589            ErrorClass::Internal,
1590            ErrorOrigin::Executor,
1591            None,
1592            vec![
1593                (
1594                    diagnostic_code::DiagnosticFactTag::ComponentKind,
1595                    diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
1596                ),
1597                (
1598                    diagnostic_code::DiagnosticFactTag::ExpectedArity,
1599                    expected_arity as u64,
1600                ),
1601                (
1602                    diagnostic_code::DiagnosticFactTag::ActualArity,
1603                    actual_arity as u64,
1604                ),
1605            ],
1606        )
1607    }
1608
1609    /// Construct the canonical relation-target key decode corruption error.
1610    pub(crate) fn relation_target_key_decode_failed(
1611        _context_label: &str,
1612        _source_path: &str,
1613        _field_name: &str,
1614        _target_path: &str,
1615        _detail: impl Sized,
1616    ) -> Self {
1617        Self::identity_corruption()
1618    }
1619
1620    /// Construct the canonical relation-target entity mismatch corruption error.
1621    pub(crate) fn relation_target_entity_mismatch(
1622        _context_label: &str,
1623        _source_path: &str,
1624        _field_name: &str,
1625        _target_path: &str,
1626        _target_entity_name: &str,
1627        expected_tag: u64,
1628        actual_tag: u64,
1629    ) -> Self {
1630        Self::with_diagnostic_facts(
1631            ErrorClass::Corruption,
1632            ErrorOrigin::Store,
1633            None,
1634            vec![
1635                (
1636                    diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
1637                    expected_tag,
1638                ),
1639                (
1640                    diagnostic_code::DiagnosticFactTag::ActualEntityTag,
1641                    actual_tag,
1642                ),
1643            ],
1644        )
1645    }
1646
1647    /// Construct the canonical relation-source row decode corruption error.
1648    pub(crate) fn relation_source_row_decode_failed(
1649        _source_path: &str,
1650        _field_name: &str,
1651        _target_path: &str,
1652        _detail: impl Sized,
1653    ) -> Self {
1654        Self::persisted_row_decode_corruption()
1655    }
1656
1657    /// Construct the canonical relation-source unsupported scalar relation-key corruption error.
1658    pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1659        _source_path: &str,
1660        _field_name: &str,
1661        _target_path: &str,
1662    ) -> Self {
1663        Self::persisted_row_decode_corruption()
1664    }
1665
1666    /// Construct the canonical unsupported relation key-kind corruption error.
1667    pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1668        Self::persisted_row_decode_corruption()
1669    }
1670
1671    /// Construct the canonical covering-component empty-payload corruption error.
1672    pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1673        Self::index_corruption()
1674    }
1675
1676    /// Construct the canonical covering-component truncated bool corruption error.
1677    pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1678        Self::index_corruption()
1679    }
1680
1681    /// Construct the canonical covering-component invalid-length corruption error.
1682    pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1683        Self::index_corruption()
1684    }
1685
1686    /// Construct the canonical covering-component invalid-bool corruption error.
1687    pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1688        Self::index_corruption()
1689    }
1690
1691    /// Construct the canonical covering-component invalid text terminator corruption error.
1692    pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1693        Self::index_corruption()
1694    }
1695
1696    /// Construct the canonical covering-component trailing-text corruption error.
1697    pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1698        Self::index_corruption()
1699    }
1700
1701    /// Construct the canonical covering-component invalid-UTF-8 text corruption error.
1702    pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1703        Self::index_corruption()
1704    }
1705
1706    /// Construct the canonical covering-component invalid text escape corruption error.
1707    pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1708        Self::index_corruption()
1709    }
1710
1711    /// Construct the canonical covering-component missing text terminator corruption error.
1712    pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1713        Self::index_corruption()
1714    }
1715
1716    /// Construct an identity-origin corruption error.
1717    pub(crate) fn identity_corruption() -> Self {
1718        Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1719    }
1720
1721    /// Construct the canonical identity-control-state corruption error.
1722    pub(crate) fn identity_state_corruption() -> Self {
1723        Self::identity_corruption()
1724    }
1725
1726    /// Construct the typed stale high-water conflict for identity publication.
1727    pub(crate) fn identity_state_conflict() -> Self {
1728        Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1729    }
1730
1731    /// Construct the bounded identity-state inventory exhaustion error.
1732    pub(crate) fn identity_state_capacity_exhausted() -> Self {
1733        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1734    }
1735
1736    /// Construct the exact unsigned identity-domain exhaustion error.
1737    pub(crate) fn identity_exhausted() -> Self {
1738        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1739    }
1740
1741    /// Construct the bounded pre-key candidate-count exhaustion error.
1742    pub(crate) fn identity_candidate_count_exhausted() -> Self {
1743        Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1744    }
1745
1746    /// Construct a store-origin unsupported error.
1747    #[cold]
1748    #[inline(never)]
1749    pub(crate) fn store_unsupported() -> Self {
1750        Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1751    }
1752
1753    /// Construct the typed optimistic/idempotency conflict for schema application.
1754    pub(crate) fn schema_application_conflict() -> Self {
1755        Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1756    }
1757
1758    /// Construct one typed source-migration lifecycle or planning result.
1759    pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1760        let class = match reason.diagnostic_code() {
1761            diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1762            diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1763            diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1764            _ => ErrorClass::Internal,
1765        };
1766        Self {
1767            class,
1768            origin: ErrorOrigin::Store,
1769            detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1770        }
1771    }
1772
1773    /// Construct the canonical schema DDL publication race error.
1774    pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1775        Self {
1776            class: ErrorClass::Unsupported,
1777            origin: ErrorOrigin::Store,
1778            detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1779        }
1780    }
1781
1782    /// Construct the canonical current physical-rewrite migration rejection.
1783    #[cfg(feature = "sql")]
1784    pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1785        Self {
1786            class: ErrorClass::Unsupported,
1787            origin: ErrorOrigin::Store,
1788            detail: Some(ErrorDetail::Store(
1789                StoreError::SchemaDdlRewriteRequiresMigration,
1790            )),
1791        }
1792    }
1793
1794    /// Construct the fail-closed journal mutation-revision exhaustion error.
1795    pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1796        Self {
1797            class: ErrorClass::Unsupported,
1798            origin: ErrorOrigin::Store,
1799            detail: Some(ErrorDetail::Store(
1800                StoreError::JournalMutationRevisionExhausted,
1801            )),
1802        }
1803    }
1804
1805    /// Construct a bounded schema-transition resource rejection.
1806    pub(crate) fn schema_transition_budget_exceeded(
1807        resource: SchemaTransitionBudgetResource,
1808    ) -> Self {
1809        Self {
1810            class: ErrorClass::Unsupported,
1811            origin: ErrorOrigin::Store,
1812            detail: Some(ErrorDetail::Store(
1813                StoreError::SchemaTransitionBudgetExceeded { resource },
1814            )),
1815        }
1816    }
1817
1818    /// Construct the canonical unsupported persisted entity-tag store error.
1819    pub(crate) fn unsupported_entity_tag_in_data_store(
1820        _entity_tag: crate::types::EntityTag,
1821    ) -> Self {
1822        Self::store_unsupported()
1823    }
1824
1825    /// Construct the canonical commit-memory id registration failure.
1826    #[cfg(not(test))]
1827    pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1828        Self::store_internal()
1829    }
1830
1831    /// Construct an index-origin unsupported error.
1832    pub(crate) fn index_unsupported() -> Self {
1833        Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1834    }
1835
1836    /// Construct the canonical index-key component size-limit unsupported error.
1837    pub(crate) fn index_component_exceeds_max_size_at(
1838        entity_tag: u64,
1839        physical_generation: u64,
1840        component_index: usize,
1841        actual_length: usize,
1842        limit: usize,
1843    ) -> Self {
1844        Self::with_diagnostic_facts(
1845            ErrorClass::Unsupported,
1846            ErrorOrigin::Index,
1847            None,
1848            vec![
1849                (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1850                (
1851                    diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1852                    physical_generation,
1853                ),
1854                (
1855                    diagnostic_code::DiagnosticFactTag::ComponentIndex,
1856                    component_index as u64,
1857                ),
1858                (
1859                    diagnostic_code::DiagnosticFactTag::ComponentKind,
1860                    diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
1861                ),
1862                (
1863                    diagnostic_code::DiagnosticFactTag::ActualLength,
1864                    actual_length as u64,
1865                ),
1866                (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1867            ],
1868        )
1869    }
1870
1871    /// Construct the canonical index-key component size-limit error when the
1872    /// generic caller has not retained one accepted index identity.
1873    pub(crate) fn index_component_exceeds_max_size() -> Self {
1874        Self::index_unsupported()
1875    }
1876
1877    /// Construct a serialize-origin unsupported error.
1878    pub(crate) fn serialize_unsupported() -> Self {
1879        Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1880    }
1881
1882    /// Construct a cursor-origin invalid-continuation error.
1883    pub(crate) fn cursor_invalid_continuation() -> Self {
1884        Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1885    }
1886
1887    /// Construct a serialize-origin incompatible persisted-format error.
1888    pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1889        Self::new(
1890            ErrorClass::IncompatiblePersistedFormat,
1891            ErrorOrigin::Serialize,
1892        )
1893    }
1894
1895    /// Construct a query-origin unsupported error preserving one SQL parser
1896    /// unsupported-feature code in structured error detail.
1897    #[cfg(feature = "sql")]
1898    pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1899        Self {
1900            class: ErrorClass::Unsupported,
1901            origin: ErrorOrigin::Query,
1902            detail: Some(ErrorDetail::Query(
1903                QueryErrorDetail::UnsupportedSqlFeature { feature },
1904            )),
1905        }
1906    }
1907
1908    /// Construct a query-origin unsupported SQL lowering error preserving one
1909    /// compact lowering reason in structured error detail.
1910    #[cfg(feature = "sql")]
1911    pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1912        Self {
1913            class: ErrorClass::Unsupported,
1914            origin: ErrorOrigin::Query,
1915            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1916        }
1917    }
1918
1919    /// Construct one query-origin SQL lowering error with bounded numeric context.
1920    #[cfg(feature = "sql")]
1921    pub(crate) fn query_sql_lowering_with_facts(
1922        reason: diagnostic_code::SqlLoweringCode,
1923        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1924    ) -> Self {
1925        Self::with_diagnostic_facts(
1926            ErrorClass::Unsupported,
1927            ErrorOrigin::Query,
1928            Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
1929            facts,
1930        )
1931    }
1932
1933    /// Construct a query-origin unsupported projection error preserving one
1934    /// compact projection reason in structured error detail.
1935    pub(crate) fn query_unsupported_projection(
1936        reason: diagnostic_code::QueryProjectionCode,
1937    ) -> Self {
1938        Self {
1939            class: ErrorClass::Unsupported,
1940            origin: ErrorOrigin::Query,
1941            detail: Some(ErrorDetail::Query(
1942                QueryErrorDetail::UnsupportedProjection { reason },
1943            )),
1944        }
1945    }
1946
1947    /// Construct a query-origin unsupported error preserving one SQL endpoint
1948    /// surface mismatch in structured error detail.
1949    #[cfg(feature = "sql")]
1950    pub(crate) fn query_sql_surface_mismatch(
1951        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1952    ) -> Self {
1953        Self {
1954            class: ErrorClass::Unsupported,
1955            origin: ErrorOrigin::Query,
1956            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1957                mismatch,
1958            })),
1959        }
1960    }
1961
1962    /// Construct a query-origin unsupported SQL write boundary error.
1963    pub(crate) fn query_sql_write_boundary(
1964        boundary: diagnostic_code::SqlWriteBoundaryCode,
1965    ) -> Self {
1966        Self {
1967            class: ErrorClass::Unsupported,
1968            origin: ErrorOrigin::Query,
1969            detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1970                boundary,
1971            })),
1972        }
1973    }
1974
1975    /// Construct one query-origin SQL write-boundary error with bounded numeric context.
1976    pub(crate) fn query_sql_write_boundary_with_facts(
1977        boundary: diagnostic_code::SqlWriteBoundaryCode,
1978        facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1979    ) -> Self {
1980        Self::with_diagnostic_facts(
1981            ErrorClass::Unsupported,
1982            ErrorOrigin::Query,
1983            Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
1984            facts,
1985        )
1986    }
1987
1988    pub fn store_not_found(_key: impl Sized) -> Self {
1989        Self {
1990            class: ErrorClass::NotFound,
1991            origin: ErrorOrigin::Store,
1992            detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1993        }
1994    }
1995
1996    /// Construct a standardized unsupported-entity-path error.
1997    pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1998        Self::store_unsupported()
1999    }
2000
2001    /// Construct an index-plan corruption error with a canonical prefix.
2002    #[cold]
2003    #[inline(never)]
2004    pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
2005        Self::new(ErrorClass::Corruption, origin)
2006    }
2007
2008    /// Construct an index-plan corruption error for index-origin failures.
2009    #[cold]
2010    #[inline(never)]
2011    pub(crate) fn index_plan_index_corruption() -> Self {
2012        Self::index_plan_corruption(ErrorOrigin::Index)
2013    }
2014
2015    /// Construct an index-plan corruption error for store-origin failures.
2016    #[cold]
2017    #[inline(never)]
2018    pub(crate) fn index_plan_store_corruption() -> Self {
2019        Self::index_plan_corruption(ErrorOrigin::Store)
2020    }
2021
2022    /// Construct an index-plan corruption error for serialize-origin failures.
2023    #[cold]
2024    #[inline(never)]
2025    pub(crate) fn index_plan_serialize_corruption() -> Self {
2026        Self::index_plan_corruption(ErrorOrigin::Serialize)
2027    }
2028
2029    /// Construct an index-plan invariant violation error with a canonical prefix.
2030    #[cfg(test)]
2031    pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
2032        Self::new(ErrorClass::InvariantViolation, origin)
2033    }
2034
2035    /// Construct an index-plan invariant violation error for store-origin failures.
2036    #[cfg(test)]
2037    pub(crate) fn index_plan_store_invariant() -> Self {
2038        Self::index_plan_invariant(ErrorOrigin::Store)
2039    }
2040
2041    /// Construct an index-origin conflict without claiming accepted identity.
2042    ///
2043    /// Live accepted uniqueness violations use compact accepted-constraint facts.
2044    /// Schema-domain staging and activation findings use this compact
2045    /// classification before an accepted write-admission diagnostic exists.
2046    pub(crate) fn index_conflict() -> Self {
2047        Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
2048    }
2049}
2050
2051impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
2052    fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
2053        Self {
2054            class: ErrorClass::Unsupported,
2055            origin: ErrorOrigin::Query,
2056            detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
2057                reason,
2058            })),
2059        }
2060    }
2061}
2062
2063impl fmt::Debug for InternalError {
2064    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2065        fmt_compact_diagnostic(
2066            f,
2067            self.diagnostic_code(),
2068            self.detail
2069                .as_ref()
2070                .and_then(ErrorDetail::diagnostic_detail),
2071        )
2072    }
2073}
2074
2075impl fmt::Display for InternalError {
2076    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2077        f.write_str(self.message())
2078    }
2079}
2080
2081impl std::error::Error for InternalError {}
2082
2083///
2084/// ConstraintValuePathComponent
2085///
2086/// Stable accepted identity or finite-value coordinate in one targeted-rule
2087/// violation. Display names are deliberately absent so renames cannot change
2088/// the diagnostic identity.
2089///
2090
2091#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
2092pub enum ConstraintValuePathComponent {
2093    /// Persisted root field whose admitted value was traversed.
2094    RootField { field_id: u32 },
2095
2096    /// Accepted record member selected by immutable composite/member identity.
2097    RecordMember {
2098        composite_type_id: u32,
2099        member_id: u32,
2100    },
2101
2102    /// Tuple element selected by accepted composite identity and ordinal.
2103    TupleElement {
2104        composite_type_id: u32,
2105        ordinal: u32,
2106    },
2107
2108    /// Transparent accepted newtype boundary.
2109    Newtype { composite_type_id: u32 },
2110
2111    /// Selected accepted enum variant.
2112    EnumVariant { enum_type_id: u32, variant_id: u32 },
2113
2114    /// List element in admitted order.
2115    ListElement { index: u32 },
2116
2117    /// Set element in canonical admitted order.
2118    SetElement { index: u32 },
2119
2120    /// Map key in canonical entry order.
2121    MapEntryKey { index: u32 },
2122
2123    /// Map value in canonical entry order.
2124    MapEntryValue { index: u32 },
2125}
2126
2127impl fmt::Display for ConstraintValuePathComponent {
2128    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2129        match self {
2130            Self::RootField { field_id } => write!(f, "field#{field_id}"),
2131            Self::RecordMember {
2132                composite_type_id,
2133                member_id,
2134            } => write!(f, "record#{composite_type_id}.member#{member_id}"),
2135            Self::TupleElement {
2136                composite_type_id,
2137                ordinal,
2138            } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
2139            Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
2140            Self::EnumVariant {
2141                enum_type_id,
2142                variant_id,
2143            } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
2144            Self::ListElement { index } => write!(f, "list[{index}]"),
2145            Self::SetElement { index } => write!(f, "set[{index}]"),
2146            Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
2147            Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
2148        }
2149    }
2150}
2151
2152///
2153/// ConstraintValuePath
2154///
2155/// Bounded typed path to the first deterministic failing value occurrence.
2156///
2157
2158#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2159pub struct ConstraintValuePath {
2160    components: Vec<ConstraintValuePathComponent>,
2161}
2162
2163impl ConstraintValuePath {
2164    /// Build one already-bounded accepted occurrence path.
2165    #[must_use]
2166    pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
2167        Self { components }
2168    }
2169
2170    /// Borrow the stable accepted components.
2171    #[must_use]
2172    pub const fn components(&self) -> &[ConstraintValuePathComponent] {
2173        self.components.as_slice()
2174    }
2175}
2176
2177impl fmt::Display for ConstraintValuePath {
2178    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2179        for (ordinal, component) in self.components.iter().enumerate() {
2180            if ordinal != 0 {
2181                f.write_str("/")?;
2182            }
2183            component.fmt(f)?;
2184        }
2185        Ok(())
2186    }
2187}
2188
2189///
2190/// ConstraintValidationFindingOutput
2191///
2192/// Bounded historical validation evidence returned only by explicit schema
2193/// validation operations. Names are resolved by host tooling from the exact
2194/// accepted fingerprint and immutable numeric identities.
2195///
2196
2197#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2198pub struct ConstraintValidationFindingOutput {
2199    accepted_schema_fingerprint: [u8; 16],
2200    entity_tag: u64,
2201    constraint_id: u32,
2202    primary_key: Vec<u8>,
2203    field_ids: Vec<u32>,
2204    value_path: Option<ConstraintValuePath>,
2205    error_code: u16,
2206}
2207
2208impl ConstraintValidationFindingOutput {
2209    /// Build one already-bounded historical validation finding.
2210    #[must_use]
2211    pub(crate) const fn new(
2212        accepted_schema_fingerprint: [u8; 16],
2213        entity_tag: u64,
2214        constraint_id: u32,
2215        primary_key: Vec<u8>,
2216        field_ids: Vec<u32>,
2217        value_path: Option<ConstraintValuePath>,
2218        error_code: u16,
2219    ) -> Self {
2220        Self {
2221            accepted_schema_fingerprint,
2222            entity_tag,
2223            constraint_id,
2224            primary_key,
2225            field_ids,
2226            value_path,
2227            error_code,
2228        }
2229    }
2230
2231    /// Return the exact accepted-schema fingerprint that binds every numeric identity.
2232    #[must_use]
2233    pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
2234        self.accepted_schema_fingerprint
2235    }
2236
2237    /// Return the stable accepted entity identity.
2238    #[must_use]
2239    pub const fn entity_tag(&self) -> u64 {
2240        self.entity_tag
2241    }
2242
2243    /// Return the stable accepted constraint identity.
2244    #[must_use]
2245    pub const fn constraint_id(&self) -> u32 {
2246        self.constraint_id
2247    }
2248
2249    /// Borrow the bounded canonical persisted primary-key locator.
2250    #[must_use]
2251    pub const fn primary_key(&self) -> &[u8] {
2252        self.primary_key.as_slice()
2253    }
2254
2255    /// Borrow immutable accepted field identities implicated by the finding.
2256    #[must_use]
2257    pub const fn field_ids(&self) -> &[u32] {
2258        self.field_ids.as_slice()
2259    }
2260
2261    /// Borrow the typed concrete value path for a targeted-rule violation.
2262    #[must_use]
2263    pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2264        self.value_path.as_ref()
2265    }
2266
2267    /// Return the compact stable error code for this exact failure.
2268    #[must_use]
2269    pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2270        diagnostic_code::ErrorCode::from_raw(self.error_code)
2271    }
2272
2273    /// Return the broad public error class derived from the compact code.
2274    #[must_use]
2275    pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2276        self.error_code().class()
2277    }
2278}
2279
2280/// Complete bounded numeric authority needed to publish E210 or E212 facts.
2281#[derive(Clone)]
2282pub(crate) struct AcceptedConstraintFactContext {
2283    fingerprint_method: u8,
2284    accepted_schema_fingerprint: [u8; 16],
2285    entity_tag: u64,
2286    constraint_id: u32,
2287    constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2288    mutation: Option<MutationDiagnosticContext>,
2289    value_path: Option<ConstraintValuePath>,
2290}
2291
2292impl AcceptedConstraintFactContext {
2293    #[must_use]
2294    pub(crate) fn write_admission(
2295        fingerprint_method: u8,
2296        accepted_schema_fingerprint: [u8; 16],
2297        entity_tag: u64,
2298        constraint_id: u32,
2299        constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2300        mutation: Option<MutationDiagnosticContext>,
2301        value_path: Option<ConstraintValuePath>,
2302    ) -> Self {
2303        debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2304        Self {
2305            fingerprint_method,
2306            accepted_schema_fingerprint,
2307            entity_tag,
2308            constraint_id,
2309            constraint_kind,
2310            mutation,
2311            value_path,
2312        }
2313    }
2314
2315    fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2316        let path_len = self
2317            .value_path
2318            .as_ref()
2319            .map_or(0, |path| path.components().len());
2320        let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2321            1 + usize::from(mutation.batch_position.is_some())
2322        });
2323        let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2324        append_accepted_schema_facts(
2325            &mut facts,
2326            self.fingerprint_method,
2327            self.accepted_schema_fingerprint,
2328        );
2329        facts.push((
2330            diagnostic_code::DiagnosticFactTag::EntityTag,
2331            self.entity_tag,
2332        ));
2333        facts.push((
2334            diagnostic_code::DiagnosticFactTag::ConstraintId,
2335            u64::from(self.constraint_id),
2336        ));
2337        facts.push((
2338            diagnostic_code::DiagnosticFactTag::ConstraintKind,
2339            self.constraint_kind.raw(),
2340        ));
2341        facts.push((
2342            diagnostic_code::DiagnosticFactTag::ConstraintContext,
2343            diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2344        ));
2345        if let Some(mutation) = self.mutation {
2346            mutation.append_operation_facts(&mut facts);
2347        }
2348        if let Some(path) = self.value_path {
2349            for component in path.components {
2350                facts.push(constraint_value_path_fact(component));
2351            }
2352        }
2353        debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2354        facts
2355    }
2356}
2357
2358/// Mutation and constraint errors use the same lossless accepted-schema identity.
2359fn append_accepted_schema_facts(
2360    facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
2361    method: u8,
2362    fingerprint: [u8; 16],
2363) {
2364    facts.extend([
2365        (
2366            diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2367            u64::from(method),
2368        ),
2369        (
2370            diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2371            u64::from_be_bytes([
2372                fingerprint[0],
2373                fingerprint[1],
2374                fingerprint[2],
2375                fingerprint[3],
2376                fingerprint[4],
2377                fingerprint[5],
2378                fingerprint[6],
2379                fingerprint[7],
2380            ]),
2381        ),
2382        (
2383            diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2384            u64::from_be_bytes([
2385                fingerprint[8],
2386                fingerprint[9],
2387                fingerprint[10],
2388                fingerprint[11],
2389                fingerprint[12],
2390                fingerprint[13],
2391                fingerprint[14],
2392                fingerprint[15],
2393            ]),
2394        ),
2395    ]);
2396}
2397
2398fn constraint_value_path_fact(
2399    component: ConstraintValuePathComponent,
2400) -> (diagnostic_code::DiagnosticFactTag, u64) {
2401    use diagnostic_code::DiagnosticFactTag;
2402    match component {
2403        ConstraintValuePathComponent::RootField { field_id } => {
2404            (DiagnosticFactTag::RootField, u64::from(field_id))
2405        }
2406        ConstraintValuePathComponent::RecordMember {
2407            composite_type_id,
2408            member_id,
2409        } => (
2410            DiagnosticFactTag::RecordMember,
2411            diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2412        ),
2413        ConstraintValuePathComponent::TupleElement {
2414            composite_type_id,
2415            ordinal,
2416        } => (
2417            DiagnosticFactTag::TupleElement,
2418            diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2419        ),
2420        ConstraintValuePathComponent::Newtype { composite_type_id } => {
2421            (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2422        }
2423        ConstraintValuePathComponent::EnumVariant {
2424            enum_type_id,
2425            variant_id,
2426        } => (
2427            DiagnosticFactTag::EnumVariant,
2428            diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2429        ),
2430        ConstraintValuePathComponent::ListElement { index } => {
2431            (DiagnosticFactTag::ListElement, u64::from(index))
2432        }
2433        ConstraintValuePathComponent::SetElement { index } => {
2434            (DiagnosticFactTag::SetElement, u64::from(index))
2435        }
2436        ConstraintValuePathComponent::MapEntryKey { index } => {
2437            (DiagnosticFactTag::MapEntryKey, u64::from(index))
2438        }
2439        ConstraintValuePathComponent::MapEntryValue { index } => {
2440            (DiagnosticFactTag::MapEntryValue, u64::from(index))
2441        }
2442    }
2443}
2444
2445///
2446/// ErrorDetail
2447///
2448/// Structured, origin-specific error detail carried by [`InternalError`].
2449/// This enum is intentionally extensible.
2450///
2451
2452pub enum ErrorDetail {
2453    /// Compact code/detail plus safe numeric context for one public failure.
2454    DiagnosticFacts(Box<DiagnosticFactDetail>),
2455    /// Executor-owned mutation and query execution details.
2456    Executor(ExecutorErrorDetail),
2457    Store(StoreError),
2458    Query(QueryErrorDetail),
2459    Recovery(RecoveryErrorDetail),
2460    // Future-proofing:
2461    // Index(IndexError),
2462}
2463
2464/// Executor-specific structured error detail.
2465pub enum ExecutorErrorDetail {
2466    /// A complete insert or replacement omitted one or more required fields.
2467    MutationRequiredFieldMissing,
2468    /// A logical mutation would move accepted managed time backward.
2469    MutationManagedTimestampRegression,
2470    /// A caller explicitly authored a field owned by accepted database policy.
2471    MutationDatabaseOwnedFieldExplicit,
2472    /// A mixed structural mutation batch contained no operations.
2473    MutationBatchEmpty,
2474    /// A mixed structural mutation batch exceeded its operation-count bound.
2475    MutationBatchTooManyItems,
2476    /// A mixed structural mutation batch exceeded its staged-byte bound.
2477    MutationBatchStagedBytesExceeded,
2478    /// A mixed structural mutation result exceeded its encoded response bound.
2479    MutationBatchResultBytesExceeded,
2480    /// A mixed structural mutation batch crossed an accepted store boundary.
2481    MutationBatchStoreMismatch,
2482    /// A mixed structural mutation batch exceeded its distinct-entity bound.
2483    MutationBatchTooManyEntities,
2484    /// More than one mixed structural operation targeted the same accepted key.
2485    MutationBatchDuplicateKey,
2486    /// Accepted row-constraint metadata or compiled state was inconsistent.
2487    AcceptedRowConstraintProgramCorrupt,
2488}
2489
2490///
2491/// RecoveryErrorDetail
2492///
2493/// Recovery-origin structured error detail payload.
2494///
2495
2496pub enum RecoveryErrorDetail {
2497    UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2498
2499    MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2500}
2501
2502/// Store boot-marker corruption classification.
2503#[derive(Clone, Copy, Eq, PartialEq)]
2504pub enum RecoveryFormatMarkerError {
2505    Magic,
2506    Checksum,
2507    State,
2508}
2509
2510impl RecoveryFormatMarkerError {
2511    const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2512        match self {
2513            Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2514            Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2515            Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2516        }
2517    }
2518}
2519
2520///
2521/// StoreError
2522///
2523/// Store-specific structured error detail.
2524/// Never returned directly; always wrapped in [`ErrorDetail::Store`].
2525///
2526
2527pub enum StoreError {
2528    NotFound,
2529
2530    Corrupt,
2531
2532    InvariantViolation,
2533
2534    SchemaDdlPublicationRaceLost,
2535
2536    SchemaDdlRewriteRequiresMigration,
2537
2538    SchemaMigration {
2539        reason: diagnostic_code::SchemaMigrationCode,
2540    },
2541
2542    SchemaRowLayoutVersionExhausted,
2543
2544    JournalMutationRevisionExhausted,
2545
2546    SchemaTransitionBudgetExceeded {
2547        resource: SchemaTransitionBudgetResource,
2548    },
2549
2550    /// A generated field would collide with an accepted DDL-owned slot.
2551    SchemaGeneratedFieldAfterDdlField,
2552
2553    /// A live generated constraint activation no longer matches its proposal.
2554    SchemaGeneratedConstraintActivationStale,
2555}
2556
2557///
2558/// QueryErrorDetail
2559///
2560/// Query-origin structured error detail payload.
2561///
2562
2563pub enum QueryErrorDetail {
2564    NumericOverflow,
2565
2566    NumericNotRepresentable,
2567
2568    UnsupportedSqlFeature {
2569        feature: diagnostic_code::SqlFeatureCode,
2570    },
2571
2572    SqlLowering {
2573        reason: diagnostic_code::SqlLoweringCode,
2574    },
2575
2576    UnsupportedProjection {
2577        reason: diagnostic_code::QueryProjectionCode,
2578    },
2579
2580    UnknownAggregateTargetField,
2581
2582    QueryReadAdmission {
2583        reason: diagnostic_code::QueryReadAdmissionCode,
2584    },
2585
2586    SqlSurfaceMismatch {
2587        mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2588    },
2589
2590    SqlWriteBoundary {
2591        boundary: diagnostic_code::SqlWriteBoundaryCode,
2592    },
2593
2594    SchemaDdlAdmission {
2595        error: SchemaDdlAdmissionError,
2596    },
2597
2598    StaleSchemaRevision,
2599}
2600
2601impl fmt::Display for QueryErrorDetail {
2602    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2603        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2604    }
2605}
2606
2607impl std::error::Error for QueryErrorDetail {}
2608
2609///
2610/// SchemaTransitionBudgetResource
2611///
2612/// Query-visible identity of the exact schema-transition resource cap that
2613/// rejected a complete validation or derived-state stage.
2614///
2615
2616#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2617pub enum SchemaTransitionBudgetResource {
2618    /// Number of physical deletion keys retained for replacement.
2619    DeletionKeys,
2620    /// Number of row-derived projection entries retained for validation.
2621    ProjectionEntries,
2622    /// Deterministic projection and physical-classification work units.
2623    ProjectionWorkUnits,
2624    /// Number of authoritative source rows.
2625    SourceRows,
2626    /// Cumulative bytes of authoritative source rows.
2627    SourceRowBytes,
2628    /// Retained raw payloads plus deterministic-sort workspace bytes.
2629    StagedRawBytes,
2630}
2631
2632///
2633/// SchemaDdlAdmissionError
2634///
2635/// Stable query-visible SQL DDL admission reason. Human diagnostics may carry
2636/// extra version, fingerprint, and target facts beside this machine-readable
2637/// variant.
2638///
2639
2640#[derive(Clone, Copy, Eq, PartialEq)]
2641pub enum SchemaDdlAdmissionError {
2642    MissingExpectedSchemaVersion,
2643
2644    MissingNextSchemaVersion,
2645
2646    StaleExpectedSchemaVersion,
2647
2648    InvalidExpectedSchemaVersion,
2649
2650    InvalidNextSchemaVersion,
2651
2652    AcceptedSchemaChangeWithoutVersionBump,
2653
2654    EmptyVersionBump,
2655
2656    VersionGap,
2657
2658    VersionRollback,
2659
2660    FingerprintMethodMismatch,
2661
2662    UnsupportedTransitionClass,
2663
2664    PhysicalRunnerMissing,
2665
2666    ValidationFailed,
2667
2668    PublicationRaceLost,
2669
2670    InvalidAddColumnDefault,
2671
2672    InvalidAlterColumnDefault,
2673
2674    RowLayoutVersionExhausted,
2675
2676    GeneratedIndexDropRejected,
2677
2678    SchemaRewriteRequiresMigration,
2679
2680    SchemaTransitionBudgetExceeded {
2681        resource: SchemaTransitionBudgetResource,
2682    },
2683
2684    GeneratedFieldDefaultChangeRejected,
2685
2686    GeneratedFieldNullabilityChangeRejected,
2687}
2688
2689impl fmt::Display for SchemaDdlAdmissionError {
2690    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2691        f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2692    }
2693}
2694
2695impl std::error::Error for SchemaDdlAdmissionError {}
2696
2697impl fmt::Debug for ErrorDetail {
2698    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2699        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2700    }
2701}
2702
2703impl fmt::Debug for ExecutorErrorDetail {
2704    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2705        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2706    }
2707}
2708
2709impl fmt::Debug for StoreError {
2710    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2711        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2712    }
2713}
2714
2715impl fmt::Debug for QueryErrorDetail {
2716    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2717        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2718    }
2719}
2720
2721impl fmt::Debug for RecoveryErrorDetail {
2722    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2723        fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2724    }
2725}
2726
2727impl fmt::Debug for RecoveryFormatMarkerError {
2728    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2729        fmt_compact_diagnostic(
2730            f,
2731            diagnostic_code::DiagnosticCode::RuntimeCorruption,
2732            Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2733                kind: diagnostic_code::RuntimeErrorKind::Corruption,
2734            }),
2735        )
2736    }
2737}
2738
2739impl fmt::Debug for SchemaDdlAdmissionError {
2740    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2741        fmt_compact_diagnostic(
2742            f,
2743            diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2744            Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2745                reason: self.diagnostic_code(),
2746            }),
2747        )
2748    }
2749}
2750
2751fn fmt_compact_diagnostic(
2752    f: &mut fmt::Formatter<'_>,
2753    code: diagnostic_code::DiagnosticCode,
2754    detail: Option<diagnostic_code::DiagnosticDetail>,
2755) -> fmt::Result {
2756    write!(
2757        f,
2758        "{}",
2759        diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2760    )
2761}
2762
2763impl ErrorDetail {
2764    /// Return the compact diagnostic code for this structured detail.
2765    #[must_use]
2766    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2767        match self {
2768            Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2769            Self::Executor(error) => error.diagnostic_code(),
2770            Self::Store(error) => error.diagnostic_code(),
2771            Self::Query(error) => error.diagnostic_code(),
2772            Self::Recovery(error) => error.diagnostic_code(),
2773        }
2774    }
2775
2776    /// Return compact structured diagnostic detail when the payload carries one.
2777    #[must_use]
2778    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2779        match self {
2780            Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2781            Self::Executor(error) => error.diagnostic_detail(),
2782            Self::Store(error) => error.diagnostic_detail(),
2783            Self::Query(error) => error.diagnostic_detail(),
2784            Self::Recovery(error) => error.diagnostic_detail(),
2785        }
2786    }
2787
2788    /// Project safe typed detail into canonical public numeric facts.
2789    #[must_use]
2790    #[cold]
2791    #[inline(never)]
2792    pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2793        match self {
2794            Self::DiagnosticFacts(detail) => detail.facts.clone(),
2795            Self::Executor(error) => error.diagnostic_facts(),
2796            Self::Query(error) => error.diagnostic_facts(),
2797            Self::Recovery(error) => error.diagnostic_facts(),
2798            Self::Store(_) => Vec::new(),
2799        }
2800    }
2801}
2802
2803impl ExecutorErrorDetail {
2804    /// Return the compact diagnostic code for this executor detail.
2805    #[must_use]
2806    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2807        match self {
2808            Self::MutationRequiredFieldMissing
2809            | Self::MutationDatabaseOwnedFieldExplicit
2810            | Self::MutationBatchEmpty
2811            | Self::MutationBatchTooManyItems
2812            | Self::MutationBatchTooManyEntities
2813            | Self::MutationBatchStagedBytesExceeded
2814            | Self::MutationBatchResultBytesExceeded => {
2815                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2816            }
2817            Self::MutationBatchStoreMismatch | Self::MutationBatchDuplicateKey => {
2818                diagnostic_code::DiagnosticCode::RuntimeConflict
2819            }
2820            Self::MutationManagedTimestampRegression => {
2821                diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2822            }
2823            Self::AcceptedRowConstraintProgramCorrupt => {
2824                diagnostic_code::DiagnosticCode::RuntimeCorruption
2825            }
2826        }
2827    }
2828
2829    /// Return compact structured diagnostic detail for this executor detail.
2830    #[must_use]
2831    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2832        match self {
2833            Self::MutationRequiredFieldMissing => {
2834                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2835                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2836                })
2837            }
2838            Self::MutationDatabaseOwnedFieldExplicit => {
2839                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2840                    boundary:
2841                        diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2842                })
2843            }
2844            Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2845                boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2846            }),
2847            Self::MutationBatchTooManyItems => {
2848                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2849                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2850                })
2851            }
2852            Self::MutationBatchStagedBytesExceeded => {
2853                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2854                    boundary:
2855                        diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2856                })
2857            }
2858            Self::MutationBatchResultBytesExceeded => {
2859                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2860                    boundary:
2861                        diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2862                })
2863            }
2864            Self::MutationBatchStoreMismatch => {
2865                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2866                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
2867                })
2868            }
2869            Self::MutationBatchTooManyEntities => {
2870                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2871                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
2872                })
2873            }
2874            Self::MutationBatchDuplicateKey => {
2875                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2876                    boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2877                })
2878            }
2879            Self::MutationManagedTimestampRegression => {
2880                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2881                    boundary:
2882                        diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2883                })
2884            }
2885            Self::AcceptedRowConstraintProgramCorrupt => {
2886                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2887                    boundary:
2888                        diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2889                })
2890            }
2891        }
2892    }
2893
2894    /// Project safe mutation detail into canonical public numeric facts.
2895    #[must_use]
2896    #[cold]
2897    #[inline(never)]
2898    pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2899        Vec::new()
2900    }
2901}
2902
2903impl RecoveryErrorDetail {
2904    /// Return the compact diagnostic code for this recovery detail.
2905    #[must_use]
2906    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2907        match self {
2908            Self::UnsupportedFormatVersion { .. } => {
2909                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2910            }
2911            Self::MalformedFormatMarker { .. } => {
2912                diagnostic_code::DiagnosticCode::RuntimeCorruption
2913            }
2914        }
2915    }
2916
2917    /// Return compact structured diagnostic detail for this recovery detail.
2918    #[must_use]
2919    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2920        let kind = match self {
2921            Self::UnsupportedFormatVersion { .. } => {
2922                diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2923            }
2924            Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2925        };
2926
2927        Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2928    }
2929
2930    /// Project database-format recovery context without retaining marker bytes.
2931    #[must_use]
2932    pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2933        match self {
2934            Self::UnsupportedFormatVersion { found, required } => {
2935                let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2936                facts.push((
2937                    diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2938                    u64::from(*required),
2939                ));
2940                if let Some(found) = found {
2941                    facts.push((
2942                        diagnostic_code::DiagnosticFactTag::ActualVersion,
2943                        u64::from(*found),
2944                    ));
2945                }
2946                facts
2947            }
2948            Self::MalformedFormatMarker { reason } => vec![(
2949                diagnostic_code::DiagnosticFactTag::DecodeReason,
2950                reason.diagnostic_decode_reason().raw(),
2951            )],
2952        }
2953    }
2954}
2955
2956impl StoreError {
2957    /// Return the compact diagnostic code for this store detail.
2958    #[must_use]
2959    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2960        match self {
2961            Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2962            Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2963            Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2964            Self::SchemaDdlPublicationRaceLost
2965            | Self::SchemaDdlRewriteRequiresMigration
2966            | Self::SchemaRowLayoutVersionExhausted
2967            | Self::SchemaTransitionBudgetExceeded { .. } => {
2968                diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2969            }
2970            Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2971                diagnostic_code::DiagnosticCode::RuntimeUnsupported
2972            }
2973            Self::SchemaGeneratedConstraintActivationStale => {
2974                diagnostic_code::DiagnosticCode::RuntimeConflict
2975            }
2976            Self::SchemaMigration { reason } => reason.diagnostic_code(),
2977        }
2978    }
2979
2980    /// Return compact structured diagnostic detail when the store error has one.
2981    #[must_use]
2982    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2983        match self {
2984            Self::SchemaDdlPublicationRaceLost => {
2985                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2986                    reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2987                })
2988            }
2989            Self::SchemaDdlRewriteRequiresMigration => {
2990                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2991                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2992                })
2993            }
2994            Self::SchemaMigration { reason } => {
2995                Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2996            }
2997            Self::SchemaRowLayoutVersionExhausted => {
2998                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2999                    reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
3000                })
3001            }
3002            Self::JournalMutationRevisionExhausted => {
3003                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
3004                    boundary:
3005                        diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
3006                })
3007            }
3008            Self::SchemaTransitionBudgetExceeded { .. } => {
3009                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
3010                    reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
3011                })
3012            }
3013            Self::SchemaGeneratedFieldAfterDdlField => {
3014                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
3015                    boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
3016                })
3017            }
3018            Self::SchemaGeneratedConstraintActivationStale => {
3019                Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
3020                    boundary:
3021                        diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
3022                })
3023            }
3024            Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
3025        }
3026    }
3027}
3028
3029impl QueryErrorDetail {
3030    /// Return the compact diagnostic code for this query detail.
3031    #[must_use]
3032    pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
3033        match self {
3034            Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
3035            Self::NumericNotRepresentable => {
3036                diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
3037            }
3038            Self::UnsupportedSqlFeature { .. } => {
3039                diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
3040            }
3041            Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
3042            Self::UnsupportedProjection { .. } => {
3043                diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
3044            }
3045            Self::UnknownAggregateTargetField => {
3046                diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
3047            }
3048            Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
3049            Self::SqlSurfaceMismatch { .. } => {
3050                diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
3051            }
3052            Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
3053            Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
3054            Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
3055        }
3056    }
3057
3058    /// Return compact structured diagnostic detail when the query detail has one.
3059    #[must_use]
3060    pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
3061        match self {
3062            Self::UnsupportedSqlFeature { feature } => {
3063                Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
3064            }
3065            Self::SqlLowering { reason } => {
3066                Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
3067            }
3068            Self::UnsupportedProjection { reason } => {
3069                Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
3070            }
3071            Self::QueryReadAdmission { reason } => {
3072                Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
3073            }
3074            Self::SqlSurfaceMismatch { mismatch } => {
3075                Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
3076                    mismatch: *mismatch,
3077                })
3078            }
3079            Self::SqlWriteBoundary { boundary } => {
3080                Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
3081                    boundary: *boundary,
3082                })
3083            }
3084            Self::SchemaDdlAdmission { error } => {
3085                Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
3086                    reason: error.diagnostic_code(),
3087                })
3088            }
3089            Self::NumericOverflow
3090            | Self::NumericNotRepresentable
3091            | Self::UnknownAggregateTargetField
3092            | Self::StaleSchemaRevision => None,
3093        }
3094    }
3095
3096    /// Project safe query detail into canonical public numeric facts.
3097    #[must_use]
3098    #[cold]
3099    #[inline(never)]
3100    pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
3101        Vec::new()
3102    }
3103}
3104
3105impl SchemaDdlAdmissionError {
3106    /// Return the compact diagnostic code for this SQL DDL admission reason.
3107    #[must_use]
3108    pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
3109        match self {
3110            Self::MissingExpectedSchemaVersion => {
3111                diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
3112            }
3113            Self::MissingNextSchemaVersion => {
3114                diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
3115            }
3116            Self::StaleExpectedSchemaVersion => {
3117                diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
3118            }
3119            Self::InvalidExpectedSchemaVersion => {
3120                diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
3121            }
3122            Self::InvalidNextSchemaVersion => {
3123                diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
3124            }
3125            Self::AcceptedSchemaChangeWithoutVersionBump => {
3126                diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
3127            }
3128            Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
3129            Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
3130            Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
3131            Self::FingerprintMethodMismatch => {
3132                diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
3133            }
3134            Self::UnsupportedTransitionClass => {
3135                diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
3136            }
3137            Self::PhysicalRunnerMissing => {
3138                diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
3139            }
3140            Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
3141            Self::PublicationRaceLost => {
3142                diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
3143            }
3144            Self::InvalidAddColumnDefault => {
3145                diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
3146            }
3147            Self::InvalidAlterColumnDefault => {
3148                diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
3149            }
3150            Self::GeneratedIndexDropRejected => {
3151                diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
3152            }
3153            Self::SchemaRewriteRequiresMigration => {
3154                diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
3155            }
3156            Self::SchemaTransitionBudgetExceeded { .. } => {
3157                diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
3158            }
3159            Self::GeneratedFieldDefaultChangeRejected => {
3160                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
3161            }
3162            Self::GeneratedFieldNullabilityChangeRejected => {
3163                diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
3164            }
3165            Self::RowLayoutVersionExhausted => {
3166                diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
3167            }
3168        }
3169    }
3170}
3171
3172///
3173/// ErrorClass
3174/// Internal error taxonomy for runtime classification.
3175/// Not a stable API; may change without notice.
3176///
3177
3178#[repr(u8)]
3179#[derive(Clone, Copy, Eq, PartialEq)]
3180pub enum ErrorClass {
3181    Corruption,
3182    IncompatiblePersistedFormat,
3183    NotFound,
3184    Internal,
3185    Conflict,
3186    Unsupported,
3187    InvariantViolation,
3188}
3189
3190impl ErrorClass {
3191    /// Return a compact diagnostic code for this broad class and origin pair.
3192    #[must_use]
3193    pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
3194        match self {
3195            Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
3196                diagnostic_code::DiagnosticCode::StoreCorruption
3197            }
3198            Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
3199            Self::IncompatiblePersistedFormat => {
3200                diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
3201            }
3202            Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
3203                diagnostic_code::DiagnosticCode::StoreNotFound
3204            }
3205            Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
3206            Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
3207            Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
3208            Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
3209                diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
3210            }
3211            Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
3212            Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
3213                diagnostic_code::DiagnosticCode::StoreInvariantViolation
3214            }
3215            Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3216        }
3217    }
3218}
3219
3220impl fmt::Debug for ErrorClass {
3221    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3222        write!(f, "{}", *self as u8)
3223    }
3224}
3225
3226///
3227/// ErrorOrigin
3228/// Internal origin taxonomy for runtime classification.
3229/// Not a stable API; may change without notice.
3230///
3231
3232#[repr(u8)]
3233#[derive(Clone, Copy, Eq, PartialEq)]
3234pub enum ErrorOrigin {
3235    Serialize,
3236    Store,
3237    Index,
3238    Identity,
3239    Query,
3240    Planner,
3241    Cursor,
3242    Recovery,
3243    Response,
3244    Executor,
3245    Interface,
3246}
3247
3248impl ErrorOrigin {
3249    /// Return the compact diagnostic origin for this internal origin.
3250    #[must_use]
3251    pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3252        match self {
3253            Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3254            Self::Store => diagnostic_code::ErrorOrigin::Store,
3255            Self::Index => diagnostic_code::ErrorOrigin::Index,
3256            Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3257            Self::Query => diagnostic_code::ErrorOrigin::Query,
3258            Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3259            Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3260            Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3261            Self::Response => diagnostic_code::ErrorOrigin::Response,
3262            Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3263            Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3264        }
3265    }
3266}
3267
3268impl fmt::Debug for ErrorOrigin {
3269    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3270        write!(f, "{}", *self as u8)
3271    }
3272}