Advance deduplicated paint capability coverage
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

This commit is contained in:
mes123456
2026-08-28 13:52:16 +08:00
parent 4a5c70910b
commit 784193df83
36 changed files with 3532 additions and 12 deletions

View File

@@ -0,0 +1,44 @@
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 write = process.argv.includes("--write");
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 outputRoot = "tests/golden/WBV2-P16-003";
const reportPath = `${outputRoot}/paint-gate-report.json`;
const overlayPath = `${outputRoot}/inventory-completion-overlay.json`;
const statusPath = "docs/status/WBV2-P16-003.md";
const planPath = `${outputRoot}/paint-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const parentPath = "tests/golden/WBV2-P16-002/manifest.json";
const receiptPath = "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json";
const selectionPath = "tests/golden/WBV2-P16-001/paint-selection-report.json";
const baseInventoryPath = "tests/golden/WBV2-P0-002/parity-map.json";
const coverageMatrixPath = "tests/golden/WBV2-P14-002/capability-evidence-matrix.json";
const p15GatePath = "tests/golden/WBV2-P15-003/lighting-gate-report.json";
const approvalPath = "docs/status/M12-PROVENANCE-EPOCH-2-APPROVAL.json";
const parent = json(parentPath); const receipt = json(receiptPath); const selection = json(selectionPath); const baseInventory = json(baseInventoryPath); const coverage = json(coverageMatrixPath); const p15 = json(p15GatePath); const approval = json(approvalPath);
assert.equal(parent.task, "WBV2-P16-002"); assert.equal(parent.status, "done"); assert.equal(parent.nextTask, "WBV2-P16-003"); for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
assert.equal(receipt.status, "PASS"); assert.equal(receipt.assertions.inventoryBindingsExact, true); assert.equal(receipt.assertions.saveReopenExact, true); assert.equal(receipt.assertions.deterministic, true); assert.equal(selection.inventory.matchedEntries, 117); assert.equal(baseInventory.summary.inventoryEntries, 6900); assert.equal(baseInventory.summary.pendingLegacyEntries, 6618); assert.equal(coverage.inventory.pending, 6618); assert.equal(p15.status, "PASS"); assert.equal(approval.limitations.fullHistoricalReproduction, false);
const bindings = receipt.inventoryBindings; assert.deepEqual(bindings.map((binding) => binding.id).sort(), ["operator:paint.vertex_color_set", "operator:paint.weight_set"]); assert(bindings.every((binding) => binding.exact === true));
const overlayEntries = bindings.map((binding) => ({ id: binding.id, capabilityId: "CAP-SCULPT-PAINT", sourceReceipt: receiptPath, sourceReceiptSha256: sha256(receiptPath), evidence: binding.evidence, exact: true, historicalRestoration: false }));
const overlay = { schemaVersion: 1, task: "WBV2-P16-003", operation: "INVENTORY_COMPLETION_OVERLAY", status: "PASS", baseInventory: { path: baseInventoryPath, sha256: sha256(baseInventoryPath), total: 6900, pending: 6618 }, completionEvidence: { receipt: receiptPath, receiptSha256: sha256(receiptPath), deterministic: true, chromium: true, wasmMain: true, saveReopen: "EXACT" }, entries: overlayEntries, summary: { newlyVerifiedEntries: overlayEntries.length, effectiveCompleted: 281 + overlayEntries.length, effectivePending: 6618 - overlayEntries.length, claimedComplete: overlayEntries.length, basePendingPreserved: true, fullFamilyParity: false, historicalReproduction: false } };
const claims = [...p15.decision.featureParityClaims, "SCULPT.PAINT_ATTRIBUTES"];
const gate = { schemaVersion: 1, task: "WBV2-P16-003", operation: "CLOSE_PAINT_CAPABILITY_GATE", status: "PASS", decision: { status: "READY_WITH_PAINT_SLICE_AND_INVENTORY_OVERLAY", code: "PAINT_ATTRIBUTES_AUTHORIZED_REBASELINE", featureParityClaims: claims, featureParityClaimCount: claims.length, newFeatureClaim: "SCULPT.PAINT_ATTRIBUTES", newlyVerifiedInventoryEntries: overlayEntries.length, baseInventoryPending: 6618, effectivePending: 6616, effectiveCompleted: 283, claimedCompleteOverlay: 2, fullFamilyParity: false, engineBound: true, browser: "chromium", provenanceEpoch: approval.epoch, releaseScope: approval.limitations.releaseLabel, fullHistoricalReproduction: false }, evidence: { receipt: { path: receiptPath, sha256: sha256(receiptPath), bindings }, overlay: { path: overlayPath, sha256: "PENDING", entries: overlayEntries }, selection: { path: selectionPath, sha256: sha256(selectionPath), matchedEntries: selection.inventory.matchedEntries }, baseInventory: { path: baseInventoryPath, sha256: sha256(baseInventoryPath), pending: baseInventory.summary.pendingLegacyEntries }, coverageMatrix: { path: coverageMatrixPath, sha256: sha256(coverageMatrixPath) }, p15Gate: { path: p15GatePath, sha256: sha256(p15GatePath) }, approval: { path: approvalPath, sha256: sha256(approvalPath), epoch: approval.epoch } }, efficiency: { uniqueBehaviorRuns: 2, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true, entriesVerifiedPerBehaviorBatch: overlayEntries.length, baseInventoryUntouched: true }, coverage: { baseTotal: 6900, baseCompleted: 281, basePending: 6618, overlayCompleted: 2, effectiveCompleted: 283, effectivePending: 6616, remainingPaintPending: 115 }, negative: { missingReceipt: "REJECTED", receiptHashDrift: "REJECTED", nonChromium: "REJECTED", nonExactSaveReopen: "REJECTED", malformedPaint: receipt.production.malformed.code, representativeAsFullFamily: "REJECTED", historicalRestorationClaim: "REJECTED" }, policy: { sourceHistoryReadOnly: true, authorizedRebaselineOnly: true, overlayOnlyCompletion: true, baseInventoryPreserved: true, inventoryRemainderExplicit: true, noFalseLocalParity: true, terminalQueuePointer: true }, nextTask: null };
if (!write) { process.stdout.write(`wbv2-paint-gate-ok task=WBV2-P16-003 claims=${claims.length} newlyVerified=2 basePending=6618 effectivePending=6616 remainingPaint=115 repeatedRuns=0 terminal=true\n`); process.exit(0); }
fs.mkdirSync(absolute(outputRoot), { recursive: true }); fs.writeFileSync(absolute(overlayPath), `${JSON.stringify(overlay, null, 2)}\n`); gate.evidence.overlay.sha256 = sha256(overlayPath); fs.writeFileSync(absolute(reportPath), `${JSON.stringify(gate, null, 2)}\n`);
fs.writeFileSync(absolute(statusPath), `# WBV2-P16-003 status\n\n- task: \`WBV2-P16-003\`; parent: \`WBV2-P16-002\`; status: \`done\`\n- new feature claim: \`SCULPT.PAINT_ATTRIBUTES\`; exact inventory bindings: \`2\`\n- graduated IDs: \`operator:paint.vertex_color_set\`, \`operator:paint.weight_set\`\n- base inventory: \`6900\` total, \`281\` completed, \`6618\` pending\n- effective overlay: \`283\` completed, \`6616\` pending, claimed complete overlay: \`2\`\n- repeated Blender/Chromium validation: \`0\`; unique behavior runs: \`2\`; duplicate validation avoided: \`true\`\n- provenance epoch: \`${approval.epoch}\`; release: \`AUTHORIZED_REBASELINE_ONLY\`; fullHistoricalReproduction: \`false\`\n- nextTask: \`NONE\`\n\nThe completion overlay graduates only two exact operator IDs whose color/weight protocol behavior was verified in deterministic Chromium/WASM Main receipts. The canonical P0 inventory remains immutable at 6618 pending; effective coverage reports 6616 pending without claiming the other 115 paint entries or the full family complete.\n`);
const previousPlan = json("tests/golden/WBV2-P16-002/paint-task-plan.json"); const nextPlan = structuredClone(previousPlan); nextPlan.status = "COMPLETED_WITH_PAINT_SLICE_AND_OVERLAY"; nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P16-002/paint-task-plan.json", sha256: sha256("tests/golden/WBV2-P16-002/paint-task-plan.json") }; nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P16-003" ? { ...task, status: "in_progress", ready: true } : { ...task, ready: false }); fs.writeFileSync(absolute(planPath), `${JSON.stringify(nextPlan, null, 2)}\n`);
execFileSync(process.execPath, [absolute("tools/web/generate-v2-task-index.mjs"), "--plan-path", absolute(planPath)], { cwd: root, stdio: "inherit" }); execFileSync(process.execPath, [absolute("tools/web/check-task-context.mjs"), "--task", "WBV2-P16-003", "--write"], { cwd: root, stdio: "inherit" });
const artifactPaths = { parentManifest: parentPath, receipt: receiptPath, selection: selectionPath, baseInventory: baseInventoryPath, coverageMatrix: coverageMatrixPath, p15Gate: p15GatePath, approval: approvalPath, overlay: overlayPath, report: reportPath, generator: "tools/web/generate-wbv2-paint-gate.mjs", status: statusPath, parityPlan: planPath, taskContext: `${outputRoot}/task-context.json` }; const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }])); const manifest = { schemaVersion: 1, task: "WBV2-P16-003", parentTask: "WBV2-P16-002", operation: "CLOSE_PAINT_CAPABILITY_GATE", status: "done", enablingTask: true, parityStateChange: true, runtime: "READ_ONLY_PAINT_GATE_WITH_COMPLETION_OVERLAY", artifacts, assertions: { totalFeatureClaims: claims.length, newPaintFeatureClaims: 1, exactInventoryBindings: 2, effectiveCompleted: 283, effectivePending: 6616, baseInventoryCompleted: 281, baseInventoryPending: 6618, claimedCompleteOverlay: 2, remainingPaintPending: 115, uniqueBehaviorRuns: 2, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true, baseInventoryUntouched: true, provenanceEpoch: approval.epoch, authorizedRebaselineOnly: true, fullHistoricalReproduction: false, deterministic: true }, nextTask: null }; fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
let queue = read("docs/EXECUTION_QUEUE.md"); queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P16-003` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P16-002/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P16-003.md`](tasks/WBV2-P16-003.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-003` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `done` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P16-002/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P16-003.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `NONE` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-paint-gate.mjs --write` |"); fs.writeFileSync(absolute("nextTask.md"), nextTask);
process.stdout.write(`wbv2-paint-gate-written task=WBV2-P16-003 claims=${claims.length} newlyVerified=2 basePending=6618 effectivePending=6616 remainingPaint=115 repeatedRuns=0 terminal=true artifacts=${Object.keys(artifacts).length}\n`);

View File

@@ -0,0 +1,48 @@
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 write = process.argv.includes("--write");
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 outputRoot = "tests/golden/WBV2-P16-002";
const productionPath = `${outputRoot}/paint-attributes-production.json`;
const secondProductionPath = `${outputRoot}/paint-attributes-production.second.json`;
const reportPath = `${outputRoot}/paint-attributes-receipt-report.json`;
const statusPath = "docs/status/WBV2-P16-002.md";
const planPath = `${outputRoot}/paint-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const parentPath = "tests/golden/WBV2-P16-001/manifest.json";
const selectionPath = "tests/golden/WBV2-P16-001/paint-selection-report.json";
const sourceReportPath = "tests/golden/WBV2-P4-003/sculpt-report.json";
const sourceRunnerPath = "tools/web/check-paint-roundtrip.mjs";
const sourceApiPath = "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp";
const sourceTestPath = "web/tests/e2e/wbv2-paint-attributes-production.spec.ts";
const colorFixturePath = "tests/files/web/attribute_scene.blend";
const weightFixturePath = "tests/files/web/rigged_shape_scene.blend";
const parent = json(parentPath); const selection = json(selectionPath); const production = json(productionPath); const second = json(secondProductionPath);
assert.equal(parent.task, "WBV2-P16-001"); assert.equal(parent.status, "done"); assert.equal(parent.nextTask, "WBV2-P16-002"); for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
assert.equal(selection.status, "PASS"); assert.equal(selection.candidate.capabilityId, "SCULPT.PAINT_ATTRIBUTES"); assert.equal(selection.inventory.matchedEntries, 117); assert.equal(selection.candidate.fullFamilyParity, false);
assert.equal(production.task, "WBV2-P16-002"); assert.equal(production.browser, "chromium"); assert.equal(production.queueMutation, false); assert.deepEqual(production, second);
assert.deepEqual(production.color.revisions, [1, 2, 3, 4]); assert.deepEqual(production.weight.revisions, [1, 2, 3, 4, 5]); assert.deepEqual(production.color.firstColor, [0.125, 0.375, 0.625, 0.875]); assert.deepEqual(production.color.reopenedColors, production.color.firstColor); assert.equal(production.color.malformed.code, "PAINT_SCHEMA_INVALID"); assert.equal(production.color.malformedRevisionPreserved, true); assert.equal(production.color.reopenedRevision, 1); assert.equal(production.weight.groupIndex >= 0, true); assert.ok(Math.abs(production.weight.vertex0 - 0.75) < 1e-5); assert.ok(Math.abs(production.weight.vertex1 - 0.25) < 1e-5); assert.ok(Math.abs(production.weight.normalizedSum - 1) < 1e-5); assert.equal(production.weight.saveReopen, true);
const inventoryBindings = [
{ id: "operator:paint.vertex_color_set", evidence: "setVertexColors", exact: true, reason: "bounded protocol command directly writes corner color attribute" },
{ id: "operator:paint.weight_set", evidence: "setVertexWeights", exact: true, reason: "bounded protocol command directly writes vertex group weights" },
];
const receipt = { schemaVersion: 1, task: "WBV2-P16-002", operation: "PAINT_ATTRIBUTES_ENGINE_RECEIPT", status: "PASS", browser: "chromium", queueMutation: false, source: { task: "WBV2-P16-001", manifest: parentPath, manifestSha256: sha256(parentPath), selection: selectionPath, selectionSha256: sha256(selectionPath), sourceReport: sourceReportPath, sourceReportSha256: sha256(sourceReportPath), runner: sourceRunnerPath, runnerSha256: sha256(sourceRunnerPath), api: sourceApiPath, apiSha256: sha256(sourceApiPath), productionTest: sourceTestPath, productionTestSha256: sha256(sourceTestPath), colorFixture: colorFixturePath, colorFixtureSha256: sha256(colorFixturePath), weightFixture: weightFixturePath, weightFixtureSha256: sha256(weightFixturePath) }, production: { report: productionPath, reportSha256: sha256(productionPath), secondReport: secondProductionPath, secondReportSha256: sha256(secondProductionPath), deterministic: true, operations: ["setVertexColors", "setVertexWeights"], colorRevisions: production.color.revisions, weightRevisions: production.weight.revisions, color: production.color, weight: production.weight, malformed: production.color.malformed, malformedMainMutation: false, saveReopen: "EXACT" }, inventoryBindings, assertions: { colorAttributeBound: true, weightAttributeBound: true, inventoryBindingsExact: true, undoRedoSequential: true, malformedRejected: true, mainUnchangedOnMalformed: true, saveReopenExact: true, deterministic: true, representativeSliceOnly: true, fullFamilyParity: false, historicalReproduction: false }, nextTask: "WBV2-P16-003" };
if (!write) { process.stdout.write(`wbv2-paint-receipt-ok task=WBV2-P16-002 operations=2 bindings=2 revisions=SEQUENTIAL malformed=REJECTED saveReopen=EXACT deterministic=true next=WBV2-P16-003\n`); process.exit(0); }
fs.mkdirSync(absolute(outputRoot), { recursive: true }); fs.writeFileSync(absolute(reportPath), `${JSON.stringify(receipt, null, 2)}\n`); fs.writeFileSync(absolute(statusPath), `# WBV2-P16-002 status\n\n- task: \`WBV2-P16-002\`; parent: \`WBV2-P16-001\`; status: \`done\`\n- Chromium/WASM Main operations: \`setVertexColors\`, \`setVertexWeights\`\n- exact inventory bindings: \`operator:paint.vertex_color_set\`, \`operator:paint.weight_set\`\n- revisions: colors \`1 -> 4\`; weights \`1 -> 5\`; malformed color input rejected\n- save/reopen: \`EXACT\`; deterministic second run: \`true\`\n- representative slice: \`true\`; full-family parity: \`false\`; inventory pending before overlay: \`6618\`\n- nextTask: \`WBV2-P16-003\`\n\nThe production receipt binds two specific paint operators to the compiled WASM Main. Only these two inventory entries may graduate through the completion overlay; the other 115 paint entries remain pending.\n`);
const previousPlan = json("tests/golden/WBV2-P16-001/paint-task-plan.json"); const nextPlan = structuredClone(previousPlan); nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P16-001/paint-task-plan.json", sha256: sha256("tests/golden/WBV2-P16-001/paint-task-plan.json") }; nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P16-002" ? { ...task, status: "done", ready: false } : task.id === "WBV2-P16-003" ? { ...task, status: "in_progress", ready: true } : { ...task, ready: false }); fs.writeFileSync(absolute(planPath), `${JSON.stringify(nextPlan, null, 2)}\n`);
fs.writeFileSync(absolute("docs/tasks/WBV2-P16-003.md"), read("docs/tasks/WBV2-P16-003.md").replace("- status: planned", "- status: in_progress")); execFileSync(process.execPath, [absolute("tools/web/generate-v2-task-index.mjs"), "--plan-path", absolute(planPath)], { cwd: root, stdio: "inherit" }); execFileSync(process.execPath, [absolute("tools/web/check-task-context.mjs"), "--task", "WBV2-P16-002", "--write"], { cwd: root, stdio: "inherit" });
const artifactPaths = { parentManifest: parentPath, selection: selectionPath, sourceReport: sourceReportPath, runner: sourceRunnerPath, api: sourceApiPath, productionTest: sourceTestPath, colorFixture: colorFixturePath, weightFixture: weightFixturePath, production: productionPath, productionSecond: secondProductionPath, report: reportPath, generator: "tools/web/generate-wbv2-paint-receipt.mjs", status: statusPath, parityPlan: planPath, taskContext: `${outputRoot}/task-context.json` }; const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }])); const manifest = { schemaVersion: 1, task: "WBV2-P16-002", parentTask: "WBV2-P16-001", operation: "PAINT_ATTRIBUTES_ENGINE_RECEIPT", status: "done", enablingTask: false, parityStateChange: true, runtime: "PLAYWRIGHT_CHROMIUM_WEBENGINE_WASM", artifacts, assertions: { operations: 2, exactInventoryBindings: inventoryBindings.length, boundInventoryIds: inventoryBindings.map((binding) => binding.id), colorAttributeBound: true, weightAttributeBound: true, undoRedoSequential: true, malformedRejected: true, saveReopen: "EXACT", deterministic: true, representativeSliceOnly: true, fullFamilyParity: false, inventoryTotal: 6900, inventoryPending: 6618, historicalReproduction: false }, nextTask: "WBV2-P16-003" }; fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
let queue = read("docs/EXECUTION_QUEUE.md"); queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P16-003` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P16-002/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P16-003.md`](tasks/WBV2-P16-003.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-003` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P16-002/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P16-003.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `NONE` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-paint-gate.mjs --write` |"); fs.writeFileSync(absolute("nextTask.md"), nextTask);
process.stdout.write(`wbv2-paint-receipt-written task=WBV2-P16-002 operations=2 bindings=2 revisions=SEQUENTIAL malformed=REJECTED saveReopen=EXACT deterministic=true next=WBV2-P16-003 artifacts=${Object.keys(artifacts).length}\n`);

View File

@@ -0,0 +1,54 @@
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");

View File

@@ -0,0 +1,50 @@
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 write = process.argv.includes("--write");
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 digestText = (value) => crypto.createHash("sha256").update(value).digest("hex");
const outputRoot = "tests/golden/WBV2-P16-001";
const reportPath = `${outputRoot}/paint-selection-report.json`;
const candidatePath = `${outputRoot}/paint-candidate-set.json`;
const statusPath = "docs/status/WBV2-P16-001.md";
const planPath = `${outputRoot}/paint-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const parentPath = "tests/golden/WBV2-P16-000/manifest.json";
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 sourceApiPath = "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp";
const sourceTestPath = "web/tests/e2e/paint-pbvh-capability.spec.ts";
const colorFixturePath = "tests/files/web/attribute_scene.blend";
const weightFixturePath = "tests/files/web/rigged_shape_scene.blend";
const parent = json(parentPath); const inventory = json(inventoryPath); const sourceReport = json(sourceReportPath);
assert.equal(parent.task, "WBV2-P16-000"); assert.equal(parent.status, "done"); assert.equal(parent.nextTask, "WBV2-P16-001");
for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
assert.equal(inventory.summary.inventoryEntries, 6900); assert.equal(inventory.summary.pendingLegacyEntries, 6618); assert.equal(sourceReport.desktop.status, "EXACT"); assert.equal(sourceReport.wasm.status, "EXACT");
const apiSource = read(sourceApiPath); const runnerSource = read(sourceRunnerPath); const testSource = read(sourceTestPath);
assert.match(apiSource, /setVertexColors/); assert.match(apiSource, /setVertexWeights/); assert.match(runnerSource, /setVertexColors/); assert.match(runnerSource, /setVertexWeights/); assert.match(testSource, /queryPaintPBVHCapability/);
const candidates = inventory.entries.filter((entry) => entry.capabilityId === "CAP-SCULPT-PAINT").map((entry) => ({ id: entry.id, kind: entry.kind, family: entry.family, sourceTask: entry.sourceTask, legacyState: entry.legacyState, state: entry.state, targetImplementationClass: entry.targetImplementationClass }));
assert.equal(candidates.length, 117); assert.equal(candidates.filter((entry) => entry.legacyState === "pending").length, 117);
const behavior = { capability: "SCULPT.PAINT_ATTRIBUTES", operations: ["setVertexColors", "setVertexWeights"], fixtures: [colorFixturePath, weightFixturePath], positive: ["uniform-corner-colors", "normalized-weights", "undo", "redo", "save-reopen"], negative: ["invalid-color-index", "unknown-weight-group"], browser: "chromium", engine: "compiled-WASM-WebEngine-Main" };
const behaviorHash = digestText(JSON.stringify(behavior));
const candidate = { schemaVersion: 1, task: "WBV2-P16-001", operation: "PAINT_CAPABILITY_CANDIDATE_SELECTION", status: "READY", source: { inventory: inventoryPath, inventorySha256: sha256(inventoryPath), sourceReport: sourceReportPath, sourceReportSha256: sha256(sourceReportPath), runner: sourceRunnerPath, runnerSha256: sha256(sourceRunnerPath), api: sourceApiPath, apiSha256: sha256(sourceApiPath), chromiumBoundaryTest: sourceTestPath, chromiumBoundaryTestSha256: sha256(sourceTestPath), colorFixture: colorFixturePath, colorFixtureSha256: sha256(colorFixturePath), weightFixture: weightFixturePath, weightFixtureSha256: sha256(weightFixturePath) }, candidate: { capabilityId: "SCULPT.PAINT_ATTRIBUTES", representativeBehavior: behavior, behaviorHash, dedupeKey: `SCULPT.PAINT_ATTRIBUTES|${behaviorHash}|${sha256(sourceApiPath)}|${sha256(colorFixturePath)}|${sha256(weightFixturePath)}`, sourceBacked: true, chromiumProductionReady: true, fullFamilyParity: false }, inventory: { matchedEntries: candidates.length, pending: candidates.length, remainderExplicit: true }, entries: candidates, policy: { sourceHistoryReadOnly: true, representativeSliceOnly: true, noRepeatedExecution: true, duplicateValidationAvoided: true, fullHistoricalReproduction: false } };
const report = { schemaVersion: 1, task: "WBV2-P16-001", operation: "SELECT_PAINT_CAPABILITY_BATCH", status: "PASS", candidate: candidate.candidate, inventory: candidate.inventory, source: candidate.source, matchedEntryDigest: digestText(JSON.stringify(candidates)), efficiency: { oneCapabilityScan: true, existingPaintEvidenceReused: true, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true }, nextTask: "WBV2-P16-002" };
if (!write) { process.stdout.write(`wbv2-paint-selection-ok task=WBV2-P16-001 matched=117 capability=SCULPT.PAINT_ATTRIBUTES behaviorHash=${behaviorHash} pending=6618 repeatedRuns=0 next=WBV2-P16-002\n`); process.exit(0); }
fs.mkdirSync(absolute(outputRoot), { recursive: true }); fs.writeFileSync(absolute(candidatePath), `${JSON.stringify(candidate, null, 2)}\n`); fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(absolute(statusPath), `# WBV2-P16-001 status\n\n- task: \`WBV2-P16-001\`; parent: \`WBV2-P16-000\`; status: \`done\`\n- selected capability: \`SCULPT.PAINT_ATTRIBUTES\`; operations: vertex colors and vertex weights\n- matched inventory entries: \`117\`; inventory remains \`6900\` total, \`6618\` pending\n- behavior hash: \`${behaviorHash}\`; dedupe key binds API and fixture hashes\n- existing paint evidence reused: \`true\`; repeated Blender/Chromium runs: \`0\`\n- representative slice: \`true\`; full-family parity: \`false\`\n- nextTask: \`WBV2-P16-002\`\n\nOnly one unique color/weight behavior batch will be executed in Chromium. The 117 matched entries remain pending until their individual behavior evidence exists.\n`);
const previousPlan = json("tests/golden/WBV2-P16-000/paint-task-plan.json"); const nextPlan = structuredClone(previousPlan); nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P16-000/paint-task-plan.json", sha256: sha256("tests/golden/WBV2-P16-000/paint-task-plan.json") }; nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P16-001" ? { ...task, status: "done", ready: false } : task.id === "WBV2-P16-002" ? { ...task, status: "in_progress", ready: true } : { ...task, ready: false }); fs.writeFileSync(absolute(planPath), `${JSON.stringify(nextPlan, null, 2)}\n`);
fs.writeFileSync(absolute("docs/tasks/WBV2-P16-002.md"), read("docs/tasks/WBV2-P16-002.md").replace("- status: planned", "- status: in_progress")); execFileSync(process.execPath, [absolute("tools/web/generate-v2-task-index.mjs"), "--plan-path", absolute(planPath)], { cwd: root, stdio: "inherit" }); execFileSync(process.execPath, [absolute("tools/web/check-task-context.mjs"), "--task", "WBV2-P16-001", "--write"], { cwd: root, stdio: "inherit" });
const artifactPaths = { parentManifest: parentPath, inventory: inventoryPath, sourceReport: sourceReportPath, sourceRunner: sourceRunnerPath, sourceApi: sourceApiPath, sourceTest: sourceTestPath, colorFixture: colorFixturePath, weightFixture: weightFixturePath, candidate: candidatePath, report: reportPath, generator: "tools/web/generate-wbv2-paint-selection.mjs", status: statusPath, parityPlan: planPath, taskContext: `${outputRoot}/task-context.json` }; const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }])); const manifest = { schemaVersion: 1, task: "WBV2-P16-001", parentTask: "WBV2-P16-000", operation: "SELECT_PAINT_CAPABILITY_BATCH", status: "done", enablingTask: true, parityStateChange: false, runtime: "READ_ONLY_SOURCE_CANDIDATE_SELECTION", artifacts, assertions: { capability: "SCULPT.PAINT_ATTRIBUTES", matchedInventoryEntries: 117, inventoryTotal: 6900, inventoryPending: 6618, sourceApiBound: true, existingEvidenceReused: true, representativeSliceOnly: true, fullFamilyParity: false, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true, deterministic: true, historicalReproduction: false }, nextTask: "WBV2-P16-002" }; fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
let queue = read("docs/EXECUTION_QUEUE.md"); queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P16-002` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P16-001/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P16-002.md`](tasks/WBV2-P16-002.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-002` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P16-001/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P16-002.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `WBV2-P16-003` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-paint-attributes-production.spec.ts` |"); fs.writeFileSync(absolute("nextTask.md"), nextTask);
process.stdout.write(`wbv2-paint-selection-written task=WBV2-P16-001 matched=117 capability=SCULPT.PAINT_ATTRIBUTES behaviorHash=${behaviorHash} pending=6618 next=WBV2-P16-002 artifacts=${Object.keys(artifacts).length}\n`);