// Makespan — Scoring block. // // The canonical objective: minimize the latest finish day. Shipping it as a // block (rather than every caller hand-writing the two-line scorer) gives // the makespan a registry name a run config can reference and weight. // // MiniZinc compile contract: harness supplies `finish_day[t]` and `TASKS`. import { z } from "zod"; import type { Schedule, Scorer } from "../level-core/types.ts"; import type { MiniZincFragment, ScoringBlock } from "./types.ts"; export const MakespanInputSchema = z.object({}); export type MakespanInput = z.infer; const ScorerOutputSchema: z.ZodType = z.custom( (val): val is Scorer => typeof val === "object" && val !== null && typeof (val as Scorer).name === "string" && ((val as Scorer).direction === "min" || (val as Scorer).direction === "max") && typeof (val as Scorer).score === "function", ); export const MakespanBlock: ScoringBlock = { id: "Makespan", schema: { input: MakespanInputSchema, output: ScorerOutputSchema }, apply: (): Scorer => ({ name: "Makespan", direction: "min", score: (schedule: Schedule): number => schedule.makespan, }), toMiniZinc: (): MiniZincFragment => ({ text: `var int: makespan = max(t in TASKS) (finish_day[t]);`, }), doc: { nl: "The latest finish day across all tasks — the schedule's total length.", pseudocode: "max(finish(task) for task in tasks)", }, };