import { afterEach, beforeEach, describe, expect, test } from "bun:test";
import type { Server } from "bun";
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
import { createHash } from "node:crypto";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { Journal } from "../journal";
import { CollectorState } from "../state";
import { startServer } from "../server";
import { RequestsStore } from "./requests-store";
import type { RequestStoryV1 } from "@overdeck/report-contract";

const TOKEN = "requests-routes-token";
let dir = "";
let server: Server<undefined> | undefined;
let previousStateDir: string | undefined;
let requests: RequestsStore | undefined;

function requestBody(id = "req-a") {
  return { id, title: "Request A", project: "overdeck", state: "asked" as const, priority: "HIGH", asked_at: "2026-08-14T00:00:00.000Z", updated_at: "2026-08-14T00:00:00.000Z" };
}

describe("requests routes", () => {
  beforeEach(() => {
    dir = mkdtempSync(join(tmpdir(), "collector-requests-routes-"));
    previousStateDir = process.env.OVERDECK_STATE_DIR;
    process.env.OVERDECK_STATE_DIR = dir;
  });
  afterEach(() => {
    server?.stop(true); server = undefined;
    if (previousStateDir === undefined) delete process.env.OVERDECK_STATE_DIR;
    else process.env.OVERDECK_STATE_DIR = previousStateDir;
    rmSync(dir, { recursive: true, force: true });
  });
  function start(
    withStore = true,
    sendRequestAnnouncement: (channel: string, text: string) => Promise<string> = async () => "message-a",
    loadFactoryRequestRunLinks: (requestId: string) => import("../adapters/factory").FactoryRequestRunLinksResult = () => ({ available: false, links: [] }),
  ): string {
    const state = new CollectorState(new Journal(join(dir, "items.jsonl")));
    requests = withStore ? new RequestsStore(join(dir, "requests.sqlite")) : undefined;
    server = startServer({ host: "127.0.0.1", port: 0, token: TOKEN, state, requests, sendRequestAnnouncement, loadFactoryRequestRunLinks });
    return `http://127.0.0.1:${server.port}`;
  }
  function get(origin: string) { return fetch(`${origin}/requests`, { headers: { authorization: `Bearer ${TOKEN}` } }); }
  function post(origin: string, path: string, body: unknown) { return fetch(`${origin}${path}`, { method: "POST", headers: { authorization: `Bearer ${TOKEN}`, "content-type": "application/json" }, body: JSON.stringify(body) }); }

  test("lists, creates, updates, and journals requests", async () => {
    const origin = start();
    expect(await (await get(origin)).json()).toEqual({ requests: [], checks: [] });
    const created = await post(origin, "/requests", { ...requestBody(), factory_run_id: "adw-req-a" });
    expect(created.status).toBe(201);
    expect(await created.json()).toMatchObject({ request: { id: "req-a", state: "asked", factory_run_id: "adw-req-a" } });
    const updated = await post(origin, "/requests/req-a", { state: "in_flight", worker: "worker-a", actor: "worker-a" });
    expect(updated.status).toBe(200);
    expect(await updated.json()).toMatchObject({ request: { state: "in_flight", worker: "worker-a", factory_run_id: "adw-req-a" } });
    const entries = readFileSync(join(dir, "actions.jsonl"), "utf8").trim().split("\n").map((line: string) => JSON.parse(line));
    expect(entries.map((entry: { verb: string }) => entry.verb)).toEqual(["requests.create", "requests.update"]);
    expect(entries[0]).toMatchObject({ requestedBy: "collector", result: "ok", rc: 0 });
  });

  test("projects recorded worker claims into the receipt trail with the real actor and timestamp", async () => {
    const origin = start();
    const created = await post(origin, "/requests", {
      ...requestBody(), state: "in_flight", worker: "codex", worker_host: "buildbox-1", updated_at: "2026-08-14T01:00:00.000Z",
    });
    expect(created.status).toBe(201);
    expect((await created.json())).toMatchObject({ request: {
      receipt_trail: [{ request_id: "req-a", at: "2026-08-14T01:00:00.000Z", kind: "claimed", line: "Work started on this request.", meta: { worker: "codex", host: "buildbox-1" } }],
    } });
  });

  test("projects an honest empty receipt trail when no lifecycle fact was recorded", async () => {
    const origin = start();
    expect(await (await get(origin)).json()).toEqual({ requests: [], checks: [] });
    await post(origin, "/requests", requestBody());
    expect(await (await get(origin)).json()).toMatchObject({ requests: [expect.objectContaining({ id: "req-a", receipt_trail: [] })] });
  });

  test("serves the immutable request story only to authenticated callers", async () => {
    const origin = start();
    const original = "  Preserve this exact ask.\nSecond line.  ";
    expect((await post(origin, "/requests", {
      ...requestBody(),
      original_body: original,
      original_body_format: "markdown",
      intake_source: "request-hook",
      intake_source_event_id: "source-event-a",
    })).status).toBe(201);

    const response = await fetch(`${origin}/requests/req-a/story`, { headers: { authorization: `Bearer ${TOKEN}` } });
    expect(response.status).toBe(200);
    expect(await response.json()).toMatchObject({ story: {
      schemaVersion: 1,
      requestId: "req-a",
      originalRequest: { body: original, format: "markdown", source: "request-hook" },
      events: [{ kind: "intake", sourceId: "request-hook", sourceRecordId: "source-event-a", legacy: false }],
      coverage: expect.arrayContaining([{ fact: "original_request", status: "complete", sourceId: "request-hook" }]),
    } });
    expect((await fetch(`${origin}/requests/req-a/story`)).status).toBe(401);
    expect((await fetch(`${origin}/requests/missing/story`, { headers: { authorization: `Bearer ${TOKEN}` } })).status).toBe(404);
  });

  test("adds only exact Factory run links to a request story", async () => {
    const origin = start(true, undefined, (requestId) => ({
      available: true,
      links: requestId === "req-a" ? [{
        requestId,
        adwId: "adw-exact-42",
        linkedAt: "2026-08-18T00:05:00.000Z",
        startedAt: "2026-08-18T00:05:01.000Z",
        status: "running",
        repo: "/work/overdeck",
      }] : [],
    }));
    expect((await post(origin, "/requests", { ...requestBody("req-a"), title: "Same words" })).status).toBe(201);
    expect((await post(origin, "/requests", { ...requestBody("req-similar"), title: "Same words", skipDedup: true })).status).toBe(201);

    const linked = (await (await fetch(`${origin}/requests/req-a/story`, { headers: { authorization: `Bearer ${TOKEN}` } })).json()) as { story: RequestStoryV1 };
    expect(linked.story.links).toEqual([expect.objectContaining({
      kind: "factory_run",
      targetId: "adw-exact-42",
      sourceId: "factory-trace",
    })]);
    expect(linked.story.events).toContainEqual(expect.objectContaining({
      kind: "run_linked",
      sourceEventId: "request-link:adw-exact-42",
      payload: { runId: "adw-exact-42", status: "running" },
    }));
    expect(linked.story.coverage).toContainEqual({ fact: "work_evidence", status: "complete", sourceId: "request-evidence-links" });

    const unlinked = (await (await fetch(`${origin}/requests/req-similar/story`, { headers: { authorization: `Bearer ${TOKEN}` } })).json()) as { story: RequestStoryV1 };
    expect(unlinked.story.links).toEqual([]);
    expect(unlinked.story.events.some((event: { kind: string }) => event.kind === "run_linked")).toBe(false);
    expect(unlinked.story.coverage).toContainEqual(expect.objectContaining({ fact: "work_evidence", status: "unavailable" }));
  });

  test("accepts idempotent durable evidence and reports producer delivery health", async () => {
    const origin = start();
    const envelope = {
      schemaVersion: 1,
      requestId: "durable-route",
      sourceId: "claude-task-hook",
      sourceEventId: "session-a:task-1:000-intake",
      producerId: "session-a",
      occurredAt: "2026-08-18T00:00:00.000Z",
      event: {
        kind: "intake",
        summary: "Request recorded from the session task list.",
        actor: { type: "agent", id: "session-a" },
        sessionId: "session-a",
        payload: { taskId: "1" },
      },
      createRequest: {
        title: "Durable lifecycle",
        project: "overdeck",
        priority: "NORMAL",
        origin: "agent-judgement",
        originalBody: "Record this exact lifecycle.",
        originalBodyFormat: "plain_text",
        sessionId: "session-a",
      },
    };
    const created = await post(origin, "/requests/durable-route/evidence", envelope);
    expect(created.status).toBe(201);
    expect(await created.json()).toEqual({ acknowledgement: {
      requestId: "durable-route",
      sourceId: "claude-task-hook",
      sourceEventId: "session-a:task-1:000-intake",
      replayed: false,
    } });
    const replayed = await post(origin, "/requests/durable-route/evidence", envelope);
    expect(replayed.status).toBe(200);
    expect(await replayed.json()).toMatchObject({ acknowledgement: { replayed: true } });

    const diff = Buffer.from("diff --git a/a.ts b/a.ts\n+exact evidence\n");
    const digest = `sha256:${createHash("sha256").update(diff).digest("hex")}`;
    const change = await post(origin, "/requests/durable-route/evidence", {
      schemaVersion: 1,
      requestId: "durable-route",
      sourceId: "factory-trace",
      sourceEventId: "run-a:change-a",
      producerId: "run-a",
      occurredAt: "2026-08-18T00:02:00.000Z",
      event: { kind: "change_recorded", summary: "Change recorded.", actor: { type: "machinery" }, payload: {} },
      links: [{ kind: "change", targetSource: "factory-trace", targetId: "change-a" }],
      attachments: [{
        digest,
        contentBase64: diff.toString("base64"),
        byteCount: diff.byteLength,
        mediaType: "text/x-diff",
        redactionStatus: "redacted",
        truncated: false,
      }],
    });
    expect(change.status).toBe(201);
    const attachment = await fetch(`${origin}/requests/durable-route/attachments/${encodeURIComponent(digest)}`, {
      headers: { authorization: `Bearer ${TOKEN}` },
    });
    expect(attachment.status).toBe(200);
    expect(attachment.headers.get("content-type")).toBe("text/x-diff");
    expect(Buffer.from(await attachment.arrayBuffer())).toEqual(diff);
    expect((await fetch(`${origin}/requests/other/attachments/${encodeURIComponent(digest)}`, {
      headers: { authorization: `Bearer ${TOKEN}` },
    })).status).toBe(404);

    expect((await post(origin, "/requests/other/evidence", envelope)).status).toBe(400);
    expect((await post(origin, "/requests/durable-route/evidence", {
      ...envelope,
      sourceEventId: "legacy-kind",
      event: { ...envelope.event, kind: "legacy_receipt" },
      createRequest: undefined,
    })).status).toBe(400);
    expect((await post(origin, "/requests/blank-intake/evidence", {
      ...envelope,
      requestId: "blank-intake",
      sourceEventId: "blank-intake",
      createRequest: { ...envelope.createRequest, originalBody: "   \n" },
    })).status).toBe(400);
    expect((await post(origin, "/requests/missing-create/evidence", {
      ...envelope,
      requestId: "missing-create",
      sourceEventId: "missing-create",
      createRequest: undefined,
    })).status).toBe(400);
    expect((await post(origin, "/requests/unexpected-create/evidence", {
      ...envelope,
      requestId: "unexpected-create",
      sourceEventId: "unexpected-create",
      event: { ...envelope.event, kind: "progress" },
    })).status).toBe(400);
    expect((await fetch(`${origin}/requests/durable-route/evidence`, {
      method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(envelope),
    })).status).toBe(401);

    const health = await post(origin, "/requests/durable-route/evidence/health", {
      schemaVersion: 1,
      requestId: "durable-route",
      sourceId: "claude-task-hook",
      producerId: "session-a",
      reportedAt: "2026-08-18T00:01:00.000Z",
      queueCount: 1,
      oldestQueuedAt: "2026-08-18T00:00:30.000Z",
      quarantineCount: 0,
      lastAcknowledgedAt: "2026-08-18T00:00:10.000Z",
    });
    expect(health.status).toBe(200);
    const story = await fetch(`${origin}/requests/durable-route/story`, { headers: { authorization: `Bearer ${TOKEN}` } });
    expect(await story.json()).toMatchObject({ story: {
      events: expect.arrayContaining([expect.objectContaining({
        sourceEventId: "session-a:task-1:000-intake",
        producerId: "session-a",
        summary: "Request recorded from the session task list.",
        payload: { taskId: "1" },
      })]),
      coverage: expect.arrayContaining([{
        fact: "activity_delivery",
        status: "pending_delivery",
        sourceId: "claude-task-hook",
        reason: "1 recorded update is waiting for delivery.",
      }]),
    } });
  });

  test("rejects a second intake that targets an existing request id", async () => {
    const origin = start();
    expect((await post(origin, "/requests", requestBody("existing"))).status).toBe(201);
    const response = await post(origin, "/requests/existing/evidence", {
      schemaVersion: 1,
      requestId: "existing",
      sourceId: "source-a",
      sourceEventId: "event-b",
      producerId: "producer-a",
      occurredAt: "2026-08-18T00:00:00.000Z",
      event: { kind: "intake", summary: "Conflicting intake.", actor: { type: "owner" }, payload: {} },
      createRequest: {
        title: "Request A", project: "overdeck", priority: "HIGH", origin: "owner",
        originalBody: "Looks similar but is a distinct ask.", originalBodyFormat: "plain_text",
      },
    });
    expect(response.status).toBe(409);
    expect(await response.json()).toEqual({ error: "conflicting-evidence" });
  });

  test("projects GitHub checks on the requests surface, including unmatched runs", async () => {
    const origin = start();
    requests!.recordGithubCheck({ repo: "owner/overdeck", run_id: 42, name: "collector-tests", status: "completed", conclusion: "success", sha: "abc123", branch: "wt/arc-ci", started_at: null, completed_at: "2026-08-16T10:00:00Z", observed_at: "2026-08-16T10:00:01Z" });
    const body = await (await get(origin)).json() as { checks: Array<{ run_id: number; work_key: string | null }> };
    expect(body.checks).toEqual([expect.objectContaining({ run_id: 42, work_key: null })]);
  });

  test("keeps the production not-yet-available path explicit when the request registry is not installed", async () => {
    const origin = start(false);
    expect((await get(origin)).status).toBe(404);
  });

  test("creation announces exactly once with the verbatim text shape", async () => {
    const sent: Array<{ channel: string; text: string }> = [];
    const origin = start(true, async (channel, text) => { sent.push({ channel, text }); return "message-a"; });
    expect((await post(origin, "/requests", requestBody())).status).toBe(201);
    await Promise.resolve();
    expect(sent).toEqual([{ channel: "overdeck", text: "New request #req-a: Request A\nReply to this thread to steer it." }]);
  });

  test("dedup does not announce", async () => {
    const sent: Array<{ channel: string; text: string }> = [];
    const origin = start(true, async (channel, text) => { sent.push({ channel, text }); return "message-a"; });
    expect((await post(origin, "/requests", requestBody("req-existing"))).status).toBe(201);
    await Promise.resolve();
    expect((await post(origin, "/requests", { ...requestBody("req-duplicate"), title: "request a" })).status).toBe(409);
    expect(sent).toHaveLength(1);
  });

  test("maps an exact-key constraint race to the same existing-row 409 response", async () => {
    const origin = start();
    const requestStore = requests!;
    const originalCreate = requestStore.create.bind(requestStore);
    let injected = false;
    requestStore.create = ((input: Parameters<RequestsStore["create"]>[0]) => {
      if (!injected && input.id === "req-racing") {
        injected = true;
        originalCreate({ ...requestBody("req-existing"), plan_ref: "work-key" });
      }
      return originalCreate(input);
    }) as typeof requestStore.create;
    const response = await post(origin, "/requests", { ...requestBody("req-racing"), plan_ref: "work-key" });
    expect(response.status).toBe(409);
    expect(await response.json()).toMatchObject({ error: "duplicate", match: { confidence: "confident", request: { id: "req-existing", plan_ref: "work-key" } } });
    expect(requests!.list()).toHaveLength(1);
  });

  test("send failure leaves announced_at NULL and creation still returns the row", async () => {
    const origin = start(true, async () => { throw new Error("no bot"); });
    const created = await post(origin, "/requests", requestBody());
    expect(created.status).toBe(201);
    expect(await created.json()).toMatchObject({ request: { id: "req-a", announced_at: null } });
    await Promise.resolve();
    expect(requests?.get("req-a")).toMatchObject({ announced_at: null });
  });

  test("rejects duplicate, invalid, and unknown request mutations", async () => {
    const origin = start();
    expect((await post(origin, "/requests", requestBody())).status).toBe(201);
    expect((await post(origin, "/requests", requestBody())).status).toBe(409);
    expect((await post(origin, "/requests", { ...requestBody("bad"), state: "invalid" })).status).toBe(400);
    expect((await post(origin, "/requests", { ...requestBody("fabricated-orphan"), state: "orphaned" })).status).toBe(400);
    expect(requests!.get("fabricated-orphan")).toBeNull();
    expect((await post(origin, "/requests", { ...requestBody("reasonless-cancel"), state: "canceled" })).status).toBe(400);
    expect(requests!.get("reasonless-cancel")).toBeNull();
    expect((await post(origin, "/requests/missing", { priority: "LOW" })).status).toBe(404);
  });

  test("state transitions are server validated, return current state on 409, and record who/when/reason", async () => {
    const origin = start();
    await post(origin, "/requests", { ...requestBody(), plan_ref: "task-lifecycle" });
    const missingReason = await post(origin, "/requests/task-lifecycle", { state: "blocked_needs_owner", actor: "codex" });
    expect(missingReason.status).toBe(400);
    expect((await post(origin, "/requests/task-lifecycle", { state: "blocked_needs_owner", actor: "codex", reason: "Need the token" })).status).toBe(200);
    const invalid = await post(origin, "/requests/task-lifecycle", { state: "shipped", actor: "codex" });
    expect(invalid.status).toBe(409);
    expect(await invalid.json()).toEqual({ error: "invalid-transition", current_state: "blocked_needs_owner", requested_state: "shipped" });
    expect((await post(origin, "/requests/task-lifecycle", { state: "in_flight", actor: "codex", worker: "codex" })).status).toBe(200);
    const blocked = await post(origin, "/requests/task-lifecycle", { state: "blocked_needs_owner", actor: "codex", reason: "Please provide the registry token." });
    expect(blocked.status).toBe(200);
    expect(await blocked.json()).toMatchObject({ request: { state: "blocked_needs_owner", detail: "Please provide the registry token.", transition_trail: [
      { from_state: "asked", to_state: "blocked_needs_owner", actor: "codex", reason: "Need the token" },
      { from_state: "blocked_needs_owner", to_state: "in_flight", actor: "codex", reason: null },
      { from_state: "in_flight", to_state: "blocked_needs_owner", actor: "codex", reason: "Please provide the registry token." },
    ] } });
    expect((await post(origin, "/requests/task-lifecycle", { state: "in_flight", actor: "owner" })).status).toBe(200);
    expect((await post(origin, "/requests/task-lifecycle", { state: "shipped", actor: "lander" })).status).toBe(200);
  });

  test("rejects fabricated recovery state and accepts a reasoned terminal cancellation", async () => {
    const origin = start();
    await post(origin, "/requests", { ...requestBody(), state: "in_flight", session_id: "session-a" });
    const fabricated = await post(origin, "/requests/req-a", { state: "orphaned", actor: "worker", reason: "Worker stopped." });
    expect(fabricated.status).toBe(409);
    expect(await fabricated.json()).toEqual({ error: "invalid-transition", current_state: "in_flight", requested_state: "orphaned" });
    const missingReason = await post(origin, "/requests/req-a", { state: "canceled", actor: "owner" });
    expect(missingReason.status).toBe(400);
    const canceled = await post(origin, "/requests/req-a", { state: "canceled", actor: "owner", reason: "Superseded by the installed path." });
    expect(canceled.status).toBe(200);
    expect(await canceled.json()).toMatchObject({ request: { state: "canceled", detail: "Superseded by the installed path." } });
  });

  test("POST /requests/:id/answer records the owner's words in both trails and resumes blocked work", async () => {
    const origin = start();
    await post(origin, "/requests", requestBody());
    await post(origin, "/requests/req-a", { state: "blocked_needs_owner", actor: "codex", reason: "Which release should ship?" });
    const answered = await post(origin, "/requests/req-a/answer", { answer: "  Ship the canary release.  " });
    expect(answered.status).toBe(200);
    const body = await answered.json() as { request: { transition_trail: Array<{ from_state: string; to_state: string; actor: string; reason: string | null }>; receipt_trail: Array<{ kind: string; line: string; meta: { worker: string } }> }; factory_delivery: string };
    expect(body).toMatchObject({
      factory_delivery: "not-applicable",
      request: {
        state: "in_flight",
        detail: null,
      },
    });
    expect(body.request.transition_trail).toContainEqual(expect.objectContaining({ from_state: "blocked_needs_owner", to_state: "in_flight", actor: "owner", reason: "Ship the canary release." }));
    expect(body.request.receipt_trail).toContainEqual(expect.objectContaining({ kind: "progress", line: "Owner answered the request.", meta: { worker: "owner" } }));
  });

  test("POST /requests/:id/answer rejects an empty answer and a wrong-state answer with the current state", async () => {
    const origin = start();
    await post(origin, "/requests", requestBody());
    const empty = await post(origin, "/requests/req-a/answer", { answer: "   " });
    expect(empty.status).toBe(400);
    expect(await empty.json()).toEqual({ error: "invalid-answer", current_state: "asked" });
    const wrongState = await post(origin, "/requests/req-a/answer", { answer: "Proceed", next_state: "shipped" });
    expect(wrongState.status).toBe(409);
    expect(await wrongState.json()).toEqual({ error: "invalid-transition", current_state: "asked", requested_state: "shipped" });
  });

  test("POST /requests/:id/answer routes factory decisions through the factory action seam", async () => {
    const delivered: unknown[] = [];
    start(true);
    server!.stop(true);
    const state = new CollectorState(new Journal(join(dir, "items-factory-answer.jsonl")));
    const factoryGateway = { handle: async (request: Request, verb: string) => {
      delivered.push({ verb, body: await request.json() });
      return Response.json({ ok: true });
    } };
    server = startServer({ host: "127.0.0.1", port: 0, token: TOKEN, state, requests, actionGateway: factoryGateway });
    const factoryOrigin = `http://127.0.0.1:${server.port}`;
    await post(factoryOrigin, "/requests", { ...requestBody(), plan_ref: "factory-decision-dec-42" });
    await post(factoryOrigin, "/requests/req-a", { state: "blocked_needs_owner", actor: "factory-adapter", reason: "Choose a release" });
    const answer = await post(factoryOrigin, "/requests/req-a/answer", { answer: "canary" });
    expect(answer.status).toBe(200);
    expect(await answer.json()).toMatchObject({ factory_delivery: "delivered" });
    expect(delivered).toEqual([{ verb: "factory.decision.answer", body: { args: { decisionId: "dec-42", choice: "canary" }, requestedBy: "owner" } }]);
  });

  test("POST /requests/:id/answer names a factory delivery gap when the action seam is unavailable", async () => {
    const origin = start();
    await post(origin, "/requests", { ...requestBody(), plan_ref: "factory-decision-dec-gap" });
    await post(origin, "/requests/req-a", { state: "blocked_needs_owner", actor: "factory-adapter", reason: "Choose a release" });
    const answer = await post(origin, "/requests/req-a/answer", { answer: "canary" });
    expect(answer.status).toBe(200);
    const body = await answer.json() as { factory_delivery: string; request: { receipt_trail: Array<{ kind: string; line: string }> } };
    expect(body.factory_delivery).toBe("gap");
    expect(body.request.receipt_trail).toContainEqual(expect.objectContaining({ kind: "failed", line: "Factory decision delivery gap: the factory action gateway is unavailable." }));
  });

  test("announces once when a row enters blocked_needs_owner", async () => {
    const sent: Array<{ channel: string; text: string }> = [];
    const origin = start(true, async (channel, text) => { sent.push({ channel, text }); return "message-a"; });
    await post(origin, "/requests", { ...requestBody(), plan_ref: "owner-decision" });
    expect((await post(origin, "/requests/owner-decision", { state: "blocked_needs_owner", actor: "codex", reason: "Choose the release option." })).status).toBe(200);
    await new Promise((resolve) => setTimeout(resolve, 0));
    expect(sent).toEqual([
      { channel: "overdeck", text: "New request #req-a: Request A\nReply to this thread to steer it." },
      { channel: "Overdeck", text: "Blocked — needs you: Request A\nChoose the release option." },
    ]);
    expect((await post(origin, "/requests/owner-decision", { state: "in_flight", actor: "owner" })).status).toBe(200);
    expect(sent).toHaveLength(2);
  });

  test("dedup blocks a confident match, including against a shipped row, and reports the existing status", async () => {
    const origin = start();
    await post(origin, "/requests", { ...requestBody("req-shipped"), title: "Ship the diff viewer", state: "shipped", proof_url: "https://proof.example/diff-viewer" } as never);
    const dup = await post(origin, "/requests", { ...requestBody("req-dup"), title: "ship the diff viewer" });
    expect(dup.status).toBe(409);
    const body = (await dup.json()) as { error: string; match: { confidence: string; request: { id: string } } };
    expect(body.error).toBe("duplicate");
    expect(body.match.confidence).toBe("confident");
    expect(body.match.request).toMatchObject({ id: "req-shipped", state: "shipped", proof_url: "https://proof.example/diff-viewer" });
  });

  test("dedup surfaces a weak match without blocking creation", async () => {
    const origin = start();
    await post(origin, "/requests", { ...requestBody("req-a"), title: "Fix the login bug in auth middleware" });
    const weak = await post(origin, "/requests", { ...requestBody("req-b"), title: "fix login bug middleware flow" });
    expect(weak.status).toBe(201);
    const body = (await weak.json()) as { request: { id: string }; match?: { confidence: string } };
    expect(body.request.id).toBe("req-b");
    expect(body.match?.confidence).toBe("weak");
  });

  test("skipDedup bypasses the match check", async () => {
    const origin = start();
    await post(origin, "/requests", requestBody("req-a"));
    const forced = await post(origin, "/requests", { ...requestBody("req-b"), skipDedup: true });
    expect(forced.status).toBe(201);
  });

  test("dedup only matches within the same project", async () => {
    const origin = start();
    await post(origin, "/requests", { ...requestBody("req-a"), project: "press-zone" });
    const created = await post(origin, "/requests", { ...requestBody("req-b"), project: "overdeck" });
    expect(created.status).toBe(201);
  });

  test("/requests/fire: a fresh signature is claimed, journaled, and origin agent-incident", async () => {
    const origin = start();
    const claimed = await post(origin, "/requests/fire", { signature: "deploy-local:actions-gateway-config-missing", project: "overdeck", worker: "lane-a" });
    expect(claimed.status).toBe(201);
    const body = await claimed.json() as { request: { id: string; state: string; origin: string; worker: string; receipt_trail: Array<{ kind: string; meta: { worker: string } }> }; claimed: boolean };
    expect(body.claimed).toBe(true);
    expect(body.request).toMatchObject({ state: "asked", origin: "agent-incident", worker: "lane-a" });
    expect(body.request.receipt_trail).toMatchObject([{ kind: "claimed", meta: { worker: "lane-a" } }]);
    const entries = readFileSync(join(dir, "actions.jsonl"), "utf8").trim().split("\n").map((line: string) => JSON.parse(line));
    expect(entries.map((entry: { verb: string }) => entry.verb)).toEqual(["requests.fire.claim"]);
  });

  test("/requests/fire: a second lane hitting the same signature is told who already claimed it, not given a new row", async () => {
    const origin = start();
    const first = await post(origin, "/requests/fire", { signature: "deploy-local:actions-gateway-config-missing", project: "overdeck", worker: "lane-a" });
    const firstBody = await first.json() as { request: { id: string } };
    const second = await post(origin, "/requests/fire", { signature: "deploy-local:actions-gateway-config-missing", project: "overdeck", worker: "lane-b" });
    expect(second.status).toBe(409);
    const secondBody = await second.json() as { request: { id: string; worker: string }; claimed: boolean };
    expect(secondBody.claimed).toBe(false);
    expect(secondBody.request.id).toBe(firstBody.request.id);
    expect(secondBody.request.worker).toBe("lane-a");
    expect(await (await get(origin)).json()).toMatchObject({ requests: [expect.objectContaining({ id: firstBody.request.id })] });
  });

  test("/requests/fire: a different project with the same signature gets its own claim", async () => {
    const origin = start();
    const a = await post(origin, "/requests/fire", { signature: "deploy-local:actions-gateway-config-missing", project: "overdeck" });
    const b = await post(origin, "/requests/fire", { signature: "deploy-local:actions-gateway-config-missing", project: "press-zone" });
    expect(a.status).toBe(201);
    expect(b.status).toBe(201);
  });

  test("/requests/fire: a resolved (shipped) incident reopens for a recurrence instead of blocking forever", async () => {
    const origin = start();
    const first = await post(origin, "/requests/fire", { signature: "sig", project: "overdeck", worker: "lane-a" });
    const firstBody = await first.json() as { request: { id: string } };
    await post(origin, `/requests/${firstBody.request.id}`, { state: "in_flight", actor: "lane-a" });
    await post(origin, `/requests/${firstBody.request.id}`, { state: "shipped", actor: "lander" });
    const recurrence = await post(origin, "/requests/fire", { signature: "sig", project: "overdeck", worker: "lane-c" });
    expect(recurrence.status).toBe(201);
    const body = await recurrence.json() as { request: { id: string; state: string; worker: string }; claimed: boolean };
    expect(body.claimed).toBe(true);
    expect(body.request.id).toBe(firstBody.request.id);
    expect(body.request).toMatchObject({ state: "asked", worker: "lane-c" });
  });

  test("/requests/fire: rejects a missing signature or project", async () => {
    const origin = start();
    expect((await post(origin, "/requests/fire", { project: "overdeck" })).status).toBe(400);
    expect((await post(origin, "/requests/fire", { signature: "sig" })).status).toBe(400);
  });
});
