- update native web_engine sources and rebuilt wasm artifacts - add task cards, status notes and tooling scripts - add web e2e specs, tutorial UI sources and tutorial assets - sync golden task manifests and audit records Co-Authored-By: Claude Code <noreply@anthropic.com>
431 lines
19 KiB
JavaScript
431 lines
19 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 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`);
|