import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { resolve } from "node:path";
import {
  manifestFingerprint,
  transitionToApproved,
  transitionToOwnerCreated,
  type ApprovedJourneyManifest,
  type OwnerCreatedJourneyManifest,
  type SeedJourneyManifest,
} from "./journey-manifest.js";
import {
  loadOwnerUiReceipt,
  ownerApprovalObservations,
  ownerAuthoringObservations,
  persistOwnerUiReceipt,
} from "./owner-ui-receipt.js";
import { loginBrowser, requireOperatorPassword } from "./auth.js";

const vision = "Deliver one trustworthy Project-to-Merge journey.";
const goalTitle = "Launch the first complete journey";
const criterion = "Project, execution, review, and trusted merge are proven.";
const taskTitles = [
  "Document the canonical owner journey",
  "Add owner journey verification notes",
  "Review owner journey documentation",
] as const;

export const ownerAuthoringProof = Object.freeze({
  unitId: "owner-authoring",
  proofId: "owner-authoring-ac-04-09",
  criterionIds: ["AC-04", "AC-05", "AC-06", "AC-07", "AC-08", "AC-09"] as const,
  runtimeInputs: [
    "AWP_WEB_URL",
    "AWP_PLAYWRIGHT_MODULE",
    "AWP_TEST_POSTGRES_URL",
    "AWP_OPERATOR_PASSWORD",
  ] as const,
  inputSelectors: ["journeyKey", "repository.remoteUrl", "agentAccountId", "agentModel"] as const,
});

export const ownerApprovalProof = Object.freeze({
  unitId: "owner-approval",
  proofId: "owner-approval-ac-10-11",
  criterionIds: ["AC-10", "AC-11"] as const,
  runtimeInputs: [
    "AWP_WEB_URL",
    "AWP_PLAYWRIGHT_MODULE",
    "AWP_TEST_POSTGRES_URL",
    "AWP_OPERATOR_PASSWORD",
  ] as const,
  inputSelectors: ["projectId", "planId", "planRevisionId", "taskIds"] as const,
});

interface Infrastructure {
  readonly webUrl: string;
  readonly playwrightModule: string;
  readonly databaseUrl: string;
  readonly checkpointPath: string;
  readonly operatorPassword: string;
}

export type OwnerSeed = SeedJourneyManifest;
export type OwnerCreatedCheckpoint = OwnerCreatedJourneyManifest;
export type ApprovedCheckpoint = ApprovedJourneyManifest;

type CriterionId = (typeof ownerAuthoringProof.criterionIds)[number] | "AC-10" | "AC-11";

export interface OwnerEvidence {
  readonly criterionId: CriterionId;
  readonly proofId: string;
  readonly outcome: "passed";
  readonly generation: number;
  readonly seedFingerprint: string;
  readonly entityIds: Readonly<Record<string, string | readonly string[]>>;
  readonly evidenceSource: "ui+postgres";
  readonly timestamp: string;
}

const required = (value: string | undefined, name: string): string => {
  if (!value?.trim()) throw new Error(`${name} is required`);
  return value;
};

function infrastructure(environment: Readonly<Record<string, string | undefined>>): Infrastructure {
  return {
    webUrl: required(environment.AWP_WEB_URL, "AWP_WEB_URL"),
    playwrightModule: required(environment.AWP_PLAYWRIGHT_MODULE, "AWP_PLAYWRIGHT_MODULE"),
    databaseUrl: required(environment.AWP_TEST_POSTGRES_URL, "AWP_TEST_POSTGRES_URL"),
    checkpointPath: resolve(
      required(environment.AWP_JOURNEY_MANIFEST_PATH, "AWP_JOURNEY_MANIFEST_PATH"),
    ),
    operatorPassword: requireOperatorPassword(environment),
  };
}

const sql = (value: string): string => `'${value.replaceAll("'", "''")}'`;

function query(databaseUrl: string, statement: string): string {
  return execFileSync("psql", [databaseUrl, "-At", "-F", "\t", "-c", statement], {
    encoding: "utf8",
  }).trim();
}

function oneRow(databaseUrl: string, statement: string, description: string): string[] {
  const rows = query(databaseUrl, statement).split("\n").filter(Boolean);
  assert.equal(rows.length, 1, `${description} must resolve to exactly one row`);
  return rows[0]!.split("\t");
}

type OwnerCreatedIdentityLike = Pick<
  OwnerCreatedCheckpoint,
  "projectId" | "planId" | "planRevisionId" | "taskIds"
>;
type ApprovalIdentityLike = Pick<ApprovedCheckpoint, "factoryRunId">;

function authoringReceiptExpectation(seed: OwnerSeed, identity: OwnerCreatedIdentityLike) {
  return {
    proofId: ownerAuthoringProof.proofId,
    seedFingerprint: seed.seedFingerprint,
    manifestStage: "seed" as const,
    manifestGeneration: seed.generation,
    entityIds: {
      projectId: identity.projectId,
      planId: identity.planId,
      planRevisionId: identity.planRevisionId,
      taskIds: identity.taskIds,
    },
    requiredObservations: ownerAuthoringObservations,
  };
}

function approvalReceiptExpectation(
  ownerCreated: OwnerCreatedCheckpoint,
  identity: ApprovalIdentityLike,
) {
  return {
    proofId: ownerApprovalProof.proofId,
    seedFingerprint: ownerCreated.seedFingerprint,
    manifestStage: "owner-created" as const,
    manifestGeneration: ownerCreated.generation,
    entityIds: {
      projectId: ownerCreated.projectId,
      planId: ownerCreated.planId,
      planRevisionId: ownerCreated.planRevisionId,
      taskIds: ownerCreated.taskIds,
      factoryRunId: identity.factoryRunId,
    },
    requiredObservations: ownerApprovalObservations,
  };
}

function recordAuthoringUiReceipt(
  checkpointPath: string,
  seed: OwnerSeed,
  identity: OwnerCreatedIdentityLike,
): void {
  const expected = authoringReceiptExpectation(seed, identity);
  persistOwnerUiReceipt(checkpointPath, {
    proofId: expected.proofId,
    seedFingerprint: expected.seedFingerprint,
    manifestStage: expected.manifestStage,
    manifestGeneration: expected.manifestGeneration,
    entityIds: expected.entityIds,
    observations: ownerAuthoringObservations,
  });
}

function recordApprovalUiReceipt(
  checkpointPath: string,
  ownerCreated: OwnerCreatedCheckpoint,
  identity: ApprovalIdentityLike,
): void {
  const expected = approvalReceiptExpectation(ownerCreated, identity);
  persistOwnerUiReceipt(checkpointPath, {
    proofId: expected.proofId,
    seedFingerprint: expected.seedFingerprint,
    manifestStage: expected.manifestStage,
    manifestGeneration: expected.manifestGeneration,
    entityIds: expected.entityIds,
    observations: ownerApprovalObservations,
  });
}

function evidence(
  criterionId: CriterionId,
  proofId: string,
  checkpoint: OwnerCreatedCheckpoint | ApprovedCheckpoint,
): OwnerEvidence {
  return {
    criterionId,
    proofId,
    outcome: "passed",
    generation: checkpoint.generation,
    seedFingerprint: checkpoint.seedFingerprint,
    entityIds: {
      projectId: checkpoint.projectId,
      planId: checkpoint.planId,
      planRevisionId: checkpoint.planRevisionId,
      taskIds: checkpoint.taskIds,
      ...(checkpoint.stage === "approved" ? { factoryRunId: checkpoint.factoryRunId } : {}),
    },
    evidenceSource: "ui+postgres",
    timestamp: new Date().toISOString(),
  };
}

export async function authorOwnerJourney(
  seed: OwnerSeed,
  environment: Readonly<Record<string, string | undefined>> = process.env,
): Promise<{ checkpoint: OwnerCreatedCheckpoint; evidence: readonly OwnerEvidence[] }> {
  const infra = infrastructure(environment);
  const { chromium } = await import(infra.playwrightModule);
  const browser = await chromium.launch({ headless: true });
  const projectName = `AWP owner journey ${seed.journeyKey}`;
  const planTitle = `Owner journey plan ${seed.journeyKey}`;
  try {
    const page = await browser.newPage();
    await loginBrowser(page, infra.webUrl, infra.operatorPassword);
    await page.goto(new URL("/projects", infra.webUrl).href, { waitUntil: "networkidle" });
    await page.getByRole("heading", { name: "Projects" }).waitFor();
    await page.getByLabel("Name").fill(projectName);
    await page.getByLabel("Repository URL").fill(seed.repository.remoteUrl);
    await page.getByRole("button", { name: "Create Project" }).click();
    await page.waitForURL(/\/projects\/[^/?]+$/u);
    const projectId = decodeURIComponent(new URL(page.url()).pathname.split("/").pop()!);
    const [persistedProjectId, repositoryUrl] = oneRow(
      infra.databaseUrl,
      `select id, repository_url from projects where id = ${sql(projectId)} and name = ${sql(projectName)}`,
      "created Project",
    );
    assert.equal(persistedProjectId, projectId);
    assert.equal(repositoryUrl, seed.repository.remoteUrl);
    await page.goto(new URL("/projects", infra.webUrl).href, { waitUntil: "networkidle" });
    assert.equal(await page.getByText(projectName, { exact: true }).count(), 1);
    await page.reload({ waitUntil: "networkidle" });
    assert.equal(await page.getByText(projectName, { exact: true }).count(), 1);

    const projectUrl = new URL(`/projects/${encodeURIComponent(projectId)}`, infra.webUrl);
    projectUrl.searchParams.set("tab", "vision");
    await page.goto(projectUrl.href, { waitUntil: "networkidle" });
    await page.getByLabel("Vision").fill(vision);
    await page.getByRole("button", { name: "Save ProjectVision" }).click();
    await page.getByText(vision, { exact: true }).waitFor();
    const [visionVersionId, visionSequence, visionSummary] = oneRow(
      infra.databaseUrl,
      `select id, sequence, summary from project_vision_versions where project_id=${sql(projectId)}`,
      "versioned ProjectVision",
    );
    assert.equal(visionSequence, "1");
    assert.equal(visionSummary, vision);
    await page.reload({ waitUntil: "networkidle" });
    await page.getByText(vision, { exact: true }).waitFor();

    projectUrl.searchParams.set("tab", "goals");
    await page.goto(projectUrl.href, { waitUntil: "networkidle" });
    await page.getByLabel("Goal title").fill(goalTitle);
    await page.getByLabel("Launch criteria").fill(criterion);
    await page.getByRole("button", { name: "Create Goal" }).click();
    await page.getByText(goalTitle, { exact: true }).waitFor();
    const [persistedGoalTitle, persistedCriterion] = oneRow(
      infra.databaseUrl,
      `select title, success_criteria->>0 from goals where project_id=${sql(projectId)}`,
      "created Goal",
    );
    assert.equal(persistedGoalTitle, goalTitle);
    assert.equal(persistedCriterion, criterion);

    projectUrl.searchParams.set("tab", "plans");
    await page.goto(projectUrl.href, { waitUntil: "networkidle" });
    await page.getByLabel("Plan title").fill(planTitle);
    await page.getByLabel("Tasks (one per line, at least three)").fill(taskTitles.join("\n"));
    await page.getByRole("button", { name: "Create Plan" }).click();

    const [planId] = oneRow(
      infra.databaseUrl,
      `select id from plans where project_id = ${sql(projectId)} and title = ${sql(planTitle)}`,
      "created Plan",
    );
    const [planRevisionId, revisionSequence, revisionVisionId] = oneRow(
      infra.databaseUrl,
      `select id, sequence, project_vision_version_id from plan_revisions where project_id = ${sql(projectId)} and plan_id = ${sql(planId)}`,
      "first PlanRevision",
    );
    assert.equal(revisionSequence, "1");
    assert.equal(revisionVisionId, visionVersionId);

    await page.goto(projectUrl.href, { waitUntil: "networkidle" });
    const taskRows = page.locator(`[data-plan-id="${planId}"] [data-task-id]`);
    const scopedRows = (await taskRows.count()) === 3 ? taskRows : page.locator("[data-task-id]");
    assert.equal(
      await scopedRows.count(),
      3,
      "exact Plan/Revision container must render three tasks",
    );
    const renderedTaskIds = await scopedRows.evaluateAll((rows: Element[]) =>
      rows.map((row) => row.getAttribute("data-task-id")),
    );
    assert.ok(renderedTaskIds.every((id: string | null): id is string => Boolean(id)));
    const persistedTasks = query(
      infra.databaseUrl,
      `select id, title from tasks where project_id = ${sql(projectId)} and plan_revision_id = ${sql(planRevisionId)} order by position`,
    )
      .split("\n")
      .map((row) => row.split("\t"));
    assert.deepEqual(
      persistedTasks.map((row) => row[1]),
      [...taskTitles],
    );
    const taskIds = persistedTasks.map((row) => row[0]!) as [string, string, string];
    assert.deepEqual(renderedTaskIds, taskIds);
    assert.equal(new Set(taskIds).size, 3);

    for (const [taskIndex, prerequisiteIndex] of [
      [1, 0],
      [2, 1],
    ] as const) {
      await scopedRows
        .nth(taskIndex)
        .getByLabel("Add prerequisite")
        .selectOption(taskIds[prerequisiteIndex]);
      await scopedRows.nth(taskIndex).getByRole("button", { name: "Add dependency" }).click();
    }
    assert.equal(
      query(
        infra.databaseUrl,
        `select count(*) from task_dependencies d join tasks t on t.id=d.task_id join tasks p on p.id=d.prerequisite_task_id where t.project_id=${sql(projectId)} and p.project_id=${sql(projectId)} and t.plan_revision_id=${sql(planRevisionId)} and p.plan_revision_id=${sql(planRevisionId)}`,
      ),
      "2",
    );
    await page.reload({ waitUntil: "networkidle" });
    const reloadedRows = page.locator("[data-task-id]");
    await reloadedRows
      .nth(1)
      .getByText(`Prerequisites: ${taskTitles[0]}`, { exact: true })
      .waitFor();
    await reloadedRows
      .nth(2)
      .getByText(`Prerequisites: ${taskTitles[1]}`, { exact: true })
      .waitFor();
    await reloadedRows.nth(1).getByText("Blocked", { exact: true }).waitFor();
    await reloadedRows.nth(2).getByText("Blocked", { exact: true }).waitFor();
    await reloadedRows.nth(0).getByLabel("Add prerequisite").selectOption(taskIds[2]);
    await reloadedRows.nth(0).getByRole("button", { name: "Add dependency" }).click();
    await reloadedRows
      .nth(0)
      .locator("[data-form-error]")
      .getByText(
        `Task dependency cycle: ${taskIds[0]} -> ${taskIds[2]} -> ${taskIds[1]} -> ${taskIds[0]}`,
        { exact: true },
      )
      .waitFor();
    assert.equal(
      query(
        infra.databaseUrl,
        `select count(*) from task_dependencies d join tasks t on t.id=d.task_id where t.project_id=${sql(projectId)} and t.plan_revision_id=${sql(planRevisionId)}`,
      ),
      "2",
    );

    const authoringReceipt = manifestFingerprint({
      projectId,
      projectName,
      repositoryUrl,
      visionVersionId,
      goalTitle: persistedGoalTitle,
      criterion: persistedCriterion,
      planId,
      planRevisionId,
      taskIds,
      taskTitles,
      dependencyCount: 2,
    });
    const ownerCreatedIdentity = {
      projectId,
      planId,
      planRevisionId,
      taskIds,
      authoringReceipt,
    };
    recordAuthoringUiReceipt(infra.checkpointPath, seed, ownerCreatedIdentity);
    const checkpoint = transitionToOwnerCreated(infra.checkpointPath, seed, ownerCreatedIdentity);
    return {
      checkpoint,
      evidence: ownerAuthoringProof.criterionIds.map((id) =>
        evidence(id, ownerAuthoringProof.proofId, checkpoint),
      ),
    };
  } finally {
    await browser.close();
  }
}

export async function ensureRecoveredOwnerAuthoringUi(
  seed: OwnerSeed,
  identity: OwnerCreatedIdentityLike,
  environment: Readonly<Record<string, string | undefined>> = process.env,
): Promise<void> {
  const infra = infrastructure(environment);
  const expected = authoringReceiptExpectation(seed, identity);
  if (loadOwnerUiReceipt(infra.checkpointPath, expected)) return;

  const { chromium } = await import(infra.playwrightModule);
  const browser = await chromium.launch({ headless: true });
  const projectName = `AWP owner journey ${seed.journeyKey}`;
  try {
    const page = await browser.newPage();
    await loginBrowser(page, infra.webUrl, infra.operatorPassword);
    await page.goto(new URL("/projects", infra.webUrl).href, { waitUntil: "networkidle" });
    assert.equal(await page.getByText(projectName, { exact: true }).count(), 1);
    await page.reload({ waitUntil: "networkidle" });
    assert.equal(await page.getByText(projectName, { exact: true }).count(), 1);

    const projectUrl = new URL(`/projects/${encodeURIComponent(identity.projectId)}`, infra.webUrl);
    projectUrl.searchParams.set("tab", "vision");
    await page.goto(projectUrl.href, { waitUntil: "networkidle" });
    await page.getByText(vision, { exact: true }).waitFor();
    await page.reload({ waitUntil: "networkidle" });
    await page.getByText(vision, { exact: true }).waitFor();

    projectUrl.searchParams.set("tab", "plans");
    await page.goto(projectUrl.href, { waitUntil: "networkidle" });
    const planRows = page.locator(`[data-plan-id="${identity.planId}"] [data-task-id]`);
    const rows = (await planRows.count()) === 3 ? planRows : page.locator("[data-task-id]");
    assert.equal(await rows.count(), 3);
    const renderedTaskIds = await rows.evaluateAll((elements: Element[]) =>
      elements.map((element) => element.getAttribute("data-task-id")),
    );
    assert.deepEqual(renderedTaskIds, [...identity.taskIds]);
    await rows.nth(1).getByText(`Prerequisites: ${taskTitles[0]}`, { exact: true }).waitFor();
    await rows.nth(2).getByText(`Prerequisites: ${taskTitles[1]}`, { exact: true }).waitFor();
    await rows.nth(1).getByText("Blocked", { exact: true }).waitFor();
    await rows.nth(2).getByText("Blocked", { exact: true }).waitFor();
    await rows.nth(0).getByLabel("Add prerequisite").selectOption(identity.taskIds[2]!);
    await rows.nth(0).getByRole("button", { name: "Add dependency" }).click();
    await rows
      .nth(0)
      .locator("[data-form-error]")
      .getByText(
        `Task dependency cycle: ${identity.taskIds[0]} -> ${identity.taskIds[2]} -> ${identity.taskIds[1]} -> ${identity.taskIds[0]}`,
        { exact: true },
      )
      .waitFor();
    assert.equal(
      query(
        infra.databaseUrl,
        `select count(*) from task_dependencies d join tasks t on t.id=d.task_id where t.project_id=${sql(identity.projectId)} and t.plan_revision_id=${sql(identity.planRevisionId)}`,
      ),
      "2",
    );
    recordAuthoringUiReceipt(infra.checkpointPath, seed, identity);
  } finally {
    await browser.close();
  }
}

export async function ensureRecoveredOwnerApprovalUi(
  ownerCreated: OwnerCreatedCheckpoint,
  identity: ApprovalIdentityLike,
  environment: Readonly<Record<string, string | undefined>> = process.env,
): Promise<void> {
  const infra = infrastructure(environment);
  const expected = approvalReceiptExpectation(ownerCreated, identity);
  if (loadOwnerUiReceipt(infra.checkpointPath, expected)) return;

  const { chromium } = await import(infra.playwrightModule);
  const browser = await chromium.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await loginBrowser(page, infra.webUrl, infra.operatorPassword);
    const projectUrl = new URL(
      `/projects/${encodeURIComponent(ownerCreated.projectId)}`,
      infra.webUrl,
    );
    projectUrl.searchParams.set("tab", "factory-runs");
    await page.goto(projectUrl.href, { waitUntil: "networkidle" });
    await page.getByText(identity.factoryRunId, { exact: true }).waitFor();

    projectUrl.searchParams.set("tab", "plans");
    await page.goto(projectUrl.href, { waitUntil: "networkidle" });
    await page.getByText("Approved", { exact: true }).waitFor();
    const firstTask = page.locator(`[data-task-id="${ownerCreated.taskIds[0]}"]`);
    const causalStatus =
      /^(?:Dispatched|Queued|Executing|Waiting|Review|Correction|Completed|Cancelled|Failed)$/u;
    await firstTask.getByText(causalStatus).waitFor();
    await page.reload({ waitUntil: "networkidle" });
    await page.getByText("Approved", { exact: true }).waitFor();
    await firstTask.getByText(causalStatus).waitFor();
    recordApprovalUiReceipt(infra.checkpointPath, ownerCreated, identity);
  } finally {
    await browser.close();
  }
}

export async function approveOwnerJourney(
  ownerCreated: OwnerCreatedCheckpoint,
  environment: Readonly<Record<string, string | undefined>> = process.env,
): Promise<{ checkpoint: ApprovedCheckpoint; evidence: readonly OwnerEvidence[] }> {
  const infra = infrastructure(environment);
  const { chromium } = await import(infra.playwrightModule);
  const browser = await chromium.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await loginBrowser(page, infra.webUrl, infra.operatorPassword);
    const plansUrl = new URL(
      `/projects/${encodeURIComponent(ownerCreated.projectId)}`,
      infra.webUrl,
    );
    plansUrl.searchParams.set("tab", "plans");
    await page.goto(plansUrl.href, { waitUntil: "networkidle" });
    const launch = page.locator(
      `[data-plan-launch][data-project-id="${ownerCreated.projectId}"][data-plan-id="${ownerCreated.planId}"]`,
    );
    await launch.getByLabel("Account").selectOption(ownerCreated.agentAccountId);
    await launch.getByLabel("Model").fill(ownerCreated.agentModel);
    await launch.getByRole("button", { name: "Approve & start FactoryRun" }).click();
    await page.waitForURL(/tab=factory-runs/u);

    const [factoryRunId, accountId, model, runStatus, runReason, factoryTaskId] = oneRow(
      infra.databaseUrl,
      `select id, account_id, model, status, reason, task_id from factory_runs where project_id=${sql(ownerCreated.projectId)} and plan_revision_id=${sql(ownerCreated.planRevisionId)}`,
      "approved FactoryRun",
    );
    assert.equal(accountId, ownerCreated.agentAccountId);
    assert.equal(model, ownerCreated.agentModel);
    assert.equal(runStatus, "queued");
    assert.equal(runReason, "Automatic dependency-legal dispatch after Plan approval");
    assert.equal(factoryTaskId, ownerCreated.taskIds[0]);
    assert.equal(
      query(
        infra.databaseUrl,
        `select count(*) from factory_runs where project_id=${sql(ownerCreated.projectId)} and plan_revision_id=${sql(ownerCreated.planRevisionId)}`,
      ),
      "1",
    );
    await page.getByText(factoryRunId, { exact: true }).waitFor();

    const [planStatus] = oneRow(
      infra.databaseUrl,
      `select status from plans where id=${sql(ownerCreated.planId)} and project_id=${sql(ownerCreated.projectId)}`,
      "approved Plan",
    );
    assert.equal(planStatus, "approved");
    const [firstTaskStatus] = oneRow(
      infra.databaseUrl,
      `select status from tasks where id=${sql(ownerCreated.taskIds[0]!)} and plan_revision_id=${sql(ownerCreated.planRevisionId)}`,
      "dispatched first Task",
    );
    assert.equal(firstTaskStatus, "dispatched");

    await page.goto(plansUrl.href, { waitUntil: "networkidle" });
    await page.getByText("Approved", { exact: true }).waitFor();
    await page
      .locator(`[data-task-id="${ownerCreated.taskIds[0]}"]`)
      .getByText("Dispatched", { exact: true })
      .waitFor();
    await page.reload({ waitUntil: "networkidle" });
    await page.getByText("Approved", { exact: true }).waitFor();
    await page
      .locator(`[data-task-id="${ownerCreated.taskIds[0]}"]`)
      .getByText("Dispatched", { exact: true })
      .waitFor();
    assert.equal(await page.locator("[data-task-id]").count(), 3);
    const approvalReceipt = manifestFingerprint({
      projectId: ownerCreated.projectId,
      planId: ownerCreated.planId,
      planRevisionId: ownerCreated.planRevisionId,
      planStatus,
      firstTaskId: ownerCreated.taskIds[0],
      firstTaskStatus,
      factoryRunId,
      factoryTaskId,
      accountId,
      model,
      runStatus,
      runReason,
    });
    const approvalIdentity = {
      factoryRunId,
      firstTaskId: ownerCreated.taskIds[0]!,
      approvalReceipt,
    };
    recordApprovalUiReceipt(infra.checkpointPath, ownerCreated, approvalIdentity);
    const checkpoint = transitionToApproved(infra.checkpointPath, ownerCreated, approvalIdentity);
    return {
      checkpoint,
      evidence: (["AC-10", "AC-11"] as const).map((id) =>
        evidence(id, ownerApprovalProof.proofId, checkpoint),
      ),
    };
  } finally {
    await browser.close();
  }
}
