import { TaskStatus } from './task-state.js'; /** * Legal state transitions for the 10-state task FSM. * * Terminal states (COMPLETED, FAILED, CANCELLED, TIMED_OUT, UNKNOWN) are * absorbing โ€” they have no outgoing transitions. * * UNKNOWN is reachable from every non-terminal state as a crash-recovery * fallback. * * Spec reference: ยง4.1 */ export const VALID_TRANSITIONS: Record> = { [TaskStatus.WAITING]: new Set([ TaskStatus.PENDING, TaskStatus.CANCELLED, TaskStatus.FAILED, TaskStatus.TIMED_OUT, TaskStatus.UNKNOWN, ]), [TaskStatus.PENDING]: new Set([ TaskStatus.RUNNING, TaskStatus.WAITING, TaskStatus.COMPLETED, TaskStatus.CANCELLED, TaskStatus.FAILED, TaskStatus.TIMED_OUT, TaskStatus.UNKNOWN, ]), [TaskStatus.RUNNING]: new Set([ TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.CANCELLED, TaskStatus.TIMED_OUT, TaskStatus.RATE_LIMITED, TaskStatus.WAITING_ANSWER, TaskStatus.UNKNOWN, ]), [TaskStatus.RATE_LIMITED]: new Set([ TaskStatus.RUNNING, TaskStatus.FAILED, TaskStatus.CANCELLED, TaskStatus.TIMED_OUT, TaskStatus.UNKNOWN, ]), [TaskStatus.WAITING_ANSWER]: new Set([ TaskStatus.RUNNING, TaskStatus.FAILED, TaskStatus.CANCELLED, TaskStatus.TIMED_OUT, TaskStatus.UNKNOWN, ]), // Terminal states โ€” no outgoing transitions [TaskStatus.COMPLETED]: new Set(), [TaskStatus.FAILED]: new Set(), [TaskStatus.CANCELLED]: new Set(), [TaskStatus.TIMED_OUT]: new Set(), [TaskStatus.UNKNOWN]: new Set(), }; /** * Returns whether `from โ†’ to` is a legal FSM transition. */ export function isValidTransition(from: TaskStatus, to: TaskStatus): boolean { return VALID_TRANSITIONS[from].has(to); }