import { readFile } from "node:fs/promises";
import { basename, isAbsolute, join } from "node:path";

import {
  findReportForTaskOnDisk,
  findReportPathForTaskOnDisk,
} from "../_internal/report-reconcile.ts";
import { parseMarkdownFrontmatter } from "../ledger/frontmatter.ts";
import type { LedgerReportRecord, LedgerTaskRecord } from "../ledger/types.ts";
import type { AgentRegistry } from "../registry/AgentRegistry.ts";
import type {
  DispatchAttempt,
  ExecutionLease,
} from "../scheduler/DispatchAttemptStore.ts";
import type { DispatchTaskStateView } from "../scheduler/TaskDispatcher.ts";
import type { SessionManager } from "../session/SessionManager.ts";
import type { SessionStore } from "../session/SessionStore.ts";
import type { AgentRecord, SessionRecord } from "../types/state.ts";
import { resolveTaskCurrentBucket } from "./taskCurrentBucket.ts";
import {
  resolveWorkerReceiptDurableHints,
  type WorkerReceiptDurableHints,
} from "./workerReceiptDurableHints.ts";

export type CanonicalTaskRuntimeState =
  | "running"
  | "waiting_capacity"
  | "settling"
  | "waiting_report"
  | "recoverable"
  | "failed"
  | "blocked"
  | "done"
  | "projection_conflict";

export type CanonicalTaskRuntimeSuggestedAction =
  | "wait"
  | "recover"
  | "review_report"
  | "inspect_conflict"
  | "none";

export interface CanonicalTaskRuntimeEvidence {
  source:
    | "formal_report"
    | "live_session"
    | "active_lease"
    | "dispatch_attempt"
    | "durable_event"
    | "registry"
    | "lifecycle";
  code: string;
  observed_at?: string;
  session_id?: string;
  run_id?: string;
  attempt_id?: string;
  lease_id?: string;
  report_id?: string;
  agent_id?: string;
  role?: string;
  task_id?: string;
  detail?: string;
}

export interface CanonicalTaskRuntimeConflict {
  code: string;
  sources: CanonicalTaskRuntimeEvidence["source"][];
  detail: string;
}

export interface CanonicalTaskRuntimeSnapshot {
  state: CanonicalTaskRuntimeState;
  phase: string;
  queue_state: CanonicalTaskRuntimeState;
  task_id: string;
  role: string | null;
  agent_id: string | null;
  session_id: string | null;
  run_id: string | null;
  attempt_id: string | null;
  lease_id: string | null;
  report_id: string | null;
  report_status: string | null;
  has_live_task_session: boolean;
  has_valid_active_lease: boolean;
  has_formal_report: boolean;
  reason_code: string;
  summary: string;
  suggested_action: CanonicalTaskRuntimeSuggestedAction;
  observed_at: string;
  startup_grace_ms: number;
  evidence: CanonicalTaskRuntimeEvidence[];
  conflicts: CanonicalTaskRuntimeConflict[];
  history: {
    last_session_id: string | null;
    last_started_at: string | null;
    last_ended_at: string | null;
    last_session_status: string | null;
    last_failure_code: string | null;
    last_failure_category: string | null;
    is_first_turn_abort: boolean;
    session_unsettled: boolean;
    historical_failure_recoverable: boolean;
  };
  /** REPORT is technical evidence only; PM/ADMIN still owns business acceptance. */
  business_decision: null;
}

export interface CanonicalFormalReport {
  report_id?: string;
  filename?: string;
  task_id?: string;
  status?: string;
  sender?: string;
  valid?: boolean;
  created_at?: string;
  updated_at?: string;
  session_id?: string;
  run_id?: string;
  attempt_id?: string;
  lease_id?: string;
  agent_id?: string;
  role?: string;
}

export interface CanonicalRegistryProjection {
  agent_id: string;
  role?: string;
  status?: string;
  last_active_at?: string;
}

export interface ResolveCanonicalTaskRuntimeStateInput {
  taskId: string;
  role?: string | null;
  agentId?: string | null;
  lifecycleBucket?: string | null;
  formalReport?: CanonicalFormalReport | null;
  liveSessions?: SessionRecord[];
  allSessions?: SessionRecord[];
  attempts?: DispatchAttempt[];
  activeLease?: ExecutionLease | null;
  durable?: WorkerReceiptDurableHints | null;
  registry?: CanonicalRegistryProjection[];
  now?: Date;
  startupGraceMs?: number;
}

export interface BuildCanonicalTaskRuntimeSnapshotInput {
  projectRoot: string;
  taskId: string;
  role?: string | null;
  agentId?: string | null;
  tasks?: LedgerTaskRecord[];
  reports?: LedgerReportRecord[];
  registry?: AgentRegistry;
  sessionManager: Pick<SessionManager, "listActive"> &
    Partial<Pick<SessionManager, "listLive">>;
  sessionStore?: Pick<SessionStore, "listAll">;
  dispatcher?: {
    getDispatchTaskState(taskId: string): Promise<DispatchTaskStateView>;
  };
  durable?: WorkerReceiptDurableHints;
  now?: Date;
  startupGraceMs?: number;
}

const PASS_REPORT = new Set(["done", "completed", "pass", "passed"]);
const FAILED_REPORT = new Set(["failed", "fail", "cancelled", "force_archived"]);
const BLOCKED_REPORT = new Set(["blocked"]);
const TERMINAL_SESSION = new Set(["completed", "done", "failed", "timeout", "cancelled", "aborted"]);
const RECOVERABLE_ATTEMPT = new Set(["expired", "stale", "session_failed"]);
const FAILED_ATTEMPT = new Set(["rejected"]);
const SETTLED_ATTEMPT = new Set(["reported", "settled"]);

function normalizeTaskId(value: string | null | undefined): string {
  const raw = String(value ?? "").replace(/\.md$/i, "").trim();
  return /^TASK-\d{8}-\d{3,}/i.exec(raw)?.[0]?.toUpperCase() ?? raw.toUpperCase();
}

function normalizeRole(value: string | null | undefined): string | null {
  const role = String(value ?? "").trim().toUpperCase();
  return role || null;
}

function sessionId(session: SessionRecord | undefined): string | null {
  return String(session?.protocol.session_id ?? session?.session_id ?? "").trim() || null;
}

function sessionAgentId(session: SessionRecord | undefined): string | null {
  return String(session?.protocol.agent_id ?? session?.agent_id ?? "").trim() || null;
}

function sessionTaskId(session: SessionRecord | undefined): string {
  return normalizeTaskId(String(session?.protocol.task_id ?? ""));
}

function sessionRole(session: SessionRecord | undefined): string | null {
  return normalizeRole(session?.runtime_role);
}

function sessionRunId(session: SessionRecord | undefined): string | null {
  return String(
    session?.runtime_active_run_id ??
      session?.protocol.runs?.at(-1)?.run_id ??
      "",
  ).trim() || null;
}

function sessionAt(session: SessionRecord | undefined): string | undefined {
  return String(
    session?.runtime_last_event_at ??
      session?.protocol.ended_at ??
      session?.protocol.started_at ??
      "",
  ).trim() || undefined;
}

function sessionKind(session: SessionRecord): string {
  return String(session.runtime_session_kind ?? "TASK_BOUND").toUpperCase();
}

function timestamp(value: string | null | undefined): number {
  const parsed = Date.parse(String(value ?? ""));
  return Number.isFinite(parsed) ? parsed : 0;
}

function latestBy<T>(values: T[], pick: (value: T) => string | undefined): T | undefined {
  return [...values].sort((a, b) => timestamp(pick(b)) - timestamp(pick(a)))[0];
}

function reportOutcome(report: CanonicalFormalReport | null | undefined):
  | "pass"
  | "failed"
  | "blocked"
  | "nonterminal"
  | null {
  if (!report || report.valid === false) return null;
  const status = String(report.status ?? "").trim().toLowerCase();
  if (PASS_REPORT.has(status)) return "pass";
  if (BLOCKED_REPORT.has(status)) return "blocked";
  if (FAILED_REPORT.has(status)) return "failed";
  return status ? "nonterminal" : null;
}

function phaseFor(state: CanonicalTaskRuntimeState): string {
  switch (state) {
    case "running": return "session_running";
    case "waiting_capacity": return "waiting_capacity";
    case "settling": return "dispatch_settling";
    case "waiting_report": return "waiting_worker_receipt";
    case "recoverable": return "session_recoverable";
    case "failed": return "worker_receipt_failed";
    case "blocked": return "worker_report_needs_pm";
    case "done": return "cleared";
    case "projection_conflict": return "projection_conflict";
  }
}

function actionFor(state: CanonicalTaskRuntimeState): CanonicalTaskRuntimeSuggestedAction {
  switch (state) {
    case "running":
    case "waiting_capacity":
    case "settling":
    case "waiting_report":
      return "wait";
    case "recoverable":
      return "recover";
    case "failed":
    case "blocked":
    case "done":
      return "review_report";
    case "projection_conflict":
      return "inspect_conflict";
  }
}

function makeSnapshot(
  input: ResolveCanonicalTaskRuntimeStateInput,
  state: CanonicalTaskRuntimeState,
  reasonCode: string,
  summary: string,
  evidence: CanonicalTaskRuntimeEvidence[],
  conflicts: CanonicalTaskRuntimeConflict[],
  binding: {
    role: string | null;
    agentId: string | null;
    session?: SessionRecord;
    attempt?: DispatchAttempt;
    lease?: ExecutionLease | null;
    report?: CanonicalFormalReport | null;
  },
): CanonicalTaskRuntimeSnapshot {
  const report = binding.report ?? null;
  return {
    state,
    phase: phaseFor(state),
    queue_state: state,
    task_id: normalizeTaskId(input.taskId),
    role: binding.role,
    agent_id: sessionAgentId(binding.session) ?? binding.lease?.agent_id ?? binding.agentId,
    session_id: sessionId(binding.session) ?? binding.lease?.session_id ?? null,
    run_id: sessionRunId(binding.session),
    attempt_id:
      binding.session?.runtime_attempt_id ??
      binding.lease?.attempt_id ??
      binding.attempt?.attempt_id ??
      null,
    lease_id: binding.session?.runtime_lease_id ?? binding.lease?.lease_id ?? null,
    report_id: String(report?.report_id ?? report?.filename ?? "").replace(/\.md$/i, "").trim() || null,
    report_status: String(report?.status ?? "").trim().toLowerCase() || null,
    has_live_task_session:
      binding.session?.protocol.status === "running" &&
      sessionKind(binding.session) === "TASK_BOUND",
    has_valid_active_lease: Boolean(binding.lease),
    has_formal_report: Boolean(report),
    reason_code: reasonCode,
    summary,
    suggested_action: actionFor(state),
    observed_at: (input.now ?? new Date()).toISOString(),
    startup_grace_ms: input.startupGraceMs ?? 30_000,
    evidence,
    conflicts,
    history: {
      last_session_id: input.durable?.lastSessionId ?? null,
      last_started_at: input.durable?.summary.lastStartedAt ?? null,
      last_ended_at: input.durable?.summary.lastEndedAt ?? null,
      last_session_status: input.durable?.lastSessionStatus ?? null,
      last_failure_code: input.durable?.lastFailureCode ?? null,
      last_failure_category: input.durable?.lastFailureCategory ?? null,
      is_first_turn_abort: input.durable?.isFirstTurnAbort === true,
      session_unsettled: input.durable?.sessionUnsettled === true,
      historical_failure_recoverable:
        input.durable?.historicalFailureRecoverable === true,
    },
    business_decision: null,
  };
}

/**
 * Deterministic, side-effect-free runtime-state resolver.
 *
 * Source priority is fixed: formal REPORT → live TASK_BOUND Session → valid
 * lease → same-Agent FIFO work → terminal execution → durable history →
 * registry/lifecycle projection. Conflicting authoritative sources stop at
 * `projection_conflict`; no recovery decision is made from registry or an
 * unsettled durable event alone.
 */
export function resolveCanonicalTaskRuntimeState(
  input: ResolveCanonicalTaskRuntimeStateInput,
): CanonicalTaskRuntimeSnapshot {
  const now = input.now ?? new Date();
  const nowMs = now.getTime();
  const startupGraceMs = Math.max(0, input.startupGraceMs ?? 30_000);
  const taskId = normalizeTaskId(input.taskId);
  const role = normalizeRole(input.role);
  const evidence: CanonicalTaskRuntimeEvidence[] = [];
  const conflicts: CanonicalTaskRuntimeConflict[] = [];

  const allLive = input.liveSessions ?? [];
  const sameTaskLiveRaw = allLive.filter((session) => sessionTaskId(session) === taskId);
  const taskSessions = sameTaskLiveRaw.filter((session) => sessionKind(session) === "TASK_BOUND");
  const taskSession = latestBy(taskSessions, sessionAt);
  const formalReport = input.formalReport?.valid === false ? null : input.formalReport ?? null;
  const outcome = reportOutcome(formalReport);
  const activeLease = input.activeLease &&
    !input.activeLease.released_at &&
    timestamp(input.activeLease.expires_at) > nowMs
      ? input.activeLease
      : null;
  const attempts = [...(input.attempts ?? [])].sort(
    (a, b) => timestamp(b.updated_at) - timestamp(a.updated_at),
  );
  const latestAttempt = attempts[0];
  const allTaskSessions = (input.allSessions ?? allLive).filter(
    (session) =>
      sessionTaskId(session) === taskId && sessionKind(session) === "TASK_BOUND",
  );
  const latestSession = latestBy(allTaskSessions, sessionAt);
  const resolvedAgentId =
    sessionAgentId(taskSession) ??
    activeLease?.agent_id ??
    (String(input.agentId ?? "").trim() || null);
  const resolvedRole = sessionRole(taskSession) ?? role;

  if (formalReport) {
    evidence.push({
      source: "formal_report",
      code: outcome ? `formal_report_${outcome}` : "formal_report_present",
      observed_at: formalReport.updated_at ?? formalReport.created_at,
      report_id: String(formalReport.report_id ?? formalReport.filename ?? "").replace(/\.md$/i, "") || undefined,
      session_id: formalReport.session_id,
      run_id: formalReport.run_id,
      attempt_id: formalReport.attempt_id,
      lease_id: formalReport.lease_id,
      agent_id: formalReport.agent_id,
      role: normalizeRole(formalReport.role ?? formalReport.sender) ?? undefined,
      task_id: taskId,
      detail: `status=${String(formalReport.status ?? "unknown")}`,
    });
  }
  for (const session of taskSessions) {
    evidence.push({
      source: "live_session",
      code: "live_task_bound_session",
      observed_at: sessionAt(session),
      session_id: sessionId(session) ?? undefined,
      run_id: sessionRunId(session) ?? undefined,
      attempt_id: session.runtime_attempt_id,
      lease_id: session.runtime_lease_id,
      agent_id: sessionAgentId(session) ?? undefined,
      role: sessionRole(session) ?? undefined,
      task_id: taskId,
    });
  }
  if (activeLease) {
    evidence.push({
      source: "active_lease",
      code: "valid_active_lease",
      observed_at: activeLease.acquired_at,
      session_id: activeLease.session_id,
      attempt_id: activeLease.attempt_id,
      lease_id: activeLease.lease_id,
      agent_id: activeLease.agent_id,
      task_id: taskId,
      detail: `expires_at=${activeLease.expires_at}`,
    });
  }
  if (latestAttempt) {
    evidence.push({
      source: "dispatch_attempt",
      code: `dispatch_attempt_${latestAttempt.status}`,
      observed_at: latestAttempt.updated_at,
      session_id: latestAttempt.session_id,
      attempt_id: latestAttempt.attempt_id,
      lease_id: latestAttempt.lease_id,
      agent_id: latestAttempt.target_agent_id,
      role: normalizeRole(latestAttempt.target_role) ?? undefined,
      task_id: taskId,
    });
  }
  if (input.durable?.sessionUnsettled) {
    evidence.push({
      source: "durable_event",
      code: "historical_session_unsettled",
      observed_at: input.durable.summary.lastStartedAt ?? undefined,
      session_id: input.durable.lastSessionId ?? undefined,
      task_id: taskId,
    });
  }
  if (input.durable?.historicalFailureRecoverable) {
    evidence.push({
      source: "durable_event",
      code: "historical_failure_recoverable",
      observed_at: input.durable.summary.lastEndedAt ?? undefined,
      session_id: input.durable.lastSessionId ?? undefined,
      task_id: taskId,
      detail: input.durable.lastFailureCode ?? undefined,
    });
  }

  if (taskSessions.length > 1) {
    conflicts.push({
      code: "multiple_live_task_sessions",
      sources: ["live_session"],
      detail: `task has ${taskSessions.length} live TASK_BOUND sessions`,
    });
  }
  if (sameTaskLiveRaw.some((session) => sessionKind(session) !== "TASK_BOUND")) {
    conflicts.push({
      code: "task_bound_kind_conflict",
      sources: ["live_session"],
      detail: "a live session carries the task id but is not TASK_BOUND",
    });
  }
  if (
    taskSession &&
    activeLease &&
    (sessionId(taskSession) !== activeLease.session_id ||
      sessionAgentId(taskSession) !== activeLease.agent_id ||
      (taskSession.runtime_attempt_id && taskSession.runtime_attempt_id !== activeLease.attempt_id))
  ) {
    conflicts.push({
      code: "session_lease_binding_conflict",
      sources: ["live_session", "active_lease"],
      detail: "live task Session does not match active lease binding",
    });
  }
  const reportBindingConflicts = formalReport && (taskSession || activeLease)
    ? [
        [formalReport.session_id, sessionId(taskSession) ?? activeLease?.session_id],
        [formalReport.run_id, sessionRunId(taskSession)],
        [formalReport.attempt_id, taskSession?.runtime_attempt_id ?? activeLease?.attempt_id],
        [formalReport.lease_id, taskSession?.runtime_lease_id ?? activeLease?.lease_id],
        [formalReport.agent_id, sessionAgentId(taskSession) ?? activeLease?.agent_id],
        [
          normalizeRole(formalReport.role ?? formalReport.sender),
          sessionRole(taskSession) ?? resolvedRole,
        ],
        [normalizeTaskId(formalReport.task_id), taskId],
      ].some(([reported, current]) => Boolean(reported && current && reported !== current))
    : false;
  if (reportBindingConflicts) {
    conflicts.push({
      code: "report_execution_binding_conflict",
      sources: ["formal_report", taskSession ? "live_session" : "active_lease"],
      detail: "formal REPORT execution binding does not match the current Session/lease",
    });
  }

  const binding = {
    role: resolvedRole,
    agentId: resolvedAgentId,
    session: taskSession,
    attempt: latestAttempt,
    lease: activeLease,
    report: formalReport,
  };

  if (conflicts.length > 0) {
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "projection_conflict",
      conflicts[0]!.code,
      "运行证据互相冲突，已禁止自动恢复",
      evidence,
      conflicts,
      binding,
    );
  }

  if (outcome) {
    const state = outcome === "pass"
      ? "done"
      : outcome === "blocked"
        ? "blocked"
        : outcome === "failed"
          ? "failed"
          : "waiting_report";
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      state,
      `formal_report_${outcome}`,
      outcome === "pass"
        ? "正式 REPORT 已记录技术完成，等待 PM/ADMIN 业务验收"
        : outcome === "nonterminal"
          ? "当前轮已有非终态 REPORT，等待后续正式回执"
          : "正式 REPORT 已记录执行结论，等待 PM/ADMIN 决策",
      evidence,
      conflicts,
      binding,
    );
  }

  if (taskSession) {
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "running",
      "live_task_bound_session",
      "Agent 正在执行；当前任务存在 live TASK_BOUND Session",
      evidence,
      conflicts,
      binding,
    );
  }

  if (activeLease) {
    const elapsed = Math.max(0, nowMs - timestamp(activeLease.acquired_at));
    if (elapsed <= startupGraceMs) {
      return makeSnapshot(
        { ...input, now, startupGraceMs },
        "settling",
        "active_lease_startup_grace",
        "有效 lease 已建立，Session 正在登记宽限期内",
        evidence,
        conflicts,
        binding,
      );
    }
    conflicts.push({
      code: "active_lease_without_live_session",
      sources: ["active_lease", "live_session"],
      detail: "valid lease remains after startup grace but no live task Session exists",
    });
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "projection_conflict",
      "active_lease_without_live_session",
      "有效 lease 与实时 Session 投影冲突，已禁止自动恢复",
      evidence,
      conflicts,
      binding,
    );
  }

  const candidateAgentId = resolvedAgentId;
  const otherAgentSession = candidateAgentId
    ? allLive.find(
        (session) =>
          sessionAgentId(session) === candidateAgentId &&
          sessionKind(session) === "TASK_BOUND" &&
          sessionTaskId(session) !== taskId,
      )
    : undefined;
  if (otherAgentSession) {
    evidence.push({
      source: "live_session",
      code: "agent_running_other_fifo_task",
      observed_at: sessionAt(otherAgentSession),
      session_id: sessionId(otherAgentSession) ?? undefined,
      run_id: sessionRunId(otherAgentSession) ?? undefined,
      agent_id: sessionAgentId(otherAgentSession) ?? undefined,
      task_id: sessionTaskId(otherAgentSession),
    });
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "waiting_capacity",
      "agent_running_other_fifo_task",
      "目标 Agent 正在执行另一项 FIFO 任务",
      evidence,
      conflicts,
      binding,
    );
  }

  const latestAttemptStatus = String(latestAttempt?.status ?? "").toLowerCase();
  const latestSessionStatus = String(latestSession?.protocol.status ?? "").toLowerCase();
  if (latestAttempt && RECOVERABLE_ATTEMPT.has(latestAttemptStatus)) {
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "recoverable",
      `dispatch_attempt_${latestAttemptStatus}`,
      "投递尝试已技术终止，且当前无 Session、lease 或正式 REPORT",
      evidence,
      conflicts,
      binding,
    );
  }
  if (
    latestAttempt &&
    ["claimed", "running"].includes(latestAttemptStatus)
  ) {
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "recoverable",
      "attempt_without_active_lease",
      "运行中 attempt 的 lease 已不存在，且当前无 Session 或正式 REPORT",
      evidence,
      conflicts,
      binding,
    );
  }
  if (latestAttempt && FAILED_ATTEMPT.has(latestAttemptStatus)) {
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "failed",
      `dispatch_attempt_${latestAttemptStatus}`,
      "投递尝试已失败，等待 PM/ADMIN 处理",
      evidence,
      conflicts,
      binding,
    );
  }
  if (latestAttempt && SETTLED_ATTEMPT.has(latestAttemptStatus)) {
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "waiting_report",
      `dispatch_attempt_${latestAttemptStatus}_without_report`,
      "投递尝试已结算，等待正式 REPORT 投影",
      evidence,
      conflicts,
      binding,
    );
  }

  if (latestSession && TERMINAL_SESSION.has(latestSessionStatus)) {
    evidence.push({
      source: "live_session",
      code: `terminal_session_${latestSessionStatus}`,
      observed_at: sessionAt(latestSession),
      session_id: sessionId(latestSession) ?? undefined,
      run_id: sessionRunId(latestSession) ?? undefined,
      agent_id: sessionAgentId(latestSession) ?? undefined,
      task_id: taskId,
    });
    if (["completed", "done"].includes(latestSessionStatus)) {
      return makeSnapshot(
        { ...input, now, startupGraceMs },
        "waiting_report",
        "terminal_session_waiting_report",
        "Session 已完成但尚未发现当前轮正式 REPORT",
        evidence,
        conflicts,
        { ...binding, session: latestSession },
      );
    }
    if (input.durable?.historicalFailureRecoverable) {
      return makeSnapshot(
        { ...input, now, startupGraceMs },
        "recoverable",
        input.durable.lastFailureCode ?? "terminal_session_recoverable",
        "Session 已技术失败，且当前无 Session、lease 或正式 REPORT",
        evidence,
        conflicts,
        { ...binding, session: latestSession },
      );
    }
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "failed",
      `terminal_session_${latestSessionStatus}`,
      "Session 已失败且不满足自动技术恢复条件",
      evidence,
      conflicts,
      { ...binding, session: latestSession },
    );
  }

  if (input.durable?.historicalFailureRecoverable) {
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "recoverable",
      input.durable.lastFailureCode ?? "historical_failure_recoverable",
      "持久化历史证明执行已技术终止，且当前无实时执行证据",
      evidence,
      conflicts,
      binding,
    );
  }
  if (input.durable?.sessionFailed) {
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "failed",
      input.durable.lastFailureCode ?? "historical_session_failed",
      "持久化历史记录了不可自动恢复的技术失败",
      evidence,
      conflicts,
      binding,
    );
  }
  if (input.durable?.sessionUnsettled) {
    conflicts.push({
      code: "durable_unsettled_without_live_session",
      sources: ["durable_event", "live_session"],
      detail: "durable history says session is open but no live task Session is present",
    });
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "projection_conflict",
      "durable_unsettled_without_live_session",
      "历史未结算提示缺少实时 Session 佐证，已禁止自动恢复",
      evidence,
      conflicts,
      binding,
    );
  }

  const registryRecord = input.registry?.find(
    (record) => record.agent_id === candidateAgentId,
  ) ?? input.registry?.find(
    (record) => role && normalizeRole(record.role) === role,
  );
  if (registryRecord) {
    evidence.push({
      source: "registry",
      code: `registry_${String(registryRecord.status ?? "unknown").toLowerCase()}`,
      observed_at: registryRecord.last_active_at,
      agent_id: registryRecord.agent_id,
      role: normalizeRole(registryRecord.role) ?? undefined,
      task_id: taskId,
    });
    if (["running", "busy", "error"].includes(String(registryRecord.status ?? "").toLowerCase())) {
      conflicts.push({
        code: "registry_busy_without_runtime_evidence",
        sources: ["registry", "live_session"],
        detail: "registry projects busy/error but no task Session or valid lease exists",
      });
      return makeSnapshot(
        { ...input, now, startupGraceMs },
        "projection_conflict",
        "registry_busy_without_runtime_evidence",
        "Registry 忙碌投影缺少实时证据，已禁止自动恢复",
        evidence,
        conflicts,
        { ...binding, agentId: registryRecord.agent_id },
      );
    }
  }

  const bucket = String(input.lifecycleBucket ?? "").trim().toLowerCase();
  if (bucket) {
    evidence.push({
      source: "lifecycle",
      code: `lifecycle_${bucket}`,
      task_id: taskId,
    });
  }
  if (bucket === "done" || bucket === "archive") {
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "done",
      `lifecycle_${bucket}`,
      "生命周期已结束；业务验收仍由 PM/ADMIN 的正式证据决定",
      evidence,
      conflicts,
      binding,
    );
  }
  if (bucket === "review") {
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "waiting_report",
      "lifecycle_review_waiting_report",
      "任务位于 review，等待当前轮正式 REPORT 投影",
      evidence,
      conflicts,
      binding,
    );
  }
  if (bucket === "active") {
    conflicts.push({
      code: "active_task_without_runtime_evidence",
      sources: ["lifecycle", "live_session"],
      detail: "active lifecycle task has no live Session, valid lease, terminal execution, or REPORT",
    });
    return makeSnapshot(
      { ...input, now, startupGraceMs },
      "projection_conflict",
      "active_task_without_runtime_evidence",
      "active 生命周期缺少确定的运行事实，已禁止自动恢复",
      evidence,
      conflicts,
      binding,
    );
  }
  return makeSnapshot(
    { ...input, now, startupGraceMs },
    "waiting_capacity",
    bucket === "inbox" ? "task_waiting_dispatch" : "task_not_started",
    "任务尚未建立执行 lease，正在等待调度或容量",
    evidence,
    conflicts,
    binding,
  );
}

function registryProjection(record: AgentRecord): CanonicalRegistryProjection {
  return {
    agent_id: record.protocol.agent_id,
    role: record.protocol.role,
    status: record.protocol.status,
    last_active_at: record.protocol.last_active_at,
  };
}

async function resolveFormalReport(
  input: BuildCanonicalTaskRuntimeSnapshotInput,
  role: string | null,
  execution?: {
    sessionId?: string;
    runId?: string;
    attemptId?: string;
    leaseId?: string;
  },
): Promise<CanonicalFormalReport | null> {
  const taskId = normalizeTaskId(input.taskId);
  const lookup = {
    projectRoot: input.projectRoot,
    taskId,
    reporter: role ?? "",
    sessionId: execution?.sessionId,
    runId: execution?.runId,
    attemptId: execution?.attemptId,
    leaseId: execution?.leaseId,
  };
  const isCurrentRound = await findReportForTaskOnDisk(lookup);
  if (!isCurrentRound) return null;
  const reportPath = await findReportPathForTaskOnDisk(lookup);
  if (reportPath) {
    const filename = basename(reportPath);
    const row = input.reports?.find((report) => report.filename === filename);
    try {
      const absoluteReportPath = isAbsolute(reportPath)
        ? reportPath
        : join(input.projectRoot, reportPath);
      const fm = parseMarkdownFrontmatter(await readFile(absoluteReportPath, "utf-8"));
      return {
        ...row,
        report_id: String(fm["report_id"] ?? filename.replace(/\.md$/i, "")),
        filename,
        task_id: String(fm["task_id"] ?? fm["source_task_id"] ?? taskId),
        status: String(fm["status"] ?? ""),
        sender: String(fm["sender"] ?? fm["reporter"] ?? role ?? ""),
        valid: fm["valid"] !== false,
        created_at: String(fm["created_at"] ?? fm["timestamp"] ?? "") || undefined,
        updated_at: String(fm["updated_at"] ?? "") || undefined,
        session_id: String(fm["session_id"] ?? "") || undefined,
        run_id: String(fm["run_id"] ?? "") || undefined,
        attempt_id: String(fm["attempt_id"] ?? "") || undefined,
        lease_id: String(fm["lease_id"] ?? "") || undefined,
        agent_id: String(fm["agent_id"] ?? "") || undefined,
        role: String(fm["role"] ?? fm["sender"] ?? "") || undefined,
      };
    } catch {
      return row ?? null;
    }
  }
  return null;
}

/** Collect current runtime facts and pass them once through the canonical resolver. */
export async function buildCanonicalTaskRuntimeSnapshot(
  input: BuildCanonicalTaskRuntimeSnapshotInput,
): Promise<CanonicalTaskRuntimeSnapshot> {
  const taskId = normalizeTaskId(input.taskId);
  const task = input.tasks?.find(
    (candidate) =>
      normalizeTaskId(candidate.task_id) === taskId ||
      normalizeTaskId(candidate.filename) === taskId,
  );
  const role = normalizeRole(input.role ?? task?.recipient);

  const activeSessions = await input.sessionManager.listActive();
  const liveSessions = input.sessionManager.listLive
    ? await input.sessionManager.listLive()
    : activeSessions;
  const allSessions = input.sessionStore
    ? await input.sessionStore.listAll()
    : activeSessions;
  const dispatch = input.dispatcher
    ? await input.dispatcher.getDispatchTaskState(taskId)
    : ({ attempts: [] } satisfies DispatchTaskStateView);
  const durable = input.durable ??
    await resolveWorkerReceiptDurableHints(input.projectRoot, taskId);
  const liveTaskSession = latestBy(
    liveSessions.filter(
      (session) => sessionTaskId(session) === taskId && sessionKind(session) === "TASK_BOUND",
    ),
    sessionAt,
  );
  const latestAttempt = latestBy(dispatch.attempts, (attempt) => attempt.updated_at);
  const currentLease = dispatch.active_lease;
  const formalReport = await resolveFormalReport(input, role, {
    sessionId:
      sessionId(liveTaskSession) ??
      currentLease?.session_id ??
      latestAttempt?.session_id,
    runId: sessionRunId(liveTaskSession) ?? undefined,
    attemptId:
      liveTaskSession?.runtime_attempt_id ??
      currentLease?.attempt_id ??
      latestAttempt?.attempt_id,
    leaseId:
      liveTaskSession?.runtime_lease_id ??
      currentLease?.lease_id ??
      latestAttempt?.lease_id,
  });
  const registry = input.registry
    ? (await input.registry.list()).map(registryProjection)
    : [];

  return resolveCanonicalTaskRuntimeState({
    taskId,
    role,
    agentId: input.agentId,
    lifecycleBucket:
      dispatch.lifecycle_bucket ??
      (task ? resolveTaskCurrentBucket(task) : null),
    formalReport,
    liveSessions,
    allSessions,
    attempts: dispatch.attempts,
    activeLease: dispatch.active_lease,
    durable,
    registry,
    now: input.now,
    startupGraceMs: input.startupGraceMs,
  });
}
