test(er): pin review-only fuzzy company boundary
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
import { POST as candidatesPOST } from "@/app/api/0pt/internal/er/candidates/route";
|
||||
|
||||
const TOKEN = "test-er-internal-token";
|
||||
let previousToken: string | undefined;
|
||||
|
||||
function request(body: unknown, token: string | undefined = TOKEN): NextRequest {
|
||||
const headers: Record<string, string> = { "content-type": "application/json" };
|
||||
if (token !== undefined) headers["x-internal-token"] = token;
|
||||
return new NextRequest("http://localhost/api/0pt/internal/er/candidates", {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
}
|
||||
|
||||
function baseBody(records: Array<{ record_id: string; fields: Record<string, unknown> }>) {
|
||||
return {
|
||||
tenant_id: "tenant_a",
|
||||
project_id: "project_a",
|
||||
records,
|
||||
blocking_fields: ["city"],
|
||||
compare_fields: [{ field: "name", weight: 1 }],
|
||||
auto_match_threshold: 0.9,
|
||||
review_threshold: 0.6,
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
previousToken = process.env.INTERNAL_TOKEN;
|
||||
process.env.INTERNAL_TOKEN = TOKEN;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (previousToken === undefined) delete process.env.INTERNAL_TOKEN;
|
||||
else process.env.INTERNAL_TOKEN = previousToken;
|
||||
});
|
||||
|
||||
describe("POST /api/0pt/internal/er/candidates", () => {
|
||||
it("fails closed without the internal service token", async () => {
|
||||
const res = await candidatesPOST(
|
||||
request(
|
||||
baseBody([
|
||||
{ record_id: "a", fields: { name: "Acme AB", city: "Stockholm" } },
|
||||
{ record_id: "b", fields: { name: "Acme AB", city: "Stockholm" } },
|
||||
]),
|
||||
undefined,
|
||||
),
|
||||
);
|
||||
expect(res.status).toBe(401);
|
||||
});
|
||||
|
||||
it("never emits a score-only fuzzy company match even above auto_match_threshold", async () => {
|
||||
const res = await candidatesPOST(
|
||||
request(
|
||||
baseBody([
|
||||
{ record_id: "a", fields: { name: "Acme Consulting AB", city: "Stockholm" } },
|
||||
{ record_id: "b", fields: { name: "Acme Consulting A B", city: "Stockholm" } },
|
||||
]),
|
||||
),
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json();
|
||||
expect(body.pairs).toHaveLength(1);
|
||||
expect(body.pairs[0].score).toBeGreaterThanOrEqual(0.9);
|
||||
expect(body.pairs[0].decided_by).toBe("score");
|
||||
expect(body.pairs[0].status).toBe("pending_review");
|
||||
expect(body.review_queue.map((pair: { candidate_id: string }) => pair.candidate_id)).toEqual([
|
||||
body.pairs[0].candidate_id,
|
||||
]);
|
||||
});
|
||||
|
||||
it("allows an exact stable company identifier hard rule to emit match", async () => {
|
||||
const res = await candidatesPOST(
|
||||
request(
|
||||
baseBody([
|
||||
{
|
||||
record_id: "a",
|
||||
fields: { name: "Acme Sweden AB", city: "Stockholm", org_nr: "556000-0001" },
|
||||
},
|
||||
{
|
||||
record_id: "b",
|
||||
fields: { name: "Acme Sverige", city: "Stockholm", org_nr: "556000-0001" },
|
||||
},
|
||||
]),
|
||||
),
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json();
|
||||
expect(body.pairs).toHaveLength(1);
|
||||
expect(body.pairs[0].status).toBe("match");
|
||||
expect(body.pairs[0].decided_by).toBe("0pt.company.stable-identifiers.v2");
|
||||
expect(body.review_queue).toEqual([]);
|
||||
});
|
||||
|
||||
it("lets conflicting stable identity evidence dominate a matching identifier", async () => {
|
||||
const res = await candidatesPOST(
|
||||
request(
|
||||
baseBody([
|
||||
{
|
||||
record_id: "a",
|
||||
fields: {
|
||||
name: "Acme Sweden AB",
|
||||
city: "Stockholm",
|
||||
lei: "549300EXAMPLE123",
|
||||
org_nr: "556000-0001",
|
||||
},
|
||||
},
|
||||
{
|
||||
record_id: "b",
|
||||
fields: {
|
||||
name: "Acme Sweden AB",
|
||||
city: "Stockholm",
|
||||
lei: "549300EXAMPLE123",
|
||||
org_nr: "556000-9999",
|
||||
},
|
||||
},
|
||||
]),
|
||||
),
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json();
|
||||
expect(body.pairs).toHaveLength(1);
|
||||
expect(body.pairs[0].status).toBe("non_match");
|
||||
expect(body.pairs[0].decided_by).toBe("0pt.company.stable-identifiers.v2");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user