#!/usr/bin/env node 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 docs = path.join(root, "docs"); const p6 = path.join(docs, "p6"); const read = (file) => JSON.parse(fs.readFileSync(path.join(p6, file), "utf8")); const hash = (file) => crypto.createHash("sha256").update(fs.readFileSync(path.join(p6, file))).digest("hex"); const chrome = read("core-shell-chrome.json"); const cases = Object.fromEntries(chrome.cases.map((item) => [item.id, item])); const required = ["core-ready", "core-action", "core-duplicate", "core-expected-error", "core-cancel", "core-reset", "core-repeat"]; const action = cases["core-action"]?.state; const native = action?.response?.result?.native; const contracts = Object.fromEntries(required.map((id) => [id, { status: cases[id]?.status ?? "missing", stage: cases[id]?.state?.stage ?? "missing", responseKind: cases[id]?.state?.response?.kind ?? null, error: cases[id]?.state?.response?.error?.code ?? null, progressEvents: cases[id]?.state?.progress?.length ?? 0, }])); const result = chrome.result === "pass" && required.every((id) => cases[id]?.status === "pass") && action?.stage === "success" && action?.response?.kind === "result" && action?.progress?.length === 3 && cases["core-duplicate"]?.state?.response?.error?.code === "duplicate_request" && cases["core-cancel"]?.state?.response?.error?.code === "cancelled" && native?.recomputeCount === 1 && native?.transactionUndoVolume > 0 && native?.transactionRedoVolume > native?.transactionUndoVolume; const report = { schema: "freecad-web-p6-core-shell-gate/v1", taskId: "FW-P6-FPA-B", result: result ? "pass" : "fail", contracts, native: { document: action?.response?.result?.document ?? null, values: native ?? null, resourcesReleased: action?.response?.result?.resourcesReleased ?? false, }, chrome: { artifact: "docs/p6/core-shell-chrome.json", sha256: hash("core-shell-chrome.json"), screenshot: chrome.evidence?.screenshot ?? null, screenshotSha256: chrome.evidence?.screenshotSha256 ?? null, browser: chrome.chrome?.version ?? null, externalRequests: chrome.cases.flatMap((item) => item.externalRequests ?? []).length, exceptions: chrome.cases.flatMap((item) => item.exceptions ?? []).length, }, architecture: { schema: "freecad-web-core/v1", worker: "web/src/core.worker.ts", runtime: "web/src/core-runtime.ts", shell: "web/src/core-shell.tsx", nativeProbe: "FreeCADWebDocumentProbe", queue: "one serial queue per Worker; duplicate and cancellation are typed terminal events", }, boundaries: [ "B closes the reusable React/Worker/Document actor substrate and one native multi-step contract only.", "403 object types, 236 format records, full FCStd graph coverage, and the 13,385 Python API dispositions remain later cards.", "The page does not claim desktop GUI or arbitrary Python execution.", ], }; fs.writeFileSync(path.join(p6, "core-shell-gate.json"), `${JSON.stringify(report, null, 2)}\n`); fs.writeFileSync(path.join(docs, "freecad-p6-core-shell-gate.log"), `${JSON.stringify({ result: report.result, cases: required.length, externalRequests: report.chrome.externalRequests, exceptions: report.chrome.exceptions })}\n`); console.log(JSON.stringify({ result: report.result, cases: required.length, externalRequests: report.chrome.externalRequests, exceptions: report.chrome.exceptions })); if (!result) process.exitCode = 1;