94 lines
11 KiB
JavaScript
94 lines
11 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import crypto from "node:crypto";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { execFileSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
const write = process.argv.includes("--write");
|
|
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 outputRoot = "tests/golden/WBV2-P12-001";
|
|
const ledgerPath = `${outputRoot}/capability-ledger.json`;
|
|
const reportPath = `${outputRoot}/capability-ledger-report.json`;
|
|
const sourceIndexPath = `${outputRoot}/source-manifest-index.json`;
|
|
const statusPath = "docs/status/WBV2-P12-001.md";
|
|
const planPath = `${outputRoot}/domain-expansion-task-plan.json`;
|
|
const manifestPath = `${outputRoot}/manifest.json`;
|
|
const parentPath = "tests/golden/WBV2-P12-000/manifest.json";
|
|
const inventoryPath = "tests/golden/WBV2-P0-002/parity-map.json";
|
|
const sourceTasks = [
|
|
"WBV2-P1-001", "WBV2-P1-002", "WBV2-P1-003", "WBV2-P1-004", "WBV2-P1-005",
|
|
"WBV2-P2-001", "WBV2-P2-002", "WBV2-P2-003", "WBV2-P2-004", "WBV2-P2-005",
|
|
"WBV2-P3-001", "WBV2-P3-002", "WBV2-P3-003", "WBV2-P3-004", "WBV2-P3-005",
|
|
"WBV2-P4-001", "WBV2-P4-002", "WBV2-P4-003", "WBV2-P4-004",
|
|
"WBV2-P5-001", "WBV2-P5-002", "WBV2-P5-003", "WBV2-P6-001", "WBV2-P6-002", "WBV2-P6-003",
|
|
"WBV2-P10-000", "WBV2-P10-001", "WBV2-P10-002", "WBV2-P10-003",
|
|
"WBV2-P11-000", "WBV2-P11-001", "WBV2-P11-002", "WBV2-P11-003", "WBV2-P11-004",
|
|
];
|
|
const parent = readJson(parentPath);
|
|
assert.equal(parent.task, "WBV2-P12-000");
|
|
assert.equal(parent.status, "done");
|
|
assert.equal(parent.nextTask, "WBV2-P12-001");
|
|
for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
|
|
const inventory = readJson(inventoryPath);
|
|
assert.equal(inventory.summary.inventoryEntries, 6900);
|
|
assert.equal(inventory.summary.pendingLegacyEntries, 6618);
|
|
|
|
const entries = sourceTasks.map((task) => {
|
|
const manifestPath = `tests/golden/${task}/manifest.json`;
|
|
const manifest = readJson(manifestPath);
|
|
assert.equal(manifest.task, task);
|
|
assert.equal(manifest.status, "done", `${task} must be completed before ledger aggregation`);
|
|
const artifacts = Object.values(manifest.artifacts ?? {}).map((artifact) => {
|
|
const exists = fs.existsSync(absolute(artifact.path));
|
|
return { path: artifact.path, recordedSha256: artifact.sha256, exists, currentHash: exists ? sha256(artifact.path) : null, drift: !exists || (exists && sha256(artifact.path) !== artifact.sha256) };
|
|
});
|
|
const currentDriftCount = artifacts.filter((artifact) => artifact.drift).length;
|
|
const engineBound = ["WBV2-P10-002", "WBV2-P11-004"].includes(task);
|
|
return { task, phase: task.match(/^WBV2-P(\d+)/u)?.[1] ?? "?", manifest: manifestPath, manifestSha256: sha256(manifestPath), status: manifest.status, operation: manifest.operation, artifactCount: artifacts.length, currentDriftCount, evidenceClass: engineBound ? "ENGINE_BOUND_EXACT" : currentDriftCount > 0 ? "HISTORICAL_DRIFT_RECORDED" : "EXACT_RECORDED", artifacts };
|
|
});
|
|
const sourceIndex = { schemaVersion: 1, task: "WBV2-P12-001", operation: "SOURCE_MANIFEST_BATCH_INDEX", policy: "read_only_batch_scan_no_repeated_execution", entries: entries.map(({ task, manifest, manifestSha256, status, operation, artifactCount, currentDriftCount, evidenceClass }) => ({ task, manifest, manifestSha256, status, operation, artifactCount, currentDriftCount, evidenceClass })) };
|
|
const ledger = { schemaVersion: 1, task: "WBV2-P12-001", operation: "EXISTING_CAPABILITY_LEDGER", status: "READY", policy: { reuseReadOnly: true, noRepeatedExecution: true, historicalDriftExplicit: true, onlyCurrentEngineReceiptsClaimed: true }, inventory: { source: inventoryPath, sourceSha256: sha256(inventoryPath), total: inventory.summary.inventoryEntries, pending: inventory.summary.pendingLegacyEntries, claimedComplete: 0, remainderExplicit: true }, sourceManifests: entries, engineBoundClaims: 6, claims: { historicalReceipts: entries.filter((entry) => entry.evidenceClass === "EXACT_RECORDED").length, historicalDriftRecorded: entries.filter((entry) => entry.evidenceClass === "HISTORICAL_DRIFT_RECORDED").length, currentEngineBound: entries.filter((entry) => entry.evidenceClass === "ENGINE_BOUND_EXACT").map((entry) => entry.task), noNewExecution: true }, summary: { manifestsDone: entries.length, artifactRecords: entries.reduce((sum, entry) => sum + entry.artifactCount, 0), historicalDriftManifests: entries.filter((entry) => entry.currentDriftCount > 0).length, currentEngineBoundManifests: entries.filter((entry) => entry.evidenceClass === "ENGINE_BOUND_EXACT").length, missingArtifacts: entries.reduce((sum, entry) => sum + entry.artifacts.filter((artifact) => !artifact.exists).length, 0) } };
|
|
assert.equal(entries.length, 34);
|
|
const report = { schemaVersion: 1, task: "WBV2-P12-001", operation: "RECONCILE_EXISTING_CAPABILITY_LEDGER", status: "PASS", ledgerSha256: "PENDING", sourceIndex: sourceIndexPath, sourceIndexSha256: "PENDING", inventory: ledger.inventory, summary: ledger.summary, reuse: { existingManifestsRead: entries.length, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, newProductionClaims: 0, engineBoundClaimsReused: ledger.engineBoundClaims }, driftPolicy: { historicalReportsUntouched: true, currentArtifactDriftRecorded: true, noHistoricalHashRewrite: true }, nextTask: "WBV2-P12-002" };
|
|
if (!write) { process.stdout.write(`wbv2-capability-ledger-dry-ok task=WBV2-P12-001 manifests=${entries.length} artifacts=${ledger.summary.artifactRecords} driftManifests=${ledger.summary.historicalDriftManifests} repeatedRuns=0 next=WBV2-P12-002\n`); process.exit(0); }
|
|
fs.mkdirSync(absolute(outputRoot), { recursive: true });
|
|
fs.writeFileSync(absolute(ledgerPath), `${JSON.stringify(ledger, null, 2)}\n`);
|
|
fs.writeFileSync(absolute(sourceIndexPath), `${JSON.stringify(sourceIndex, null, 2)}\n`);
|
|
report.ledgerSha256 = sha256(ledgerPath);
|
|
report.sourceIndexSha256 = sha256(sourceIndexPath);
|
|
fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
|
|
execFileSync(process.execPath, [absolute("tools/web/check-wbv2-capability-ledger.mjs")], { cwd: root, stdio: "inherit" });
|
|
fs.writeFileSync(absolute(statusPath), `# WBV2-P12-001 status\n\n- task: \`WBV2-P12-001\`; parent: \`WBV2-P12-000\`; status: \`done\`\n- source manifests batch-scanned: \`34\`; artifact records: \`${ledger.summary.artifactRecords}\`\n- repeated Blender/Chromium runs: \`0\`; historical drift manifests recorded: \`${ledger.summary.historicalDriftManifests}\`\n- current engine-bound claims reused: \`6\`; inventory: \`6900\` total, \`6618\` pending, claimed complete: \`0\`\n- nextTask: \`WBV2-P12-002\`\n\nThis ledger reuses existing P1-P6, P10, and P11 manifests as read-only evidence. It records current artifact drift instead of rewriting historical hashes and does not rerun already completed Blender or Chromium checks. Only P10/P11 engine-bound receipts are treated as current engine evidence; the remaining inventory stays explicit.\n`);
|
|
const previousPlan = readJson("tests/golden/WBV2-P12-000/domain-expansion-task-plan.json");
|
|
const nextPlan = structuredClone(previousPlan);
|
|
nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P12-000/domain-expansion-task-plan.json", sha256: sha256("tests/golden/WBV2-P12-000/domain-expansion-task-plan.json") };
|
|
nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P12-001" ? { ...task, status: "done", ready: false } : task.id === "WBV2-P12-002" ? { ...task, status: "in_progress", ready: true } : { ...task, ready: false });
|
|
fs.writeFileSync(absolute(planPath), `${JSON.stringify(nextPlan, null, 2)}\n`);
|
|
const nextCardPath = "docs/tasks/WBV2-P12-002.md";
|
|
fs.writeFileSync(absolute(nextCardPath), read(nextCardPath).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-P12-001", "--write"], { cwd: root, stdio: "inherit" });
|
|
const artifactPaths = { parentManifest: parentPath, inventory: inventoryPath, sourceIndex: sourceIndexPath, ledger: ledgerPath, report: reportPath, generator: "tools/web/generate-wbv2-capability-ledger.mjs", checker: "tools/web/check-wbv2-capability-ledger.mjs", parityPlan: planPath, status: statusPath, 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-P12-001", parentTask: "WBV2-P12-000", operation: "RECONCILE_EXISTING_CAPABILITY_LEDGER", status: "done", enablingTask: true, parityStateChange: false, runtime: "READ_ONLY_MANIFEST_BATCH_SCAN", artifacts, assertions: { sourceManifests: 34, artifactRecords: ledger.summary.artifactRecords, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, historicalDriftExplicit: true, currentEngineBoundClaimsReused: 6, inventoryTotal: 6900, inventoryPending: 6618, inventoryClaimedComplete: 0, historicalReproduction: false }, nextTask: "WBV2-P12-002" };
|
|
fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
|
|
let queue = read("docs/EXECUTION_QUEUE.md");
|
|
queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P12-002` |")
|
|
.replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P12-001/manifest.json` |")
|
|
.replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P12-002.md`](tasks/WBV2-P12-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-P12-002` |")
|
|
.replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |")
|
|
.replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P12-001/manifest.json` |")
|
|
.replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P12-002.md` |")
|
|
.replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `WBV2-P12-003` |")
|
|
.replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-scene-object-production.spec.ts` |");
|
|
fs.writeFileSync(absolute("nextTask.md"), nextTaskFile);
|
|
process.stdout.write(`wbv2-capability-ledger-written task=WBV2-P12-001 manifests=34 artifacts=${ledger.summary.artifactRecords} driftManifests=${ledger.summary.historicalDriftManifests} repeatedRuns=0 next=WBV2-P12-002\n`);
|