84 lines
4.2 KiB
JavaScript
84 lines
4.2 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import crypto from "node:crypto";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
const abs = (file) => path.join(root, file);
|
|
const readJson = (file) => JSON.parse(fs.readFileSync(abs(file), "utf8"));
|
|
const sha = (file) => crypto.createHash("sha256").update(fs.readFileSync(abs(file))).digest("hex");
|
|
const writeJson = (file, value) => fs.writeFileSync(abs(file), `${JSON.stringify(value, null, 2)}\n`);
|
|
|
|
const bindingsPath = "tests/golden/WBV2/dynamic-coverage-bindings.json";
|
|
const inventoryPath = "tests/golden/WBV2/dynamic-inventory.json";
|
|
const coverageManifestPath = "tests/golden/WBV2/dynamic-coverage-manifest.json";
|
|
const inventoryManifestPath = "tests/golden/WBV2/dynamic-inventory-manifest.json";
|
|
const auditPath = "tests/golden/WBV2/dynamic-coverage-audit.json";
|
|
const repairPath = "tests/golden/WBV2/macro-binding-repair.json";
|
|
|
|
const bindings = readJson(bindingsPath);
|
|
const inventory = readJson(inventoryPath);
|
|
const macroTasks = new Set();
|
|
const index = readJson("tests/golden/WBV2/task-index.json");
|
|
const plan = readJson(index.source.path);
|
|
for (const task of plan.tasks ?? []) {
|
|
if (String(task.module?.moduleId ?? "").endsWith("_MACRO_BATCH")) macroTasks.add(task.id);
|
|
}
|
|
const removed = bindings.filter((binding) => macroTasks.has(binding.task) || String(binding.capabilityId ?? "").endsWith("_MACRO_BATCH"));
|
|
const kept = bindings.filter((binding) => !macroTasks.has(binding.task) && !String(binding.capabilityId ?? "").endsWith("_MACRO_BATCH"));
|
|
const removedIds = new Set(removed.map((binding) => binding.unitId));
|
|
const updatedUnits = inventory.units.map((unit) => {
|
|
if (!removedIds.has(unit.id)) return unit;
|
|
const { coverage, ...withoutCoverage } = unit;
|
|
return { ...withoutCoverage, coverageStatus: "UNVERIFIED" };
|
|
});
|
|
const verifiedUnits = updatedUnits.filter((unit) => unit.coverageStatus === "VERIFIED").length;
|
|
const updatedInventory = {
|
|
...inventory,
|
|
units: updatedUnits,
|
|
coverage: { ...inventory.coverage, verifiedUnits, unverifiedUnits: inventory.summary.unitCount - verifiedUnits },
|
|
coverageLedger: kept,
|
|
};
|
|
writeJson(bindingsPath, kept);
|
|
writeJson(inventoryPath, updatedInventory);
|
|
const refresh = (file) => {
|
|
if (!fs.existsSync(abs(file))) return;
|
|
const value = readJson(file);
|
|
if (file === coverageManifestPath) {
|
|
value.artifacts.inventory.sha256 = sha(inventoryPath);
|
|
value.artifacts.bindings.sha256 = sha(bindingsPath);
|
|
value.coverage = { ...value.coverage, verifiedUnits, unverifiedUnits: inventory.summary.unitCount - verifiedUnits, boundUnitDelta: -removed.length };
|
|
} else if (file === inventoryManifestPath) {
|
|
value.artifacts.inventory.sha256 = sha(inventoryPath);
|
|
value.inventory = { ...value.inventory, verifiedUnits, unverifiedUnits: inventory.summary.unitCount - verifiedUnits, boundCaseDelta: -removed.length };
|
|
} else {
|
|
const coverageByKind = {};
|
|
const coverageByFamily = {};
|
|
for (const unit of updatedUnits) {
|
|
const kind = coverageByKind[unit.kind] ??= { verified: 0, unverified: 0 };
|
|
const family = coverageByFamily[unit.family] ??= { verified: 0, unverified: 0 };
|
|
const key = unit.coverageStatus === "VERIFIED" ? "verified" : "unverified";
|
|
kind[key] += 1;
|
|
family[key] += 1;
|
|
}
|
|
value.dynamicInventory = { ...(value.dynamicInventory ?? {}), afterSha256: sha(inventoryPath), verifiedUnits, unverifiedUnits: inventory.summary.unitCount - verifiedUnits };
|
|
value.coverageByKind = coverageByKind;
|
|
value.coverageByFamily = coverageByFamily;
|
|
value.explicitBindings = kept;
|
|
}
|
|
writeJson(file, value);
|
|
};
|
|
refresh(coverageManifestPath);
|
|
refresh(inventoryManifestPath);
|
|
refresh(auditPath);
|
|
writeJson(repairPath, {
|
|
schemaVersion: 1,
|
|
operation: "REMOVE_FALSE_BROAD_MACRO_BINDINGS",
|
|
removedBindingCount: removed.length,
|
|
removedUnitIds: [...removedIds],
|
|
verifiedUnits,
|
|
unverifiedUnits: inventory.summary.unitCount - verifiedUnits,
|
|
rule: "macro names require an exact native command gate; family substring matches are forbidden",
|
|
});
|
|
process.stdout.write(`macro-binding-repair removed=${removed.length} verified=${verifiedUnits} unverified=${inventory.summary.unitCount - verifiedUnits}\n`);
|