import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); const readJson = (relative) => JSON.parse(fs.readFileSync(path.join(root, relative), "utf8")); const sha = (relative) => crypto.createHash("sha256").update(fs.readFileSync(path.join(root, relative))).digest("hex"); const report = readJson("tests/golden/WBV2-P1424-001/product-implementation-report.json"); const catalog = readJson("web/app/src/capabilities/blender-feature-route-catalog.json"); const smokePlan = readJson("tests/golden/WBV2/feature-smoke-plan.json"); const smokeReport = readJson("tests/golden/WBV2/feature-smoke-report.json"); const smokeFix = readJson("tests/golden/WBV2/feature-smoke-fix-report.json"); const wasmManifest = readJson("web/app/public/wasm-module-manifest.json"); const countBy = (items, selector) => Object.fromEntries([...new Set(items.map(selector))].sort().map((key) => [key, items.filter((item) => selector(item) === key).length])); const unverified = catalog.entries.filter((entry) => entry.evidenceStatus === "UNVERIFIED"); const failedSmoke = smokeReport.cases.filter((entry) => entry.status !== "PASS"); const focusedPasses = new Set(smokeFix.fixes.filter((entry) => entry.status === "PASS").map((entry) => entry.featureId)); const unresolvedSmoke = failedSmoke.filter((entry) => !focusedPasses.has(entry.featureId)); const implementationResults = report.implementationTasks.map((task) => ({ id: task.id, module: task.module, status: task.status, resultPath: task.resultPath ?? null, resultPresent: task.resultPath ? fs.existsSync(path.join(root, task.resultPath)) : false, })); const missingResults = implementationResults.filter((entry) => !entry.resultPresent); const audit = { schemaVersion: 1, auditId: "WBV2-FEATURE-COMPLETENESS-001", operation: "DETAILED_MIGRATION_COMPLETENESS_AUDIT", status: missingResults.length || unresolvedSmoke.length ? "PARTIAL_BLOCKED" : "IMPLEMENTATION_COMPLETE", implementation: { workflowModules: { total: report.workflowModules.length, implemented: report.workflowModules.filter((item) => item.status === "implemented").length }, productTasks: { total: report.implementationTasks.length, implemented: report.implementationTasks.filter((item) => item.status === "implemented").length, missingResultFiles: missingResults }, }, routeCoverage: { unitCount: catalog.unitCount, classifiedCount: catalog.classifiedCount, unclassifiedCount: catalog.unclassifiedCount, counts: catalog.counts, unavailable: catalog.entries.filter((entry) => entry.route === "UNAVAILABLE").map((entry) => entry.id), byKind: countBy(catalog.entries, (entry) => entry.kind), byFamily: countBy(catalog.entries, (entry) => entry.family), }, behavioralEvidence: { status: catalog.behavioralEvidence.status, verifiedUnits: catalog.behavioralEvidence.verifiedUnits, unverifiedUnits: catalog.behavioralEvidence.unverifiedUnits, unverifiedByKind: countBy(unverified, (entry) => entry.kind), unverifiedByFamily: countBy(unverified, (entry) => entry.family), rule: "route assignment is not behavioral completion", }, smoke: { planId: smokePlan.planId, totalFeatures: smokePlan.cases.length, attempts: smokeReport.cases.reduce((sum, entry) => sum + Number(entry.attempts ?? 0), 0), passed: smokeReport.cases.filter((entry) => entry.status === "PASS").length, resolved: smokeReport.cases.filter((entry) => entry.status === "PASS").length + focusedPasses.size, initialFailed: failedSmoke, unresolved: unresolvedSmoke, focusedFix: smokeFix.fixes, retries: smokeFix.retries, }, wasmLifecycle: wasmManifest.modules.map((module) => ({ id: module.id, lifecycle: module.lifecycle, preload: module.preload, single: module.resources?.single?.fileName ?? null, pthread: module.resources?.pthread?.fileName ?? null })), actualMissingOrBlocked: [ { id: "IO_IMPORT_WASM_ARTIFACT", status: "RESOLVED", description: "importScene/exportScene is compiled into the source-matched WebEngine WASM and passed native ABI plus focused Chromium checks.", evidence: "tests/golden/WBV2/feature-smoke-fix-report.json" }, { id: "BEHAVIORAL_EVIDENCE_OVERLAY", status: "DEFERRED", description: "2720 classified source units still lack exact behavioral receipts; they remain routed, not claimed verified.", evidence: "web/app/src/capabilities/blender-feature-route-catalog.json" }, ], nextWork: { priority: ["schedule batched evidence for unverified operators/RNA/macros/modifier units"], forbidden: ["do not rerun passed feature smoke cases", "do not mark route assignment as behavioral verification", "do not replace WASM with a simulated JS implementation"], }, inputs: { productReportSha256: sha("tests/golden/WBV2-P1424-001/product-implementation-report.json"), routeCatalogSha256: sha("web/app/src/capabilities/blender-feature-route-catalog.json"), smokeReportSha256: sha("tests/golden/WBV2/feature-smoke-report.json"), }, }; const outputPath = path.join(root, "tests/golden/WBV2/feature-completeness-audit.json"); fs.writeFileSync(outputPath, `${JSON.stringify(audit, null, 2)}\n`); process.stdout.write(`wbv2-feature-completeness-audit status=${audit.status} modules=${audit.implementation.workflowModules.implemented}/${audit.implementation.workflowModules.total} tasks=${audit.implementation.productTasks.implemented}/${audit.implementation.productTasks.total} routes=${audit.routeCoverage.classifiedCount}/${audit.routeCoverage.unitCount} verified=${audit.behavioralEvidence.verifiedUnits} unverified=${audit.behavioralEvidence.unverifiedUnits} smokeResolved=${audit.smoke.resolved}/${audit.smoke.totalFeatures} blocked=${audit.actualMissingOrBlocked.filter((item) => item.status === "BLOCKED").length}\n`);