gen_statem state machine correctness analysis.
Detects structural state machine bugs: unreachable states and terminal
states that never stop. Both rules reason over the extracted transition
graph and are scoped to state_functions mode; in
handle_event_function mode there is a single callback and states are
data values, so a per-state graph cannot be built. A state is a state
only if it is an exported arity-3 function that returns a gen_statem
action, and the entry point is read from init/1 rather than guessed
topologically.
Output relations
unreachable_state(mod, state, site)— state defined but no transition leads to it.terminal_without_stop(mod, state, site)— state with no outgoing transitions that doesn't stop.state_missing_info_catchall(mod, state, site)— a state function without an:infocatch-all clause beside sibling states that have one.statem_timeout_unhandled(mod, kind, state)— a:timeoutor:state_timeoutaction is armed and no clause handles that event type.
Finding severities
unreachable_state—:warning. Dead state code is either an unused leftover or a missing transition; both are design bugs in the machine.terminal_without_stop—:info. A final resting state can be intentional; flagged because an unintentional one leaks an idle process.state_missing_info_catchall—:warning. The module handles stray messages in its other states; in this one they are a crash.statem_timeout_unhandled—:error. The timer fires into a FunctionClauseError or falls through to a clause written for something else; either way the timeout's work never runs.