#!/usr/bin/env node import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { spawnSync } from "node:child_process"; import { fileURLToPath } from "node:url"; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const smoke = path.join(root, "freecad-source/src/WebAssembly/FreeCADCoreProbe/python-runtime-smoke.js"); const build = path.join(root, "freecad-source/build-web/configure/bin"); const run = spawnSync(process.execPath, [smoke, build], { cwd: root, encoding: "utf8" }); const output = (run.stdout ?? "").trim().split("\n").filter(Boolean).at(-1) ?? ""; const details = output ? JSON.parse(output) : null; const result = details?.ready?.ready === 1 && details.success?.value === "42" && details.facade?.run === 1 && details.facade?.value.includes("'type': 'Part::Box'") && details.failure?.error === "ZeroDivisionError: division by zero" && details.reset?.type === "reset" && details.timeout === "worker request timeout" && details.replacement?.ready === 1 && run.status === 0; const report = { schema: "freecad-web-p6-python-api-substrate-gate/v1", taskId: "FW-P6-FPA-F0", result: result ? "pass" : "fail", contracts: { pythonWorkerReady: details?.ready ?? null, valueConversion: details?.success ?? null, nativeFacade: details?.facade ?? null, structuredException: details?.failure ?? null, reset: details?.reset ?? null, timeoutTermination: details?.timeout ?? null, workerReplacement: details?.replacement ?? null, }, source: { smoke: "freecad-source/src/WebAssembly/FreeCADCoreProbe/python-runtime-smoke.js", build: "freecad-source/build-web/configure/bin/FreeCADWebPythonProbe.js", smokeSha256: crypto.createHash("sha256").update(fs.readFileSync(smoke)).digest("hex") }, protocol: { envelope: "freecad-web-core/v1", execution: "real Python/WASM", arbitraryNativePointers: false, resourceBoundary: "terminate and replace Worker" }, boundaries: ["F0 closes the reusable Python/WASM substrate behavior, not any module's full API inventory.", "Python API records remain planned until their own native family evidence and disposition are generated."], }; const docs = path.join(root, "docs/p6"); fs.writeFileSync(path.join(docs, "python-api-substrate-gate.json"), `${JSON.stringify(report, null, 2)}\n`); fs.writeFileSync(path.join(root, "docs/freecad-p6-python-api-substrate-gate.log"), `${JSON.stringify({ result: report.result, exitCode: run.status, timeout: details?.timeout, exception: details?.failure?.error })}\n`); console.log(JSON.stringify({ result: report.result, exitCode: run.status, timeout: details?.timeout })); if (!result) process.exitCode = 1;