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

24 lines
4.9 KiB
JavaScript

import fs from "node:fs";
import path from "node:path";
import crypto from "node:crypto";
import { Worker } from "node:worker_threads";
import { pathToFileURL } from "node:url";
const root="/home/mes123456/FreeCADWasmDev/working/FreeCAD";
const build=path.resolve(process.argv[2]??path.join(root,"freecad-source/build-web/configure/bin"));
const batch=JSON.parse(fs.readFileSync(path.join(root,"docs/current/module-batch-manifest.json"),"utf8"));
if(batch.status!=="ready"||batch.taskId!=="FW-P6-FPA-Y"||batch.selected?.module!=="Sketcher"||batch.selected?.tier!=="tier-3-stateful"||batch.selected?.family!=="document-graph") throw Error("unexpected batch");
const records=batch.records.map(([apiId,name,disposition,sourcePath,sourceLine])=>({apiId,name,family:"document-graph",sourcePath,sourceLine,disposition}));
const out=fs.mkdtempSync("/tmp/sketcher-docgraph-"); const facadeOut=path.join(out,"facade"); fs.mkdirSync(facadeOut);
const runtime=path.join(out,"runtime"); fs.mkdirSync(runtime); fs.writeFileSync(path.join(runtime,"package.json"),'{"type":"module"}\n');
const runtimeSource=fs.readFileSync(path.join(build,"FreeCADWebSketcherProbe.js"),"utf8").replaceAll("FreeCADWebSketcherProbe.worker.js","FreeCADWebSketcherProbe.worker.cjs"); fs.writeFileSync(path.join(runtime,"FreeCADWebSketcherProbe.js"),runtimeSource); fs.copyFileSync(path.join(build,"FreeCADWebSketcherProbe.worker.js"),path.join(runtime,"FreeCADWebSketcherProbe.worker.cjs"));
const tsc=path.join(root,"web/node_modules/.bin/tsc"); const {execFileSync}=await import("node:child_process"); execFileSync(tsc,["--target","ES2022","--module","ESNext","--moduleResolution","Bundler","--strict","--skipLibCheck","--outDir",facadeOut,"--declaration","false",path.join(root,"web/src/facade-envelope.ts"),path.join(root,"web/src/sketcher-python-family-facade.ts")],{cwd:root,stdio:"inherit"});
const facade=await import(pathToFileURL(path.join(facadeOut,"sketcher-python-family-facade.js"))); const envelope=await import(pathToFileURL(path.join(facadeOut,"facade-envelope.js")));
const worker=new Worker(path.join(root,"tools/sketcher-python-family-facade-smoke-worker.mjs"),{workerData:{buildDirectory:build,runtimeDirectory:runtime,facadePath:pathToFileURL(path.join(facadeOut,"sketcher-python-family-facade.js")).href,envelopePath:pathToFileURL(path.join(facadeOut,"facade-envelope.js")).href}});
const next=()=>new Promise((res,rej)=>{const m=v=>{worker.off("error",e);res(v)},e=x=>{worker.off("message",m);rej(x)};worker.once("message",m);worker.once("error",e)});
const req=facade.createSketcherPythonFamilyRequest("sketcher-document-graph",records,"tier-3-stateful"); const ready=await next(); worker.postMessage(req); const success=await next(); worker.postMessage(req); const repeat=await next(); worker.postMessage({kind:"reset",requestId:"reset"}); const reset=await next(); await worker.terminate();
if(ready.kind!=="ready"||success.kind!=="result"||repeat.kind!=="error"||repeat.error?.code!=="duplicate_request"||reset.requestId!=="reset") throw Error(JSON.stringify({ready,success,repeat,reset}));
const result=success.result; if(result.count!==2||result.resourcesReleased!==true) throw Error("invalid result");
for(const r of result.records) if(r.status!=="not_implemented"||r.code!=="document_graph_native_boundary"||r.native!==true||r.resourcesReleased!==true) throw Error("boundary missing");
const hash=v=>crypto.createHash("sha256").update(JSON.stringify(v)).digest("hex"); const modules=JSON.parse(fs.readFileSync(path.join(root,"web/public/modules/manifest.json"),"utf8")); const mod=modules.modules?.Sketcher??modules.Sketcher; const wk=mod?.workers?.["sketcher-python.worker.ts"];
const evidence=`docs/p6/sketcher-document-graph-module-batch-${batch.batchId}-runtime.json`; const report={schema:"freecad-web-sketcher-document-graph-module-batch-runtime/v1",taskId:"FW-P6-FPA-Y",batchId:batch.batchId,module:"Sketcher",tier:"tier-3-stateful",family:"document-graph",status:"pass_with_boundaries",dispatcher:"fc_web_dispatch_json",route:{command:facade.SKETCHER_PYTHON_FAMILY_COMMAND,native:"freecad-source/src/WebAssembly/FreeCADCoreProbe/SketcherProbe.cpp:fc_web_dispatch_json",facade:"web/src/sketcher-python-family-facade.ts",worker:"web/src/sketcher-python.worker.ts"},result,resultSha256:hash(result),facadeWorker:{ready,success,repeat,reset},resources:{resourcesReleased:true,documentMutation:false},artifacts:{module:"Sketcher",worker:"sketcher-python.worker.ts",revision:mod.revision,runtimeUrl:wk.runtimeUrl,wasmUrl:wk.wasmUrl,dataUrl:wk.dataUrl??null,assetBaseUrl:mod.assetBaseUrl,workerRevision:wk.revision},boundaries:["SketchObject and SketchObjectSF document-graph mutation remain explicit headless native boundaries.","Statuses derive from compiled FreeCAD through fc_web_dispatch_json."]}; fs.writeFileSync(path.join(root,evidence),JSON.stringify(report,null,2)+"\n"); console.log(JSON.stringify({status:report.status,batchId:batch.batchId,records:2,resultSha256:report.resultSha256})); process.exit(0);