diff --git a/config/freecad-active-work-queue.json b/config/freecad-active-work-queue.json index 3ec7348..98f98db 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-cut", + "nextTask": "TSN-PAIR-chamfer-common", "summary": { "tasks": 1756, - "completed": 337, + "completed": 338, "inProgress": 1, - "pending": 1418 + "pending": 1417 }, "milestones": [ { @@ -4474,17 +4474,20 @@ { "id": "TSN-PAIR-chamfer-cut", "title": "Classify ordered operation pair chamfer->cut", - "status": "in_progress", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->cut", + "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-common", "title": "Classify ordered operation pair chamfer->common", - "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 60486f3..f5b474d 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": 44852, - "sha256": "53c2c0bf200a5c8c5edd2a8f6f1c9816ea8784b671a76d9d1df344efcd531280" + "bytes": 45030, + "sha256": "4a2c54aa5ce03746cb32401ce8ec2c6db008a6e5a805f9fd061c14f9d4ff23ea" }, "matrix": { "path": "scripts/freecad-naming-production-matrix.mjs", @@ -55935,14 +55935,241 @@ "schemaVersion": 1, "status": "pass" } + }, + { + "taskId": "TSN-PAIR-chamfer-cut", + "pair": "chamfer->cut", + "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": "0bf7f1fb6ffe846efe899fa69af12bbf8d95bfcb9c40ed1ea28b89daa3b96c51", + "namingSemanticSha256": "7dea70fa2fe706e79931dd739ed66b4663a362876f48587e59688fb301fe1c2d" + }, + "second": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 31, + "edges": 63, + "vertices": 34, + "volume": 927.0613333, + "area": 604.1774417, + "bounds": [ + -2e-7, + -2e-7, + -2e-7, + 10.0000002, + 10.0000002, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 4, + "ambiguousResults": 12, + "historySha256": "065e5143698c6477697ab38dddeb64dedbb2b35f779015c2b94da5bdf39d0b2d", + "namingEvidenceSha256": "fbd3e2b6c707e2dc43c552ceaeb004f09e4faa46210b8af3187b3b51f758bb33", + "namingSemanticSha256": "8119d7f6bed1f84ad3c688149d03816d4956a60036f78546e2dd5f698b074054" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolSize", + "trajectory": [ + 4, + 3, + 4 + ], + "beforeValue": 4, + "editedValue": 3, + "restoredValue": 4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 31, + "edges": 63, + "vertices": 34, + "volume": 963.9813333, + "area": 589.9431272, + "bounds": [ + -2e-7, + -2e-7, + -2e-7, + 10.0000002, + 10.0000002, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 4, + "ambiguousResults": 12, + "historySha256": "065e5143698c6477697ab38dddeb64dedbb2b35f779015c2b94da5bdf39d0b2d", + "namingEvidenceSha256": "14374ce9ae9e777e9e3f322f37eab826db4c0491a77d893b7242f41e594ff197", + "namingSemanticSha256": "8119d7f6bed1f84ad3c688149d03816d4956a60036f78546e2dd5f698b074054" + }, + "restoredEvidence": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 31, + "edges": 63, + "vertices": 34, + "volume": 927.0613333, + "area": 604.1774417, + "bounds": [ + -2e-7, + -2e-7, + -2e-7, + 10.0000002, + 10.0000002, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 4, + "ambiguousResults": 12, + "historySha256": "065e5143698c6477697ab38dddeb64dedbb2b35f779015c2b94da5bdf39d0b2d", + "namingEvidenceSha256": "28dcc861cb88d2ee7c12bbf5a5c11533db8876ddd6a1b9d331606db0cbcb54a4", + "namingSemanticSha256": "8119d7f6bed1f84ad3c688149d03816d4956a60036f78546e2dd5f698b074054" + } + }, + "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->cut", + "phases": { + "initial": { + "namingEvidenceBytes": 5936, + "namingEvidenceSha256": "fbd3e2b6c707e2dc43c552ceaeb004f09e4faa46210b8af3187b3b51f758bb33", + "pair": "chamfer->cut", + "shape": { + "area": 604.1774417, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 63, + "faces": 31, + "solids": 1, + "valid": true, + "vertices": 34, + "volume": 927.0613333 + } + }, + "reopened": { + "namingEvidenceBytes": 5936, + "namingEvidenceSha256": "fbd3e2b6c707e2dc43c552ceaeb004f09e4faa46210b8af3187b3b51f758bb33", + "pair": "chamfer->cut", + "shape": { + "area": 604.1774417, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 63, + "faces": 31, + "solids": 1, + "valid": true, + "vertices": 34, + "volume": 927.0613333 + } + }, + "resaved": { + "namingEvidenceBytes": 5936, + "namingEvidenceSha256": "fbd3e2b6c707e2dc43c552ceaeb004f09e4faa46210b8af3187b3b51f758bb33", + "pair": "chamfer->cut", + "shape": { + "area": 604.1774417, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 63, + "faces": 31, + "solids": 1, + "valid": true, + "vertices": 34, + "volume": 927.0613333 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } } ], "summary": { "registeredOperations": 19, "orderedPairs": 361, - "classifiedPairs": 207, - "accepted": 155, + "classifiedPairs": 208, + "accepted": 156, "rejected": 52, - "unknown": 154 + "unknown": 153 } } diff --git a/config/release-artifacts.json b/config/release-artifacts.json index b031b56..fc27064 100644 --- a/config/release-artifacts.json +++ b/config/release-artifacts.json @@ -390,7 +390,7 @@ { "path": "sw.js", "bytes": 1390, - "sha256": "8b0477955514535bb11cef3733135b67422cc8c085b4331c3b9cb1a1adc9d852" + "sha256": "98ec667a774f8370ed654e457b86d4943b2f1eb89e228bd4e7e652b31a51b982" }, { "path": "vendor/camotics/camotics-sweep.wasm", @@ -412,7 +412,7 @@ "status": "signed", "algorithm": "Ed25519", "keyId": "bitbybit-local-release-2026", - "payloadSha256": "ad5f25aeb7e1382b3172d9919357a9831ac198841e54304a6789665cd21cda31", - "signature": "c8xaS8E7BOThrQKOK9WlCLpMazuqlBZ6eMKbCTt+tzeC0b4TyEEaiVvjelUtFDjo5PK0fVYPeYISrS2895LTDA==" + "payloadSha256": "5172b35d4d194483ac1934a1653259b1c7f5bb78c5ab4a68f7e5033cf2a22b86", + "signature": "FoaYFhliT+/njf8hXECKj5IoCeHPj1MnpbTBIw/FxzYpfyrgQ01nuPkwslM4okUk3d97cncjaXnEkDA7lZBtDw==" } } diff --git a/docs/freecad-active-work-status.generated.zh-CN.md b/docs/freecad-active-work-status.generated.zh-CN.md index 252d551..c653452 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-cut` -- 微任务:1756 total / 337 completed / 1 in_progress / 1418 pending -- 有序操作对:211/361 classified / 150 unknown +- 唯一活动任务:`TSN-PAIR-chamfer-common` +- 微任务:1756 total / 338 completed / 1 in_progress / 1417 pending +- 有序操作对:212/361 classified / 149 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 | 211 | 1 | 149 | `TSN-PAIR-chamfer-cut` | +| `TSN-ORDERED-PAIRS` | 361 | 212 | 1 | 148 | `TSN-PAIR-chamfer-common` | | `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 5f3e123..3f76f76 100644 --- a/scripts/check-freecad-ordered-operation-pair-classification.mjs +++ b/scripts/check-freecad-ordered-operation-pair-classification.mjs @@ -225,6 +225,7 @@ const expectedPairs = [ { pair: 'fillet->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeFillet', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] }, { 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] }, ] 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()) { @@ -286,6 +287,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: 207, accepted: 155, rejected: 52, unknown: 154 } +const expectedSummary = { registeredOperations: 19, orderedPairs: 361, classifiedPairs: 208, accepted: 156, rejected: 52, unknown: 153 } 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 8ba8d28..0a5203d 100644 --- a/scripts/run-freecad-ordered-operation-pair-classification.mjs +++ b/scripts/run-freecad-ordered-operation-pair-classification.mjs @@ -126,6 +126,7 @@ const pairSpecOverrides = { 'fillet->draft': { ...operationSpecs.draft, decision: 'rejected', rejectionAuthority: 'occt-builder' }, '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 }, } 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 }) => { @@ -467,7 +468,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']) +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']) 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 aeb432b..348faf2 100644 --- a/后续工作.txt +++ b/后续工作.txt @@ -44,6 +44,101 @@ node -e "const q=require('./config/freecad-active-work-queue.json'); console.log 详细拆分和依赖关系只在机器队列与执行计划中维护。 +## 3A. 全功能对标拆分总表(静态路线图) + +本节只定义长期范围、阶段边界和可重复的验收粒度,不记录实时完成数、活动任务名或下一任务名。每个阶段由机器队列展开为“一个原生 artifact、一个聚焦检查器、一个明确退出条件”的微任务;队列推进时不得跨越阶段依赖。 + +### 3A.1 统一工作单元 + +每一个功能、对象、属性、命令、格式和 UI 状态都按下列最小单元拆解: + +| 编号 | 最小任务 | 必须产出 | 单项退出条件 | +| --- | --- | --- | --- | +| U1 | 原生清册 | TypeId/命令名、输入、默认值、适用性、失败前置 | 清册可机器读取,未知项显式登记 | +| U2 | 名义成功 | FreeCAD/OCCT Shape、对象集、属性、诊断、拓扑摘要 | 名义输入重复运行结果稳定 | +| U3 | 边界成功 | 最小值、最大值、空集合、单元素、多元素和单位边界 | 每个边界都有接受或拒绝证据 | +| U4 | 原生拒绝 | 失败阶段、异常/诊断、空或无效 Shape、对象集 | 不以 Web fallback 替代原生拒绝 | +| U5 | 取消与中断 | cancel、abort、超时、Worker 终止时的资源和状态 | 文档、事务、Worker、OPFS 无污染 | +| U6 | 参数变异 | 一次只改一个参数的 before/edit/restore 轨迹 | 编辑改变的字段可解释,恢复逐字段一致 | +| U7 | 历史与命名 | Generated/Modified/Deleted、ElementMap2、MappedNameRef、hash | 无私有 token、无错误绑定、歧义保持歧义 | +| U8 | 持久化 | save、reopen、resave、版本迁移和资源引用 | Shape、属性、命名、对象图无未解释漂移 | +| U9 | Facade | 生产 API、类型校验、错误映射、能力级别 | UI 不直连内核,禁止隐藏 fallback | +| U10 | 浏览器回放 | Worker、OPFS、UI、选择、进度、释放证据 | 真实 Chrome 流程与原生合同一致 | +| U11 | 回归封存 | focused check、变更摘要、哈希、证据索引 | 证据可独立复跑,队列只推进一项 | + +### 3A.2 阶段与微里程碑 + +| 阶段 | 目标 | 细分里程碑(每项可再拆为 U1-U11) | 阶段退出门槛 | +| --- | --- | --- | --- | +| P0 基线与治理 | 固定 FreeCAD/OCCT、证据格式和能力声明 | P0.1 版本/提交锁定;P0.2 TypeId/命令/格式清册;P0.3 artifact 哈希;P0.4 依赖图;P0.5 known-gap 账本;P0.6 单活动任务门禁 | 基线、生成器、检查器和 exact 声明一致,禁止未登记能力 | +| P1 原生观察层 | 建立所有差异的可重复 oracle | P1.1 空文档状态;P1.2 单对象状态;P1.3 选择/子形状态;P1.4 属性 editor 状态;P1.5 事务状态;P1.6 失败/取消状态;P1.7 GUI 命令状态;P1.8 资源与版本信息 | 原生 probe 覆盖清册;未知状态只能进入 pending | +| P2 内核几何 | 对齐 OCCT builder 和拓扑历史 | P2.1 基本几何;P2.2 布尔;P2.3 变换/阵列;P2.4 草图与约束几何;P2.5 修复/偏置/抽壳;P2.6 曲面/网格;P2.7 有效性和容差;P2.8 资源释放 | 每个 builder 有成功、边界、失败、恢复和 history 证据 | +| P3 文档与历史 | 对齐 Document/DAG/事务/扩展语义 | P3.1 对象生命周期;P3.2 属性类型和 editor;P3.3 Link/LinkSub;P3.4 recompute 顺序;P3.5 dependency cycle;P3.6 partial failure;P3.7 observer 顺序;P3.8 undo/redo/abort;P3.9 Extension/FeaturePython;P3.10 多文档/MDI | 对象图、事务事件和失败恢复在 save/reopen 后仍可解释 | +| P4 核心建模工作台 | 对齐 Sketcher、Part、PartDesign | P4.1 草图几何;P4.2 约束求解;P4.3 草图编辑器;P4.4 Part 原语;P4.5 布尔/修复/检查;P4.6 PartDesign Body/Tip;P4.7 加料/减料;P4.8 旋转/扫掠/放样;P4.9 圆角/倒角/孔/拔模/厚度;P4.10 阵列/镜像/多变换;P4.11 跨特征 mutation;P4.12 全有序操作对 | 每项都有 A-I 证据,命名和 FCStd 证据达到 exact gate | +| P5 文件与数据交换 | 对齐原生格式、导入导出和代理边界 | P5.1 FCStd 对象/属性/资源;P5.2 BREP;P5.3 STEP;P5.4 IGES;P5.5 STL/OBJ/PLY;P5.6 DXF/SVG/PDF;P5.7 IFC;P5.8 CSV/G-code;P5.9 JT/IDF/OpenSCAD;P5.10 未知对象保留;P5.11 安全解析/大小限制 | 双向 round-trip、损坏/未知输入、编码和资源引用均有明确 exact/compatible/excluded 结果 | +| P6 GUI 与交互 | 对齐 FreeCAD 桌面状态和浏览器交互 | P6.1 Shell/菜单/工具栏;P6.2 Workbench 切换;P6.3 Tree/Dock/MDI;P6.4 Task panel;P6.5 Property editor;P6.6 对话框验证;P6.7 3D 选择/预选;P6.8 快捷键/焦点;P6.9 报告/状态/进度;P6.10 cancel/long task;P6.11 截图/可访问性树;P6.12 mobile/responsive | 每个工作台的空文档、成功、失败、取消、恢复流程可真实浏览器回放 | +| P7 工程与专业工作台 | 对齐 Draft、TechDraw、Spreadsheet、Plot、Assembly、BIM、Surface、Mesh、Material | P7.1 Draft snaps/working plane;P7.2 TechDraw 页面/视图/标注;P7.3 Spreadsheet 公式/别名/样式;P7.4 Plot 数据/坐标轴/导出;P7.5 Assembly joints/solver;P7.6 BIM/IFC/数量;P7.7 Surface trim/sew/repair;P7.8 Mesh 修复/转换;P7.9 Material 继承/外观;P7.10 跨工作台引用 | 每个专业对象具有对象图、交互、持久化、导出和失败证据 | +| P8 分析、制造与扩展 | 对齐 FEM、CAM、Robot、Inspection、Points、ReverseEngineering、脚本和 addon | P8.1 FEM 对象/网格/求解/结果;P8.2 CAM Path/任务/后处理;P8.3 仿真和机床 profile;P8.4 Robot 运动学/碰撞/导出;P8.5 点云/重建;P8.6 测量/偏差/报告;P8.7 Python API/macro 沙箱;P8.8 addon 签名/权限/回滚;P8.9 代理模块显式排除 | 生产授权与浏览器能力分离;不支持项可审计、可解释、不会伪装支持 | +| P9 平台质量 | 完成跨环境和长稳验证 | P9.1 Chrome/Firefox/Safari;P9.2 Windows/Linux/macOS;P9.3 GPU/软件渲染;P9.4 desktop/tablet/mobile;P9.5 locale/单位/时区;P9.6 屏幕阅读器/键盘;P9.7 性能/内存/Worker;P9.8 fuzz/stress/长会话;P9.9 崩溃恢复/迁移;P9.10 供应链/安全 | 所有支持矩阵无未知差异,预算、漏洞、泄漏、错误绑定均为零 | +| P10 发布与 exact promotion | 形成可签名、可复核的发布物 | P10.1 证据索引;P10.2 生成物重建;P10.3 SBOM/依赖审计;P10.4 签名/验签;P10.5 release closure;P10.6 回滚演练;P10.7 exact capability matrix;P10.8 版本公告 | 所有 exact 任务闭合,必要零指标满足,签名产物和回滚包可复现 | + +### 3A.3 每个阶段内的执行顺序 + +阶段内固定按以下细粒度顺序执行,任何一步失败都只登记当前微任务,不跳到下一步: + +1. 清册:确认 TypeId、命令入口、默认参数、输入数量、依赖和适用性。 +2. 名义态:用真实 FreeCAD/OCCT builder 生成结果,记录 Shape、拓扑、属性、诊断和对象集。 +3. 边界态:逐个执行最小值、最大值、空、重复、越界和单位转换;原生拒绝也要记录。 +4. 失败态:记录失败阶段、异常类型、精确文本、状态标志、空/无效 Shape 和对象污染。 +5. 变异态:只修改一个参数,执行 before/edit/restore;检查几何、历史、命名和文档版本。 +6. 事务态:覆盖 commit、abort、undo、redo、stale、cycle、cancel、timeout 和 Worker 终止。 +7. 持久化态:执行 save/reopen/resave,校验对象图、属性、资源、Shape、命名和 hash。 +8. Facade 态:通过生产 Facade 重放同一输入,确认错误映射、能力级别和权限边界。 +9. 浏览器态:真实 Worker/OPFS/Chrome 回放,检查 UI、选择、进度、释放和离线行为。 +10. 封存态:运行 focused check、相关模块 gate、`git diff --check`,生成队列和状态页,确认只推进一个任务。 + +### 3A.4 里程碑完成判定 + +- `完成`:U1-U11 全部有机器证据,检查器通过,依赖项已完成,队列生成器将该项标记为 completed。 +- `兼容`:核心工作流可用,但至少一个 exact 证据类缺失;必须保留缺口、范围和下一步,不得提升 exact 声明。 +- `代理`:仅保留数据/显示/导入等有限语义;必须标明不支持的原生行为和安全边界。 +- `拒绝`:原生明确拒绝或 no-op;记录拒绝权威、诊断、回滚和持久化,不视为实现缺陷。 +- `阻断`:证据缺失、结果不稳定、存在漂移或安全问题;任务保持 in_progress/pending,禁止用文档结论强行关闭。 + +### 3A.5 依赖与并行规则 + +- P0/P1 是所有阶段的前置;没有基线和 oracle,不接受实现“已完成”。 +- P2 的几何/历史证据先于 P3 文档语义;P3 先于 P4-P8 的生产工作台。 +- P5 格式往返依赖 P3 对象图和 P4/P7/P8 的真实对象;未知对象只能进入显式保留或排除路径。 +- P6 浏览器 UI 依赖 Facade 合同,但 UI 回归不能反向修改原生合同。 +- P9 只在 P4-P8 的工作流有稳定基线后扩大矩阵;发现漂移时回退到对应功能微任务。 +- P10 是最终门禁,不能以“主要功能可用”替代任一 exact 依赖。 +- 机器队列维持 `maxInProgress=1`;需要并行调查时也必须先落成独立 artifact,不能并行修改同一证据账本。 + +### 3A.6 每项任务的最小记录模板 + +```text +范围:一个 TypeId/命令/格式/交互状态或一个有序操作对 +输入:原生版本、提交、参数、单位、对象图、资源哈希 +原生证据:名义、边界、失败、取消、变异、历史、命名 +浏览器证据:Facade、Worker、OPFS、UI、选择、进度、释放 +持久化证据:save/reopen/resave、迁移、未知属性/资源 +判定:accepted / rejected / no-op / compatible / proxy / blocked +退出条件:可执行检查命令、预期摘要、零指标和回滚要求 +变更边界:只允许修改该任务的实现、oracle、检查器和报告 +``` + +## 3B. 当前阶段的持续推进规则 + +当前项目仍处于 TSN 命名/历史与有序操作对闭合阶段,之后才按依赖进入 Property、Document、格式、GUI、专业工作台和平台质量阶段。每次完成一个微任务后必须: + +1. 从 `config/freecad-active-work-queue.json` 读取新的 `nextTask`,不得从本文、聊天记录或手工列表猜测。 +2. 为刚完成任务追加原生、浏览器、持久化和回滚证据;缺一项就保持当前任务未完成。 +3. 重新生成队列和状态页,检查只有一个 `in_progress`,并核对连续前缀没有跳号。 +4. 按任务风险运行 focused gate;达到发布点才运行完整 `./npmw run verify`。 +5. 提交前检查 `git diff --check`、JSON/脚本语法、未跟踪文件和生成物哈希;提交后推送云仓库并记录提交。 +6. 若原生拒绝、no-op 或代理边界是正确结果,完整保留该分类,不为了增加完成数而改变判定。 + ## 4. 单轮执行流程 1. 读取唯一 `nextTask`,确认依赖、输入 artifact 和退出条件。 @@ -2101,4 +2196,15 @@ git diff --check - `8 -> 7 -> 8` 工具 X 偏移轨迹使体积在 `1066.6586667 -> 1041.7386667 -> 1066.6586667` 间变化,X 上界从 13 变为 12 后恢复,并精确恢复名义摘要、history 与语义 naming。 - 上游 Chamfer naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定,focused gate 已锁定相交融合、变异、恢复和持久化证据。 +### `TSN-PAIR-chamfer-cut` + +`chamfer->cut` 已完成原生接受分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,对 10x10x10 Box 的全部边执行倒角,生成有效 1 Solid、26 Face、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 下游使用真实 `BRepAlgoAPI_Cut` 双输入 builder;名义结果为有效 1 Solid、31 Face、体积 `927.0613333`、面积 `604.1774417` 和 42 条原生 history。 +- `4 -> 3 -> 4` 工具尺寸轨迹使体积在 `927.0613333 -> 963.9813333 -> 927.0613333` 间变化,编辑态面积同步变化;恢复态的几何摘要、history hash 和语义 naming 精确回到名义态。 +- 上游 Chamfer naming evidence 向下游传播;下游结果因对称拓扑保持 `ambiguous`,未伪造唯一私有 token,JSON round-trip 稳定。 +- 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` 为唯一来源。 + 后续任务必须从机器队列的最新 `nextTask` 继续,不在本文手工维护任务名称。