import { createHash } from 'node:crypto' import { readFile, writeFile } from 'node:fs/promises' import { resolve } from 'node:path' const root = resolve(new URL('..', import.meta.url).pathname) const sourcePath = resolve(root, '.cache/freecad/reference-desktop.json') const outputPath = resolve(root, 'config/freecad-property-force-inventory.json') const sourceContent = await readFile(sourcePath) const source = JSON.parse(sourceContent) const fail = (message) => { throw new Error(`FreeCAD PropertyForce inventory generation failed: ${message}`) } if (source.schemaVersion !== 1 || source.freecadVersion !== '1.1.1' || source.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('desktop oracle is not the locked FreeCAD baseline') const records = [] for (const objectType of source.runtimeObjects?.types ?? []) { for (const property of objectType.properties ?? []) { if (property.typeId !== 'App::PropertyForce') continue const output = JSON.stringify(property.status) === '[27]' records.push({ objectTypeId: objectType.typeId, objectAvailable: objectType.available === true, probeStatus: objectType.probeStatus, propertyName: property.name, group: property.group, status: property.status, defaultRaw: property.default, valueModel: { kind: 'quantity', dimension: 'mass*length/time^2', internalUnit: 'mm*kg/s^2', displayUnit: 'N', newtonScale: 1000, defaultValue: 0, writable: !output, derivedOutput: output, acceptedBoundaryEvidence: 'inventory-only; value and boundary acceptance remain pending in phase B/C', }, dependencies: [], applicability: { requiredObjectTypeId: objectType.typeId, source: 'Document.supportedTypes runtime inventory', }, }) } } if (records.length !== 4) fail(`expected four native App::PropertyForce records, found ${records.length}`) const report = { schemaVersion: 1, status: 'pass', baseline: { freecadVersion: source.freecadVersion, commit: source.gitCommit }, propertyType: 'App::PropertyForce', recordCount: records.length, writableRecordCount: records.filter(({ valueModel }) => valueModel.writable).length, outputRecordCount: records.filter(({ valueModel }) => valueModel.derivedOutput).length, records, source: { path: '.cache/freecad/reference-desktop.json', bytes: sourceContent.length, sha256: createHash('sha256').update(sourceContent).digest('hex'), }, classification: 'opaque-fcstd-proxy', nextPhases: ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], } await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-force-inventory.json', propertyType: report.propertyType, recordCount: report.recordCount, writableRecordCount: report.writableRecordCount, outputRecordCount: report.outputRecordCount }, null, 2))