This guide starts with the 0.6 breaking change for 0.5.x users, then keeps
the earlier 0.5 migration notes for older code. If you are starting fresh on
0.6, you can skip this page and start with the README plus
tutorial-review-workflow.md.
- Remove any imports of
statum::bonorstatum::bon::builder. - If you still want bon in your application, depend on
bondirectly. - Keep using
Machine::<State>::builder(),into_machine(),.into_machines(), and.into_machines_by(...); those call shapes are unchanged. Machine::rebuild(&row)andMachine::rebuild_many(rows)are additive validator-side helpers if you want the machine type to own the entrypoint.- Treat generated builder internals as implementation details rather than stable public API.
Before:
use statum::bon;
use statum::bon::builder as _;After:
[dependencies]
bon = "3"Or just remove the import if you were only using Statum's generated builders.
0.6 keeps the builder-first workflow surface, but Statum now owns the builder
implementation instead of re-exporting bon. The supported entry points stay the
same:
Machine::<State>::builder()row.into_machine()rows.into_machines()rows.into_machines_by(...)
The intentional break is the bon re-export and any bon-specific generated builder internals, not the normal Statum call patterns.
- Add
#[transition]to transition impl blocks. - Switch validators to
#[validators(Machine)]. - Rename rebuild entrypoints to
into_machine(),.into_machines(), and.into_machines_by(...). - Match rebuilt output on
machine::SomeState. - Move code that relied on legacy generated helper traits to the crate-level advanced traits or to direct machine methods.
Before:
impl Machine<Draft> {
fn submit(self) -> Machine<InReview> {
self.transition()
}
}After:
#[transition]
impl Machine<Draft> {
fn submit(self) -> Machine<InReview> {
self.transition()
}
}Before:
#[validators(state = TaskState, machine = TaskMachine)]
impl StoredTask {
fn is_draft(&self) -> Result<()> { /* ... */ }
}After:
#[validators(TaskMachine)]
impl StoredTask {
fn is_draft(&self) -> statum::Result<()> { /* ... */ }
}Statum resolves the state family from the machine definition.
- You need one
is_{state}method per state variant. - Validator methods must take exactly
&self. - Unit states return
statum::Result<()>orstatum::Validation<()>. - Data-bearing states return
statum::Result<StateData>orstatum::Validation<StateData>. - If any validator is
async, the generated builders becomeasync.
Use these names in 0.5 and later:
into_machine()for one item.into_machines()when machine fields are shared across the collection.into_machines_by(|row| machine::Fields { ... })when machine fields vary per itemmachine::SomeStatewhen matching rebuilt outputmachine::Stateis still available as a compatibility alias during migration
Removed names:
machine_builder()machines_builder()TaskMachineSuperState
Cross-module batch rebuilds still need the machine-scoped trait import:
use task_machine::IntoMachinesExt as _;The old public generated helper traits, such as TaskMachineTransitionTo or
StateVariant, are no longer the supported API.
Use:
- direct machine methods
statum::StateMarkerstatum::UnitStatestatum::DataStatestatum::CanTransitionTo<Next>statum::CanTransitionWith<Data>statum::CanTransitionMap<Next>
- Must be an enum
- Must have at least one variant
- Variants must be unit, single-field tuple, or named-field variants
- State enum generics are rejected
- Must be a struct
- The first generic parameter must match the
#[state]enum name - Additional type and const generics are supported after the state generic
- Extra machine lifetime generics are still effectively unavailable because Rust requires lifetimes before type parameters, and Statum reserves the first generic slot for the state family
- Matching derives on the
#[state]enum and machine are required when needed #[machine]should sit above#[derive(...)]
Use the generated per-state builders:
let draft = Machine::<Draft>::builder()
.field_a(...)
.build();
let review = Machine::<InReview>::builder()
.field_a(...)
.state_data(ReviewData { ... })
.build();Use Machine::rebuild(&row) and Machine::rebuild_many(rows) as additive
entrypoints at the validator boundary when you want the machine type to own the
rebuild call shape. row.into_machine() and .into_machines() still work.
0.5 and later also add surface area you may want during migration:
.into_machines_by(...)for heterogeneous batch machine contextMachine::rebuild(&row)andMachine::rebuild_many(rows)for type-first validator entrypointsstatum::Validation<T>,.build_report(), and.build_reports()when rebuild traces need stable reason keys or messagesstatum::projection::{ProjectionReducer, reduce_one, reduce_grouped}for event-log projection before rehydrationtransition_map(...)for data-to-data transitions that should consume the current state payload
- Old
statum/examples/*.rsexamples are gone. - Toy demos now live under
statum-examples/src/toy_demos/. - Service-shaped and protocol-shaped showcases live under
statum-examples/src/showcases/.
- Update the
#[state]enum to match the current variant rules. - Update the machine generic and derive placement.
- Add
#[transition]to protocol-edge impl blocks. - Rename validators and rehydration entrypoints.
- Update match sites to use
machine::SomeState. - Move any generic helper code off removed legacy traits.
- Re-run
cargo test -p statum-macrosand your workspace tests.