import assert from "node:assert/strict"; import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); const read = (relative) => fs.readFileSync(path.join(root, relative), "utf8"); const json = (relative) => JSON.parse(read(relative)); const sha256 = (bytes) => crypto.createHash("sha256").update(bytes).digest("hex"); const plan = json("docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json"); const index = json("tests/golden/WBV2/task-index.json"); const catalogBytes = fs.readFileSync(path.join(root, index.catalog.path)); assert.equal(index.schemaVersion, 1); assert.equal(index.operation, "BLENDER_WEB_CAPABILITY_TASK_INDEX"); assert.equal(sha256(read(index.source.path)), index.source.sha256); assert.equal(sha256(catalogBytes), index.catalog.sha256); assert.equal(index.taskCount, plan.tasks.length); const ready = plan.tasks.filter((task) => task.ready === true); assert.equal(ready.length, 1); assert.equal(index.activeTask, ready[0].id); const lines = catalogBytes.toString("utf8").trimEnd().split("\n").filter(Boolean).map((line) => JSON.parse(line)); assert.equal(lines.length, plan.tasks.length); assert.equal(lines.filter((task) => task.state === "active").length, 1); assert.equal(lines.find((task) => task.state === "active")?.id, index.activeTask); for (const task of plan.tasks.filter((candidate) => candidate.ready || candidate.status === "done")) { assert.ok(index.entries[task.id], `${task.id} must have an index entry`); assert.ok(fs.existsSync(path.join(root, task.card)), `${task.id} card must exist before activation`); } process.stdout.write(`v2-task-index-ok tasks=${index.taskCount} active=${index.activeTask} catalog=${index.catalog.path}\n`);