Files
FreeCADWasmDev/tools/run_p6_mesh_python_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

4 lines
3.7 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{pathToFileURL}from"node:url";
const root=path.resolve(path.dirname(new URL(import.meta.url).pathname),"..");const build=path.resolve(process.argv[2]||path.join(root,"freecad-source/build-web/configure/bin"));const mp=path.join(root,"docs/p6/python-api-manifest.json");const m=JSON.parse(fs.readFileSync(mp,"utf8"));const records=m.records.filter(r=>r.module==="Mesh"&&r.tier==="tier-1-readonly").map(({id,name,family})=>({apiId:id,name,family}));if(records.length!==38)throw Error(`Mesh records expected 38, got ${records.length}`);globalThis.__dirname=`${build}${path.sep}`;globalThis.require=createRequire(import.meta.url);const l=await import(pathToFileURL(path.join(build,"FreeCADWebMeshRuntimeProbe.js")));const k=await l.default({wasmBinary:fs.readFileSync(path.join(build,"FreeCADWebMeshRuntimeProbe.wasm"))});const call=v=>JSON.parse(String(k.ccall("fc_web_dispatch_json","string",["string"],[JSON.stringify(v)])));const req={cmd:"mesh.pythonFamilyBatch",args:{tier:"tier-1-readonly",records}};const ok=call(req),rep=call(req),bad=call({cmd:req.cmd,args:{tier:req.args.tier,records:[{...records[0],apiId:"py:BIM:class:Binding"}]}}),mal=call({cmd:req.cmd,args:{tier:"tier-2-pure",records}});if(ok.ok!==true||ok.count!==38||ok.records?.length!==38||ok.resourcesReleased!==true)throw Error("Mesh family dispatch incomplete");if(ok.records.some(r=>!["exposed","restricted","nonportable","not_implemented"].includes(r.status)||r.native!==true||r.resourcesReleased!==true))throw Error("Mesh non-terminal result");if(JSON.stringify(ok)!==JSON.stringify(rep)||bad.records?.[0]?.code!=="unmatched_source_record"||mal.ok!==false)throw Error("Mesh replay/error boundary failed");const h=v=>crypto.createHash("sha256").update(JSON.stringify(v)).digest("hex");const by=new Map(ok.records.map(r=>[r.apiId,r]));for(const row of m.records){if(row.module!=="Mesh"||row.tier!=="tier-1-readonly")continue;const n=by.get(row.id);row.disposition=n.status;row.dispositionEvidence=["docs/p6/mesh-tier1-readonly-family.json"];row.dispositionReason=n.status==="restricted"?"requires Mesh GUI/view-provider capability outside the GUI-free Web runtime":"native Mesh Python family adapter evidence from FreeCAD WebAssembly";}fs.writeFileSync(mp,JSON.stringify(m,null,2)+"\n");const report={schema:"freecad-web-p6-mesh-tier1-readonly-family/v1",taskId:"FW-P6-FPA-F1-MESH",module:"Mesh",tier:"tier-1-readonly",status:"pass_with_boundaries",sourceRevision:"2778e3f9c215da48bf0cfd562478d45d624aaa47",route:{worker:"web/src/mesh.worker.ts",command:req.cmd,native:"freecad-source/src/WebAssembly/FreeCADCoreProbe/MeshRuntimeProbe.cpp:fc_web_dispatch_json"},input:req,inputSha256:h(req),result:ok,resultSha256:h(ok),replay:{equal:true,resultSha256:h(rep)},invalidRecord:{result:bad,resultSha256:h(bad)},malformedRequest:{result:mal,resultSha256:h(mal)},dispositionCounts:ok.records.reduce((a,r)=>(a[r.status]=(a[r.status]||0)+1,a),{}),resources:{resourcesReleased:true,documentMutation:false},boundaries:["All 38 records are returned by native fc_web_dispatch_json; MeshWorkbench and ViewProviderMesh remain restricted without GUI."]};fs.writeFileSync(path.join(root,"docs/p6/mesh-tier1-readonly-family.json"),JSON.stringify(report,null,2)+"\n");fs.writeFileSync(path.join(root,"docs/freecad-p6-mesh-tier1-readonly-family.log"),JSON.stringify({status:report.status,count:records.length,dispositionCounts:report.dispositionCounts,resultSha256:report.resultSha256})+"\n");console.log(JSON.stringify({status:report.status,count:records.length,dispositionCounts:report.dispositionCounts,resultSha256:report.resultSha256}));