When changing a versioned VBARE schema, follow the existing migration pattern.
-
Never edit an existing published
*.bareschema in place. Add a new versioned schema instead. -
Update the matching
versioned.rslike this:- If the bytes did not change, deserialize both versions into the new wrapper variant:
6 | 7 => Ok(ToClientMk2::V7(serde_bare::from_slice(payload)?))
-
If the bytes did change, write the conversion field by field.
-
Do not do this:
let bytes = serde_bare::to_vec(&x)?; serde_bare::from_slice(&bytes)?
-
Verify the affected Rust crate still builds.
-
For the runner protocol specifically:
- Bump both protocol constants together:
engine/packages/runner-protocol/src/lib.rsPROTOCOL_MK2_VERSIONrivetkit-typescript/packages/engine-runner/src/mod.tsPROTOCOL_VERSION
- Update the Rust latest re-export in
engine/packages/runner-protocol/src/lib.rsto the new generated module.
- Bump both protocol constants together:
- All epoxy durable state lives under per-replica subspaces (
keys::subspace(replica_id)for v2,keys::legacy_subspace(replica_id)for read-only legacy data). Shared key types (KvValueKey,KvBallotKey, etc.) live inengine/packages/epoxy/src/keys/keys.rsand new tuple segment constants go inengine/packages/universaldb/src/utils/keys.rs. - When adding fields to epoxy workflow state structs, mark them
#[serde(default)]so Gasoline can replay older serialized state. - Epoxy integration tests that spin up
tests/common::TestCtxmust callshutdown()before returning.
Use test-snapshot-gen to generate and load RocksDB snapshots of the full UDB KV store for migration and integration tests. Scenarios produce per-replica RocksDB checkpoints stored under engine/packages/test-snapshot-gen/snapshots/ (git LFS tracked). In tests, use test_snapshot::SnapshotTestCtx::from_snapshot("scenario-name") to boot a cluster from snapshot data. See docs-internal/engine/TEST_SNAPSHOTS.md for the full guide.