feat: classify chamfer common pair
Some checks failed
real-verification / chrome (push) Has been cancelled
real-verification / freecad-oracle (push) Has been cancelled
real-verification / wasm (push) Has been cancelled

This commit is contained in:
2026-08-16 01:34:40 -04:00
parent 27db1a8f93
commit 00ed27b7b8
6 changed files with 262 additions and 19 deletions

View File

@@ -24,12 +24,12 @@
],
"followUpProgress": "config/freecad-follow-up-task-progress.json"
},
"nextTask": "TSN-PAIR-chamfer-common",
"nextTask": "TSN-PAIR-chamfer-rotate",
"summary": {
"tasks": 1756,
"completed": 338,
"completed": 339,
"inProgress": 1,
"pending": 1417
"pending": 1416
},
"milestones": [
{
@@ -4487,17 +4487,20 @@
{
"id": "TSN-PAIR-chamfer-common",
"title": "Classify ordered operation pair chamfer->common",
"status": "in_progress",
"dependencies": [
"TSN-PROD-DRIFT-001"
],
"status": "completed",
"dependencies": [],
"pair": "chamfer->common",
"classification": "accepted",
"evidence": [
"config/freecad-ordered-operation-pair-classification.json",
"native-builders-mutation-naming-and-fcstd-resave-pass"
],
"exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence"
},
{
"id": "TSN-PAIR-chamfer-rotate",
"title": "Classify ordered operation pair chamfer->rotate",
"status": "pending",
"status": "in_progress",
"dependencies": [
"TSN-PROD-DRIFT-001"
],

View File

@@ -10,8 +10,8 @@
"nativeProbe": {
"executor": {
"path": "scripts/run-freecad-ordered-operation-pair-classification.mjs",
"bytes": 45030,
"sha256": "4a2c54aa5ce03746cb32401ce8ec2c6db008a6e5a805f9fd061c14f9d4ff23ea"
"bytes": 45217,
"sha256": "f89493cbe219c3dc91ef7fa360dc393fdb6bbe9ecbbc40a26199a63462f02790"
},
"matrix": {
"path": "scripts/freecad-naming-production-matrix.mjs",
@@ -56162,14 +56162,241 @@
"schemaVersion": 1,
"status": "pass"
}
},
{
"taskId": "TSN-PAIR-chamfer-common",
"pair": "chamfer->common",
"classification": "accepted",
"reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass",
"nativeDecision": "accepted",
"first": {
"operation": "chamfer",
"builder": "BRepFilletAPI_MakeChamfer",
"inputCount": 1,
"historyProvider": "occt-native",
"namingStatus": "ambiguous",
"summary": {
"isValid": true,
"solids": 1,
"faces": 26,
"edges": 48,
"vertices": 24,
"volume": 990.7413333,
"area": 571.4001834,
"bounds": [
-1e-7,
-1e-7,
-1e-7,
10.0000001,
10.0000001,
10.0000001
]
},
"historyRecords": 150,
"selectedRecords": 6,
"ambiguousResults": 20,
"historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62",
"namingEvidenceSha256": "f51c213ccdbac861df83ffc32859dafcae17fe2e5802c9d71323b5b81c833111",
"namingSemanticSha256": "567b58f5bceb467101d14726299da3fb5857a8dbabc93b02af503a1be55212b7"
},
"second": {
"operation": "common",
"builder": "BRepAlgoAPI_Common",
"inputCount": 2,
"historyProvider": "occt-native",
"namingStatus": "ambiguous",
"summary": {
"isValid": true,
"solids": 1,
"faces": 10,
"edges": 21,
"vertices": 13,
"volume": 74.0026667,
"area": 106.6536521,
"bounds": [
6.9999999,
-2e-7,
-2e-7,
10.0000001,
5.0000001,
5.0000001
]
},
"historyRecords": 339,
"selectedRecords": 4,
"ambiguousResults": 16,
"historySha256": "a0c850e7ab088a27448e329782cce18595daeafa9ca2adf1878a00badd7d43f4",
"namingEvidenceSha256": "ec6b267032b17485820f6e29079fac4ebe194dccee66d55e597bc3562ef4dbfd",
"namingSemanticSha256": "2384ec15cdfe80170f8c01c8d0d133720172dc1b479c9d16b6bdd38055b1d2e9"
},
"mutation": {
"scope": "second-operation-only",
"parameter": "toolOffsetX",
"trajectory": [
7,
6,
7
],
"beforeValue": 7,
"editedValue": 6,
"restoredValue": 7,
"changed": true,
"restoredExactly": true,
"editedEvidence": {
"operation": "common",
"builder": "BRepAlgoAPI_Common",
"inputCount": 2,
"historyProvider": "occt-native",
"namingStatus": "ambiguous",
"summary": {
"isValid": true,
"solids": 1,
"faces": 10,
"edges": 21,
"vertices": 13,
"volume": 98.9226667,
"area": 126.4193375,
"bounds": [
5.9999999,
-2e-7,
-2e-7,
10.0000001,
5.0000001,
5.0000001
]
},
"historyRecords": 339,
"selectedRecords": 4,
"ambiguousResults": 16,
"historySha256": "a0c850e7ab088a27448e329782cce18595daeafa9ca2adf1878a00badd7d43f4",
"namingEvidenceSha256": "63991e706e26259b560956e0f0083aff856e6188b45ef372d9928e237253f117",
"namingSemanticSha256": "2384ec15cdfe80170f8c01c8d0d133720172dc1b479c9d16b6bdd38055b1d2e9"
},
"restoredEvidence": {
"operation": "common",
"builder": "BRepAlgoAPI_Common",
"inputCount": 2,
"historyProvider": "occt-native",
"namingStatus": "ambiguous",
"summary": {
"isValid": true,
"solids": 1,
"faces": 10,
"edges": 21,
"vertices": 13,
"volume": 74.0026667,
"area": 106.6536521,
"bounds": [
6.9999999,
-2e-7,
-2e-7,
10.0000001,
5.0000001,
5.0000001
]
},
"historyRecords": 339,
"selectedRecords": 4,
"ambiguousResults": 16,
"historySha256": "a0c850e7ab088a27448e329782cce18595daeafa9ca2adf1878a00badd7d43f4",
"namingEvidenceSha256": "2f9a60a57c19350e3bc8873ac6ebd113c0a894fc6cc7bc4105b6c6b3984dc018",
"namingSemanticSha256": "2384ec15cdfe80170f8c01c8d0d133720172dc1b479c9d16b6bdd38055b1d2e9"
}
},
"naming": {
"upstreamEvidenceRestored": true,
"downstreamEvidence": true,
"jsonRoundtripStable": true
},
"persistence": {
"baselineId": "freecad-1.1.1-ordered-operation-pair-resave",
"checks": {
"namingEvidenceStable": true,
"shapeStable": true
},
"decision": "accepted",
"freecadVersion": "1.1.1",
"gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d",
"pair": "chamfer->common",
"phases": {
"initial": {
"namingEvidenceBytes": 6702,
"namingEvidenceSha256": "ec6b267032b17485820f6e29079fac4ebe194dccee66d55e597bc3562ef4dbfd",
"pair": "chamfer->common",
"shape": {
"area": 106.6536521,
"bounds": [
7,
0,
0,
10,
5,
5
],
"edges": 21,
"faces": 10,
"solids": 1,
"valid": true,
"vertices": 13,
"volume": 74.0026667
}
},
"reopened": {
"namingEvidenceBytes": 6702,
"namingEvidenceSha256": "ec6b267032b17485820f6e29079fac4ebe194dccee66d55e597bc3562ef4dbfd",
"pair": "chamfer->common",
"shape": {
"area": 106.6536521,
"bounds": [
7,
0,
0,
10,
5,
5
],
"edges": 21,
"faces": 10,
"solids": 1,
"valid": true,
"vertices": 13,
"volume": 74.0026667
}
},
"resaved": {
"namingEvidenceBytes": 6702,
"namingEvidenceSha256": "ec6b267032b17485820f6e29079fac4ebe194dccee66d55e597bc3562ef4dbfd",
"pair": "chamfer->common",
"shape": {
"area": 106.6536521,
"bounds": [
7,
0,
0,
10,
5,
5
],
"edges": 21,
"faces": 10,
"solids": 1,
"valid": true,
"vertices": 13,
"volume": 74.0026667
}
}
},
"schemaVersion": 1,
"status": "pass"
}
}
],
"summary": {
"registeredOperations": 19,
"orderedPairs": 361,
"classifiedPairs": 208,
"accepted": 156,
"classifiedPairs": 209,
"accepted": 157,
"rejected": 52,
"unknown": 153
"unknown": 152
}
}

View File

@@ -3,9 +3,9 @@
生成日期2026-08-15。基线FreeCAD 1.1.1 / `0108fd4b4850cc46e625b60e53cea7a7bbe69f8d`
- 唯一活动任务:`TSN-PAIR-chamfer-common`
- 微任务1756 total / 338 completed / 1 in_progress / 1417 pending
- 有序操作对212/361 classified / 149 unknown
- 唯一活动任务:`TSN-PAIR-chamfer-rotate`
- 微任务1756 total / 339 completed / 1 in_progress / 1416 pending
- 有序操作对213/361 classified / 148 unknown
- Property27/85 native types / 58 opaque types
- exact 任务5/52 completed
- 模块能力0 exact / 26 compatible / 5 proxy / 3 development
@@ -15,7 +15,7 @@
| `ORA-GUI-BASELINE` | 106 | 106 | 0 | 0 | `-` |
| `ORA-GUI-WORKFLOWS` | 7 | 7 | 0 | 0 | `-` |
| `TSN-RECOVERY-DRIFT` | 13 | 13 | 0 | 0 | `-` |
| `TSN-ORDERED-PAIRS` | 361 | 212 | 1 | 148 | `TSN-PAIR-chamfer-common` |
| `TSN-ORDERED-PAIRS` | 361 | 213 | 1 | 147 | `TSN-PAIR-chamfer-rotate` |
| `PROPERTY-CODECS` | 522 | 0 | 0 | 522 | `-` |
| `DOCUMENT-SEMANTICS` | 90 | 0 | 0 | 90 | `-` |
| `CORE-MODELING` | 171 | 0 | 0 | 171 | `-` |

View File

@@ -226,6 +226,7 @@ const expectedPairs = [
{ pair: 'fillet->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeFillet', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] },
{ pair: 'chamfer->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [8, 7, 8] },
{ pair: 'chamfer->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] },
{ pair: 'chamfer->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [7, 6, 7] },
]
if (report.nativeProbe?.artifacts?.length !== 3 || report.classifications?.length !== expectedPairs.length) fail('native artifacts or classification prefix is incomplete.')
for (const [index, entry] of report.classifications.entries()) {
@@ -287,6 +288,6 @@ for (const [index, entry] of report.classifications.entries()) {
const phases = entry.persistence.phases
if (JSON.stringify(phases?.initial) !== JSON.stringify(phases?.reopened) || JSON.stringify(phases?.initial) !== JSON.stringify(phases?.resaved) || phases.initial.namingEvidenceSha256 !== entry.second.namingEvidenceSha256) fail(`${expected.pair} FCStd phases changed Shape or naming evidence.`)
}
const expectedSummary = { registeredOperations: 19, orderedPairs: 361, classifiedPairs: 208, accepted: 156, rejected: 52, unknown: 153 }
const expectedSummary = { registeredOperations: 19, orderedPairs: 361, classifiedPairs: 209, accepted: 157, rejected: 52, unknown: 152 }
if (JSON.stringify(report.summary) !== JSON.stringify(expectedSummary)) fail('summary is inconsistent.')
console.log(JSON.stringify({ status: 'freecad-ordered-operation-pair-classification-pass', completedTasks: report.classifications.map(({ taskId }) => taskId), pairs: report.classifications.map(({ pair, classification }) => ({ pair, classification })), nativeBuilderRuns: report.classifications.length * 4, fcstdPhases: report.classifications.length * 3, remainingPairs: report.summary.unknown }, null, 2))

View File

@@ -127,6 +127,7 @@ const pairSpecOverrides = {
'fillet->thickness': { ...operationSpecs.thickness, decision: 'rejected', rejectionAuthority: 'occt-no-op', kernelOutcome: 'no-op' },
'chamfer->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 8 }, edited: { toolSize: 5, toolOffset: 7 }, beforeValue: 8, editedValue: 7 },
'chamfer->cut': { ...operationSpecs.cut, nominal: { toolSize: 4, toolOffset: 2 }, edited: { toolSize: 3, toolOffset: 2 }, beforeValue: 4, editedValue: 3 },
'chamfer->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 },
}
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 }) => {
@@ -468,7 +469,7 @@ 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'], ['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']]
orderedPairPrefix.push(['groove', 'multi-transform'], ['fillet', 'fuse'], ['fillet', 'cut'], ['fillet', 'common'], ['fillet', 'rotate'], ['fillet', 'pad'], ['fillet', 'pocket'], ['fillet', 'loft'], ['fillet', 'pipe'], ['fillet', 'revolution'], ['fillet', 'groove'], ['fillet', 'fillet'], ['fillet', 'chamfer'], ['fillet', 'hole'], ['fillet', 'draft'], ['fillet', 'thickness'], ['fillet', 'linear-pattern'], ['fillet', 'polar-pattern'], ['fillet', 'multi-transform'], ['chamfer', 'fuse'], ['chamfer', 'cut'])
orderedPairPrefix.push(['groove', 'multi-transform'], ['fillet', 'fuse'], ['fillet', 'cut'], ['fillet', 'common'], ['fillet', 'rotate'], ['fillet', 'pad'], ['fillet', 'pocket'], ['fillet', 'loft'], ['fillet', 'pipe'], ['fillet', 'revolution'], ['fillet', 'groove'], ['fillet', 'fillet'], ['fillet', 'chamfer'], ['fillet', 'hole'], ['fillet', 'draft'], ['fillet', 'thickness'], ['fillet', 'linear-pattern'], ['fillet', 'polar-pattern'], ['fillet', 'multi-transform'], ['chamfer', 'fuse'], ['chamfer', 'cut'], ['chamfer', 'common'])
const classifications = []
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.`)

View File

@@ -2207,4 +2207,15 @@ git diff --check
- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持有效 1 Solid、31 Face、63 Edge、34 Vertex、体积 `927.0613333`、面积 `604.1774417` 及 naming evidence hash `fbd3e2b6...` 一致focused ordered-pair gate 已通过。
- 机器队列已自动前移一项;新的活动任务仍以 `config/freecad-active-work-queue.json.nextTask` 为唯一来源。
### `TSN-PAIR-chamfer-common`
`chamfer->common` 已完成原生接受分类:
- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder对 10x10x10 Box 的全部边执行倒角,生成有效 1 Solid、26 Face、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。
- 下游使用真实 `BRepAlgoAPI_Common` 双输入 builder以相交工具对 Chamfer 结果求交;名义结果为有效 1 Solid、10 Face、21 Edge、13 Vertex、体积 `74.0026667`、面积 `106.6536521` 和 339 条原生 history。
- `7 -> 6 -> 7` 工具 X 偏移轨迹使体积在 `74.0026667 -> 98.9226667 -> 74.0026667` 间变化,面积和 X 下界同步变化恢复态的几何摘要、history hash 和语义 naming 精确回到名义态。
- 上游 Chamfer naming evidence 向下游传播;下游对称拓扑保持 `ambiguous`,未伪造唯一私有 tokenJSON round-trip 稳定。
- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持有效 1 Solid、10 Face、21 Edge、13 Vertex、体积 `74.0026667`、面积 `106.6536521` 及 naming evidence hash `ec6b2670...` 一致focused ordered-pair gate 已通过。
- 机器队列已自动前移一项;新的活动任务仍以 `config/freecad-active-work-queue.json.nextTask` 为唯一来源。
后续任务必须从机器队列的最新 `nextTask` 继续,不在本文手工维护任务名称。