export type CheckState = "success" | "failure" | "error" | "pending" | "missing" | "untrusted" | "stale";
/** Polls of the fix commit's CI before giving up: 30 x 2 minutes covers an hour of CI. */
export const MAX_CI_POLLS = 30;
/** With no statuses at all after this many polls, the repo is assumed to have no CI for the branch. */
export const NO_CI_GRACE_POLLS = 3;
/** Attempts to put the pull back in the queue when enqueueing itself fails (for example the queue is full). */
export const MAX_ENQUEUE_ATTEMPTS = 3;
export const NO_CI_REASON = "No CI reported on the AI-resolved commit; a human must review and re-queue it";
export type Verdict = { kind: "green" } | { kind: "wait" } | { kind: "red"; reason: string };
/**
* Decides whether the fix commit is green. Required checks (from base branch protection) must all succeed;
* without required checks every reported status must succeed; with no statuses at all after a grace period
* the machine-resolved commit is unverified, so it is handed back to a human instead of re-entering the queue.
*/
export function ciVerdict(input: {
required: string[];
requiredResults: CheckState[];
statuses: Array<{ context: string; state: CheckState }>;
poll: number;
}): Verdict {
if (input.required.length > 0) {
const bad = input.required.findIndex((_, index) =>
["failure", "error", "untrusted", "stale"].includes(input.requiredResults[index]),
);
if (bad >= 0) return { kind: "red", reason: `Required check "${input.required[bad]}" did not pass on the fix` };
if (input.requiredResults.every((state) => state === "success")) return { kind: "green" };
} else if (input.statuses.length > 0) {
const bad = input.statuses.find((status) => ["failure", "error", "untrusted"].includes(status.state));
if (bad) return { kind: "red", reason: `Check "${bad.context}" failed on the fix` };
if (input.statuses.every((status) => status.state === "success")) return { kind: "green" };
} else if (input.poll >= NO_CI_GRACE_POLLS) {
return { kind: "red", reason: NO_CI_REASON };
}
if (input.poll >= MAX_CI_POLLS) return { kind: "red", reason: "Timed out waiting for CI on the fix" };
return { kind: "wait" };
}