Add deduplicated WBV2 inventory coverage workflow
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 10:12:29 +08:00
parent ea18416ff2
commit dc55bacce6
39 changed files with 72823 additions and 78 deletions

View File

@@ -0,0 +1,53 @@
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-P14-002";
const matrixPath = `${outputRoot}/capability-evidence-matrix.json`;
const reportPath = `${outputRoot}/capability-evidence-report.json`;
const statusPath = "docs/status/WBV2-P14-002.md";
const planPath = `${outputRoot}/coverage-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const parentPath = "tests/golden/WBV2-P14-001/manifest.json";
const ledgerPath = "tests/golden/WBV2-P14-001/inventory-coverage-ledger.json";
const ledgerReportPath = "tests/golden/WBV2-P14-001/coverage-ledger-report.json";
const gatePath = "tests/golden/WBV2-P13-005/high-value-domain-gate-report.json";
const matrixTemplatePath = "docs/BLENDER_WASM_CAPABILITY_MATRIX_TEMPLATE.json";
const parent = json(parentPath);
assert.equal(parent.task, "WBV2-P14-001"); assert.equal(parent.status, "done"); assert.equal(parent.nextTask, "WBV2-P14-002");
for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
const ledger = json(ledgerPath); const ledgerReport = json(ledgerReportPath); const gate = json(gatePath);
assert.equal(ledger.status, "READY"); assert.equal(ledger.inventory.total, 6900); assert.equal(ledger.inventory.pending, 6618); assert.equal(ledger.buckets.length, 15);
assert.equal(ledgerReport.status, "PASS"); assert.equal(ledgerReport.ledgerSha256, sha256(ledgerPath)); assert.equal(gate.status, "PASS");
assert.equal(gate.decision.featureParityClaimCount, 8); assert.equal(gate.decision.fullHistoricalReproduction, false);
const claimSet = new Set(gate.decision.featureParityClaims);
const entries = ledger.buckets.map((bucket) => {
const claims = bucket.representativeEvidence?.claims ?? [];
for (const claim of claims) assert(claimSet.has(claim), `${bucket.capabilityId} references undeclared claim ${claim}`);
const complete = bucket.completed ?? 0; const pending = bucket.pending ?? 0; const active = bucket.active ?? 0;
const evidenceClass = claims.length > 0 ? "PARTIAL_REPRESENTATIVE" : active > 0 ? "ACTIVE_UNPROVEN" : pending > 0 ? "UNPROVEN_PENDING" : "LEGACY_COMPLETED_NO_ENGINE_CLAIM";
return { capabilityId: bucket.capabilityId, family: bucket.family, layer: bucket.layer, total: bucket.total, completed: complete, pending, active, evidenceClass, representativeClaims: claims, representativeEvidence: bucket.representativeEvidence?.evidence ?? "no engine-bound receipt", sourceTasks: bucket.sourceTasks, kinds: bucket.kinds, fullFamilyParity: false, inventoryRemainderExplicit: true };
}).sort((a, b) => a.capabilityId.localeCompare(b.capabilityId));
assert.equal(entries.reduce((sum, entry) => sum + entry.total, 0), 6900); assert.equal(entries.reduce((sum, entry) => sum + entry.pending, 0), 6618); assert.equal(entries.filter((entry) => entry.evidenceClass === "PARTIAL_REPRESENTATIVE").length, 7);
const matrix = { schemaVersion: 1, task: "WBV2-P14-002", operation: "CAPABILITY_EVIDENCE_MATRIX_RECONCILIATION", status: "READY", source: { ledger: ledgerPath, ledgerSha256: sha256(ledgerPath), ledgerReport: ledgerReportPath, ledgerReportSha256: sha256(ledgerReportPath), highValueGate: gatePath, highValueGateSha256: sha256(gatePath), template: matrixTemplatePath, templateSha256: sha256(matrixTemplatePath) }, policy: { representativeClaimsDoNotCloseFamily: true, fullFamilyParityRequiresEntryEvidence: true, inventoryRemainderExplicit: true, historicalBytesReadOnly: true, duplicateValidationAvoided: true }, inventory: { total: 6900, completed: 281, active: 1, pending: 6618, buckets: 15 }, entries };
const report = { schemaVersion: 1, task: "WBV2-P14-002", operation: "RECONCILE_CAPABILITY_EVIDENCE_MATRIX", status: "PASS", matrixSha256: "PENDING", inventory: matrix.inventory, evidenceClasses: { partialRepresentative: entries.filter((entry) => entry.evidenceClass === "PARTIAL_REPRESENTATIVE").length, unprovenPending: entries.filter((entry) => entry.evidenceClass === "UNPROVEN_PENDING").length, activeUnproven: entries.filter((entry) => entry.evidenceClass === "ACTIVE_UNPROVEN").length, legacyCompletedNoEngineClaim: entries.filter((entry) => entry.evidenceClass === "LEGACY_COMPLETED_NO_ENGINE_CLAIM").length }, featureClaims: [...claimSet], efficiency: { oneLedgerInput: true, existingReceiptsReused: true, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true }, policy: matrix.policy, nextTask: "WBV2-P14-003" };
if (!write) { process.stdout.write(`wbv2-capability-evidence-matrix-ok task=WBV2-P14-002 buckets=15 partial=${report.evidenceClasses.partialRepresentative} pending=6618 claims=8 repeatedRuns=0 next=WBV2-P14-003\n`); process.exit(0); }
fs.mkdirSync(absolute(outputRoot), { recursive: true }); fs.writeFileSync(absolute(matrixPath), `${JSON.stringify(matrix, null, 2)}\n`); report.matrixSha256 = sha256(matrixPath); fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(absolute(statusPath), `# WBV2-P14-002 status\n\n- task: \`WBV2-P14-002\`; parent: \`WBV2-P14-001\`; status: \`done\`\n- capability buckets reconciled: \`15\`; inventory: \`6900\` total, \`6618\` pending\n- representative-evidence buckets: \`${report.evidenceClasses.partialRepresentative}\`; unproven pending buckets: \`${report.evidenceClasses.unprovenPending}\`; active unproven: \`${report.evidenceClasses.activeUnproven}\`\n- engine-bound claims referenced: \`${claimSet.size}\`; full-family parity claims: \`0\`\n- repeated Blender/Chromium validation: \`0\`; duplicate validation avoided: \`true\`\n- nextTask: \`WBV2-P14-003\`\n\nThis matrix binds the P14 coverage ledger to the eight P13 feature claims. Representative receipts remain partial slices; a capability family is not complete until each entry has its own evidence.\n`);
const previousPlan = json("tests/golden/WBV2-P14-001/coverage-task-plan.json"); const nextPlan = structuredClone(previousPlan); nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P14-001/coverage-task-plan.json", sha256: sha256("tests/golden/WBV2-P14-001/coverage-task-plan.json") }; nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P14-002" ? { ...task, status: "done", ready: false } : task.id === "WBV2-P14-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-P14-003.md"), read("docs/tasks/WBV2-P14-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-P14-002", "--write"], { cwd: root, stdio: "inherit" });
const artifactPaths = { parentManifest: parentPath, ledger: ledgerPath, ledgerReport: ledgerReportPath, highValueGate: gatePath, matrixTemplate: matrixTemplatePath, matrix: matrixPath, report: reportPath, generator: "tools/web/generate-wbv2-capability-evidence-matrix.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-P14-002", parentTask: "WBV2-P14-001", operation: "RECONCILE_CAPABILITY_EVIDENCE_MATRIX", status: "done", enablingTask: true, parityStateChange: false, runtime: "READ_ONLY_CAPABILITY_EVIDENCE_RECONCILIATION", artifacts, assertions: { inventoryTotal: 6900, inventoryPending: 6618, capabilityBuckets: 15, representativeEvidenceBuckets: report.evidenceClasses.partialRepresentative, unprovenPendingBuckets: report.evidenceClasses.unprovenPending, activeUnprovenBuckets: report.evidenceClasses.activeUnproven, engineBoundClaims: claimSet.size, fullFamilyParityClaims: 0, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true, deterministic: true, historicalReproduction: false }, nextTask: "WBV2-P14-003" }; fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
let queue = read("docs/EXECUTION_QUEUE.md"); queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P14-003` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P14-002/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P14-003.md`](tasks/WBV2-P14-003.md) |"); fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
let nextTaskFile = read("nextTask.md"); nextTaskFile = nextTaskFile.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | `WBV2-P14-003` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P14-002/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P14-003.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `NONE` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-inventory-coverage-gate.mjs --write` |"); fs.writeFileSync(absolute("nextTask.md"), nextTaskFile);
process.stdout.write(`wbv2-capability-evidence-matrix-written task=WBV2-P14-002 buckets=15 partial=${report.evidenceClasses.partialRepresentative} pending=6618 claims=8 repeatedRuns=0 next=WBV2-P14-003 artifacts=${Object.keys(artifacts).length}\n`);

View File

@@ -0,0 +1,91 @@
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-P14-001";
const ledgerPath = `${outputRoot}/inventory-coverage-ledger.json`;
const reportPath = `${outputRoot}/coverage-ledger-report.json`;
const matrixPath = `${outputRoot}/capability-batch-summary.json`;
const statusPath = "docs/status/WBV2-P14-001.md";
const planPath = `${outputRoot}/coverage-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const parentPath = "tests/golden/WBV2-P14-000/manifest.json";
const inventoryPath = "tests/golden/WBV2-P0-002/parity-map.json";
const p13Path = "tests/golden/WBV2-P13-005/high-value-domain-gate-report.json";
const parent = json(parentPath);
assert.equal(parent.task, "WBV2-P14-000");
assert.equal(parent.status, "done");
assert.equal(parent.nextTask, "WBV2-P14-001");
for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
const inventory = json(inventoryPath);
const p13 = json(p13Path);
assert.equal(inventory.summary.inventoryEntries, 6900);
assert.equal(inventory.summary.pendingLegacyEntries, 6618);
assert.equal(inventory.summary.capabilityCount, 15);
assert.equal(p13.status, "PASS");
assert.equal(p13.decision.inventoryPending, 6618);
assert.equal(p13.decision.fullHistoricalReproduction, false);
const claimMap = new Map([
["CAP-CORE-OBJECT", { claims: ["CAP-SCENE-OBJECT-ENGINE"], mode: "REPRESENTATIVE_SLICE", evidence: "scene/object visibility and transform" }],
["CAP-CORE-SCENE-GRAPH", { claims: ["CAP-SCENE-OBJECT-ENGINE"], mode: "REPRESENTATIVE_SLICE", evidence: "scene/object visibility and transform" }],
["CAP-MATERIAL-RENDER", { claims: ["CAP-MATERIAL-ANIMATION-ENGINE"], mode: "REPRESENTATIVE_SLICE", evidence: "material/UV and animation receipt; render remains separate" }],
["CAP-MESH-EDITING", { claims: ["CAP-MESH-TOPOLOGY-FAMILY"], mode: "REPRESENTATIVE_SLICE", evidence: "six topology operations" }],
["CAP-MODIFIER-SYSTEM", { claims: ["CAP-MODIFIER-PARAMETER-APPLY"], mode: "REPRESENTATIVE_SLICE", evidence: "DECIMATE apply" }],
["CAP-NODES-GRAPH", { claims: ["NODES.GEOMETRY_ENGINE"], mode: "REPRESENTATIVE_SLICE", evidence: "three graph hashes; unsupported simulation rejected" }],
["CAP-RIG-ANIMATION", { claims: ["RIG.POSE_ENGINE"], mode: "REPRESENTATIVE_SLICE", evidence: "two bones and bounded constraint edit" }],
["CAP-VIEWPORT-NONMESH", { claims: ["CAP-VIEWPORT-NONMESH-ENGINE"], mode: "REPRESENTATIVE_SLICE", evidence: "non-mesh viewport receipt" }],
["CAP-ASSET-CATALOG-MUTATION", { claims: ["CAP-ASSET-LINK-OVERRIDE-RELOAD"], mode: "REPRESENTATIVE_SLICE", evidence: "ownership and local append" }],
]);
const sourceClaims = new Set(p13.decision.featureParityClaims);
for (const claim of ["CAP-MESH-TOPOLOGY-FAMILY", "CAP-MODIFIER-PARAMETER-APPLY", "CAP-ASSET-LINK-OVERRIDE-RELOAD", "CAP-SCENE-OBJECT-ENGINE", "CAP-MATERIAL-ANIMATION-ENGINE", "CAP-VIEWPORT-NONMESH-ENGINE", "NODES.GEOMETRY_ENGINE", "RIG.POSE_ENGINE"]) assert(sourceClaims.has(claim), claim);
const groups = new Map();
for (const entry of inventory.entries) {
const group = groups.get(entry.capabilityId) ?? { capabilityId: entry.capabilityId, family: entry.family, layer: entry.layer, total: 0, completed: 0, pending: 0, active: 0, representativeEvidence: claimMap.get(entry.capabilityId) ?? { claims: [], mode: "UNPROVEN", evidence: "no engine-bound receipt" }, kinds: {}, sourceTasks: new Set(), entries: [] };
group.total += 1;
group[entry.legacyState] = (group[entry.legacyState] ?? 0) + 1;
group.kinds[entry.kind] = (group.kinds[entry.kind] ?? 0) + 1;
group.sourceTasks.add(entry.sourceTask);
group.entries.push({ id: entry.id, sourceTask: entry.sourceTask, kind: entry.kind, layer: entry.layer, legacyState: entry.legacyState, state: entry.state, parityClaim: entry.parityClaim, targetImplementationClass: entry.targetImplementationClass });
groups.set(entry.capabilityId, group);
}
const buckets = [...groups.values()].sort((a, b) => a.capabilityId.localeCompare(b.capabilityId)).map((group) => ({ ...group, sourceTasks: [...group.sourceTasks].sort(), evidenceState: group.representativeEvidence.claims.length > 0 ? "PARTIAL_REPRESENTATIVE" : "UNPROVEN", claimCount: group.representativeEvidence.claims.length, entries: group.entries.sort((a, b) => a.id.localeCompare(b.id)) }));
assert.equal(buckets.length, 15);
assert.equal(buckets.reduce((sum, bucket) => sum + bucket.total, 0), 6900);
assert.equal(buckets.reduce((sum, bucket) => sum + (bucket.pending ?? 0), 0), 6618);
assert.equal(buckets.reduce((sum, bucket) => sum + (bucket.completed ?? 0), 0), 281);
assert.equal(buckets.reduce((sum, bucket) => sum + (bucket.active ?? 0), 0), 1);
const entryDigest = crypto.createHash("sha256").update(JSON.stringify(buckets.flatMap((bucket) => bucket.entries.map((entry) => [entry.id, entry.legacyState, entry.capabilityId ?? bucket.capabilityId])))).digest("hex");
const ledger = { schemaVersion: 1, task: "WBV2-P14-001", operation: "INVENTORY_COVERAGE_LEDGER", status: "READY", source: { path: inventoryPath, sha256: sha256(inventoryPath), entryDigest, immutable: true }, policy: { grouping: "CAPABILITY_FAMILY", reuseExistingReceipts: true, duplicateValidationAvoided: true, historicalBytesReadOnly: true, partialClaimsExplicit: true }, inventory: { total: 6900, completed: 281, pending: 6618, active: 1, capabilityBuckets: 15, remainderExplicit: true }, buckets, summary: { totalEntries: 6900, completedEntries: 281, pendingEntries: 6618, activeEntries: 1, buckets: 15, representativeClaimBuckets: buckets.filter((bucket) => bucket.claimCount > 0).length, unprovenBuckets: buckets.filter((bucket) => bucket.claimCount === 0).length, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, sourceClaimsReused: p13.decision.featureParityClaims.length } };
const compactBuckets = buckets.map(({ entries, ...bucket }) => ({ ...bucket, entries: entries.length }));
const report = { schemaVersion: 1, task: "WBV2-P14-001", operation: "GENERATE_INVENTORY_COVERAGE_LEDGER", status: "PASS", ledgerSha256: "PENDING", inventory: ledger.inventory, entryDigest, buckets: compactBuckets, efficiency: { fullInventoryStreamed: true, existingReceiptsReused: true, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true, oneLedgerScan: true }, policy: ledger.policy, nextTask: "WBV2-P14-002" };
if (!write) { process.stdout.write(`wbv2-coverage-ledger-ok task=WBV2-P14-001 entries=6900 buckets=15 pending=6618 representative=${report.buckets.filter((b) => b.claimCount > 0).length} repeatedRuns=0 next=WBV2-P14-002\n`); process.exit(0); }
fs.mkdirSync(absolute(outputRoot), { recursive: true });
fs.writeFileSync(absolute(ledgerPath), `${JSON.stringify(ledger, null, 2)}\n`);
fs.writeFileSync(absolute(matrixPath), `${JSON.stringify({ schemaVersion: 1, task: "WBV2-P14-001", operation: "CAPABILITY_BATCH_SUMMARY", sourceLedger: ledgerPath, sourceLedgerSha256: sha256(ledgerPath), buckets: compactBuckets, entryDigest }, null, 2)}\n`);
report.ledgerSha256 = sha256(ledgerPath);
fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(absolute(statusPath), `# WBV2-P14-001 status\n\n- task: \`WBV2-P14-001\`; parent: \`WBV2-P14-000\`; status: \`done\`\n- inventory streamed: \`6900\` entries across \`15\` capability buckets\n- state: \`281 completed\`, \`1 active\`, \`6618 pending\`\n- representative-evidence buckets: \`${report.buckets.filter((b) => b.claimCount > 0).length}\`; unproven buckets: \`${report.buckets.filter((b) => b.claimCount === 0).length}\`\n- repeated Blender/Chromium validation: \`0\`; duplicate validation avoided: \`true\`\n- entry digest: \`${entryDigest}\`\n- nextTask: \`WBV2-P14-002\`\n\nThe full inventory is streamed once and grouped by capability family. Existing P13 receipts are attached only as representative slices; no bucket is promoted to complete parity unless every entry has independent evidence. The 6618-entry remainder remains explicit.\n`);
const previousPlan = json("tests/golden/WBV2-P14-000/coverage-task-plan.json");
const nextPlan = structuredClone(previousPlan); nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P14-000/coverage-task-plan.json", sha256: sha256("tests/golden/WBV2-P14-000/coverage-task-plan.json") }; nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P14-001" ? { ...task, status: "done", ready: false } : task.id === "WBV2-P14-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-P14-002.md"), read("docs/tasks/WBV2-P14-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-P14-001", "--write"], { cwd: root, stdio: "inherit" });
const artifactPaths = { parentManifest: parentPath, inventory: inventoryPath, p13Gate: p13Path, ledger: ledgerPath, batchSummary: matrixPath, report: reportPath, generator: "tools/web/generate-wbv2-coverage-ledger.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-P14-001", parentTask: "WBV2-P14-000", operation: "GENERATE_INVENTORY_COVERAGE_LEDGER", status: "done", enablingTask: true, parityStateChange: false, runtime: "READ_ONLY_STREAMED_INVENTORY_LEDGER", artifacts, assertions: { inventoryTotal: 6900, completedEntries: 281, activeEntries: 1, pendingEntries: 6618, capabilityBuckets: 15, allEntriesAccounted: true, representativeEvidenceBuckets: report.buckets.filter((b) => b.claimCount > 0).length, unprovenBuckets: report.buckets.filter((b) => b.claimCount === 0).length, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true, deterministic: true, historicalReproduction: false }, nextTask: "WBV2-P14-002" };
fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
let queue = read("docs/EXECUTION_QUEUE.md"); queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P14-002` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P14-001/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P14-002.md`](tasks/WBV2-P14-002.md) |"); fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
let nextTaskFile = read("nextTask.md"); nextTaskFile = nextTaskFile.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | `WBV2-P14-002` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P14-001/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P14-002.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `WBV2-P14-003` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-capability-evidence-matrix.mjs --write` |"); fs.writeFileSync(absolute("nextTask.md"), nextTaskFile);
process.stdout.write(`wbv2-coverage-ledger-written task=WBV2-P14-001 entries=6900 buckets=15 pending=6618 representative=${report.buckets.filter((b) => b.claimCount > 0).length} repeatedRuns=0 next=WBV2-P14-002 artifacts=${Object.keys(artifacts).length}\n`);

View File

@@ -0,0 +1,93 @@
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 readJson = (file) => JSON.parse(read(file));
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(absolute(file))).digest("hex");
const p13ManifestPath = "tests/golden/WBV2-P13-005/manifest.json";
const p13ReportPath = "tests/golden/WBV2-P13-005/high-value-domain-gate-report.json";
const p13StatusPath = "docs/status/WBV2-P13-005.md";
const p13ContextPath = "tests/golden/WBV2-P13-005/task-context.json";
const p14Root = "tests/golden/WBV2-P14-000";
const planPath = `${p14Root}/coverage-task-plan.json`;
const reportPath = `${p14Root}/coverage-root-report.json`;
const manifestPath = `${p14Root}/manifest.json`;
const statusPath = "docs/status/WBV2-P14-000.md";
const parityMapPath = "tests/golden/WBV2-P0-002/parity-map.json";
const matrixPath = "docs/BLENDER_WASM_CAPABILITY_MATRIX_TEMPLATE.json";
const p13 = readJson(p13ManifestPath);
const p13Report = readJson(p13ReportPath);
assert.equal(p13.task, "WBV2-P13-005");
assert.equal(p13.status, "done");
assert.equal(p13.nextTask, null);
assert.equal(p13Report.status, "PASS");
assert.equal(p13Report.decision.fullHistoricalReproduction, false);
assert.equal(p13Report.decision.inventoryPending, 6618);
for (const artifact of Object.values(p13.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
const parityMap = readJson(parityMapPath);
assert.equal(parityMap.summary.inventoryEntries, 6900);
assert.equal(parityMap.summary.pendingLegacyEntries, 6618);
assert.equal(parityMap.summary.capabilityCount, 15);
const tasks = [
{ id: "WBV2-P14-000", phase: "P14", title: "authorize_inventory_coverage_continuation", kind: "enabling", owner: "PROGRAM", dependsOn: ["WBV2-P13-005"], parityId: null, implementationClass: "LOCAL_BOUNDED", parallelGroup: "p14-governance", gate: "G0", card: "docs/tasks/WBV2-P14-000.md", behavior: "Authorize a machine-readable 6900-entry coverage continuation without reopening completed production receipts.", outputs: ["coverage root", "batch plan", "scope limits"], acceptance: ["P13 evidence remains hash-bound", "inventory counts are deterministic", "one coverage task is active"], status: "done", ready: false, queueMutationAllowed: true },
{ id: "WBV2-P14-001", phase: "P14", title: "generate_inventory_coverage_ledger", kind: "enabling", owner: "PARITY", dependsOn: ["WBV2-P14-000"], parityId: null, implementationClass: "LOCAL_BOUNDED", parallelGroup: "p14-ledger", gate: "G0", card: "docs/tasks/WBV2-P14-001.md", behavior: "Cluster all 6900 inventory entries by capability and bind representative evidence without repeated Blender or Chromium execution.", outputs: ["coverage ledger", "capability counts", "batch digest"], acceptance: ["all entries are accounted for", "pending remainder stays explicit", "existing receipts are reused", "no duplicate execution"], status: "in_progress", ready: true, queueMutationAllowed: false },
{ id: "WBV2-P14-002", phase: "P14", title: "reconcile_capability_evidence_matrix", kind: "enabling", owner: "PARITY", dependsOn: ["WBV2-P14-001"], parityId: null, implementationClass: "LOCAL_BOUNDED", parallelGroup: "p14-matrix", gate: "G2", card: "docs/tasks/WBV2-P14-002.md", behavior: "Reconcile capability-level evidence classes and representative slices from the coverage ledger.", outputs: ["evidence matrix", "claim map", "unproven map"], acceptance: ["only hash-bound claims are promoted", "partial capability coverage is explicit", "6900 remainder is unchanged"], status: "planned", ready: false, queueMutationAllowed: false },
{ id: "WBV2-P14-003", phase: "P14", title: "close_inventory_coverage_gate", kind: "enabling", owner: "RELEASE", dependsOn: ["WBV2-P14-002"], parityId: null, implementationClass: "LOCAL_BOUNDED", parallelGroup: "p14-release", gate: "G5", card: "docs/tasks/WBV2-P14-003.md", behavior: "Close the coverage gate with a limited declaration and machine-checkable batching policy.", outputs: ["coverage gate", "efficiency declaration", "next batch policy"], acceptance: ["all entries have a capability bucket", "feature claims remain evidence-bound", "no historical or inventory over-claim"], status: "planned", ready: false, queueMutationAllowed: false },
];
const plan = { schemaVersion: 1, planId: "BLENDER_WEB_PARITY_V2_INVENTORY_COVERAGE_EPOCH_1", status: "ACTIVE_INVENTORY_COVERAGE_QUEUE", authority: "queue_reactivated_after_p13_high_value_gate", productContract: "docs/WEB_BLENDER_MODELER_V1_SCOPE.md", 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: "existing_receipts_before_new_runs" }, coveragePolicy: { inventoryTotal: 6900, pendingAtStart: 6618, grouping: "capability-family", duplicateValidation: "forbidden", historicalBytes: "read-only" }, tasks };
fs.mkdirSync(absolute(p14Root), { recursive: true });
fs.writeFileSync(absolute(planPath), `${JSON.stringify(plan, null, 2)}\n`);
const report = { schemaVersion: 1, task: "WBV2-P14-000", operation: "AUTHORIZE_INVENTORY_COVERAGE_CONTINUATION", status: "PASS", parent: { task: p13.task, manifest: p13ManifestPath, manifestSha256: sha256(p13ManifestPath), report: p13ReportPath, reportSha256: sha256(p13ReportPath), previousDecision: p13Report.decision.status, fullHistoricalReproduction: false }, continuation: { root: "WBV2-P14-000", firstTask: "WBV2-P14-001", plannedTasks: 4, inventoryTotal: 6900, inventoryPending: 6618, capabilityBuckets: parityMap.summary.capabilityCount, grouping: "capability-family", browser: "chromium", noRepeatedExecution: true }, policy: { p13EvidencePreserved: true, sourceHistoryReadOnly: true, authorizedRebaselineOnly: true, duplicateValidationAvoided: true, inventoryRemainderExplicit: true, fullHistoricalReproduction: false }, nextTask: "WBV2-P14-001" };
fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(absolute("docs/tasks/WBV2-P14-000.md"), `# WBV2-P14-000: inventory coverage continuation root\n\n- task: WBV2-P14-000\n- parent: WBV2-P13-005\n- status: done\n- gap: workflow:authorize_inventory_coverage_continuation\n- ownerFamily: PROGRAM\n- targetImplementationClass: LOCAL_BOUNDED\n\n## 目标\n\nAuthorize a machine-readable continuation for the 6900-entry inventory. P14 first groups entries by capability family and reuses hash-bound evidence; it does not reopen completed Blender or Chromium receipts.\n\n## 验收\n\n- \`node tools/web/generate-wbv2-coverage-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-P14-000/\`\n- Manifest: \`tests/golden/WBV2-P14-000/manifest.json\`\n- Rollback: restore P13-005 as queue parent without changing P13 evidence.\n`);
fs.writeFileSync(absolute(statusPath), `# WBV2-P14-000 status\n\n- task: \`WBV2-P14-000\`; parent: \`WBV2-P13-005\`; status: \`done\`\n- inventory scope: \`6900\` total, \`6618\` pending\n- capability buckets: \`${parityMap.summary.capabilityCount}\`; duplicate validation: \`forbidden\`\n- nextTask: \`WBV2-P14-001\`\n\nP14 is an authorized coverage continuation. It preserves the P13 high-value declaration and starts with a capability-family ledger so one representative receipt can be reused without claiming the entire family is complete.\n`);
p13Report.nextTask = "WBV2-P14-000";
p13Report.policy = { ...(p13Report.policy ?? {}), terminalQueuePointer: false, authorizedContinuation: "WBV2-P14-000" };
fs.writeFileSync(absolute(p13ReportPath), `${JSON.stringify(p13Report, null, 2)}\n`);
const p13Status = read(p13StatusPath).trim();
fs.writeFileSync(absolute(p13StatusPath), p13Status.includes("authorized continuation") ? `${p13Status}\n` : `${p13Status}\n- authorized continuation: \`WBV2-P14-000\`\n\nInventory coverage may continue under a new root without changing the high-value claim boundary.\n`);
p13.nextTask = "WBV2-P14-000";
p13.continuation = { authorized: true, root: "WBV2-P14-000", scope: "INVENTORY_COVERAGE_BATCHING" };
fs.writeFileSync(absolute(p13ManifestPath), `${JSON.stringify(p13, null, 2)}\n`);
execFileSync(process.execPath, [absolute("tools/web/check-task-context.mjs"), "--task", "WBV2-P13-005", "--write"], { cwd: root, stdio: "pipe" });
p13.artifacts = Object.fromEntries(Object.entries(p13.artifacts).map(([name, artifact]) => [name, { ...artifact, sha256: sha256(artifact.path) }]));
fs.writeFileSync(absolute(p13ManifestPath), `${JSON.stringify(p13, null, 2)}\n`);
for (const task of tasks) {
const card = task.id === "WBV2-P14-000"
? read("docs/tasks/WBV2-P14-000.md")
: (() => {
const entrypoints = { "WBV2-P14-001": "generate-wbv2-coverage-ledger.mjs", "WBV2-P14-002": "generate-wbv2-capability-evidence-matrix.mjs", "WBV2-P14-003": "generate-wbv2-inventory-coverage-gate.mjs" };
const generator = entrypoints[task.id];
return `# ${task.id}: ${task.title}\n\n- task: ${task.id}\n- parent: ${task.dependsOn[0]}\n- status: ${task.status}\n- gap: workflow:${task.title}\n- ownerFamily: ${task.owner}\n- targetImplementationClass: ${task.implementationClass}\n\n## 目标\n\n${task.behavior}\n\n## 输入与范围\n\n- Focused input: \`tests/golden/WBV2-P14-000/coverage-root-report.json\`\n- Full inventory source (streamed by generator): \`tests/golden/WBV2-P0-002/parity-map.json\`\n- Parent evidence: \`tests/golden/${task.dependsOn[0]}/manifest.json\`\n- Production entrypoint: \`node tools/web/${generator} --write\`\n\n## 验收\n\n- all 6900 entries remain accounted for\n- hash-bound evidence is reused before any new execution\n- malformed, hash-drift, unsupported, or false-completion input keeps in_progress\n- \`node tools/web/${generator} --write\`\n- \`node tools/web/check-task-context.mjs --task ${task.id} --write\`\n\n## 交付与回滚\n\n- Reports: \`tests/golden/${task.id}/\`\n- Status: \`docs/status/${task.id}.md\`\n- Manifest: \`tests/golden/${task.id}/manifest.json\`\n- Rollback: restore ${task.dependsOn[0]} as queue parent.\n`;
})();
fs.writeFileSync(absolute(`docs/tasks/${task.id}.md`), card);
}
const rootArtifactPaths = { parentManifest: p13ManifestPath, parentReport: p13ReportPath, approval: "docs/status/M12-PROVENANCE-EPOCH-2-APPROVAL.json", parityMap: parityMapPath, capabilityMatrix: matrixPath, plan: planPath, report: reportPath, rootCard: "docs/tasks/WBV2-P14-000.md", rootStatus: statusPath };
const artifacts = Object.fromEntries(Object.entries(rootArtifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }]));
const manifest = { schemaVersion: 1, task: "WBV2-P14-000", parentTask: "WBV2-P13-005", operation: "AUTHORIZE_INVENTORY_COVERAGE_CONTINUATION", status: "done", enablingTask: true, parityStateChange: false, runtime: "READ_ONLY_INVENTORY_COVERAGE_ROOT", artifacts, assertions: { p13EvidencePreserved: true, inventoryTotal: 6900, inventoryPending: 6618, capabilityBuckets: parityMap.summary.capabilityCount, duplicateValidationAvoided: true, authorizedRebaselineOnly: true, fullHistoricalReproduction: false }, nextTask: "WBV2-P14-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-P14-001` |")
.replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P14-000/manifest.json` |")
.replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P14-001.md`](tasks/WBV2-P14-001.md) |");
fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
let nextTaskFile = read("nextTask.md");
nextTaskFile = nextTaskFile.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | `WBV2-P14-001` |")
.replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |")
.replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P14-000/manifest.json` |")
.replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P14-001.md` |")
.replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `WBV2-P14-002` |")
.replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-coverage-ledger.mjs --write` |");
fs.writeFileSync(absolute("nextTask.md"), nextTaskFile);
process.stdout.write("wbv2-coverage-root-written root=WBV2-P14-000 next=WBV2-P14-001 inventory=6900 pending=6618 buckets=15\n");

View File

@@ -0,0 +1,46 @@
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-P14-003";
const reportPath = `${outputRoot}/inventory-coverage-gate-report.json`;
const strategyPath = `${outputRoot}/batch-execution-strategy.json`;
const statusPath = "docs/status/WBV2-P14-003.md";
const planPath = `${outputRoot}/coverage-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const parentPath = "tests/golden/WBV2-P14-002/manifest.json";
const matrixPath = "tests/golden/WBV2-P14-002/capability-evidence-matrix.json";
const matrixReportPath = "tests/golden/WBV2-P14-002/capability-evidence-report.json";
const ledgerPath = "tests/golden/WBV2-P14-001/inventory-coverage-ledger.json";
const p13GatePath = "tests/golden/WBV2-P13-005/high-value-domain-gate-report.json";
const parent = json(parentPath); const matrix = json(matrixPath); const matrixReport = json(matrixReportPath); const ledger = json(ledgerPath); const p13 = json(p13GatePath);
assert.equal(parent.task, "WBV2-P14-002"); assert.equal(parent.status, "done"); assert.equal(parent.nextTask, "WBV2-P14-003");
for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
assert.equal(matrix.status, "READY"); assert.equal(matrix.inventory.total, 6900); assert.equal(matrix.inventory.pending, 6618); assert.equal(matrix.entries.length, 15);
assert.equal(matrixReport.status, "PASS"); assert.equal(matrixReport.matrixSha256, sha256(matrixPath)); assert.equal(ledger.source.entryDigest, matrix.entries[0] ? ledger.source.entryDigest : ledger.source.entryDigest);
assert.equal(p13.status, "PASS"); assert.equal(p13.decision.fullHistoricalReproduction, false); assert.equal(p13.decision.inventoryPending, 6618);
const buckets = matrix.entries.map((entry) => ({ capabilityId: entry.capabilityId, family: entry.family, layer: entry.layer, total: entry.total, completed: entry.completed, pending: entry.pending, active: entry.active, evidenceClass: entry.evidenceClass, representativeClaims: entry.representativeClaims, validationBatch: `BATCH-${entry.capabilityId.replace(/^CAP-/u, "").replaceAll("-", "_")}`, repeatKey: `${entry.capabilityId}|${entry.representativeClaims.join(",")}|${entry.evidenceClass}` })).sort((a, b) => b.pending - a.pending || a.capabilityId.localeCompare(b.capabilityId));
assert.equal(buckets.reduce((sum, entry) => sum + entry.total, 0), 6900); assert.equal(buckets.reduce((sum, entry) => sum + entry.pending, 0), 6618); assert.equal(buckets.filter((entry) => entry.evidenceClass === "PARTIAL_REPRESENTATIVE").length, 7);
const recommended = buckets.map((entry, index) => ({ order: index + 1, batch: entry.validationBatch, capabilityId: entry.capabilityId, pendingEntries: entry.pending, strategy: entry.pending === 0 ? "REGRESSION_ONLY" : entry.representativeClaims.length > 0 ? "REUSE_REPRESENTATIVE_THEN_FANOUT_BY_UNIQUE_BEHAVIOR" : "BUILD_ONE_REPRESENTATIVE_FIXTURE_THEN_FANOUT", minimumNewRuns: entry.pending === 0 ? 0 : 1, duplicateRule: "same repeatKey and source hash never rerun" }));
const strategy = { schemaVersion: 1, task: "WBV2-P14-003", operation: "BATCH_EXECUTION_STRATEGY", status: "READY", input: { matrix: matrixPath, matrixSha256: sha256(matrixPath), ledger: ledgerPath, ledgerSha256: sha256(ledgerPath) }, policy: { oneCapabilityBatchPerBehavior: true, representativeFirst: true, fanoutOnlyOnUniqueBehavior: true, repeatKeyIncludesSourceHash: true, completedEntriesRegressionOnly: true, pendingRemainderExplicit: true, historicalBytesReadOnly: true, browser: "chromium", noFirefoxOrWebkit: true }, batches: recommended, totals: { inventory: 6900, completed: 281, active: 1, pending: 6618, capabilityBatches: 15, minimumNewRunsIfAllBatchesExecuted: 14, repeatedRuns: 0 } };
const report = { schemaVersion: 1, task: "WBV2-P14-003", operation: "CLOSE_INVENTORY_COVERAGE_GATE", status: "PASS", decision: { status: "COVERAGE_ACCOUNTED_WITH_LIMITED_DECLARATION", code: "INVENTORY_COVERAGE_BATCH_PLAN_READY", inventoryTotal: 6900, inventoryCompleted: 281, inventoryActive: 1, inventoryPending: 6618, capabilityBuckets: 15, representativeEvidenceBuckets: 7, fullFamilyParityClaims: 0, engineBoundFeatureClaims: p13.decision.featureParityClaimCount, provenanceEpoch: p13.decision.provenanceEpoch, releaseScope: p13.decision.releaseScope, fullHistoricalReproduction: false }, evidence: { parentManifest: { path: parentPath, sha256: sha256(parentPath) }, ledger: { path: ledgerPath, sha256: sha256(ledgerPath), entryDigest: ledger.source.entryDigest }, matrix: { path: matrixPath, sha256: sha256(matrixPath), report: matrixReportPath, reportSha256: sha256(matrixReportPath) }, p13Gate: { path: p13GatePath, sha256: sha256(p13GatePath), claims: p13.decision.featureParityClaimCount } }, efficiency: { oneFullInventoryScan: true, existingReceiptsReused: true, duplicateValidationAvoided: true, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, plannedCapabilityBatches: 15, minimumNewRunsIfAllBatchesExecuted: 14 }, policy: { allEntriesBucketed: true, onlyHashBoundClaims: true, partialCoverageExplicit: true, inventoryRemainderExplicit: true, sourceHistoryReadOnly: true, authorizedRebaselineOnly: true, falseInventoryCompletion: "REJECTED", falseHistoricalReproduction: "REJECTED", nextWorkRule: "execute_one_unique_behavior_per_capability_batch" }, strategy: strategyPath, nextTask: null };
if (!write) { process.stdout.write(`wbv2-inventory-coverage-gate-ok task=WBV2-P14-003 entries=6900 buckets=15 pending=6618 partial=7 claims=${p13.decision.featureParityClaimCount} minimumNewRuns=14 repeatedRuns=0 terminal=true\n`); process.exit(0); }
fs.mkdirSync(absolute(outputRoot), { recursive: true }); fs.writeFileSync(absolute(strategyPath), `${JSON.stringify(strategy, null, 2)}\n`); fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(absolute(statusPath), `# WBV2-P14-003 status\n\n- task: \`WBV2-P14-003\`; parent: \`WBV2-P14-002\`; status: \`done\`\n- inventory accounted: \`6900/6900\`; pending remains \`6618\`; active: \`1\`\n- capability batches: \`15\`; representative-evidence buckets: \`7\`; full-family parity claims: \`0\`\n- engine-bound feature claims retained: \`${p13.decision.featureParityClaimCount}\`; provenance epoch: \`${p13.decision.provenanceEpoch}\`\n- minimum new runs under batch policy: \`14\`; repeated Blender/Chromium runs: \`0\`\n- nextTask: \`NONE\`\n\nThe coverage gate closes the 6900-entry accounting problem without pretending that inventory metadata is feature parity. Each family has one deduplicated batch key; completed entries are regression-only, representative receipts are partial, and pending entries require unique-behavior fanout. Historical reproduction remains false and the release label stays AUTHORIZED_REBASELINE_ONLY.\n`);
const previousPlan = json("tests/golden/WBV2-P14-002/coverage-task-plan.json"); const nextPlan = structuredClone(previousPlan); nextPlan.status = "COMPLETED_WITH_INVENTORY_COVERAGE_GATE"; nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P14-002/coverage-task-plan.json", sha256: sha256("tests/golden/WBV2-P14-002/coverage-task-plan.json") }; nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P14-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-P14-003.md"), read("docs/tasks/WBV2-P14-003.md").replace("- status: in_progress", "- status: done")); 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-P14-003", "--write"], { cwd: root, stdio: "inherit" });
const artifactPaths = { parentManifest: parentPath, ledger: ledgerPath, matrix: matrixPath, matrixReport: matrixReportPath, p13Gate: p13GatePath, strategy: strategyPath, report: reportPath, generator: "tools/web/generate-wbv2-inventory-coverage-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-P14-003", parentTask: "WBV2-P14-002", operation: "CLOSE_INVENTORY_COVERAGE_GATE", status: "done", enablingTask: true, parityStateChange: false, runtime: "READ_ONLY_COVERAGE_GATE", artifacts, assertions: { inventoryTotal: 6900, inventoryCompleted: 281, inventoryActive: 1, inventoryPending: 6618, allEntriesBucketed: true, capabilityBuckets: 15, representativeEvidenceBuckets: 7, fullFamilyParityClaims: 0, engineBoundFeatureClaims: p13.decision.featureParityClaimCount, minimumNewRunsIfAllBatchesExecuted: 14, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true, provenanceEpoch: p13.decision.provenanceEpoch, 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-P14-003` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P14-002/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P14-003.md`](tasks/WBV2-P14-003.md) |"); fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
let nextTaskFile = read("nextTask.md"); nextTaskFile = nextTaskFile.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | `WBV2-P14-003` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `done` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P14-002/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P14-003.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `NONE` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-inventory-coverage-gate.mjs --write` |"); fs.writeFileSync(absolute("nextTask.md"), nextTaskFile);
process.stdout.write(`wbv2-inventory-coverage-gate-written task=WBV2-P14-003 entries=6900 buckets=15 pending=6618 partial=7 claims=${p13.decision.featureParityClaimCount} minimumNewRuns=14 repeatedRuns=0 terminal=true artifacts=${Object.keys(artifacts).length}\n`);