Debugging Transitions
Problem
You need visibility into which guards pass or fail, when invokes start and abort, and a history of recent transitions to diagnose unexpected machine behaviour during development.
Solution
Pass debug options to interpret(). The onDebug callback receives a discriminated union of all debug events — pattern-match on type to handle specific cases.
ts
import { machine } from '@vielzeug/clockwork';
import { config } from './machine'; // your machine config object
const m = machine(config, {
debug: {
onDebug: (event) => {
switch (event.type) {
case 'guard':
console.debug(`[guard] ${event.from} → ${event.target}: ${event.passed ? 'pass' : 'fail'}`);
break;
case 'transition-skipped':
console.debug(`[skip] ${event.event.type} in ${event.from}`);
break;
case 'invoke-start':
console.debug(`[invoke #${event.invokeId}] started in ${event.state}`);
break;
case 'invoke-done':
console.debug(`[invoke #${event.invokeId}] done`, event.result);
break;
case 'invoke-error':
console.error(`[invoke #${event.invokeId}] error`, event.error);
break;
case 'invoke-abort':
console.debug(`[invoke #${event.invokeId}] aborted in ${event.state}`);
break;
}
},
onTransition: ({ event, from, to }) => console.info(`[transition] ${from} → ${to} via ${event.type}`),
traceLimit: 200,
},
});
// Read the trace ring buffer at any time
const trace = m.getTrace();
console.table(
trace.map(({ event, from, timestamp, to }) => ({
event: event.type,
from,
ms: timestamp,
to,
})),
);Pitfalls
can()does not fire debug events. Guard evaluation incan()is silent. Usecan()freely for UI-driven enablement without adding debug noise.- Auto-enabled tracing. When
onDebugoronTransitionis set, a 50-entry trace buffer is enabled automatically. SettraceLimit: 0to opt out explicitly. - Trace is a ring buffer. Once the ring is full, new entries overwrite the oldest. Set
traceLimitlarge enough to cover the transition sequences you need to inspect. getTrace()returns cloned entries. Mutating the returned array or entries does not affect the internal buffer.- Remove debug hooks in production.
debughooks add per-send()overhead. Either omit thedebugoption or gate it behindimport.meta.env.DEV.
Related
- Unit Testing with
resolveTransition()— Pure guard testing without a live machine - API Reference —
DebugEvent - API Reference —
MachineInstance