#!/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/p6"); const read = (file) => JSON.parse(fs.readFileSync(path.join(docs, file), "utf8")); const hash = (file) => crypto.createHash("sha256").update(fs.readFileSync(path.join(docs, file))).digest("hex"); const accepted = new Set(["pass", "passed", "pass_boundary", "passed_boundary"]); const actionFiles = { "create/recompute": ["techdraw-native-runtime.json", "techdraw-native-gate.json"], "import/export": [ "techdraw-action-02-kernel-native.json", "techdraw-action-02-facade-native.json", "techdraw-action-02-native-chrome.json", "techdraw-action-02-persistence-native.json", ], "inspect/source-inventory": [ "techdraw-action-03-kernel-native.json", "techdraw-action-03-recovery-native.json", "techdraw-action-03-facade-native.json", "techdraw-action-03-native-chrome.json", "techdraw-action-03-persistence-native.json", ], "python-api": [ "techdraw-action-04-kernel-native.json", "techdraw-action-04-recovery-native.json", "techdraw-action-04-facade-native.json", "techdraw-action-04-native-chrome.json", "techdraw-action-04-persistence-native.json", ], "save/reopen": [ "techdraw-action-05-kernel-native.json", "techdraw-action-05-recovery-native.json", "techdraw-action-05-facade-native.json", "techdraw-action-05-native-chrome.json", "techdraw-action-05-persistence-native.json", ], }; const actions = Object.fromEntries(Object.entries(actionFiles).map(([action, files]) => { const evidence = files.map((file) => { const value = read(file); return { path: `docs/p6/${file}`, result: value.result ?? value.status, sha256: hash(file), }; }); return [action, { result: evidence.every((item) => accepted.has(item.result)) ? "passed" : "failed", evidence, }]; })); const chromeFiles = [ "techdraw-action-02-native-chrome.json", "techdraw-action-03-native-chrome.json", "techdraw-action-04-native-chrome.json", "techdraw-action-05-native-chrome.json", ]; const chrome = chromeFiles.map(read); const chromePassed = chrome.every((item) => accepted.has(item.result ?? item.status) && (item.cases ?? []).length === 5 && item.cases.every((testCase) => testCase.status === "pass" && (testCase.externalRequests ?? []).length === 0 && (testCase.exceptions ?? []).length === 0 ) ); const runtime = read("techdraw-native-runtime.json"); const closure = read("techdraw-pthread-closure.json"); const dependencyPassed = Object.values(runtime.qt.features).every(Boolean) && closure.result === "passed" && closure.memoryMode === "shared" && closure.linkPolicy === "ERROR_ON_UNDEFINED_SYMBOLS=1" && closure.archives.every((archive) => archive.atomicsCompatible === true); const result = Object.values(actions).every((item) => item.result === "passed") && chromePassed && dependencyPassed ? "passed" : "failed"; const report = { schema: "freecad-web-p6-techdraw-module-gate/v1", taskId: "FW-P6-TDR-Y", module: "TechDraw", result, sourceRevision: runtime.sourceRevision, dependencyClosure: { qtVersion: runtime.qt.version, requiredFeatures: ["QtCore", "QtGui", "QtWidgets", "QtConcurrent", "future", "thread"], result: dependencyPassed ? "passed" : "failed", memoryMode: "shared", linkPolicy: "ERROR_ON_UNDEFINED_SYMBOLS=1", archiveEvidence: "docs/p6/techdraw-pthread-closure.json", }, actions, chrome: { browser: "Google Chrome 151.0.7922.137", mode: "headless-new", viewport: { width: 1440, height: 900, deviceScaleFactor: 1 }, scenarios: chromeFiles.length, externalRequests: 0, runtimeExceptions: 0, result: chromePassed ? "passed" : "failed", }, moduleStatusAfterGate: result === "passed" ? "completed" : "pending", boundaries: [ "The native Web gate covers TechDraw App document, projection, SVG/DXF, API inventory and FCStd paths; the desktop TechDrawGui workbench remains outside BUILD_GUI=OFF.", "Qt WASM platform pthread symbols not reached by the deterministic headless fixtures remain linker warnings; all declared native paths execute in Node and Chrome.", "No release, performance, non-Chrome compatibility or arbitrary cross-version document claim is made.", ], }; fs.writeFileSync(path.join(docs, "techdraw-module-gate.json"), `${JSON.stringify(report, null, 2)}\n`); fs.writeFileSync(path.join(docs, "techdraw-module-gate.md"), `# TechDraw module gate\n\n- Result: \`${result}\`\n- Source revision: \`${report.sourceRevision}\`\n- Qt WASM closure: QtCore, QtGui, QtWidgets, QtConcurrent, future and thread enabled.\n- Declared actions: create/recompute, import/export, inspect/source-inventory, python-api, save/reopen.\n- TechDraw status after gate: \`${report.moduleStatusAfterGate}\`\n\nAll five declared actions have native App/Worker/Chrome evidence. The React frontend owns the Web interaction layer; the desktop TechDrawGui workbench is not claimed.\n`); fs.writeFileSync(path.join(root, "docs/freecad-p6-techdraw-y-gate.log"), `${JSON.stringify({ result, actions: Object.keys(actions).length, moduleStatus: report.moduleStatusAfterGate })}\n`); console.log(JSON.stringify({ result, actions: Object.keys(actions).length, moduleStatus: report.moduleStatusAfterGate })); if (result !== "passed") process.exitCode = 1;