Build and verify the candidate-only FreeCAD naming bridge and OCCT worker path, including three-stage StringHasher restoration. Add Datum, ShapeBinder, attachment-mode, and PartDesign structure oracles plus offline SDK build plans and CI boundary checks.
67 lines
6.7 KiB
JavaScript
67 lines
6.7 KiB
JavaScript
import { readFile } from 'node:fs/promises'
|
|
import { resolve } from 'node:path'
|
|
|
|
const root = resolve(new URL('..', import.meta.url).pathname)
|
|
const oracle = JSON.parse(await readFile(resolve(root, 'config/freecad-attachment-mode-oracle.json'), 'utf8'))
|
|
const fail = (message) => { throw new Error(`FreeCAD attachment mode oracle: ${message}`) }
|
|
const near = (actual, expected) => typeof actual === 'number' && Math.abs(actual - expected) <= oracle.tolerance
|
|
const same = (actual, expected) => JSON.stringify(actual) === JSON.stringify(expected)
|
|
|
|
const modes = [
|
|
'Deactivated', 'Translate', 'ObjectXY', 'ObjectXZ', 'ObjectYZ', 'FlatFace', 'TangentPlane', 'NormalToEdge',
|
|
'FrenetNB', 'FrenetTN', 'FrenetTB', 'Concentric', 'SectionOfRevolution', 'ThreePointsPlane', 'ThreePointsNormal', 'Folding',
|
|
'ObjectX', 'ObjectY', 'ObjectZ', 'AxisOfCurvature', 'Directrix1', 'Directrix2', 'Asymptote1', 'Asymptote2', 'Tangent', 'Normal',
|
|
'Binormal', 'TangentU', 'TangentV', 'TwoPointLine', 'IntersectionLine', 'ProximityLine', 'ObjectOrigin', 'Focus1', 'Focus2',
|
|
'OnEdge', 'CenterOfCurvature', 'CenterOfMass', 'IntersectionPoint', 'Vertex', 'ProximityPoint1', 'ProximityPoint2',
|
|
'AxisOfInertia1', 'AxisOfInertia2', 'AxisOfInertia3', 'InertialCS', 'FaceNormal', 'OZX', 'OZY', 'OXY', 'OXZ', 'OYZ', 'OYX',
|
|
'ParallelPlane', 'MidPoint',
|
|
]
|
|
const implemented = {
|
|
plane: ['Translate', 'ObjectXY', 'ObjectXZ', 'ObjectYZ', 'FlatFace', 'TangentPlane', 'NormalToEdge', 'FrenetNB', 'FrenetTN', 'FrenetTB', 'Concentric', 'SectionOfRevolution', 'ThreePointsPlane', 'ThreePointsNormal', 'Folding', 'InertialCS', 'OZX', 'OZY', 'OXY', 'OXZ', 'OYZ', 'OYX', 'ParallelPlane'],
|
|
line: ['ObjectX', 'ObjectY', 'ObjectZ', 'AxisOfCurvature', 'Directrix1', 'Directrix2', 'Asymptote1', 'Asymptote2', 'Tangent', 'Normal', 'Binormal', 'TwoPointLine', 'IntersectionLine', 'ProximityLine', 'AxisOfInertia1', 'AxisOfInertia2', 'AxisOfInertia3', 'FaceNormal'],
|
|
point: ['ObjectOrigin', 'Focus1', 'Focus2', 'OnEdge', 'CenterOfCurvature', 'CenterOfMass', 'Vertex', 'ProximityPoint1', 'ProximityPoint2'],
|
|
}
|
|
implemented.sketch = implemented.plane
|
|
const engineTypes = { plane: 'Attacher::AttachEnginePlane', line: 'Attacher::AttachEngineLine', point: 'Attacher::AttachEnginePoint', sketch: 'Attacher::AttachEnginePlane' }
|
|
const objectTypes = { plane: 'PartDesign::Plane', line: 'PartDesign::Line', point: 'PartDesign::Point', sketch: 'Sketcher::SketchObject' }
|
|
|
|
if (oracle.schemaVersion !== 1 || oracle.baselineId !== 'freecad-1.1.1-attachment-mode-oracle' || oracle.freecadVersion !== '1.1.1' || oracle.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || oracle.status !== 'pass' || oracle.tolerance !== 1e-7) fail('baseline is invalid.')
|
|
if (oracle.registry?.modeCount !== 55 || !same(oracle.registry.modes, modes) || oracle.registry.implementedUnionCount !== 50 || !same(oracle.registry.unimplementedModes, ['Deactivated', 'TangentU', 'TangentV', 'IntersectionPoint', 'MidPoint'])) fail('persistent mode registry or implemented union changed.')
|
|
|
|
for (const name of Object.keys(engineTypes)) {
|
|
const engine = oracle.engines?.[name]
|
|
if (engine?.typeId !== objectTypes[name] || engine.attacherType !== engineTypes[name] || !same(engine.completeModeList, modes) || !same(engine.implementedModes, implemented[name])) fail(`${name} engine identity or implemented modes changed.`)
|
|
for (const mode of implemented[name]) {
|
|
const info = engine.modeInfo?.[mode]
|
|
if (info?.modeIndex !== modes.indexOf(mode) || !Array.isArray(info.referenceCombinations) || info.referenceCombinations.length === 0) fail(`${name}.${mode} mode metadata is incomplete.`)
|
|
}
|
|
}
|
|
if (!same(oracle.engines.plane.modeInfo.FlatFace.referenceCombinations, [['Plane']]) || !same(oracle.engines.line.modeInfo.TwoPointLine.referenceCombinations, [['Vertex', 'Vertex'], ['Line']]) || !same(oracle.engines.point.modeInfo.Vertex.referenceCombinations, [['Vertex'], ['Line']])) fail('representative reference combination contract changed.')
|
|
|
|
const expectedSuccess = {
|
|
plane: { typeId: 'PartDesign::Plane', mode: 'FlatFace', refs: ['Plane'], support: ['Face1'] },
|
|
line: { typeId: 'PartDesign::Line', mode: 'TwoPointLine', refs: ['Vertex', 'Vertex'], support: ['Vertex1', 'Vertex2'] },
|
|
point: { typeId: 'PartDesign::Point', mode: 'Vertex', refs: ['Vertex'], support: ['Vertex1'] },
|
|
sketch: { typeId: 'Sketcher::SketchObject', mode: 'FlatFace', refs: ['Plane'], support: ['Face1'] },
|
|
}
|
|
for (const phase of ['initial', 'edited', 'roundtrip']) {
|
|
for (const [name, expected] of Object.entries(expectedSuccess)) {
|
|
const result = oracle.success?.[phase]?.[name]
|
|
if (result?.typeId !== expected.typeId || result.mapMode !== expected.mode || result.positionBySupport !== true || !same(result.state, ['Up-to-date']) || result.status !== 'Valid' || result.suggestion?.message !== 'OK' || !result.suggestion.allApplicableModes.includes(expected.mode) || !same(result.suggestion.referenceTypes, expected.refs) || !same(result.support?.[0]?.subElements, expected.support) || result.support?.[0]?.object !== 'SourceBox') fail(`${phase} ${name} success evidence is invalid.`)
|
|
}
|
|
}
|
|
if (!near(oracle.success.initial.point.placement.position?.[2], 6) || !near(oracle.success.edited.point.placement.position?.[2], 9) || !near(oracle.success.roundtrip.point.placement.position?.[2], 9)) fail('source mutation did not move the attached point through edit and round-trip.')
|
|
|
|
const failureContract = {
|
|
InvalidPlane: ['PartDesign::Plane', 'Vertex', 'Attachment mode Vertex is not implemented.'],
|
|
InvalidLine: ['PartDesign::Line', 'FlatFace', 'Attachment mode FlatFace is not implemented.'],
|
|
InvalidPoint: ['PartDesign::Point', 'FlatFace', 'Attachment mode FlatFace is not implemented.'],
|
|
}
|
|
for (const [name, [typeId, mode, status]] of Object.entries(failureContract)) {
|
|
const initial = oracle.failures?.initial?.[name]
|
|
const roundtrip = oracle.failures?.roundtrip?.[name]
|
|
if (initial?.typeId !== typeId || initial.mapMode !== mode || !same(initial.state, ['Touched', 'Invalid']) || initial.status !== status || roundtrip?.mapMode !== mode || !same(roundtrip.state, ['Touched', 'Invalid']) || roundtrip.status !== status) fail(`${name} unsupported-mode failure did not survive FCStd round-trip.`)
|
|
}
|
|
|
|
console.log(JSON.stringify({ status: 'freecad-attachment-mode-oracle-pass', baselineId: oracle.baselineId, persistentModes: oracle.registry.modeCount, implementedModes: { plane: implemented.plane.length, line: implemented.line.length, point: implemented.point.length, sketch: implemented.sketch.length }, representativeSuccesses: Object.keys(expectedSuccess), unsupportedFailures: Object.keys(failureContract), pointMutationZ: [oracle.success.initial.point.placement.position[2], oracle.success.edited.point.placement.position[2]], fcstdRoundtrip: true }, null, 2))
|