From 00ed27b7b886764e8e5265a83dd221e3fa4ae61b Mon Sep 17 00:00:00 2001 From: wangdequan Date: Sun, 16 Aug 2026 01:34:40 -0400 Subject: [PATCH] feat: classify chamfer common pair --- config/freecad-active-work-queue.json | 19 +- ...ordered-operation-pair-classification.json | 237 +++++++++++++++++- ...ecad-active-work-status.generated.zh-CN.md | 8 +- ...-ordered-operation-pair-classification.mjs | 3 +- ...-ordered-operation-pair-classification.mjs | 3 +- 后续工作.txt | 11 + 6 files changed, 262 insertions(+), 19 deletions(-) diff --git a/config/freecad-active-work-queue.json b/config/freecad-active-work-queue.json index 98f98db..20c6fa8 100644 --- a/config/freecad-active-work-queue.json +++ b/config/freecad-active-work-queue.json @@ -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" ], diff --git a/config/freecad-ordered-operation-pair-classification.json b/config/freecad-ordered-operation-pair-classification.json index f5b474d..5f84ac6 100644 --- a/config/freecad-ordered-operation-pair-classification.json +++ b/config/freecad-ordered-operation-pair-classification.json @@ -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 } } diff --git a/docs/freecad-active-work-status.generated.zh-CN.md b/docs/freecad-active-work-status.generated.zh-CN.md index c653452..74bc6ae 100644 --- a/docs/freecad-active-work-status.generated.zh-CN.md +++ b/docs/freecad-active-work-status.generated.zh-CN.md @@ -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 - Property:27/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 | `-` | diff --git a/scripts/check-freecad-ordered-operation-pair-classification.mjs b/scripts/check-freecad-ordered-operation-pair-classification.mjs index 3f76f76..e1ae38a 100644 --- a/scripts/check-freecad-ordered-operation-pair-classification.mjs +++ b/scripts/check-freecad-ordered-operation-pair-classification.mjs @@ -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)) diff --git a/scripts/run-freecad-ordered-operation-pair-classification.mjs b/scripts/run-freecad-ordered-operation-pair-classification.mjs index 0a5203d..866ef90 100644 --- a/scripts/run-freecad-ordered-operation-pair-classification.mjs +++ b/scripts/run-freecad-ordered-operation-pair-classification.mjs @@ -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.`) diff --git a/后续工作.txt b/后续工作.txt index 348faf2..868ebd4 100644 --- a/后续工作.txt +++ b/后续工作.txt @@ -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`,未伪造唯一私有 token,JSON 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` 继续,不在本文手工维护任务名称。