wip: checkpoint before pod redeploy

This commit is contained in:
2026-08-19 17:05:31 +00:00
parent 495cbbe0fd
commit cce4efb7d0
+34 -18
View File
@@ -1,31 +1,47 @@
// =============================================================================
// Section: UpcastError enum + Display impl. Captures wire-format mismatch scenarios for read_record when on-disk schema form differs from CURRENT; missing adapter case (no V1→V2 path registered) surfaces here too. ErrorKind::UnknownSchemaVersion variant per spec — caller can match on specific variant to decide between error vs panic strategy without fabricating values in the upcasted wire shape during tests (preserves "byte shape identical" invariant).
// =============================================================================
use crate::{BlobRef, SchemaVersion};
//! UpcastError enum + Display impl for upcasting failures.
use crate::SchemaVersion;
use std::fmt;
/// Upcast error variants. Each reflects a distinct failure surface when read_record attempts to migrate from on-disk schema form toward CURRENT_SCHEMA — the three listed here are: unknown schema (no wire-format descriptor at all), missing migration adapter for known-but-unmapped version (chain has gaps), and serde Cbor round-trip failure mid-migration (wire-shape incompatible). Other variants would be Added but not yet used.
#[derive(Debug, Clone)]
/// Variant for missing adapter hop (between known but unmapped schema versions).
#[derive(Debug, Clone)]
pub struct MissingUpcaster { pub from: SchemaVersion, pub to: Option<SchemaVersion> }
// =============================================================================
// Section: UpcastError enum + Display impl. Captures wire-format mismatch scenarios. ErrorKind::UnknownSchemaVersion variant per spec — caller can match on specific variant for error vs panic strategy. The schema field tag in read_record helper uses current-schema form; chain walk invokes each adapter from ascending source order to reach CURRENT_SCHEMA target.
// =============================================================================
/// Upcast error variants. Each reflects a distinct failure surface when read_record attempts to migrate from on-disk schema form toward CURRENT_SCHEMA — the six listed here are: unknown schema (no wire-format descriptor at all), missing migration adapter for known-but-unmapped version (chain has gaps), serde Cbor round-trip failure mid-migration, unsupported future version, and reserved variants for extensions. The `from` field shows source on-disk form number; `to` is optional current-schema target when chain can determine what we'd reach. MissingUpcaster uses Option<SchemaVersion> semantics so the to value may remain unset (e.g., when next hop unknown during partial-chain walk).
#[derive(Debug, Clone)]
pub enum UpcastError {
/// On-disk schema form (SchemaVersion number) was never described by any adapter — the wire format doesn't exist in our registry. Per spec this is a fatal misconfiguration; we surface it as error so callers can react (vs panic on "no known V1→V2 path" which is more common at runtime).
UnknownSchemaVersion(SchemaVersion),
/// The record's schema was recognized (there exists some adapter entry for that source number) but no migration path forward to next form; i.e., chain has a gap. Per spec this should panic per assumption A2 since it indicates a registration error, but we choose ErrorKind::UnsupportedSchema here instead — callers can match and re-panic if they need loud behavior. The choice between Unsupported (error) vs Unknown (also error but distinct semantic) is intentional to let callers differentiate "no adapter at all" from "adapter exists with no next hops".
/// On-disk schema form (SchemaVersion number) was never described by any adapter — the wire format doesn't exist in our registry. Per spec this is a fatal misconfiguration; surfaced as error so callers can react versus panic on "no known V1→V2 path".
UnknownSchemaVersion(SchemaVersion),
/// No migration path from one schema to the next: chain has gap (adapter registered for source but not for target of intermediate step). Per A2 choice "panic at build time" — we surface as error so tests asserting identity preservation can detect missing registrations early instead of silently fabricating.
MissingAdapterBetween { from: SchemaVersion, to: SchemaVersion },
/// One of the adapter steps failed mid-migration due to serde round-trip not preserving byte shape or wire incompatibility — either input bytes weren't actually in expected source form OR the adapter returned malformed output. We surface this explicitly rather than panicking so test harness can verify invariant that folded byte shape MUST equal CURRENT-schema form per V-checklist item 2.
/// Intermediate migration step missing during walk (adapter exists for source but there's no registered adapter that consumes the next hop). Per spec "MissingUpcaster path open" — we surface this via dedicated variant with optional target so callers can determine why chain stopped. `to` is None when the walk was heading toward CURRENT_SCHEMA; Some(_) otherwise (intermediate target known but missing step reached before completion).
MissingUpcaster(MissingUpcaster),
/// One of the adapter steps failed mid-migration due to serde round-trip not preserving byte shape or wire incompatibility — input bytes weren't actually in expected source form OR the adapter returned malformed output. Surface this explicitly rather than panic so tests can verify invariant that folded byte shape MUST equal CURRENT-schema form per V-checklist item 2.
SerializationError(String),
/// Reserved for future wire-shape extensions — would be used when a new schema introduces fields incompatible with the current fold path. Currently unused in T0.4 only migration path (just v1→v2) so kept as explicit variant to avoid fabricating bytes in on-disk test assertions that check no-fabrication.
/// Reserved for future schema extensions — would be used when a new on-disk schema introduces fields incompatible with current fold path. Currently unused in T0.4 (only v1->v2 supported) so kept as explicit variant to avoid fabricating bytes during test assertions that check no-fabrication-on-current-schema path invariant.
SchemaVersionUnsupported { version: u32 },
}
impl fmt::Display for UpcastError {
fn fmt(\u0026self, f: \u0026mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnknownSchemaVersion(v) => write!(f, "on-disk schema version {} not described in any adapter", v),
Self::MissingAdapterBetween{from:a, to:b} => write!(f, "no migration path from schema {} → {}", a.0, b.0), // using tuple-struct access for field `to` since that's reserved Word in Rust
Self::UnknownSchemaVersion(v) => write!(f, "on-disk schema version {:?} not described in any adapter", v),
#[allow(clippy::explicit_auto_deref)] // clippy warns about `a.0` — use explicit deref with &self since we're inside Display impl where self is reference but want value-type argument for Debug formatting
Self::MissingAdapterBetween { from, to } => write!(f, "no migration path from schema {:?} -> {:?}", from, to), // using field-name access to bypass reserved Word issue (to is a method on Result)
Self::MissingUpcaster(u) => match &u.to {
None => write!(f, "missing upcast step starting at {:?} toward CURRENT_SCHEMA", u.from),
Some(target) => write!(f, "missing upcast step from {:?} to {:?}", u.from, target),
},
Self::SerializationError(msg) => write!(f, "serialization failure during upcast: {}", msg),
Self::SchemaVersionUnsupported { version } => write!(f, "schema version {} not supported by current fold", version),
}