// World lifecycle phases — the canonical FSM every Olam world walks
// through from spawn to terminal state.
//
// Order is load-bearing: a world's `lastPhase` is a monotonic high-water
// mark, and the classifier's precedence rules in classify.mjs assume
// this ordering when deciding which failure bucket to attribute a stall
// to. Do NOT reorder without updating the classifier.

/**
 * @typedef {'Spawning' | 'TrustRequired' | 'ReadyForPrompt' | 'Running' | 'Finished' | 'Failed'} WorldLifecyclePhase
 */

/**
 * @type {Readonly<Record<WorldLifecyclePhase, WorldLifecyclePhase>>}
 */
export const WorldLifecyclePhase = Object.freeze({
  /** Container or worktree created; before any code runs inside. */
  Spawning: 'Spawning',
  /** Agent process up; awaiting trust-gate approval. */
  TrustRequired: 'TrustRequired',
  /** Trust granted; awaiting initial dispatch. */
  ReadyForPrompt: 'ReadyForPrompt',
  /** Actively processing dispatch. */
  Running: 'Running',
  /** Completed successfully. Terminal. */
  Finished: 'Finished',
  /** Terminal failure. Carries an evidence bundle + classified failure kind. */
  Failed: 'Failed',
});

/** Phases in canonical order. Useful for ordinal comparison. */
export const WORLD_LIFECYCLE_PHASE_ORDER = Object.freeze([
  WorldLifecyclePhase.Spawning,
  WorldLifecyclePhase.TrustRequired,
  WorldLifecyclePhase.ReadyForPrompt,
  WorldLifecyclePhase.Running,
  WorldLifecyclePhase.Finished,
  WorldLifecyclePhase.Failed,
]);

/** Terminal phases — no transitions out. */
export const TERMINAL_PHASES = Object.freeze(
  new Set([WorldLifecyclePhase.Finished, WorldLifecyclePhase.Failed]),
);

/**
 * @param {unknown} value
 * @returns {value is WorldLifecyclePhase}
 */
export function isWorldLifecyclePhase(value) {
  return typeof value === 'string' && WORLD_LIFECYCLE_PHASE_ORDER.includes(/** @type {any} */ (value));
}
