//// Replay assertions for `aion/testing`.
////
//// The helper runs a workflow twice in the same process-scoped harness, compares
//// the captured observation sequences, and reports mismatches as typed data. This
//// is a test-time simulation of AD's non-determinism detection: production replay
//// remains the responsibility of AD, but workflow authors can catch accidental
//// unrecorded branching in ordinary `gleam test` suites.
import aion/error
import aion/internal/ffi
/// A replay assertion failure.
pub type ReplayError(workflow_error) {
/// The workflow returned an error during either the first run or replay.
WorkflowFailed(workflow_error)
/// The two runs completed but emitted different observable command sequences.
ObservationMismatch(recorded: String, replayed: String)
/// The test harness itself failed while capturing or resetting observations.
ReplayHarnessFailure(error.EngineError)
}
/// Run a workflow twice and require identical observations.
pub fn assert_replay(
_env: env,
workflow: fn() -> Result(value, workflow_error),
) -> Result(value, ReplayError(workflow_error)) {
case clear() {
Error(harness_error) -> Error(harness_error)
Ok(_) ->
case workflow() {
Error(workflow_error) -> Error(WorkflowFailed(workflow_error))
Ok(value) ->
case capture() {
Error(harness_error) -> Error(harness_error)
Ok(recorded) -> compare_replay(value, recorded, workflow)
}
}
}
}
fn compare_replay(
value: value,
recorded: String,
workflow: fn() -> Result(value, workflow_error),
) -> Result(value, ReplayError(workflow_error)) {
case clear() {
Error(harness_error) -> Error(harness_error)
Ok(_) ->
case workflow() {
Error(workflow_error) -> Error(WorkflowFailed(workflow_error))
Ok(_) ->
case capture() {
Error(harness_error) -> Error(harness_error)
Ok(replayed) ->
case recorded == replayed {
True -> Ok(value)
False ->
Error(ObservationMismatch(
recorded: recorded,
replayed: replayed,
))
}
}
}
}
}
fn clear() -> Result(Nil, ReplayError(workflow_error)) {
case ffi.testing_clear_observations() {
Ok(_) -> Ok(Nil)
Error(raw_error) ->
Error(ReplayHarnessFailure(error.EngineFailure(raw_error)))
}
}
fn capture() -> Result(String, ReplayError(workflow_error)) {
case ffi.testing_observations() {
Ok(observations) -> Ok(observations)
Error(raw_error) ->
Error(ReplayHarnessFailure(error.EngineFailure(raw_error)))
}
}