import assert from "node:assert/strict"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { pathToFileURL } from "node:url"; import test from "node:test"; import ts from "typescript"; const repoRoot = path.resolve(import.meta.dirname, "../../.."); const temporary = fs.mkdtempSync(path.join(os.tmpdir(), "paint-pbvh-capability-unit-")); function transpile(sourceName, outputName, replacements = []) { const sourcePath = path.join(repoRoot, "web/protocol", sourceName); const transpiled = ts.transpileModule(fs.readFileSync(sourcePath, "utf8"), { compilerOptions: { module: ts.ModuleKind.ES2022, target: ts.ScriptTarget.ES2022 }, fileName: sourcePath, reportDiagnostics: true, }); assert.deepEqual(transpiled.diagnostics, []); const output = replacements.reduce((source, [from, to]) => source.replaceAll(from, to), transpiled.outputText); fs.writeFileSync(path.join(temporary, outputName), output); } transpile("capability-gates.ts", "capability-gates.mjs"); transpile("paint-pbvh-capability.ts", "paint-pbvh-capability.mjs", [ ['from "./capability-gates"', 'from "./capability-gates.mjs"'], ]); const pbvh = await import(pathToFileURL(path.join(temporary, "paint-pbvh-capability.mjs"))); const base = { schemaVersion: 1, operation: "PBVH_BRUSH", domain: "VERTEX_COLOR", brush: "DRAW", objectId: "object:Paint", meshId: "mesh:Paint", baseRevision: 7, }; test("M9-13 freezes the active Blender 5.2 PBVH-related brush inventory", () => { const inventory = pbvh.paintPBVHBrushInventory(); const counts = Object.fromEntries(["SCULPT", "VERTEX_COLOR", "WEIGHT", "TEXTURE"].map((domain) => [ domain, inventory.filter((entry) => entry.domain === domain).length, ])); assert.deepEqual(counts, { SCULPT: 32, VERTEX_COLOR: 4, WEIGHT: 4, TEXTURE: 6 }); assert.equal(new Set(inventory.map((entry) => `${entry.domain}:${entry.brush}`)).size, 46); assert.ok(inventory.every((entry) => entry.source.endsWith("DNA_brush_enums.h"))); }); test("M9-13 blocks every PBVH brush when the WASM entrypoint is absent", () => { for (const entry of pbvh.paintPBVHBrushInventory()) { const gate = pbvh.gatePaintPBVHCapability({ ...base, domain: entry.domain, brush: entry.brush }, { nativeEntrypointPresent: false, sessionContextReady: false, verifiedBrushes: new Set(), currentRevision: 7, currentObjectId: base.objectId, currentMeshId: base.meshId, }); assert.equal(gate.taskId, "N-017"); assert.equal(gate.status, "BLOCKED"); assert.deepEqual(gate.issues.map((issue) => issue.code), ["PAINT_PBVH_UNAVAILABLE"]); assert.equal(gate.issues[0].recoverable, false); } }); test("M9-13 remains fail-closed after symbol discovery until context and a brush golden exist", () => { const common = { nativeEntrypointPresent: true, verifiedBrushes: new Set(), currentRevision: 7 }; assert.equal(pbvh.gatePaintPBVHCapability(base, { ...common, sessionContextReady: false }).issues[0].code, "PAINT_PBVH_CONTEXT_UNAVAILABLE"); assert.equal(pbvh.gatePaintPBVHCapability(base, { ...common, sessionContextReady: true }).issues[0].code, "PAINT_PBVH_BRUSH_UNVERIFIED"); assert.equal(pbvh.gatePaintPBVHCapability(base, { ...common, sessionContextReady: true, verifiedBrushes: new Set(["VERTEX_COLOR:DRAW"]), }).status, "READY"); }); test("M9-13 validates identity and revision before reporting runtime availability", () => { const context = { nativeEntrypointPresent: false, sessionContextReady: false, verifiedBrushes: new Set(), currentRevision: 7, currentObjectId: base.objectId, currentMeshId: base.meshId, }; assert.equal(pbvh.gatePaintPBVHCapability({ ...base, baseRevision: 6 }, context).issues[0].code, "REVISION_CONFLICT"); assert.equal(pbvh.gatePaintPBVHCapability({ ...base, objectId: "object:Other" }, context).issues[0].code, "PAINT_SCHEMA_INVALID"); assert.throws(() => pbvh.parsePaintPBVHCapabilityRequest({ ...base, brush: "FAKE" }), { code: "PAINT_PBVH_BRUSH_UNVERIFIED" }); assert.throws(() => pbvh.parsePaintPBVHCapabilityRequest({ ...base, proxySuccess: true }), { code: "PAINT_SCHEMA_INVALID" }); });