Files
workinf_Blender_Wasm/tools/web/generate-wbv2-inventory-rebaseline.mjs
mes123456 b78e23b16c
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
Advance WBV2 through native engine module matrix
2026-08-28 00:46:58 +08:00

93 lines
8.9 KiB
JavaScript

import assert from "node:assert/strict";
import crypto from "node:crypto";
import fs from "node:fs";
import os from "node:os";
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 read = (file) => fs.readFileSync(absolute(file), "utf8");
const readJson = (file) => JSON.parse(read(file));
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(absolute(file))).digest("hex");
const outputRoot = "tests/golden/WBV2-P10-001";
const historicalPath = "tests/golden/WBV2-P0-002/source-hashes.json";
const currentPath = `${outputRoot}/current-source-hashes.json`;
const dependencyPath = `${outputRoot}/dependency-inventory.current.json`;
const reportPath = `${outputRoot}/inventory-rebaseline-report.json`;
const statusPath = "docs/status/WBV2-P10-001.md";
const planPath = `${outputRoot}/native-parity-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const parentManifestPath = "tests/golden/WBV2-P10-000/manifest.json";
const historicalDependencyPath = "tests/golden/M13-05C/dependency-inventory.json";
const previousReportPath = "tests/golden/WBV2-P8-001/recovery-baseline-report.json";
const parent = readJson(parentManifestPath);
assert.equal(parent.task, "WBV2-P10-000");
assert.equal(parent.status, "done");
assert.equal(parent.nextTask, "WBV2-P10-001");
for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
const historical = readJson(historicalPath);
const previous = readJson(previousReportPath);
const drift = Object.entries(historical.sources).map(([file, expected]) => ({ file, expected, actual: sha256(file) })).filter((entry) => entry.expected !== entry.actual);
assert.deepEqual(drift.map((entry) => entry.file), ["docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json"]);
assert.equal(previous.wbv2.drift.length, 1);
assert.equal(previous.wbv2.drift[0].file, drift[0].file);
assert.equal(previous.wbv2.drift[0].actual, drift[0].actual);
const historicalDependency = readJson(historicalDependencyPath);
const temporary = fs.mkdtempSync(path.join(os.tmpdir(), "wbv2-p10-dependency-"));
const generatedPath = path.join(temporary, "dependency-inventory.json");
try {
execFileSync(process.execPath, [absolute("tools/web/generate-dependency-inventory.mjs"), generatedPath], { cwd: root, stdio: "pipe" });
} finally {
// The generated bytes are read before cleanup; the temporary directory is
// deliberately outside the repository and never becomes evidence.
}
const dependency = JSON.parse(fs.readFileSync(generatedPath, "utf8"));
assert.deepEqual(dependency.roots, historicalDependency.roots);
assert.deepEqual(dependency.categoryCounts, historicalDependency.categoryCounts);
assert.deepEqual(dependency.packages, historicalDependency.packages);
assert.equal(dependency.lockfile.sha256, historicalDependency.lockfile.sha256);
assert.equal(dependency.packages.length, 144);
const current = { schemaVersion: 1, task: "WBV2-P10-001", operation: "CURRENT_WBV2_SOURCE_HASH_BASELINE", historicalSourceHashes: historicalPath, historicalSourceHashesSha256: sha256(historicalPath), sources: Object.fromEntries(Object.keys(historical.sources).map((file) => [file, sha256(file)])), drift: drift.map(({ file, expected, actual }) => ({ file, expected, actual, classification: "AUTHORIZED_MUTABLE_PLAN" })) };
const report = { schemaVersion: 1, task: "WBV2-P10-001", operation: "RECONCILE_WBV2_INVENTORY_SOURCE_DRIFT", status: "PASS", historical: { sourceHashes: historicalPath, sourceHashesSha256: sha256(historicalPath), manifestsRewritten: false, baselinePreserved: true }, currentSourceBaseline: { path: currentPath, sha256: "PENDING", planPath: "docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json", planSha256: sha256("docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json") }, drift: { count: drift.length, entries: current.drift, onlyAuthorizedMutablePlan: true }, dependency: { historicalInventory: historicalDependencyPath, currentInventory: dependencyPath, packageCount: dependency.packages.length, packageHashChanged: dependency.package.sha256 !== historicalDependency.package.sha256, lockfileHashStable: dependency.lockfile.sha256 === historicalDependency.lockfile.sha256, rootsStable: JSON.stringify(dependency.roots) === JSON.stringify(historicalDependency.roots), closureStable: JSON.stringify(dependency.packages) === JSON.stringify(historicalDependency.packages), packagesAdded: 0 }, policy: { historicalP0Unchanged: true, historicalP8Unchanged: true, additiveCurrentBaseline: true, falseHistoricalRestoration: false }, nextTask: "WBV2-P10-002" };
if (!write) {
process.stdout.write(`wbv2-inventory-rebaseline-dry-ok task=WBV2-P10-001 planDrift=${drift.length} dependencyPackages=${dependency.packages.length} closureStable=1\n`);
process.exit(0);
}
fs.mkdirSync(absolute(outputRoot), { recursive: true });
fs.writeFileSync(absolute(currentPath), `${JSON.stringify(current, null, 2)}\n`);
fs.copyFileSync(generatedPath, absolute(dependencyPath));
fs.rmSync(temporary, { recursive: true, force: true });
report.currentSourceBaseline.sha256 = sha256(currentPath);
fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(absolute(statusPath), `# WBV2-P10-001 status\n\n- task: \`WBV2-P10-001\`; parent: \`WBV2-P10-000\`; status: \`done\`\n- plan drift: \`1\` authorized mutable plan hash\n- dependency packages: \`144\`; lockfile/roots/closure: \`STABLE\`\n- historical P0 hashes: preserved\n- nextTask: \`WBV2-P10-002\`\n\nThe current WBV2 plan hash is recorded as an additive epoch-1 baseline. The historical P0-002 source-hashes.json and all historical manifests remain unchanged. Dependency roots, lockfile, package closure, and package count remain stable.\n`);
const previousPlan = readJson("tests/golden/WBV2-P10-000/native-parity-task-plan.json");
const nextPlan = structuredClone(previousPlan);
nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P10-000/native-parity-task-plan.json", sha256: sha256("tests/golden/WBV2-P10-000/native-parity-task-plan.json") };
nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P10-001" ? { ...task, status: "done", ready: false } : task.id === "WBV2-P10-002" ? { ...task, status: "in_progress", ready: true } : { ...task, ready: false });
fs.writeFileSync(absolute(planPath), `${JSON.stringify(nextPlan, null, 2)}\n`);
const nextCardPath = "docs/tasks/WBV2-P10-002.md";
const nextCard = read(nextCardPath).replace("- status: planned", "- status: in_progress");
fs.writeFileSync(absolute(nextCardPath), nextCard);
execFileSync(process.execPath, [absolute("tools/web/generate-v2-task-index.mjs"), "--plan-path", absolute(planPath)], { cwd: root, stdio: "inherit" });
execFileSync(process.execPath, [absolute("tools/web/check-task-context.mjs"), "--task", "WBV2-P10-001", "--write"], { cwd: root, stdio: "inherit" });
execFileSync(process.execPath, [absolute("tools/web/check-wbv2-inventory-rebaseline.mjs")], { cwd: root, stdio: "inherit" });
const artifactPaths = { parentManifest: parentManifestPath, historicalSourceHashes: historicalPath, historicalDependencyManifest: "tests/golden/M13-05C/manifest.json", historicalRecoveryReport: previousReportPath, currentSourceHashes: currentPath, currentDependencyInventory: dependencyPath, sourcePlan: "docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json", generator: "tools/web/generate-wbv2-inventory-rebaseline.mjs", checker: "tools/web/check-wbv2-inventory-rebaseline.mjs", report: reportPath, status: statusPath, parityPlan: 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-P10-001", parentTask: "WBV2-P10-000", operation: "RECONCILE_WBV2_INVENTORY_SOURCE_DRIFT", status: "done", enablingTask: true, parityStateChange: false, artifacts, assertions: { historicalP0Preserved: true, historicalP8Preserved: true, authorizedPlanDrift: 1, currentBaseline: true, dependencyPackages: 144, dependencyClosureStable: true, lockfileStable: true, nextEngineTask: "WBV2-P10-002" }, nextTask: "WBV2-P10-002" };
fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
let queue = read("docs/EXECUTION_QUEUE.md");
queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P10-002` |")
.replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P10-001/manifest.json` |")
.replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P10-002.md`](tasks/WBV2-P10-002.md) |");
fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
process.stdout.write(`wbv2-inventory-rebaseline-written task=WBV2-P10-001 planDrift=1 dependencyPackages=144 closureStable=1 next=WBV2-P10-002 artifacts=${Object.keys(artifacts).length}\n`);