map/tests/additional-generation-coverage-worker.mjs

119 lines
5.1 KiB
JavaScript
Raw Permalink Normal View History

2026-08-11 21:51:07 +09:00
import assert from "node:assert/strict";
2026-08-10 13:59:33 +09:00
import { Worker } from "node:worker_threads";
import { performance } from "node:perf_hooks";
import { generateMap } from "../src/mapPipeline.js";
import { createWorldMap } from "../src/worldMap.js";
const worldSeed = 8;
const initial = generateMap(worldSeed);
const baseline = createWorldMap(initial);
const rect = { x0: 20, y0: 120, x1: 180, y1: 230 };
const terrainType = initial.terrainTemplate?.terrainType || initial.terrainDebug?.terrainType || "auto";
2026-08-11 21:51:07 +09:00
function runWorkerCase(patchMode, id, overrides = {}) {
2026-08-10 13:59:33 +09:00
return new Promise((resolve, reject) => {
const worker = new Worker(new URL("./browser-worker-node-shim.mjs", import.meta.url), { type: "module" });
const timer = setTimeout(async () => {
try { await worker.terminate(); } catch {}
reject(new Error(`${patchMode} coverage regression timed out`));
2026-08-11 21:51:07 +09:00
}, overrides.timeoutMs ?? 90_000);
2026-08-10 13:59:33 +09:00
const startedAt = performance.now();
2026-08-11 21:51:07 +09:00
const seed = overrides.seed ?? 123;
const candidatePlan = overrides.candidatePlan || [{ candidateId: `coverage-${patchMode}:0`, candidateOrdinal: 1, variant: 0, seed }];
2026-08-10 13:59:33 +09:00
worker.on("error", reject);
worker.on("message", async (message) => {
if (message.id !== id || message.type === "progress") return;
clearTimeout(timer);
try { await worker.terminate(); } catch {}
resolve({ message, elapsedMs: Math.round(performance.now() - startedAt) });
});
worker.postMessage({
id,
world: structuredClone(baseline),
rect,
options: {
patchMode,
terrainType,
variant: 0,
seed,
maxQualityRetries: 0,
2026-08-11 21:51:07 +09:00
qualityTerrainAttempts: candidatePlan.length,
2026-08-10 13:59:33 +09:00
acceptBestAvailableQuality: false,
includeSeamVisualization: false,
},
search: {
searchId: `coverage-${patchMode}`,
operationId: `coverage-${patchMode}`,
committedRevision: 1,
workerEpoch: 1,
executionAttempt: 1,
2026-08-11 21:51:07 +09:00
totalCandidateCount: candidatePlan.length,
candidatePlan,
...(overrides.search || {}),
2026-08-10 13:59:33 +09:00
},
});
});
}
2026-08-11 21:51:07 +09:00
const bestOfPlan = [0, 1, 2].map((variant, index) => ({
candidateId: `coverage-bestof:${variant}`,
candidateOrdinal: index + 1,
variant,
seed: (123 + variant) >>> 0,
}));
const { message: bestOfMessage } = await runWorkerCase("expansion", 3, {
candidatePlan: bestOfPlan,
search: {
draftSelection: true,
selectBestCandidate: true,
parallelDrafts: false,
resolvedPatchMode: "expansion",
},
});
assert.equal(bestOfMessage.ok, true, bestOfMessage.error || bestOfMessage.code || "best-of worker failed");
const bestOfResult = bestOfMessage.result || {};
assert.equal(bestOfResult.ok, true, bestOfResult.reason || bestOfResult.code || "best-of candidate search failed");
assert.equal(bestOfResult.searchStatus, "succeeded");
assert.equal(bestOfResult.bestOfCandidates, true, "best-of selection remains enabled");
assert.equal(bestOfResult.draftSelection?.enabled, true, "Branch-and-Bound ranking remains enabled");
assert.equal(Number(bestOfResult.candidateUnmappedActiveCells || 0), 0, "best candidate covers every active write cell");
assert.ok((bestOfResult.searchAttempts || []).length >= bestOfPlan.length, "every planned candidate remains visible to selection");
assert.equal((bestOfResult.searchAttempts || []).some((attempt) => attempt.code === "candidate-execution-error" && /did not cover/i.test(attempt.reason || "")), false,
"parent operation context never leaks into the canonical internal tile");
2026-08-10 13:59:33 +09:00
for (const [index, patchMode] of ["auto", "expansion"].entries()) {
const { message, elapsedMs } = await runWorkerCase(patchMode, index + 1);
const result = message.result || {};
2026-08-11 21:51:07 +09:00
const topology = result.candidateQuality?.finalMerge?.transportTopology;
const prefectureCoherence = result.candidateQuality?.finalMerge?.prefectureCoherence;
const demandedTopologyConnected = Object.values(topology?.byClass || {}).every((entry) => entry?.hardPass !== false);
2026-08-10 13:59:33 +09:00
const ok = message.ok === true
&& result.ok === true
&& result.searchStatus === "succeeded"
&& result.patchMode === "expansion"
&& result.tiledExpansion === true
&& Number(result.tileCount) === 1
&& Number(result.candidateUnmappedActiveCells || 0) === 0
2026-08-11 21:51:07 +09:00
&& result.seamDiagnostics?.hardPass === true
&& topology?.hardPass === true
&& demandedTopologyConnected
&& prefectureCoherence?.hardPass === true;
2026-08-10 13:59:33 +09:00
console.log(JSON.stringify({
patchMode,
ok,
elapsedMs,
workerOk: message.ok === true,
searchStatus: result.searchStatus || null,
resultCode: result.code || null,
resolvedPatchMode: result.patchMode || null,
tiledExpansion: result.tiledExpansion === true,
tileCount: Number(result.tileCount || 0),
candidateUnmappedActiveCells: Number(result.candidateUnmappedActiveCells || 0),
seamPass: result.seamDiagnostics?.hardPass === true,
2026-08-11 21:51:07 +09:00
transportTopologyPass: topology?.hardPass === true,
transportTopology: topology?.byClass || null,
prefectureCoherencePass: prefectureCoherence?.hardPass === true,
2026-08-10 13:59:33 +09:00
reason: result.reason || message.error || null,
}, null, 2));
if (!ok) process.exitCode = 1;
}