Something went wrong. Try again.
A functional toolkit for authoring resource-leveling algorithms — compose constraint and scoring blocks, enumerate feasible schedules
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291import { readFileSync } from "node:fs";
import { test, expect, describe } from "bun:test";import { z } from "zod";
import lexicographicRaw from "./fixtures/lexicographic.config.json";import minimalRaw from "./fixtures/minimal.config.json";import variadicRaw from "./fixtures/variadic-nested-disabled.config.json";import { parseConf, type ConfIssue } from "../../src/conf/index.ts";import { runConfigSchema, type RunConfig,} from "../../src/level-blocks/runConfig.ts";import { standardRegistry } from "../../src/level-blocks/standard.ts";
// Imported JSON widens literal types (formatVersion → number); read the// goldens back through the schema so they compare as RunConfig.const lexicographicJson: RunConfig = runConfigSchema.parse(lexicographicRaw);const variadicJson: RunConfig = runConfigSchema.parse(variadicRaw);const minimalJson: RunConfig = runConfigSchema.parse(minimalRaw);
const registry = standardRegistry();
function fixture(name: string): string { return readFileSync(`${import.meta.dir}/fixtures/${name}.conf`, "utf8");}
function parseOk(name: string) { const result = parseConf(fixture(name), { registry }); if (!result.ok) throw new Error( `${name} unexpectedly failed:\n${JSON.stringify(result.issues, null, 2)}`, ); return result.config;}
function firstIssue(text: string): ConfIssue { const result = parseConf(text, { registry }); expect(result.ok).toBe(false); if (result.ok) throw new Error("expected parse to fail"); expect(result.issues.length).toBe(1); return result.issues[0]!;}
describe("parseConf — grammar goldens", () => { test("lexicographic fixture parses to its expected raw config", () => { expect(parseOk("lexicographic")).toEqual(lexicographicJson); });
test("variadic/nested/disabled fixture parses to its expected raw config", () => { expect(parseOk("variadic-nested-disabled")).toEqual(variadicJson); });
test("minimal fixture parses to its expected raw config", () => { expect(parseOk("minimal")).toEqual(minimalJson); });
test("every golden config is a valid RunConfig", () => { for (const raw of [lexicographicRaw, variadicRaw, minimalRaw]) { expect(() => runConfigSchema.parse(raw)).not.toThrow(); } });});
describe("parseConf — grammar features", () => { test("sweep axes preserve broadcast, zip, and $enabled targets", () => { const result = parseConf( `[levelset]\nformat = 1\n\n[blocks.cap-a]\ncode = "levelset.MaxConcurrentResource.v1"\nresourceUniqueId = 1\nmax = 2\n\n[blocks.cap-b]\ncode = "levelset.MaxConcurrentResource.v1"\nresourceUniqueId = 2\nmax = 2\n\n[blocks.search]\ncode = "levelset.SerialSGS.v1"\n\n[sweep]\nmaxCombinations = 8\n\n[[sweep.axes]]\nid = "caps"\n\n[[sweep.axes.targets]]\ninstanceId = "cap-a"\nparamPath = "max"\nvalueKey = "A"\n\n[[sweep.axes.targets]]\ninstanceId = "cap-b"\nparamPath = "max"\nvalueKey = "B"\n\n[[sweep.axes.values]]\nA = 2\nB = 3\n\n[[sweep.axes.values]]\nA = 3\nB = 4\n\n[[sweep.axes]]\nid = "enabled"\nvalues = [true, false]\n\n[[sweep.axes.targets]]\ninstanceId = "cap-a"\nparamPath = "$enabled"\n`, ); expect(result.ok).toBe(true); if (!result.ok) throw new Error(JSON.stringify(result.issues)); expect(result.config.sweep).toEqual({ maxCombinations: 8, axes: [ { id: "caps", targets: [ { instanceId: "cap-a", paramPath: "max", valueKey: "A" }, { instanceId: "cap-b", paramPath: "max", valueKey: "B" }, ], values: [ { A: 2, B: 3 }, { A: 3, B: 4 }, ], }, { id: "enabled", targets: [{ instanceId: "cap-a", paramPath: "$enabled" }], values: [true, false], }, ], }); });
test("block document order is preserved", () => { const config = parseOk("lexicographic"); expect(config.pipeline.blocks.map((b) => b.instanceId)).toEqual([ "deadlineA", "lateness", "makespan", "sgs", ]); });
test('the "report" weight sentinel maps to null; a number stays a number', () => { const config = parseOk("lexicographic"); expect(config.weights).toEqual({ makespan: null, lateness: 1 }); });
test("array-of-tables becomes an object array param", () => { const config = parseOk("lexicographic"); const lateness = config.pipeline.blocks.find( (b) => b.instanceId === "lateness", )!; expect(lateness.params).toEqual({ phases: [ { name: "phase-1", taskUniqueIds: [1, 2, 3], targetDay: 80, weight: 2 }, ], }); });
test("dotted keys nest into an object param", () => { const config = parseOk("variadic-nested-disabled"); const peak = config.pipeline.blocks.find((b) => b.instanceId === "peak")!; expect(peak.params).toEqual({ resourceUniqueId: 3, cap: 5, window: { fromDay: 10, toDay: 20 }, }); });
test("a quoted table key is the verbatim instanceId", () => { const config = parseOk("variadic-nested-disabled"); expect( config.pipeline.blocks.some((b) => b.instanceId === "units.open"), ).toBe(true); });
test("reserved flags: enabled=false, candidate provenance, shadow=true", () => { const config = parseOk("variadic-nested-disabled"); const wip = config.pipeline.blocks.find((b) => b.instanceId === "wip")!; expect(wip.enabled).toBe(false); const open = config.pipeline.blocks.find( (b) => b.instanceId === "units.open", )!; expect(open.provenance).toBe("candidate"); expect(open.shadow).toBe(true); });
test("format maps to both runConfig and pipeline formatVersion; version is stamped back", () => { const config = parseOk("minimal"); expect(config.formatVersion).toBe(1); expect(config.pipeline.formatVersion).toBe(1); expect(config.levelset).toBe("0.1.0"); });
test("parsing without a registry skips graph validation (raw config)", () => { // No search block — validateGraph would reject, but registry-less parse // returns the raw config for the caller to fill/validate. const result = parseConf( `[levelset]\nformat = 1\n[blocks.m]\ncode = "levelset.Makespan.v1"`, ); expect(result.ok).toBe(true); });});
describe("parseConf — error fixtures (one per code)", () => { test("E301 TOML syntax carries line and column", () => { const issue = firstIssue(`[levelset]\nformat = = 1`); expect(issue.code).toBe("LEVELSET_E301"); expect(issue.pos).toEqual({ line: 2, column: 10 }); });
test("E302 unknown top-level section", () => { const issue = firstIssue( `[levelset]\nformat = 1\n[nonsense]\nx = 1\n[blocks.s]\ncode = "levelset.SerialSGS.v1"`, ); expect(issue.code).toBe("LEVELSET_E302"); expect(issue.path).toBe("nonsense"); });
test("E302 config shape error carries a conf-oriented path", () => { const issue = firstIssue( `[levelset]\nformat = 1\n[resolve]\nhorizonDays = "ninety"\n[blocks.s]\ncode = "levelset.SerialSGS.v1"`, ); expect(issue.code).toBe("LEVELSET_E302"); expect(issue.path).toBe("resolve.horizonDays"); });
test("E303 missing format", () => { const issue = firstIssue(`[blocks.s]\ncode = "levelset.SerialSGS.v1"`); expect(issue.code).toBe("LEVELSET_E303"); expect(issue.path).toBe("levelset.format"); });
test("E303 unsupported format", () => { const issue = firstIssue( `[levelset]\nformat = 2\n[blocks.s]\ncode = "levelset.SerialSGS.v1"`, ); expect(issue.code).toBe("LEVELSET_E303"); });
test("E304 rejects a bare TOML datetime literal", () => { const issue = firstIssue( `[levelset]\nformat = 1\n[resolve]\nepoch = 2026-01-01\n[blocks.s]\ncode = "levelset.SerialSGS.v1"`, ); expect(issue.code).toBe("LEVELSET_E304"); expect(issue.path).toBe("resolve.epoch"); });
test("E305 a reserved-named param collision", () => { // A synthetic block whose schema declares a `shadow` param — unreachable // through the conf format. const collidingRegistry = standardRegistry([ { code: "test.Colliding.v1", family: "constraint", tier: "engineer", block: { id: "Colliding", schema: { input: z.object({ shadow: z.number() }), output: z.unknown(), }, apply: (i: unknown) => i, toMiniZinc: () => ({ text: "" }), doc: { nl: "", pseudocode: "" }, }, defaultShadow: { shadow: 1 }, }, ]); const result = parseConf( `[levelset]\nformat = 1\n[blocks.x]\ncode = "test.Colliding.v1"\nshadow = 3\n[blocks.s]\ncode = "levelset.SerialSGS.v1"`, { registry: collidingRegistry }, ); expect(result.ok).toBe(false); if (result.ok) throw new Error("expected failure"); const e305 = result.issues.find((i) => i.code === "LEVELSET_E305")!; expect(e305).toBeDefined(); expect(e305.instanceId).toBe("x"); });
test("E306 rejects a non-finite number", () => { const issue = firstIssue( `[levelset]\nformat = 1\n[resolve]\nhorizonDays = inf\n[blocks.s]\ncode = "levelset.SerialSGS.v1"`, ); expect(issue.code).toBe("LEVELSET_E306"); });
test("E308 unknown block code, attributed to its instanceId", () => { const issue = firstIssue( `[levelset]\nformat = 1\n[blocks.mystery]\ncode = "levelset.Nope.v1"\n[blocks.s]\ncode = "levelset.SerialSGS.v1"`, ); expect(issue.code).toBe("LEVELSET_E308"); expect(issue.instanceId).toBe("mystery"); });
test("E308 invalid sweep target is attributed to its instanceId", () => { const issue = firstIssue( `[levelset]\nformat = 1\n[blocks.s]\ncode = "levelset.SerialSGS.v1"\n[sweep]\n[[sweep.axes]]\nid = "missing-cap"\nvalues = [1, 2]\n[[sweep.axes.targets]]\ninstanceId = "missing"\nparamPath = "max"`, ); expect(issue.code).toBe("LEVELSET_E308"); expect(issue.instanceId).toBe("missing"); expect(issue.message).toContain('sweep axis "missing-cap"'); });
test("E308 zero searches", () => { const issue = firstIssue( `[levelset]\nformat = 1\n[blocks.m]\ncode = "levelset.Makespan.v1"`, ); expect(issue.code).toBe("LEVELSET_E308"); expect(issue.message).toMatch(/exactly one search/); });
test("E308 invalid params, attributed to its instanceId", () => { const issue = firstIssue( `[levelset]\nformat = 1\n[blocks.cap]\ncode = "levelset.MaxConcurrentResource.v1"\nresourceUniqueId = 1\nmax = -3\n[blocks.s]\ncode = "levelset.SerialSGS.v1"`, ); expect(issue.code).toBe("LEVELSET_E308"); expect(issue.instanceId).toBe("cap"); });
test("E308 a weight referencing a non-scorer instance", () => { const issue = firstIssue( `[levelset]\nformat = 1\n[blocks.s]\ncode = "levelset.SerialSGS.v1"\n[weights]\nghost = 2`, ); expect(issue.code).toBe("LEVELSET_E308"); expect(issue.instanceId).toBe("ghost"); });});