import { createHash } from "node:crypto";
import { constants as fsConstants } from "node:fs";
import {
  chmod,
  lstat,
  mkdir,
  open as openFile,
  readdir,
  readFile,
  realpath
} from "node:fs/promises";
import path from "node:path";
import { TextDecoder } from "node:util";

const fatalUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
const formats = new Set(["sarif", "junit", "lcov"]);
const receiptKeys = Object.freeze([
  "schemaVersion",
  "artifactType",
  "profile",
  "receiptId",
  "reviewId",
  "format",
  "sourceEvidenceSha256",
  "reviewAuditChecksumSha256",
  "candidateRevisionMatched",
  "summary",
  "boundaries",
  "checksumSha256"
]);
const boundaryKeys = Object.freeze([
  "externalEvidence",
  "aggregateOnly",
  "pathFree",
  "sourceIncluded",
  "rawOutputIncluded",
  "commandExecuted",
  "projectCodeExecuted",
  "projectTestsExecutedByRunrail",
  "verdictChanged",
  "assuranceChanged",
  "sourceMutation",
  "networkUsed",
  "authority"
]);
const summaryKeys = Object.freeze({
  sarif: ["runCount", "resultCount", "errorCount", "warningCount", "noteCount"],
  junit: ["suiteCount", "testCount", "failureCount", "errorCount", "skippedCount"],
  lcov: [
    "recordCount",
    "lineFoundCount",
    "lineHitCount",
    "functionFoundCount",
    "functionHitCount",
    "branchFoundCount",
    "branchHitCount"
  ]
});

export const RUNRAIL_EXTERNAL_EVIDENCE = Object.freeze({
  schemaVersion: 1,
  artifactType: "runrail-external-evidence",
  profile: "runrail-external-evidence-v1",
  outputDirectory: "external-evidence",
  formats: Object.freeze([...formats]),
  maximumDecodedBytes: 2 * 1024 * 1024,
  maximumReceiptsPerReview: 100,
  authority: "none"
});

export class RunrailExternalEvidenceError extends Error {
  constructor(code, message) {
    super(message);
    this.name = "RunrailExternalEvidenceError";
    this.code = code;
  }
}

function fail(code, message) {
  throw new RunrailExternalEvidenceError(code, message);
}

function sha256(value) {
  return createHash("sha256").update(value).digest("hex");
}

function stableValue(value) {
  if (Array.isArray(value)) return value.map(stableValue);
  if (value && typeof value === "object") {
    return Object.fromEntries(
      Object.keys(value)
        .sort()
        .map((key) => [key, stableValue(value[key])])
    );
  }
  return value;
}

export function stableRunrailExternalEvidenceJson(value) {
  return `${JSON.stringify(stableValue(value), null, 2)}\n`;
}

function isPlainRecord(value) {
  return (
    value !== null &&
    typeof value === "object" &&
    !Array.isArray(value) &&
    Object.getPrototypeOf(value) === Object.prototype
  );
}

function exactKeys(value, expected, code) {
  if (!isPlainRecord(value)) fail(code, "External evidence must be a plain object.");
  const actual = Object.keys(value).sort();
  const required = [...expected].sort();
  if (
    actual.length !== required.length ||
    actual.some((key, index) => key !== required[index])
  ) {
    fail(code, "External evidence contains missing or unsupported fields.");
  }
}

function boundedInteger(value, label, maximum = 10_000_000) {
  if (!Number.isSafeInteger(value) || value < 0 || value > maximum) {
    fail("external-evidence-summary-invalid", `${label} is outside the bounded integer range.`);
  }
  return value;
}

function boundedId(value, label, maximum = 80) {
  const text = String(value || "");
  if (
    text.length < 1 ||
    text.length > maximum ||
    !/^[A-Za-z0-9._:-]+$/.test(text)
  ) {
    fail("external-evidence-input-invalid", `${label} is invalid.`);
  }
  return text;
}

function checksum(value, label = "Checksum") {
  const text = String(value || "").toLowerCase();
  if (!/^[a-f0-9]{64}$/.test(text)) {
    fail("external-evidence-checksum-invalid", `${label} must be a SHA-256 digest.`);
  }
  return text;
}

function gitCommit(value) {
  const text = String(value || "").toLowerCase();
  if (!/^[a-f0-9]{40,64}$/.test(text)) {
    fail(
      "external-evidence-revision-missing",
      "External evidence must identify the reviewed candidate revision."
    );
  }
  return text;
}

function safeRelativeSourcePath(value) {
  const text = String(value || "").replaceAll("\\", "/");
  if (
    !text ||
    text.length > 512 ||
    text.includes("\0") ||
    text.startsWith("/") ||
    /^[A-Za-z]:\//.test(text) ||
    text.startsWith("//") ||
    /(^|\/)\.\.(\/|$)/.test(text) ||
    /^(?:file|https?):/i.test(text)
  ) {
    fail(
      "external-evidence-path-invalid",
      "External evidence contains an absolute, remote, or traversing source path."
    );
  }
  return text;
}

function rejectHostPathText(text) {
  if (
    /(?:^|[\s"'(])(?:\/(?:home|Users|private|tmp|var|etc)\/|[A-Za-z]:[\\/]|\\\\[^\\\s]+\\|file:\/\/)/m.test(
      text
    ) ||
    /(?:^|[\\/])\.\.(?:[\\/]|$)/m.test(text)
  ) {
    fail(
      "external-evidence-path-invalid",
      "External evidence contains a host path or traversal sequence."
    );
  }
}

function decodeContent(contentBase64, sourceSha256) {
  const encoded = String(contentBase64 || "");
  if (
    encoded.length < 4 ||
    encoded.length > Math.ceil(RUNRAIL_EXTERNAL_EVIDENCE.maximumDecodedBytes / 3) * 4 + 4 ||
    encoded.length % 4 !== 0 ||
    !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(encoded)
  ) {
    fail("external-evidence-content-invalid", "External evidence must be canonical bounded base64.");
  }
  const bytes = Buffer.from(encoded, "base64");
  if (
    bytes.length < 1 ||
    bytes.length > RUNRAIL_EXTERNAL_EVIDENCE.maximumDecodedBytes ||
    bytes.toString("base64") !== encoded
  ) {
    fail("external-evidence-content-invalid", "External evidence content is empty, oversized, or malformed.");
  }
  if (sha256(bytes) !== checksum(sourceSha256, "Source evidence checksum")) {
    fail("external-evidence-content-tampered", "External evidence does not match its supplied checksum.");
  }
  let text;
  try {
    text = fatalUtf8Decoder.decode(bytes);
  } catch {
    fail("external-evidence-content-invalid", "External evidence must be valid UTF-8.");
  }
  if (text.includes("\0")) {
    fail("external-evidence-content-invalid", "External evidence contains a NUL byte.");
  }
  rejectHostPathText(text);
  return { bytes, text };
}

function candidateMatches(found, expected) {
  const revisions = [...new Set(found.map(gitCommit))];
  if (revisions.length !== 1 || revisions[0] !== gitCommit(expected)) {
    fail(
      "external-evidence-stale-revision",
      "External evidence is not bound to the current reviewed candidate revision."
    );
  }
}

function sarifCandidateRevisions(run) {
  const revisions = [];
  const propertyRevision = run?.properties?.runrailCandidateCommit;
  if (propertyRevision) revisions.push(propertyRevision);
  if (Array.isArray(run?.versionControlProvenance)) {
    for (const entry of run.versionControlProvenance) {
      if (entry?.revisionId) revisions.push(entry.revisionId);
    }
  }
  return revisions;
}

function validateSarifLocations(run) {
  const uris = [];
  if (Array.isArray(run?.artifacts)) {
    for (const artifact of run.artifacts) {
      if (artifact?.location?.uri) uris.push(artifact.location.uri);
    }
  }
  if (Array.isArray(run?.results)) {
    for (const result of run.results) {
      for (const location of Array.isArray(result?.locations) ? result.locations : []) {
        const uri = location?.physicalLocation?.artifactLocation?.uri;
        if (uri) uris.push(uri);
      }
    }
  }
  for (const uri of uris) safeRelativeSourcePath(uri);
}

function parseSarif(text, candidateCommit) {
  let document;
  try {
    document = JSON.parse(text);
  } catch {
    fail("external-evidence-sarif-invalid", "SARIF evidence is not valid JSON.");
  }
  if (!isPlainRecord(document) || document.version !== "2.1.0" || !Array.isArray(document.runs)) {
    fail("external-evidence-sarif-invalid", "SARIF evidence must use SARIF 2.1.0 with a runs array.");
  }
  if (document.runs.length < 1 || document.runs.length > 32) {
    fail("external-evidence-sarif-invalid", "SARIF run count is outside the supported boundary.");
  }
  let resultCount = 0;
  let errorCount = 0;
  let warningCount = 0;
  let noteCount = 0;
  const revisions = [];
  for (const run of document.runs) {
    if (!isPlainRecord(run) || !isPlainRecord(run.tool) || !isPlainRecord(run.tool.driver)) {
      fail("external-evidence-sarif-invalid", "Every SARIF run must identify a tool driver.");
    }
    const results = Array.isArray(run.results) ? run.results : [];
    if (results.length > 10_000 || resultCount + results.length > 10_000) {
      fail("external-evidence-sarif-invalid", "SARIF result count exceeds the supported boundary.");
    }
    resultCount += results.length;
    revisions.push(...sarifCandidateRevisions(run));
    validateSarifLocations(run);
    for (const result of results) {
      const level = String(result?.level || "warning");
      if (!["error", "warning", "note", "none"].includes(level)) {
        fail("external-evidence-sarif-invalid", "SARIF contains an unsupported result level.");
      }
      if (level === "error") errorCount += 1;
      if (level === "warning") warningCount += 1;
      if (level === "note") noteCount += 1;
    }
  }
  candidateMatches(revisions, candidateCommit);
  return {
    runCount: document.runs.length,
    resultCount,
    errorCount,
    warningCount,
    noteCount
  };
}

function decodeXmlAttribute(value) {
  if (/&(?!(?:amp|lt|gt|quot|apos);)/.test(value)) {
    fail("external-evidence-junit-invalid", "JUnit XML contains an unsupported entity.");
  }
  return value
    .replaceAll("&quot;", "\"")
    .replaceAll("&apos;", "'")
    .replaceAll("&lt;", "<")
    .replaceAll("&gt;", ">")
    .replaceAll("&amp;", "&");
}

function parseXmlAttributes(source) {
  const attributes = {};
  const expression = /([A-Za-z_:][A-Za-z0-9_.:-]*)\s*=\s*("([^"]*)"|'([^']*)')/g;
  let cursor = 0;
  let match;
  while ((match = expression.exec(source)) !== null) {
    if (
      source.slice(cursor, match.index).trim() !== "" ||
      Object.hasOwn(attributes, match[1])
    ) {
      fail("external-evidence-junit-invalid", "JUnit XML contains malformed attributes.");
    }
    attributes[match[1]] = decodeXmlAttribute(match[3] ?? match[4] ?? "");
    cursor = expression.lastIndex;
  }
  if (source.slice(cursor).replace(/[/?\s]+/g, "") !== "") {
    fail("external-evidence-junit-invalid", "JUnit XML contains malformed attributes.");
  }
  return attributes;
}

function parseJunit(text, candidateCommit) {
  let xml = text.trim();
  if (/^<\?xml\s+version=(?:"1\.0"|'1\.0')(?:\s+encoding=(?:"UTF-8"|'UTF-8'|"utf-8"|'utf-8'))?\s*\?>/.test(xml)) {
    xml = xml.replace(/^<\?xml[^?]*\?>\s*/, "");
  }
  if (
    /<!DOCTYPE|<!ENTITY|<!\[CDATA\[|<!--|<\?/i.test(xml) ||
    xml.length < 10
  ) {
    fail("external-evidence-junit-invalid", "JUnit XML contains a disallowed declaration or construct.");
  }
  const tagExpression = /<\/?([A-Za-z_:][A-Za-z0-9_.:-]*)([^<>]*)>/g;
  const stack = [];
  let cursor = 0;
  let suiteCount = 0;
  let testCount = 0;
  let failureCount = 0;
  let errorCount = 0;
  let skippedCount = 0;
  const revisions = [];
  let match;
  while ((match = tagExpression.exec(xml)) !== null) {
    const textBetween = xml.slice(cursor, match.index);
    if (/[<>]/.test(textBetween)) {
      fail("external-evidence-junit-invalid", "JUnit XML contains malformed markup.");
    }
    const full = match[0];
    const name = match[1];
    const closing = full.startsWith("</");
    const selfClosing = /\/\s*>$/.test(full);
    const attributes = closing ? {} : parseXmlAttributes(match[2]);
    if (closing) {
      if (stack.pop() !== name) {
        fail("external-evidence-junit-invalid", "JUnit XML contains mismatched tags.");
      }
    } else {
      if (name === "testsuite") suiteCount += 1;
      if (name === "testcase") testCount += 1;
      if (name === "failure") failureCount += 1;
      if (name === "error") errorCount += 1;
      if (name === "skipped") skippedCount += 1;
      if (
        name === "property" &&
        attributes.name === "runrail.candidateCommit"
      ) {
        revisions.push(attributes.value);
      }
      for (const [key, value] of Object.entries(attributes)) {
        if (/(?:file|path|uri|directory|workspace)/i.test(key) && value) {
          safeRelativeSourcePath(value);
        }
      }
      if (!selfClosing) stack.push(name);
    }
    cursor = tagExpression.lastIndex;
  }
  if (
    stack.length > 0 ||
    /[<>]/.test(xml.slice(cursor)) ||
    suiteCount < 1 ||
    testCount > 1_000_000
  ) {
    fail("external-evidence-junit-invalid", "JUnit XML is incomplete or exceeds supported limits.");
  }
  candidateMatches(revisions, candidateCommit);
  return {
    suiteCount: boundedInteger(suiteCount, "JUnit suite count"),
    testCount: boundedInteger(testCount, "JUnit test count", 1_000_000),
    failureCount: boundedInteger(failureCount, "JUnit failure count", 1_000_000),
    errorCount: boundedInteger(errorCount, "JUnit error count", 1_000_000),
    skippedCount: boundedInteger(skippedCount, "JUnit skipped count", 1_000_000)
  };
}

function parseLcovInteger(line, label) {
  const value = Number(line.slice(line.indexOf(":") + 1));
  return boundedInteger(value, label, 100_000_000);
}

function parseLcov(text, candidateCommit) {
  const lines = text.split(/\r?\n/);
  if (lines.length < 3 || lines.length > 200_000) {
    fail("external-evidence-lcov-invalid", "LCOV evidence is empty or exceeds supported limits.");
  }
  const revisions = [];
  let recordCount = 0;
  let currentSource = false;
  const totals = {
    lineFoundCount: 0,
    lineHitCount: 0,
    functionFoundCount: 0,
    functionHitCount: 0,
    branchFoundCount: 0,
    branchHitCount: 0
  };
  const mapping = {
    LF: "lineFoundCount",
    LH: "lineHitCount",
    FNF: "functionFoundCount",
    FNH: "functionHitCount",
    BRF: "branchFoundCount",
    BRH: "branchHitCount"
  };
  for (const rawLine of lines) {
    const line = rawLine.trim();
    if (!line) continue;
    if (line.startsWith("TN:runrail-candidate:")) {
      revisions.push(line.slice("TN:runrail-candidate:".length));
      continue;
    }
    if (line.startsWith("SF:")) {
      safeRelativeSourcePath(line.slice(3));
      currentSource = true;
      continue;
    }
    if (line === "end_of_record") {
      if (!currentSource) {
        fail("external-evidence-lcov-invalid", "LCOV record is missing a source file.");
      }
      recordCount += 1;
      currentSource = false;
      continue;
    }
    const prefix = line.slice(0, line.indexOf(":"));
    if (Object.hasOwn(mapping, prefix)) {
      totals[mapping[prefix]] += parseLcovInteger(line, `LCOV ${prefix}`);
      continue;
    }
    if (!/^(?:DA|FN|FNDA|BRDA):/.test(line)) {
      fail("external-evidence-lcov-invalid", "LCOV evidence contains an unsupported record.");
    }
  }
  if (recordCount < 1 || currentSource) {
    fail("external-evidence-lcov-invalid", "LCOV evidence contains an incomplete record.");
  }
  candidateMatches(revisions, candidateCommit);
  return {
    recordCount,
    ...totals
  };
}

function parseSummary(format, text, candidateCommit) {
  if (format === "sarif") return parseSarif(text, candidateCommit);
  if (format === "junit") return parseJunit(text, candidateCommit);
  if (format === "lcov") return parseLcov(text, candidateCommit);
  fail("external-evidence-format-invalid", "External evidence format is not supported.");
}

function receiptBody({
  reviewId,
  format,
  sourceEvidenceSha256,
  reviewAuditChecksumSha256,
  summary
}) {
  const receiptId = `REE-${sha256(
    `${reviewId}\0${format}\0${sourceEvidenceSha256}\0${reviewAuditChecksumSha256}`
  )
    .slice(0, 20)
    .toUpperCase()}`;
  return {
    schemaVersion: RUNRAIL_EXTERNAL_EVIDENCE.schemaVersion,
    artifactType: RUNRAIL_EXTERNAL_EVIDENCE.artifactType,
    profile: RUNRAIL_EXTERNAL_EVIDENCE.profile,
    receiptId,
    reviewId,
    format,
    sourceEvidenceSha256,
    reviewAuditChecksumSha256,
    candidateRevisionMatched: true,
    summary,
    boundaries: {
      externalEvidence: true,
      aggregateOnly: true,
      pathFree: true,
      sourceIncluded: false,
      rawOutputIncluded: false,
      commandExecuted: false,
      projectCodeExecuted: false,
      projectTestsExecutedByRunrail: false,
      verdictChanged: false,
      assuranceChanged: false,
      sourceMutation: false,
      networkUsed: false,
      authority: "none"
    }
  };
}

export function createRunrailExternalEvidenceReceipt({
  reviewId,
  format,
  contentBase64,
  sourceSha256,
  candidateCommit,
  reviewAuditChecksumSha256
}) {
  const safeReviewId = boundedId(reviewId, "Review ID");
  const safeFormat = String(format || "").toLowerCase();
  if (!formats.has(safeFormat)) {
    fail("external-evidence-format-invalid", "External evidence format is not supported.");
  }
  const { text } = decodeContent(contentBase64, sourceSha256);
  const summary = parseSummary(safeFormat, text, candidateCommit);
  const body = receiptBody({
    reviewId: safeReviewId,
    format: safeFormat,
    sourceEvidenceSha256: checksum(sourceSha256, "Source evidence checksum"),
    reviewAuditChecksumSha256: checksum(
      reviewAuditChecksumSha256,
      "Review audit checksum"
    ),
    summary
  });
  return verifyRunrailExternalEvidenceReceipt({
    ...body,
    checksumSha256: sha256(stableRunrailExternalEvidenceJson(body))
  });
}

export function verifyRunrailExternalEvidenceReceipt(receipt) {
  exactKeys(receipt, receiptKeys, "external-evidence-receipt-invalid");
  if (
    receipt.schemaVersion !== RUNRAIL_EXTERNAL_EVIDENCE.schemaVersion ||
    receipt.artifactType !== RUNRAIL_EXTERNAL_EVIDENCE.artifactType ||
    receipt.profile !== RUNRAIL_EXTERNAL_EVIDENCE.profile ||
    !formats.has(receipt.format) ||
    receipt.candidateRevisionMatched !== true
  ) {
    fail("external-evidence-receipt-invalid", "External evidence receipt identity is invalid.");
  }
  boundedId(receipt.receiptId, "Receipt ID");
  boundedId(receipt.reviewId, "Review ID");
  checksum(receipt.sourceEvidenceSha256, "Source evidence checksum");
  checksum(receipt.reviewAuditChecksumSha256, "Review audit checksum");
  exactKeys(
    receipt.summary,
    summaryKeys[receipt.format],
    "external-evidence-summary-invalid"
  );
  for (const [key, value] of Object.entries(receipt.summary)) {
    boundedInteger(value, key, 100_000_000);
  }
  exactKeys(receipt.boundaries, boundaryKeys, "external-evidence-boundary-invalid");
  const expectedBoundaries = {
    externalEvidence: true,
    aggregateOnly: true,
    pathFree: true,
    sourceIncluded: false,
    rawOutputIncluded: false,
    commandExecuted: false,
    projectCodeExecuted: false,
    projectTestsExecutedByRunrail: false,
    verdictChanged: false,
    assuranceChanged: false,
    sourceMutation: false,
    networkUsed: false,
    authority: "none"
  };
  if (
    boundaryKeys.some(
      (key) => receipt.boundaries[key] !== expectedBoundaries[key]
    )
  ) {
    fail("external-evidence-boundary-invalid", "External evidence receipt expands authority.");
  }
  const { checksumSha256, ...body } = receipt;
  if (
    checksum(checksumSha256) !==
    sha256(stableRunrailExternalEvidenceJson(body))
  ) {
    fail("external-evidence-receipt-tampered", "External evidence receipt checksum is invalid.");
  }
  return receipt;
}

function inside(root, candidate) {
  const relative = path.relative(root, candidate);
  return (
    relative !== "" &&
    relative !== ".." &&
    !relative.startsWith(`..${path.sep}`) &&
    !path.isAbsolute(relative)
  );
}

async function verifiedArtifactRoot(artifactRoot) {
  const root = path.resolve(artifactRoot);
  const entry = await lstat(root).catch(() => null);
  if (!entry || !entry.isDirectory() || entry.isSymbolicLink()) {
    fail("external-evidence-root-invalid", "Review artifact root is not an ordinary directory.");
  }
  if (await realpath(root) !== root) {
    fail("external-evidence-root-invalid", "Review artifact root traverses a symbolic link.");
  }
  return root;
}

export async function writeRunrailExternalEvidenceReceipt({
  artifactRoot,
  receipt
}) {
  const verified = verifyRunrailExternalEvidenceReceipt(receipt);
  const root = await verifiedArtifactRoot(artifactRoot);
  const outputRoot = path.join(root, RUNRAIL_EXTERNAL_EVIDENCE.outputDirectory);
  if (!inside(root, outputRoot)) {
    fail("external-evidence-path-invalid", "External evidence output escaped the review root.");
  }
  const outputEntry = await lstat(outputRoot).catch(() => null);
  if (outputEntry && (!outputEntry.isDirectory() || outputEntry.isSymbolicLink())) {
    fail("external-evidence-path-invalid", "External evidence output is not an ordinary directory.");
  }
  await mkdir(outputRoot, { recursive: true, mode: 0o700 });
  if (await realpath(outputRoot) !== outputRoot) {
    fail("external-evidence-path-invalid", "External evidence output traverses a symbolic link.");
  }
  const existing = await readdir(outputRoot);
  if (
    !existing.includes(`${verified.receiptId}.json`) &&
    existing.length >= RUNRAIL_EXTERNAL_EVIDENCE.maximumReceiptsPerReview
  ) {
    fail("external-evidence-limit-reached", "This review has reached its external evidence receipt limit.");
  }
  const receiptPath = path.join(outputRoot, `${verified.receiptId}.json`);
  if (!inside(outputRoot, receiptPath)) {
    fail("external-evidence-path-invalid", "External evidence receipt path escaped.");
  }
  const serialized = stableRunrailExternalEvidenceJson(verified);
  const existingEntry = await lstat(receiptPath).catch(() => null);
  if (existingEntry) {
    if (
      !existingEntry.isFile() ||
      existingEntry.isSymbolicLink() ||
      existingEntry.size < 2 ||
      existingEntry.size > 32 * 1024 ||
      await realpath(receiptPath) !== receiptPath
    ) {
      fail("external-evidence-artifact-invalid", "Existing external evidence receipt is unsafe.");
    }
    const existingReceipt = verifyRunrailExternalEvidenceReceipt(
      JSON.parse(await readFile(receiptPath, "utf8"))
    );
    if (
      existingReceipt.checksumSha256 !== verified.checksumSha256 ||
      await readFile(receiptPath, "utf8") !== serialized
    ) {
      fail("external-evidence-artifact-conflict", "External evidence receipt conflicts with existing evidence.");
    }
    return { receipt: existingReceipt, receiptPath, created: false };
  }
  const handle = await openFile(
    receiptPath,
    fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY,
    0o600
  );
  try {
    await handle.writeFile(serialized, "utf8");
    await handle.sync();
  } finally {
    await handle.close();
  }
  if (process.platform !== "win32") await chmod(receiptPath, 0o600);
  return { receipt: verified, receiptPath, created: true };
}

export async function listRunrailExternalEvidenceReceipts({ artifactRoot }) {
  const root = await verifiedArtifactRoot(artifactRoot);
  const outputRoot = path.join(root, RUNRAIL_EXTERNAL_EVIDENCE.outputDirectory);
  const outputEntry = await lstat(outputRoot).catch(() => null);
  if (!outputEntry) return [];
  if (
    !outputEntry.isDirectory() ||
    outputEntry.isSymbolicLink() ||
    await realpath(outputRoot) !== outputRoot
  ) {
    fail("external-evidence-path-invalid", "External evidence output is unsafe.");
  }
  const names = (await readdir(outputRoot))
    .filter((name) => /^REE-[A-F0-9]{20}\.json$/.test(name))
    .sort();
  if (names.length > RUNRAIL_EXTERNAL_EVIDENCE.maximumReceiptsPerReview) {
    fail("external-evidence-limit-reached", "External evidence receipt count exceeds the supported boundary.");
  }
  const receipts = [];
  for (const name of names) {
    const receiptPath = path.join(outputRoot, name);
    const entry = await lstat(receiptPath);
    if (
      !entry.isFile() ||
      entry.isSymbolicLink() ||
      entry.size < 2 ||
      entry.size > 32 * 1024 ||
      await realpath(receiptPath) !== receiptPath
    ) {
      fail("external-evidence-artifact-invalid", "External evidence receipt is unsafe.");
    }
    const receipt = verifyRunrailExternalEvidenceReceipt(
      JSON.parse(await readFile(receiptPath, "utf8"))
    );
    if (`${receipt.receiptId}.json` !== name) {
      fail("external-evidence-artifact-invalid", "External evidence receipt filename is invalid.");
    }
    receipts.push(receipt);
  }
  return receipts;
}
