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 sourcePlanPath = "tests/golden/WBV2-P1424-001/recovery-20261020/execution-plan.json"; const planPath = "tests/golden/WBV2-P1425-000/domain-parity-plan.json"; const parentTask = "WBV2-P1424-001"; const bridgeTask = "WBV2-P1424-900"; const rootTask = "WBV2-P1425-000"; const moduleTask = "WBV2-P1425-001"; const moduleId = "OBJECT_ADD_ROUTE"; const queuePath = "docs/EXECUTION_QUEUE.md"; const parentManifestPath = `tests/golden/${parentTask}/manifest.json`; const bridgeManifestPath = `tests/golden/${bridgeTask}/manifest.json`; const planDocPath = "docs/plans/CREATE_MODEL_HIERARCHY_PARITY_PLAN.md"; const preservedContinuation = "tests/golden/WBV2-P1424-001/continuation-20261103-goal-numpy.json"; // Repair the partial first run if it touched the preserved task head; the original // task must keep its in_progress status and null nextTask byte-for-byte. const parentManifest = read(parentManifestPath); const polluted = ` "status": "in_progress",\n "enablingTask": true,\n "nextTask": "${rootTask}",\n "supersession": [^\n]*,\n`; const pristine = ` "status": "in_progress",\n "nextTask": null,\n`; const restored = parentManifest.replace(new RegExp(polluted, "u"), pristine); assert.ok(!restored.includes(`"nextTask": "${rootTask}"`), "failed to restore the preserved P1424-001 manifest"); if (restored !== parentManifest) writeText(parentManifestPath, restored); assert.equal(fs.statSync(abs(parentManifestPath)).size, 212423, "P1424-001 manifest size changed; refuse to continue"); const inventory = json("tests/golden/WBV2/dynamic-inventory.json"); const createIdentifiers = new Set([ "OBJECT_OT_add", "OBJECT_OT_add_named", "OBJECT_OT_camera_add", "OBJECT_OT_light_add", "OBJECT_OT_empty_add", "OBJECT_OT_armature_add", ]); const coverageBindings = inventory.units .filter((unit) => { const id = unit.identifier ?? ""; return /^MESH_OT_primitive_(circle|cone|cube|cylinder|grid|ico_sphere|monkey|plane|uv_sphere)_add$/u.test(id) || createIdentifiers.has(id); }) .map((unit) => unit.id); assert.ok(coverageBindings.length >= 14, `create coverage bindings too small: ${coverageBindings.length}`); const moduleContract = { moduleId, sourceBacked: true, capabilities: [ "CAP-OBJECT-ADD-MENU", "CAP-MESH-PRIMITIVE-ADD", "CAP-MESH-PRIMITIVE-PARAMETERS", "CAP-OPERATOR-CHANNEL-NATIVE-CONTEXT", ], sourcePaths: [ "blender-5.2.0/source/blender/web_engine/web_engine_python_bootstrap.py", "blender-5.2.0/source/blender/web_engine/web_engine_gpu_ui.cpp", "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", "web/app/src/app/App.tsx", "web/app/src/engine-client/WebEngineClient.ts", "web/protocol/web-engine.ts", "web/app/src/capabilities/blender-feature-route-catalog.json", ], reuseReceipts: [ { manifest: "tests/golden/WBV2-P18-002/manifest.json", report: "tests/golden/WBV2-P18-002/object-create-production.json" }, ], positive: [ "Add Circle/Grid/Monkey and existing mesh primitives through the native operator channel", "Create camera/light/empty/armature through the same Add menu route", "location/rotation/scale/align/enter_editmode are applied by the native operator", ], negative: [ "unsupported primitive identifier fails with a structured error and no Main mutation", "stale baseRevision and wrong mode/area fail closed without an undo entry", ], recovery: ["undo", "redo", "save/reopen", "worker restart"], commands: [ "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8", "node tools/web/sync-web-engine-runtime.mjs", ], coverageBindings, fullFamilyParity: false, }; const bridgeRecord = { id: bridgeTask, phase: "1424", title: "supersede_stalled_task_for_domain_parity", kind: "bridge", owner: "PROGRAM", dependsOn: [parentTask], parityId: null, implementationClass: "QUEUE_ONLY", parallelGroup: "domain-parity-bridge", gate: "QUEUE", card: `docs/tasks/${bridgeTask}.md`, behavior: "Record the user-authorized supersession of stalled WBV2-P1424-001 and authorize the P1425 domain-parity epoch without modifying the preserved task manifest.", outputs: ["supersession record", "bridge manifest", "status"], acceptance: ["P1424-001 manifest and continuation remain preserved", "bridge manifest points to P1425-000"], commands: ["node tools/web/check-execution-control-plane.mjs"], status: "done", ready: false, queueMutationAllowed: true, supersedes: parentTask, }; const rootRecord = { id: rootTask, phase: "1425", title: "authorize_create_model_hierarchy_parity_epoch", kind: "bridge", owner: "PROGRAM", dependsOn: [bridgeTask], parityId: null, implementationClass: "QUEUE_ONLY", parallelGroup: "domain-parity-root-1425", gate: "QUEUE", card: `docs/tasks/${rootTask}.md`, behavior: "Authorize the create/modeling/hierarchy full-parity epoch while preserving the stalled P1424-001 task record.", outputs: ["domain parity plan", "successor authorization", "manifest", "status"], acceptance: [ "P1424-001 manifest and continuation remain intact and in_progress", "plan/index/queue pointer are consistent", "one source-backed module is active", ], commands: ["node tools/web/check-execution-control-plane.mjs"], status: "done", ready: false, queueMutationAllowed: true, supersedes: parentTask, userAuthorization: { approvedAt: "2026-11-10", scope: "创建模型 / 模型化 / 模型层级 三域全量对标桌面 Blender", planDocument: planDocPath, decision: "授权桥接并保留 P1424-001 记录", }, }; const moduleRecord = { id: moduleTask, phase: "1425", title: "implement_object_add_route", kind: "module", owner: "OBJECT", dependsOn: [rootTask], parityId: moduleId, implementationClass: "LOCAL_EXACT", parallelGroup: "module-object_add_route", gate: "MODULE", card: `docs/tasks/${moduleTask}.md`, behavior: "Route the Web Add menu through the native desktop operator channel for mesh primitives and basic object helpers.", outputs: ["module contract", "Add menu wiring", "positive/negative/recovery cases", "manifest", "status"], acceptance: [ "every bound operator unit has a native Main mutation case", "unsupported/stale/wrong-context cases fail closed", "undo/redo and save/reopen preserve identical semantics", "full-family parity remains explicit", ], commands: moduleContract.commands, status: "in_progress", ready: true, queueMutationAllowed: true, module: moduleContract, }; const plan = fs.existsSync(abs(planPath)) ? json(planPath) : JSON.parse(JSON.stringify(json(sourcePlanPath))); plan.planId = "BLENDER_WEB_CREATE_MODEL_HIERARCHY_PARITY_P1425"; plan.status = "ACTIVE_MODULE_EXECUTION_QUEUE"; plan.authority = { ...(plan.authority ?? {}), userAuthorization: { approvedAt: "2026-11-10", scope: "创建模型 / 模型化 / 模型层级 三域全量对标桌面 Blender", planDocument: planDocPath, supersedes: parentTask, preservedTask: parentTask, bridge: bridgeTask, }, }; plan.tasks = plan.tasks.filter((task) => ![bridgeTask, rootTask, moduleTask].includes(task.id)); plan.modules = plan.modules.filter((module) => module.id !== moduleId); const stalled = plan.tasks.find((task) => task.id === parentTask); assert.ok(stalled, `${parentTask} record is missing`); stalled.status = "blocked"; stalled.ready = false; stalled.supersededBy = bridgeTask; stalled.supersessionReason = "User approved the three-domain full-parity plan on 2026-11-10; P1424-001 manifest, continuation and acceptance state are preserved."; stalled.preservedContinuation = preservedContinuation; plan.tasks.push(bridgeRecord, rootRecord, moduleRecord); plan.modules.push({ id: moduleId, task: moduleTask, owner: "OBJECT", sourceBacked: true, capabilities: moduleContract.capabilities, reusedReceipts: moduleContract.reuseReceipts, fullFamilyParity: false, }); writeJson(planPath, plan); writeText(planDocPath, fs.readFileSync(path.join(process.env.HOME ?? "", ".claude/plans/cosmic-greeting-marble.md"), "utf8")); writeText(`docs/tasks/${bridgeTask}.md`, `# ${bridgeTask}: supersede stalled task for domain parity - task: ${bridgeTask} - parent: ${parentTask} - status: done - ownerFamily: PROGRAM - targetImplementationClass: QUEUE_ONLY ## 目标 记录用户 2026-11-10 授权的队列桥接:保留 \`${parentTask}\` 的 manifest、continuation、\`in_progress\` 状态和全部未闭合证据,不修改该文件;由本桥接指向三域全量对标 epoch 根任务 \`${rootTask}\`。 ## 输入与范围 - 保留任务:\`${parentManifestPath}\`(期望 212423 bytes,原样) - 保留 continuation:\`${preservedContinuation}\` - 新计划:\`${planPath}\` ## 验收 - P1424-001 manifest 字节级不变;桥接 manifest 为 done 且 nextTask 指向 \`${rootTask}\`。 - 负例:P1424-001 manifest 大小变化、continuation 缺失或队列已被再次切换时拒绝继续。 - 校验:\`node tools/web/check-execution-control-plane.mjs\` ## 交付与回滚 - 交付桥接 manifest/status/report;回滚把队列恢复为 \`${parentTask}\` 并删除桥接指针,不删除任何证据。 `); writeText(`docs/tasks/${rootTask}.md`, `# ${rootTask}: authorize create/modeling/hierarchy parity epoch - task: ${rootTask} - parent: ${bridgeTask} - status: done - ownerFamily: PROGRAM - targetImplementationClass: QUEUE_ONLY - Implementation entrypoint: \`node tools/web/authorize-wbv2-p1425.mjs\` ## 目标 以用户 2026-11-10 批准的三域全量对标计划为依据,授权新的 module epoch,并把队列指向首个模块 \`${moduleTask}\`。\`${parentTask}\` 的 manifest、continuation、in_progress 状态和全部未闭合证据原样保留,不删除、不伪装完成。 ## 输入与范围 - 用户批准计划:\`${planDocPath}\` - 源队列计划:\`${sourcePlanPath}\` - 新计划:\`${planPath}\` - 保留任务:\`${parentTask}\`(\`${parentManifestPath}\`) - 桥接 manifest:\`${bridgeManifestPath}\` ## 验收 - P1424-001 manifest 仍为 \`in_progress\` 且字节级未变。 - 新计划中恰好一个 ready/in_progress 模块;索引 activeTask 与队列指针一致。 - 负例:P1424-001 缺失、重复授权或索引不一致时脚本必须拒绝对队列做第二次切换。 - \`node tools/web/check-execution-control-plane.mjs\` ## 交付与回滚 - 交付 plan、manifest、status、report、task-context;校验 \`node tools/web/check-execution-control-plane.mjs\`。 - 回滚:恢复队列指针为 \`${parentTask}\`;新计划文件保留但不得作为 active 队列。 `); writeText(`docs/tasks/${moduleTask}.md`, `# ${moduleTask}: implement Add menu native operator route - task: ${moduleTask} - parent: ${rootTask} - status: in_progress - gap: workflow:object_add_route - ownerFamily: OBJECT - targetImplementationClass: LOCAL_EXACT - moduleId: ${moduleId} - Implementation entrypoint: \`node tools/web/run-wbv2-module-task.mjs --task ${moduleTask} --write\` ## 目标 让 WASM 本地模式的 Add 菜单通过现有通用桌面 operator 通道(\`desktop_operator_catalog/schema/desktop_operator\` + \`gpuUIInvoke\`)创建 Mesh 全部基础体,包括缺失的 Circle/Grid/Monkey,并支持 location/rotation/scale/align/enter_editmode 参数;复用 Operator Palette、\`WebEngineClient\` 与原生 Main,不新增并行执行器。 ## 输入与范围 - 原生通道:\`blender-5.2.0/source/blender/web_engine/web_engine_python_bootstrap.py\`、\`web_engine_gpu_ui.cpp\`、\`web_engine_api.cpp\` - 前端:\`web/app/src/app/App.tsx\`(Add 菜单、F3、快捷条)、\`web/app/src/engine-client/WebEngineClient.ts\` - 协议/路由:\`web/protocol/web-engine.ts\`、\`web/app/src/capabilities/blender-feature-route-catalog.json\` - 绑定的源码单元:${coverageBindings.join(", ")} - 已复用证据:\`tests/golden/WBV2-P18-002/manifest.json\`、\`tests/golden/WBV2-P18-002/object-create-production.json\` ## 失败边界 不支持的基础体/参数、错误 mode/area、陈旧 baseRevision、modal 占用必须返回结构化错误,Main revision 不变且不产生 undo 记录;linked/只读对象不得被创建路径绕过。 ## 验收 - 正例:Add Circle/Grid/Monkey 及既有基础体经原生通道创建,Main mutation 与 snapshot 反映对象。 - 负例:非法标识、非法参数、陈旧 revision、错误上下文均 no-mutation。 - 恢复:undo/redo、save/reopen、Worker restart 语义一致。 - 命令:实现期只做增量编译与 runtime 同步;全部功能完成后由用户在 Chromium 验证。结果标 \`NOT_CLAIMED\`。 - \`cmake --build build_web_blender6 --target web_engine -- -j8\` - \`node tools/web/sync-web-engine-runtime.mjs\` ## 交付与回滚 - 交付 module receipt、manifest、status、continuation;失败保持 \`in_progress\`,保留已有构件与证据。 `); const reportPath = `tests/golden/${rootTask}/successor-authorization-report.json`; writeJson(`tests/golden/${bridgeTask}/supersession-report.json`, { schemaVersion: 1, task: bridgeTask, operation: "SUPERSEDE_STALLED_TASK_FOR_DOMAIN_PARITY", status: "PASS", preserved: { task: parentTask, manifest: parentManifestPath, manifestBytes: fs.statSync(abs(parentManifestPath)).size, manifestSha256: sha(parentManifestPath), status: "in_progress", continuation: preservedContinuation, continuationSha256: sha(preservedContinuation), acceptance: "NOT_CLAIMED", }, userAuthorization: rootRecord.userAuthorization, successor: { task: rootTask, plan: planPath }, nextTask: rootTask, }); writeText(`docs/status/${bridgeTask}.md`, `# ${bridgeTask} status - task: \`${bridgeTask}\`; parent: \`${parentTask}\`; status: \`done\` - operation: \`SUPERSEDE_STALLED_TASK_FOR_DOMAIN_PARITY\` - preserved: \`${parentTask}\` manifest \`${fs.statSync(abs(parentManifestPath)).size}\` bytes, status \`in_progress\`, continuance \`${preservedContinuation}\` - successor: \`${rootTask}\`; plan: \`${planPath}\` - nextTask: \`${rootTask}\` `); writeJson(bridgeManifestPath, { schemaVersion: 1, task: bridgeTask, parentTask, operation: "SUPERSEDE_STALLED_TASK_FOR_DOMAIN_PARITY", status: "done", enablingTask: true, parityStateChange: false, artifacts: { preservedManifest: { path: parentManifestPath, sha256: sha(parentManifestPath) }, preservedContinuation: { path: preservedContinuation, sha256: sha(preservedContinuation) }, report: { path: `tests/golden/${bridgeTask}/supersession-report.json`, sha256: sha(`tests/golden/${bridgeTask}/supersession-report.json`) }, status: { path: `docs/status/${bridgeTask}.md`, sha256: sha(`docs/status/${bridgeTask}.md`) }, }, assertions: { preservedTaskStatus: "in_progress", preservedAcceptance: "NOT_CLAIMED", preservedManifestBytes: fs.statSync(abs(parentManifestPath)).size, supersedes: parentTask, userApprovedAt: rootRecord.userAuthorization.approvedAt, }, nextTask: rootTask, }); writeJson(reportPath, { schemaVersion: 1, task: rootTask, operation: "AUTHORIZE_DOMAIN_PARITY_EPOCH", status: "PASS", parent: { task: bridgeTask, manifest: bridgeManifestPath }, preserved: { task: parentTask, manifest: parentManifestPath, status: "in_progress", continuation: preservedContinuation, acceptance: "NOT_CLAIMED" }, successor: { task: moduleTask, moduleId, sourceBacked: true, coverageBindings: coverageBindings.length }, plan: { path: planPath, sha256: sha(planPath) }, userAuthorization: rootRecord.userAuthorization, nextTask: moduleTask, }); writeText(`docs/status/${rootTask}.md`, `# ${rootTask} status - task: \`${rootTask}\`; parent: \`${bridgeTask}\`; status: \`done\` - operation: \`AUTHORIZE_DOMAIN_PARITY_EPOCH\`; module: \`${moduleId}\` - preserved: \`${parentTask}\` manifest remains \`in_progress\` (\`${fs.statSync(abs(parentManifestPath)).size}\` bytes); continuation \`${preservedContinuation}\`; acceptance \`NOT_CLAIMED\` - new plan: \`${planPath}\`; bound source units: \`${coverageBindings.length}\` - nextTask: \`${moduleTask}\` `); run("tools/web/generate-v2-task-index.mjs", "--plan-path", abs(planPath)); let queue = read(queuePath); queue = queue .replace(/\| 当前任务 \| `[^`]+` \|/u, `| 当前任务 | \`${moduleTask}\` |`) .replace(/\| 里程碑 \| [^|]+ \|/u, `| 里程碑 | 三域全量对标(创建模型 / 模型化 / 模型层级) |`) .replace(/\| parent manifest \| `[^`]+` \|/u, `| parent manifest | \`tests/golden/${rootTask}/manifest.json\` |`) .replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, `| 任务卡 | [\`tasks/${moduleTask}.md\`](tasks/${moduleTask}.md) |`); writeText(queuePath, queue); run("tools/web/check-task-context.mjs", "--task", rootTask, "--write"); writeJson(`tests/golden/${rootTask}/manifest.json`, { schemaVersion: 1, task: rootTask, parentTask: bridgeTask, operation: "AUTHORIZE_DOMAIN_PARITY_EPOCH", status: "done", enablingTask: true, parityStateChange: false, artifacts: { parentManifest: { path: bridgeManifestPath, sha256: sha(bridgeManifestPath) }, plan: { path: planPath, sha256: sha(planPath) }, report: { path: reportPath, sha256: sha(reportPath) }, status: { path: `docs/status/${rootTask}.md`, sha256: sha(`docs/status/${rootTask}.md`) }, taskContext: { path: `tests/golden/${rootTask}/task-context.json`, sha256: sha(`tests/golden/${rootTask}/task-context.json`) }, }, assertions: { supersedes: parentTask, bridge: bridgeTask, preservedTaskStatus: "in_progress", preservedManifestBytes: fs.statSync(abs(parentManifestPath)).size, preservedContinuation, userApprovedAt: rootRecord.userAuthorization.approvedAt, moduleId, coverageBindings: coverageBindings.length, sourceBackedSuccessor: true, fullFamilyParity: false, }, nextTask: moduleTask, }); run("tools/web/check-task-context.mjs", "--task", moduleTask, "--write"); run("tools/web/check-execution-control-plane.mjs"); process.stdout.write(`wbv2-domain-parity-authorized bridge=${bridgeTask} root=${rootTask} next=${moduleTask} module=${moduleId} preserved=${parentTask}\n`);