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

74 lines
4.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import { execFileSync } from "node:child_process";
const root = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..");
const docs = path.join(root, "docs/p6");
const source = path.join(root, "freecad-source");
const evidencePaths = {
A: "import-source-boundary.json",
B: "import-runtime.json",
C: "import-kernel.json",
D: "import-recovery.json",
E: "import-facade.json",
F: "import-chrome.json",
G: "import-persistence.json",
};
const sha256 = (value) => crypto.createHash("sha256").update(value).digest("hex");
const evidence = Object.fromEntries(Object.entries(evidencePaths).map(([card, file]) => {
const bytes = fs.readFileSync(path.join(docs, file));
return [card, { path: `docs/p6/${file}`, sha256: sha256(bytes), data: JSON.parse(bytes) }];
}));
assert.equal(evidence.A.data.result, "pass_probe_only");
for (const card of ["B", "C", "D", "E", "F"]) assert.equal(evidence[card].data.result, "pass");
assert.equal(evidence.G.data.result, "pass_boundary");
assert.equal(evidence.C.data.deterministic, true);
assert.equal(evidence.D.data.statePreserved, true);
assert.equal(evidence.E.data.sequencing.maxActive, 1);
assert.equal(evidence.E.data.schemaChecks.noNativePointers, true);
assert.equal(evidence.F.data.network.externalRequestCount, 0);
assert.equal(evidence.F.data.runtimeExceptionCount, 0);
assert.equal(evidence.G.data.replayDeterministic, true);
assert.equal(evidence.G.data.persistence.applicability, "not_applicable_current_action");
const sourceInputs = Object.entries(evidence.A.data.inputs).map(([file, expectedSha256]) => {
const actualSha256 = sha256(fs.readFileSync(path.join(source, file)));
assert.equal(actualSha256, expectedSha256, `${file} changed after the source boundary probe`);
return { file, expectedSha256, actualSha256, unchanged: true };
});
const report = {
schema: "freecad-web-p6-import-gate/v1",
module: "Import",
slice: "import/step",
result: "pass_first_slice_only",
taskRange: "FW-P6-IMP-A..FW-P6-IMP-G",
sourceRevision: {
boundary: evidence.A.data.sourceRevision,
current: execFileSync("git", ["-C", source, "rev-parse", "HEAD"], { encoding: "utf8" }).trim(),
importInputsUnchanged: sourceInputs.every((input) => input.unchanged),
inputs: sourceInputs,
},
fixture: evidence.C.data.input,
kernelSummary: evidence.C.data.first.summary,
stateSha256: evidence.D.data.validSnapshotSha256,
chrome: {
version: evidence.F.data.chrome.version,
mode: evidence.F.data.mode,
viewport: evidence.F.data.viewport,
externalRequests: evidence.F.data.network.externalRequestCount,
runtimeExceptions: evidence.F.data.runtimeExceptionCount,
screenshotSha256: evidence.F.data.evidence.screenshotSha256,
},
evidence: Object.fromEntries(Object.entries(evidence).map(([card, item]) => [card, { path: item.path, sha256: item.sha256, result: item.data.result }])),
covered: ["Import App target initialization", "Import.StepShape registration", "STEP import through ReaderStep and ImportOCAFExt", "deterministic summary", "structured errors and recovery", "typed Facade/Worker", "Google Chrome replay", "resource manifest and fresh-runtime replay"],
pending: ["create/recompute action chain", "inspect/source-inventory action chain", "python-api action chain", "save/reopen action chain", "STEP export", "IGES/glTF/DXF/IFC/OBJ format coverage"],
moduleStatus: "pending",
conclusion: "The source-backed STEP import first slice is complete; the Import module remains pending until all declared action chains pass.",
};
fs.writeFileSync(path.join(docs, "import-gate.json"), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(path.join(docs, "import-gate.md"), `# Import 首切片 gate\n\n- 结果:\`pass_first_slice_only\`\n- 首切片:\`import/step\`\n- 内核摘要:32 objects / 5 parts / 5 solids / volume 104939.95608486432\n- 状态 SHA-256:\`${report.stateSha256}\`\n- Chrome:${report.chrome.version},${report.chrome.mode},${report.chrome.viewport.width}x${report.chrome.viewport.height},外部请求 0,运行时异常 0\n- 源码复核:A 卡记录的 ${sourceInputs.length} 个 Import 输入 hash 在当前 revision 仍全部一致\n- 模块状态:\`pending\`;本 gate 只关闭 STEP import 首切片\n\n## 未覆盖\n\n${report.pending.map((item) => `- ${item}`).join("\n")}\n`);
console.log(JSON.stringify({ result: report.result, evidence: Object.keys(evidence).length, sourceInputs: sourceInputs.length, moduleStatus: report.moduleStatus }));