45 lines
8.8 KiB
JavaScript
45 lines
8.8 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 sha = (file) => crypto.createHash("sha256").update(fs.readFileSync(abs(file))).digest("hex");
|
|
const queue = read("docs/EXECUTION_QUEUE.md");
|
|
const task = queue.match(/\| 当前任务 \| `(WBV2-P\d+-000)` \|/u)?.[1];
|
|
if (!task) throw new Error("capability continuation root requires a -000 queue task");
|
|
const phase = Number(task.match(/^WBV2-P(\d+)-000$/u)?.[1]);
|
|
const parentPath = queue.match(/\| parent manifest \| `([^`]+)` \|/u)?.[1];
|
|
if (!parentPath || !Number.isSafeInteger(phase)) throw new Error("capability continuation root pointer is incomplete");
|
|
const parent = JSON.parse(read(parentPath));
|
|
assert.equal(parent.status, "done");
|
|
assert.equal(parent.nextTask, task);
|
|
const ids = [`WBV2-P${phase}-000`, `WBV2-P${phase}-001`, `WBV2-P${phase}-002`, `WBV2-P${phase}-003`];
|
|
const records = ids.map((id, index) => ({ id, phase: `P${phase}`, title: index === 0 ? "authorize_capability_family_wave" : index === 1 ? "index_capability_family_batches" : index === 2 ? "implement_capability_family_slice" : "run_capability_family_smoke", kind: index === 0 || index === 3 ? "enabling" : "feature", owner: index === 0 ? "PROGRAM" : index === 2 ? "IMPLEMENTATION" : "RELEASE", dependsOn: [index === 0 ? parent.task : ids[index - 1]], parityId: null, implementationClass: "SOURCE_BACKED", parallelGroup: `p${phase}-${String(index).padStart(3, "0")}`, gate: index === 0 ? "G1" : "IMPLEMENTATION", card: `docs/tasks/${id}.md`, behavior: index === 0 ? "Authorize capability-family implementation over the immutable 6900-entry inventory." : index === 1 ? "Reuse the 27 deduplicated capability batches and unique behavior keys." : index === 2 ? "Implement the next uncovered Blender capability family from the source-backed index." : "Run source and frontend smoke without Chromium parity verification.", outputs: ["implementation-report", "manifest", "status"], acceptance: ["6900 inventory remains immutable", "capability families are deduplicated before implementation", "real Blender source or WebEngine Main path is wired", "verification and completion overlay remain deferred"], status: index === 0 ? "done" : index === 1 ? "in_progress" : "planned", ready: index === 1, queueMutationAllowed: index === 0 }));
|
|
const out = `tests/golden/WBV2-P${phase}-000`;
|
|
const planPath = `${out}/capability-continuation-plan.json`;
|
|
fs.mkdirSync(abs(out), { recursive: true });
|
|
fs.writeFileSync(abs(planPath), `${JSON.stringify({ schemaVersion: 1, planId: `BLENDER_WEB_CAPABILITY_CONTINUATION_P${phase}`, status: "ACTIVE_CAPABILITY_FAMILY_QUEUE", authority: "user_authorized_implementation_first_execution", sourceAuthority: { blenderRoot: "blender-5.2.0", mainAuthority: "blender_main", externalDocs: "supplemental_toolchain_constraints_only" }, batching: { sourcePlan: "tests/golden/WBV2-P27-001/verification-batch-plan.json", batchCount: 27, pendingRows: 6609, dedupeBy: ["sourceHash", "behaviorHash", "dedupeKey"] }, inventoryPolicy: { total: 6900, legacyCompleted: 281, legacyPending: 6618, effectiveCompleted: 290, effectivePending: 6609, overlayMutation: "forbidden_during_implementation_wave" }, tasks: records }, null, 2)}\n`);
|
|
const reportPath = `${out}/capability-continuation-root-report.json`;
|
|
const statusPath = `docs/status/${task}.md`;
|
|
fs.writeFileSync(abs(reportPath), `${JSON.stringify({ schemaVersion: 1, task, operation: "AUTHORIZE_CAPABILITY_FAMILY_CONTINUATION", taskClass: "QUEUE_ENABLEMENT", capabilityId: null, behaviorMarker: "AUTHORIZE_CAPABILITY_FAMILY_CONTINUATION", status: "PASS", parent: { task: parent.task, manifest: parentPath, manifestSha256: sha(parentPath) }, sourceAuthority: "blender-5.2.0", batching: { batchCount: 27, pendingRows: 6609, deduplication: true }, verification: { status: "DEFERRED", chromium: false, completionOverlay: false }, inventory: { total: 6900, legacyCompleted: 281, legacyPending: 6618, effectiveCompleted: 290, effectivePending: 6609 }, nextTask: ids[1] }, null, 2)}\n`);
|
|
fs.writeFileSync(abs(statusPath), `# ${task} status\n\n- task: \`${task}\`; parent: \`${parent.task}\`; status: \`done\`\n- taskClass: \`QUEUE_ENABLEMENT\`; no Blender capability completion claimed\n- capability-family continuation authorized from Blender source\n- 6900 inventory: 27 deduplicated batches, 6609 pending rows\n- verification and completion overlay: \`DEFERRED\`\n- nextTask: \`${ids[1]}\`\n`);
|
|
const manifestPath = `${out}/manifest.json`;
|
|
fs.writeFileSync(abs(manifestPath), `${JSON.stringify({ schemaVersion: 1, task, parentTask: parent.task, operation: "AUTHORIZE_CAPABILITY_FAMILY_CONTINUATION", taskClass: "QUEUE_ENABLEMENT", status: "done", enablingTask: true, parityStateChange: false, runtime: "SOURCE_BACKED_CAPABILITY_FAMILY_QUEUE", artifacts: { parentManifest: { path: parentPath, sha256: sha(parentPath) }, plan: { path: planPath, sha256: sha(planPath) }, report: { path: reportPath, sha256: sha(reportPath) }, status: { path: statusPath, sha256: sha(statusPath) } }, assertions: { capabilityId: null, behaviorMarker: "AUTHORIZE_CAPABILITY_FAMILY_CONTINUATION", batchCount: 27, pendingRows: 6609, verificationDeferred: true, completionOverlayWritten: false, inventoryTotal: 6900, effectiveCompleted: 290, effectivePending: 6609, historicalReproduction: false }, nextTask: ids[1] }, null, 2)}\n`);
|
|
for (const [index, id] of ids.entries()) if (index > 0) fs.writeFileSync(abs(`docs/tasks/${id}.md`), `# ${id}: ${records[index].title}\n\n- task: ${id}\n- parent: ${records[index].dependsOn[0]}\n- status: ${records[index].status}\n- gap: workflow:${records[index].title}\n- ownerFamily: ${records[index].owner}\n- targetImplementationClass: SOURCE_BACKED\n\n## 目标\n\n${records[index].behavior}\n\n## 输入与范围\n\n- Blender source authority: \`blender-5.2.0/source/blender\`\n- Batch plan: \`tests/golden/WBV2-P27-001/verification-batch-plan.json\`\n- Implementation entrypoint: \`node tools/web/generate-wbv2-capability-continuation-slice.mjs --task ${id} --write\`\n\n## 验收\n\n- 6900 inventory and provenance remain read-only\n- capability-family deduplication is reused\n- malformed, unsupported, hash-drift and false-completion input fails closed\n- Chromium, E2E receipts and completion overlays remain deferred\n- \`node tools/web/check-task-context.mjs --task ${id} --write\`\n\n## 失败边界\n\n- missing source or unsupported capability remains in_progress/blocked\n- representative implementation is never declared as full-family parity\n\n## 交付与回滚\n\n- Reports: \`tests/golden/${id}/\`\n- Status: \`docs/status/${id}.md\`\n- Manifest: \`tests/golden/${id}/manifest.json\`\n- Rollback: restore ${records[index].dependsOn[0]} as queue parent and leave the task in_progress.\n`);
|
|
execFileSync(process.execPath, [abs("tools/web/generate-v2-task-index.mjs"), "--plan-path", abs(planPath)], { cwd: root, stdio: "inherit" });
|
|
let updatedQueue = read("docs/EXECUTION_QUEUE.md");
|
|
updatedQueue = updatedQueue.replace(/\| 当前任务 \| `[^`]+` \|/u, `| 当前任务 | \`${ids[1]}\` |`).replace(/\| parent manifest \| `[^`]+` \|/u, `| parent manifest | \`tests/golden/WBV2-P${phase}-000/manifest.json\` |`).replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, `| 任务卡 | [\`tasks/${ids[1]}.md\`](tasks/${ids[1]}.md) |`);
|
|
fs.writeFileSync(abs("docs/EXECUTION_QUEUE.md"), updatedQueue);
|
|
execFileSync(process.execPath, [abs("tools/web/check-task-context.mjs"), "--task", task, "--write"], { cwd: root, stdio: "inherit" });
|
|
execFileSync(process.execPath, [abs("tools/web/check-task-context.mjs"), "--task", ids[1], "--write"], { cwd: root, stdio: "inherit" });
|
|
const tick = String.fromCharCode(96);
|
|
let next = read("nextTask.md");
|
|
next = next.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | " + tick + ids[1] + tick + " |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | " + tick + "in_progress" + tick + " |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | " + tick + "tests/golden/WBV2-P" + phase + "-000/manifest.json" + tick + " |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | " + tick + "docs/tasks/" + ids[1] + ".md" + tick + " |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | " + tick + ids[2] + tick + " |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | " + tick + "node tools/web/generate-wbv2-capability-continuation-slice.mjs --task " + ids[1] + " --write" + tick + " |");
|
|
fs.writeFileSync(abs("nextTask.md"), next);
|
|
console.log(`wbv2-capability-continuation-root-written task=${task} next=${ids[1]} batches=27 pending=6609 verification=DEFERRED`);
|