import { test } from "node:test"; import assert from "node:assert/strict"; import { compileLaneRoot, compileLanes, sanitizeChannelPriority, } from "../lib/channelPriority"; import { LANES, isGroup } from "../lib/autoQueueTypes"; import type { AutoQueueNode } from "../lib/autoQueueTypes"; import { sanitizeAutoQueue } from "./autoQueuePolicy"; // IN jobs/, NOT lib/, for the reason `laneMigration.test.ts` is: the property // being asserted is that `sanitizeAutoQueue` is the IDENTITY on a compiled // tree, and ../architecture.test.ts forbids `lib/ -> jobs/` — including from a // test file, and its ALLOWED list may only shrink. // // WHY IT MATTERS. The compiler writes into `autoQueue[lane].root`, and every // read of settings.json puts that back through `sanitizeAutoQueue`. If the // sanitizer touched anything the compiler emits — reassigned an id (leaf ids // key the lane's fairness memory and its pick log), defaulted a weight, coerced // a mode — then the tree an operator compiled and the tree the runner walks // would be two different trees, and the difference would show up as a silently // reset ledger rather than as an error. That is why every node the compiler // emits already spells `weight: 1` and `maxWorkers: null`. // // The focus/hold/release proof through the real engine (buildPendingByLeaf + // selectNextWork) is slice S1's `channelPriorityCompile.test.ts`. function eachNode(node: AutoQueueNode, fn: (n: AutoQueueNode) => void): void { fn(node); if (isGroup(node)) for (const child of node.children) eachNode(child, fn); } test("sanitizeAutoQueue is the identity on a compiled tree", () => { const model = sanitizeChannelPriority({ channels: { lowly: { tier: "low" }, gone: { tier: "paused" }, first: { tier: "normal", rank: 0 }, // A per-operation override, so the four lanes are NOT all the same tree. nodl: { tier: "normal", overrides: { download: "paused" } }, }, }); const slugs = ["first", "lowly", "gone", "other", "focused", "nodl"]; const roots = compileLanes(model, slugs, ["focused"]); const before = { transcription: { enabled: true, root: roots.transcription }, download: { enabled: false, root: roots.download }, digest: { enabled: false, root: roots.digest }, backfill: { enabled: false, root: roots.backfill }, }; const after = sanitizeAutoQueue(before); for (const lane of LANES) { assert.deepEqual(after[lane].root, roots[lane], `${lane} root changed`); } // And through JSON, which is what settings.json actually does to it. const roundTripped = sanitizeAutoQueue(JSON.parse(JSON.stringify(before))); for (const lane of LANES) { assert.deepEqual(roundTripped[lane].root, roots[lane], `${lane} via JSON`); } // The override really did split the lanes, so the assertion above was not // four copies of one comparison. assert.notDeepEqual( { ...after.download.root, id: "x" }, { ...after.transcription.root, id: "x" }, ); }); test("no compiled id is reassigned by the sanitizer", () => { const model = sanitizeChannelPriority({ channels: { l: { tier: "low" }, p: { tier: "paused" } }, }); const root = compileLaneRoot("transcription", model, ["a", "b", "l", "p"], [ "a", ]); const ids: string[] = []; eachNode(root, (n) => ids.push(n.id)); const after = sanitizeAutoQueue({ transcription: { root } }).transcription .root; const afterIds: string[] = []; eachNode(after, (n) => afterIds.push(n.id)); assert.deepEqual(afterIds, ids); // Every id is stable and derived — `node-` would mean the sanitizer had // to invent one, which is exactly the fairness-memory reset this guards. assert.ok(!afterIds.some((id) => id.startsWith("node-")), afterIds.join(",")); }); test("an empty model still compiles to a tree the sanitizer accepts", () => { const roots = compileLanes(sanitizeChannelPriority(undefined), [], []); for (const lane of LANES) { // No channels at all: just the catch-all net. assert.deepEqual( roots[lane].children.map((c) => c.id), ["prio-all"], ); assert.deepEqual( sanitizeAutoQueue({ [lane]: { root: roots[lane] } })[lane].root, roots[lane], ); } });