-- 编排器/规划器：per-requirement run 聚合根，驱动 6 阶段状态机。每个 step 由
-- jobs (orchestrator.step) 驱动，可在重启后恢复。owner_id 是"特权但真实"的身份，
-- 用于创建所有子 session（不放松 checkNotSystemToken）。
--
-- phase CHECK 复用 requirements 的六阶段集合（planning/prototyping/auditing/
-- implementing/reviewing/done），与 internal/project Phase 枚举一致。

CREATE TABLE orchestrator_runs (
  id             UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  project_id     UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
  requirement_id UUID NOT NULL REFERENCES requirements(id) ON DELETE CASCADE,
  workspace_id   UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
  owner_id       UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
  status         TEXT NOT NULL,
  current_phase  TEXT NOT NULL,
  config         JSONB NOT NULL DEFAULT '{}',
  last_error     TEXT,
  created_at     TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at     TIMESTAMPTZ NOT NULL DEFAULT now(),
  ended_at       TIMESTAMPTZ,
  CONSTRAINT orchestrator_runs_status_check
    CHECK (status IN ('pending','running','paused','succeeded','failed','canceled')),
  CONSTRAINT orchestrator_runs_phase_check
    CHECK (current_phase IN ('planning','prototyping','auditing','implementing','reviewing','done'))
);

-- 每个 requirement 同一时间只允许一个活跃 run。
CREATE UNIQUE INDEX uq_orch_runs_active_requirement
  ON orchestrator_runs(requirement_id)
  WHERE status IN ('pending','running','paused');

CREATE INDEX idx_orch_runs_status ON orchestrator_runs(status);

CREATE TABLE orchestrator_steps (
  id             UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  run_id         UUID NOT NULL REFERENCES orchestrator_runs(id) ON DELETE CASCADE,
  phase          TEXT NOT NULL,
  attempt        INT NOT NULL DEFAULT 1,
  parent_step_id UUID REFERENCES orchestrator_steps(id) ON DELETE SET NULL,
  depth          INT NOT NULL DEFAULT 0,
  status         TEXT NOT NULL,
  agent_kind_id  UUID NOT NULL REFERENCES acp_agent_kinds(id) ON DELETE RESTRICT,
  acp_session_id UUID REFERENCES acp_sessions(id) ON DELETE SET NULL,
  prompt         TEXT NOT NULL,
  stop_reason    TEXT,
  gate_result    JSONB,
  last_error     TEXT,
  job_id         UUID,
  created_at     TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at     TIMESTAMPTZ NOT NULL DEFAULT now(),
  ended_at       TIMESTAMPTZ,
  CONSTRAINT orchestrator_steps_status_check
    CHECK (status IN ('pending','spawning','running','awaiting_gate','succeeded','failed','dead')),
  CONSTRAINT orchestrator_steps_phase_check
    CHECK (phase IN ('planning','prototyping','auditing','implementing','reviewing','done'))
);

CREATE INDEX idx_orch_steps_run ON orchestrator_steps(run_id, created_at);
CREATE INDEX idx_orch_steps_session ON orchestrator_steps(acp_session_id)
  WHERE acp_session_id IS NOT NULL;
CREATE INDEX idx_orch_steps_active ON orchestrator_steps(status)
  WHERE status IN ('spawning','running','awaiting_gate');
CREATE INDEX idx_orch_steps_parent ON orchestrator_steps(parent_step_id)
  WHERE parent_step_id IS NOT NULL;

-- 反向链接：让 ACP supervisor 的 onExit / 启动 reaper 能把崩溃 session 映射回 step。
-- manual session 留 NULL。
ALTER TABLE acp_sessions
  ADD COLUMN orchestrator_step_id UUID REFERENCES orchestrator_steps(id) ON DELETE SET NULL;

CREATE INDEX idx_acp_sessions_orch_step ON acp_sessions(orchestrator_step_id)
  WHERE orchestrator_step_id IS NOT NULL;
