Files
workinf_Blender_Wasm/tools/web/authorize-wbv2-p1143.mjs
mes123456 f3e21c6b98
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
chore: checkpoint web Blender migration source, tools and docs
Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer,
web workflow engine and protocol, tooling, docs and task records.
Large generated evidence, user-testing archives, build snapshots and
imported test assets remain untracked.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-11-10 11:18:01 +08:00

77 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 abs = (file) => path.join(root, file);
const read = (file) => fs.readFileSync(abs(file), "utf8");
const json = (file) => JSON.parse(read(file));
const sha = (file) => crypto.createHash("sha256").update(fs.readFileSync(abs(file))).digest("hex");
const writeJson = (file, value) => { fs.mkdirSync(path.dirname(abs(file)), { recursive: true }); fs.writeFileSync(abs(file), `${JSON.stringify(value, null, 2)}\n`); };
const writeText = (file, value) => { fs.mkdirSync(path.dirname(abs(file)), { recursive: true }); fs.writeFileSync(abs(file), value); };
const run = (entry, ...args) => execFileSync(process.execPath, [abs(entry), ...args], { cwd: root, stdio: "inherit" });
const parentTask = "WBV2-P1142-001";
const rootTask = "WBV2-P1143-000";
const moduleTask = "WBV2-P1143-001";
const moduleId = "FCURVE_MODIFIER_READER";
const planPath = "tests/golden/WBV2-P1100-000/module-execution-plan.json";
const parentManifestPath = `tests/golden/${parentTask}/manifest.json`;
const dynamicPath = "tests/golden/WBV2/dynamic-inventory.json";
const sourcePaths = [
"blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp",
"web/protocol/scene-ir.ts",
"web/app/src/workers/web-engine.worker.ts",
"web/app/src/engine-client/WebEngineClient.ts",
"web/tests/e2e/wbv2-fcurve-modifier-production.spec.ts",
"web/app/src/vendor/blender/web_engine.wasm",
];
const commands = [
"source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm",
"npm --prefix web run typecheck",
"npm --prefix web run build",
"WEB_TEST_PORT=5368 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-fcurve-modifier-production.spec.ts",
];
const queuePath = "docs/EXECUTION_QUEUE.md";
const queueTask = read(queuePath).match(/\| 当前任务 \| `([^`]+)` \|/u)?.[1];
assert.ok([parentTask, rootTask, moduleTask].includes(queueTask));
const parent = json(parentManifestPath);
assert.equal(parent.status, "done");
assert.ok(parent.nextTask === null || parent.nextTask === rootTask);
const plan = json(planPath);
assert.ok(["COMPLETED_MODULE_EXECUTION", "ACTIVE_MODULE_EXECUTION_QUEUE"].includes(plan.status));
const dynamic = json(dynamicPath);
const dynamicSummary = { path: dynamicPath, sourceTreeSha256: dynamic.authority.sourceTreeSha256, unitCount: dynamic.summary.unitCount, planningEstimate: dynamic.policy.planningEstimate, hardTarget: dynamic.policy.hardTarget, verifiedUnits: dynamic.coverage.verifiedUnits, unverifiedUnits: dynamic.coverage.unverifiedUnits };
const module = { moduleId, sourceBacked: true, capabilities: ["CAP-FCURVE-MODIFIER-READER", "CAP-FCURVE-MODIFIER-RECOVERY", "CAP-FCURVE-MODIFIER-FAIL-CLOSED"], sourcePaths, reuseReceipts: [{ manifest: "tests/golden/WBV2-P1142-001/manifest.json", report: "tests/golden/WBV2-P1142-001/module-receipt.json" }], positive: ["FCurveModifiers Main reader exposes native modifier stack", "FModifierCycles preserves type/name/flags/influence", "save/reopen preserves modifier metadata"], negative: ["malformed blend is rejected without Main mutation", "missing modifier payload is fail-closed", "unsupported modifier type is not synthesized"], recovery: ["undo", "redo", "save/reopen", "worker termination and deterministic modifier state"], commands, fullFamilyParity: false };
const rootRecord = { id: rootTask, phase: "1143", title: "authorize_fcurve_modifier_reader_module", kind: "enabling", owner: "ANIMATION", dependsOn: [parentTask], parityId: null, implementationClass: "QUEUE_ONLY", parallelGroup: "module-root-1143", gate: "MODULE", card: `docs/tasks/${rootTask}.md`, behavior: "Authorize a source-backed FCurve modifier reader and recovery module after P1142.", outputs: ["successor authorization", "module plan", "manifest", "status"], acceptance: ["P1142 evidence remains hash-bound", "FCurveModifiers has explicit Blender source mapping", "inventory remains source-derived", "one source-backed module is active"], commands: ["node tools/web/check-execution-control-plane.mjs"], status: "done", ready: false, queueMutationAllowed: true };
const moduleRecord = { id: moduleTask, phase: "1143", title: "verify_fcurve_modifier_reader_module", kind: "module", owner: "ANIMATION", dependsOn: [rootTask], parityId: moduleId, implementationClass: "LOCAL_EXACT", parallelGroup: "module-fcurve_modifier_reader", gate: "MODULE", card: `docs/tasks/${moduleTask}.md`, behavior: "Verify FCurve modifier metadata through Blender Main reader, protocol and Chromium recovery.", outputs: ["module receipt", "negative matrix", "manifest", "status"], acceptance: ["source and protocol hashes are bound", "positive Main reader is proven", "negative no-mutation and recovery are proven", "Chromium and save/reopen evidence are exact", "full-family parity remains explicit"], status: "in_progress", ready: true, queueMutationAllowed: true, module };
plan.status = "ACTIVE_MODULE_EXECUTION_QUEUE";
if (!plan.modules.some((entry) => entry.id === moduleId)) plan.modules.push({ id: moduleId, task: moduleTask, owner: "ANIMATION", sourceBacked: true, capabilities: module.capabilities, reusedReceipts: module.reuseReceipts, fullFamilyParity: false });
if (!plan.tasks.some((entry) => entry.id === rootTask)) plan.tasks.push(rootRecord);
if (!plan.tasks.some((entry) => entry.id === moduleTask)) plan.tasks.push(moduleRecord);
writeJson(planPath, plan);
run("tools/web/generate-v2-task-index.mjs", "--plan-path", abs(planPath));
parent.nextTask = rootTask;
parent.continuation = { authorized: true, root: rootTask, scope: moduleId, priorModule: parentTask };
parent.artifacts.plan.sha256 = sha(planPath);
writeJson(parentManifestPath, parent);
writeText(`docs/tasks/${rootTask}.md`, `# ${rootTask}: authorize FCurve modifier reader\n\n- task: ${rootTask}\n- parent: ${parentTask}\n- status: done\n- ownerFamily: ANIMATION\n- targetImplementationClass: QUEUE_ONLY\n- Implementation entrypoint: \`node tools/web/authorize-wbv2-p1143.mjs\`\n\n## 目标\n\n授权一个 source-backed FCurve modifier reader/recovery 模块。\n\n## 输入与范围\n\n- RNA: \`blender-5.2.0/source/blender/makesrna/intern/rna_fcurve.cc\` (FCurveModifiers/FModifier/FModifierCycles)\n- Reader: \`blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp\`\n- Chromium: \`web/tests/e2e/wbv2-fcurve-sample-production.spec.ts\`\n\n## 验收\n\n- P1142 evidence stays hash-bound; one source-backed module active; malformed or hash-drift input remains \`in_progress\`.\n- \`node tools/web/check-execution-control-plane.mjs\`\n\n## 交付与回滚\n\n- 交付 P1143 manifests/status/receipt;回滚恢复 P1142 终态指针。\n`);
writeText(`docs/status/${rootTask}.md`, `# ${rootTask} status\n\n- task: \`${rootTask}\`; parent: \`${parentTask}\`; status: \`done\`\n- operation: \`AUTHORIZE_SOURCE_BACKED_MODULE\`; module: \`${moduleId}\`\n- P1142 evidence reused; historical 6900-entry inventory remains immutable\n- dynamic source inventory: \`${dynamicSummary.unitCount}\` units, verified \`${dynamicSummary.verifiedUnits}\`, unverified \`${dynamicSummary.unverifiedUnits}\`, planning estimate \`${dynamicSummary.planningEstimate}\` (non-binding)\n- nextTask: \`${moduleTask}\`\n`);
let updatedQueue = read(queuePath).replace(/\| 当前任务 \| `[^`]+` \|/u, `| 当前任务 | \`${rootTask}\` |`).replace(/\| parent manifest \| `[^`]+` \|/u, `| parent manifest | \`${parentManifestPath}\` |`).replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, `| 任务卡 | [\`tasks/${rootTask}.md\`](tasks/${rootTask}.md) |`);
writeText(queuePath, updatedQueue);
run("tools/web/check-task-context.mjs", "--task", rootTask, "--write");
const rootReportPath = `tests/golden/${rootTask}/successor-authorization-report.json`;
const rootStatusPath = `docs/status/${rootTask}.md`;
const rootContextPath = `tests/golden/${rootTask}/task-context.json`;
writeJson(rootReportPath, { schemaVersion: 1, task: rootTask, operation: "AUTHORIZE_SOURCE_BACKED_MODULE", status: "PASS", parent: { task: parentTask, manifest: parentManifestPath, manifestSha256: sha(parentManifestPath) }, successor: { task: moduleTask, moduleId, sourceBacked: true, noRepeatedImplementation: true }, inventory: { ...plan.inventory, boundCaseDelta: 0 }, dynamicInventory: { ...dynamicSummary, boundUnitDelta: 0 }, nextTask: moduleTask });
writeJson(`tests/golden/${rootTask}/manifest.json`, { schemaVersion: 1, task: rootTask, parentTask, operation: "AUTHORIZE_SOURCE_BACKED_MODULE", status: "done", enablingTask: true, parityStateChange: false, runtime: "MODULE_EXECUTION_QUEUE_BRIDGE", artifacts: { parentManifest: { path: parentManifestPath, sha256: sha(parentManifestPath) }, plan: { path: planPath, sha256: sha(planPath) }, report: { path: rootReportPath, sha256: sha(rootReportPath) }, status: { path: rootStatusPath, sha256: sha(rootStatusPath) }, taskContext: { path: rootContextPath, sha256: sha(rootContextPath) } }, assertions: { sourceBackedSuccessor: true, priorEvidencePreserved: true, inventoryTotal: 6900, effectiveCompleted: 290, effectivePending: 6609, boundCaseDelta: 0, dynamicInventory: dynamicSummary, fullHistoricalReproduction: false }, nextTask: moduleTask });
updatedQueue = read(queuePath).replace(/\| 当前任务 \| `[^`]+` \|/u, `| 当前任务 | \`${moduleTask}\` |`).replace(/\| parent manifest \| `[^`]+` \|/u, `| parent manifest | \`tests/golden/${rootTask}/manifest.json\` |`).replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, `| 任务卡 | [\`tasks/${moduleTask}.md\`](tasks/${moduleTask}.md) |`);
writeText(queuePath, updatedQueue);
writeText(`docs/tasks/${moduleTask}.md`, `# ${moduleTask}: verify FCurve modifier reader\n\n- task: ${moduleTask}\n- parent: ${rootTask}\n- status: in_progress\n- gap: workflow:fcurve_modifier_reader\n- ownerFamily: ANIMATION\n- targetImplementationClass: LOCAL_EXACT\n- moduleId: ${moduleId}\n- Implementation entrypoint: \`node tools/web/run-wbv2-module-task.mjs --task ${moduleTask} --write\`\n\n## 目标\n\n验证 Blender Main 的 FCurve modifier 栈在 Chromium recovery/save-reopen 中保持一致。\n\n## 输入与范围\n\n${sourcePaths.map((file) => `- \`${file}\``).join("\n")}\n- RNA: \`blender-5.2.0/source/blender/makesrna/intern/rna_fcurve.cc\` (FCurveModifiers/FModifier/FModifierCycles)\n- Fixture: \`tests/files/web/generated/M16-GAP-00161-action-fcurve-modifier.blend\`\n- Production test: \`web/tests/e2e/wbv2-fcurve-sample-production.spec.ts\`\n\n## 验收\n\n- Positive: ${module.positive.join(", ")}\n- Negative: ${module.negative.join(", ")}\n- Recovery: ${module.recovery.join(", ")}\n- Commands:\n${commands.map((command) => `- \`${command}\``).join("\n")}\n- JS simulation is forbidden; all behavior must come from Blender Main/WASM.\n\n## 交付与回滚\n\n- Receipt: \`tests/golden/${moduleTask}/module-receipt.json\`; Manifest: \`tests/golden/${moduleTask}/manifest.json\`; Status: \`docs/status/${moduleTask}.md\`.\n`);
run("tools/web/check-task-context.mjs", "--task", moduleTask, "--write");
run("tools/web/check-execution-control-plane.mjs");
process.stdout.write(`wbv2-successor-authorized root=${rootTask} next=${moduleTask} module=${moduleId}\n`);