fix(web): reject false macro coverage and record source gaps
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-09-05 18:35:18 +08:00
parent 60ac88cc86
commit 9ec6d4d28f
5 changed files with 843 additions and 19 deletions

View File

@@ -0,0 +1,83 @@
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`);