Files
workinf_Blender_Wasm/tools/web/generate-wbv2-paint-root.mjs
mes123456 784193df83
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 deduplicated paint capability coverage
2026-08-28 13:52:16 +08:00

55 lines
14 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 absolute = (file) => path.join(root, file);
const read = (file) => fs.readFileSync(absolute(file), "utf8");
const json = (file) => JSON.parse(read(file));
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(absolute(file))).digest("hex");
const p15ManifestPath = "tests/golden/WBV2-P15-003/manifest.json";
const p15ReportPath = "tests/golden/WBV2-P15-003/lighting-gate-report.json";
const p16Root = "tests/golden/WBV2-P16-000";
const planPath = `${p16Root}/paint-task-plan.json`;
const reportPath = `${p16Root}/paint-root-report.json`;
const manifestPath = `${p16Root}/manifest.json`;
const statusPath = "docs/status/WBV2-P16-000.md";
const inventoryPath = "tests/golden/WBV2-P0-002/parity-map.json";
const sourceReportPath = "tests/golden/WBV2-P4-003/sculpt-report.json";
const sourceRunnerPath = "tools/web/check-paint-roundtrip.mjs";
const sourceCommandPath = "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp";
const sourceTestPath = "web/tests/e2e/paint-pbvh-capability.spec.ts";
const p15 = json(p15ManifestPath); const p15Report = json(p15ReportPath); const inventory = json(inventoryPath);
assert.equal(p15.task, "WBV2-P15-003"); assert.equal(p15.status, "done"); assert.equal(p15.nextTask, null); assert.equal(p15Report.status, "PASS"); assert.equal(p15Report.decision.fullHistoricalReproduction, false); assert.equal(inventory.summary.inventoryEntries, 6900);
for (const artifact of Object.values(p15.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
const tasks = [
{ id: "WBV2-P16-000", phase: "P16", title: "authorize_paint_capability_continuation", kind: "enabling", owner: "PROGRAM", dependsOn: ["WBV2-P15-003"], parityId: null, implementationClass: "LOCAL_BOUNDED", parallelGroup: "p16-governance", gate: "G2", card: "docs/tasks/WBV2-P16-000.md", behavior: "Authorize a source-backed Sculpt/Paint continuation without reopening completed batches.", outputs: ["continuation root", "candidate scope", "hash boundary"], acceptance: ["P15 evidence remains hash-bound", "paint source and fixtures exist", "one production task is active"], status: "done", ready: false, queueMutationAllowed: true },
{ id: "WBV2-P16-001", phase: "P16", title: "select_paint_capability_batch", kind: "enabling", owner: "PARITY", dependsOn: ["WBV2-P16-000"], parityId: "SCULPT.PAINT_ATTRIBUTES", implementationClass: "LOCAL_BOUNDED", parallelGroup: "p16-selection", gate: "G2", card: "docs/tasks/WBV2-P16-001.md", behavior: "Select one deterministic vertex-color and weight-paint behavior batch from source and inventory evidence.", outputs: ["candidate report", "behavior hash", "dedupe key"], acceptance: ["source commands are present", "existing paint evidence is reused", "candidate remains representative"], status: "in_progress", ready: true, queueMutationAllowed: false },
{ id: "WBV2-P16-002", phase: "P16", title: "paint_attributes_engine_receipt", kind: "feature", owner: "SCULPT", dependsOn: ["WBV2-P16-001"], parityId: "SCULPT.PAINT_ATTRIBUTES", implementationClass: "LOCAL_EXACT", parallelGroup: "p16-paint", gate: "G2", card: "docs/tasks/WBV2-P16-002.md", behavior: "Bind vertex colors and weights, undo/redo, malformed rejection, and exact save/reopen to compiled WASM Main in Chromium.", outputs: ["paint production report", "paint receipt", "manifest"], acceptance: ["vertex colors and weights match", "undo/redo is sequential", "malformed input fails closed", "save/reopen is exact"], status: "planned", ready: false, queueMutationAllowed: false },
{ id: "WBV2-P16-003", phase: "P16", title: "close_paint_capability_gate", kind: "enabling", owner: "RELEASE", dependsOn: ["WBV2-P16-002"], parityId: null, implementationClass: "LOCAL_BOUNDED", parallelGroup: "p16-release", gate: "G5", card: "docs/tasks/WBV2-P16-003.md", behavior: "Close the paint capability gate without promoting representative evidence to full-family completion.", outputs: ["paint gate", "limited declaration", "manifest"], acceptance: ["only tested paint behavior is claimed", "inventory remainder stays explicit", "no duplicate validation or historical over-claim"], status: "planned", ready: false, queueMutationAllowed: false },
];
const plan = { schemaVersion: 1, planId: "BLENDER_WEB_PARITY_V2_PAINT_EPOCH_1", status: "ACTIVE_PAINT_QUEUE", authority: "queue_reactivated_after_p15_lighting_gate", sourcePlan: "docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json", executionPointer: "docs/EXECUTION_QUEUE.md", runtimePolicy: { blenderSource: "blender-5.2.0", browserEvidence: ["chromium"], forbiddenBrowsers: ["firefox", "webkit"], mainAuthority: "blender_main", reusePolicy: "source_hash_and_behavior_hash_deduplication" }, parentHighValue: { manifest: p15ManifestPath, report: p15ReportPath, inventoryTotal: 6900, inventoryPending: 6618, duplicateValidationAvoided: true }, tasks };
fs.mkdirSync(absolute(p16Root), { recursive: true }); fs.writeFileSync(absolute(planPath), `${JSON.stringify(plan, null, 2)}\n`);
const report = { schemaVersion: 1, task: "WBV2-P16-000", operation: "AUTHORIZE_PAINT_CAPABILITY_CONTINUATION", status: "PASS", parent: { task: p15.task, manifest: p15ManifestPath, manifestSha256: sha256(p15ManifestPath), report: p15ReportPath, reportSha256: sha256(p15ReportPath), previousDecision: p15Report.decision.status }, continuation: { root: "WBV2-P16-000", firstTask: "WBV2-P16-001", plannedTasks: 4, candidate: "SCULPT.PAINT_ATTRIBUTES", sourceReport: sourceReportPath, sourceRunner: sourceRunnerPath, sourceApi: sourceCommandPath, chromiumBoundaryTest: sourceTestPath, browser: "chromium", inventoryTotal: 6900, inventoryPending: 6618, noRepeatedExecution: true }, policy: { p15EvidencePreserved: true, sourceHistoryReadOnly: true, representativeSliceOnly: true, duplicateValidationAvoided: true, authorizedRebaselineOnly: true, fullHistoricalReproduction: false }, nextTask: "WBV2-P16-001" };
fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(absolute("docs/tasks/WBV2-P16-000.md"), `# WBV2-P16-000: paint capability continuation root\n\n- task: WBV2-P16-000\n- parent: WBV2-P15-003\n- status: done\n- gap: workflow:authorize_paint_capability_continuation\n- ownerFamily: PROGRAM\n- targetImplementationClass: LOCAL_BOUNDED\n\n## 目标\n\nAuthorize a source-backed Sculpt/Paint continuation. P16 reuses the 6900-entry coverage ledger and validates one vertex-color/weight behavior batch against the compiled WebEngine WASM Main in Chromium.\n\n## 验收\n\n- \`node tools/web/generate-wbv2-paint-root.mjs\`\n- \`node tools/web/check-execution-control-plane.mjs\`\n- \`node tools/web/check-v2-task-index.mjs\`\n\n## 交付与回滚\n\n- Reports: \`tests/golden/WBV2-P16-000/\`\n- Manifest: \`tests/golden/WBV2-P16-000/manifest.json\`\n- Rollback: restore P15-003 as queue parent without rewriting P15 evidence.\n`);
const cards = {
"WBV2-P16-001": `# WBV2-P16-001: select_paint_capability_batch\n\n- task: WBV2-P16-001\n- parent: WBV2-P16-000\n- status: in_progress\n- gap: capability:SCULPT.PAINT_ATTRIBUTES\n- ownerFamily: PARITY\n- targetImplementationClass: LOCAL_BOUNDED\n\n## 目标\n\nSelect one deterministic vertex-color and weight-paint behavior batch from source and inventory evidence.\n\n## 输入与范围\n\n- Focused source: \`tests/golden/WBV2-P0-002/parity-map.json\`\n- Existing source receipt: \`tests/golden/WBV2-P4-003/sculpt-report.json\`\n- Production API: \`blender-5.2.0/source/blender/web_engine/web_engine_api.cpp\`\n- Production entrypoint: \`node tools/web/generate-wbv2-paint-selection.mjs --write\`\n\n## 验收\n\n- source commands are present and hash-bound\n- existing paint evidence is reused read-only\n- candidate remains representative rather than full-family completion\n- malformed, hash-drift, unsupported, or false-completion input keeps in_progress\n- \`node tools/web/check-task-context.mjs --task WBV2-P16-001 --write\`\n\n## 交付与回滚\n\n- Reports: \`tests/golden/WBV2-P16-001/\`\n- Status: \`docs/status/WBV2-P16-001.md\`\n- Manifest: \`tests/golden/WBV2-P16-001/manifest.json\`\n- Rollback: restore P16-000 as queue parent.\n`,
"WBV2-P16-002": `# WBV2-P16-002: paint_attributes_engine_receipt\n\n- task: WBV2-P16-002\n- parent: WBV2-P16-001\n- status: planned\n- gap: capability:SCULPT.PAINT_ATTRIBUTES\n- ownerFamily: SCULPT\n- targetImplementationClass: LOCAL_EXACT\n\n## 目标\n\nBind vertex colors and weights, undo/redo, malformed rejection, and exact save/reopen to compiled WASM Main in Chromium.\n\n## 输入与范围\n\n- Focused source: \`tests/golden/WBV2-P16-001/paint-selection-report.json\`\n- Production test: \`web/tests/e2e/wbv2-paint-attributes-production.spec.ts\`\n- Production entrypoint: \`npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-paint-attributes-production.spec.ts\`\n\n## 验收\n\n- vertex colors and weights match bounded expectations\n- undo/redo revisions are sequential\n- malformed input fails closed without Main mutation\n- save/reopen is exact and deterministic\n- Chromium is the only browser\n- \`node tools/web/check-task-context.mjs --task WBV2-P16-002 --write\`\n\n## 交付与回滚\n\n- Reports: \`tests/golden/WBV2-P16-002/\`\n- Status: \`docs/status/WBV2-P16-002.md\`\n- Manifest: \`tests/golden/WBV2-P16-002/manifest.json\`\n- Rollback: restore P16-001 as queue parent.\n`,
"WBV2-P16-003": `# WBV2-P16-003: close_paint_capability_gate\n\n- task: WBV2-P16-003\n- parent: WBV2-P16-002\n- status: planned\n- gap: workflow:close_paint_capability_gate\n- ownerFamily: RELEASE\n- targetImplementationClass: LOCAL_BOUNDED\n\n## 目标\n\nClose the paint capability gate without promoting representative evidence to full-family completion.\n\n## 输入与范围\n\n- Focused receipt: \`tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json\`\n- Coverage matrix: \`tests/golden/WBV2-P14-002/capability-evidence-matrix.json\`\n- Production entrypoint: \`node tools/web/generate-wbv2-paint-gate.mjs --write\`\n\n## 验收\n\n- only tested paint behavior is claimed\n- inventory remainder remains 6618\n- duplicate validation remains zero\n- malformed, hash-drift, unsupported, or false-completion input keeps in_progress\n- historical reproduction remains false\n- \`node tools/web/check-task-context.mjs --task WBV2-P16-003 --write\`\n\n## 交付与回滚\n\n- Reports: \`tests/golden/WBV2-P16-003/\`\n- Status: \`docs/status/WBV2-P16-003.md\`\n- Manifest: \`tests/golden/WBV2-P16-003/manifest.json\`\n- Rollback: restore P16-002 as queue parent.\n`,
};
for (const [id, card] of Object.entries(cards)) fs.writeFileSync(absolute(`docs/tasks/${id}.md`), `${card}\n`);
fs.writeFileSync(absolute(statusPath), `# WBV2-P16-000 status\n\n- task: \`WBV2-P16-000\`; parent: \`WBV2-P15-003\`; status: \`done\`\n- candidate: \`SCULPT.PAINT_ATTRIBUTES\`; source commands and existing receipts are present\n- inventory carried forward: \`6900\` total, \`6618\` pending\n- duplicate validation: \`forbidden\`; representative slice only\n- nextTask: \`WBV2-P16-001\`\n\nP16 is an authorized continuation that reuses P14 coverage and validates one unique vertex-color/weight behavior batch in Chromium.\n`);
const artifactPaths = { parentManifest: p15ManifestPath, parentReport: p15ReportPath, inventory: inventoryPath, sourceReport: sourceReportPath, sourceRunner: sourceRunnerPath, sourceApi: sourceCommandPath, sourceTest: sourceTestPath, plan: planPath, report: reportPath, rootCard: "docs/tasks/WBV2-P16-000.md", rootStatus: statusPath };
const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }]));
const manifest = { schemaVersion: 1, task: "WBV2-P16-000", parentTask: "WBV2-P15-003", operation: "AUTHORIZE_PAINT_CAPABILITY_CONTINUATION", status: "done", enablingTask: true, parityStateChange: false, runtime: "READ_ONLY_PAINT_CONTINUATION_ROOT", artifacts, assertions: { p15EvidencePreserved: true, sourceCommandsBound: true, existingPaintReceiptBound: true, inventoryTotal: 6900, inventoryPending: 6618, duplicateValidationAvoided: true, representativeSliceOnly: true, authorizedRebaselineOnly: true, fullHistoricalReproduction: false }, nextTask: "WBV2-P16-001" };
fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
execFileSync(process.execPath, [absolute("tools/web/generate-v2-task-index.mjs"), "--plan-path", absolute(planPath)], { cwd: root, stdio: "inherit" });
let queue = read("docs/EXECUTION_QUEUE.md"); queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P16-001` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P16-000/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P16-001.md`](tasks/WBV2-P16-001.md) |"); fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
let nextTask = read("nextTask.md"); nextTask = nextTask.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | `WBV2-P16-001` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P16-000/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P16-001.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `WBV2-P16-002` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-paint-selection.mjs --write` |"); fs.writeFileSync(absolute("nextTask.md"), nextTask);
process.stdout.write("wbv2-paint-root-written root=WBV2-P16-000 next=WBV2-P16-001 candidate=SCULPT.PAINT_ATTRIBUTES inventoryPending=6618\n");