export const STATES = ["RECEIVED", "PREFLIGHT", "ROUTED", "SCOUTING", "SWARMING", "DEEP_RUNNING", "WAR_ROOM", "IMPLEMENTING", "VERIFYING", "REPAIRING", "ESCALATING", "REVIEWING", "PRESENTING", "COMPLETED", "BLOCKED", "CANCELLED", "BUDGET_EXHAUSTED", "FAILED"] as const; export type ControllerState = (typeof STATES)[number]; const ALLOWED: Record = { RECEIVED: ["PREFLIGHT", "CANCELLED", "FAILED"], PREFLIGHT: ["ROUTED", "BLOCKED", "BUDGET_EXHAUSTED", "CANCELLED", "FAILED"], ROUTED: ["SCOUTING", "SWARMING", "DEEP_RUNNING", "WAR_ROOM", "IMPLEMENTING", "VERIFYING", "PRESENTING", "BLOCKED", "BUDGET_EXHAUSTED", "CANCELLED", "FAILED"], SCOUTING: ["IMPLEMENTING", "DEEP_RUNNING", "BLOCKED", "BUDGET_EXHAUSTED", "CANCELLED", "FAILED"], SWARMING: ["IMPLEMENTING", "DEEP_RUNNING", "VERIFYING", "BLOCKED", "BUDGET_EXHAUSTED", "CANCELLED", "FAILED"], DEEP_RUNNING: ["IMPLEMENTING", "VERIFYING", "BLOCKED", "BUDGET_EXHAUSTED", "CANCELLED", "FAILED"], WAR_ROOM: ["DEEP_RUNNING", "IMPLEMENTING", "VERIFYING", "BLOCKED", "BUDGET_EXHAUSTED", "CANCELLED", "FAILED"], IMPLEMENTING: ["VERIFYING", "BLOCKED", "BUDGET_EXHAUSTED", "FAILED", "CANCELLED"], VERIFYING: ["REPAIRING", "ESCALATING", "REVIEWING", "PRESENTING", "BLOCKED", "CANCELLED", "FAILED"], REPAIRING: ["DEEP_RUNNING", "ESCALATING", "BLOCKED", "BUDGET_EXHAUSTED", "CANCELLED", "FAILED"], ESCALATING: ["DEEP_RUNNING", "VERIFYING", "BLOCKED", "BUDGET_EXHAUSTED", "CANCELLED", "FAILED"], REVIEWING: ["VERIFYING", "PRESENTING", "REPAIRING", "BLOCKED", "BUDGET_EXHAUSTED", "CANCELLED", "FAILED"], PRESENTING: ["COMPLETED", "BLOCKED", "CANCELLED", "FAILED"], COMPLETED: [], BLOCKED: [], CANCELLED: [], BUDGET_EXHAUSTED: [], FAILED: [], }; export function transition(from: ControllerState, to: ControllerState): ControllerState { if (!ALLOWED[from].includes(to)) throw new Error(`Invalid UltraPi transition ${from} -> ${to}`); return to; } const TERMINAL_STATES = new Set(["COMPLETED", "BLOCKED", "CANCELLED", "BUDGET_EXHAUSTED", "FAILED"]); /** A run in one of these states is settled: nothing may transition out of it. */ export function isTerminal(state: ControllerState): boolean { return TERMINAL_STATES.has(state); }