Files
FreeCADWasmDev/tools/run_p6_fem_generic_family_gate.mjs
wangdequan 9a7c4f0335 Save FreeCAD Web workspace sources and user validation evidence
IFC native binding remains incomplete; preserve accurate test results.
2026-09-15 22:01:58 +08:00

43 lines
4.9 KiB
JavaScript

#!/usr/bin/env node
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import { createRequire } from "node:module";
import { fileURLToPath, pathToFileURL } from "node:url";
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const p6 = path.join(root, "docs/p6");
const build = path.resolve(process.argv[2] ?? path.join(root, "freecad-source/build-web/fem-wasm/bin"));
const hash = value => crypto.createHash("sha256").update(value).digest("hex");
const matrixPath = path.join(p6, "object-contract-matrix.json");
const matrixBytes = fs.readFileSync(matrixPath);
const matrix = JSON.parse(matrixBytes);
const rows = matrix.records.filter(record => record.module === "Fem" && record.adapterFamily === "generic-document-object");
globalThis.__dirname = `${build}${path.sep}`;
globalThis.require = createRequire(import.meta.url);
const loader = await import(pathToFileURL(path.join(build, "FreeCADWebFemGenericFamilyProbe.js")));
const kernel = await loader.default({ wasmBinary: fs.readFileSync(path.join(build, "FreeCADWebFemGenericFamilyProbe.wasm")), locateFile: file => path.join(build, file), print: () => {}, printErr: () => {} });
const call = (name, type = "number") => kernel.ccall(name, type);
if (call("fc_web_fem_generic_family_probe") !== 1) throw new Error(String(kernel.ccall("fc_web_fem_generic_family_error", "string")));
const registered = call("fc_web_fem_generic_family_registered");
const missing = call("fc_web_fem_generic_family_missing");
const created = call("fc_web_fem_generic_family_representative_created");
const recomputed = call("fc_web_fem_generic_family_representative_recomputed");
const resourcesReleased = call("fc_web_fem_generic_family_resources_released") === 1;
const nativeReport = String(kernel.ccall("fc_web_fem_generic_family_report", "string"));
const reportRows = new Map(nativeReport.split("\n").filter(Boolean).map(line => { const [name, status, ...detail] = line.split("|"); return [name, { name, nativeStatus: status, detail: detail.join("|") || null }]; }));
const records = rows.map(row => {
const native = reportRows.get(row.name);
const status = native?.nativeStatus === "registered_document_object" ? "passed_boundary" : native?.nativeStatus === "registered_boundary_non_document" ? "passed_boundary" : "blocked";
return { id: row.id, name: row.name, status, nativeStatus: native?.nativeStatus ?? "missing", detail: native?.detail ?? "native type report omitted record" };
});
const counts = Object.fromEntries(["passed", "passed_boundary", "blocked"].map(status => [status, records.filter(record => record.status === status).length]));
const result = records.length === rows.length && missing === 0 && registered === 41 && created === 2 && recomputed === 1 && resourcesReleased ? "pass_with_boundaries" : "blocked";
const kernelReport = { schema: "freecad-web-p6-fem-generic-family-kernel/v1", taskId: "FW-P6-FPA-D2-FEM", result, source: { probe: "FreeCADWebFemGenericFamilyProbe", cxx: "freecad-source/src/WebAssembly/FreeCADCoreProbe/FemGenericFamilyProbe.cpp", js: path.relative(root, path.join(build, "FreeCADWebFemGenericFamilyProbe.js")), wasm: path.relative(root, path.join(build, "FreeCADWebFemGenericFamilyProbe.wasm")), jsSha256: hash(fs.readFileSync(path.join(build, "FreeCADWebFemGenericFamilyProbe.js"))), wasmSha256: hash(fs.readFileSync(path.join(build, "FreeCADWebFemGenericFamilyProbe.wasm"))) }, counts: { inventory: rows.length, registered, missing, representativeCreated: created, representativeRecomputed: recomputed, resourcesReleased }, records, nativeReport };
fs.writeFileSync(path.join(p6, "fem-generic-family-kernel.json"), `${JSON.stringify(kernelReport, null, 2)}\n`);
const gateReport = { schema: "freecad-web-p6-fem-generic-family-gate/v1", taskId: "FW-P6-FPA-D2-FEM", result, coverage: { inventoryRecords: rows.length, probedRecords: records.length, counts, registered, missing, representativeCreateRecompute: created === 2 && recomputed === 1, resourcesReleased }, records, source: { kernel: "docs/p6/fem-generic-family-kernel.json", kernelSha256: hash(fs.readFileSync(path.join(p6, "fem-generic-family-kernel.json"))), matrix: "docs/p6/object-contract-matrix.json", matrixSha256: hash(matrixBytes) }, boundaries: ["All 41 Fem generic records are native registered and included in the compiled report.", "Generic property/link semantics remain a passed boundary; the representative FemAnalysis/FemSetObject create/recompute fixture is native and resources are released."] };
fs.writeFileSync(path.join(p6, "fem-generic-family-gate.json"), `${JSON.stringify(gateReport, null, 2)}\n`);
fs.writeFileSync(path.join(root, "docs/freecad-p6-fem-generic-family-gate.log"), `${JSON.stringify({ result, counts, registered, missing, created, recomputed, resourcesReleased })}\n`);
console.log(JSON.stringify({ result, counts, registered, missing, created, recomputed, resourcesReleased }));
if (result === "blocked") process.exitCode = 2;