71 lines
4.0 KiB
JavaScript
71 lines
4.0 KiB
JavaScript
#!/usr/bin/env node
|
|
import crypto from "node:crypto";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
const root = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..");
|
|
const docs = path.join(root, "docs", "p6");
|
|
const matrixPath = path.join(docs, "object-contract-matrix.json");
|
|
const matrix = JSON.parse(fs.readFileSync(matrixPath, "utf8"));
|
|
const gateNames = [
|
|
"geometry-family-gate.json", "cam-generic-family-gate.json", "part-generic-family-gate.json",
|
|
"fem-generic-family-gate.json", "mesh-geometry-family-gate.json", "fem-geometry-family-gate.json",
|
|
"partdesign-generic-family-gate.json", "robot-generic-family-gate.json",
|
|
"cam-geometry-family-gate.json", "import-geometry-family-gate.json",
|
|
"inspection-geometry-family-gate.json", "part-geometry-family-gate.json",
|
|
"partdesign-geometry-family-gate.json", "points-geometry-family-gate.json",
|
|
"robot-geometry-family-gate.json", "sandbox-geometry-family-gate.json",
|
|
"sketcher-geometry-family-gate.json", "surface-geometry-family-gate.json",
|
|
"measure-object-family-gate.json", "data-property-family-gate.json",
|
|
"document-graph-family-gate.json", "viewprovider-family-gate.json",
|
|
];
|
|
const gated = new Map();
|
|
const gatedByName = new Map();
|
|
const gateModules = {
|
|
"cam-generic-family-gate.json": "CAM", "part-generic-family-gate.json": "Part",
|
|
"fem-generic-family-gate.json": "Fem", "partdesign-generic-family-gate.json": "PartDesign",
|
|
"robot-generic-family-gate.json": "Robot",
|
|
};
|
|
for (const name of gateNames) {
|
|
const file = path.join(docs, name);
|
|
if (!fs.existsSync(file)) continue;
|
|
const gate = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
for (const record of gate.records ?? []) {
|
|
if (record.id) gated.set(record.id, record);
|
|
if (record.name) {
|
|
const module = gateModules[name];
|
|
if (module) gatedByName.set(`${module}:${record.name}`, record);
|
|
for (const candidate of matrix.records.filter(item => item.name === record.name)) {
|
|
gatedByName.set(`${candidate.module}:${record.name}`, record);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const records = matrix.records.map((record) => {
|
|
const existing = gated.get(record.id) ?? gatedByName.get(`${record.module}:${record.name}`);
|
|
if (existing?.status) return { ...record, status: existing.status, detail: existing.detail ?? null, gate: existing.gate ?? null };
|
|
return {
|
|
...record,
|
|
status: "blocked",
|
|
detail: {
|
|
code: "native_fixture_required",
|
|
message: "No family-specific C-G native object fixture is registered yet",
|
|
firstError: true,
|
|
},
|
|
};
|
|
});
|
|
const counts = Object.fromEntries(["passed", "passed_boundary", "blocked"].map((status) => [status, records.filter((record) => record.status === status).length]));
|
|
const report = {
|
|
schema: "freecad-web-p6-object-contract-gate/v1",
|
|
taskId: "FW-P6-FPA-D",
|
|
result: records.length === matrix.records.length && counts.blocked > 0 ? "pass_with_blocked_records" : records.length === matrix.records.length ? "pass" : "fail",
|
|
coverage: { inventoryRecords: matrix.records.length, terminalRecords: records.filter((record) => ["passed", "passed_boundary", "blocked"].includes(record.status)).length, counts },
|
|
records,
|
|
source: { matrix: "docs/p6/object-contract-matrix.json", matrixSha256: crypto.createHash("sha256").update(fs.readFileSync(matrixPath)).digest("hex"), familyGates: gateNames.filter((name) => fs.existsSync(path.join(docs, name))) },
|
|
boundaries: ["blocked records retain source evidence but have no native fixture claim", "GUI-only view providers remain passed_boundary only when a family gate proves the boundary"],
|
|
};
|
|
fs.writeFileSync(path.join(docs, "object-contract-gate.json"), `${JSON.stringify(report, null, 2)}\n`);
|
|
fs.writeFileSync(path.join(root, "docs", "freecad-p6-object-contract-d.log"), `result=${report.result}\ninventoryRecords=${report.coverage.inventoryRecords}\nterminalRecords=${report.coverage.terminalRecords}\npassed=${counts.passed}\npassed_boundary=${counts.passed_boundary}\nblocked=${counts.blocked}\n`);
|
|
console.log(JSON.stringify({ result: report.result, ...report.coverage }));
|
|
if (report.result === "fail") process.exitCode = 1;
|