// SPEC: PJ2026-0103 HarnessRL draft-2026-06-25-p0-web-caserun-e2e.
// Responsibility: CaseRun evidence rendering, archive, aggregate, and terminal closeout.

import { copyFile, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
import path from "node:path";
import { renderTraceRowsMarkdown, traceDisplayRows, traceNoiseEventCount, type TraceEventRow } from "./hwlab-cli/trace-renderer.ts";
import {
  agentTerminalEvidence,
  agentToolCallSummaryFromResult,
  arrayOfObjects,
  clean,
  cliError,
  clipText,
  commandVisibility,
  commandsFromToolCallSummary,
  compactObject,
  hwpodCommandKind,
  mentionsHwpod,
  numberOption,
  parseJsonMaybe,
  sha256,
  summarizeAgentTrace,
  text,
  uniqueStrings,
} from "./hwlab-caserun-evidence.ts";
import { webUrlFrom } from "./hwlab-caserun-runtime-config.ts";
import type { AgentRunStage, ArchivedAgentTraceSnapshot, AgentTraceCommand, AgentTraceStage, CaseContext, CaseReadableAgentArchive, CaseRegistryArchive, CaseRegistryArchiveFile, PreparedCaseRun } from "./hwlab-caserun-shared.ts";
const CASE_TRACE_RENDERER = "tools/src/hwlab-cli/trace-renderer:traceDisplayRows";
const MAX_AGENT_TRACE_COMMANDS = 30;
const HWLAB_API_KEY_PREFIX = "hwl_live_";

export function agentTraceLookup(input: { baseUrl: string; traceId: string; sessionId?: string; conversationId?: string; threadId?: string }) {
  const traceId = input.traceId;
  const commands = clean({
    result: `hwlab-cli client agent result ${traceId}`,
    trace: `hwlab-cli client agent trace ${traceId} --render web`,
    traceFull: `hwlab-cli client agent trace ${traceId} --render web --full`,
    inspect: `hwlab-cli client agent inspect --trace-id ${traceId}`,
    sessionStatus: input.sessionId ? `hwlab-cli client agent session status ${input.sessionId}` : undefined,
  });
  return clean({
    source: "hwlab-cli.client.agent",
    strategy: "id_plus_existing_cli",
    note: "CaseRun records trace/session identity and reuses existing HWLAB Web-equivalent agent CLI for trace/result/inspect; it does not implement a separate trace query path.",
    baseUrl: input.baseUrl,
    traceId,
    sessionId: input.sessionId,
    conversationId: input.conversationId,
    threadId: input.threadId,
    commands,
  });
}

export function agentTraceIdentityArtifact(run: PreparedCaseRun, agent: AgentRunStage) {
  const traceId = text(agent.traceId);
  const lookup = agent.traceLookup ?? agentTraceLookup({ baseUrl: agent.baseUrl, traceId, sessionId: agent.sessionId, conversationId: agent.conversationId, threadId: agent.threadId });
  const resultBody = (agent.result?.body && typeof agent.result.body === "object" ? agent.result.body : agent.result) as Record<string, any>;
  return clean({
    contractVersion: "hwpod-case-run-agent-trace-identity-v1",
    source: "caserun-identity",
    lookupOnly: true,
    status: text(resultBody?.status ?? agent.stageStatus) || "recorded",
    traceId,
    sessionId: agent.sessionId,
    conversationId: agent.conversationId,
    threadId: agent.threadId,
    providerProfile: agent.providerProfile,
    requestedProviderProfile: agent.requestedProviderProfile,
    resolvedBackendProfile: agent.resolvedBackendProfile,
    provider: agent.provider,
    model: agent.model,
    backend: agent.backend,
    infrastructureBackend: agent.infrastructureBackend,
    providerTrace: agent.providerTrace,
    projectId: agent.projectId,
    resultStatus: text(resultBody?.status),
    terminalStatus: agent.terminalStatus,
    commandStatus: agent.commandStatus,
    agentRunStatus: agent.agentRunStatus,
    toolCallSummary: agent.toolCallSummary ?? agentToolCallSummaryFromResult(resultBody),
    finalResponse: resultBody?.finalResponse ?? resultBody?.reply ?? null,
    traceSummary: resultBody?.traceSummary ?? null,
    terminalEvidence: resultBody?.terminalEvidence ?? null,
    agentRun: compactObject(resultBody?.agentRun ?? resultBody?.traceSummary?.agentRun ?? null),
    lookup,
    hint: "Use lookup.commands.trace or lookup.commands.result to query the full Web-equivalent AgentRun trace with the existing HWLAB CLI.",
    runId: run.runId,
    caseId: run.caseId,
  });
}

function requiredText(value: unknown, field: string) {
  const result = text(value);
  if (!result) {
    throw Object.assign(new Error(`${field} is required`), {
      code: "missing_required_value",
      details: { field },
    });
  }
  return result;
}

async function readJsonIfExists(file: string) {
  try {
    return JSON.parse(await readFile(file, "utf8"));
  } catch {
    return null;
  }
}

async function readTextIfExists(file: string) {
  try {
    return await readFile(file, "utf8");
  } catch {
    return "";
  }
}

async function fileExists(file: string) {
  try {
    await stat(file);
    return true;
  } catch {
    return false;
  }
}

async function writeJson(file: string, value: any) {
  await mkdir(path.dirname(file), { recursive: true });
  await writeFile(file, `${JSON.stringify(value, null, 2)}\n`, "utf8");
}

async function runProcess(command: string[], cwd: string, env: Record<string, string | undefined>) {
  const proc = Bun.spawn(command, { cwd, env, stdout: "pipe", stderr: "pipe" });
  const [stdout, stderr, exitCode] = await Promise.all([
    new Response(proc.stdout).text(),
    new Response(proc.stderr).text(),
    proc.exited,
  ]);
  return { command, stdout, stderr, exitCode };
}
export function agentTraceLookupForRun(run: any, evidence?: any) {
  const agent = run.agent ?? evidence?.agent;
  const traceId = text(agent?.traceId ?? evidence?.agentTrace?.traceId ?? run.agentTrace?.traceId);
  const baseUrl = text(agent?.baseUrl ?? run.agent?.baseUrl ?? evidence?.agent?.baseUrl);
  if (!traceId || !baseUrl) return null;
  return { source: "hwlab-cli.client.agent", strategy: "id_plus_existing_cli", baseUrl, traceId, sessionId: text(agent?.sessionId), conversationId: text(agent?.conversationId), threadId: text(agent?.threadId), commands: clean({ result: `hwlab-cli client agent result ${traceId}`, trace: `hwlab-cli client agent trace ${traceId} --render web`, traceFull: `hwlab-cli client agent trace ${traceId} --render web --full`, inspect: `hwlab-cli client agent inspect --trace-id ${traceId}`, sessionStatus: agent?.sessionId ? `hwlab-cli client agent session status ${agent.sessionId}` : undefined }) };
}
export function renderEvidenceSummary(evidence: any) {
  const agentStage = agentStageSummary(evidence);
  const traceLookup = evidence.traceLookup ?? evidence.agent?.traceLookup;
  const traceCommands = traceLookup?.commands ?? {};
  const stageTable = agentStage.commands.length > 0 ? [
    ``,
    `## Agent HWPOD Raw Steps`,
    ``,
    `| Step | Status | Exit | Command | Raw detail |`,
    `|---|---:|---:|---|---|`,
    ...agentStage.commands.map((command: any) => `| ${command.kind} | ${command.status || ""} | ${command.exitCode ?? ""} | \`${markdownTableText(command.command, 160)}\` | ${markdownTableText(command.detail, 180)} |`)
  ].join("\n") : "";
  return `# HWPOD CaseRun ${evidence.caseId}\n\n- runId: ${evidence.runId}\n- status: ${evidence.status}\n- autoEvaluation: false\n- compileOnly: ${evidence.compileOnly}\n- subjectRepoLocalPath: ${evidence.subject?.repoLocalPath ?? ""}\n- subjectCommitId: ${evidence.subject?.commitId ?? ""}\n- subjectWorktreePath: ${evidence.subject?.worktreePath ?? ""}\n- agentTraceId: ${evidence.agent?.traceId ?? ""}\n- agentSessionId: ${evidence.agent?.sessionId ?? ""}\n- requestedProviderProfile: ${evidence.agent?.requestedProviderProfile ?? evidence.agent?.providerProfile ?? ""}\n- resolvedBackendProfile: ${evidence.agent?.resolvedBackendProfile ?? ""}\n- model: ${evidence.agent?.model ?? ""}\n- infrastructureBackend: ${evidence.agent?.infrastructureBackend ?? ""}\n- traceLookupStrategy: ${traceLookup?.strategy ?? ""}\n- traceCommand: ${traceCommands.trace ?? ""}\n- resultCommand: ${traceCommands.result ?? ""}\n- inspectCommand: ${traceCommands.inspect ?? ""}\n- agentTraceCommandCount: ${evidence.agentTrace?.commandCount ?? 0}\n- agentTraceHwpodCommandCount: ${evidence.agentTrace?.hwpodCommandCount ?? 0}\n- agentTraceHwpodBuildCommandCount: ${evidence.agentTrace?.hwpodBuildCommandCount ?? 0}\n- agentTerminalStatus: ${evidence.agentFinal?.terminalStatus ?? evidence.agentTrace?.terminalStatus ?? ""}\n- agentFinalPresent: ${evidence.agentFinal?.present ?? false}\n- agentFinalMissingReason: ${evidence.agentFinal?.missingReason ?? ""}\n- postValidationStatus: ${evidence.postValidation?.status ?? ""}\n- agentReportedBuildWarningCount: ${evidence.warnings?.agentReportedBuildWarningCount ?? ""}\n- runnerPostValidationWarningCount: ${evidence.warnings?.runnerPostValidationWarningCount ?? ""}\n- agentToolCallSummaryCount: ${evidence.agentTrace?.toolCallSummary?.count ?? evidence.agent?.toolCallSummary?.count ?? ""}\n- agentToolCallStatusCounts: ${JSON.stringify(evidence.agentTrace?.toolCallSummary?.statusCounts ?? evidence.agent?.toolCallSummary?.statusCounts ?? {})}\n- agentToolCallExitCodeCounts: ${JSON.stringify(evidence.agentTrace?.toolCallSummary?.exitCodeCounts ?? evidence.agent?.toolCallSummary?.exitCodeCounts ?? {})}\n- agentStageCommandCount: ${agentStage.commands.length}\n- agentStageKinds: ${agentStage.kinds.join(", ")}\n- diffPatchPath: ${evidence.agentDiff?.diffPatchPath ?? ""}\n- runnerHwpodSource: ${evidence.hwpod?.source ?? ""}\n- hwpodExitCode: ${evidence.hwpod?.exitCode ?? ""}\n- jobId: ${evidence.keilJob?.jobId ?? ""}\n- runnerPostAgentCompileCheck: recorded\n${stageTable}\n`;
}

export function agentStageSummary(evidence: any) {
  const toolCallSummary = evidence.agentTrace?.toolCallSummary ?? evidence.agent?.toolCallSummary ?? null;
  const traceCommands = arrayOfObjects(evidence.agentTrace?.commands).filter(mentionsHwpod);
  const summaryCommands = commandsFromToolCallSummary(toolCallSummary).filter(mentionsHwpod);
  const commands = (summaryCommands.length > 0 ? summaryCommands : traceCommands).map(agentStageCommand).filter((command) => text(command.kind));
  const selected: Record<string, any> = {};
  for (const command of commands) {
    if (!selected[command.kind]) selected[command.kind] = command;
    if (command.status === "completed" || command.exitCode === 0) selected[command.kind] = command;
  }
  const ordered = ["spec-validate", "inspect", "workspace-edit", "build", "download", "uart-read"]
    .map((kind) => selected[kind])
    .filter(Boolean);
  const extras = commands.filter((command) => !ordered.some((item) => item.kind === command.kind && item.command === command.command));
  return clean({
    source: summaryCommands.length > 0 ? "agentrun-result.toolCallSummary" : "agent-trace-commands",
    autoEvaluation: false,
    toolCallSummaryCount: toolCallSummary?.count,
    commands: [...ordered, ...extras].slice(0, MAX_AGENT_TRACE_COMMANDS),
    kinds: uniqueStrings([...ordered, ...extras].map((command) => command.kind))
  });
}

export function agentStageCommand(command: AgentTraceCommand) {
  return clean({
    kind: hwpodCommandKind(command) || "hwpod-other",
    seq: command.seq,
    status: command.status,
    exitCode: command.exitCode,
    command: clipText(command.normalizedCommand || command.command, 1000),
    detail: clipText(agentCommandDetail(command), 1000)
  });
}

export function agentCommandDetail(command: AgentTraceCommand) {
  const body = text(command.bodyPreview);
  if (!body) return "";
  return body.split(/\r?\n/u).filter((line) => !line.includes(text(command.command))).join(" ").replace(/\s+/gu, " ").trim() || body;
}

export function markdownTableText(value: unknown, maxBytes = 200) {
  return clipText(value, maxBytes).replace(/\|/gu, "\\|").replace(/\r?\n/gu, " ").trim();
}

export async function writeCaseAggregateFromRegistry(context: CaseContext, caseRepo: string, options: { sync?: boolean } = {}) {
  const caseId = requiredText(context.parsed.caseId ?? context.rest[1], "caseId");
  const runId = await resolveAggregateRunId(caseRepo, caseId, text(context.parsed.runId ?? context.rest[2]));
  const runRel = artifactRel(path.join("runs", caseId, runId));
  const caseRepoRunDir = path.join(caseRepo, runRel);
  const evidence = await readJsonIfExists(path.join(caseRepoRunDir, "evidence.json"));
  const run = await readJsonIfExists(path.join(caseRepoRunDir, "run.json"));
  const manifest = await readJsonIfExists(path.join(caseRepoRunDir, "artifact-manifest.json"));
  if (!evidence && !run && !manifest) throw cliError("case_registry_run_not_found", "case registry run artifacts were not found", { caseRepoRunDir, caseId, runId });
  const outputRel = aggregateOutputRel(context);
  const outputPath = path.join(caseRepoRunDir, outputRel);
  const markdown = await renderCaseAggregateMarkdown(context, { caseRepoRunDir, caseId, runId, evidence, run, manifest });
  await mkdir(path.dirname(outputPath), { recursive: true });
  await writeFile(outputPath, markdown, "utf8");
  const file = await registryAggregateFileRecord(outputPath);
  const registrySync = options.sync === true ? await syncCaseRegistryRel(context, caseRepo, artifactRel(path.join(runRel, outputRel)), `data: aggregate caserun ${runId}`) : null;
  return { caseId, runId, caseRepoRunDir, path: outputPath, rel: artifactRel(path.join(runRel, outputRel)), bytes: file.bytes, sha256: file.sha256, registrySync };
}

export async function resolveAggregateRunId(caseRepo: string, caseId: string, explicit: string) {
  if (explicit) return explicit;
  const runRoot = path.join(caseRepo, "runs", caseId);
  let entries: string[] = [];
  try {
    entries = await readdir(runRoot);
  } catch {
    throw cliError("case_registry_runs_not_found", "case registry has no run directory for this case", { caseId, runRoot });
  }
  const runs = entries.filter((entry) => !entry.startsWith(".")).sort();
  if (runs.length === 0) throw cliError("case_registry_runs_empty", "case registry has no runs for this case", { caseId, runRoot });
  return runs.at(-1) ?? "";
}

export function aggregateOutputRel(context: CaseContext) {
  const value = text(context.parsed.output ?? context.parsed.outputPath ?? context.parsed.aggregatePath) || "aggregate.md";
  const rel = artifactRel(value).replace(/^\/+/, "");
  if (!rel || rel.includes("../") || rel === ".." || path.isAbsolute(value)) throw cliError("invalid_aggregate_output_path", "aggregate output must be a relative path inside the registry run directory", { output: value });
  if (!rel.endsWith(".md")) throw cliError("invalid_aggregate_output_ext", "aggregate output must be a markdown file", { output: value });
  return rel;
}

export async function renderCaseAggregateMarkdown(context: CaseContext, input: { caseRepoRunDir: string; caseId: string; runId: string; evidence: any; run: any; manifest: any }) {
  const prompt = await readTextIfExists(path.join(input.caseRepoRunDir, "agent-prompt.md"));
  const finalResponse = await readTextIfExists(path.join(input.caseRepoRunDir, "final-response.md"));
  const diffPatch = await readTextIfExists(path.join(input.caseRepoRunDir, "agent-diff.patch"));
  const traceMarkdown = await readTextIfExists(path.join(input.caseRepoRunDir, "agent-trace.md"));
  const specText = await readTextIfExists(path.join(input.caseRepoRunDir, ".hwlab", "hwpod-spec.yaml"));
  const validationArchive = await readJsonIfExists(path.join(input.caseRepoRunDir, "validation-observations.json"));
  const evidence = input.evidence ?? {};
  const run = input.run ?? {};
  const manifest = input.manifest ?? {};
  const archivedMessages = await readJsonIfExists(path.join(input.caseRepoRunDir, "agent-messages.json"));
  const traceLookup = manifest.traceLookup ?? evidence.traceLookup ?? run.agent?.traceLookup;
  const commands = traceLookup?.commands ?? {};
  const agent = manifest.agent ?? manifest.trace ?? evidence.agent ?? run.agent ?? {};
  const subject = manifest.subject ?? evidence.subject ?? run.subject ?? {};
  const trace = manifest.trace ?? evidence.agentTrace ?? run.agentTrace ?? {};
  const diff = manifest.diff ?? evidence.agentDiff ?? run.agentDiff ?? {};
  const keilJob = manifest.keilJob ?? evidence.keilJob ?? null;
  const agentStage = manifest.agentStage ?? agentStageSummary(evidence);
  const messages = archivedMessages;
  const traceBody = aggregateTraceBody(messages, traceMarkdown);
  return `${[
    `# HWPOD CaseRun Aggregate: ${input.caseId}`,
    ``,
    `- caseId: ${input.caseId}`,
    `- runId: ${input.runId}`,
    `- generatedFrom: case registry artifacts`,
    `- aggregationOnly: true`,
    `- autoEvaluation: false`,
    `- primaryEntry: aggregate.md`,
    ``,
    `## 运行环境信息`,
    ``,
    aggregateBullets([
      ["apiUrl", run.apiUrl ?? evidence.apiUrl],
      ["compileOnly", evidence.compileOnly ?? run.compileOnly],
      ["caseRepoRunDir", input.caseRepoRunDir],
      ["sourceRunDir", manifest.sourceRunDir ?? run.runDir],
      ["createdAt", run.createdAt],
      ["completedAt", run.completedAt ?? run._control?.completedAt],
      ["runnerPostAgentCompileCheck", manifest.decisions?.runnerPostAgentCompileCheck ?? evidence.decisions?.runnerPostAgentCompileCheck ?? "recorded"]
    ]),
    ``,
    `## HWPOD 信息`,
    ``,
    aggregateBullets([
      ["subjectRepoLocalPath", subject.repoLocalPath],
      ["subjectCommitId", subject.commitId],
      ["subjectSubdir", subject.subdir],
      ["subjectWorktreePath", subject.worktreePath],
      ["sourceRootBaselineStatus", subject.sourceRootBaseline?.statusShort],
      ["sourceRootAfterPrepareStatus", subject.sourceRootAfterPrepare?.statusShort],
      ["keilJobId", keilJob?.jobId],
      ["keilStatus", keilJob?.status],
      ["hwpodExitCode", evidence.hwpod?.exitCode]
    ]),
    specText ? aggregateDetails("Run-local HWPOD spec", "yaml", specText) : `_Run-local HWPOD spec artifact is missing._`,
    ``,
    `## Runtime Validation Observations`,
    ``,
    renderValidationObservationSummary(validationArchive ?? evidence.validation),
    ``,
    `## Code Agent 信息`,
    ``,
    aggregateBullets([
      ["providerProfile", agent.providerProfile],
      ["projectId", agent.projectId],
      ["conversationId", agent.conversationId],
      ["sessionId", agent.sessionId],
      ["threadId", agent.threadId],
      ["traceId", agent.traceId ?? trace.traceId],
      ["agentRunId", trace.agentRun?.runId],
      ["agentCommandId", trace.agentRun?.commandId],
      ["traceSource", trace.source],
      ["traceCommand", commands.trace],
      ["resultCommand", commands.result],
      ["inspectCommand", commands.inspect]
    ]),
    ``,
    `## 输入 Prompt`,
    ``,
    prompt ? aggregateFence("markdown", prompt) : `_agent-prompt.md artifact is missing._`,
    ``,
    `## 低噪声 Trace`,
    ``,
    `- renderer: ${manifest.readableAgent?.renderer ?? messages?.renderer ?? CASE_TRACE_RENDERER}`,
    `- sourceEventCount: ${manifest.readableAgent?.traceRender?.sourceEventCount ?? messages?.sourceEventCount ?? trace.sourceEventCount ?? ""}`,
    `- renderedRowCount: ${manifest.readableAgent?.traceRender?.renderedRowCount ?? messages?.renderedRowCount ?? trace.renderedRowCount ?? ""}`,
    `- hwpodCommandCount: ${trace.hwpodCommandCount ?? evidence.agentTrace?.hwpodCommandCount ?? ""}`,
    `- hwpodBuildCommandCount: ${trace.hwpodBuildCommandCount ?? evidence.agentTrace?.hwpodBuildCommandCount ?? ""}`,
    ``,
    traceBody,
    ``,
    `## Final Response`,
    ``,
    finalResponse ? finalResponse.trimEnd() : `_final-response.md artifact is missing._`,
    ``,
    `## 最后 Diff`,
    ``,
    aggregateBullets([
      ["statusShort", diff.statusShort],
      ["diffStat", diff.diffStat],
      ["diffSha256", diff.sha256 ?? diff.diffPatchSha256],
      ["sourceRootChangedAfterPrepare", diff.sourceRootChangedAfterPrepare],
      ["sourceRootChangedAfterAgent", diff.sourceRootChangedAfterAgent]
    ]),
    diffPatch ? aggregateFence("diff", diffPatch) : `_agent-diff.patch artifact is missing._`,
    ``,
    `## 原始产物索引`,
    ``,
    aggregateArtifactIndex(manifest),
    ``,
    `## 说明`,
    ``,
    `本文件只做已完成 CaseRun registry 产物的二次整理聚合，不新增自动结论、门禁或等级。`
  ].join("\n")}\n`;
}

export function aggregateTraceBody(messages: any, traceMarkdown: string) {
  const rows = arrayOfObjects(messages?.rows);
  if (rows.length > 0) {
    return renderTraceRowsMarkdown(rows.map((row) => traceEventRowFromAggregate(row)));
  }
  if (traceMarkdown) {
    return renderTraceRowsMarkdown([{ rowId: "trace-markdown", seq: null, sequenceAuthority: "source", tone: "source", header: "Rendered trace markdown", body: traceMarkdown, bodyFormat: "markdown" }]);
  }
  return `_No readable trace artifact was found._`;
}

export async function aggregateMessagesWithFreshFullTrace(context: CaseContext, input: { archivedMessages: any; traceLookup: any; traceId: unknown; run: any; evidence: any; manifest: any }) {
  const archivedMessages = input.archivedMessages;
  const traceId = text(input.traceId ?? input.traceLookup?.traceId ?? input.run?.agent?.traceId ?? input.evidence?.agent?.traceId ?? input.manifest?.agent?.traceId);
  const baseUrl = text(input.traceLookup?.baseUrl ?? input.run?.agent?.baseUrl ?? input.evidence?.agent?.baseUrl);
  const apiKey = text(context.env.HWLAB_API_KEY ?? process.env.HWLAB_API_KEY);
  if (!traceId || !baseUrl || !apiKey.startsWith(HWLAB_API_KEY_PREFIX)) return archivedMessages;
  const command = [process.execPath, path.join(context.cwd, "tools/hwlab-cli/bin/hwlab-cli.mjs"), "client", "agent", "trace", traceId, "--render", "web", "--full"];
  const result = await (context.runProcess ?? runProcess)(command, context.cwd, { ...process.env, ...context.env, HWLAB_RUNTIME_WEB_URL: baseUrl });
  if (result.exitCode !== 0) return archivedMessages;
  const parsed = parseJsonMaybe(result.stdout);
  const rendered = freshRenderedTraceBody(parsed);
  const rows = arrayOfObjects(rendered?.rows);
  if (rows.length === 0) return archivedMessages;
  return clean({
    ...(archivedMessages && typeof archivedMessages === "object" ? archivedMessages : {}),
    renderer: rendered.renderer ?? archivedMessages?.renderer ?? CASE_TRACE_RENDERER,
    traceSource: rendered.source ?? archivedMessages?.traceSource,
    traceLookup: archivedMessages?.traceLookup ?? input.traceLookup,
    traceId: rendered.traceId ?? traceId,
    status: rendered.traceStatus ?? rendered.status ?? archivedMessages?.status,
    sourceEventCount: rendered.sourceEventCount ?? archivedMessages?.sourceEventCount,
    renderedRowCount: rendered.renderedRowCount ?? rows.length,
    returnedRowCount: rendered.returnedRowCount ?? rows.length,
    noiseEventCount: rendered.noiseEventCount ?? archivedMessages?.noiseEventCount,
    finalResponse: rendered.finalResponse ?? archivedMessages?.finalResponse,
    rows
  });
}

export function freshRenderedTraceBody(parsed: any) {
  if (!parsed || typeof parsed !== "object") return null;
  const body = parsed.body && typeof parsed.body === "object" ? parsed.body : null;
  if (Array.isArray(body?.rows)) return body;
  const data = parsed.data && typeof parsed.data === "object" ? parsed.data : null;
  if (Array.isArray(data?.rows)) return data;
  return Array.isArray(parsed.rows) ? parsed : null;
}

export function traceEventRowFromAggregate(row: Record<string, unknown>): TraceEventRow {
  const bodyFormat = text(row.bodyFormat);
  return {
    rowId: text(row.rowId) || text(row.header) || "trace-row",
    seq: numberOption(row.seq) ?? null,
    sequenceAuthority: row.sequenceAuthority === "projected" ? "projected" : "source",
    tone: traceRowTone(row.tone),
    header: text(row.header) || text(row.rowId) || "trace row",
    body: row.body === undefined || row.body === null ? null : String(row.body),
    terminal: row.terminal === true ? true : undefined,
    bodyFormat: bodyFormat === "markdown" || bodyFormat === "text" ? bodyFormat : undefined
  };
}

export function aggregateBullets(items: Array<[string, unknown]>) {
  const lines = items.map(([key, value]) => `- ${key}: ${aggregateInlineValue(value)}`).filter((line) => !line.endsWith(": "));
  return lines.length > 0 ? lines.join("\n") : `_No data recorded._`;
}

export function aggregateInlineValue(value: unknown) {
  if (value === undefined || value === null || value === "") return "";
  if (typeof value === "boolean" || typeof value === "number") return String(value);
  if (typeof value === "object") return `\`${markdownInline(JSON.stringify(value))}\``;
  return markdownInline(String(value));
}

export function markdownInline(value: string) {
  return value.replace(/\r?\n/gu, " ").trim();
}

export function aggregateDetails(summary: string, language: string, body: string) {
  return [`<details>`, `<summary>${escapeHtml(summary)}</summary>`, ``, aggregateFence(language, body), ``, `</details>`].join("\n");
}

export function escapeHtml(value: string) {
  return String(value).replace(/&/gu, "&amp;").replace(/</gu, "&lt;").replace(/>/gu, "&gt;");
}

export function aggregateFence(language: string, body: string) {
  const fence = body.includes("```") ? "````" : "```";
  return `${fence}${language}\n${body.trimEnd()}\n${fence}`;
}

export function aggregateArtifactIndex(manifest: any) {
  const files = arrayOfObjects(manifest?.files).filter((file) => text(file.path) !== "aggregate.md");
  if (files.length === 0) return `_artifact-manifest.json is missing or has no files list._`;
  return [`| Path | Bytes | SHA-256 |`, `|---|---:|---|`, ...files.map((file) => `| ${markdownTableText(file.path, 220)} | ${file.bytes ?? ""} | ${markdownTableText(file.sha256, 80)} |`)].join("\n");
}

export async function registryAggregateFileRecord(file: string) {
  const content = await readFile(file);
  return { bytes: content.length, sha256: sha256(content) };
}

export async function archiveCaseRunArtifacts(context: CaseContext, run: PreparedCaseRun, evidence: any, options: { sync?: boolean } = {}): Promise<CaseRegistryArchive> {
  const runRel = caseRegistryRunRel(run);
  const caseRepoRunDir = path.join(run.caseRepo, runRel);
  await mkdir(caseRepoRunDir, { recursive: true });
  const agentTraceSnapshot = await archivedAgentTraceSnapshot(context, run, evidence);
  applyArchivedAgentTraceSummary(run, evidence, agentTraceSnapshot.summary);
  await writeJson(path.join(run.runDir, "evidence.json"), evidence);
  await writeJson(path.join(caseRepoRunDir, "evidence.json"), evidence);
  await writeFile(path.join(caseRepoRunDir, "summary.md"), renderEvidenceSummary(evidence), "utf8");

  const materialized = new Map<string, string | undefined>([
    ["evidence.json", path.join(run.runDir, "evidence.json")],
    ["summary.md", undefined]
  ]);
  if (await fileExists(path.join(caseRepoRunDir, "aggregate.md"))) materialized.set("aggregate.md", undefined);
  const readableAgent = await writeReadableAgentArtifacts(caseRepoRunDir, run, evidence, agentTraceSnapshot);
  for (const rel of readableAgent.generatedFiles) materialized.set(rel, undefined);
  const skippedFiles: string[] = [];
  for (const entry of caseRunArtifactEntries(run)) {
    const rel = artifactRel(entry.rel);
    const copied = await copyCaseRunArtifact(entry.source, path.join(caseRepoRunDir, rel));
    if (copied) materialized.set(rel, entry.source);
    else skippedFiles.push(rel);
  }

  const files: CaseRegistryArchiveFile[] = [];
  for (const [rel, source] of materialized) files.push(await registryArtifactFileRecord(run, caseRepoRunDir, rel, source));
  const artifactManifestPath = path.join(caseRepoRunDir, "artifact-manifest.json");
  const existingManifest = await readJsonIfExists(artifactManifestPath);
  const manifest = caseRunArtifactManifest(context, run, evidence, files, skippedFiles, readableAgent, existingManifest);
  await writeJson(artifactManifestPath, manifest);
  const caseRepoFiles = [...files.map((file) => artifactRel(path.join(runRel, file.path))), artifactRel(path.join(runRel, "artifact-manifest.json"))];
  const registrySync = options.sync === true ? await syncCaseRegistryRun(context, run, runRel) : null;
  return { caseRepoRunDir, artifactManifestPath, caseRepoFiles, files, skippedFiles, manifest, registrySync };
}

export async function syncCaseRegistryRun(context: CaseContext, run: PreparedCaseRun, runRel: string) {
  return syncCaseRegistryRel(context, run.caseRepo, runRel, `data: archive caserun ${run.runId}`);
}

export async function syncCaseRegistryRel(context: CaseContext, caseRepo: string, relInput: string, commitMessage: string) {
  if (context.parsed.noCaseRepoGitSync === true || context.parsed.noRegistryGitSync === true) {
    return { status: "skipped", reason: "disabled_by_cli_flag" };
  }
  const rel = artifactRel(relInput);
  const before = await gitProcess(context, caseRepo, ["status", "--short", "--", rel]);
  if (before.exitCode !== 0) return { status: "failed", stage: "status_before", command: before.command, exitCode: before.exitCode, stderr: clipText(before.stderr) };
  if (!text(before.stdout)) return { status: "unchanged", path: rel };
  const add = await gitProcess(context, caseRepo, ["add", "--", rel]);
  if (add.exitCode !== 0) return { status: "failed", stage: "add", command: add.command, exitCode: add.exitCode, stderr: clipText(add.stderr) };
  const staged = await gitProcess(context, caseRepo, ["diff", "--cached", "--quiet", "--", rel]);
  if (staged.exitCode === 0) return { status: "unchanged_after_add", path: rel };
  if (staged.exitCode !== 1) return { status: "failed", stage: "diff_cached", command: staged.command, exitCode: staged.exitCode, stderr: clipText(staged.stderr) };
  const commit = await gitProcess(context, caseRepo, ["commit", "-m", commitMessage, "--", rel]);
  if (commit.exitCode !== 0) return { status: "failed", stage: "commit", command: commit.command, exitCode: commit.exitCode, stderr: clipText(commit.stderr), stdout: clipText(commit.stdout) };
  const push = await gitProcess(context, caseRepo, ["push", "origin", "HEAD"]);
  if (push.exitCode !== 0) return { status: "failed", stage: "push", command: push.command, exitCode: push.exitCode, stderr: clipText(push.stderr), stdout: clipText(push.stdout) };
  const commitSha = text(commit.stdout.match(/\[\S+\s+([0-9a-f]{7,40})\]/iu)?.[1]);
  return clean({ status: "pushed", path: rel, commitMessage, commitSha, commitStdout: clipText(commit.stdout, 1000), pushStdout: clipText(push.stdout, 1000), pushStderr: clipText(push.stderr, 1000) });
}

export async function gitProcess(context: CaseContext, cwd: string, args: string[]) {
  return (context.runProcess ?? runProcess)(["git", ...args], cwd, { ...process.env, ...context.env });
}

export function collectSummaryFromArchive(run: PreparedCaseRun, evidence: any, archive: CaseRegistryArchive) {
  return {
    caseRepo: run.caseRepo,
    caseRepoRunDir: archive.caseRepoRunDir,
    caseRepoFiles: archive.caseRepoFiles,
    artifactManifestPath: archive.artifactManifestPath,
    artifactCount: archive.files.length + 1,
    skippedFiles: archive.skippedFiles,
    registrySync: archive.registrySync ?? null,
    trace: archive.manifest.trace ?? null,
    traceLookup: archive.manifest.traceLookup ?? agentTraceLookupForRun(run, evidence),
    agentStage: archive.manifest.agentStage ?? agentStageSummary(evidence),
    status: evidence.status,
    autoEvaluation: false
  };
}

export async function writeReadableAgentArtifacts(caseRepoRunDir: string, run: PreparedCaseRun, evidence: any, snapshot: ArchivedAgentTraceSnapshot): Promise<CaseReadableAgentArchive> {
  const messagesRel = "agent-messages.json";
  const traceRel = "agent-trace.md";
  const transcriptRel = "agent-transcript.md";
  const finalResponseRel = "final-response.md";
  const traceBody = snapshot.traceBody;
  const events = snapshot.events;
  const rows = snapshot.rows;
  const finalResponse = agentFinalResponse(run, evidence, traceBody, rows);
  const traceLookup = traceBody?.lookup ?? evidence.traceLookup ?? agentTraceLookupForRun(run, evidence);
  const diffPatch = await readTextIfExists(evidence.agentDiff?.diffPatchPath ?? run.agentDiff?.diffPatchPath ?? path.join(run.runDir, "agent-diff.patch"));
  const messages = clean({
    contractVersion: "hwpod-case-run-agent-messages-v1",
    renderer: CASE_TRACE_RENDERER,
    traceSource: text(traceBody?.source),
    lookupOnly: traceBody?.lookupOnly === true ? true : undefined,
    traceLookup,
    traceId: evidence.agent?.traceId ?? run.agent?.traceId ?? traceBody?.traceId ?? run.agentTrace?.traceId,
    conversationId: evidence.agent?.conversationId ?? run.agent?.conversationId,
    sessionId: evidence.agent?.sessionId ?? run.agent?.sessionId,
    threadId: evidence.agent?.threadId ?? run.agent?.threadId,
    status: traceBody?.traceStatus ?? traceBody?.status ?? run.agentTrace?.status ?? evidence.agentTrace?.status,
    sourceEventCount: traceBody?.eventCount ?? traceBody?.sourceEventCount ?? events.length,
    renderedRowCount: rows.length,
    noiseEventCount: traceNoiseEventCount(events),
    finalResponse,
    rows: rows.map(agentMessageRowForArchive),
    diff: clean({ path: "agent-diff.patch", sha256: evidence.agentDiff?.diffPatchSha256 ?? run.agentDiff?.diffPatchSha256, statusShort: evidence.agentDiff?.statusShort ?? run.agentDiff?.statusShort, diffStat: evidence.agentDiff?.diffStat ?? run.agentDiff?.diffStat, collection: evidence.agentDiff?.diffCollection ?? run.agentDiff?.diffCollection, patchIncludedInTranscript: true })
  });
  const transcript = renderAgentTranscript(run, evidence, messages, rows, diffPatch);
  await writeJson(path.join(caseRepoRunDir, messagesRel), messages);
  await writeFile(path.join(caseRepoRunDir, traceRel), transcript, "utf8");
  await writeFile(path.join(caseRepoRunDir, transcriptRel), transcript, "utf8");
  await writeFile(path.join(caseRepoRunDir, finalResponseRel), renderFinalResponseArtifact(run, evidence, finalResponse, rows), "utf8");
  return {
    messagesRel,
    traceRel,
    transcriptRel,
    finalResponseRel,
    generatedFiles: [messagesRel, traceRel, transcriptRel, finalResponseRel],
    traceRender: clean({ renderer: CASE_TRACE_RENDERER, status: messages.status, sourceEventCount: messages.sourceEventCount, renderedRowCount: messages.renderedRowCount, noiseEventCount: messages.noiseEventCount }),
    finalResponse
  };
}

export async function archivedAgentTraceSnapshot(context: CaseContext, run: PreparedCaseRun, evidence: any): Promise<ArchivedAgentTraceSnapshot> {
  const initialTrace = await archivedAgentTraceBody(run, evidence);
  const traceBody = await materializeFullAgentTraceWithExistingCli(context, run, evidence, initialTrace);
  const bodyForSummary = traceBody?.body && typeof traceBody.body === "object" ? traceBody.body : traceBody;
  const events = arrayOfObjects(bodyForSummary?.events ?? bodyForSummary?.trace?.events ?? bodyForSummary?.sourceEvents);
  const rows = traceRowsFromBody(bodyForSummary, events);
  const hasRenderableTrace = rows.length > 0 || events.length > 0 || Boolean(bodyForSummary?.toolCallSummary);
  const summary = hasRenderableTrace
    ? summarizeAgentTrace(text(bodyForSummary?.traceId ?? traceBody?.traceId ?? evidence.agent?.traceId ?? run.agent?.traceId), numberOption(traceBody?.httpStatus) ?? 0, traceBody)
    : existingAgentTraceSummary(run, evidence, bodyForSummary);
  return { traceBody: bodyForSummary, rows, events, summary };
}

export function existingAgentTraceSummary(run: PreparedCaseRun, evidence: any, traceBody: any): AgentTraceStage {
  const existing = evidence.agentTrace ?? run.agentTrace;
  if (existing?.traceId) return existing as AgentTraceStage;
  return summarizeAgentTrace(text(traceBody?.traceId ?? evidence.agent?.traceId ?? run.agent?.traceId), 0, traceBody);
}

export async function archivedAgentTraceBody(run: PreparedCaseRun, evidence: any) {
  const rawTrace = await readJsonIfExists(path.join(run.runDir, "agent-trace.json"));
  if (rawTrace) return rawTrace;
  const resultTrace = agentTraceBody(run, evidence);
  if (resultTrace) return resultTrace;
  return run.agent ? agentTraceIdentityArtifact(run, run.agent) : clean({ traceId: evidence.agentTrace?.traceId ?? run.agentTrace?.traceId, status: evidence.agentTrace?.status ?? run.agentTrace?.status ?? "recorded", lookupOnly: true });
}

export async function materializeFullAgentTraceWithExistingCli(context: CaseContext, run: PreparedCaseRun, evidence: any, initialTrace: any) {
  const body = initialTrace?.body && typeof initialTrace.body === "object" ? initialTrace.body : initialTrace;
  const existingEvents = arrayOfObjects(body?.events ?? body?.trace?.events ?? body?.sourceEvents);
  const forceRuntimeRefresh = context.parsed.caseRefreshSource === "runtime";
  if (existingEvents.length > 0 && !forceRuntimeRefresh) return initialTrace;
  if (!run.agent) return initialTrace;
  const traceId = text(body?.traceId ?? initialTrace?.traceId ?? evidence.agent?.traceId ?? run.agent?.traceId);
  const lookup = agentTraceLookupForRun(run, evidence);
  const apiKey = text(context.env.HWLAB_API_KEY ?? process.env.HWLAB_API_KEY);
  if (!traceId || !lookup || !apiKey.startsWith(HWLAB_API_KEY_PREFIX)) {
    if (forceRuntimeRefresh) throw cliError("case_refresh_runtime_unavailable", "explicit runtime refresh requires trace identity, runtime base URL, and HWLAB_API_KEY", { traceId, hasLookup: Boolean(lookup), hasApiKey: apiKey.startsWith(HWLAB_API_KEY_PREFIX) });
    return initialTrace;
  }
  const baseUrl = text((lookup as any).baseUrl) || webUrlFrom(context);
  const command = [process.execPath, path.join(context.cwd, "tools/hwlab-cli/bin/hwlab-cli.mjs"), "client", "agent", "trace", traceId, "--render", "web", "--full"];
  const result = await (context.runProcess ?? runProcess)(command, context.cwd, { ...process.env, ...context.env, HWLAB_RUNTIME_WEB_URL: baseUrl });
  if (result.exitCode !== 0) {
    if (forceRuntimeRefresh) throw cliError("case_refresh_trace_fetch_failed", "explicit runtime refresh failed through the existing trace CLI", { traceId, exitCode: result.exitCode, stderr: clipText(result.stderr, 1200) });
    return clean({ ...body, traceFetch: { status: "failed", source: "existing-hwlab-cli", command: commandVisibility(command), exitCode: result.exitCode, stderr: clipText(result.stderr, 1200), stdout: clipText(result.stdout, 1200) } });
  }
  const parsed = parseJsonMaybe(result.stdout);
  if (!parsed) {
    if (forceRuntimeRefresh) throw cliError("case_refresh_trace_invalid_json", "explicit runtime refresh returned invalid trace JSON", { traceId, stdout: clipText(result.stdout, 1200) });
    return clean({ ...body, traceFetch: { status: "failed", source: "existing-hwlab-cli", command: commandVisibility(command), exitCode: 0, error: "invalid_json_stdout", stdout: clipText(result.stdout, 1200) } });
  }
  const parsedBody = parsed?.body && typeof parsed.body === "object" ? parsed.body : null;
  const preserved = clean({
    toolCallSummary: body?.toolCallSummary,
    terminalStatus: body?.terminalStatus,
    commandStatus: body?.commandStatus,
    agentRunStatus: body?.agentRunStatus,
    requestedProviderProfile: body?.requestedProviderProfile,
    resolvedBackendProfile: body?.resolvedBackendProfile,
    provider: body?.provider,
    model: body?.model,
    backend: body?.backend,
    infrastructureBackend: body?.infrastructureBackend,
    providerTrace: body?.providerTrace
  });
  const materialized = parsedBody ? { ...parsed, body: clean({ ...preserved, ...parsedBody, source: text(parsedBody.source) || "hwlab-cli.client.agent.trace", lookup: parsedBody.lookup ?? lookup }) } : clean({ ...preserved, ...parsed, source: text(parsed.source) || "hwlab-cli.client.agent.trace", lookup: parsed.lookup ?? lookup });
  await writeJson(path.join(run.runDir, "agent-trace.json"), materialized);
  return materialized;
}

export function traceRowsFromBody(traceBody: any, events: Record<string, unknown>[]) {
  const existingRows = arrayOfObjects(traceBody?.rows ?? traceBody?.renderedRows ?? traceBody?.traceRows).map(traceEventRowFromObject).filter((row) => text(row.rowId || row.header || row.body));
  return existingRows.length > 0 ? existingRows : traceDisplayRows(traceBody ?? {}, events);
}

export function traceEventRowFromObject(row: Record<string, unknown>): TraceEventRow {
  return {
    rowId: text(row.rowId ?? row.id),
    seq: numberOption(row.seq) ?? null,
    sequenceAuthority: row.sequenceAuthority === "projected" ? "projected" : "source",
    tone: traceRowTone(row.tone),
    header: text(row.header ?? row.title ?? row.label),
    body: row.body === null || row.body === undefined ? null : text(row.body ?? row.content ?? row.text ?? row.message),
    terminal: row.terminal === true ? true : undefined,
    bodyFormat: row.bodyFormat === "markdown" ? "markdown" : row.bodyFormat === "text" ? "text" : undefined
  };
}

export function traceRowTone(value: unknown): TraceEventRow["tone"] {
  const raw = text(value);
  return raw === "ok" || raw === "blocked" || raw === "warn" || raw === "source" ? raw : "source";
}

export function applyArchivedAgentTraceSummary(run: PreparedCaseRun, evidence: any, summary: AgentTraceStage) {
  if (!summary?.traceId) return;
  run.agentTrace = summary;
  evidence.agentTrace = summary;
  evidence.traceLookup = evidence.traceLookup ?? agentTraceLookupForRun(run, evidence);
}

export function agentTraceBody(run: PreparedCaseRun, evidence: any) {
  const result = run.agent?.result ?? evidence.agent?.result ?? null;
  return result?.body && typeof result.body === "object" ? result.body : result;
}

export function agentFinalResponse(run: PreparedCaseRun, evidence: any, traceBody: any, rows: TraceEventRow[]) {
  const candidates = [
    traceBody?.finalResponse,
    traceBody?.terminalEvidence?.finalResponse,
    run.agent?.result?.finalResponse,
    run.agent?.result?.reply,
    evidence.agent?.finalResponse
  ];
  for (const candidate of candidates) {
    const body = text((candidate as any)?.text ?? (candidate as any)?.content ?? (candidate as any)?.message);
    if (body) return clean({ present: true, status: text((candidate as any)?.status) || "completed", source: text((candidate as any)?.source) || "agent-result", text: body, textChars: body.length, traceId: text((candidate as any)?.traceId ?? traceBody?.traceId ?? run.agent?.traceId) });
  }
  const terminal = rows.filter((row) => row.terminal === true || row.tone === "blocked").slice(-5).map(agentMessageRowForArchive);
  return clean({
    present: false,
    value: null,
    reason: finalResponseMissingReason(traceBody, rows),
    status: text(traceBody?.status ?? traceBody?.traceStatus ?? run.agent?.stageStatus),
    terminalRows: terminal,
    error: compactObject(traceBody?.error ?? run.agent?.error ?? null)
  });
}

export function finalResponseMissingReason(traceBody: any, rows: TraceEventRow[]) {
  const errorText = text(traceBody?.error?.message ?? traceBody?.terminalEvidence?.error?.message);
  if (errorText) return errorText;
  const terminalBody = rows.slice().reverse().map((row) => text(row.body)).find((body) => /error|failed|404|not found|blocked|timeout/iu.test(body));
  return terminalBody ? clipText(terminalBody, 1200) : "finalResponse=null; no authoritative final assistant response was returned by the trace/result payload";
}

export function agentMessageRowForArchive(row: TraceEventRow) {
  return clean({ rowId: row.rowId, seq: row.seq, tone: row.tone, header: row.header, terminal: row.terminal === true ? true : undefined, bodyFormat: row.bodyFormat, body: row.body });
}

export function renderAgentTranscript(run: PreparedCaseRun, evidence: any, messages: any, rows: TraceEventRow[], diffPatch: string) {
  const sections = [
    `# CaseRun Agent Transcript`,
    ``,
    `- caseId: ${run.caseId}`,
    `- runId: ${run.runId}`,
    `- traceId: ${messages.traceId ?? ""}`,
    `- conversationId: ${messages.conversationId ?? ""}`,
    `- sessionId: ${messages.sessionId ?? ""}`,
    `- threadId: ${messages.threadId ?? ""}`,
    `- renderer: ${CASE_TRACE_RENDERER}`,
    `- traceLookupStrategy: ${messages.traceLookup?.strategy ?? ""}`,
    `- traceCommand: ${messages.traceLookup?.commands?.trace ?? ""}`,
    `- resultCommand: ${messages.traceLookup?.commands?.result ?? ""}`,
    `- inspectCommand: ${messages.traceLookup?.commands?.inspect ?? ""}`,
    `- lookupOnly: ${messages.lookupOnly === true}`,
    `- finalResponse: ${messages.finalResponse?.present === true ? "present" : "null"}`,
    `- autoEvaluation: false`,
    ``,
    `## Messages`,
    rows.length > 0 ? rows.map(renderTranscriptRow).join("\n\n") : `_No rendered trace rows were returned._`,
    ``,
    `## Final Response`,
    messages.finalResponse?.present === true ? text(messages.finalResponse.text) : [`finalResponse=null`, `reason: ${text(messages.finalResponse?.reason)}`].join("\n"),
    ``,
    `## Subject Diff`,
    ``,
    `statusShort:`,
    `\`\`\`text`,
    text(evidence.agentDiff?.statusShort ?? run.agentDiff?.statusShort) || "(empty)",
    `\`\`\``,
    ``,
    `diffStat:`,
    `\`\`\`text`,
    text(evidence.agentDiff?.diffStat ?? run.agentDiff?.diffStat) || "(empty)",
    `\`\`\``,
    ``,
    `patch:`,
    `\`\`\`diff`,
    diffPatch || "(empty)",
    `\`\`\``
  ];
  return `${sections.join("\n")}\n`;
}

export function renderTranscriptRow(row: TraceEventRow) {
  const body = text(row.body);
  return [`### ${row.header}`, ``, `- rowId: ${row.rowId}`, row.terminal === true ? `- terminal: true` : null, ``, body ? body : `_No body._`].filter((item) => item !== null).join("\n");
}

export function renderFinalResponseArtifact(run: PreparedCaseRun, evidence: any, finalResponse: any, rows: TraceEventRow[]) {
  const lines = [
    `# CaseRun Final Response`,
    ``,
    `- caseId: ${run.caseId}`,
    `- runId: ${run.runId}`,
    `- traceId: ${evidence.agent?.traceId ?? run.agent?.traceId ?? ""}`,
    `- present: ${finalResponse.present === true}`,
    ``
  ];
  if (finalResponse.present === true) return `${[...lines, text(finalResponse.text)].join("\n")}\n`;
  const terminalRows = rows.filter((row) => row.terminal === true || row.tone === "blocked").slice(-5);
  return `${[
    ...lines,
    `finalResponse=null`,
    ``,
    `reason: ${text(finalResponse.reason)}`,
    ``,
    `## Terminal/Error Rows`,
    terminalRows.length > 0 ? terminalRows.map(renderTranscriptRow).join("\n\n") : `_No terminal/error rows were rendered._`
  ].join("\n")}\n`;
}

export async function refreshCompletedRunArchive(context: CaseContext, run: PreparedCaseRun, evidence?: any, options: { sync?: boolean } = {}) {
  if (context.parsed.noCaseRepoRecord === true) return null;
  if (!text(run.caseRepo)) return null;
  const loadedEvidence = evidence ?? await readJsonIfExists(path.join(run.runDir, "evidence.json"));
  if (!loadedEvidence) return null;
  const archive = await archiveCaseRunArtifacts(context, run, loadedEvidence, options);
  return { evidence: loadedEvidence, archive, summary: collectSummaryFromArchive(run, loadedEvidence, archive) };
}

export function caseRunArtifactEntries(run: PreparedCaseRun) {
  return [
    { rel: "run.json", source: path.join(run.runDir, "run.json") },
    { rel: "result.json", source: path.join(run.runDir, "result.json") },
    { rel: "agent-trace.json", source: path.join(run.runDir, "agent-trace.json") },
    { rel: "agent-prompt.md", source: path.join(run.runDir, "agent-prompt.md") },
    { rel: "agent-diff.patch", source: path.join(run.runDir, "agent-diff.patch") },
    { rel: "validation-observations.json", source: path.join(run.runDir, "validation-observations.json") },
    { rel: path.join(".hwlab", "hwpod-spec.yaml"), source: run.specPath },
    { rel: "worker.stdout.log", source: path.join(run.runDir, "worker.stdout.log") },
    { rel: "worker.stderr.log", source: path.join(run.runDir, "worker.stderr.log") }
  ];
}

export async function copyCaseRunArtifact(source: string, destination: string) {
  if (path.resolve(source) === path.resolve(destination)) {
    try { return (await stat(source)).isFile(); } catch { return false; }
  }
  try {
    const info = await stat(source);
    if (!info.isFile()) return false;
    await mkdir(path.dirname(destination), { recursive: true });
    await copyFile(source, destination);
    return true;
  } catch {
    return false;
  }
}

export async function registryArtifactFileRecord(run: PreparedCaseRun, caseRepoRunDir: string, rel: string, source?: string): Promise<CaseRegistryArchiveFile> {
  const file = path.join(caseRepoRunDir, rel);
  const content = await readFile(file);
  return clean({
    path: artifactRel(rel),
    bytes: content.length,
    sha256: sha256(content),
    source: artifactSourceLabel(run, source)
  });
}

export function caseRunArtifactManifest(context: CaseContext, run: PreparedCaseRun, evidence: any, files: CaseRegistryArchiveFile[], skippedFiles: string[], readableAgent: CaseReadableAgentArchive, existingManifest?: any) {
  return clean({
    contractVersion: "hwpod-case-run-artifact-manifest-v1",
    caseId: run.caseId,
    runId: run.runId,
    archivedAt: text(existingManifest?.archivedAt) || context.now(),
    sourceRunDir: run.runDir,
    caseRepoRunDir: path.join(run.caseRepo, caseRegistryRunRel(run)),
    trace: caseRunArtifactTrace(run, evidence),
    traceLookup: evidence.traceLookup ?? agentTraceLookupForRun(run, evidence),
    subject: evidence.subject ?? run.subject,
    agent: clean({
      providerProfile: evidence.agent?.providerProfile ?? run.agent?.providerProfile,
      requestedProviderProfile: evidence.agent?.requestedProviderProfile ?? run.agent?.requestedProviderProfile,
      resolvedBackendProfile: evidence.agent?.resolvedBackendProfile ?? run.agent?.resolvedBackendProfile,
      provider: evidence.agent?.provider ?? run.agent?.provider,
      model: evidence.agent?.model ?? run.agent?.model,
      backend: evidence.agent?.backend ?? run.agent?.backend,
      infrastructureBackend: evidence.agent?.infrastructureBackend ?? run.agent?.infrastructureBackend,
      providerTrace: evidence.agent?.providerTrace ?? run.agent?.providerTrace,
      projectId: evidence.agent?.projectId ?? run.agent?.projectId,
      conversationId: evidence.agent?.conversationId ?? run.agent?.conversationId,
      sessionId: evidence.agent?.sessionId ?? run.agent?.sessionId,
      threadId: evidence.agent?.threadId ?? run.agent?.threadId,
      traceId: evidence.agent?.traceId ?? run.agent?.traceId,
      terminalStatus: evidence.agent?.terminalStatus ?? run.agent?.terminalStatus,
      commandStatus: evidence.agent?.commandStatus ?? run.agent?.commandStatus,
      agentRunStatus: evidence.agent?.agentRunStatus ?? run.agent?.agentRunStatus,
      toolCallSummary: evidence.agent?.toolCallSummary ?? run.agent?.toolCallSummary
    }),
    readableAgent: clean({
      renderer: CASE_TRACE_RENDERER,
      messagesPath: readableAgent.messagesRel,
      tracePath: readableAgent.traceRel,
      transcriptPath: readableAgent.transcriptRel,
      finalResponsePath: readableAgent.finalResponseRel,
      traceRender: readableAgent.traceRender,
      finalResponse: readableAgent.finalResponse
    }),
    aggregate: aggregateManifestEntry(files),
    prompt: clean({ path: "agent-prompt.md", sha256: evidence.agent?.promptSha256 ?? run.agent?.promptSha256 }),
    diff: clean({
      path: "agent-diff.patch",
      sha256: evidence.agentDiff?.diffPatchSha256 ?? run.agentDiff?.diffPatchSha256,
      statusShort: evidence.agentDiff?.statusShort ?? run.agentDiff?.statusShort,
      diffStat: evidence.agentDiff?.diffStat ?? run.agentDiff?.diffStat,
      collection: evidence.agentDiff?.diffCollection ?? run.agentDiff?.diffCollection,
      sourceRootStatusShort: evidence.agentDiff?.sourceRootStatusShort ?? run.agentDiff?.sourceRootStatusShort,
      sourceRootChangedAfterPrepare: evidence.agentDiff?.sourceRootChangedAfterPrepare ?? run.agentDiff?.sourceRootChangedAfterPrepare,
      sourceRootChangedAfterAgent: evidence.agentDiff?.sourceRootChangedAfterAgent ?? run.agentDiff?.sourceRootChangedAfterAgent,
      sourceRootBaseline: evidence.agentDiff?.sourceRootBaseline ?? run.agentDiff?.sourceRootBaseline,
      sourceRootAfterPrepare: evidence.agentDiff?.sourceRootAfterPrepare ?? run.agentDiff?.sourceRootAfterPrepare,
      sourceRootAfterAgent: evidence.agentDiff?.sourceRootAfterAgent ?? run.agentDiff?.sourceRootAfterAgent
    }),
    agentStage: agentStageSummary(evidence),
    agentFinal: evidence.agentFinal ?? null,
    postValidation: evidence.postValidation ?? null,
    validation: evidence.validation ?? null,
    replay: evidence.replay ?? null,
    warnings: evidence.warnings ?? null,
    keilJob: evidence.keilJob ?? null,
    artifacts: evidence.artifacts ?? [],
    decisions: {
      autoEvaluation: false,
      runnerPostAgentCompileCheck: "recorded",
      reason: "flow-only run: the manifest records artifacts and trace without auto-grading or gate decisions"
    },
    refresh: evidence.refresh ?? existingManifest?.refresh,
    files,
    skippedFiles
  });
}

export function renderValidationObservationSummary(value: any) {
  const plan = value?.plan ?? value?.validation?.plan ?? {};
  const results = Array.isArray(value?.results) ? value.results : Array.isArray(value?.validation?.results) ? value.validation.results : [];
  const observations = results.map((item: any) => item?.observation).filter(Boolean);
  const blockers = results.map((item: any) => item?.blocker).filter(Boolean);
  const lines = [
    `- authority: HWPOD service operation/observation results`,
    `- mode: ${plan.mode ?? ""}`,
    `- compileOnly: ${plan.compileOnly ?? ""}`,
    `- actionCount: ${Array.isArray(plan.steps) ? plan.steps.length : results.length}`,
    `- observationCount: ${observations.length}`,
    `- blockerCount: ${blockers.length}`,
    `- agentFinalBoundary: independent-from-post-validation`,
    `- replayRelationship: archived-observation-ids-to-action-and-operation`
  ];
  if (observations.length === 0) return `${lines.join("\n")}\n\n_No runtime observation was archived._`;
  const readings = observations.map((item: any) => [
    `- actionId: ${item.actionId ?? ""}`,
    `  - relationship: operationId=${item.operationId ?? ""}; kind=${item.kind ?? ""}; stage=${item.stage ?? ""}`,
    `  - reading: probeId=${item.probeId ?? ""}; quantity=${item.quantity ?? ""}; unit=${item.unit ?? ""}; samples=${item.sampleCount ?? ""}; mean=${item.mean ?? ""}; min=${item.min ?? ""}; max=${item.max ?? ""}`,
    `  - evidence: level=${item.evidenceLevel ?? ""}; rawArtifactRef=${item.rawArtifactRef ?? ""}`
  ].join("\n"));
  return `${lines.join("\n")}\n\n${readings.join("\n")}`;
}

export function aggregateManifestEntry(files: CaseRegistryArchiveFile[]) {
  const file = files.find((entry) => entry.path === "aggregate.md");
  if (!file) return undefined;
  return { path: file.path, bytes: file.bytes, sha256: file.sha256, primaryEntry: true, aggregationOnly: true, autoEvaluation: false };
}

export function caseRunArtifactTrace(run: PreparedCaseRun, evidence: any) {
  return clean({
    traceId: evidence.agent?.traceId ?? run.agent?.traceId ?? evidence.agentTrace?.traceId ?? run.agentTrace?.traceId,
    sessionId: evidence.agent?.sessionId ?? run.agent?.sessionId,
    conversationId: evidence.agent?.conversationId ?? run.agent?.conversationId,
    threadId: evidence.agent?.threadId ?? run.agent?.threadId,
    providerProfile: evidence.agent?.providerProfile ?? run.agent?.providerProfile,
    projectId: evidence.agent?.projectId ?? run.agent?.projectId,
    source: evidence.agentTrace?.source ?? run.agentTrace?.source,
    lookupOnly: evidence.agentTrace?.lookupOnly ?? run.agentTrace?.lookupOnly,
    lookup: evidence.traceLookup ?? evidence.agentTrace?.lookup ?? run.agentTrace?.lookup ?? agentTraceLookupForRun(run, evidence),
    status: evidence.agentTrace?.status ?? run.agentTrace?.status,
    terminalStatus: evidence.agentTrace?.terminalStatus ?? run.agentTrace?.terminalStatus,
    toolCallSummary: evidence.agentTrace?.toolCallSummary ?? run.agentTrace?.toolCallSummary ?? evidence.agent?.toolCallSummary ?? run.agent?.toolCallSummary,
    commandCount: evidence.agentTrace?.commandCount ?? run.agentTrace?.commandCount,
    hwpodCommandCount: evidence.agentTrace?.hwpodCommandCount ?? run.agentTrace?.hwpodCommandCount,
    hwpodBuildCommandCount: evidence.agentTrace?.hwpodBuildCommandCount ?? run.agentTrace?.hwpodBuildCommandCount,
    agentRun: compactObject(evidence.agentTrace?.agentRun ?? run.agentTrace?.agentRun ?? null)
  });
}

export function caseRegistryRunRel(run: PreparedCaseRun) {
  return artifactRel(path.join("runs", run.caseId, run.runId));
}

export function artifactRel(value: string) {
  return value.replace(/\\/gu, "/");
}

export function artifactSourceLabel(run: PreparedCaseRun, source?: string) {
  if (!source) return undefined;
  const relative = path.relative(path.resolve(run.runDir), path.resolve(source));
  if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) return artifactRel(relative);
  return source;
}
