feat: extend ordered pair evidence through groove
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@
|
|||||||
"wrong-document-root": 77
|
"wrong-document-root": 77
|
||||||
},
|
},
|
||||||
"timing": {
|
"timing": {
|
||||||
"p95Ms": 0.179,
|
"p95Ms": 0.131,
|
||||||
"maxMs": 3.391
|
"maxMs": 2.695
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
"zero-revolution-axis": 67
|
"zero-revolution-axis": 67
|
||||||
},
|
},
|
||||||
"timing": {
|
"timing": {
|
||||||
"p95Ms": 0.023,
|
"p95Ms": 0.025,
|
||||||
"maxMs": 1.521
|
"maxMs": 1.112
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"invalid": 800
|
"invalid": 800
|
||||||
},
|
},
|
||||||
"timing": {
|
"timing": {
|
||||||
"p95Ms": 0.035,
|
"p95Ms": 0.033,
|
||||||
"maxMs": 0.893
|
"maxMs": 0.795
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -390,7 +390,7 @@
|
|||||||
{
|
{
|
||||||
"path": "sw.js",
|
"path": "sw.js",
|
||||||
"bytes": 1390,
|
"bytes": 1390,
|
||||||
"sha256": "98ec667a774f8370ed654e457b86d4943b2f1eb89e228bd4e7e652b31a51b982"
|
"sha256": "dfe8893e68cda6991ca64b5f5eaa19097c5b6d8f4bdc13f2423328950671a5be"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "vendor/camotics/camotics-sweep.wasm",
|
"path": "vendor/camotics/camotics-sweep.wasm",
|
||||||
@@ -412,7 +412,7 @@
|
|||||||
"status": "signed",
|
"status": "signed",
|
||||||
"algorithm": "Ed25519",
|
"algorithm": "Ed25519",
|
||||||
"keyId": "bitbybit-local-release-2026",
|
"keyId": "bitbybit-local-release-2026",
|
||||||
"payloadSha256": "5172b35d4d194483ac1934a1653259b1c7f5bb78c5ab4a68f7e5033cf2a22b86",
|
"payloadSha256": "e6d83894b72503eed170bec685d761d868784e28fbc5a221d78c0b270a472b37",
|
||||||
"signature": "FoaYFhliT+/njf8hXECKj5IoCeHPj1MnpbTBIw/FxzYpfyrgQ01nuPkwslM4okUk3d97cncjaXnEkDA7lZBtDw=="
|
"signature": "FZ+gouN7G/kpiInw2zMQ5FBLXPJzurcdHv3lk4NThmtPGe6NXoe8KkIngxO8vbRba0E2e1jwoSgbv2HfvY5xAw=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
生成日期:2026-08-15。基线:FreeCAD 1.1.1 / `0108fd4b4850cc46e625b60e53cea7a7bbe69f8d`。
|
生成日期:2026-08-15。基线:FreeCAD 1.1.1 / `0108fd4b4850cc46e625b60e53cea7a7bbe69f8d`。
|
||||||
|
|
||||||
- 唯一活动任务:`TSN-PAIR-pocket-fuse`
|
- 唯一活动任务:`TSN-PAIR-groove-multi-transform`
|
||||||
- 微任务:1756 total / 223 completed / 1 in_progress / 1532 pending
|
- 微任务:1756 total / 317 completed / 1 in_progress / 1438 pending
|
||||||
- 有序操作对:97/361 classified / 264 unknown
|
- 有序操作对:191/361 classified / 170 unknown
|
||||||
- Property:27/85 native types / 58 opaque types
|
- Property:27/85 native types / 58 opaque types
|
||||||
- exact 任务:5/52 completed
|
- exact 任务:5/52 completed
|
||||||
- 模块能力:0 exact / 26 compatible / 5 proxy / 3 development
|
- 模块能力:0 exact / 26 compatible / 5 proxy / 3 development
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
| `ORA-GUI-BASELINE` | 106 | 106 | 0 | 0 | `-` |
|
| `ORA-GUI-BASELINE` | 106 | 106 | 0 | 0 | `-` |
|
||||||
| `ORA-GUI-WORKFLOWS` | 7 | 7 | 0 | 0 | `-` |
|
| `ORA-GUI-WORKFLOWS` | 7 | 7 | 0 | 0 | `-` |
|
||||||
| `TSN-RECOVERY-DRIFT` | 13 | 13 | 0 | 0 | `-` |
|
| `TSN-RECOVERY-DRIFT` | 13 | 13 | 0 | 0 | `-` |
|
||||||
| `TSN-ORDERED-PAIRS` | 361 | 97 | 1 | 263 | `TSN-PAIR-pocket-fuse` |
|
| `TSN-ORDERED-PAIRS` | 361 | 191 | 1 | 169 | `TSN-PAIR-groove-multi-transform` |
|
||||||
| `PROPERTY-CODECS` | 522 | 0 | 0 | 522 | `-` |
|
| `PROPERTY-CODECS` | 522 | 0 | 0 | 522 | `-` |
|
||||||
| `DOCUMENT-SEMANTICS` | 90 | 0 | 0 | 90 | `-` |
|
| `DOCUMENT-SEMANTICS` | 90 | 0 | 0 | 90 | `-` |
|
||||||
| `CORE-MODELING` | 171 | 0 | 0 | 171 | `-` |
|
| `CORE-MODELING` | 171 | 0 | 0 | 171 | `-` |
|
||||||
|
|||||||
@@ -111,6 +111,100 @@ const expectedPairs = [
|
|||||||
{ pair: 'pad->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] },
|
{ pair: 'pad->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] },
|
||||||
{ pair: 'pad->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [5, 6, 5] },
|
{ pair: 'pad->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [5, 6, 5] },
|
||||||
{ pair: 'pad->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] },
|
{ pair: 'pad->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] },
|
||||||
|
{ pair: 'pocket->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [8, 7, 8] },
|
||||||
|
{ pair: 'pocket->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] },
|
||||||
|
{ pair: 'pocket->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [7, 6, 7] },
|
||||||
|
{ pair: 'pocket->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] },
|
||||||
|
{ pair: 'pocket->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' },
|
||||||
|
{ pair: 'pocket->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] },
|
||||||
|
{ pair: 'pocket->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' },
|
||||||
|
{ pair: 'pocket->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' },
|
||||||
|
{ pair: 'pocket->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'Solids are not Processed' },
|
||||||
|
{ pair: 'pocket->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] },
|
||||||
|
{ pair: 'pocket->fillet', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4] },
|
||||||
|
{ pair: 'pocket->chamfer', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4] },
|
||||||
|
{ pair: 'pocket->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [1, 1.5, 1] },
|
||||||
|
{ pair: 'pocket->draft', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5] },
|
||||||
|
{ pair: 'pocket->thickness', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4] },
|
||||||
|
{ pair: 'pocket->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [8, 9, 8] },
|
||||||
|
{ pair: 'pocket->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] },
|
||||||
|
{ pair: 'pocket->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [5, 6, 5] },
|
||||||
|
{ pair: 'pocket->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] },
|
||||||
|
{ pair: 'loft->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [8, 7, 8] },
|
||||||
|
{ pair: 'loft->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] },
|
||||||
|
{ pair: 'loft->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [7, 6, 7] },
|
||||||
|
{ pair: 'loft->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] },
|
||||||
|
{ pair: 'loft->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' },
|
||||||
|
{ pair: 'loft->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] },
|
||||||
|
{ pair: 'loft->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' },
|
||||||
|
{ pair: 'loft->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' },
|
||||||
|
{ pair: 'loft->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'Solids are not Processed' },
|
||||||
|
{ pair: 'loft->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] },
|
||||||
|
{ pair: 'loft->fillet', decision: 'rejected', reasonCode: 'native-builder-wasm-abort-with-freecad-profile-acceptance-and-clean-resave', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4], nativeTypeId: 'Part::Fillet', freecadProfileAccepted: true, wasmCrashSignature: 'table index is out of bounds' },
|
||||||
|
{ pair: 'loft->chamfer', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4] },
|
||||||
|
{ pair: 'loft->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [1, 1.5, 1] },
|
||||||
|
{ pair: 'loft->draft', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5] },
|
||||||
|
{ pair: 'loft->thickness', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4] },
|
||||||
|
{ pair: 'loft->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [8, 9, 8] },
|
||||||
|
{ pair: 'loft->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] },
|
||||||
|
{ pair: 'loft->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [5, 6, 5] },
|
||||||
|
{ pair: 'loft->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_ThruSections', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] },
|
||||||
|
{ pair: 'pipe->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [0, 0.5, 0] },
|
||||||
|
{ pair: 'pipe->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [0, 0.5, 0] },
|
||||||
|
{ pair: 'pipe->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [0, 0.5, 0] },
|
||||||
|
{ pair: 'pipe->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] },
|
||||||
|
{ pair: 'pipe->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' },
|
||||||
|
{ pair: 'pipe->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] },
|
||||||
|
{ pair: 'pipe->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' },
|
||||||
|
{ pair: 'pipe->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' },
|
||||||
|
{ pair: 'pipe->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'Solids are not Processed' },
|
||||||
|
{ pair: 'pipe->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] },
|
||||||
|
{ pair: 'pipe->fillet', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4] },
|
||||||
|
{ pair: 'pipe->chamfer', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4] },
|
||||||
|
{ pair: 'pipe->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4] },
|
||||||
|
{ pair: 'pipe->draft', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5] },
|
||||||
|
{ pair: 'pipe->thickness', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4] },
|
||||||
|
{ pair: 'pipe->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [1.5, 1, 1.5] },
|
||||||
|
{ pair: 'pipe->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] },
|
||||||
|
{ pair: 'pipe->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [1, 1.5, 1] },
|
||||||
|
{ pair: 'pipe->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakePipe', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 7, 8] },
|
||||||
|
{ pair: 'revolution->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [0, 0.5, 0] },
|
||||||
|
{ pair: 'revolution->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [0, 0.5, 0] },
|
||||||
|
{ pair: 'revolution->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [0, 0.5, 0] },
|
||||||
|
{ pair: 'revolution->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] },
|
||||||
|
{ pair: 'revolution->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' },
|
||||||
|
{ pair: 'revolution->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [2, 1, 2] },
|
||||||
|
{ pair: 'revolution->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' },
|
||||||
|
{ pair: 'revolution->pipe', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' },
|
||||||
|
{ pair: 'revolution->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'Solids are not Processed' },
|
||||||
|
{ pair: 'revolution->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] },
|
||||||
|
{ pair: 'revolution->fillet', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4] },
|
||||||
|
{ pair: 'revolution->chamfer', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4] },
|
||||||
|
{ pair: 'revolution->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4] },
|
||||||
|
{ pair: 'revolution->draft', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5] },
|
||||||
|
{ pair: 'revolution->thickness', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4] },
|
||||||
|
{ pair: 'revolution->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [4, 3, 4] },
|
||||||
|
{ pair: 'revolution->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [10, 15, 10] },
|
||||||
|
{ pair: 'revolution->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [0, 0.5, 0] },
|
||||||
|
{ pair: 'revolution->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [4, 3, 4] },
|
||||||
|
{ pair: 'groove->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [8, 7, 8] },
|
||||||
|
{ pair: 'groove->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] },
|
||||||
|
{ pair: 'groove->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [7, 6, 7] },
|
||||||
|
{ pair: 'groove->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] },
|
||||||
|
{ pair: 'groove->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' },
|
||||||
|
{ pair: 'groove->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] },
|
||||||
|
{ pair: 'groove->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' },
|
||||||
|
{ pair: 'groove->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' },
|
||||||
|
{ pair: 'groove->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'Solids are not Processed' },
|
||||||
|
{ pair: 'groove->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] },
|
||||||
|
{ pair: 'groove->fillet', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4], nativeTypeId: 'Part::Fillet', freeCadDiagnostic: 'BRep_API: command not done' },
|
||||||
|
{ pair: 'groove->chamfer', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4], nativeTypeId: 'Part::Chamfer', freeCadDiagnostic: 'BRep_API: command not done', wasmCrashSignature: 'memory access out of bounds' },
|
||||||
|
{ pair: 'groove->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [1, 1.5, 1] },
|
||||||
|
{ pair: 'groove->draft', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5] },
|
||||||
|
{ pair: 'groove->thickness', decision: 'rejected', reasonCode: 'native-builder-wasm-abort-with-freecad-profile-acceptance-and-clean-resave', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4], nativeTypeId: 'Part::Thickness', freecadProfileAccepted: true, wasmCrashSignature: 'memory access out of bounds' },
|
||||||
|
{ pair: 'groove->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [8, 9, 8] },
|
||||||
|
{ pair: 'groove->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [90, 120, 90] },
|
||||||
|
{ pair: 'groove->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', firstInputCount: 2, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [5, 6, 5] },
|
||||||
]
|
]
|
||||||
if (report.nativeProbe?.artifacts?.length !== 3 || report.classifications?.length !== expectedPairs.length) fail('native artifacts or classification prefix is incomplete.')
|
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()) {
|
for (const [index, entry] of report.classifications.entries()) {
|
||||||
@@ -126,7 +220,8 @@ for (const [index, entry] of report.classifications.entries()) {
|
|||||||
if (expected.rejectionAuthority === 'occt-builder') {
|
if (expected.rejectionAuthority === 'occt-builder') {
|
||||||
if (rejection.stable !== true || rejection.attempts?.length !== 3) fail(`${expected.pair} OCCT rejection is unstable.`)
|
if (rejection.stable !== true || rejection.attempts?.length !== 3) fail(`${expected.pair} OCCT rejection is unstable.`)
|
||||||
for (const [attemptIndex, attempt] of rejection.attempts.entries()) {
|
for (const [attemptIndex, attempt] of rejection.attempts.entries()) {
|
||||||
if (attempt.operation !== secondOperation || attempt.builder !== expected.secondBuilder || attempt.inputCount !== expected.secondInputCount || attempt.parameter !== expected.mutationParameter || attempt.parameterValue !== expected.mutationTrajectory[attemptIndex] || attempt.runtime !== 'occt-native' || attempt.outcome !== 'rejected' || attempt.resultProduced !== false || attempt.shapeProduced !== false || attempt.historyProduced !== false || attempt.rejectionStage !== 'builder' || attempt.exceptionTransport !== 'emscripten-cpp-exception' || attempt.thrownType !== 'number') fail(`${expected.pair} OCCT attempt ${attemptIndex} is invalid.`)
|
const wasmAbort = typeof expected.wasmCrashSignature === 'string'
|
||||||
|
if (attempt.operation !== secondOperation || attempt.builder !== expected.secondBuilder || attempt.inputCount !== expected.secondInputCount || attempt.parameter !== expected.mutationParameter || attempt.parameterValue !== expected.mutationTrajectory[attemptIndex] || attempt.runtime !== 'occt-native' || attempt.outcome !== 'rejected' || attempt.resultProduced !== false || attempt.shapeProduced !== false || attempt.historyProduced !== false || attempt.rejectionStage !== 'builder' || attempt.exceptionTransport !== (wasmAbort ? 'emscripten-wasm-abort' : 'emscripten-cpp-exception') || attempt.thrownType !== (wasmAbort ? 'RuntimeError' : 'number') || (wasmAbort && attempt.crashSignature !== expected.wasmCrashSignature)) fail(`${expected.pair} OCCT attempt ${attemptIndex} is invalid.`)
|
||||||
for (const absent of ['summary', 'historyProvider', 'historyRecords', 'historySha256', 'namingStatus', 'namingEvidenceSha256', 'namingSemanticSha256', 'resultStep', 'resultBrep', 'shape', 'history']) if (absent in attempt) fail(`${expected.pair} OCCT attempt ${attemptIndex} fabricates ${absent}.`)
|
for (const absent of ['summary', 'historyProvider', 'historyRecords', 'historySha256', 'namingStatus', 'namingEvidenceSha256', 'namingSemanticSha256', 'resultStep', 'resultBrep', 'shape', 'history']) if (absent in attempt) fail(`${expected.pair} OCCT attempt ${attemptIndex} fabricates ${absent}.`)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -135,8 +230,15 @@ for (const [index, entry] of report.classifications.entries()) {
|
|||||||
}
|
}
|
||||||
const persistence = rejection.persistence
|
const persistence = rejection.persistence
|
||||||
const diagnostic = persistence?.diagnostic
|
const diagnostic = persistence?.diagnostic
|
||||||
if (persistence?.status !== 'pass' || persistence.decision !== 'rejected' || persistence.pair !== entry.pair || persistence.operation !== secondOperation || persistence.nativeTypeId !== expected.nativeTypeId || persistence.freecadVersion !== '1.1.1' || !Object.values(persistence.checks ?? {}).every(Boolean)) fail(`${expected.pair} FCStd rejection evidence is incomplete.`)
|
const freecadProfileAccepted = expected.freecadProfileAccepted === true
|
||||||
if (diagnostic?.nativeTypeId !== expected.nativeTypeId || diagnostic.parameter?.name !== expected.mutationParameter || diagnostic.parameter.value !== expected.mutationTrajectory[0] || diagnostic.inputShape?.solids !== 1 || diagnostic.recomputeResult !== true || diagnostic.shapeNull !== true || diagnostic.shapeValid !== false || !diagnostic.state?.includes('Invalid') || diagnostic.statusString === 'Valid' || !diagnostic.objects?.some(({ name, typeId }) => name === 'PairResult' && typeId === expected.nativeTypeId)) fail(`${expected.pair} did not capture a real rejected FreeCAD recompute.`)
|
const persistenceChecksPass = Object.values(persistence?.checks ?? {}).every(Boolean) || (freecadProfileAccepted && persistence?.checks?.nativeFeatureRejected === false && Object.entries(persistence?.checks ?? {}).filter(([key]) => key !== 'nativeFeatureRejected').every(([, value]) => value === true)) || (!freecadProfileAccepted && persistence?.checks?.nativeFeatureRejected === true && Object.entries(persistence?.checks ?? {}).filter(([key]) => key !== 'freecadProfileAccepted').every(([, value]) => value === true))
|
||||||
|
if (persistence?.status !== 'pass' || persistence.decision !== 'rejected' || persistence.pair !== entry.pair || persistence.operation !== secondOperation || persistence.nativeTypeId !== expected.nativeTypeId || persistence.freecadVersion !== '1.1.1' || !persistenceChecksPass) fail(`${expected.pair} FCStd rejection evidence is incomplete.`)
|
||||||
|
if (diagnostic?.nativeTypeId !== expected.nativeTypeId || diagnostic.parameter?.name !== expected.mutationParameter || diagnostic.parameter.value !== expected.mutationTrajectory[0] || diagnostic.inputShape?.solids !== 1 || diagnostic.recomputeResult !== true || !diagnostic.objects?.some(({ name, typeId }) => name === 'PairResult' && typeId === expected.nativeTypeId)) fail(`${expected.pair} did not capture a real FreeCAD profile evaluation.`)
|
||||||
|
if (freecadProfileAccepted) {
|
||||||
|
if (persistence.checks.nativeFeatureRejected !== false || persistence.checks.freecadProfileAccepted !== true || diagnostic.shapeNull !== false || diagnostic.shapeValid !== true || diagnostic.statusString !== 'Valid' || !diagnostic.state?.includes('Up-to-date')) fail(`${expected.pair} FreeCAD profile acceptance evidence is incomplete.`)
|
||||||
|
} else if (diagnostic.shapeNull !== true || diagnostic.shapeValid !== false || !diagnostic.state?.includes('Invalid') || diagnostic.statusString === 'Valid') {
|
||||||
|
fail(`${expected.pair} did not capture a real rejected FreeCAD recompute.`)
|
||||||
|
}
|
||||||
if (expected.freeCadDiagnostic && diagnostic.statusString !== expected.freeCadDiagnostic) fail(`${expected.pair} FreeCAD profile diagnostic changed.`)
|
if (expected.freeCadDiagnostic && diagnostic.statusString !== expected.freeCadDiagnostic) fail(`${expected.pair} FreeCAD profile diagnostic changed.`)
|
||||||
if (persistence.source?.shape?.solids !== 1 || !persistence.source.shape.brepSha256 || JSON.stringify(persistence.rollback?.before) !== JSON.stringify(persistence.rollback?.after)) fail(`${expected.pair} abort did not restore the source object set and Shape.`)
|
if (persistence.source?.shape?.solids !== 1 || !persistence.source.shape.brepSha256 || JSON.stringify(persistence.rollback?.before) !== JSON.stringify(persistence.rollback?.after)) fail(`${expected.pair} abort did not restore the source object set and Shape.`)
|
||||||
const phases = persistence.phases
|
const phases = persistence.phases
|
||||||
@@ -153,6 +255,6 @@ for (const [index, entry] of report.classifications.entries()) {
|
|||||||
const phases = entry.persistence.phases
|
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.`)
|
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: 93, accepted: 73, rejected: 20, unknown: 268 }
|
const expectedSummary = { registeredOperations: 19, orderedPairs: 361, classifiedPairs: 187, accepted: 143, rejected: 44, unknown: 174 }
|
||||||
if (JSON.stringify(report.summary) !== JSON.stringify(expectedSummary)) fail('summary is inconsistent.')
|
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))
|
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))
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
import math
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import FreeCAD as App
|
import FreeCAD as App
|
||||||
@@ -39,6 +40,18 @@ def shape_snapshot(feature):
|
|||||||
return shape_snapshot_from_shape(feature.Shape)
|
return shape_snapshot_from_shape(feature.Shape)
|
||||||
|
|
||||||
|
|
||||||
|
def imported_solid_shapes(document):
|
||||||
|
shapes = []
|
||||||
|
for obj in document.Objects:
|
||||||
|
if obj.TypeId != "Part::Feature" or not hasattr(obj, "Shape") or obj.Shape.isNull() or not obj.Shape.isValid() or not obj.Shape.Solids:
|
||||||
|
continue
|
||||||
|
bounds = obj.Shape.BoundBox
|
||||||
|
if not all(math.isfinite(float(value)) for value in (bounds.XMin, bounds.YMin, bounds.ZMin, bounds.XMax, bounds.YMax, bounds.ZMax)):
|
||||||
|
continue
|
||||||
|
shapes.append(obj.Shape)
|
||||||
|
return shapes
|
||||||
|
|
||||||
|
|
||||||
def phase_snapshot(document):
|
def phase_snapshot(document):
|
||||||
feature = document.getObject("PairResult")
|
feature = document.getObject("PairResult")
|
||||||
if feature is None:
|
if feature is None:
|
||||||
@@ -92,7 +105,7 @@ def collect_accepted():
|
|||||||
try:
|
try:
|
||||||
Import.insert(step_path, document.Name)
|
Import.insert(step_path, document.Name)
|
||||||
document.recompute()
|
document.recompute()
|
||||||
source_shapes = [obj.Shape for obj in document.Objects if hasattr(obj, "Shape") and not obj.Shape.isNull()]
|
source_shapes = imported_solid_shapes(document)
|
||||||
if not source_shapes:
|
if not source_shapes:
|
||||||
raise RuntimeError("STEP import produced no Shape")
|
raise RuntimeError("STEP import produced no Shape")
|
||||||
result = document.addObject("Part::Feature", "PairResult")
|
result = document.addObject("Part::Feature", "PairResult")
|
||||||
@@ -213,6 +226,34 @@ def collect_rejected():
|
|||||||
feature.Solid = True
|
feature.Solid = True
|
||||||
diagnostic["parameter"] = {"name": "angle", "value": round(float(feature.Angle), 7)}
|
diagnostic["parameter"] = {"name": "angle", "value": round(float(feature.Angle), 7)}
|
||||||
diagnostic["input"] = link_snapshot(feature.Source)
|
diagnostic["input"] = link_snapshot(feature.Source)
|
||||||
|
elif operation == "fuse":
|
||||||
|
tool = document.addObject("Part::Feature", "Tool")
|
||||||
|
tool.Shape = Part.makeBox(5.0, 5.0, 5.0, App.Vector(8.0, 0.0, 0.0))
|
||||||
|
feature = document.addObject("Part::Fuse", "PairResult")
|
||||||
|
feature.Base = source
|
||||||
|
feature.Tool = tool
|
||||||
|
diagnostic["parameter"] = {"name": "toolOffsetX", "value": 8.0}
|
||||||
|
diagnostic["input"] = {"base": link_snapshot(feature.Base), "tool": link_snapshot(feature.Tool)}
|
||||||
|
elif operation == "fillet":
|
||||||
|
feature = document.addObject("Part::Fillet", "PairResult")
|
||||||
|
feature.Base = source
|
||||||
|
feature.Edges = [(index, 0.4, 0.4) for index in range(1, len(source.Shape.Edges) + 1)]
|
||||||
|
diagnostic["parameter"] = {"name": "radius", "value": 0.4}
|
||||||
|
diagnostic["input"] = link_snapshot(feature.Base)
|
||||||
|
elif operation == "chamfer":
|
||||||
|
feature = document.addObject("Part::Chamfer", "PairResult")
|
||||||
|
feature.Base = source
|
||||||
|
feature.Edges = [(index, 0.4, 0.4) for index in range(1, len(source.Shape.Edges) + 1)]
|
||||||
|
diagnostic["parameter"] = {"name": "distance", "value": 0.4}
|
||||||
|
diagnostic["input"] = link_snapshot(feature.Base)
|
||||||
|
elif operation == "thickness":
|
||||||
|
feature = document.addObject("Part::Thickness", "PairResult")
|
||||||
|
feature.Faces = (source, ["Face2"])
|
||||||
|
feature.Value = -0.4
|
||||||
|
feature.Mode = 0
|
||||||
|
feature.Join = 0
|
||||||
|
diagnostic["parameter"] = {"name": "offset", "value": round(float(feature.Value), 7)}
|
||||||
|
diagnostic["input"] = link_snapshot(feature.Faces)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unsupported rejected ordered-pair operation: " + operation)
|
raise RuntimeError("Unsupported rejected ordered-pair operation: " + operation)
|
||||||
diagnostic["nativeTypeId"] = feature.TypeId
|
diagnostic["nativeTypeId"] = feature.TypeId
|
||||||
@@ -256,13 +297,15 @@ def collect_rejected():
|
|||||||
or "Error" in diagnostic["state"]
|
or "Error" in diagnostic["state"]
|
||||||
or "Invalid" in diagnostic["state"]
|
or "Invalid" in diagnostic["state"]
|
||||||
)
|
)
|
||||||
expected_type_id = {"pad": "PartDesign::Pad", "loft": "Part::Loft", "pipe": "Part::Sweep", "revolution": "Part::Revolution"}[operation]
|
freecad_profile_accepted = operation in ("fillet", "chamfer", "thickness") and not feature_rejected and not diagnostic["shapeNull"] and diagnostic["shapeValid"] and diagnostic["statusString"] == "Valid"
|
||||||
input_names = [diagnostic.get("input", {}).get("name")] if operation in ("pad", "revolution") else [item["name"] for item in diagnostic.get("input", {}).get("sections", [])]
|
expected_type_id = {"pad": "PartDesign::Pad", "loft": "Part::Loft", "pipe": "Part::Sweep", "revolution": "Part::Revolution", "fuse": "Part::Fuse", "fillet": "Part::Fillet", "chamfer": "Part::Chamfer", "thickness": "Part::Thickness"}[operation]
|
||||||
|
input_names = [diagnostic.get("input", {}).get("name")] if operation in ("pad", "revolution", "fillet", "chamfer", "thickness") else ([diagnostic.get("input", {}).get(key, {}).get("name") for key in ("base", "tool")] if operation == "fuse" else [item["name"] for item in diagnostic.get("input", {}).get("sections", [])])
|
||||||
checks = {
|
checks = {
|
||||||
"nativeFeatureConstructed": diagnostic.get("nativeTypeId") == expected_type_id,
|
"nativeFeatureConstructed": diagnostic.get("nativeTypeId") == expected_type_id,
|
||||||
"fuseSolidUsedAsInput": source_name in input_names and diagnostic.get("inputShape", {}).get("solids") == 1,
|
"fuseSolidUsedAsInput": source_name in input_names and diagnostic.get("inputShape", {}).get("solids") == 1,
|
||||||
"recomputeStatusCaptured": diagnostic["recomputeResult"] is not None or diagnostic["exceptionType"] is not None,
|
"recomputeStatusCaptured": diagnostic["recomputeResult"] is not None or diagnostic["exceptionType"] is not None,
|
||||||
"nativeFeatureRejected": feature_rejected,
|
"nativeFeatureRejected": feature_rejected,
|
||||||
|
"freecadProfileAccepted": freecad_profile_accepted,
|
||||||
"objectSetRestored": baseline_objects == restored_objects,
|
"objectSetRestored": baseline_objects == restored_objects,
|
||||||
"sourceShapeRestored": baseline_source_shape == restored_source_shape,
|
"sourceShapeRestored": baseline_source_shape == restored_source_shape,
|
||||||
"documentUnpolluted": baseline == initial,
|
"documentUnpolluted": baseline == initial,
|
||||||
@@ -289,7 +332,7 @@ def collect_rejected():
|
|||||||
},
|
},
|
||||||
"phases": {"initial": initial, "reopened": reopened_snapshot, "resaved": resaved_snapshot},
|
"phases": {"initial": initial, "reopened": reopened_snapshot, "resaved": resaved_snapshot},
|
||||||
"checks": checks,
|
"checks": checks,
|
||||||
"status": "pass" if all(checks.values()) else "failed",
|
"status": "pass" if all(checks.values()) or (operation in ("fillet", "chamfer", "thickness") and freecad_profile_accepted and all(value for key, value in checks.items() if key != "nativeFeatureRejected")) or (not freecad_profile_accepted and feature_rejected and all(value for key, value in checks.items() if key != "freecadProfileAccepted")) else "failed",
|
||||||
}
|
}
|
||||||
finally:
|
finally:
|
||||||
for name in list(App.listDocuments().keys()):
|
for name in list(App.listDocuments().keys()):
|
||||||
|
|||||||
@@ -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->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->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 },
|
||||||
'pad->pipe': { ...operationSpecs.pipe, kernelOutcome: 'accepted' },
|
'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 baseStep = objectStep ?? shapeStep(module, 'makeBox', 10, 10, 10)
|
||||||
const objectInput = input('object', 'object', stage.objectId, stage.objectTag, baseStep, stage.namingEvidence)
|
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] }
|
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 {
|
if (operation === 'multi-transform') return {
|
||||||
response: module.multiTransformHistoryFromStep(baseStep, [
|
response: module.multiTransformHistoryFromStep(baseStep, [
|
||||||
{ type: 'linear', direction: [multiTranslationX, 0, 0] },
|
{ 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],
|
inputs: [objectInput],
|
||||||
}
|
}
|
||||||
if (operation === 'groove') {
|
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 {
|
return {
|
||||||
response: module.grooveHistoryFromStep(baseStep, profileStep, 0, 0, 0, 0, 1, 0, angle),
|
response: module.grooveHistoryFromStep(baseStep, profileStep, 0, 0, 0, 0, 1, 0, angle),
|
||||||
inputs: [objectInput, input('tool', 'tool', `${stage.resultObjectId}:profile`, stage.objectTag + 1, profileStep)],
|
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 === 'pad') return { response: module.prismHistoryFromStep(baseStep, 0, 0, length), inputs: [objectInput] }
|
||||||
if (operation === 'pocket') {
|
if (operation === 'pocket') {
|
||||||
const profileStep = shapeStep(module, 'makeRectangleFace', 2, 3)
|
const profileStep = shapeStep(module, 'makeRectangleFace', profileWidth, profileHeight)
|
||||||
return {
|
return {
|
||||||
response: module.pocketHistoryFromStep(baseStep, profileStep, 0, 0, length),
|
response: module.pocketHistoryFromStep(baseStep, profileStep, 0, 0, length),
|
||||||
inputs: [objectInput, input('tool', 'tool', `${stage.resultObjectId}:profile`, stage.objectTag + 1, profileStep)],
|
inputs: [objectInput, input('tool', 'tool', `${stage.resultObjectId}:profile`, stage.objectTag + 1, profileStep)],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (operation === 'loft') {
|
if (operation === 'loft') {
|
||||||
const sectionStep = shapeStep(module, 'makeRectangleFacePlaced', 2, 3, 0, 0, 15)
|
const sectionStep = shapeStep(module, 'makeRectangleFacePlaced', 10, 10, 0, 0, 15)
|
||||||
return {
|
return {
|
||||||
response: module.loftHistoryFromStep(baseStep, sectionStep, ruled),
|
response: module.loftHistoryFromStep(baseStep, sectionStep, ruled),
|
||||||
inputs: [objectInput, input('tool', 'tool', `${stage.resultObjectId}:section`, stage.objectTag + 1, sectionStep)],
|
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 captureRejectedStage = (module, definition) => {
|
||||||
const spec = operationSpecs[definition.operation]
|
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
|
let capture
|
||||||
try {
|
try {
|
||||||
capture = createOperation(module, definition)
|
capture = createOperation(module, definition)
|
||||||
@@ -148,7 +212,7 @@ const captureRejectedStage = (module, definition) => {
|
|||||||
return {
|
return {
|
||||||
operation: definition.operation,
|
operation: definition.operation,
|
||||||
builder: spec.builder,
|
builder: spec.builder,
|
||||||
inputCount: 1,
|
inputCount: definition.operation === 'pipe' ? 2 : 1,
|
||||||
parameter: spec.parameter,
|
parameter: spec.parameter,
|
||||||
parameterValue: definition[spec.parameter],
|
parameterValue: definition[spec.parameter],
|
||||||
runtime: 'occt-native',
|
runtime: 'occt-native',
|
||||||
@@ -171,7 +235,8 @@ const captureKernelCompatibilityStage = (module, definition, parameterValue, exp
|
|||||||
const { response, inputs } = createOperation(module, definition)
|
const { response, inputs } = createOperation(module, definition)
|
||||||
try {
|
try {
|
||||||
const outcome = response.summary?.isValid === true ? 'accepted' : 'invalid-result'
|
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 {
|
return {
|
||||||
operation: definition.operation,
|
operation: definition.operation,
|
||||||
builder: operationSpecs[definition.operation].builder,
|
builder: operationSpecs[definition.operation].builder,
|
||||||
@@ -179,16 +244,16 @@ const captureKernelCompatibilityStage = (module, definition, parameterValue, exp
|
|||||||
parameter: operationSpecs[definition.operation].parameter,
|
parameter: operationSpecs[definition.operation].parameter,
|
||||||
parameterValue,
|
parameterValue,
|
||||||
runtime: 'occt-native',
|
runtime: 'occt-native',
|
||||||
outcome,
|
outcome: noHistorySuperset ? expectedOutcome : outcome,
|
||||||
resultProduced: true,
|
resultProduced: true,
|
||||||
shapeProduced: true,
|
shapeProduced: true,
|
||||||
validShapeProduced: response.summary.isValid === true,
|
validShapeProduced: response.summary.isValid === true,
|
||||||
historyProduced: true,
|
historyProduced: response.records.length > 0,
|
||||||
historyProvider: response.provider,
|
historyProvider: response.provider,
|
||||||
summary: canonicalSummary(response.summary),
|
summary: canonicalSummary(response.summary),
|
||||||
historyRecords: response.records.length,
|
historyRecords: response.records.length,
|
||||||
historySha256: sha256(JSON.stringify(response.records)),
|
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 {
|
} finally {
|
||||||
response.result?.delete?.()
|
response.result?.delete?.()
|
||||||
@@ -200,7 +265,7 @@ const captureStage = (module, definition) => {
|
|||||||
try {
|
try {
|
||||||
const provenance = classifyFreeCadPrivateNamingHistory(response.records, inputs)
|
const provenance = classifyFreeCadPrivateNamingHistory(response.records, inputs)
|
||||||
const stableRecords = provenance.records.filter(({ relation }) => relation !== 'deleted').length
|
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({
|
const request = createFreeCadPrivateNamingAbiRequest({
|
||||||
requestId: `${definition.stage.stageId}:request`,
|
requestId: `${definition.stage.stageId}:request`,
|
||||||
documentId: 'ordered-operation-pair',
|
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
|
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()}`)
|
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)
|
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
|
return persistence
|
||||||
} finally {
|
} finally {
|
||||||
await rm(temporaryDirectory, { recursive: true, force: true })
|
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 classifyPair = async (fromOperation, toOperation, pairIndex) => {
|
||||||
const pair = `${fromOperation}->${toOperation}`
|
const pair = `${fromOperation}->${toOperation}`
|
||||||
const pairId = pair.replace('->', '-')
|
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 }
|
? { toolSize: 10, toolOffset: 5 }
|
||||||
|
: pair === 'pocket->thickness'
|
||||||
|
? { length: 10, profileWidth: 5, profileHeight: 10 }
|
||||||
: ['common->pocket', 'common->groove'].includes(pair)
|
: ['common->pocket', 'common->groove'].includes(pair)
|
||||||
? { toolSize: 5, toolOffset: 0 }
|
? { toolSize: 5, toolOffset: 0 }
|
||||||
: fromOperation === 'fuse'
|
: fromOperation === 'fuse'
|
||||||
@@ -299,6 +369,12 @@ const classifyPair = async (fromOperation, toOperation, pairIndex) => {
|
|||||||
? { toolSize: 5, toolOffset: 4 }
|
? { toolSize: 5, toolOffset: 4 }
|
||||||
: fromOperation === 'pad'
|
: fromOperation === 'pad'
|
||||||
? { ...operationSpecs.pad.nominal, objectStep: shapeStep(module, 'makeRectangleFace', 10, 10) }
|
? { ...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
|
: operationSpecs[fromOperation].nominal
|
||||||
const first = captureStage(module, {
|
const first = captureStage(module, {
|
||||||
operation: fromOperation, ...firstParameters,
|
operation: fromOperation, ...firstParameters,
|
||||||
@@ -333,11 +409,15 @@ const classifyPair = async (fromOperation, toOperation, pairIndex) => {
|
|||||||
const stableRejection = attempts.every((attempt) => rejectionSignature(attempt) === rejectionSignature(attempts[0]))
|
const stableRejection = attempts.every((attempt) => rejectionSignature(attempt) === rejectionSignature(attempts[0]))
|
||||||
if (!stableRejection) fail(`${pair} rejection changed across its parameter trajectory.`)
|
if (!stableRejection) fail(`${pair} rejection changed across its parameter trajectory.`)
|
||||||
const persistence = await persistPair(pair, first.response.resultStep, first.namingEvidence, 'rejected')
|
const persistence = await persistPair(pair, first.response.resultStep, first.namingEvidence, 'rejected')
|
||||||
return {
|
const freecadProfileAccepted = persistence.checks.freecadProfileAccepted === true
|
||||||
taskId: `TSN-PAIR-${pairId}`,
|
const wasmAbort = attempts.every(({ exceptionTransport }) => exceptionTransport === 'emscripten-wasm-abort')
|
||||||
pair,
|
return {
|
||||||
classification: 'rejected',
|
taskId: `TSN-PAIR-${pairId}`,
|
||||||
reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave',
|
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',
|
nativeDecision: 'rejected',
|
||||||
first: first.report,
|
first: first.report,
|
||||||
rejection: { scope: 'second-operation-only', authority: 'occt-builder', parameter: spec.parameter, trajectory, stable: stableRejection, attempts, persistence },
|
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 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 = []
|
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([
|
const [artifacts, executorHarness, matrixHarness, resaveHarness] = await Promise.all([
|
||||||
Promise.all(artifactNames.map(async (name) => {
|
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 },
|
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`)
|
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))
|
||||||
|
|||||||
833
后续工作.txt
833
后续工作.txt
@@ -1086,4 +1086,837 @@ git diff --check
|
|||||||
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
- focused ordered-pair gate 已锁定真实 Profile、ordered builder、单 Solid 约束、变异、恢复、history、naming 和持久化证据。
|
- focused ordered-pair gate 已锁定真实 Profile、ordered builder、单 Solid 约束、变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-fuse`
|
||||||
|
|
||||||
|
`pocket->fuse` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Fuse` 双输入 builder,对 Pocket 结果执行布尔并集。
|
||||||
|
- 默认工具 X 偏移 `12` 会产生分离实体,未被误记为接受;改用保持实体交叠的 `8 -> 7 -> 8` 专用轨迹。
|
||||||
|
- 工具偏移轨迹使体积在 `1045 -> 1020 -> 1045` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,包含 52 条原生 history 记录。
|
||||||
|
- 上游 Pocket naming 证据向下游传播,FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定真实 Profile、两阶段双输入 builder、专用变异轨迹、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-cut`
|
||||||
|
|
||||||
|
`pocket->cut` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Cut` 双输入 builder,对 Pocket 结果继续执行布尔减料。
|
||||||
|
- `4 -> 3 -> 4` 工具尺寸轨迹改变体积、面积与拓扑,体积在 `906 -> 943 -> 906` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,包含 48 条原生 history 记录。
|
||||||
|
- 上游 Pocket naming 证据向下游传播,恢复态语义摘要与名义态一致。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定真实 Profile、两阶段双输入减料、变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-common`
|
||||||
|
|
||||||
|
`pocket->common` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Common` 双输入 builder,对 Pocket 结果执行布尔交集。
|
||||||
|
- 默认工具 X 偏移 `10` 仅与 Pocket 外边界相切且没有实体交集,未被误记为接受;改用 `7 -> 6 -> 7` 专用轨迹。
|
||||||
|
- 工具偏移轨迹使交集体积在 `75 -> 100 -> 75` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,包含 178 条原生 history 记录。
|
||||||
|
- 上游 Pocket naming 证据向下游传播,FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定真实 Profile、专用交叠轨迹、两阶段双输入 builder、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-rotate`
|
||||||
|
|
||||||
|
`pocket->rotate` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform` 单输入 builder,将 Pocket 结果绕锁定 Z 轴旋转。
|
||||||
|
- `15 -> 22.5 -> 15` 角度轨迹改变边界,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,体积 `970`,包含 135 条原生 history 记录。
|
||||||
|
- 上游 Pocket naming 证据向下游传播,恢复态语义摘要与名义态一致。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定真实 Profile、两阶段 builder、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-pad`
|
||||||
|
|
||||||
|
`pocket->pad` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- OCCT `BRepPrimAPI_MakePrism` 在 `5 -> 7.5 -> 5` 长度轨迹中稳定拒绝 Pocket Solid 输入,且不产生结果 Shape 或 history。
|
||||||
|
- FreeCAD `PartDesign::Pad` 使用同一 Pocket Solid 作为 Profile,返回 `FeatureExtrusion: Length: Could not extrude the sketch!`。
|
||||||
|
- FreeCAD 结果 Shape 为空、状态包含 `Invalid`,拒绝任务没有伪造下游 naming 或变异证据。
|
||||||
|
- transaction abort 后对象集与 Pocket 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、异常传输、精确诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-pocket`
|
||||||
|
|
||||||
|
`pocket->pocket` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 第一、第二阶段均使用真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,上游 Pocket 生成体积 `970` 的有效单 Solid。
|
||||||
|
- 下游使用锁定的 `3x3` Face Profile,避免默认 `2x3` Profile 只重复切除已空区域而产生无效变异轨迹。
|
||||||
|
- `5 -> 4 -> 5` 深度轨迹使体积在 `955 -> 958 -> 955` 间变化,同时改变拓扑和 history,并精确恢复名义摘要与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,包含 111 条原生 history 记录。
|
||||||
|
- 上游 Pocket naming 证据向下游传播,FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段双输入 builder、非平凡 Profile、深度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-loft`
|
||||||
|
|
||||||
|
`pocket->loft` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- OCCT `BRepOffsetAPI_ThruSections` 在 `false -> true -> false` ruled 轨迹中生成有效 Shape,但该结果仅记为 kernel-superset 诊断。
|
||||||
|
- FreeCAD `Part::Loft` 对 Pocket Solid section 返回 `Profile shape is not a single vertex, edge, wire nor face.`。
|
||||||
|
- FreeCAD 结果 Shape 为空、状态包含 `Invalid`,拒绝任务没有伪造下游 naming 或变异证据。
|
||||||
|
- transaction abort 后对象集与 Pocket 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致。
|
||||||
|
- focused ordered-pair gate 已锁定 FreeCAD 决策权、OCCT 超集诊断、精确失败信息、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-pipe`
|
||||||
|
|
||||||
|
`pocket->pipe` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 初始的 kernel-invalid 预期被真实 probe 否定;OCCT `BRepOffsetAPI_MakePipe` 在 `15 -> 12 -> 15` spine 长度轨迹中生成有效 Shape,但该结果仅记为 kernel-superset 诊断。
|
||||||
|
- FreeCAD `Part::Sweep` 对 Pocket Solid section 返回 `A fatal error occurred when making the sweep`。
|
||||||
|
- FreeCAD 结果 Shape 为空、状态包含 `Invalid`,拒绝任务没有伪造下游 naming 或变异证据。
|
||||||
|
- transaction abort 后对象集与 Pocket 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致。
|
||||||
|
- focused ordered-pair gate 已锁定 FreeCAD 决策权、OCCT 超集诊断、精确失败信息、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-revolution`
|
||||||
|
|
||||||
|
`pocket->revolution` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- OCCT `BRepPrimAPI_MakeRevol` 在 `360 -> 270 -> 360` 角度轨迹中稳定拒绝 Pocket Solid 输入,且不产生结果 Shape 或 history。
|
||||||
|
- FreeCAD `Part::Revolution` 使用同一 Pocket Solid 作为 Source,返回 `Solids are not Processed`。
|
||||||
|
- FreeCAD 结果 Shape 为空、状态包含 `Invalid`,拒绝任务没有伪造下游 naming 或变异证据。
|
||||||
|
- transaction abort 后对象集与 Pocket 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、异常传输、精确诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-groove`
|
||||||
|
|
||||||
|
`pocket->groove` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 下游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 Pocket 结果执行旋转减料。
|
||||||
|
- `360 -> 180 -> 360` 角度轨迹改变体积、拓扑和 history,并精确恢复名义摘要与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,体积 `966.8584073`,包含 40 条原生 history 记录。
|
||||||
|
- 上游 Pocket naming 证据向下游传播,恢复态语义摘要与名义态一致。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段双输入 builder、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-fillet`
|
||||||
|
|
||||||
|
`pocket->fillet` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 下游使用真实 `BRepFilletAPI_MakeFillet` 单输入 builder,对 Pocket 结果的锁定原生边执行倒圆。
|
||||||
|
- `0.4 -> 0.6 -> 0.4` 半径轨迹改变体积与面积,体积在 `965.9792974 -> 961.0655284 -> 965.9792974` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,包含 44 Face 和 261 条原生 history 记录。
|
||||||
|
- 上游 Pocket naming 证据向下游传播,FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、原生边选择、半径变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-chamfer`
|
||||||
|
|
||||||
|
`pocket->chamfer` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 下游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,对 Pocket 结果的锁定原生边执行倒角。
|
||||||
|
- `0.4 -> 0.6 -> 0.4` 距离轨迹改变体积与面积,体积在 `960.848 -> 949.912 -> 960.848` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,包含 44 Face 和 261 条原生 history 记录。
|
||||||
|
- 上游 Pocket naming 证据向下游传播,FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、原生边选择、距离变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-hole`
|
||||||
|
|
||||||
|
`pocket->hole` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 下游使用真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` 单输入 builder,以锁定位置和方向的圆柱刀具贯穿 Pocket 结果。
|
||||||
|
- `1 -> 1.5 -> 1` 半径轨迹改变体积与面积,体积在 `938.5840735 -> 899.3141653 -> 938.5840735` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,包含 23 条原生 history 记录,下游 naming 状态为无歧义 `native-evidence`。
|
||||||
|
- 上游 Pocket naming 证据向下游传播,FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、圆柱减料、半径变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-draft`
|
||||||
|
|
||||||
|
`pocket->draft` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 下游使用真实 `BRepOffsetAPI_DraftAngle` 单输入 builder,对 Pocket 结果的锁定原生 Face、中性面和拉伸方向执行拔模。
|
||||||
|
- `5 -> 8 -> 5` 角度轨迹改变体积与面积,体积在 `929.5364931 -> 904.999864 -> 929.5364931` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,包含 7 条原生 history 记录,下游 naming 状态为无歧义 `native-evidence`。
|
||||||
|
- 上游 Pocket naming 证据向下游传播,FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、原生 Face 选择、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-thickness`
|
||||||
|
|
||||||
|
`pocket->thickness` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `10x10` Box 与 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,按专用 `5x10` Profile 贯穿切除,生成体积 `500` 的有效单 Solid 和 25 条原生 history。
|
||||||
|
- 下游使用真实 `BRepOffsetAPI_MakeThickSolid` 单输入 builder,对锁定的原生 Face 执行厚壳;名义结果为有效 1 Solid、11 Face,体积 `129.056`。
|
||||||
|
- `-0.4 -> -0.6 -> -0.4` offset 轨迹使体积在 `129.056 -> 185.664 -> 129.056` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Pocket naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、原生 Face 选择、offset 变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-linear-pattern`
|
||||||
|
|
||||||
|
`pocket->linear-pattern` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 单输入 builder,将 Pocket 结果沿 X 方向平移复制并融合为单 Solid;名义体积 `1770`,边界覆盖 X=`[-0, 18]`。
|
||||||
|
- `8 -> 9 -> 8` 平移轨迹使体积在 `1770 -> 1855 -> 1770` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Pocket naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定真实 Profile、单 Solid 约束、平移变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pocket-polar-pattern`
|
||||||
|
|
||||||
|
`pocket->polar-pattern` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,生成体积 `970` 的有效单 Solid 和 42 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 单输入 builder,将 Pocket 结果绕锁定 Z 轴旋转复制并融合为单 Solid;名义体积 `1388.0087147`,边界覆盖 X=`[-5, 10]`、Y=`[0, 13.6602542]`。
|
||||||
|
- `30 -> 45 -> 30` 角度轨迹使体积在 `1388.0087147 -> 1545.7864376 -> 1388.0087147` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Pocket naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定真实 Profile、旋转实例融合、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-loft-fillet`
|
||||||
|
|
||||||
|
`loft->fillet` 已完成 Web 原生 history builder 拒绝分类,并显式记录 FreeCAD profile 接受差异:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_ThruSections` 双输入 builder,生成体积 `1500` 的有效单 Solid 和 24 条原生 history。
|
||||||
|
- 下游 `BRepFilletAPI_MakeFillet` 在 `0.4 -> 0.6 -> 0.4` 半径轨迹中稳定触发 `RuntimeError: table index is out of bounds`,三次尝试均没有产生 Shape、history 或 naming。
|
||||||
|
- FreeCAD 1.1.1 `Part::Fillet` 对同一 Loft Solid 重算成功,状态为 `Valid` / `Up-to-date`;该差异被锁定为 Web 原生 history builder 中止,没有伪造 FreeCAD 拒绝。
|
||||||
|
- transaction abort 后对象集与 Loft 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致。
|
||||||
|
- focused ordered-pair gate 已锁定 WASM abort 签名、FreeCAD 接受对照、精确回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-loft-chamfer`
|
||||||
|
|
||||||
|
`loft->chamfer` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_ThruSections` 双输入 builder,生成体积 `1500` 的有效单 Solid 和 24 条原生 history。
|
||||||
|
- 下游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,对 Loft 结果的原生边执行倒角。
|
||||||
|
- `0.4 -> 0.6 -> 0.4` 距离轨迹使体积在 `1489.1413333 -> 1475.952 -> 1489.1413333` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、26 Face,包含 150 条原生 history 记录。
|
||||||
|
- 上游 Loft naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、原生边选择、距离变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-loft-hole`
|
||||||
|
|
||||||
|
`loft->hole` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_ThruSections` 双输入 builder,生成体积 `1500` 的有效单 Solid 和 24 条原生 history。
|
||||||
|
- 下游使用真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` builder,以锁定位置和方向的圆柱刀具贯穿 Loft 结果。
|
||||||
|
- `1 -> 1.5 -> 1` 半径轨迹使体积在 `1462.3008882 -> 1415.1769984 -> 1462.3008882` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,包含 13 条原生 history 记录,下游 naming 状态为无歧义 `native-evidence`。
|
||||||
|
- 上游 Loft naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、圆柱减料、半径变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-loft-draft`
|
||||||
|
|
||||||
|
`loft->draft` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_ThruSections` 双输入 builder,生成体积 `1500` 的有效单 Solid 和 24 条原生 history。
|
||||||
|
- 下游使用真实 `BRepOffsetAPI_DraftAngle` 单输入 builder,对 Loft 结果的锁定原生 Face、中性面和拉伸方向执行拔模。
|
||||||
|
- `5 -> 8 -> 5` 角度轨迹使体积在 `1401.5752535 -> 1341.891561 -> 1401.5752535` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid,包含 5 条原生 history 记录。
|
||||||
|
- 上游 Loft naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、原生 Face 选择、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-loft-thickness`
|
||||||
|
|
||||||
|
`loft->thickness` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_ThruSections` 双输入 builder,生成体积 `1500` 的有效单 Solid 和 24 条原生 history。
|
||||||
|
- 下游使用真实 `BRepOffsetAPI_MakeThickSolid` 单输入 builder,对锁定的原生 Face 执行厚壳;名义结果为有效 1 Solid、11 Face,体积 `245.856`。
|
||||||
|
- `-0.4 -> -0.6 -> -0.4` offset 轨迹使体积在 `245.856 -> 358.464 -> 245.856` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果包含 38 条原生 history 记录,上游 Loft naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、原生 Face 选择、offset 变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-loft-linear-pattern`
|
||||||
|
|
||||||
|
`loft->linear-pattern` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_ThruSections` 双输入 builder,生成体积 `1500` 的有效单 Solid 和 24 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 单输入 builder,将 Loft 结果沿 X 方向平移复制并融合为单 Solid。
|
||||||
|
- `8 -> 9 -> 8` 平移轨迹使体积在 `2700 -> 2850 -> 2700` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、14 Face,边界覆盖 X=`[0, 18]`,包含 66 条原生 history 记录。
|
||||||
|
- 上游 Loft naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、单 Solid 约束、平移变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-loft-polar-pattern`
|
||||||
|
|
||||||
|
`loft->polar-pattern` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_ThruSections` 双输入 builder,生成体积 `1500` 的有效单 Solid 和 24 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 单输入 builder,将 Loft 结果绕锁定 Z 轴旋转复制并融合为单 Solid。
|
||||||
|
- `30 -> 45 -> 30` 角度轨迹使体积在 `2133.9745962 -> 2378.6796564 -> 2133.9745962` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、12 Face,边界覆盖 X=`[-5, 10]`、Y=`[0, 13.660254]`,包含 78 条原生 history 记录。
|
||||||
|
- 上游 Loft naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、旋转实例融合、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-loft-mirrored`
|
||||||
|
|
||||||
|
`loft->mirrored` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_ThruSections` 双输入 builder,生成体积 `1500` 的有效单 Solid 和 24 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 单输入 builder,将 Loft 结果绕锁定平面镜像复制并融合。
|
||||||
|
- 名义 X=5 镜像与 Loft 本体完全重合但仍保留 156 条原生 history;`5 -> 6 -> 5` 轨迹使体积在 `1500 -> 1800 -> 1500` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、6 Face,FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定。
|
||||||
|
- 上游 Loft naming 证据向下游传播;focused ordered-pair gate 已锁定重合名义对照、镜像实例融合、变异、恢复、history 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-loft-multi-transform`
|
||||||
|
|
||||||
|
`loft->multi-transform` 已完成原生接受分类,并闭合 Loft 起始行全部 19 个有序操作对:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_ThruSections` 双输入 builder,生成体积 `1500` 的有效单 Solid 和 24 条原生 history。
|
||||||
|
- 下游使用 ordered `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder,先执行 X 平移,再镜像平移结果并保留每个实例的原生追踪关系。
|
||||||
|
- `8 -> 9 -> 8` 首步 X 平移轨迹使体积在 `3900 -> 4200 -> 3900` 间变化,名义边界覆盖 X=`[-8, 18]`,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义与编辑态均包含 355 条原生 history,结果为有效 1 Solid、22 Face。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定 ordered builder、实例追踪、变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-fuse`
|
||||||
|
|
||||||
|
`pipe->fuse` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以真实 `2x3` Face section 沿 15 长度 spine 扫掠,生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Fuse` 双输入 builder,使用与 Pipe 保持交叠的工具。
|
||||||
|
- `0 -> 0.5 -> 0` 工具 X 偏移轨迹使体积在 `185 -> 192.5 -> 185` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、14 Face,包含 66 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定真实 Face section、双输入 builder、交叠变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-cut`
|
||||||
|
|
||||||
|
`pipe->cut` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Cut` 双输入 builder,以贯穿交叠的工具继续减料。
|
||||||
|
- `0 -> 0.5 -> 0` 工具 X 偏移轨迹使体积在 `66 -> 72 -> 66` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、6 Face、包含 117 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定 Face section、双输入减料 builder、偏移变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-common`
|
||||||
|
|
||||||
|
`pipe->common` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Common` 双输入 builder,使用与 Pipe 保持交叠的工具。
|
||||||
|
- `0 -> 0.5 -> 0` 工具 X 偏移轨迹使交集体积在 `24 -> 18 -> 24` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、6 Face、包含 132 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定 Face section、交叠变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-rotate`
|
||||||
|
|
||||||
|
`pipe->rotate` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform` 单输入 builder,将 Pipe 结果绕 Z 轴旋转。
|
||||||
|
- `15 -> 22.5 -> 15` 角度轨迹保持体积 `90`,改变边界并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、6 Face、包含 78 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定旋转变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-pad`
|
||||||
|
|
||||||
|
`pipe->pad` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- OCCT `BRepPrimAPI_MakePrism` 在 `5 -> 7.5 -> 5` 长度轨迹中稳定拒绝 Pipe Solid 输入,不产生结果 Shape 或 history。
|
||||||
|
- FreeCAD `PartDesign::Pad` 使用同一 Pipe Solid 作 Profile,返回 `FeatureExtrusion: Length: Could not extrude the sketch!`;结果 Shape 为空、状态包含 `Invalid`。
|
||||||
|
- transaction abort 后对象集与 Pipe 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、异常传输、精确诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-pocket`
|
||||||
|
|
||||||
|
`pipe->pocket` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,以贯穿 Profile 对 Pipe 结果执行减料。
|
||||||
|
- `5 -> 4 -> 5` 深度轨迹使体积在 `60 -> 66 -> 60` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、6 Face、包含 98 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定真实 Profile、双输入 builder、深度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-loft`
|
||||||
|
|
||||||
|
`pipe->loft` 已完成 FreeCAD 文档前置拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- OCCT `BRepOffsetAPI_ThruSections` 在 `false -> true -> false` ruled 轨迹中均生成有效 Shape,仅记为 `kernel-superset-only` 兼容性诊断,三次结果精确恢复。
|
||||||
|
- FreeCAD `Part::Loft` 对 Pipe Solid section 返回 `Profile shape is not a single vertex, edge, wire nor face.`,结果 Shape 为空、状态包含 `Invalid`。
|
||||||
|
- transaction abort 后对象集与 Pipe 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致。
|
||||||
|
- focused ordered-pair gate 已锁定 FreeCAD 决策权、OCCT 超集诊断、精确失败信息、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-pipe`
|
||||||
|
|
||||||
|
`pipe->pipe` 已完成 FreeCAD 文档前置拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- OCCT 下游 `BRepOffsetAPI_MakePipe` 在 `15 -> 12 -> 15` spine 长度轨迹中均产生无效 Shape(`kernel-invalid-result`),三次诊断精确恢复。
|
||||||
|
- FreeCAD `Part::Sweep` 对 Pipe Solid section 返回 `A fatal error occurred when making the sweep`,结果 Shape 为空、状态包含 `Invalid`。
|
||||||
|
- transaction abort 后对象集与 Pipe 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致。
|
||||||
|
- focused ordered-pair gate 已锁定 FreeCAD 决策权、OCCT 无效结果诊断、精确失败信息、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-revolution`
|
||||||
|
|
||||||
|
`pipe->revolution` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- OCCT `BRepPrimAPI_MakeRevol` 在 `360 -> 270 -> 360` 角度轨迹中稳定拒绝 Pipe Solid 输入,不产生结果 Shape 或 history。
|
||||||
|
- FreeCAD `Part::Revolution` 使用同一 Pipe Solid 作 Source,返回 `Solids are not Processed`;结果 Shape 为空、状态包含 `Invalid`。
|
||||||
|
- transaction abort 后对象集与 Pipe 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、异常传输、精确诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-groove`
|
||||||
|
|
||||||
|
`pipe->groove` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 Pipe 结果执行旋转减料。
|
||||||
|
- `360 -> 180 -> 360` 角度轨迹使体积在 `88.4292037 -> 90 -> 88.4292037` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、10 Face、包含 40 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定双输入 builder、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-fillet`
|
||||||
|
|
||||||
|
`pipe->fillet` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepFilletAPI_MakeFillet` 单输入 builder,对 Pipe 结果的全部原生边执行圆角。
|
||||||
|
- `0.4 -> 0.6 -> 0.4` 半径轨迹使体积在 `87.3388075 -> 84.1087417 -> 87.3388075` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、26 Face,包含 150 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定原生边选择、半径变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-chamfer`
|
||||||
|
|
||||||
|
`pipe->chamfer` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,对 Pipe 结果的全部原生边执行倒角。
|
||||||
|
- `0.4 -> 0.6 -> 0.4` 距离轨迹使体积在 `83.9413333 -> 76.752 -> 83.9413333` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、26 Face,包含 150 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定原生边选择、距离变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-hole`
|
||||||
|
|
||||||
|
`pipe->hole` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` builder,在截面中心 `(1, 1.5)` 以贯穿圆柱对 Pipe 结果减料。
|
||||||
|
- `0.4 -> 0.6 -> 0.4` 半径轨迹使体积在 `82.4601776 -> 73.0353997 -> 82.4601776` 间变化,保持有效单 Solid,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为 7 Face,包含 23 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定贯穿位置、半径变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-draft`
|
||||||
|
|
||||||
|
`pipe->draft` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 原生 Face 枚举确认端面索引 `0/5` 被 Draft builder 拒绝,侧面索引 `1/2/3/4` 可接受;下游锁定 `faceIndex: 1`、Z 向中性面和拉伸方向执行真实 `BRepOffsetAPI_DraftAngle`。
|
||||||
|
- `5 -> 8 -> 5` 角度轨迹使体积在 `70.3150507 -> 58.3783122 -> 70.3150507` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、6 Face,包含 5 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定侧面适用性、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-thickness`
|
||||||
|
|
||||||
|
`pipe->thickness` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepOffsetAPI_MakeThickSolid` 单输入 builder,对锁定的 Pipe 侧面执行厚壳。
|
||||||
|
- `-0.4 -> -0.6 -> -0.4` offset 轨迹使体积在 `45.696 -> 63.504 -> 45.696` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、11 Face,包含 38 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定侧面选择、offset 变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-linear-pattern`
|
||||||
|
|
||||||
|
`pipe->linear-pattern` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 单输入 builder;针对窄 Pipe 截面锁定交叠平移,避免沿用 Box 的 X=8 参数产生分离结果。
|
||||||
|
- `1.5 -> 1 -> 1.5` X 平移轨迹使体积在 `157.5 -> 135 -> 157.5` 间变化,名义和编辑态均保持有效单 Solid,并精确恢复摘要、history 与语义 naming。
|
||||||
|
- 名义结果为 14 Face,边界覆盖 X=`[0, 3.5]`,包含 66 条原生 history 记录,上游 Pipe naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定交叠融合、平移变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-polar-pattern`
|
||||||
|
|
||||||
|
`pipe->polar-pattern` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 单输入 builder,绕锁定 Z 轴复制并融合 Pipe 结果。
|
||||||
|
- `30 -> 45 -> 30` 角度轨迹使体积在 `132.3686028 -> 150 -> 132.3686028` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、12 Face,边界覆盖 X=`[-1.5, 2]`、Y=`[0, 3.5980764]`,包含 78 条原生 history 记录。
|
||||||
|
- 上游 Pipe naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定,focused ordered-pair gate 已锁定旋转融合、变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-mirrored`
|
||||||
|
|
||||||
|
`pipe->mirrored` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 单输入 builder;名义镜像平面锁定为 `x=1`,与 Pipe 截面对称重合,编辑平面为 `x=1.5` 并保持实例交叠。
|
||||||
|
- `1 -> 1.5 -> 1` 平面轨迹使体积在 `90 -> 135 -> 90` 间变化,恢复态保留名义 1 Solid 和 156 条原生 history,并精确恢复语义 naming。
|
||||||
|
- 编辑态为有效单 Solid、14 Face;上游 Pipe naming 证据向下游传播,FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定重合名义对照、交叠镜像、变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-pipe-multi-transform`
|
||||||
|
|
||||||
|
`pipe->multi-transform` 已完成原生接受分类,并闭合 Pipe 起始行全部 19 个有序操作对:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepOffsetAPI_MakePipe` 双输入 builder,以 `2x3` Face section 生成体积 `90` 的有效单 Solid 和 28 条原生 history。
|
||||||
|
- 下游使用 ordered `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder,先沿 X 平移,再绕 `x=5` 平面镜像;该实例布局原生形成有效 2 Solid 结果,没有伪装为单 Solid。
|
||||||
|
- `8 -> 7 -> 8` 首步 X 平移轨迹使体积在 `180 -> 270 -> 180` 间变化,并精确恢复名义摘要、300 条 history 与语义 naming。
|
||||||
|
- STEP 导入会同时创建 `Part::Feature`、聚合 `App::Part` 和 Origin 基准对象;FCStd harness 已改为只组合有限、有效、含 Solid 的 `Part::Feature`,消除了重复几何和 `1e100` 退化边界。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段均保持 2 Solid、12 Face、体积 `180` 与 naming evidence 一致;focused gate 已锁定多实体拓扑、导入筛选、变异、恢复和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-fuse`
|
||||||
|
|
||||||
|
`revolution->fuse` 已完成原生接受分类,并验证新的 Revolution 上游基线:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,绕锁定 Y 轴生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Fuse` 双输入 builder,工具与 Revolution 结果保持体积交叠。
|
||||||
|
- `0 -> 0.5 -> 0` 工具 X 偏移轨迹使体积在 `188.0229122 -> 192.1067282 -> 188.0229122` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义下游结果为有效 1 Solid、11 Face,包含 45 条原生 history 记录,上游 Revolution naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused ordered-pair gate 已锁定 Face Profile、旋转轴、融合变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-cut`
|
||||||
|
|
||||||
|
`revolution->cut` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Cut` 双输入 builder;`4 -> 3 -> 4` 工具尺寸轨迹覆盖同一正象限、摘要不变,未被采用。
|
||||||
|
- 最终使用小型交叠工具的 `0 -> 0.5 -> 0` X 偏移轨迹,使体积在 `68.3585388 -> 70.3585388 -> 68.3585388` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、8 Face,包含 75 条原生 history 记录,上游 Revolution naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused gate 已锁定弱轨迹拒绝、偏移变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-common`
|
||||||
|
|
||||||
|
`revolution->common` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Common` 双输入 builder,以贯穿正象限的工具和 Revolution 结果求交。
|
||||||
|
- `0 -> 0.5 -> 0` 工具 X 偏移轨迹使交集体积在 `12.3753114 -> 8.2914955 -> 12.3753114` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、5 Face,包含 100 条原生 history 记录,上游 Revolution naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused gate 已锁定交叠工具、偏移变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-rotate`
|
||||||
|
|
||||||
|
`revolution->rotate` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform` 单输入 builder,绕锁定 Z 轴旋转 Revolution 结果。
|
||||||
|
- `15 -> 22.5 -> 15` 角度轨迹保持体积 `75.3982237`,改变边界并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、4 Face,包含 40 条原生 history 记录,上游 Revolution naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定;focused gate 已锁定旋转变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-pad`
|
||||||
|
|
||||||
|
`revolution->pad` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid和 23 条原生 history。
|
||||||
|
- 下游 `BRepPrimAPI_MakePrism` 在 `5 -> 7.5 -> 5` 长度轨迹中稳定拒绝 Revolution Solid 输入,三次均不产生 Shape、history 或 naming。
|
||||||
|
- FreeCAD `PartDesign::Pad` 使用同一 Revolution Solid 作 Profile,返回 `FeatureExtrusion: Length: Could not extrude the sketch!`,结果 Shape 为空、状态包含 `Touched/Invalid`。
|
||||||
|
- transaction abort 后对象集与 Revolution 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致且文档无污染。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 builder、异常传输、精确诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-pocket`
|
||||||
|
|
||||||
|
`revolution->pocket` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid 和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,以同一截面 Profile 沿 Z 方向执行部分减料。
|
||||||
|
- `2 -> 1 -> 2` 深度轨迹使体积在 `64.8386964 -> 69.5677847 -> 64.8386964` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、7 Face,包含 104 条原生 history 记录,上游 Revolution naming 证据向下游传播。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段的 Shape 与 naming evidence 稳定;focused gate 已锁定部分深度、变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-loft`
|
||||||
|
|
||||||
|
`revolution->loft` 已完成 FreeCAD 文档前置拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid 和 23 条原生 history。
|
||||||
|
- OCCT `BRepOffsetAPI_ThruSections` 在 `false -> true -> false` ruled 轨迹中均产生 `isValid:false`、负体积的 `kernel-invalid-result`,三次诊断精确恢复。
|
||||||
|
- FreeCAD `Part::Loft` 对 Revolution Solid section 返回 `Profile shape is not a single vertex, edge, wire nor face.`,结果 Shape 为空、状态包含 `Touched/Invalid`。
|
||||||
|
- transaction abort 后对象集与 Revolution 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致。
|
||||||
|
- focused gate 已锁定 FreeCAD 决策权、OCCT 无效结果、精确失败信息、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-pipe`
|
||||||
|
|
||||||
|
`revolution->pipe` 已完成原生 builder 拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid 和 23 条原生 history。
|
||||||
|
- OCCT `BRepOffsetAPI_MakePipe` 在 `15 -> 12 -> 15` spine 长度轨迹中均于 builder 阶段抛出稳定 Emscripten C++ 异常,不产生 Shape、history 或 naming。
|
||||||
|
- FreeCAD `Part::Sweep` 对同一 Revolution Solid section 返回 `A fatal error occurred when making the sweep`,结果 Shape 为空、状态包含 `Touched/Invalid`。
|
||||||
|
- transaction abort 后对象集与 Revolution 源 Shape 完整恢复,干净 FCStd save/reopen/resave 三阶段一致。
|
||||||
|
- focused gate 已锁定异常阶段、输入数、精确失败信息、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-revolution`
|
||||||
|
|
||||||
|
`revolution->revolution` 已完成原生 builder 拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游再次使用 `BRepPrimAPI_MakeRevol`,对 Revolution Solid 在 `360 -> 270 -> 360` 角度轨迹中稳定于 builder 阶段抛出 Emscripten C++ 异常;三次均不产生 Shape、history 或 naming。
|
||||||
|
- FreeCAD `Part::Revolution` 使用同一 Revolution Solid 作为 Source,返回 `Solids are not Processed`,结果 Shape 为空、状态包含 `Touched/Invalid`。
|
||||||
|
- transaction abort 后对象集与 Revolution 源 Shape 完整恢复,源 Shape 体积、拓扑和 BREP 哈希保持一致;干净 FCStd save/reopen/resave 三阶段一致且文档无污染。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Revolution builder、异常传输、精确诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-groove`
|
||||||
|
|
||||||
|
`revolution->groove` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 Revolution 结果执行旋转减料;名义结果为有效 1 Solid、10 Face、体积 `71.0943912`,包含 43 条原生 history。
|
||||||
|
- `360 -> 180 -> 360` 角度轨迹使体积在 `71.0943912 -> 73.2463075 -> 71.0943912` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Revolution naming 证据向下游传播,恢复态语义摘要与名义态一致;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Revolution/Groove builder、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-fillet`
|
||||||
|
|
||||||
|
`revolution->fillet` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepFilletAPI_MakeFillet` 单输入 builder,对 Revolution 结果的原生边执行全边圆角;名义结果为有效 1 Solid、8 Face、体积 `73.6722933`,包含 48 条原生 history。
|
||||||
|
- `0.4 -> 0.6 -> 0.4` 半径轨迹使体积在 `73.6722933 -> 71.5148803 -> 73.6722933` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Revolution naming 证据向下游传播,恢复态语义摘要与名义态一致;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Revolution/Fillet builder、原生边选择、半径变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-chamfer`
|
||||||
|
|
||||||
|
`revolution->chamfer` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,对 Revolution 结果的原生边执行全边倒角;名义结果为有效 1 Solid、8 Face、体积 `71.3769851`,包含 48 条原生 history。
|
||||||
|
- `0.4 -> 0.6 -> 0.4` 距离轨迹使体积在 `71.3769851 -> 66.3504368 -> 71.3769851` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Revolution naming 证据向下游传播,恢复态语义摘要与名义态一致;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Revolution/Chamfer builder、原生边选择、距离变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-hole`
|
||||||
|
|
||||||
|
`revolution->hole` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` builder,在锁定位置 `[0, 1.5, 0]`、方向 `+Z` 和深度 `0.1` 的局部圆柱刀具上执行减料;名义结果为有效 1 Solid、8 Face、体积 `75.3729574`,包含 19 条原生 history。
|
||||||
|
- `0.4 -> 0.6 -> 0.4` 半径轨迹使体积在 `75.3729574 -> 75.3414747 -> 75.3729574` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Revolution naming 证据向下游传播,恢复态语义摘要与名义态一致;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Revolution/Hole builder、局部圆柱刀具、半径变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-draft`
|
||||||
|
|
||||||
|
`revolution->draft` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepOffsetAPI_DraftAngle` 单输入 builder,对锁定原生 Face、中性面和 +Z 拉伸方向执行拔模;名义结果为有效 1 Solid、4 Face、体积 `75.3982238`,包含 3 条原生 history。
|
||||||
|
- `5 -> 8 -> 5` 角度轨迹使 Y 方向边界在 `-0.3154312 -> -0.5067054 -> -0.3154312` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Revolution naming 证据向下游传播,下游获得无歧义 `native-evidence` naming;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Revolution/DraftAngle builder、原生 Face 选择、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-thickness`
|
||||||
|
|
||||||
|
`revolution->thickness` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepOffsetAPI_MakeThickSolid` 单输入 builder,对锁定原生 Face 执行厚壳;名义结果为有效 1 Solid、8 Face、体积 `26.7412367`,包含 39 条原生 history。
|
||||||
|
- `-0.4 -> -0.6 -> -0.4` offset 轨迹使体积在 `26.7412367 -> 38.9808816 -> 26.7412367` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Revolution naming 证据向下游传播,恢复态语义摘要与名义态一致;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Revolution/Thickness builder、原生 Face 选择、offset 变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-linear-pattern`
|
||||||
|
|
||||||
|
`revolution->linear-pattern` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder,将 Revolution 结果沿 X 方向复制并融合;专用 `4 -> 3 -> 4` 平移轨迹确保所有状态保持单 Solid。
|
||||||
|
- 平移轨迹使体积在 `132.2115549 -> 126.3867082 -> 132.2115549` 间变化,并精确恢复名义摘要、history 与语义 naming;名义结果为 12 Face,包含 53 条原生 history。
|
||||||
|
- 上游 Revolution naming 证据向下游传播,恢复态语义摘要与名义态一致;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Revolution/LinearPattern builder、单 Solid 约束、平移变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-polar-pattern`
|
||||||
|
|
||||||
|
`revolution->polar-pattern` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 默认 `30°` 轨迹触发原生 WASM 越界中止,未被误记为接受;改用保持实例相交且稳定的 `10 -> 15 -> 10` 专用角度轨迹。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder,将旋转实例融合为单 Solid;角度轨迹使体积在 `87.2727929 -> 92.4535717 -> 87.2727929` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 名义结果为有效 1 Solid、14 Face,包含 70 条原生 history;上游 Revolution naming 证据向下游传播,FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定专用角度轨迹、单 Solid 约束、变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-mirrored`
|
||||||
|
|
||||||
|
`revolution->mirrored` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder,将 Revolution 结果关于 X=`0` 镜像并融合为单 Solid;专用 `0 -> 0.5 -> 0` 平面轨迹避免默认分离实例。
|
||||||
|
- 平面轨迹使体积在 `120.1447575 -> 126.3867082 -> 120.1447575` 间变化,并精确恢复名义摘要、history 与语义 naming;名义结果为 14 Face,包含 92 条原生 history。
|
||||||
|
- 上游 Revolution naming 证据向下游传播,恢复态语义摘要与名义态一致;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定专用镜像平面、单 Solid 约束、变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-revolution-multi-transform`
|
||||||
|
|
||||||
|
`revolution->multi-transform` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `2x3` Face Profile 和 `BRepPrimAPI_MakeRevol` 单输入 builder,生成体积 `75.3982237` 的有效单 Solid、4 Face 和 23 条原生 history。
|
||||||
|
- 下游使用 ordered `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder,锁定镜像平面 `X=0`,按平移和镜像顺序生成并融合四个实例;名义结果为有效 1 Solid、48 Face、体积 `190.7882692`,包含 313 条原生 history。
|
||||||
|
- `4 -> 3 -> 4` 平移轨迹使体积在 `190.7882692 -> 155.9773894 -> 190.7882692` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Revolution naming 证据向下游传播,恢复态语义摘要与名义态一致;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定 ordered builder、镜像平面、单 Solid 约束、平移变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-fuse`
|
||||||
|
|
||||||
|
`groove->fuse` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 10x10 Box 执行旋转减料,生成体积 `995.287611` 的有效单 Solid、10 Face 和 18 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Fuse` 双输入 builder;专用 `8 -> 7 -> 8` 工具 X 偏移轨迹保持实体交叠并融合为单 Solid。
|
||||||
|
- 轨迹使体积在 `1070.287611 -> 1045.287611 -> 1070.287611` 间变化,并精确恢复名义摘要、history 与语义 naming;名义结果为 17 Face,包含 52 条原生 history。
|
||||||
|
- 上游 Groove naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Groove/Fuse builder、专用交叠轨迹、变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-cut`
|
||||||
|
|
||||||
|
`groove->cut` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 10x10 Box 执行旋转减料,生成体积 `995.287611` 的有效单 Solid、10 Face 和 18 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Cut` 双输入 builder,对 Groove 结果继续执行减料;名义结果为有效 1 Solid、14 Face、体积 `931.287611`,包含 22 条原生 history。
|
||||||
|
- `4 -> 3 -> 4` 工具尺寸轨迹使体积在 `931.287611 -> 968.287611 -> 931.287611` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Groove naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Groove/Cut builder、工具变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-common`
|
||||||
|
|
||||||
|
`groove->common` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 10x10 Box 执行旋转减料,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- 下游使用真实 `BRepAlgoAPI_Common` 双输入 builder,与 Groove 结果及交叠工具执行布尔交集;名义结果为有效 1 Solid、6 Face、体积 `75`,包含 197 条原生 history。
|
||||||
|
- `7 -> 6 -> 7` 工具 X 偏移轨迹使体积在 `75 -> 100 -> 75` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Groove naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Groove/Common builder、交叠轨迹、变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-rotate`
|
||||||
|
|
||||||
|
`groove->rotate` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 10x10 Box 执行旋转减料,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform` 单输入 builder,对 Groove 结果绕 Z 轴旋转;名义结果保持有效 1 Solid、10 Face、体积 `995.287611`,包含 154 条原生 history。
|
||||||
|
- `15 -> 22.5 -> 15` 角度轨迹改变包围盒(名义 `[-2.5881906, -1e-7, -1e-7, 9.6592584, 12.2474488, 10.0000001]`,编辑态 `[-3.8268344, -1e-7, -1e-7, 9.2387954, 13.0656297, 10.0000001]`),并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Groove naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Groove/Transform builder、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-pad`
|
||||||
|
|
||||||
|
`groove->pad` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 10x10 Box 执行旋转减料,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- OCCT `BRepPrimAPI_MakePrism` 对 Groove Solid 在 `5 -> 7.5 -> 5` 长度轨迹中稳定于 builder 阶段拒绝,三次均不产生结果 Shape 或 history。
|
||||||
|
- FreeCAD `PartDesign::Pad` 使用同一 Groove Solid 作为 Profile,返回 `FeatureExtrusion: Length: Could not extrude the sketch!`,结果 Shape 为空且状态含 `Invalid`;未伪造下游命名或变异证据。
|
||||||
|
- transaction abort 后对象集、源 Shape 和 BREP 哈希精确恢复;干净 FCStd save/reopen/resave 三阶段一致,focused gate 已锁定拒绝阶段、诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-pocket`
|
||||||
|
|
||||||
|
`groove->pocket` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 10x10 Box 执行旋转减料,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- 下游使用真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,对 Groove 结果执行减料拉伸;名义结果为有效 1 Solid、13 Face、体积 `966.8584073`,包含 91 条原生 history。
|
||||||
|
- `5 -> 4 -> 5` 深度轨迹使体积在 `966.8584073 -> 972.8584073 -> 966.8584073` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Groove naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Groove/Pocket builder、深度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-loft`
|
||||||
|
|
||||||
|
`groove->loft` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 10x10 Box 执行旋转减料,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- OCCT `BRepOffsetAPI_ThruSections` 在 `false -> true -> false` ruled 轨迹中生成有效 Shape 和 24 条 history,但该结果仅作为 `kernel-superset-only` 诊断,不提升 FreeCAD 能力。
|
||||||
|
- FreeCAD `Part::Loft` 对 Groove Solid section 返回 `Profile shape is not a single vertex, edge, wire nor face.`,结果 Shape 为空且状态含 `Invalid`;未伪造下游命名或接受变异证据。
|
||||||
|
- transaction abort 后对象集、源 Shape 和 BREP 哈希精确恢复;干净 FCStd save/reopen/resave 三阶段一致,focused gate 已锁定 FreeCAD 决策权、kernel 诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-pipe`
|
||||||
|
|
||||||
|
`groove->pipe` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 10x10 Box 执行旋转减料,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- OCCT `BRepOffsetAPI_MakePipe` 在 `15 -> 12 -> 15` spine 长度轨迹中均产生无效结果,仅记为 `kernel-invalid-result`,不伪造接受 Shape/history。
|
||||||
|
- FreeCAD `Part::Sweep` 对 Groove Solid section 返回 `A fatal error occurred when making the sweep`,结果 Shape 为空且状态含 `Invalid`。
|
||||||
|
- transaction abort 后对象集、源 Shape 和 BREP 哈希精确恢复;干净 FCStd save/reopen/resave 三阶段一致,focused gate 已锁定 FreeCAD 决策权、kernel 无效诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-revolution`
|
||||||
|
|
||||||
|
`groove->revolution` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 10x10 Box 执行旋转减料,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- OCCT `BRepPrimAPI_MakeRevol` 对 Groove Solid 在 `360 -> 270 -> 360` 角度轨迹中稳定于 builder 阶段拒绝,三次均不产生结果 Shape 或 history。
|
||||||
|
- FreeCAD `Part::Revolution` 使用同一 Groove Solid 作为 Source,返回 `Solids are not Processed`,结果 Shape 为空且状态含 `Invalid`;未伪造下游命名或变异证据。
|
||||||
|
- transaction abort 后对象集、源 Shape 和 BREP 哈希精确恢复;干净 FCStd save/reopen/resave 三阶段一致,focused gate 已锁定拒绝阶段、诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-groove`
|
||||||
|
|
||||||
|
`groove->groove` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 10x10 Box 执行旋转减料,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- 下游再次使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,并将第二阶段 profile 真实放置在 `profileX=2` 以切削不同半径区域;名义结果为有效 1 Solid、14 Face、体积 `983.5066386`,包含 18 条原生 history。
|
||||||
|
- `360 -> 180 -> 360` 角度轨迹改变拓扑(编辑态 11 Face、28 Edge)并精确恢复名义摘要、history 与语义 naming;未采用同 profile 的 no-op 轨迹。
|
||||||
|
- 上游 Groove naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定。
|
||||||
|
- focused ordered-pair gate 已锁定两阶段 Groove/Groove builder、专用 profile、角度变异、恢复、history、naming 和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-fillet`
|
||||||
|
|
||||||
|
`groove->fillet` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,对 10x10 Box 执行旋转减料,生成有效 1 Solid、体积 `995.287611`、10 Face、24 Edge 和 18 条原生 history。
|
||||||
|
- 下游按 native contract 使用 `BRepFilletAPI_MakeFillet` 对全部 24 条源边执行圆角;`0.4 -> 0.6 -> 0.4` 半径轨迹三次均稳定在 OCCT builder 阶段以 Emscripten C++ 异常拒绝,没有产生 Shape、history 或下游 naming。
|
||||||
|
- FreeCAD 1.1.1 `Part::Fillet` 对同一 Groove Solid 和全部源边返回 `BRep_API: command not done`;结果 Shape 为空、状态包含 `Invalid`,与 OCCT 拒绝结论一致。
|
||||||
|
- transaction abort 后对象集、源 Shape 和 BREP 哈希精确恢复;干净 FCStd save/reopen/resave 三阶段一致,focused gate 已锁定拒绝阶段、异常传输、精确诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-chamfer`
|
||||||
|
|
||||||
|
`groove->chamfer` 已完成原生拒绝分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,生成有效 1 Solid、体积 `995.287611`、10 Face、24 Edge 和 18 条原生 history。
|
||||||
|
- 下游按 native contract 使用 `BRepFilletAPI_MakeChamfer` 对全部 24 条源边执行对称倒角;`0.4 -> 0.6 -> 0.4` 距离轨迹稳定触发原生 WASM `memory access out of bounds`,三次均不产生 Shape、history 或下游 naming。
|
||||||
|
- FreeCAD 1.1.1 `Part::Chamfer` 对同一 Groove Solid 和全部源边返回 `BRep_API: command not done`;结果 Shape 为空且状态包含 `Invalid`。
|
||||||
|
- transaction abort 后对象集、源 Shape 和 BREP 哈希精确恢复;干净 FCStd save/reopen/resave 三阶段一致,focused gate 已锁定 WASM 崩溃签名、FreeCAD 精确诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-hole`
|
||||||
|
|
||||||
|
`groove->hole` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- 下游使用真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` builder,在 Groove 结果中心执行贯穿孔;名义结果为有效 1 Solid、11 Face、体积 `963.8716845`,包含 23 条原生 history。
|
||||||
|
- `1 -> 1.5 -> 1` 半径轨迹使体积在 `963.8716845 -> 924.6017763 -> 963.8716845` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 下游获得无歧义 `native-evidence` naming,上游 Groove naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定,focused gate 已锁定两阶段 builder、变异、恢复和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-draft`
|
||||||
|
|
||||||
|
`groove->draft` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- 下游使用真实 `BRepOffsetAPI_DraftAngle` 单输入 builder,对锁定的原生 Face、中性面和 +Z 方向执行拔模;名义结果为有效 1 Solid、10 Face、体积 `951.8050786`,包含 9 条原生 history。
|
||||||
|
- `5 -> 8 -> 5` 角度轨迹使体积在 `951.8050786 -> 925.4360727 -> 951.8050786` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 下游 9 条选定 history 均形成无歧义 `native-evidence` naming;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定,focused gate 已锁定 Face 选择、方向、变异、恢复和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-thickness`
|
||||||
|
|
||||||
|
`groove->thickness` 已完成原生拒绝分类,并显式保留 Web 原生与 FreeCAD profile 的能力差异:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- Web 原生下游使用 `BRepOffsetAPI_MakeThickSolid` 对锁定的第二个 Face 执行厚壳;`-0.4 -> -0.6 -> -0.4` offset 轨迹稳定触发 WASM `memory access out of bounds`,三次均不产生 Shape、history 或下游 naming。
|
||||||
|
- FreeCAD 1.1.1 `Part::Thickness` 对同一 Groove Solid、`Face2` 和 `Value=-0.4` 生成有效 Shape,状态为 `Valid`;该 FreeCAD 接受证据没有被用于伪造 Web 原生接受能力。
|
||||||
|
- transaction abort 后对象集、源 Shape 和 BREP 哈希精确恢复;干净 FCStd save/reopen/resave 三阶段一致,focused gate 已锁定崩溃签名、FreeCAD 接受诊断、回滚和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-linear-pattern`
|
||||||
|
|
||||||
|
`groove->linear-pattern` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder,沿 X 方向复制并融合 Groove 结果;名义结果为有效 1 Solid、19 Face、体积 `1795.287611`,包含 119 条原生 history。
|
||||||
|
- `8 -> 9 -> 8` 平移轨迹始终保持单 Solid,使体积在 `1795.287611 -> 1894.1260552 -> 1795.287611` 间变化,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Groove naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定,focused gate 已锁定交叠融合、变异、恢复和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-polar-pattern`
|
||||||
|
|
||||||
|
`groove->polar-pattern` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- 默认 `30°` 及小角度 `10°/15°` 交叠融合轨迹均触发原生 WASM 越界,未被误记为接受;最终采用稳定且仍具真实拓扑变异的 `90 -> 120 -> 90` 专用轨迹。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder;`90°` 名义态为有效 1 Solid、19 Face、体积 `1990.575222` 和 98 条 history,`120°` 编辑态真实变为 2 Solid,恢复后摘要、history 与语义 naming 精确复原。
|
||||||
|
- FreeCAD FCStd save/reopen/resave 三阶段保持名义单 Solid Shape 与 naming evidence 一致;focused gate 已锁定专用角度轨迹、真实多实体编辑态、恢复和持久化证据。
|
||||||
|
|
||||||
|
### `TSN-PAIR-groove-mirrored`
|
||||||
|
|
||||||
|
`groove->mirrored` 已完成原生接受分类:
|
||||||
|
|
||||||
|
- 上游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder,生成有效 1 Solid、体积 `995.287611`、10 Face 和 18 条原生 history。
|
||||||
|
- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder;关于 `x=5` 的名义镜像让两侧缺口互补融合,得到有效 1 Solid、10 Face、体积 `1000` 和 216 条原生 history。
|
||||||
|
- `5 -> 6 -> 5` 镜像平面轨迹使体积在 `1000 -> 1190.575222 -> 1000` 间变化,编辑态增至 22 Face,并精确恢复名义摘要、history 与语义 naming。
|
||||||
|
- 上游 Groove naming 证据向下游传播;FreeCAD FCStd save/reopen/resave 三阶段 Shape 与 naming evidence 稳定,focused gate 已锁定镜像平面、互补融合、变异、恢复和持久化证据。
|
||||||
|
|
||||||
后续任务必须从机器队列的最新 `nextTask` 继续,不在本文手工维护任务名称。
|
后续任务必须从机器队列的最新 `nextTask` 继续,不在本文手工维护任务名称。
|
||||||
|
|||||||
Reference in New Issue
Block a user