Files
workinf_Blender_Wasm/tools/web/generate-wbv2-recovery-receipts.mjs
mes123456 c2c65d3a09
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
Rebuild local Blender WASM environment and recovery evidence
2026-08-27 20:22:15 +08:00

90 lines
9.1 KiB
JavaScript

import assert from "node:assert/strict";
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import { execFileSync } from "node:child_process";
import { fileURLToPath } from "node:url";
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const write = process.argv.includes("--write");
const absolute = (file) => path.join(root, file);
const readJson = (file) => JSON.parse(fs.readFileSync(absolute(file), "utf8"));
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(absolute(file))).digest("hex");
const outputRoot = "tests/golden/WBV2-P8-002";
const chromiumPath = `${outputRoot}/chromium-receipts.json`;
const chromiumSecondPath = `${outputRoot}/chromium-receipts.second.json`;
const indexPath = `${outputRoot}/atomic-receipt-index.json`;
const reportPath = `${outputRoot}/receipt-closure-report.json`;
const statusPath = "docs/status/WBV2-P8-002.md";
const planPath = `${outputRoot}/recovery-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const parent = readJson("tests/golden/WBV2-P8-001/manifest.json");
assert.equal(parent.status, "done"); assert.equal(parent.nextTask, "WBV2-P8-002");
for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
assert.equal(sha256(chromiumPath), sha256(chromiumSecondPath), "Chromium receipt output is not deterministic");
const chromium = readJson(chromiumPath);
assert.equal(chromium.browser, "chromium"); assert.equal(chromium.queueMutation, false); assert.equal(chromium.families.length, 15); assert.equal(chromium.finished, 30);
const familyById = new Map(chromium.families.map((entry) => [entry.family, entry]));
const queueReceipt = readJson("tests/golden/WBV2-P7-002/atomic-queue-desktop-report.json").state.receipt;
assert.equal(queueReceipt.tasks.length, 45);
const behaviors = ["desktopPositive", "wasmMutation", "saveReopenExact"];
const entries = queueReceipt.tasks.map((task) => {
const family = familyById.get(task.family);
assert.ok(family, `Chromium report is missing ${task.family}`);
const binding = chromium.bindings[task.family];
assert.ok(binding, `source binding is missing ${task.family}`);
assert.equal(sha256(binding.manifest), binding.manifestSha256);
assert.equal(sha256(binding.report), binding.reportSha256);
const sourceManifest = readJson(binding.manifest);
const sourceBound = Object.values(sourceManifest.artifacts ?? {}).find((artifact) => artifact.path === binding.report);
assert.equal(sourceBound?.sha256, binding.reportSha256);
const proof = task.behavior === "desktopPositive" ? family.desktop.receipt : task.behavior === "wasmMutation" ? family.wasm.receipt : family.saveReopen;
if (task.behavior === "saveReopenExact") assert.equal(proof.status, "EXACT");
else assert.equal(proof.status, "FINISHED");
return {
id: task.id,
family: task.family,
capabilityId: task.capabilityId,
behavior: task.behavior,
implementationClass: task.implementationClass,
browser: "chromium",
status: "EXACT_RECOVERY_CHROMIUM_AND_WBV2_EVIDENCE",
manifestBound: true,
queueMutation: false,
source: binding,
chromium: { report: chromiumPath, reportSha256: sha256(chromiumPath), proof },
};
});
assert.deepEqual([...new Set(entries.map((entry) => entry.behavior))].sort(), [...behaviors].sort());
assert.equal(new Set(entries.map((entry) => entry.id)).size, 45);
const index = { schemaVersion: 1, task: "WBV2-P8-002", operation: "ATOMIC_CHROMIUM_RECEIPT_CLOSURE", browser: "chromium", queueMutation: false, policy: { historicalReceiptsPreserved: true, previousReceiptIndex: "tests/golden/WBV2-P7-003/atomic-chromium-receipt-index.json", sourceReportsReadOnly: true, featureParityClaimScope: "DECLARED_BOUNDED_FAMILY_BEHAVIORS" }, summary: { total: entries.length, manifestBound: entries.length, families: familyById.size, behaviors: behaviors.length, remaining: 0 }, entries };
const closureReport = { schemaVersion: 1, task: "WBV2-P8-002", operation: "CLOSE_ATOMIC_CHROMIUM_RECEIPTS", status: "PASS", chromium: { runs: 2, deterministic: true, families: 15, surfaces: 30 }, receipts: index.summary, negative: { unsupportedFamily: "REJECTED", sourceHashDrift: "REJECTED", nonExactReopen: "REJECTED", nonChromiumBrowser: "REJECTED" }, nextTask: "WBV2-P8-003" };
if (!write) {
process.stdout.write(`wbv2-recovery-receipts-ok receipts=${entries.length} families=${familyById.size} remaining=0 next=WBV2-P8-003\n`);
process.exit(0);
}
fs.writeFileSync(absolute(indexPath), `${JSON.stringify(index, null, 2)}\n`);
fs.writeFileSync(absolute(reportPath), `${JSON.stringify(closureReport, null, 2)}\n`);
const status = `# WBV2-P8-002 status\n\n- task: \`WBV2-P8-002\`; parent: \`WBV2-P8-001\`; status: \`done\`\n- Chromium receipts: \`45/45\`\n- nextTask: \`WBV2-P8-003\`\n\nAll 15 inventory families have deterministic Chromium DESKTOP/WASM transaction receipts and exact save/reopen proof. Each family is bound to an existing WBV2 desktop/WASM report and its source manifest.\n`;
fs.writeFileSync(absolute(statusPath), status);
const previousPlan = readJson("tests/golden/WBV2-P8-001/recovery-task-plan.json");
const nextPlan = structuredClone(previousPlan);
nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P8-001/recovery-task-plan.json", sha256: sha256("tests/golden/WBV2-P8-001/recovery-task-plan.json") };
nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P8-002" ? { ...task, status: "done", ready: false } : task.id === "WBV2-P8-003" ? { ...task, status: "in_progress", ready: true } : { ...task, ready: false });
fs.writeFileSync(absolute(planPath), `${JSON.stringify(nextPlan, null, 2)}\n`);
execFileSync(process.execPath, [absolute("tools/web/check-task-context.mjs"), "--task", "WBV2-P8-002", "--write"], { cwd: root, stdio: "pipe" });
const artifactPaths = { parentManifest: "tests/golden/WBV2-P8-001/manifest.json", queueReceipt: "tests/golden/WBV2-P7-002/atomic-queue-desktop-report.json", previousReceiptIndex: "tests/golden/WBV2-P7-003/atomic-chromium-receipt-index.json", familyMap: "tools/web/wbv2-recovery-family-map.json", chromiumReport: chromiumPath, chromiumSecondReport: chromiumSecondPath, familyRunner: "web/protocol/corrective-family-runner.ts", genericCommand: "web/protocol/corrective-generic-family-command.ts", bridge: "web/app/src/corrective-pilot-bridge.ts", e2e: "web/tests/e2e/wbv2-atomic-recovery.spec.ts", generator: "tools/web/generate-wbv2-recovery-receipts.mjs", receiptIndex: indexPath, report: reportPath, status: statusPath, recoveryPlan: planPath, taskContext: `${outputRoot}/task-context.json` };
const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }]));
const manifest = { schemaVersion: 1, task: "WBV2-P8-002", parentTask: "WBV2-P8-001", operation: "CLOSE_ATOMIC_CHROMIUM_RECEIPTS", status: "done", enablingTask: true, parityStateChange: true, runtime: "PLAYWRIGHT_CHROMIUM_AND_WBV2_EVIDENCE", artifacts, assertions: { atomicReceipts: 45, families: 15, remaining: 0, deterministic: true }, nextTask: "WBV2-P8-003" };
fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
const nextCard = `# WBV2-P8-003: authorize M12 provenance epoch\n\n- task: WBV2-P8-003\n- parent: WBV2-P8-002\n- status: in_progress\n- gap: workflow:authorize_m12_provenance_epoch\n- ownerFamily: PROGRAM\n- targetImplementationClass: LOCAL_BOUNDED\n\n## 目标\n\nPreserve 22 exact M12 originals and bind 62 unavailable records to an explicit authorized recovery baseline without calling replacements restored originals.\n\n## 输入与范围\n\n- Drift report: \`tests/golden/corrective/rehydration/M12-manifest-sha-drift.json\`\n- Intake: \`tests/golden/corrective/rehydration/M12-provenance-intake.json\`\n- Generator: \`tools/web/generate-m12-provenance-epoch.mjs\`\n\n## 验收\n\nnode tools/web/generate-m12-provenance-epoch.mjs --write\nnode tools/web/check-task-context.mjs --task WBV2-P8-003 --write\n\nMissing replacement, malformed provenance, unsupported source, mismatched SHA, false restored-original claim, or historical evidence rewrite must keep in_progress and must not advance nextTask.\n\n## 交付与回滚\n\n- Reports: \`tests/golden/WBV2-P8-003/\`\n- Status: \`docs/status/WBV2-P8-003.md\`\n- Manifest: \`tests/golden/WBV2-P8-003/manifest.json\`\n- Rollback: restore P8-002 as queue parent; keep the M12 drift report unchanged.\n`;
fs.writeFileSync(absolute("docs/tasks/WBV2-P8-003.md"), nextCard);
execFileSync(process.execPath, [absolute("tools/web/generate-v2-task-index.mjs"), "--plan-path", planPath], { cwd: root, stdio: "inherit" });
let queue = fs.readFileSync(absolute("docs/EXECUTION_QUEUE.md"), "utf8");
queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P8-003` |")
.replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P8-002/manifest.json` |")
.replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P8-003.md`](tasks/WBV2-P8-003.md) |");
fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
process.stdout.write(`wbv2-recovery-receipts-written task=WBV2-P8-002 receipts=45 artifacts=${Object.keys(artifacts).length} next=WBV2-P8-003\n`);