"use client";
/**
* Asking a model whether two proven folds are the same change.
*
* Advisory only. Everything the judge says passes through `applyJudgement`,
* which refuses invented ids, single-member clusters, and any attempt to
* absorb a file that stands alone. See `lib/diff-group.ts`.
*
* Requests are cached on the exact payload, so looking at the same diff twice
* cannot produce two different groupings.
*/
import { judgePayload, type DiffGroup, type Judgement } from "./diff-group.ts";
let configured: Promise<boolean> | null = null;
/** One quiet probe, rather than a failing POST per diff. */
export function judgeConfigured(): Promise<boolean> {
configured ??= fetch("/judge")
.then((r) => (r.ok ? r.json() : { configured: false }))
.then((j: { configured?: boolean }) => Boolean(j.configured))
.catch(() => false);
return configured;
}
const cache = new Map<string, Promise<Judgement | null>>();
/**
* Returns the judge's view, or null when it is unavailable or has nothing to
* say. Never throws: a grouping that cannot be judged is still a grouping.
*/
export function judgeGroups(groups: DiffGroup[]): Promise<Judgement | null> {
if (groups.length < 2) return Promise.resolve(null);
const payload = judgePayload(groups);
const key = JSON.stringify(payload);
const hit = cache.get(key);
if (hit) return hit;
const run = judgeConfigured()
.then((ok) => {
if (!ok) return null;
return fetch("/judge", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ groups: payload }),
})
.then((r) => (r.ok ? r.json() : null))
.then((j: Judgement | null) =>
j && Array.isArray(j.clusters) && j.clusters.length > 0 ? j : null,
);
})
.catch(() => null);
cache.set(key, run);
return run;
}