import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; import test from "node:test"; import ts from "typescript"; const repoRoot = path.resolve(import.meta.dirname, "../../.."); const sourcePath = path.join(repoRoot, "web/protocol/editing-domain-recovery.ts"); 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 moduleUrl = "data:text/javascript;base64," + Buffer.from(transpiled.outputText).toString("base64"); const recovery = await import(moduleUrl); const hash = "a".repeat(64); const base = (domain, dataId) => ({ schemaVersion: 1, domain, baseline: { objectIds: [`object:${domain}`], dataIds: [dataId], objectCount: 1, revision: 4, identityHash: hash }, workerRestart: { status: "RECOVERED", workerGeneration: 2, revisionBefore: 4, revisionAfter: 4, hashBefore: hash, hashAfter: hash, liveHandles: 1, temporaryResourcesAfter: 0 }, oom: { status: "RECOVERED", faultPoint: "GPU_GEOMETRY_UPLOAD", code: "GPU_GEOMETRY_BUDGET_EXCEEDED", revisionBefore: 4, revisionAfter: 4, hashBefore: hash, hashAfter: hash, releasedBytes: 4096, temporaryResourcesAfter: 0 }, gpuRelease: { status: "RECOVERED", backend: "WEBGL2", releaseCount: 1, reinitCount: 1, disposedResources: 6, visiblePixels: 12, pixelHashBefore: hash, pixelHashAfter: hash }, smallScene: { status: "RECOVERED", revision: 4, identityHash: hash, objectCount: 1, dataIds: [dataId], visiblePixels: 12 }, }); test("M9-14 parses all three editing domains and preserves recovery invariants", () => { const reports = recovery.parseEditingDomainRecoverySuite([ base("CURVE", "curve:Recovery"), base("GREASE_PENCIL", "grease-pencil:Recovery"), base("PAINT", "mesh:Recovery"), ]); assert.deepEqual(reports.map((report) => report.domain), ["CURVE", "GREASE_PENCIL", "PAINT"]); assert.equal(reports.every((report) => report.workerRestart.hashAfter === report.baseline.identityHash), true); assert.equal(reports.every((report) => report.oom.releasedBytes > 0 && report.gpuRelease.visiblePixels > 0), true); }); test("M9-14 rejects stale identity, duplicate domains and GPU release drift", () => { const curve = base("CURVE", "curve:Recovery"); const stale = structuredClone(curve); stale.smallScene.identityHash = "b".repeat(64); assert.throws(() => recovery.parseEditingDomainRecoveryEvidence(stale), /smallScene identity/); assert.throws(() => recovery.parseEditingDomainRecoverySuite([curve, curve, base("PAINT", "mesh:Recovery")]), /duplicate editing domain/); const releaseDrift = structuredClone(curve); releaseDrift.gpuRelease.releaseCount = 2; assert.throws(() => recovery.parseEditingDomainRecoveryEvidence(releaseDrift), /release and reinitialize exactly once/); }); test("M9-14 summarizes only visible objects in the requested editing domain", () => { const snapshot = { nodes: [ { id: "object:curve", type: "CURVE", visible: true, dataId: "curve:one" }, { id: "object:hidden", type: "CURVE", visible: false, dataId: "curve:two" }, { id: "object:mesh", type: "MESH", visible: true, dataId: "mesh:one" }, ], }; assert.deepEqual(recovery.summarizeEditingDomain(snapshot, "CURVE"), { objectIds: ["object:curve"], dataIds: ["curve:one"], objectCount: 1 }); assert.deepEqual(recovery.summarizeEditingDomain(snapshot, "PAINT"), { objectIds: ["object:mesh"], dataIds: ["mesh:one"], objectCount: 1 }); assert.throws(() => recovery.summarizeEditingDomain({ nodes: [] }, "GREASE_PENCIL"), /DOMAIN_MISSING/); });