Hechos, no mutaciones
El estado significativo comienza como un evento tipado. Un fold proyecta esos hechos hacia el estado requerido por la interfaz. Reproducir la misma historia aceptada debe producir el mismo estado y salida.
#[derive(Clone)]
enum TaskEvent {
Created { id: u64, title: String },
Completed { id: u64 },
}
fn reduce(state: &mut Tasks, event: &TaskEvent) {
match event {
TaskEvent::Created { id, title } => state.insert(*id, title),
TaskEvent::Completed { id } => state.complete(*id),
}
}Modos operativos progresivos
- 01
Sólo estático
No se requiere historia de eventos. Crea contenido completo y salida determinista.
- 02
Historia local
Añade eventos localmente y prueba la paridad de proyección live-versus-replay.
- 03
Outbox durable
Registra comandos y efectos pendientes antes de transporte o retry.
- 04
Sync verificado
Acepta historia remota sólo mediante recibos tipados, contiguos y verificados.
Paridad de replay
Cada starter event-native debe probar tres rutas: append live, restore desde snapshot más tail y replay desde genesis. Sus bytes canónicos de proyección deben coincidir.
assert_eq!(live_state, replay(&events));
assert_eq!(live_state, restore(snapshot, &tail));Los efectos se convierten en evidencia
Los reducers no llaman relojes, random, redes, filesystems o modelos. Emiten un comando; un effect runner realiza el trabajo externo; el resultado observado vuelve como evento o recibo.