import { describe, expect, it } from "vitest";
import {
  assertReviewCandidateUnchanged,
  parseReviewResult,
} from "../../../infra/agent-runner/reviewer.mjs";

describe("independent reviewer runner contract", () => {
  it("accepts the final structured reviewer disposition and findings", () => {
    expect(
      parseReviewResult(
        'Review complete.\n{"disposition":"changes-requested","findings":[{"severity":"blocking","summary":"Candidate violates the dependency invariant"}]}',
      ),
    ).toEqual({
      disposition: "changes-requested",
      findings: [{ severity: "blocking", summary: "Candidate violates the dependency invariant" }],
    });
    expect(parseReviewResult('{"disposition":"approved","findings":[]}')).toEqual({
      disposition: "approved",
      findings: [],
    });
  });

  it("rejects malformed/non-actionable review results", () => {
    expect(() => parseReviewResult("approved")).toThrow(/required JSON disposition/);
    expect(() => parseReviewResult('{"disposition":"changes-requested","findings":[]}')).toThrow(
      /required JSON disposition/,
    );
    expect(() =>
      parseReviewResult(
        '{"disposition":"blocked","findings":[{"severity":"unknown","summary":"bad"}]}',
      ),
    ).toThrow(/required JSON disposition/);
  });

  it("fails closed if the reviewer changes the immutable candidate tree", () => {
    const digest = "a".repeat(40);
    expect(() => assertReviewCandidateUnchanged(digest, digest)).not.toThrow();
    expect(() => assertReviewCandidateUnchanged(digest, "b".repeat(40))).toThrow(
      /modified the exact candidate/,
    );
  });
});
