import assert from "node:assert/strict"; import test from "node:test"; import { readFile } from "node:fs/promises"; import { FIDELITY_LEVELS, IMPLEMENTATION_STATUSES, buildEncounterImplementationReport, } from "./lib/encounter-implementation-report.mjs"; test("encounter ledger exhaustively classifies portable RuneWaker evidence", async () => { const report = await buildEncounterImplementationReport(); assert.equal(report.validationStatus, "green", report.issues.join("\n")); assert.equal(report.summary.dungeons, 30); assert.equal(report.summary.deferredSourceRows, 4_113); assert.equal(report.summary.uniqueMechanicsEvidence, 1_524); assert.equal(report.summary.luaEvidenceSignals, 329); assert.equal(report.summary.templateEvidenceSignals, 1_195); const inventory = report.dungeons.flatMap((dungeon) => [ ...dungeon.deferredSourceRows, ...dungeon.mechanicsEvidence, ]); assert.equal(new Set(inventory.map((item) => item.id)).size, inventory.length); for (const item of inventory) { assert.ok(IMPLEMENTATION_STATUSES.includes(item.status), item.id); assert.ok(FIDELITY_LEVELS.includes(item.fidelity), item.id); assert.ok(item.blocker, item.id); assert.ok(item.nextWork, item.id); assert.ok(item.clearingTest, item.id); } for (const row of report.dungeons.flatMap((dungeon) => dungeon.deferredSourceRows)) { assert.ok(row.sourceIds.spawnId > 0, row.id); assert.ok(row.sourceIds.templateId > 0, row.id); assert.ok(row.source.snapshot.path.endsWith(".json"), row.id); assert.match(row.source.snapshot.sha256, /^[a-f0-9]{64}$/, row.id); assert.match(row.source.snapshot.contentSha256, /^[a-f0-9]{64}$/, row.id); } }); test("regex labels are memberships rather than inflated mechanic records", async () => { const report = await buildEncounterImplementationReport(); const evidence = report.dungeons.flatMap((dungeon) => dungeon.mechanicsEvidence); const multiCategory = evidence.find((item) => item.categories.length > 1); assert.ok(multiCategory, "expected at least one source line with overlapping review labels"); assert.equal(evidence.filter((item) => item.id === multiCategory.id).length, 1); assert.equal( report.summary.evidenceCategoryMembershipCount, evidence.reduce((total, item) => total + item.categories.length, 0), ); assert.notEqual(report.summary.evidenceCategoryMembershipCount, evidence.length); }); test("source gaps, fallbacks, zero-boss packages, and empty variants stay explicit", async () => { const report = await buildEncounterImplementationReport(); assert.deepEqual( report.specialCases.fallbackBosses.map((boss) => boss.entityId), ["rw-fa-100070", "rw-fa-100561", "rw-fa-100562", "rw-fa-100563"], ); assert.ok(report.specialCases.fallbackBosses.every((boss) => ( boss.status === "implemented" && boss.fidelity === "healer-man-authored" ))); assert.ok(report.specialCases.fallbackBosses.every((boss) => ( boss.mechanicIds.length > 0 && boss.telegraphedMechanicIds.length === boss.mechanicIds.length ))); assert.deepEqual( report.specialCases.nonEmptyZeroBossPackages.map((entry) => entry.dungeonId), [ "aeternal-circle", "dungeon-of-dalanis", "grafu-castle", "kal-turok-hive", "lair-demon-dragon", "tomb-seven-heroes", "warnorken-arena", "zurhidon-stronghold", ], ); assert.deepEqual( report.specialCases.intentionalEmptyPackages.map((entry) => entry.dungeonId), ["demon-stronghold-125", "zurhidon-stronghold-124"], ); assert.equal(report.summary.deferredRowStatuses["deferred-source-gap"], 4_113); }); test("the report has no timestamps and is byte-deterministic in memory", async () => { const first = await buildEncounterImplementationReport(); const second = await buildEncounterImplementationReport(); assert.equal(JSON.stringify(first), JSON.stringify(second)); assert.equal(Object.hasOwn(first, "generatedAt"), false); }); test("checked-in JSON is the current deterministic report", async () => { const built = await buildEncounterImplementationReport(); const checkedIn = JSON.parse(await readFile( new URL("./RUNEWAKER_ENCOUNTER_IMPLEMENTATION_REPORT.json", import.meta.url), "utf8", )); assert.deepEqual(checkedIn, built); });