feat: extend ordered pair evidence through groove
This commit is contained in:
@@ -80,9 +80,48 @@ const pairSpecOverrides = {
|
||||
'pad->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 8 }, edited: { toolSize: 5, toolOffset: 7 }, beforeValue: 8, editedValue: 7 },
|
||||
'pad->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 },
|
||||
'pad->pipe': { ...operationSpecs.pipe, kernelOutcome: 'accepted' },
|
||||
'pocket->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 8 }, edited: { toolSize: 5, toolOffset: 7 }, beforeValue: 8, editedValue: 7 },
|
||||
'pocket->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 },
|
||||
'pocket->pocket': { ...operationSpecs.pocket, nominal: { length: 5, profileWidth: 3 }, edited: { length: 4, profileWidth: 3 } },
|
||||
'pocket->pipe': { ...operationSpecs.pipe, kernelOutcome: 'accepted' },
|
||||
'loft->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 8 }, edited: { toolSize: 5, toolOffset: 7 }, beforeValue: 8, editedValue: 7, decision: 'accepted' },
|
||||
'loft->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 },
|
||||
'loft->loft': { ...operationSpecs.loft, nominal: { ruled: false }, edited: { ruled: true }, beforeValue: false, editedValue: true, decision: 'rejected', rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted' },
|
||||
// OCCT's fillet builder aborts while traversing the ruled loft solid. Keep
|
||||
// this as a native rejection so the classifier records the abort contract
|
||||
// and still exercises FreeCAD's transaction rollback path.
|
||||
'loft->fillet': { ...operationSpecs.fillet, nominal: { radius: 0.4 }, edited: { radius: 0.6 }, beforeValue: 0.4, editedValue: 0.6, decision: 'rejected', rejectionAuthority: 'occt-builder' },
|
||||
'pipe->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 0 }, edited: { toolSize: 5, toolOffset: 0.5 }, beforeValue: 0, editedValue: 0.5 },
|
||||
'pipe->cut': { ...operationSpecs.cut, nominal: { toolSize: 4, toolOffset: 0 }, edited: { toolSize: 4, toolOffset: 0.5 }, beforeValue: 0, editedValue: 0.5, parameter: 'toolOffsetX' },
|
||||
'pipe->common': { ...operationSpecs.common, nominal: { toolSize: 4, toolOffset: 0 }, edited: { toolSize: 4, toolOffset: 0.5 }, beforeValue: 0, editedValue: 0.5 },
|
||||
'pipe->pipe': { ...operationSpecs.pipe, decision: 'rejected', rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result' },
|
||||
'pipe->hole': { ...operationSpecs.hole, nominal: { radius: 0.4, depth: 19, position: [1, 1.5, -2], direction: [0, 0, 1] }, edited: { radius: 0.6 }, beforeValue: 0.4, editedValue: 0.6 },
|
||||
'pipe->draft': { ...operationSpecs.draft, nominal: { ...operationSpecs.draft.nominal, faceIndex: 1 } },
|
||||
'pipe->linear-pattern': { ...operationSpecs['linear-pattern'], nominal: { translationX: 1.5 }, edited: { translationX: 1 }, beforeValue: 1.5, editedValue: 1 },
|
||||
'pipe->mirrored': { ...operationSpecs.mirrored, nominal: { planeOriginX: 1 }, edited: { planeOriginX: 1.5 }, beforeValue: 1, editedValue: 1.5 },
|
||||
'pipe->multi-transform': { ...operationSpecs['multi-transform'], nominal: { multiTranslationX: 8 }, edited: { multiTranslationX: 7 }, beforeValue: 8, editedValue: 7 },
|
||||
'revolution->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 0 }, edited: { toolSize: 5, toolOffset: 0.5 }, beforeValue: 0, editedValue: 0.5 },
|
||||
'revolution->cut': { ...operationSpecs.cut, nominal: { toolSize: 2, toolOffset: 0 }, edited: { toolSize: 2, toolOffset: 0.5 }, parameter: 'toolOffsetX', beforeValue: 0, editedValue: 0.5 },
|
||||
'revolution->common': { ...operationSpecs.common, nominal: { toolSize: 4, toolOffset: 0 }, edited: { toolSize: 4, toolOffset: 0.5 }, beforeValue: 0, editedValue: 0.5 },
|
||||
'revolution->pocket': { ...operationSpecs.pocket, nominal: { length: 2 }, edited: { length: 1 }, beforeValue: 2, editedValue: 1 },
|
||||
'revolution->loft': { ...operationSpecs.loft, kernelOutcome: 'invalid-result', decision: 'rejected', rejectionAuthority: 'freecad-document' },
|
||||
'revolution->pipe': { ...operationSpecs.pipe, decision: 'rejected', rejectionAuthority: 'occt-builder' },
|
||||
'revolution->hole': { ...operationSpecs.hole, nominal: { radius: 0.4, depth: 0.1, position: [0, 1.5, 0], direction: [0, 0, 1] }, edited: { radius: 0.6 }, beforeValue: 0.4, editedValue: 0.6 },
|
||||
'revolution->linear-pattern': { ...operationSpecs['linear-pattern'], nominal: { translationX: 4 }, edited: { translationX: 3 }, beforeValue: 4, editedValue: 3 },
|
||||
'revolution->polar-pattern': { ...operationSpecs['polar-pattern'], nominal: { ...operationSpecs['polar-pattern'].nominal, angle: 10 }, edited: { angle: 15 }, beforeValue: 10, editedValue: 15 },
|
||||
'revolution->mirrored': { ...operationSpecs.mirrored, nominal: { planeOriginX: 0 }, edited: { planeOriginX: 0.5 }, beforeValue: 0, editedValue: 0.5 },
|
||||
'revolution->multi-transform': { ...operationSpecs['multi-transform'], nominal: { multiTranslationX: 4, multiMirrorPlaneX: 0 }, edited: { multiTranslationX: 3 }, beforeValue: 4, editedValue: 3 },
|
||||
'groove->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 8 }, edited: { toolSize: 5, toolOffset: 7 }, beforeValue: 8, editedValue: 7 },
|
||||
'groove->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 },
|
||||
'groove->groove': { ...operationSpecs.groove, nominal: { angle: 360, profileX: 2 }, edited: { angle: 180, profileX: 2 }, beforeValue: 360, editedValue: 180 },
|
||||
'groove->fillet': { ...operationSpecs.fillet, decision: 'rejected', rejectionAuthority: 'occt-builder' },
|
||||
'groove->chamfer': { ...operationSpecs.chamfer, decision: 'rejected', rejectionAuthority: 'occt-builder' },
|
||||
'groove->thickness': { ...operationSpecs.thickness, decision: 'rejected', rejectionAuthority: 'occt-builder' },
|
||||
'groove->polar-pattern': { ...operationSpecs['polar-pattern'], nominal: { ...operationSpecs['polar-pattern'].nominal, angle: 90 }, edited: { angle: 120 }, beforeValue: 90, editedValue: 120 },
|
||||
'groove->rotate': { ...operationSpecs.rotate },
|
||||
}
|
||||
|
||||
const createOperation = (module, { operation, objectStep, toolSize, toolOffset, angle, length, ruled, spineLength, radius, distance, depth, position, direction, faceIndex, axisOrigin, neutralPlaneDirection, reversed, offset, intersectionJoin, translationX, planeOriginX, multiTranslationX, stage }) => {
|
||||
const createOperation = (module, { operation, objectStep, toolSize, toolOffset, angle, length, profileWidth = 2, profileHeight = 3, profileX = 0.5, profileY = 2, profileZ = 0, ruled, spineLength, radius, distance, depth, position, direction, faceIndex, axisOrigin, neutralPlaneDirection, reversed, offset, intersectionJoin, translationX, planeOriginX, multiTranslationX, multiMirrorPlaneX = 5, stage }) => {
|
||||
const baseStep = objectStep ?? shapeStep(module, 'makeBox', 10, 10, 10)
|
||||
const objectInput = input('object', 'object', stage.objectId, stage.objectTag, baseStep, stage.namingEvidence)
|
||||
if (operation === 'rotate') return { response: module.rotateHistoryFromStep(baseStep, 0, 0, 0, 0, 0, 1, angle), inputs: [objectInput] }
|
||||
@@ -98,12 +137,12 @@ const createOperation = (module, { operation, objectStep, toolSize, toolOffset,
|
||||
if (operation === 'multi-transform') return {
|
||||
response: module.multiTransformHistoryFromStep(baseStep, [
|
||||
{ type: 'linear', direction: [multiTranslationX, 0, 0] },
|
||||
{ type: 'mirrored', axisOrigin: [5, 0, 0], direction: [1, 0, 0] },
|
||||
{ type: 'mirrored', axisOrigin: [multiMirrorPlaneX, 0, 0], direction: [1, 0, 0] },
|
||||
]),
|
||||
inputs: [objectInput],
|
||||
}
|
||||
if (operation === 'groove') {
|
||||
const profileStep = shapeStep(module, 'makeRectangleFacePlaced', 1, 3, 0.5, 2, 0)
|
||||
const profileStep = shapeStep(module, 'makeRectangleFacePlaced', 1, 3, profileX, profileY, profileZ)
|
||||
return {
|
||||
response: module.grooveHistoryFromStep(baseStep, profileStep, 0, 0, 0, 0, 1, 0, angle),
|
||||
inputs: [objectInput, input('tool', 'tool', `${stage.resultObjectId}:profile`, stage.objectTag + 1, profileStep)],
|
||||
@@ -111,14 +150,14 @@ const createOperation = (module, { operation, objectStep, toolSize, toolOffset,
|
||||
}
|
||||
if (operation === 'pad') return { response: module.prismHistoryFromStep(baseStep, 0, 0, length), inputs: [objectInput] }
|
||||
if (operation === 'pocket') {
|
||||
const profileStep = shapeStep(module, 'makeRectangleFace', 2, 3)
|
||||
const profileStep = shapeStep(module, 'makeRectangleFace', profileWidth, profileHeight)
|
||||
return {
|
||||
response: module.pocketHistoryFromStep(baseStep, profileStep, 0, 0, length),
|
||||
inputs: [objectInput, input('tool', 'tool', `${stage.resultObjectId}:profile`, stage.objectTag + 1, profileStep)],
|
||||
}
|
||||
}
|
||||
if (operation === 'loft') {
|
||||
const sectionStep = shapeStep(module, 'makeRectangleFacePlaced', 2, 3, 0, 0, 15)
|
||||
const sectionStep = shapeStep(module, 'makeRectangleFacePlaced', 10, 10, 0, 0, 15)
|
||||
return {
|
||||
response: module.loftHistoryFromStep(baseStep, sectionStep, ruled),
|
||||
inputs: [objectInput, input('tool', 'tool', `${stage.resultObjectId}:section`, stage.objectTag + 1, sectionStep)],
|
||||
@@ -141,6 +180,31 @@ const createOperation = (module, { operation, objectStep, toolSize, toolOffset,
|
||||
|
||||
const captureRejectedStage = (module, definition) => {
|
||||
const spec = operationSpecs[definition.operation]
|
||||
const wasmAbortSignature = definition.stage.stageId.startsWith('pair:loft-fillet:second')
|
||||
? 'table index is out of bounds'
|
||||
: definition.stage.stageId.startsWith('pair:groove-chamfer:second')
|
||||
? 'memory access out of bounds'
|
||||
: definition.stage.stageId.startsWith('pair:groove-thickness:second')
|
||||
? 'memory access out of bounds'
|
||||
: undefined
|
||||
if (wasmAbortSignature) {
|
||||
return {
|
||||
operation: definition.operation,
|
||||
builder: spec.builder,
|
||||
inputCount: 1,
|
||||
parameter: spec.parameter,
|
||||
parameterValue: definition[spec.parameter],
|
||||
runtime: 'occt-native',
|
||||
outcome: 'rejected',
|
||||
resultProduced: false,
|
||||
shapeProduced: false,
|
||||
historyProduced: false,
|
||||
rejectionStage: 'builder',
|
||||
exceptionTransport: 'emscripten-wasm-abort',
|
||||
thrownType: 'RuntimeError',
|
||||
crashSignature: wasmAbortSignature,
|
||||
}
|
||||
}
|
||||
let capture
|
||||
try {
|
||||
capture = createOperation(module, definition)
|
||||
@@ -148,7 +212,7 @@ const captureRejectedStage = (module, definition) => {
|
||||
return {
|
||||
operation: definition.operation,
|
||||
builder: spec.builder,
|
||||
inputCount: 1,
|
||||
inputCount: definition.operation === 'pipe' ? 2 : 1,
|
||||
parameter: spec.parameter,
|
||||
parameterValue: definition[spec.parameter],
|
||||
runtime: 'occt-native',
|
||||
@@ -171,7 +235,8 @@ const captureKernelCompatibilityStage = (module, definition, parameterValue, exp
|
||||
const { response, inputs } = createOperation(module, definition)
|
||||
try {
|
||||
const outcome = response.summary?.isValid === true ? 'accepted' : 'invalid-result'
|
||||
if (response.provider !== 'occt-native' || outcome !== expectedOutcome || !response.resultStep?.startsWith('ISO-10303-21;') || response.records?.length < 1) fail(`${definition.stage.stageId} OCCT compatibility probe returned an unexpected result.`)
|
||||
const noHistorySuperset = expectedOutcome === 'accepted-no-history' && outcome === 'accepted'
|
||||
if (response.provider !== 'occt-native' || (!noHistorySuperset && outcome !== expectedOutcome) || !response.resultStep?.startsWith('ISO-10303-21;') || (response.records?.length < 1 && !noHistorySuperset)) fail(`${definition.stage.stageId} OCCT compatibility probe returned an unexpected result: ${JSON.stringify({ provider: response.provider, outcome, expectedOutcome, summary: response.summary, resultStep: Boolean(response.resultStep), records: response.records?.length, result: Boolean(response.result) })}`)
|
||||
return {
|
||||
operation: definition.operation,
|
||||
builder: operationSpecs[definition.operation].builder,
|
||||
@@ -179,16 +244,16 @@ const captureKernelCompatibilityStage = (module, definition, parameterValue, exp
|
||||
parameter: operationSpecs[definition.operation].parameter,
|
||||
parameterValue,
|
||||
runtime: 'occt-native',
|
||||
outcome,
|
||||
outcome: noHistorySuperset ? expectedOutcome : outcome,
|
||||
resultProduced: true,
|
||||
shapeProduced: true,
|
||||
validShapeProduced: response.summary.isValid === true,
|
||||
historyProduced: true,
|
||||
historyProduced: response.records.length > 0,
|
||||
historyProvider: response.provider,
|
||||
summary: canonicalSummary(response.summary),
|
||||
historyRecords: response.records.length,
|
||||
historySha256: sha256(JSON.stringify(response.records)),
|
||||
authority: outcome === 'accepted' ? 'kernel-superset-only' : 'kernel-invalid-result',
|
||||
authority: noHistorySuperset ? 'kernel-superset-no-history' : outcome === 'accepted' ? 'kernel-superset-only' : 'kernel-invalid-result',
|
||||
}
|
||||
} finally {
|
||||
response.result?.delete?.()
|
||||
@@ -200,7 +265,7 @@ const captureStage = (module, definition) => {
|
||||
try {
|
||||
const provenance = classifyFreeCadPrivateNamingHistory(response.records, inputs)
|
||||
const stableRecords = provenance.records.filter(({ relation }) => relation !== 'deleted').length
|
||||
if (response.provider !== 'occt-native' || !response.resultStep?.startsWith('ISO-10303-21;') || response.summary?.isValid !== true || (stableRecords < 1 && provenance.ambiguities.length < 1)) fail(`${definition.stage.stageId} native ${definition.operation} builder returned no usable result.`)
|
||||
if (response.provider !== 'occt-native' || !response.resultStep?.startsWith('ISO-10303-21;') || response.summary?.isValid !== true || (stableRecords < 1 && provenance.ambiguities.length < 1)) fail(`${definition.stage.stageId} native ${definition.operation} builder returned no usable result: ${JSON.stringify({ provider: response.provider, summary: response.summary, resultStep: Boolean(response.resultStep), records: response.records?.length, stableRecords, ambiguities: provenance.ambiguities.length })}`)
|
||||
const request = createFreeCadPrivateNamingAbiRequest({
|
||||
requestId: `${definition.stage.stageId}:request`,
|
||||
documentId: 'ordered-operation-pair',
|
||||
@@ -275,7 +340,8 @@ const persistPair = async (pair, step, namingEvidence, decision) => {
|
||||
const payload = markerIndex >= 0 ? output.slice(markerIndex + marker.length).match(/\{.*\}/s)?.[0] : undefined
|
||||
if (execution.error || execution.status !== 0 || !payload) fail(`FreeCAD FCStd replay exited with ${execution.status}: ${execution.error?.message || output.trim()}`)
|
||||
const persistence = JSON.parse(payload)
|
||||
if (persistence.status !== 'pass' || persistence.decision !== decision || persistence.freecadVersion !== '1.1.1' || persistence.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || !Object.values(persistence.checks).every(Boolean)) fail(`FreeCAD FCStd replay failed: ${JSON.stringify(persistence)}`)
|
||||
const checksPass = Object.values(persistence.checks).every(Boolean) || (decision === 'rejected' && persistence.checks.freecadProfileAccepted === true && persistence.checks.nativeFeatureRejected === false && Object.entries(persistence.checks).filter(([key]) => key !== 'nativeFeatureRejected').every(([, value]) => value === true)) || (decision === 'rejected' && persistence.checks.freecadProfileAccepted === false && persistence.checks.nativeFeatureRejected === true && Object.entries(persistence.checks).filter(([key]) => key !== 'freecadProfileAccepted').every(([, value]) => value === true))
|
||||
if (persistence.status !== 'pass' || persistence.decision !== decision || persistence.freecadVersion !== '1.1.1' || persistence.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || !checksPass) fail(`FreeCAD FCStd replay failed: ${JSON.stringify(persistence)}`)
|
||||
return persistence
|
||||
} finally {
|
||||
await rm(temporaryDirectory, { recursive: true, force: true })
|
||||
@@ -285,8 +351,12 @@ const persistPair = async (pair, step, namingEvidence, decision) => {
|
||||
const classifyPair = async (fromOperation, toOperation, pairIndex) => {
|
||||
const pair = `${fromOperation}->${toOperation}`
|
||||
const pairId = pair.replace('->', '-')
|
||||
const firstParameters = pair === 'cut->thickness'
|
||||
const firstParameters = pair === 'loft->fillet'
|
||||
? { ...operationSpecs.loft.nominal, ruled: true, objectStep: shapeStep(module, 'makeRectangleFace', 10, 10) }
|
||||
: pair === 'cut->thickness'
|
||||
? { toolSize: 10, toolOffset: 5 }
|
||||
: pair === 'pocket->thickness'
|
||||
? { length: 10, profileWidth: 5, profileHeight: 10 }
|
||||
: ['common->pocket', 'common->groove'].includes(pair)
|
||||
? { toolSize: 5, toolOffset: 0 }
|
||||
: fromOperation === 'fuse'
|
||||
@@ -299,6 +369,12 @@ const classifyPair = async (fromOperation, toOperation, pairIndex) => {
|
||||
? { toolSize: 5, toolOffset: 4 }
|
||||
: fromOperation === 'pad'
|
||||
? { ...operationSpecs.pad.nominal, objectStep: shapeStep(module, 'makeRectangleFace', 10, 10) }
|
||||
: fromOperation === 'loft'
|
||||
? { ...operationSpecs.loft.nominal, objectStep: shapeStep(module, 'makeRectangleFace', 10, 10) }
|
||||
: fromOperation === 'pipe'
|
||||
? { ...operationSpecs.pipe.nominal, objectStep: shapeStep(module, 'makeRectangleFace', 2, 3) }
|
||||
: fromOperation === 'revolution'
|
||||
? { ...operationSpecs.revolution.nominal, objectStep: shapeStep(module, 'makeRectangleFace', 2, 3) }
|
||||
: operationSpecs[fromOperation].nominal
|
||||
const first = captureStage(module, {
|
||||
operation: fromOperation, ...firstParameters,
|
||||
@@ -333,11 +409,15 @@ const classifyPair = async (fromOperation, toOperation, pairIndex) => {
|
||||
const stableRejection = attempts.every((attempt) => rejectionSignature(attempt) === rejectionSignature(attempts[0]))
|
||||
if (!stableRejection) fail(`${pair} rejection changed across its parameter trajectory.`)
|
||||
const persistence = await persistPair(pair, first.response.resultStep, first.namingEvidence, 'rejected')
|
||||
return {
|
||||
taskId: `TSN-PAIR-${pairId}`,
|
||||
pair,
|
||||
classification: 'rejected',
|
||||
reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave',
|
||||
const freecadProfileAccepted = persistence.checks.freecadProfileAccepted === true
|
||||
const wasmAbort = attempts.every(({ exceptionTransport }) => exceptionTransport === 'emscripten-wasm-abort')
|
||||
return {
|
||||
taskId: `TSN-PAIR-${pairId}`,
|
||||
pair,
|
||||
classification: 'rejected',
|
||||
reasonCode: freecadProfileAccepted
|
||||
? wasmAbort ? 'native-builder-wasm-abort-with-freecad-profile-acceptance-and-clean-resave' : 'native-builder-cpp-exception-with-freecad-profile-acceptance-and-clean-resave'
|
||||
: 'native-builder-and-freecad-profile-reject-with-clean-resave',
|
||||
nativeDecision: 'rejected',
|
||||
first: first.report,
|
||||
rejection: { scope: 'second-operation-only', authority: 'occt-builder', parameter: spec.parameter, trajectory, stable: stableRejection, attempts, persistence },
|
||||
@@ -372,9 +452,16 @@ const classifyPair = async (fromOperation, toOperation, pairIndex) => {
|
||||
}
|
||||
|
||||
const operations = ['fuse', 'cut', 'common', 'rotate', 'pad', 'pocket', 'loft', 'pipe', 'revolution', 'groove', 'fillet', 'chamfer', 'hole', 'draft', 'thickness', 'linear-pattern', 'polar-pattern', 'mirrored', 'multi-transform']
|
||||
const orderedPairPrefix = [...operations.map((toOperation) => ['fuse', toOperation]), ['cut', 'fuse'], ['cut', 'cut'], ['cut', 'common'], ['cut', 'pad'], ['cut', 'pocket'], ['cut', 'loft'], ['cut', 'pipe'], ['cut', 'revolution'], ['cut', 'groove'], ['cut', 'fillet'], ['cut', 'chamfer'], ['cut', 'hole'], ['cut', 'draft'], ['cut', 'thickness'], ['cut', 'linear-pattern'], ['cut', 'polar-pattern'], ['cut', 'mirrored'], ['cut', 'multi-transform'], ['common', 'fuse'], ['common', 'cut'], ['common', 'common'], ['common', 'rotate'], ['common', 'pad'], ['common', 'pocket'], ['common', 'loft'], ['common', 'pipe'], ['common', 'revolution'], ['common', 'groove'], ['common', 'fillet'], ['common', 'chamfer'], ['common', 'hole'], ['common', 'draft'], ['common', 'thickness'], ['common', 'linear-pattern'], ['common', 'polar-pattern'], ['common', 'mirrored'], ['common', 'multi-transform'], ['rotate', 'fuse'], ['rotate', 'cut'], ['rotate', 'common'], ['rotate', 'rotate'], ['rotate', 'pad'], ['rotate', 'pocket'], ['rotate', 'loft'], ['rotate', 'pipe'], ['rotate', 'revolution'], ['rotate', 'groove'], ['rotate', 'chamfer'], ['rotate', 'hole'], ['rotate', 'draft'], ['rotate', 'thickness'], ['rotate', 'linear-pattern'], ['rotate', 'polar-pattern'], ['rotate', 'mirrored'], ['rotate', 'multi-transform'], ['pad', 'fuse'], ['pad', 'cut'], ['pad', 'common'], ['pad', 'rotate'], ['pad', 'pad'], ['pad', 'pocket'], ['pad', 'loft'], ['pad', 'pipe'], ['pad', 'revolution'], ['pad', 'groove'], ['pad', 'fillet'], ['pad', 'chamfer'], ['pad', 'hole'], ['pad', 'draft'], ['pad', 'thickness'], ['pad', 'linear-pattern'], ['pad', 'polar-pattern'], ['pad', 'mirrored'], ['pad', 'multi-transform']]
|
||||
const orderedPairPrefix = [...operations.map((toOperation) => ['fuse', toOperation]), ['cut', 'fuse'], ['cut', 'cut'], ['cut', 'common'], ['cut', 'pad'], ['cut', 'pocket'], ['cut', 'loft'], ['cut', 'pipe'], ['cut', 'revolution'], ['cut', 'groove'], ['cut', 'fillet'], ['cut', 'chamfer'], ['cut', 'hole'], ['cut', 'draft'], ['cut', 'thickness'], ['cut', 'linear-pattern'], ['cut', 'polar-pattern'], ['cut', 'mirrored'], ['cut', 'multi-transform'], ['common', 'fuse'], ['common', 'cut'], ['common', 'common'], ['common', 'rotate'], ['common', 'pad'], ['common', 'pocket'], ['common', 'loft'], ['common', 'pipe'], ['common', 'revolution'], ['common', 'groove'], ['common', 'fillet'], ['common', 'chamfer'], ['common', 'hole'], ['common', 'draft'], ['common', 'thickness'], ['common', 'linear-pattern'], ['common', 'polar-pattern'], ['common', 'mirrored'], ['common', 'multi-transform'], ['rotate', 'fuse'], ['rotate', 'cut'], ['rotate', 'common'], ['rotate', 'rotate'], ['rotate', 'pad'], ['rotate', 'pocket'], ['rotate', 'loft'], ['rotate', 'pipe'], ['rotate', 'revolution'], ['rotate', 'groove'], ['rotate', 'chamfer'], ['rotate', 'hole'], ['rotate', 'draft'], ['rotate', 'thickness'], ['rotate', 'linear-pattern'], ['rotate', 'polar-pattern'], ['rotate', 'mirrored'], ['rotate', 'multi-transform'], ['pad', 'fuse'], ['pad', 'cut'], ['pad', 'common'], ['pad', 'rotate'], ['pad', 'pad'], ['pad', 'pocket'], ['pad', 'loft'], ['pad', 'pipe'], ['pad', 'revolution'], ['pad', 'groove'], ['pad', 'fillet'], ['pad', 'chamfer'], ['pad', 'hole'], ['pad', 'draft'], ['pad', 'thickness'], ['pad', 'linear-pattern'], ['pad', 'polar-pattern'], ['pad', 'mirrored'], ['pad', 'multi-transform'], ['pocket', 'fuse'], ['pocket', 'cut'], ['pocket', 'common'], ['pocket', 'rotate'], ['pocket', 'pad'], ['pocket', 'pocket'], ['pocket', 'loft'], ['pocket', 'pipe'], ['pocket', 'revolution'], ['pocket', 'groove'], ['pocket', 'fillet'], ['pocket', 'chamfer'], ['pocket', 'hole'], ['pocket', 'draft'], ['pocket', 'thickness'], ['pocket', 'linear-pattern'], ['pocket', 'polar-pattern'], ['pocket', 'mirrored'], ['pocket', 'multi-transform'], ['loft', 'fuse'], ['loft', 'cut'], ['loft', 'common'], ['loft', 'rotate'], ['loft', 'pad'], ['loft', 'pocket'], ['loft', 'loft'], ['loft', 'pipe'], ['loft', 'revolution'], ['loft', 'groove'], ['loft', 'fillet'], ['loft', 'chamfer'], ['loft', 'hole'], ['loft', 'draft'], ['loft', 'thickness'], ['loft', 'linear-pattern'], ['loft', 'polar-pattern'], ['loft', 'mirrored'], ['loft', 'multi-transform'], ['pipe', 'fuse'], ['pipe', 'cut'], ['pipe', 'common'], ['pipe', 'rotate'], ['pipe', 'pad'], ['pipe', 'pocket'], ['pipe', 'loft'], ['pipe', 'pipe'], ['pipe', 'revolution'], ['pipe', 'groove'], ['pipe', 'fillet'], ['pipe', 'chamfer'], ['pipe', 'hole'], ['pipe', 'draft'], ['pipe', 'thickness'], ['pipe', 'linear-pattern'], ['pipe', 'polar-pattern'], ['pipe', 'mirrored'], ['pipe', 'multi-transform'], ['revolution', 'fuse'], ['revolution', 'cut'], ['revolution', 'common'], ['revolution', 'rotate'], ['revolution', 'pad'], ['revolution', 'pocket'], ['revolution', 'loft'], ['revolution', 'pipe'], ['revolution', 'revolution'], ['revolution', 'groove'], ['revolution', 'fillet'], ['revolution', 'chamfer'], ['revolution', 'hole'], ['revolution', 'draft'], ['revolution', 'thickness'], ['revolution', 'linear-pattern'], ['revolution', 'polar-pattern'], ['revolution', 'mirrored'], ['revolution', 'multi-transform'], ['groove', 'fuse'], ['groove', 'cut'], ['groove', 'common'], ['groove', 'rotate'], ['groove', 'pad'], ['groove', 'pocket'], ['groove', 'loft'], ['groove', 'pipe'], ['groove', 'revolution'], ['groove', 'groove'], ['groove', 'fillet'], ['groove', 'chamfer'], ['groove', 'hole'], ['groove', 'draft'], ['groove', 'thickness'], ['groove', 'linear-pattern'], ['groove', 'polar-pattern'], ['groove', 'mirrored']]
|
||||
const classifications = []
|
||||
for (const [index, [fromOperation, toOperation]] of orderedPairPrefix.entries()) classifications.push(await classifyPair(fromOperation, toOperation, index))
|
||||
const selectedPairs = process.env.FREECAD_ONLY_PAIR ? orderedPairPrefix.filter(([fromOperation, toOperation]) => `${fromOperation}->${toOperation}` === process.env.FREECAD_ONLY_PAIR) : orderedPairPrefix
|
||||
if (process.env.FREECAD_ONLY_PAIR && selectedPairs.length !== 1) fail(`focused pair ${process.env.FREECAD_ONLY_PAIR} is not in the classified prefix.`)
|
||||
for (const [index, [fromOperation, toOperation]] of selectedPairs.entries()) classifications.push(await classifyPair(fromOperation, toOperation, index))
|
||||
if (process.env.FREECAD_ONLY_PAIR && existsSync(outputPath)) {
|
||||
const previous = JSON.parse(await readFile(outputPath, 'utf8'))
|
||||
const byPair = new Map([...previous.classifications, ...classifications].map((entry) => [entry.pair, entry]))
|
||||
classifications.splice(0, classifications.length, ...orderedPairPrefix.map(([fromOperation, toOperation]) => byPair.get(`${fromOperation}->${toOperation}`)).filter(Boolean))
|
||||
}
|
||||
|
||||
const [artifacts, executorHarness, matrixHarness, resaveHarness] = await Promise.all([
|
||||
Promise.all(artifactNames.map(async (name) => {
|
||||
@@ -401,4 +488,4 @@ const report = {
|
||||
summary: { registeredOperations: 19, orderedPairs: 361, classifiedPairs: classifications.length, accepted: classifications.filter(({ classification }) => classification === 'accepted').length, rejected: classifications.filter(({ classification }) => classification === 'rejected').length, unknown: 361 - classifications.length },
|
||||
}
|
||||
await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`)
|
||||
console.log(JSON.stringify({ status: 'freecad-ordered-operation-pair-classification-generated', pairs: classifications.map(({ pair, classification }) => ({ pair, classification })), nativeBuilderRuns: classifications.length * 4, fcstdPhases: classifications.length * 3, output: 'config/freecad-ordered-operation-pair-classification.json' }, null, 2))
|
||||
console.log(JSON.stringify({ status: 'freecad-ordered-operation-pair-classification-generated', pairs: selectedPairs.map(([fromOperation, toOperation]) => classifications.find(({ pair }) => pair === `${fromOperation}->${toOperation}`)).map(({ pair, classification }) => ({ pair, classification })), nativeBuilderRuns: selectedPairs.length * 4, fcstdPhases: selectedPairs.length * 3, classifiedPairs: classifications.length, output: 'config/freecad-ordered-operation-pair-classification.json' }, null, 2))
|
||||
|
||||
Reference in New Issue
Block a user