feat: advance TSN drift and ordered pair evidence
This commit is contained in:
@@ -12,12 +12,12 @@
|
|||||||
"transitionUnit": "one ordered operation pair",
|
"transitionUnit": "one ordered operation pair",
|
||||||
"driftUnit": "one native case"
|
"driftUnit": "one native case"
|
||||||
},
|
},
|
||||||
"nextTask": "TSN-DRIFT-002",
|
"nextTask": "TSN-PAIR-fuse-pad",
|
||||||
"summary": {
|
"summary": {
|
||||||
"tasks": 487,
|
"tasks": 487,
|
||||||
"completed": 119,
|
"completed": 134,
|
||||||
"inProgress": 1,
|
"inProgress": 1,
|
||||||
"pending": 367
|
"pending": 352
|
||||||
},
|
},
|
||||||
"milestones": [
|
"milestones": [
|
||||||
{
|
{
|
||||||
@@ -1477,7 +1477,7 @@
|
|||||||
{
|
{
|
||||||
"id": "TSN-RECOVERY-DRIFT",
|
"id": "TSN-RECOVERY-DRIFT",
|
||||||
"exactTask": "EX-TSN-04",
|
"exactTask": "EX-TSN-04",
|
||||||
"status": "in_progress",
|
"status": "completed",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"id": "TSN-DRIFT-000",
|
"id": "TSN-DRIFT-000",
|
||||||
@@ -1522,7 +1522,7 @@
|
|||||||
{
|
{
|
||||||
"id": "TSN-DRIFT-002",
|
"id": "TSN-DRIFT-002",
|
||||||
"title": "Classify recovered naming evolution for partdesign-reverse",
|
"title": "Classify recovered naming evolution for partdesign-reverse",
|
||||||
"status": "in_progress",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-DRIFT-001"
|
"TSN-DRIFT-001"
|
||||||
],
|
],
|
||||||
@@ -1532,12 +1532,17 @@
|
|||||||
0,
|
0,
|
||||||
9
|
9
|
||||||
],
|
],
|
||||||
|
"classification": "allowed_evolution",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-recovered-naming-classification.json",
|
||||||
|
"native-history-stabilizes-after-edit-restore"
|
||||||
|
],
|
||||||
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-DRIFT-003",
|
"id": "TSN-DRIFT-003",
|
||||||
"title": "Classify recovered naming evolution for partdesign-taper",
|
"title": "Classify recovered naming evolution for partdesign-taper",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-DRIFT-002"
|
"TSN-DRIFT-002"
|
||||||
],
|
],
|
||||||
@@ -1547,12 +1552,17 @@
|
|||||||
0,
|
0,
|
||||||
9
|
9
|
||||||
],
|
],
|
||||||
|
"classification": "allowed_evolution",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-recovered-naming-classification.json",
|
||||||
|
"native-history-stabilizes-after-edit-restore"
|
||||||
|
],
|
||||||
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-DRIFT-004",
|
"id": "TSN-DRIFT-004",
|
||||||
"title": "Classify recovered naming evolution for partdesign-twoside",
|
"title": "Classify recovered naming evolution for partdesign-twoside",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-DRIFT-003"
|
"TSN-DRIFT-003"
|
||||||
],
|
],
|
||||||
@@ -1562,12 +1572,17 @@
|
|||||||
0,
|
0,
|
||||||
9
|
9
|
||||||
],
|
],
|
||||||
|
"classification": "allowed_evolution",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-recovered-naming-classification.json",
|
||||||
|
"native-history-stabilizes-after-edit-restore"
|
||||||
|
],
|
||||||
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-DRIFT-005",
|
"id": "TSN-DRIFT-005",
|
||||||
"title": "Classify recovered naming evolution for partdesign-pocket",
|
"title": "Classify recovered naming evolution for partdesign-pocket",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-DRIFT-004"
|
"TSN-DRIFT-004"
|
||||||
],
|
],
|
||||||
@@ -1578,12 +1593,17 @@
|
|||||||
9,
|
9,
|
||||||
11
|
11
|
||||||
],
|
],
|
||||||
|
"classification": "allowed_evolution",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-recovered-naming-classification.json",
|
||||||
|
"native-history-stabilizes-after-edit-restore"
|
||||||
|
],
|
||||||
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-DRIFT-006",
|
"id": "TSN-DRIFT-006",
|
||||||
"title": "Classify recovered naming evolution for partdesign-pocket-through",
|
"title": "Classify recovered naming evolution for partdesign-pocket-through",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-DRIFT-005"
|
"TSN-DRIFT-005"
|
||||||
],
|
],
|
||||||
@@ -1594,12 +1614,17 @@
|
|||||||
9,
|
9,
|
||||||
11
|
11
|
||||||
],
|
],
|
||||||
|
"classification": "allowed_evolution",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-recovered-naming-classification.json",
|
||||||
|
"native-history-stabilizes-after-edit-restore"
|
||||||
|
],
|
||||||
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-DRIFT-007",
|
"id": "TSN-DRIFT-007",
|
||||||
"title": "Classify recovered naming evolution for partdesign-pocket-midplane",
|
"title": "Classify recovered naming evolution for partdesign-pocket-midplane",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-DRIFT-006"
|
"TSN-DRIFT-006"
|
||||||
],
|
],
|
||||||
@@ -1610,12 +1635,17 @@
|
|||||||
9,
|
9,
|
||||||
11
|
11
|
||||||
],
|
],
|
||||||
|
"classification": "allowed_evolution",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-recovered-naming-classification.json",
|
||||||
|
"native-history-stabilizes-after-edit-restore"
|
||||||
|
],
|
||||||
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-DRIFT-008",
|
"id": "TSN-DRIFT-008",
|
||||||
"title": "Classify recovered naming evolution for partdesign-pocket-twoside",
|
"title": "Classify recovered naming evolution for partdesign-pocket-twoside",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-DRIFT-007"
|
"TSN-DRIFT-007"
|
||||||
],
|
],
|
||||||
@@ -1626,12 +1656,17 @@
|
|||||||
9,
|
9,
|
||||||
11
|
11
|
||||||
],
|
],
|
||||||
|
"classification": "allowed_evolution",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-recovered-naming-classification.json",
|
||||||
|
"native-history-stabilizes-after-edit-restore"
|
||||||
|
],
|
||||||
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-DRIFT-009",
|
"id": "TSN-DRIFT-009",
|
||||||
"title": "Classify recovered naming evolution for partdesign-pocket-taper",
|
"title": "Classify recovered naming evolution for partdesign-pocket-taper",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-DRIFT-008"
|
"TSN-DRIFT-008"
|
||||||
],
|
],
|
||||||
@@ -1642,12 +1677,17 @@
|
|||||||
9,
|
9,
|
||||||
11
|
11
|
||||||
],
|
],
|
||||||
|
"classification": "allowed_evolution",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-recovered-naming-classification.json",
|
||||||
|
"native-history-stabilizes-after-edit-restore"
|
||||||
|
],
|
||||||
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-DRIFT-010",
|
"id": "TSN-DRIFT-010",
|
||||||
"title": "Classify recovered naming evolution for partdesign-pocket-up-to-face",
|
"title": "Classify recovered naming evolution for partdesign-pocket-up-to-face",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-DRIFT-009"
|
"TSN-DRIFT-009"
|
||||||
],
|
],
|
||||||
@@ -1658,28 +1698,43 @@
|
|||||||
9,
|
9,
|
||||||
11
|
11
|
||||||
],
|
],
|
||||||
|
"classification": "allowed_evolution",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-recovered-naming-classification.json",
|
||||||
|
"native-history-stabilizes-after-edit-restore"
|
||||||
|
],
|
||||||
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
"exit": "the case is classified as stable semantics, allowed evolution, or an implementation defect"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-PROD-DRIFT-000",
|
"id": "TSN-PROD-DRIFT-000",
|
||||||
"title": "Classify production restore topology drift for cut",
|
"title": "Classify production restore topology drift for cut",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-DRIFT-010"
|
"TSN-DRIFT-010"
|
||||||
],
|
],
|
||||||
"operation": "cut",
|
"operation": "cut",
|
||||||
"driftStages": 3,
|
"driftStages": 3,
|
||||||
|
"classification": "allowed_evolution",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-production-drift-classification.json",
|
||||||
|
"native-downstream-topology-stabilizes-after-edit-restore"
|
||||||
|
],
|
||||||
"exit": "every changed downstream stage has a native comparison and classification"
|
"exit": "every changed downstream stage has a native comparison and classification"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-PROD-DRIFT-001",
|
"id": "TSN-PROD-DRIFT-001",
|
||||||
"title": "Classify production restore topology drift for rotate",
|
"title": "Classify production restore topology drift for rotate",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-PROD-DRIFT-000"
|
"TSN-PROD-DRIFT-000"
|
||||||
],
|
],
|
||||||
"operation": "rotate",
|
"operation": "rotate",
|
||||||
"driftStages": 2,
|
"driftStages": 2,
|
||||||
|
"classification": "allowed_evolution",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-production-drift-classification.json",
|
||||||
|
"native-downstream-topology-stabilizes-after-edit-restore"
|
||||||
|
],
|
||||||
"exit": "every changed downstream stage has a native comparison and classification"
|
"exit": "every changed downstream stage has a native comparison and classification"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1687,52 +1742,64 @@
|
|||||||
{
|
{
|
||||||
"id": "TSN-ORDERED-PAIRS",
|
"id": "TSN-ORDERED-PAIRS",
|
||||||
"exactTask": "EX-TSN-04",
|
"exactTask": "EX-TSN-04",
|
||||||
"status": "pending",
|
"status": "in_progress",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"id": "TSN-PAIR-fuse-fuse",
|
"id": "TSN-PAIR-fuse-fuse",
|
||||||
"title": "Classify ordered operation pair fuse->fuse",
|
"title": "Classify ordered operation pair fuse->fuse",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [],
|
||||||
"TSN-PROD-DRIFT-001"
|
|
||||||
],
|
|
||||||
"pair": "fuse->fuse",
|
"pair": "fuse->fuse",
|
||||||
|
"classification": "accepted",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-ordered-operation-pair-classification.json",
|
||||||
|
"native-builders-mutation-naming-and-fcstd-resave-pass"
|
||||||
|
],
|
||||||
"exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence"
|
"exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-PAIR-fuse-cut",
|
"id": "TSN-PAIR-fuse-cut",
|
||||||
"title": "Classify ordered operation pair fuse->cut",
|
"title": "Classify ordered operation pair fuse->cut",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [],
|
||||||
"TSN-PROD-DRIFT-001"
|
|
||||||
],
|
|
||||||
"pair": "fuse->cut",
|
"pair": "fuse->cut",
|
||||||
|
"classification": "accepted",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-ordered-operation-pair-classification.json",
|
||||||
|
"native-builders-mutation-naming-and-fcstd-resave-pass"
|
||||||
|
],
|
||||||
"exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence"
|
"exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-PAIR-fuse-common",
|
"id": "TSN-PAIR-fuse-common",
|
||||||
"title": "Classify ordered operation pair fuse->common",
|
"title": "Classify ordered operation pair fuse->common",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [],
|
||||||
"TSN-PROD-DRIFT-001"
|
|
||||||
],
|
|
||||||
"pair": "fuse->common",
|
"pair": "fuse->common",
|
||||||
|
"classification": "accepted",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-ordered-operation-pair-classification.json",
|
||||||
|
"native-builders-mutation-naming-and-fcstd-resave-pass"
|
||||||
|
],
|
||||||
"exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence"
|
"exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-PAIR-fuse-rotate",
|
"id": "TSN-PAIR-fuse-rotate",
|
||||||
"title": "Classify ordered operation pair fuse->rotate",
|
"title": "Classify ordered operation pair fuse->rotate",
|
||||||
"status": "pending",
|
"status": "completed",
|
||||||
"dependencies": [
|
"dependencies": [],
|
||||||
"TSN-PROD-DRIFT-001"
|
|
||||||
],
|
|
||||||
"pair": "fuse->rotate",
|
"pair": "fuse->rotate",
|
||||||
|
"classification": "accepted",
|
||||||
|
"evidence": [
|
||||||
|
"config/freecad-ordered-operation-pair-classification.json",
|
||||||
|
"native-builders-mutation-naming-and-fcstd-resave-pass"
|
||||||
|
],
|
||||||
"exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence"
|
"exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TSN-PAIR-fuse-pad",
|
"id": "TSN-PAIR-fuse-pad",
|
||||||
"title": "Classify ordered operation pair fuse->pad",
|
"title": "Classify ordered operation pair fuse->pad",
|
||||||
"status": "pending",
|
"status": "in_progress",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"TSN-PROD-DRIFT-001"
|
"TSN-PROD-DRIFT-001"
|
||||||
],
|
],
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -38,8 +38,8 @@
|
|||||||
"name": "Fuse01",
|
"name": "Fuse01",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 40,
|
"relationCount": 40,
|
||||||
"relationDigest": "15f38b7d771c2d966a5bed886befdf4da68371401863d9d9f7b8ccb19627eabc",
|
"relationDigest": "d3eba0b5d86842a31e1a79b8fe98340a1b197451bb4caa682bdee26ed62748d8",
|
||||||
"semanticNameDigest": "dece2b8f8787384f070c14f62691734aaf1b55d585f92182282f3e377a8c6ecf",
|
"semanticNameDigest": "24d8c54ee7bfa29609e3840c13ca5889c8c97f285b4645a7c1e9f6b55fe7fc04",
|
||||||
"typeId": "Part::Fuse"
|
"typeId": "Part::Fuse"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -73,8 +73,8 @@
|
|||||||
"name": "Fuse01",
|
"name": "Fuse01",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 40,
|
"relationCount": 40,
|
||||||
"relationDigest": "15f38b7d771c2d966a5bed886befdf4da68371401863d9d9f7b8ccb19627eabc",
|
"relationDigest": "d3eba0b5d86842a31e1a79b8fe98340a1b197451bb4caa682bdee26ed62748d8",
|
||||||
"semanticNameDigest": "dece2b8f8787384f070c14f62691734aaf1b55d585f92182282f3e377a8c6ecf",
|
"semanticNameDigest": "24d8c54ee7bfa29609e3840c13ca5889c8c97f285b4645a7c1e9f6b55fe7fc04",
|
||||||
"typeId": "Part::Fuse"
|
"typeId": "Part::Fuse"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -108,8 +108,8 @@
|
|||||||
"name": "Fuse01",
|
"name": "Fuse01",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 40,
|
"relationCount": 40,
|
||||||
"relationDigest": "15f38b7d771c2d966a5bed886befdf4da68371401863d9d9f7b8ccb19627eabc",
|
"relationDigest": "d3eba0b5d86842a31e1a79b8fe98340a1b197451bb4caa682bdee26ed62748d8",
|
||||||
"semanticNameDigest": "dece2b8f8787384f070c14f62691734aaf1b55d585f92182282f3e377a8c6ecf",
|
"semanticNameDigest": "24d8c54ee7bfa29609e3840c13ca5889c8c97f285b4645a7c1e9f6b55fe7fc04",
|
||||||
"typeId": "Part::Fuse"
|
"typeId": "Part::Fuse"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -716,8 +716,8 @@
|
|||||||
"name": "Common07",
|
"name": "Common07",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 8,
|
"relationCount": 8,
|
||||||
"relationDigest": "7794560879873d1dd1468a41ff9a0fed2e5912ac6ebf493d0de6725aede5d014",
|
"relationDigest": "295286347d8935ff0fc96fe706a211f55c042edd96c5f714a6ef31d2b9eac359",
|
||||||
"semanticNameDigest": "9d9b0bb54f9c3cc9d1bacbcb9d4e48a9014844b888085edb0b4cbc0dd9a28a22",
|
"semanticNameDigest": "bad23fbf57f26098673a1e702fad4011f7fa332e96c2d415d32063b8b934d3ed",
|
||||||
"typeId": "Part::Common"
|
"typeId": "Part::Common"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -751,8 +751,8 @@
|
|||||||
"name": "Common07",
|
"name": "Common07",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 8,
|
"relationCount": 8,
|
||||||
"relationDigest": "7794560879873d1dd1468a41ff9a0fed2e5912ac6ebf493d0de6725aede5d014",
|
"relationDigest": "295286347d8935ff0fc96fe706a211f55c042edd96c5f714a6ef31d2b9eac359",
|
||||||
"semanticNameDigest": "9d9b0bb54f9c3cc9d1bacbcb9d4e48a9014844b888085edb0b4cbc0dd9a28a22",
|
"semanticNameDigest": "bad23fbf57f26098673a1e702fad4011f7fa332e96c2d415d32063b8b934d3ed",
|
||||||
"typeId": "Part::Common"
|
"typeId": "Part::Common"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -786,8 +786,8 @@
|
|||||||
"name": "Common07",
|
"name": "Common07",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 8,
|
"relationCount": 8,
|
||||||
"relationDigest": "7794560879873d1dd1468a41ff9a0fed2e5912ac6ebf493d0de6725aede5d014",
|
"relationDigest": "295286347d8935ff0fc96fe706a211f55c042edd96c5f714a6ef31d2b9eac359",
|
||||||
"semanticNameDigest": "9d9b0bb54f9c3cc9d1bacbcb9d4e48a9014844b888085edb0b4cbc0dd9a28a22",
|
"semanticNameDigest": "bad23fbf57f26098673a1e702fad4011f7fa332e96c2d415d32063b8b934d3ed",
|
||||||
"typeId": "Part::Common"
|
"typeId": "Part::Common"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -942,8 +942,8 @@
|
|||||||
"name": "Common09",
|
"name": "Common09",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 8,
|
"relationCount": 8,
|
||||||
"relationDigest": "2be84bc707a5d5cceac0892c21948e193b48fb882a32a0230fff4b320178c9a9",
|
"relationDigest": "88e97943c245fbee81321de0c940374e1f8e94c90af688c0e2471f1ac4b13b8e",
|
||||||
"semanticNameDigest": "bad23fbf57f26098673a1e702fad4011f7fa332e96c2d415d32063b8b934d3ed",
|
"semanticNameDigest": "9d9b0bb54f9c3cc9d1bacbcb9d4e48a9014844b888085edb0b4cbc0dd9a28a22",
|
||||||
"typeId": "Part::Common"
|
"typeId": "Part::Common"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -977,8 +977,8 @@
|
|||||||
"name": "Common09",
|
"name": "Common09",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 8,
|
"relationCount": 8,
|
||||||
"relationDigest": "2be84bc707a5d5cceac0892c21948e193b48fb882a32a0230fff4b320178c9a9",
|
"relationDigest": "88e97943c245fbee81321de0c940374e1f8e94c90af688c0e2471f1ac4b13b8e",
|
||||||
"semanticNameDigest": "bad23fbf57f26098673a1e702fad4011f7fa332e96c2d415d32063b8b934d3ed",
|
"semanticNameDigest": "9d9b0bb54f9c3cc9d1bacbcb9d4e48a9014844b888085edb0b4cbc0dd9a28a22",
|
||||||
"typeId": "Part::Common"
|
"typeId": "Part::Common"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -1012,8 +1012,8 @@
|
|||||||
"name": "Common09",
|
"name": "Common09",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 8,
|
"relationCount": 8,
|
||||||
"relationDigest": "2be84bc707a5d5cceac0892c21948e193b48fb882a32a0230fff4b320178c9a9",
|
"relationDigest": "88e97943c245fbee81321de0c940374e1f8e94c90af688c0e2471f1ac4b13b8e",
|
||||||
"semanticNameDigest": "bad23fbf57f26098673a1e702fad4011f7fa332e96c2d415d32063b8b934d3ed",
|
"semanticNameDigest": "9d9b0bb54f9c3cc9d1bacbcb9d4e48a9014844b888085edb0b4cbc0dd9a28a22",
|
||||||
"typeId": "Part::Common"
|
"typeId": "Part::Common"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -2713,8 +2713,8 @@
|
|||||||
"name": "Body15",
|
"name": "Body15",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "48ca1f5bc04d2b40dee361740cea63e5d7f40bd447abd97af63a6cff9c33ae44",
|
"relationDigest": "083f7d4c5bb5d23dfa0a08d635131a8abb5b9b832d549630156b66cdc161832f",
|
||||||
"semanticNameDigest": "2c5e4fc67634c300b98cdc62c51d57a6248428ef0b9b0973b3a37ffed3336418",
|
"semanticNameDigest": "4b0ca170becae0ee3509ec4745823ceafc605fd45e1339b915dd108412117d48",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2830,8 +2830,8 @@
|
|||||||
"name": "Pocket15",
|
"name": "Pocket15",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "37cc4db7c553219ced9d96419849ebfab4bad1bb49e33f7406da753a3eb88f95",
|
"relationDigest": "6a0f6dcfc8e94125d60f130d24b9490ecabe0747294e9ca9ce100052135fc49d",
|
||||||
"semanticNameDigest": "90c517098693f8d01c88f618db28d8063ab41de7d34c7bebd9fbdaa56aeb24e8",
|
"semanticNameDigest": "e8d011101c491aeafae69eed47885e8919345e8dd4dcc501d987df316c58c3a1",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -2848,8 +2848,8 @@
|
|||||||
"name": "Body15",
|
"name": "Body15",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "48ca1f5bc04d2b40dee361740cea63e5d7f40bd447abd97af63a6cff9c33ae44",
|
"relationDigest": "083f7d4c5bb5d23dfa0a08d635131a8abb5b9b832d549630156b66cdc161832f",
|
||||||
"semanticNameDigest": "2c5e4fc67634c300b98cdc62c51d57a6248428ef0b9b0973b3a37ffed3336418",
|
"semanticNameDigest": "4b0ca170becae0ee3509ec4745823ceafc605fd45e1339b915dd108412117d48",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2965,8 +2965,8 @@
|
|||||||
"name": "Pocket15",
|
"name": "Pocket15",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "37cc4db7c553219ced9d96419849ebfab4bad1bb49e33f7406da753a3eb88f95",
|
"relationDigest": "6a0f6dcfc8e94125d60f130d24b9490ecabe0747294e9ca9ce100052135fc49d",
|
||||||
"semanticNameDigest": "90c517098693f8d01c88f618db28d8063ab41de7d34c7bebd9fbdaa56aeb24e8",
|
"semanticNameDigest": "e8d011101c491aeafae69eed47885e8919345e8dd4dcc501d987df316c58c3a1",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -2983,8 +2983,8 @@
|
|||||||
"name": "Body15",
|
"name": "Body15",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "48ca1f5bc04d2b40dee361740cea63e5d7f40bd447abd97af63a6cff9c33ae44",
|
"relationDigest": "083f7d4c5bb5d23dfa0a08d635131a8abb5b9b832d549630156b66cdc161832f",
|
||||||
"semanticNameDigest": "2c5e4fc67634c300b98cdc62c51d57a6248428ef0b9b0973b3a37ffed3336418",
|
"semanticNameDigest": "4b0ca170becae0ee3509ec4745823ceafc605fd45e1339b915dd108412117d48",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -3100,8 +3100,8 @@
|
|||||||
"name": "Pocket15",
|
"name": "Pocket15",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "37cc4db7c553219ced9d96419849ebfab4bad1bb49e33f7406da753a3eb88f95",
|
"relationDigest": "6a0f6dcfc8e94125d60f130d24b9490ecabe0747294e9ca9ce100052135fc49d",
|
||||||
"semanticNameDigest": "90c517098693f8d01c88f618db28d8063ab41de7d34c7bebd9fbdaa56aeb24e8",
|
"semanticNameDigest": "e8d011101c491aeafae69eed47885e8919345e8dd4dcc501d987df316c58c3a1",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -3126,8 +3126,8 @@
|
|||||||
"name": "Body16",
|
"name": "Body16",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 50,
|
"relationCount": 50,
|
||||||
"relationDigest": "789f08ee93078a4993256f4f84aaeebeda55b1e4b85ba320bc3bf1660f61424f",
|
"relationDigest": "9f5f0cf8bcfa9cfa4d5bc181fc77e00cf357779f0bc911453c5e3298cd315280",
|
||||||
"semanticNameDigest": "a43643c71e07a6f3cf199cf37eda3d1048f7cdbb62c4b069ad64a42d98380d38",
|
"semanticNameDigest": "88fa663eb0c658c3a5053bbf387295d860160c090e152dc4e7e5e56649f0dfc4",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -3243,8 +3243,8 @@
|
|||||||
"name": "Pocket16",
|
"name": "Pocket16",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 50,
|
"relationCount": 50,
|
||||||
"relationDigest": "5342570780854a405f82bfef7a11730681d8f6b71dfd318e482096b1be058678",
|
"relationDigest": "6243b4a96b360c27acefa6e7f3d33c0028fb399764ed25618ca02b815859576c",
|
||||||
"semanticNameDigest": "406cb7e44499069fbb747666aa20b9fc3070698d033d6becc6ed582f5394981b",
|
"semanticNameDigest": "18fffcdaa360c13dd3279890d0b061e1a55e998933329ea37445ca0ec7487c7b",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -3261,8 +3261,8 @@
|
|||||||
"name": "Body16",
|
"name": "Body16",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 50,
|
"relationCount": 50,
|
||||||
"relationDigest": "789f08ee93078a4993256f4f84aaeebeda55b1e4b85ba320bc3bf1660f61424f",
|
"relationDigest": "9f5f0cf8bcfa9cfa4d5bc181fc77e00cf357779f0bc911453c5e3298cd315280",
|
||||||
"semanticNameDigest": "a43643c71e07a6f3cf199cf37eda3d1048f7cdbb62c4b069ad64a42d98380d38",
|
"semanticNameDigest": "88fa663eb0c658c3a5053bbf387295d860160c090e152dc4e7e5e56649f0dfc4",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -3378,8 +3378,8 @@
|
|||||||
"name": "Pocket16",
|
"name": "Pocket16",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 50,
|
"relationCount": 50,
|
||||||
"relationDigest": "5342570780854a405f82bfef7a11730681d8f6b71dfd318e482096b1be058678",
|
"relationDigest": "6243b4a96b360c27acefa6e7f3d33c0028fb399764ed25618ca02b815859576c",
|
||||||
"semanticNameDigest": "406cb7e44499069fbb747666aa20b9fc3070698d033d6becc6ed582f5394981b",
|
"semanticNameDigest": "18fffcdaa360c13dd3279890d0b061e1a55e998933329ea37445ca0ec7487c7b",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -3396,8 +3396,8 @@
|
|||||||
"name": "Body16",
|
"name": "Body16",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 50,
|
"relationCount": 50,
|
||||||
"relationDigest": "789f08ee93078a4993256f4f84aaeebeda55b1e4b85ba320bc3bf1660f61424f",
|
"relationDigest": "9f5f0cf8bcfa9cfa4d5bc181fc77e00cf357779f0bc911453c5e3298cd315280",
|
||||||
"semanticNameDigest": "a43643c71e07a6f3cf199cf37eda3d1048f7cdbb62c4b069ad64a42d98380d38",
|
"semanticNameDigest": "88fa663eb0c658c3a5053bbf387295d860160c090e152dc4e7e5e56649f0dfc4",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -3513,8 +3513,8 @@
|
|||||||
"name": "Pocket16",
|
"name": "Pocket16",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 50,
|
"relationCount": 50,
|
||||||
"relationDigest": "5342570780854a405f82bfef7a11730681d8f6b71dfd318e482096b1be058678",
|
"relationDigest": "6243b4a96b360c27acefa6e7f3d33c0028fb399764ed25618ca02b815859576c",
|
||||||
"semanticNameDigest": "406cb7e44499069fbb747666aa20b9fc3070698d033d6becc6ed582f5394981b",
|
"semanticNameDigest": "18fffcdaa360c13dd3279890d0b061e1a55e998933329ea37445ca0ec7487c7b",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -3539,8 +3539,8 @@
|
|||||||
"name": "Body17",
|
"name": "Body17",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "18f04373fb3582655d5e225456f985d7c20a0142ffe28ebd325aaf93479007cb",
|
"relationDigest": "67afcfff404e1e4bce3c08f4c5be3993e4160c462194b3005c6926880b592b06",
|
||||||
"semanticNameDigest": "5b0acd2a833d282517f489087eb32b9098dd37092dc93ce41cf62f43e5ec60e1",
|
"semanticNameDigest": "1ec30f3d1fe50691136139ba972738e93d5a7ffd5c026a90ca78568a200acafb",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -3656,8 +3656,8 @@
|
|||||||
"name": "Pocket17",
|
"name": "Pocket17",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "b4cb276cb4aaa207e7e681898324f517794a3003f8ae49d0c221161f423c4504",
|
"relationDigest": "2068b7180d47301a2953579c7c04ca0a969d9b17363453523161ed6cb9377887",
|
||||||
"semanticNameDigest": "2cd5034a729734056e855cc31d2e8652221923fe8a2387aeadf770e406e17369",
|
"semanticNameDigest": "fdf43eda27a3f13ebf1102a380b5f0cc0a8ec24b8176b5d919fdac1928c84037",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -3674,8 +3674,8 @@
|
|||||||
"name": "Body17",
|
"name": "Body17",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "18f04373fb3582655d5e225456f985d7c20a0142ffe28ebd325aaf93479007cb",
|
"relationDigest": "67afcfff404e1e4bce3c08f4c5be3993e4160c462194b3005c6926880b592b06",
|
||||||
"semanticNameDigest": "5b0acd2a833d282517f489087eb32b9098dd37092dc93ce41cf62f43e5ec60e1",
|
"semanticNameDigest": "1ec30f3d1fe50691136139ba972738e93d5a7ffd5c026a90ca78568a200acafb",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -3791,8 +3791,8 @@
|
|||||||
"name": "Pocket17",
|
"name": "Pocket17",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "b4cb276cb4aaa207e7e681898324f517794a3003f8ae49d0c221161f423c4504",
|
"relationDigest": "2068b7180d47301a2953579c7c04ca0a969d9b17363453523161ed6cb9377887",
|
||||||
"semanticNameDigest": "2cd5034a729734056e855cc31d2e8652221923fe8a2387aeadf770e406e17369",
|
"semanticNameDigest": "fdf43eda27a3f13ebf1102a380b5f0cc0a8ec24b8176b5d919fdac1928c84037",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -3809,8 +3809,8 @@
|
|||||||
"name": "Body17",
|
"name": "Body17",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "18f04373fb3582655d5e225456f985d7c20a0142ffe28ebd325aaf93479007cb",
|
"relationDigest": "67afcfff404e1e4bce3c08f4c5be3993e4160c462194b3005c6926880b592b06",
|
||||||
"semanticNameDigest": "5b0acd2a833d282517f489087eb32b9098dd37092dc93ce41cf62f43e5ec60e1",
|
"semanticNameDigest": "1ec30f3d1fe50691136139ba972738e93d5a7ffd5c026a90ca78568a200acafb",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -3926,8 +3926,8 @@
|
|||||||
"name": "Pocket17",
|
"name": "Pocket17",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "b4cb276cb4aaa207e7e681898324f517794a3003f8ae49d0c221161f423c4504",
|
"relationDigest": "2068b7180d47301a2953579c7c04ca0a969d9b17363453523161ed6cb9377887",
|
||||||
"semanticNameDigest": "2cd5034a729734056e855cc31d2e8652221923fe8a2387aeadf770e406e17369",
|
"semanticNameDigest": "fdf43eda27a3f13ebf1102a380b5f0cc0a8ec24b8176b5d919fdac1928c84037",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -3952,8 +3952,8 @@
|
|||||||
"name": "Body18",
|
"name": "Body18",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "ac09a053ed37c89a51ff719fd8dbd3d2995a57046f2a0966bd216d4e43c403e7",
|
"relationDigest": "467a57582389ca941f33368c79920ed41d828935cea47995883c404002051134",
|
||||||
"semanticNameDigest": "6dd306ccbeb4bab8bac339ccbaf7ba1b31277502c2d2575b70ed9fc6292586ac",
|
"semanticNameDigest": "4b0ca170becae0ee3509ec4745823ceafc605fd45e1339b915dd108412117d48",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -4069,8 +4069,8 @@
|
|||||||
"name": "Pocket18",
|
"name": "Pocket18",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "17b7e1a8bf07c76449457915d1054099e92b783a37fb47fa25fbd7332b2e739a",
|
"relationDigest": "509fccfd3fde5e4a826da07c1afd0b534e3e72eed3c658576fbe7bee0be35b19",
|
||||||
"semanticNameDigest": "2576a581360b1033746428f0e1092c2f952b4dd3515c615787d151c9a69b1371",
|
"semanticNameDigest": "e8d011101c491aeafae69eed47885e8919345e8dd4dcc501d987df316c58c3a1",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -4087,8 +4087,8 @@
|
|||||||
"name": "Body18",
|
"name": "Body18",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "ac09a053ed37c89a51ff719fd8dbd3d2995a57046f2a0966bd216d4e43c403e7",
|
"relationDigest": "467a57582389ca941f33368c79920ed41d828935cea47995883c404002051134",
|
||||||
"semanticNameDigest": "6dd306ccbeb4bab8bac339ccbaf7ba1b31277502c2d2575b70ed9fc6292586ac",
|
"semanticNameDigest": "4b0ca170becae0ee3509ec4745823ceafc605fd45e1339b915dd108412117d48",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -4204,8 +4204,8 @@
|
|||||||
"name": "Pocket18",
|
"name": "Pocket18",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "17b7e1a8bf07c76449457915d1054099e92b783a37fb47fa25fbd7332b2e739a",
|
"relationDigest": "509fccfd3fde5e4a826da07c1afd0b534e3e72eed3c658576fbe7bee0be35b19",
|
||||||
"semanticNameDigest": "2576a581360b1033746428f0e1092c2f952b4dd3515c615787d151c9a69b1371",
|
"semanticNameDigest": "e8d011101c491aeafae69eed47885e8919345e8dd4dcc501d987df316c58c3a1",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -4222,8 +4222,8 @@
|
|||||||
"name": "Body18",
|
"name": "Body18",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "ac09a053ed37c89a51ff719fd8dbd3d2995a57046f2a0966bd216d4e43c403e7",
|
"relationDigest": "467a57582389ca941f33368c79920ed41d828935cea47995883c404002051134",
|
||||||
"semanticNameDigest": "6dd306ccbeb4bab8bac339ccbaf7ba1b31277502c2d2575b70ed9fc6292586ac",
|
"semanticNameDigest": "4b0ca170becae0ee3509ec4745823ceafc605fd45e1339b915dd108412117d48",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -4339,8 +4339,8 @@
|
|||||||
"name": "Pocket18",
|
"name": "Pocket18",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "17b7e1a8bf07c76449457915d1054099e92b783a37fb47fa25fbd7332b2e739a",
|
"relationDigest": "509fccfd3fde5e4a826da07c1afd0b534e3e72eed3c658576fbe7bee0be35b19",
|
||||||
"semanticNameDigest": "2576a581360b1033746428f0e1092c2f952b4dd3515c615787d151c9a69b1371",
|
"semanticNameDigest": "e8d011101c491aeafae69eed47885e8919345e8dd4dcc501d987df316c58c3a1",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -4365,8 +4365,8 @@
|
|||||||
"name": "Body19",
|
"name": "Body19",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "7c1b00fdf204b6bf50cc126fa488aa048bf528ce3d34cd79028eeb1aeca37587",
|
"relationDigest": "0c39abf77a575312d9bf82d11f956e956a8418e1a9ef5045c899e47a3438f98c",
|
||||||
"semanticNameDigest": "32b62497980ecd089a353b0aeb7c1f6d0681784ee3fafa2b4b0f277696c439d9",
|
"semanticNameDigest": "4b0ca170becae0ee3509ec4745823ceafc605fd45e1339b915dd108412117d48",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -4482,8 +4482,8 @@
|
|||||||
"name": "Pocket19",
|
"name": "Pocket19",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "bd52e5138be030f440045de2c5b1282ccc97bb45ed47c318307632c97a53eb76",
|
"relationDigest": "3d3142e1b5d42846f9bcab93a054b34904539ab49d91a6a113c710fe3d32d759",
|
||||||
"semanticNameDigest": "c5e1ad7e6d66764cbc7b457b3dddb90051f27aca8464c4cac7cd185d76108b53",
|
"semanticNameDigest": "e8d011101c491aeafae69eed47885e8919345e8dd4dcc501d987df316c58c3a1",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -4500,8 +4500,8 @@
|
|||||||
"name": "Body19",
|
"name": "Body19",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "7c1b00fdf204b6bf50cc126fa488aa048bf528ce3d34cd79028eeb1aeca37587",
|
"relationDigest": "0c39abf77a575312d9bf82d11f956e956a8418e1a9ef5045c899e47a3438f98c",
|
||||||
"semanticNameDigest": "32b62497980ecd089a353b0aeb7c1f6d0681784ee3fafa2b4b0f277696c439d9",
|
"semanticNameDigest": "4b0ca170becae0ee3509ec4745823ceafc605fd45e1339b915dd108412117d48",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -4617,8 +4617,8 @@
|
|||||||
"name": "Pocket19",
|
"name": "Pocket19",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "bd52e5138be030f440045de2c5b1282ccc97bb45ed47c318307632c97a53eb76",
|
"relationDigest": "3d3142e1b5d42846f9bcab93a054b34904539ab49d91a6a113c710fe3d32d759",
|
||||||
"semanticNameDigest": "c5e1ad7e6d66764cbc7b457b3dddb90051f27aca8464c4cac7cd185d76108b53",
|
"semanticNameDigest": "e8d011101c491aeafae69eed47885e8919345e8dd4dcc501d987df316c58c3a1",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -4635,8 +4635,8 @@
|
|||||||
"name": "Body19",
|
"name": "Body19",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "7c1b00fdf204b6bf50cc126fa488aa048bf528ce3d34cd79028eeb1aeca37587",
|
"relationDigest": "0c39abf77a575312d9bf82d11f956e956a8418e1a9ef5045c899e47a3438f98c",
|
||||||
"semanticNameDigest": "32b62497980ecd089a353b0aeb7c1f6d0681784ee3fafa2b4b0f277696c439d9",
|
"semanticNameDigest": "4b0ca170becae0ee3509ec4745823ceafc605fd45e1339b915dd108412117d48",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -4752,8 +4752,8 @@
|
|||||||
"name": "Pocket19",
|
"name": "Pocket19",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 52,
|
"relationCount": 52,
|
||||||
"relationDigest": "bd52e5138be030f440045de2c5b1282ccc97bb45ed47c318307632c97a53eb76",
|
"relationDigest": "3d3142e1b5d42846f9bcab93a054b34904539ab49d91a6a113c710fe3d32d759",
|
||||||
"semanticNameDigest": "c5e1ad7e6d66764cbc7b457b3dddb90051f27aca8464c4cac7cd185d76108b53",
|
"semanticNameDigest": "e8d011101c491aeafae69eed47885e8919345e8dd4dcc501d987df316c58c3a1",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -4778,8 +4778,8 @@
|
|||||||
"name": "Body20",
|
"name": "Body20",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "d2c546c1b376c3e3e086e52ec2cbbf631126cacd44fccde2480d1ebc87a1e247",
|
"relationDigest": "24551d9d0227423408c974d0638a74838fc3cc3f33f78b3ca9fee3c16f1f9b09",
|
||||||
"semanticNameDigest": "a23e1ffaad552432ef689925f97acfe32a0e379e506dc7eb8f5143f3428d20db",
|
"semanticNameDigest": "b3afa5b1f6f8b298e668c00e3235faa9aa6f250a26ec96535dc8386f6a9e09e8",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -4895,8 +4895,8 @@
|
|||||||
"name": "Pocket20",
|
"name": "Pocket20",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "7438bef8b5f9d6f1162ba373d1773cdd62af2ebc52c86b35400bf83c5171f5b1",
|
"relationDigest": "3d923d29d8d60a27f1da5cdfa1e95148911e6f2028d7fe4f07629fcfe15d58e6",
|
||||||
"semanticNameDigest": "1462a3875d27d44f54e718dd87c347c2beef89c897744b8ebd59a8fc7943dee9",
|
"semanticNameDigest": "3eb604a3dc43243edc0fab1433ff6eef9b6a970d474a160df8b7a6485658df3e",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -4913,8 +4913,8 @@
|
|||||||
"name": "Body20",
|
"name": "Body20",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "d2c546c1b376c3e3e086e52ec2cbbf631126cacd44fccde2480d1ebc87a1e247",
|
"relationDigest": "24551d9d0227423408c974d0638a74838fc3cc3f33f78b3ca9fee3c16f1f9b09",
|
||||||
"semanticNameDigest": "a23e1ffaad552432ef689925f97acfe32a0e379e506dc7eb8f5143f3428d20db",
|
"semanticNameDigest": "b3afa5b1f6f8b298e668c00e3235faa9aa6f250a26ec96535dc8386f6a9e09e8",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5030,8 +5030,8 @@
|
|||||||
"name": "Pocket20",
|
"name": "Pocket20",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "7438bef8b5f9d6f1162ba373d1773cdd62af2ebc52c86b35400bf83c5171f5b1",
|
"relationDigest": "3d923d29d8d60a27f1da5cdfa1e95148911e6f2028d7fe4f07629fcfe15d58e6",
|
||||||
"semanticNameDigest": "1462a3875d27d44f54e718dd87c347c2beef89c897744b8ebd59a8fc7943dee9",
|
"semanticNameDigest": "3eb604a3dc43243edc0fab1433ff6eef9b6a970d474a160df8b7a6485658df3e",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -5048,8 +5048,8 @@
|
|||||||
"name": "Body20",
|
"name": "Body20",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "d2c546c1b376c3e3e086e52ec2cbbf631126cacd44fccde2480d1ebc87a1e247",
|
"relationDigest": "24551d9d0227423408c974d0638a74838fc3cc3f33f78b3ca9fee3c16f1f9b09",
|
||||||
"semanticNameDigest": "a23e1ffaad552432ef689925f97acfe32a0e379e506dc7eb8f5143f3428d20db",
|
"semanticNameDigest": "b3afa5b1f6f8b298e668c00e3235faa9aa6f250a26ec96535dc8386f6a9e09e8",
|
||||||
"typeId": "PartDesign::Body"
|
"typeId": "PartDesign::Body"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5165,8 +5165,8 @@
|
|||||||
"name": "Pocket20",
|
"name": "Pocket20",
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
"relationCount": 51,
|
"relationCount": 51,
|
||||||
"relationDigest": "7438bef8b5f9d6f1162ba373d1773cdd62af2ebc52c86b35400bf83c5171f5b1",
|
"relationDigest": "3d923d29d8d60a27f1da5cdfa1e95148911e6f2028d7fe4f07629fcfe15d58e6",
|
||||||
"semanticNameDigest": "1462a3875d27d44f54e718dd87c347c2beef89c897744b8ebd59a8fc7943dee9",
|
"semanticNameDigest": "3eb604a3dc43243edc0fab1433ff6eef9b6a970d474a160df8b7a6485658df3e",
|
||||||
"typeId": "PartDesign::Pocket"
|
"typeId": "PartDesign::Pocket"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -5208,8 +5208,8 @@
|
|||||||
"name": "Fuse21",
|
"name": "Fuse21",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 40,
|
"relationCount": 40,
|
||||||
"relationDigest": "b7048ea8f7a69323d0fcb7bab013a91d91244041251cfc526706e0738555c97c",
|
"relationDigest": "4de249036d09a8c959e8812ea82f0ded5d4e307e8de05bdadec553bd3054007b",
|
||||||
"semanticNameDigest": "24d8c54ee7bfa29609e3840c13ca5889c8c97f285b4645a7c1e9f6b55fe7fc04",
|
"semanticNameDigest": "dece2b8f8787384f070c14f62691734aaf1b55d585f92182282f3e377a8c6ecf",
|
||||||
"typeId": "Part::Fuse"
|
"typeId": "Part::Fuse"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5231,8 +5231,8 @@
|
|||||||
"name": "CompositeCut21",
|
"name": "CompositeCut21",
|
||||||
"ordinal": 4,
|
"ordinal": 4,
|
||||||
"relationCount": 66,
|
"relationCount": 66,
|
||||||
"relationDigest": "2b31d2cb3b00c9520451a9a61c70549c6acc8a916740018bfe4ab5cf1b1f95bc",
|
"relationDigest": "180592dbf29effd2b83eec65e868debfb3764df8e25bf23922d051f953755599",
|
||||||
"semanticNameDigest": "9f7d4828bc4dc4631e2008d27c289fe2f148c067a9b185493af56727cb7af894",
|
"semanticNameDigest": "81b9eeedb8e62427e8ff20733db837f3211c12dcac22104c89e339fbb103a7cc",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -5266,8 +5266,8 @@
|
|||||||
"name": "Fuse21",
|
"name": "Fuse21",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 40,
|
"relationCount": 40,
|
||||||
"relationDigest": "b7048ea8f7a69323d0fcb7bab013a91d91244041251cfc526706e0738555c97c",
|
"relationDigest": "4de249036d09a8c959e8812ea82f0ded5d4e307e8de05bdadec553bd3054007b",
|
||||||
"semanticNameDigest": "24d8c54ee7bfa29609e3840c13ca5889c8c97f285b4645a7c1e9f6b55fe7fc04",
|
"semanticNameDigest": "dece2b8f8787384f070c14f62691734aaf1b55d585f92182282f3e377a8c6ecf",
|
||||||
"typeId": "Part::Fuse"
|
"typeId": "Part::Fuse"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5289,8 +5289,8 @@
|
|||||||
"name": "CompositeCut21",
|
"name": "CompositeCut21",
|
||||||
"ordinal": 4,
|
"ordinal": 4,
|
||||||
"relationCount": 66,
|
"relationCount": 66,
|
||||||
"relationDigest": "2b31d2cb3b00c9520451a9a61c70549c6acc8a916740018bfe4ab5cf1b1f95bc",
|
"relationDigest": "180592dbf29effd2b83eec65e868debfb3764df8e25bf23922d051f953755599",
|
||||||
"semanticNameDigest": "9f7d4828bc4dc4631e2008d27c289fe2f148c067a9b185493af56727cb7af894",
|
"semanticNameDigest": "81b9eeedb8e62427e8ff20733db837f3211c12dcac22104c89e339fbb103a7cc",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -5324,8 +5324,8 @@
|
|||||||
"name": "Fuse21",
|
"name": "Fuse21",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 40,
|
"relationCount": 40,
|
||||||
"relationDigest": "b7048ea8f7a69323d0fcb7bab013a91d91244041251cfc526706e0738555c97c",
|
"relationDigest": "4de249036d09a8c959e8812ea82f0ded5d4e307e8de05bdadec553bd3054007b",
|
||||||
"semanticNameDigest": "24d8c54ee7bfa29609e3840c13ca5889c8c97f285b4645a7c1e9f6b55fe7fc04",
|
"semanticNameDigest": "dece2b8f8787384f070c14f62691734aaf1b55d585f92182282f3e377a8c6ecf",
|
||||||
"typeId": "Part::Fuse"
|
"typeId": "Part::Fuse"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5347,8 +5347,8 @@
|
|||||||
"name": "CompositeCut21",
|
"name": "CompositeCut21",
|
||||||
"ordinal": 4,
|
"ordinal": 4,
|
||||||
"relationCount": 66,
|
"relationCount": 66,
|
||||||
"relationDigest": "2b31d2cb3b00c9520451a9a61c70549c6acc8a916740018bfe4ab5cf1b1f95bc",
|
"relationDigest": "180592dbf29effd2b83eec65e868debfb3764df8e25bf23922d051f953755599",
|
||||||
"semanticNameDigest": "9f7d4828bc4dc4631e2008d27c289fe2f148c067a9b185493af56727cb7af894",
|
"semanticNameDigest": "81b9eeedb8e62427e8ff20733db837f3211c12dcac22104c89e339fbb103a7cc",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -5390,8 +5390,8 @@
|
|||||||
"name": "Cut22",
|
"name": "Cut22",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "996db922ea9b879f9f166d344a02e2113e08405c2f7e3bd2c2c30435891e52c5",
|
"relationDigest": "313e61ab643adc1fc132732847c963004f7312c3d35307e5e8abc148c51268a1",
|
||||||
"semanticNameDigest": "ae506e04fc0cc271258f65ef5f83d4db416a88ca0aa24c4a2716fd88428dab04",
|
"semanticNameDigest": "0e5cd8a02bc1dbf68d1af01e559cc0766a92c5d58975615f26cd32f166f4044b",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5413,8 +5413,8 @@
|
|||||||
"name": "CompositeCut22",
|
"name": "CompositeCut22",
|
||||||
"ordinal": 4,
|
"ordinal": 4,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "590320fac4c896df47311594fe48465129ae822f076d2c13f8631fcc21ec6c50",
|
"relationDigest": "6f68b991611eb08fa97211478b3ad4ecdef5e79fa5e68cf394cd716f94afcffc",
|
||||||
"semanticNameDigest": "3ee8ce68cce26a0e5695cfa40a50d484b6b934fd2fb87ba727482d7c7d22eb9d",
|
"semanticNameDigest": "e3075f73dfc637c6f0df4c728ccee90f5178100ef4f51b4c60dd99e0f6e02f5a",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -5448,8 +5448,8 @@
|
|||||||
"name": "Cut22",
|
"name": "Cut22",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "996db922ea9b879f9f166d344a02e2113e08405c2f7e3bd2c2c30435891e52c5",
|
"relationDigest": "313e61ab643adc1fc132732847c963004f7312c3d35307e5e8abc148c51268a1",
|
||||||
"semanticNameDigest": "ae506e04fc0cc271258f65ef5f83d4db416a88ca0aa24c4a2716fd88428dab04",
|
"semanticNameDigest": "0e5cd8a02bc1dbf68d1af01e559cc0766a92c5d58975615f26cd32f166f4044b",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5471,8 +5471,8 @@
|
|||||||
"name": "CompositeCut22",
|
"name": "CompositeCut22",
|
||||||
"ordinal": 4,
|
"ordinal": 4,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "590320fac4c896df47311594fe48465129ae822f076d2c13f8631fcc21ec6c50",
|
"relationDigest": "6f68b991611eb08fa97211478b3ad4ecdef5e79fa5e68cf394cd716f94afcffc",
|
||||||
"semanticNameDigest": "3ee8ce68cce26a0e5695cfa40a50d484b6b934fd2fb87ba727482d7c7d22eb9d",
|
"semanticNameDigest": "e3075f73dfc637c6f0df4c728ccee90f5178100ef4f51b4c60dd99e0f6e02f5a",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -5506,8 +5506,8 @@
|
|||||||
"name": "Cut22",
|
"name": "Cut22",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "996db922ea9b879f9f166d344a02e2113e08405c2f7e3bd2c2c30435891e52c5",
|
"relationDigest": "313e61ab643adc1fc132732847c963004f7312c3d35307e5e8abc148c51268a1",
|
||||||
"semanticNameDigest": "ae506e04fc0cc271258f65ef5f83d4db416a88ca0aa24c4a2716fd88428dab04",
|
"semanticNameDigest": "0e5cd8a02bc1dbf68d1af01e559cc0766a92c5d58975615f26cd32f166f4044b",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5529,8 +5529,8 @@
|
|||||||
"name": "CompositeCut22",
|
"name": "CompositeCut22",
|
||||||
"ordinal": 4,
|
"ordinal": 4,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "590320fac4c896df47311594fe48465129ae822f076d2c13f8631fcc21ec6c50",
|
"relationDigest": "6f68b991611eb08fa97211478b3ad4ecdef5e79fa5e68cf394cd716f94afcffc",
|
||||||
"semanticNameDigest": "3ee8ce68cce26a0e5695cfa40a50d484b6b934fd2fb87ba727482d7c7d22eb9d",
|
"semanticNameDigest": "e3075f73dfc637c6f0df4c728ccee90f5178100ef4f51b4c60dd99e0f6e02f5a",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -5754,8 +5754,8 @@
|
|||||||
"name": "Cut24",
|
"name": "Cut24",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "1ed5f1320e33ded3a77834fdb9d943ee7b234db13649c8a9e51f5acd35031626",
|
"relationDigest": "05f84541c1424e27110b860941ad4d17c2120c5b1f874a8572218eca31993e46",
|
||||||
"semanticNameDigest": "e57854d68a7acdcdef26c8cbdc6173317eeb040d08331848717165c8294e685f",
|
"semanticNameDigest": "ae506e04fc0cc271258f65ef5f83d4db416a88ca0aa24c4a2716fd88428dab04",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5777,8 +5777,8 @@
|
|||||||
"name": "CompositeCut24",
|
"name": "CompositeCut24",
|
||||||
"ordinal": 4,
|
"ordinal": 4,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "3536dcc7f7c1d21f91e6ca952ffdcc7d06581376a807860fda3bee1f34f68519",
|
"relationDigest": "0a40b440a48e5ae101c9d7c050170a0bfddb5495b84c4c27f8c80ac85cce73e9",
|
||||||
"semanticNameDigest": "57985accd97b0ed3c94f0f8b40227bcf86974fafe5ad3a502e64f30d0f138943",
|
"semanticNameDigest": "3ee8ce68cce26a0e5695cfa40a50d484b6b934fd2fb87ba727482d7c7d22eb9d",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -5812,8 +5812,8 @@
|
|||||||
"name": "Cut24",
|
"name": "Cut24",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "1ed5f1320e33ded3a77834fdb9d943ee7b234db13649c8a9e51f5acd35031626",
|
"relationDigest": "05f84541c1424e27110b860941ad4d17c2120c5b1f874a8572218eca31993e46",
|
||||||
"semanticNameDigest": "e57854d68a7acdcdef26c8cbdc6173317eeb040d08331848717165c8294e685f",
|
"semanticNameDigest": "ae506e04fc0cc271258f65ef5f83d4db416a88ca0aa24c4a2716fd88428dab04",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5835,8 +5835,8 @@
|
|||||||
"name": "CompositeCut24",
|
"name": "CompositeCut24",
|
||||||
"ordinal": 4,
|
"ordinal": 4,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "3536dcc7f7c1d21f91e6ca952ffdcc7d06581376a807860fda3bee1f34f68519",
|
"relationDigest": "0a40b440a48e5ae101c9d7c050170a0bfddb5495b84c4c27f8c80ac85cce73e9",
|
||||||
"semanticNameDigest": "57985accd97b0ed3c94f0f8b40227bcf86974fafe5ad3a502e64f30d0f138943",
|
"semanticNameDigest": "3ee8ce68cce26a0e5695cfa40a50d484b6b934fd2fb87ba727482d7c7d22eb9d",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -5870,8 +5870,8 @@
|
|||||||
"name": "Cut24",
|
"name": "Cut24",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "1ed5f1320e33ded3a77834fdb9d943ee7b234db13649c8a9e51f5acd35031626",
|
"relationDigest": "05f84541c1424e27110b860941ad4d17c2120c5b1f874a8572218eca31993e46",
|
||||||
"semanticNameDigest": "e57854d68a7acdcdef26c8cbdc6173317eeb040d08331848717165c8294e685f",
|
"semanticNameDigest": "ae506e04fc0cc271258f65ef5f83d4db416a88ca0aa24c4a2716fd88428dab04",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5893,8 +5893,8 @@
|
|||||||
"name": "CompositeCut24",
|
"name": "CompositeCut24",
|
||||||
"ordinal": 4,
|
"ordinal": 4,
|
||||||
"relationCount": 32,
|
"relationCount": 32,
|
||||||
"relationDigest": "3536dcc7f7c1d21f91e6ca952ffdcc7d06581376a807860fda3bee1f34f68519",
|
"relationDigest": "0a40b440a48e5ae101c9d7c050170a0bfddb5495b84c4c27f8c80ac85cce73e9",
|
||||||
"semanticNameDigest": "57985accd97b0ed3c94f0f8b40227bcf86974fafe5ad3a502e64f30d0f138943",
|
"semanticNameDigest": "3ee8ce68cce26a0e5695cfa40a50d484b6b934fd2fb87ba727482d7c7d22eb9d",
|
||||||
"typeId": "Part::Cut"
|
"typeId": "Part::Cut"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
958
config/freecad-ordered-operation-pair-classification.json
Normal file
958
config/freecad-ordered-operation-pair-classification.json
Normal file
@@ -0,0 +1,958 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"baseline": {
|
||||||
|
"freecadVersion": "1.1.1",
|
||||||
|
"commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d",
|
||||||
|
"occtVersion": "8.0.0"
|
||||||
|
},
|
||||||
|
"generatedBy": "./npmw run probe:freecad-ordered-operation-pairs",
|
||||||
|
"checkedBy": "./npmw run check:freecad-ordered-operation-pairs",
|
||||||
|
"nativeProbe": {
|
||||||
|
"executor": {
|
||||||
|
"path": "scripts/run-freecad-ordered-operation-pair-classification.mjs",
|
||||||
|
"bytes": 14390,
|
||||||
|
"sha256": "ec6cc4556269d538f1c979886e7cc9b6cca0a194b6e4b67291e140b773d595db"
|
||||||
|
},
|
||||||
|
"matrix": {
|
||||||
|
"path": "scripts/freecad-naming-production-matrix.mjs",
|
||||||
|
"bytes": 19819,
|
||||||
|
"sha256": "01532d8d3197aacddc0c18d4d8e41b4aee3b88bb4eb6636d8d0457a194651125"
|
||||||
|
},
|
||||||
|
"resave": {
|
||||||
|
"path": "scripts/freecad-ordered-operation-pair-resave.py",
|
||||||
|
"bytes": 4467,
|
||||||
|
"sha256": "d02f2cc0c6427fc324693692a1bce036e58feb238bf5259fb17803a454d6d22b"
|
||||||
|
},
|
||||||
|
"artifacts": [
|
||||||
|
{
|
||||||
|
"name": "bitbybit-occt-history.js",
|
||||||
|
"bytes": 359739,
|
||||||
|
"sha256": "6a90575b81ceab5c00a2440e45e010bd62d3455b012541b4449f7b0e88a644c0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bitbybit-occt-history.wasm",
|
||||||
|
"bytes": 37482285,
|
||||||
|
"sha256": "c03cf553e71bf4e74667c5aada921769bb241d6021f28a5b166b49c738965515"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bitbybit-occt-history.data",
|
||||||
|
"bytes": 3322679,
|
||||||
|
"sha256": "ada204b276208027a5cb1cc1288d4aab95b8ee1f28e3a43a00cd062720b87e99"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"classifications": [
|
||||||
|
{
|
||||||
|
"taskId": "TSN-PAIR-fuse-fuse",
|
||||||
|
"pair": "fuse->fuse",
|
||||||
|
"classification": "accepted",
|
||||||
|
"reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass",
|
||||||
|
"nativeDecision": "accepted",
|
||||||
|
"first": {
|
||||||
|
"operation": "fuse",
|
||||||
|
"builder": "BRepAlgoAPI_Fuse",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 13,
|
||||||
|
"edges": 29,
|
||||||
|
"vertices": 18,
|
||||||
|
"volume": 1075,
|
||||||
|
"area": 660,
|
||||||
|
"bounds": [
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
13.0000001,
|
||||||
|
10.0000001,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 52,
|
||||||
|
"selectedRecords": 7,
|
||||||
|
"ambiguousResults": 16,
|
||||||
|
"historySha256": "3c9d5be39dd201d2a637810cc9ae644ee5c056f7eab523ab3480a74c7dc5c427",
|
||||||
|
"namingEvidenceSha256": "287fcff75041d48313bcfb533053ba8e19571b19333dd5e01165488ebd20742a",
|
||||||
|
"namingSemanticSha256": "5260dde0df276e2af3f052757055a408402c4c8c3ec0ea744022c4ac9d8e31af"
|
||||||
|
},
|
||||||
|
"second": {
|
||||||
|
"operation": "fuse",
|
||||||
|
"builder": "BRepAlgoAPI_Fuse",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 21,
|
||||||
|
"edges": 45,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1175,
|
||||||
|
"area": 740,
|
||||||
|
"bounds": [
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
17.0000001,
|
||||||
|
10.0000001,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 66,
|
||||||
|
"selectedRecords": 8,
|
||||||
|
"ambiguousResults": 24,
|
||||||
|
"historySha256": "ebfcbd3c59dc35e40d4b14b68bd5daa81b998e59e732a2648883f3552733de50",
|
||||||
|
"namingEvidenceSha256": "f739749cc0e8a766033d22214bd736152572ff3c2ad638dc52c4d54f67fb473b",
|
||||||
|
"namingSemanticSha256": "3d6d1293adb46419c3c27ddc62367230efb87188cea5cef2fdd8c3266c793a04"
|
||||||
|
},
|
||||||
|
"mutation": {
|
||||||
|
"scope": "second-operation-only",
|
||||||
|
"parameter": "toolOffsetX",
|
||||||
|
"trajectory": [
|
||||||
|
12,
|
||||||
|
11,
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"beforeValue": 12,
|
||||||
|
"editedValue": 11,
|
||||||
|
"restoredValue": 12,
|
||||||
|
"changed": true,
|
||||||
|
"restoredExactly": true,
|
||||||
|
"editedEvidence": {
|
||||||
|
"operation": "fuse",
|
||||||
|
"builder": "BRepAlgoAPI_Fuse",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 21,
|
||||||
|
"edges": 45,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1150,
|
||||||
|
"area": 720,
|
||||||
|
"bounds": [
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
16.0000001,
|
||||||
|
10.0000001,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 66,
|
||||||
|
"selectedRecords": 8,
|
||||||
|
"ambiguousResults": 24,
|
||||||
|
"historySha256": "ebfcbd3c59dc35e40d4b14b68bd5daa81b998e59e732a2648883f3552733de50",
|
||||||
|
"namingEvidenceSha256": "40447213be94a2f67270155dd907782feab7019d7c2cf3ef18fadac5a6d42daa",
|
||||||
|
"namingSemanticSha256": "3d6d1293adb46419c3c27ddc62367230efb87188cea5cef2fdd8c3266c793a04"
|
||||||
|
},
|
||||||
|
"restoredEvidence": {
|
||||||
|
"operation": "fuse",
|
||||||
|
"builder": "BRepAlgoAPI_Fuse",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 21,
|
||||||
|
"edges": 45,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1175,
|
||||||
|
"area": 740,
|
||||||
|
"bounds": [
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
17.0000001,
|
||||||
|
10.0000001,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 66,
|
||||||
|
"selectedRecords": 8,
|
||||||
|
"ambiguousResults": 24,
|
||||||
|
"historySha256": "ebfcbd3c59dc35e40d4b14b68bd5daa81b998e59e732a2648883f3552733de50",
|
||||||
|
"namingEvidenceSha256": "61ef6064d9a23212767f63d611e21ac03005d4fe49891d64f0142cead96d2fa6",
|
||||||
|
"namingSemanticSha256": "3d6d1293adb46419c3c27ddc62367230efb87188cea5cef2fdd8c3266c793a04"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"naming": {
|
||||||
|
"upstreamEvidenceRestored": true,
|
||||||
|
"downstreamEvidence": true,
|
||||||
|
"jsonRoundtripStable": true
|
||||||
|
},
|
||||||
|
"persistence": {
|
||||||
|
"baselineId": "freecad-1.1.1-ordered-operation-pair-resave",
|
||||||
|
"checks": {
|
||||||
|
"namingEvidenceStable": true,
|
||||||
|
"shapeStable": true
|
||||||
|
},
|
||||||
|
"freecadVersion": "1.1.1",
|
||||||
|
"gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d",
|
||||||
|
"pair": "fuse->fuse",
|
||||||
|
"phases": {
|
||||||
|
"initial": {
|
||||||
|
"namingEvidenceBytes": 11392,
|
||||||
|
"namingEvidenceSha256": "f739749cc0e8a766033d22214bd736152572ff3c2ad638dc52c4d54f67fb473b",
|
||||||
|
"pair": "fuse->fuse",
|
||||||
|
"shape": {
|
||||||
|
"area": 740,
|
||||||
|
"bounds": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
17,
|
||||||
|
10,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"edges": 45,
|
||||||
|
"faces": 21,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1175
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"reopened": {
|
||||||
|
"namingEvidenceBytes": 11392,
|
||||||
|
"namingEvidenceSha256": "f739749cc0e8a766033d22214bd736152572ff3c2ad638dc52c4d54f67fb473b",
|
||||||
|
"pair": "fuse->fuse",
|
||||||
|
"shape": {
|
||||||
|
"area": 740,
|
||||||
|
"bounds": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
17,
|
||||||
|
10,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"edges": 45,
|
||||||
|
"faces": 21,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1175
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resaved": {
|
||||||
|
"namingEvidenceBytes": 11392,
|
||||||
|
"namingEvidenceSha256": "f739749cc0e8a766033d22214bd736152572ff3c2ad638dc52c4d54f67fb473b",
|
||||||
|
"pair": "fuse->fuse",
|
||||||
|
"shape": {
|
||||||
|
"area": 740,
|
||||||
|
"bounds": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
17,
|
||||||
|
10,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"edges": 45,
|
||||||
|
"faces": 21,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1175
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"status": "pass"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"taskId": "TSN-PAIR-fuse-cut",
|
||||||
|
"pair": "fuse->cut",
|
||||||
|
"classification": "accepted",
|
||||||
|
"reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass",
|
||||||
|
"nativeDecision": "accepted",
|
||||||
|
"first": {
|
||||||
|
"operation": "fuse",
|
||||||
|
"builder": "BRepAlgoAPI_Fuse",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 13,
|
||||||
|
"edges": 29,
|
||||||
|
"vertices": 18,
|
||||||
|
"volume": 1075,
|
||||||
|
"area": 660,
|
||||||
|
"bounds": [
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
13.0000001,
|
||||||
|
10.0000001,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 52,
|
||||||
|
"selectedRecords": 7,
|
||||||
|
"ambiguousResults": 16,
|
||||||
|
"historySha256": "3c9d5be39dd201d2a637810cc9ae644ee5c056f7eab523ab3480a74c7dc5c427",
|
||||||
|
"namingEvidenceSha256": "e2bbd4e8c2e94112763a16246c9a385cbb525f2141fff24249bb6bd35087fa60",
|
||||||
|
"namingSemanticSha256": "dde2d7ea9e29065a3b2f1e665daa1c508e7f9f35980954c89b41007450224d7a"
|
||||||
|
},
|
||||||
|
"second": {
|
||||||
|
"operation": "cut",
|
||||||
|
"builder": "BRepAlgoAPI_Cut",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 17,
|
||||||
|
"edges": 41,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1011,
|
||||||
|
"area": 692,
|
||||||
|
"bounds": [
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
13.0000001,
|
||||||
|
10.0000001,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 22,
|
||||||
|
"selectedRecords": 2,
|
||||||
|
"ambiguousResults": 8,
|
||||||
|
"historySha256": "f8fe7d63848e9487e10aab0234b4197cd915fd34b9a5b2cd2b8d7c19f0102e82",
|
||||||
|
"namingEvidenceSha256": "ac0a97a31fd8881bed24b86415d80eeae582229f7f2d247d9accafdaf1ac0cc4",
|
||||||
|
"namingSemanticSha256": "8ac3978f4a10529ca422c6a865dc389c8b20082efff597f7c5db56421bf13ada"
|
||||||
|
},
|
||||||
|
"mutation": {
|
||||||
|
"scope": "second-operation-only",
|
||||||
|
"parameter": "toolSize",
|
||||||
|
"trajectory": [
|
||||||
|
4,
|
||||||
|
3,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"beforeValue": 4,
|
||||||
|
"editedValue": 3,
|
||||||
|
"restoredValue": 4,
|
||||||
|
"changed": true,
|
||||||
|
"restoredExactly": true,
|
||||||
|
"editedEvidence": {
|
||||||
|
"operation": "cut",
|
||||||
|
"builder": "BRepAlgoAPI_Cut",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 17,
|
||||||
|
"edges": 41,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1048,
|
||||||
|
"area": 678,
|
||||||
|
"bounds": [
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
13.0000001,
|
||||||
|
10.0000001,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 22,
|
||||||
|
"selectedRecords": 2,
|
||||||
|
"ambiguousResults": 8,
|
||||||
|
"historySha256": "f8fe7d63848e9487e10aab0234b4197cd915fd34b9a5b2cd2b8d7c19f0102e82",
|
||||||
|
"namingEvidenceSha256": "746cb6d768b72baab35a1d138d0933e73d7bf081728725686440f2c3c92e7822",
|
||||||
|
"namingSemanticSha256": "8ac3978f4a10529ca422c6a865dc389c8b20082efff597f7c5db56421bf13ada"
|
||||||
|
},
|
||||||
|
"restoredEvidence": {
|
||||||
|
"operation": "cut",
|
||||||
|
"builder": "BRepAlgoAPI_Cut",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 17,
|
||||||
|
"edges": 41,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1011,
|
||||||
|
"area": 692,
|
||||||
|
"bounds": [
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
13.0000001,
|
||||||
|
10.0000001,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 22,
|
||||||
|
"selectedRecords": 2,
|
||||||
|
"ambiguousResults": 8,
|
||||||
|
"historySha256": "f8fe7d63848e9487e10aab0234b4197cd915fd34b9a5b2cd2b8d7c19f0102e82",
|
||||||
|
"namingEvidenceSha256": "c6af78a4fc31e1382c389d343d639f723e9ca4c749bf17fe24bdd572beec6490",
|
||||||
|
"namingSemanticSha256": "8ac3978f4a10529ca422c6a865dc389c8b20082efff597f7c5db56421bf13ada"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"naming": {
|
||||||
|
"upstreamEvidenceRestored": true,
|
||||||
|
"downstreamEvidence": true,
|
||||||
|
"jsonRoundtripStable": true
|
||||||
|
},
|
||||||
|
"persistence": {
|
||||||
|
"baselineId": "freecad-1.1.1-ordered-operation-pair-resave",
|
||||||
|
"checks": {
|
||||||
|
"namingEvidenceStable": true,
|
||||||
|
"shapeStable": true
|
||||||
|
},
|
||||||
|
"freecadVersion": "1.1.1",
|
||||||
|
"gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d",
|
||||||
|
"pair": "fuse->cut",
|
||||||
|
"phases": {
|
||||||
|
"initial": {
|
||||||
|
"namingEvidenceBytes": 3695,
|
||||||
|
"namingEvidenceSha256": "ac0a97a31fd8881bed24b86415d80eeae582229f7f2d247d9accafdaf1ac0cc4",
|
||||||
|
"pair": "fuse->cut",
|
||||||
|
"shape": {
|
||||||
|
"area": 692,
|
||||||
|
"bounds": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
13,
|
||||||
|
10,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"edges": 41,
|
||||||
|
"faces": 17,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1011
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"reopened": {
|
||||||
|
"namingEvidenceBytes": 3695,
|
||||||
|
"namingEvidenceSha256": "ac0a97a31fd8881bed24b86415d80eeae582229f7f2d247d9accafdaf1ac0cc4",
|
||||||
|
"pair": "fuse->cut",
|
||||||
|
"shape": {
|
||||||
|
"area": 692,
|
||||||
|
"bounds": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
13,
|
||||||
|
10,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"edges": 41,
|
||||||
|
"faces": 17,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1011
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resaved": {
|
||||||
|
"namingEvidenceBytes": 3695,
|
||||||
|
"namingEvidenceSha256": "ac0a97a31fd8881bed24b86415d80eeae582229f7f2d247d9accafdaf1ac0cc4",
|
||||||
|
"pair": "fuse->cut",
|
||||||
|
"shape": {
|
||||||
|
"area": 692,
|
||||||
|
"bounds": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
13,
|
||||||
|
10,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"edges": 41,
|
||||||
|
"faces": 17,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 26,
|
||||||
|
"volume": 1011
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"status": "pass"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"taskId": "TSN-PAIR-fuse-common",
|
||||||
|
"pair": "fuse->common",
|
||||||
|
"classification": "accepted",
|
||||||
|
"reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass",
|
||||||
|
"nativeDecision": "accepted",
|
||||||
|
"first": {
|
||||||
|
"operation": "fuse",
|
||||||
|
"builder": "BRepAlgoAPI_Fuse",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 13,
|
||||||
|
"edges": 29,
|
||||||
|
"vertices": 18,
|
||||||
|
"volume": 1075,
|
||||||
|
"area": 660,
|
||||||
|
"bounds": [
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
13.0000001,
|
||||||
|
10.0000001,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 52,
|
||||||
|
"selectedRecords": 7,
|
||||||
|
"ambiguousResults": 16,
|
||||||
|
"historySha256": "3c9d5be39dd201d2a637810cc9ae644ee5c056f7eab523ab3480a74c7dc5c427",
|
||||||
|
"namingEvidenceSha256": "af9be791d652b3a0ac5762fdecef7c936c64015330ad253d96b68eedbd5049f3",
|
||||||
|
"namingSemanticSha256": "84f46e75d9855d67bc068f70650ba10932d491442cac4b36d296e49d2bf8fcf5"
|
||||||
|
},
|
||||||
|
"second": {
|
||||||
|
"operation": "common",
|
||||||
|
"builder": "BRepAlgoAPI_Common",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 6,
|
||||||
|
"edges": 12,
|
||||||
|
"vertices": 8,
|
||||||
|
"volume": 75,
|
||||||
|
"area": 110,
|
||||||
|
"bounds": [
|
||||||
|
9.9999999,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
13.0000001,
|
||||||
|
5.0000001,
|
||||||
|
5.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 240,
|
||||||
|
"selectedRecords": 1,
|
||||||
|
"ambiguousResults": 20,
|
||||||
|
"historySha256": "4cec040527a627b73017af103188173f2460dfd41dfa46d8acee005ed80eb8dc",
|
||||||
|
"namingEvidenceSha256": "d04cd4d189cc9549f8ae9700a102526071281c0711f2edb0ff1e38fc27470ab5",
|
||||||
|
"namingSemanticSha256": "5286bbbbd37367c6630c7ae2b59502be156b30bcd92798f775bc3c85d86a97bc"
|
||||||
|
},
|
||||||
|
"mutation": {
|
||||||
|
"scope": "second-operation-only",
|
||||||
|
"parameter": "toolOffsetX",
|
||||||
|
"trajectory": [
|
||||||
|
10,
|
||||||
|
9,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"beforeValue": 10,
|
||||||
|
"editedValue": 9,
|
||||||
|
"restoredValue": 10,
|
||||||
|
"changed": true,
|
||||||
|
"restoredExactly": true,
|
||||||
|
"editedEvidence": {
|
||||||
|
"operation": "common",
|
||||||
|
"builder": "BRepAlgoAPI_Common",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 10,
|
||||||
|
"edges": 20,
|
||||||
|
"vertices": 12,
|
||||||
|
"volume": 100,
|
||||||
|
"area": 130,
|
||||||
|
"bounds": [
|
||||||
|
8.9999999,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
13.0000001,
|
||||||
|
5.0000001,
|
||||||
|
5.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 189,
|
||||||
|
"selectedRecords": 2,
|
||||||
|
"ambiguousResults": 24,
|
||||||
|
"historySha256": "8f261b8808601b450505468dd5cb9f4770383aec3239298414525c39d44b8edb",
|
||||||
|
"namingEvidenceSha256": "d3e61c87153732e0b5b335867a995af0736365dd56f6c33d8c55997af93dd651",
|
||||||
|
"namingSemanticSha256": "60cf00e28e3c1949c7d0a713755acc1cb58098afdc883f83c618b29a9b303d0e"
|
||||||
|
},
|
||||||
|
"restoredEvidence": {
|
||||||
|
"operation": "common",
|
||||||
|
"builder": "BRepAlgoAPI_Common",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 6,
|
||||||
|
"edges": 12,
|
||||||
|
"vertices": 8,
|
||||||
|
"volume": 75,
|
||||||
|
"area": 110,
|
||||||
|
"bounds": [
|
||||||
|
9.9999999,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
13.0000001,
|
||||||
|
5.0000001,
|
||||||
|
5.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 240,
|
||||||
|
"selectedRecords": 1,
|
||||||
|
"ambiguousResults": 20,
|
||||||
|
"historySha256": "4cec040527a627b73017af103188173f2460dfd41dfa46d8acee005ed80eb8dc",
|
||||||
|
"namingEvidenceSha256": "71ed437758d6e92affcc87bc92ff0a06557b8cac350cfe40e8b769099ad23af3",
|
||||||
|
"namingSemanticSha256": "5286bbbbd37367c6630c7ae2b59502be156b30bcd92798f775bc3c85d86a97bc"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"naming": {
|
||||||
|
"upstreamEvidenceRestored": true,
|
||||||
|
"downstreamEvidence": true,
|
||||||
|
"jsonRoundtripStable": true
|
||||||
|
},
|
||||||
|
"persistence": {
|
||||||
|
"baselineId": "freecad-1.1.1-ordered-operation-pair-resave",
|
||||||
|
"checks": {
|
||||||
|
"namingEvidenceStable": true,
|
||||||
|
"shapeStable": true
|
||||||
|
},
|
||||||
|
"freecadVersion": "1.1.1",
|
||||||
|
"gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d",
|
||||||
|
"pair": "fuse->common",
|
||||||
|
"phases": {
|
||||||
|
"initial": {
|
||||||
|
"namingEvidenceBytes": 10867,
|
||||||
|
"namingEvidenceSha256": "d04cd4d189cc9549f8ae9700a102526071281c0711f2edb0ff1e38fc27470ab5",
|
||||||
|
"pair": "fuse->common",
|
||||||
|
"shape": {
|
||||||
|
"area": 110,
|
||||||
|
"bounds": [
|
||||||
|
10,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
13,
|
||||||
|
5,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"edges": 12,
|
||||||
|
"faces": 6,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 8,
|
||||||
|
"volume": 75
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"reopened": {
|
||||||
|
"namingEvidenceBytes": 10867,
|
||||||
|
"namingEvidenceSha256": "d04cd4d189cc9549f8ae9700a102526071281c0711f2edb0ff1e38fc27470ab5",
|
||||||
|
"pair": "fuse->common",
|
||||||
|
"shape": {
|
||||||
|
"area": 110,
|
||||||
|
"bounds": [
|
||||||
|
10,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
13,
|
||||||
|
5,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"edges": 12,
|
||||||
|
"faces": 6,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 8,
|
||||||
|
"volume": 75
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resaved": {
|
||||||
|
"namingEvidenceBytes": 10867,
|
||||||
|
"namingEvidenceSha256": "d04cd4d189cc9549f8ae9700a102526071281c0711f2edb0ff1e38fc27470ab5",
|
||||||
|
"pair": "fuse->common",
|
||||||
|
"shape": {
|
||||||
|
"area": 110,
|
||||||
|
"bounds": [
|
||||||
|
10,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
13,
|
||||||
|
5,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"edges": 12,
|
||||||
|
"faces": 6,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 8,
|
||||||
|
"volume": 75
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"status": "pass"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"taskId": "TSN-PAIR-fuse-rotate",
|
||||||
|
"pair": "fuse->rotate",
|
||||||
|
"classification": "accepted",
|
||||||
|
"reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass",
|
||||||
|
"nativeDecision": "accepted",
|
||||||
|
"first": {
|
||||||
|
"operation": "fuse",
|
||||||
|
"builder": "BRepAlgoAPI_Fuse",
|
||||||
|
"inputCount": 2,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 13,
|
||||||
|
"edges": 29,
|
||||||
|
"vertices": 18,
|
||||||
|
"volume": 1075,
|
||||||
|
"area": 660,
|
||||||
|
"bounds": [
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
13.0000001,
|
||||||
|
10.0000001,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 52,
|
||||||
|
"selectedRecords": 7,
|
||||||
|
"ambiguousResults": 16,
|
||||||
|
"historySha256": "3c9d5be39dd201d2a637810cc9ae644ee5c056f7eab523ab3480a74c7dc5c427",
|
||||||
|
"namingEvidenceSha256": "fd409f86f18d6fa703b61a3858c55953a1dfa14865e568a48024400d469bed15",
|
||||||
|
"namingSemanticSha256": "4b26aadb2ea960138e17671468b18ee999e37f20099fc26dd39619e211fd699b"
|
||||||
|
},
|
||||||
|
"second": {
|
||||||
|
"operation": "rotate",
|
||||||
|
"builder": "BRepBuilderAPI_Transform",
|
||||||
|
"inputCount": 1,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 13,
|
||||||
|
"edges": 29,
|
||||||
|
"vertices": 18,
|
||||||
|
"volume": 1075,
|
||||||
|
"area": 660,
|
||||||
|
"bounds": [
|
||||||
|
-2.5881906,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
12.5570358,
|
||||||
|
12.2474488,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 187,
|
||||||
|
"selectedRecords": 11,
|
||||||
|
"ambiguousResults": 49,
|
||||||
|
"historySha256": "ac25647ecb694f2a760b41bcd58fcfc75ef36957a8792e13c7ec821bc93cef91",
|
||||||
|
"namingEvidenceSha256": "cd2d92741d0b05d91599d1ac8709c4397db44f30c6bdab0e92815e241f5e639e",
|
||||||
|
"namingSemanticSha256": "b7657ff63d563ef94469db9448bb0307b38798aa495458206884d975136fdba4"
|
||||||
|
},
|
||||||
|
"mutation": {
|
||||||
|
"scope": "second-operation-only",
|
||||||
|
"parameter": "angle",
|
||||||
|
"trajectory": [
|
||||||
|
15,
|
||||||
|
22.5,
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"beforeValue": 15,
|
||||||
|
"editedValue": 22.5,
|
||||||
|
"restoredValue": 15,
|
||||||
|
"changed": true,
|
||||||
|
"restoredExactly": true,
|
||||||
|
"editedEvidence": {
|
||||||
|
"operation": "rotate",
|
||||||
|
"builder": "BRepBuilderAPI_Transform",
|
||||||
|
"inputCount": 1,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 13,
|
||||||
|
"edges": 29,
|
||||||
|
"vertices": 18,
|
||||||
|
"volume": 1075,
|
||||||
|
"area": 660,
|
||||||
|
"bounds": [
|
||||||
|
-3.8268344,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
12.010434,
|
||||||
|
13.0656297,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 187,
|
||||||
|
"selectedRecords": 11,
|
||||||
|
"ambiguousResults": 49,
|
||||||
|
"historySha256": "ac25647ecb694f2a760b41bcd58fcfc75ef36957a8792e13c7ec821bc93cef91",
|
||||||
|
"namingEvidenceSha256": "0e63cafe49b8cd74f5f4239e38189666a2a0c8ed99f966187eeb77d96a5047ab",
|
||||||
|
"namingSemanticSha256": "b7657ff63d563ef94469db9448bb0307b38798aa495458206884d975136fdba4"
|
||||||
|
},
|
||||||
|
"restoredEvidence": {
|
||||||
|
"operation": "rotate",
|
||||||
|
"builder": "BRepBuilderAPI_Transform",
|
||||||
|
"inputCount": 1,
|
||||||
|
"historyProvider": "occt-native",
|
||||||
|
"namingStatus": "ambiguous",
|
||||||
|
"summary": {
|
||||||
|
"isValid": true,
|
||||||
|
"solids": 1,
|
||||||
|
"faces": 13,
|
||||||
|
"edges": 29,
|
||||||
|
"vertices": 18,
|
||||||
|
"volume": 1075,
|
||||||
|
"area": 660,
|
||||||
|
"bounds": [
|
||||||
|
-2.5881906,
|
||||||
|
-1e-7,
|
||||||
|
-1e-7,
|
||||||
|
12.5570358,
|
||||||
|
12.2474488,
|
||||||
|
10.0000001
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"historyRecords": 187,
|
||||||
|
"selectedRecords": 11,
|
||||||
|
"ambiguousResults": 49,
|
||||||
|
"historySha256": "ac25647ecb694f2a760b41bcd58fcfc75ef36957a8792e13c7ec821bc93cef91",
|
||||||
|
"namingEvidenceSha256": "61b4ce04b159cd390a9d35eccf7d65280a9ee69edc128b60372ea4e2fb908359",
|
||||||
|
"namingSemanticSha256": "b7657ff63d563ef94469db9448bb0307b38798aa495458206884d975136fdba4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"naming": {
|
||||||
|
"upstreamEvidenceRestored": true,
|
||||||
|
"downstreamEvidence": true,
|
||||||
|
"jsonRoundtripStable": true
|
||||||
|
},
|
||||||
|
"persistence": {
|
||||||
|
"baselineId": "freecad-1.1.1-ordered-operation-pair-resave",
|
||||||
|
"checks": {
|
||||||
|
"namingEvidenceStable": true,
|
||||||
|
"shapeStable": true
|
||||||
|
},
|
||||||
|
"freecadVersion": "1.1.1",
|
||||||
|
"gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d",
|
||||||
|
"pair": "fuse->rotate",
|
||||||
|
"phases": {
|
||||||
|
"initial": {
|
||||||
|
"namingEvidenceBytes": 23836,
|
||||||
|
"namingEvidenceSha256": "cd2d92741d0b05d91599d1ac8709c4397db44f30c6bdab0e92815e241f5e639e",
|
||||||
|
"pair": "fuse->rotate",
|
||||||
|
"shape": {
|
||||||
|
"area": 660,
|
||||||
|
"bounds": [
|
||||||
|
-2.5881905,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
12.5570357,
|
||||||
|
12.2474487,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"edges": 29,
|
||||||
|
"faces": 13,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 18,
|
||||||
|
"volume": 1075
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"reopened": {
|
||||||
|
"namingEvidenceBytes": 23836,
|
||||||
|
"namingEvidenceSha256": "cd2d92741d0b05d91599d1ac8709c4397db44f30c6bdab0e92815e241f5e639e",
|
||||||
|
"pair": "fuse->rotate",
|
||||||
|
"shape": {
|
||||||
|
"area": 660,
|
||||||
|
"bounds": [
|
||||||
|
-2.5881905,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
12.5570357,
|
||||||
|
12.2474487,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"edges": 29,
|
||||||
|
"faces": 13,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 18,
|
||||||
|
"volume": 1075
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resaved": {
|
||||||
|
"namingEvidenceBytes": 23836,
|
||||||
|
"namingEvidenceSha256": "cd2d92741d0b05d91599d1ac8709c4397db44f30c6bdab0e92815e241f5e639e",
|
||||||
|
"pair": "fuse->rotate",
|
||||||
|
"shape": {
|
||||||
|
"area": 660,
|
||||||
|
"bounds": [
|
||||||
|
-2.5881905,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
12.5570357,
|
||||||
|
12.2474487,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"edges": 29,
|
||||||
|
"faces": 13,
|
||||||
|
"solids": 1,
|
||||||
|
"valid": true,
|
||||||
|
"vertices": 18,
|
||||||
|
"volume": 1075
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"status": "pass"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": {
|
||||||
|
"registeredOperations": 19,
|
||||||
|
"orderedPairs": 361,
|
||||||
|
"classifiedPairs": 4,
|
||||||
|
"accepted": 4,
|
||||||
|
"rejected": 0,
|
||||||
|
"unknown": 357
|
||||||
|
}
|
||||||
|
}
|
||||||
3425
config/freecad-production-drift-classification.json
Normal file
3425
config/freecad-production-drift-classification.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,7 @@
|
|||||||
{ "id": "EX-TSN-01", "title": "Capture native stage Shape and Generated/Modified/Deleted for every builder", "priority": "P0", "status": "completed", "dependencies": ["EX-KER-01", "EX-TSN-00"], "deliverables": ["All builder-stage captures", "Multi-input and one-to-many lineage", "Local feature recompute history"], "acceptance": ["Every feature result relation has a producing native stage", "No final-result index is applied to an intermediate Shape"], "evidence": ["check:freecad-composite-history-elementmap", "check:freecad-tsn-stage-evidence"], "exactBlockedBy": [] },
|
{ "id": "EX-TSN-01", "title": "Capture native stage Shape and Generated/Modified/Deleted for every builder", "priority": "P0", "status": "completed", "dependencies": ["EX-KER-01", "EX-TSN-00"], "deliverables": ["All builder-stage captures", "Multi-input and one-to-many lineage", "Local feature recompute history"], "acceptance": ["Every feature result relation has a producing native stage", "No final-result index is applied to an intermediate Shape"], "evidence": ["check:freecad-composite-history-elementmap", "check:freecad-tsn-stage-evidence"], "exactBlockedBy": [] },
|
||||||
{ "id": "EX-TSN-02", "title": "Expose native MappedNameRef and StringHasher decisions for every feature", "priority": "P0", "status": "completed", "dependencies": ["EX-TSN-01"], "deliverables": ["Native naming callback ABI", "Per-stage StringHasher evidence", "Lossless ElementMap2 token generation"], "acceptance": ["All new tokens originate in native evidence", "FreeCAD round-trip names remain byte and semantic stable"], "evidence": ["check:freecad-native-naming-evidence", "check:freecad-sketcher-partdesign-abi", "check:freecad-naming-sdk", "check:freecad-naming-production", "check:chrome-freecad-naming-production", "check:freecad-private-naming-boundary", "check:occt-history-artifact"], "exactBlockedBy": [] },
|
{ "id": "EX-TSN-02", "title": "Expose native MappedNameRef and StringHasher decisions for every feature", "priority": "P0", "status": "completed", "dependencies": ["EX-TSN-01"], "deliverables": ["Native naming callback ABI", "Per-stage StringHasher evidence", "Lossless ElementMap2 token generation"], "acceptance": ["All new tokens originate in native evidence", "FreeCAD round-trip names remain byte and semantic stable"], "evidence": ["check:freecad-native-naming-evidence", "check:freecad-sketcher-partdesign-abi", "check:freecad-naming-sdk", "check:freecad-naming-production", "check:chrome-freecad-naming-production", "check:freecad-private-naming-boundary", "check:occt-history-artifact"], "exactBlockedBy": [] },
|
||||||
{ "id": "EX-TSN-03", "title": "Resolve isomorphic topology only from unique native provenance", "priority": "P0", "status": "completed", "dependencies": ["EX-TSN-01", "EX-TSN-02"], "deliverables": ["Symmetric Boolean corpus", "Candidate provenance graph", "Ambiguity repair lifecycle"], "acceptance": ["Unique native sources resolve deterministically", "Non-unique sources remain ambiguous across save, undo and recompute"], "evidence": ["test:topology-replay", "test:facade", "check:freecad-isomorphic-provenance", "check:freecad-naming-production", "check:chrome-freecad-naming-production", "check:freecad-exact-history-elementmap-gate"], "exactBlockedBy": [] },
|
{ "id": "EX-TSN-03", "title": "Resolve isomorphic topology only from unique native provenance", "priority": "P0", "status": "completed", "dependencies": ["EX-TSN-01", "EX-TSN-02"], "deliverables": ["Symmetric Boolean corpus", "Candidate provenance graph", "Ambiguity repair lifecycle"], "acceptance": ["Unique native sources resolve deterministically", "Non-unique sources remain ambiguous across save, undo and recompute"], "evidence": ["test:topology-replay", "test:facade", "check:freecad-isomorphic-provenance", "check:freecad-naming-production", "check:chrome-freecad-naming-production", "check:freecad-exact-history-elementmap-gate"], "exactBlockedBy": [] },
|
||||||
{ "id": "EX-TSN-04", "title": "Close topology naming across all feature edits and FCStd round-trips", "priority": "P0", "status": "in_progress", "dependencies": ["EX-TSN-02", "EX-TSN-03"], "deliverables": ["Cross-feature mutation matrix", "ElementMap2 history migration", "Long-chain LinkSub stability report"], "acceptance": ["Wrong bindings, unexplained relations and name drift are zero for the exhaustive corpus"], "evidence": ["check:freecad-isomorphic-provenance", "check:freecad-composite-history-elementmap", "check:freecad-tsn-stage-correlation", "check:freecad-fcstd-roundtrip", "check:freecad-exact-history-elementmap-gate", "check:freecad-recovered-naming-classification"], "exactBlockedBy": ["The locked 30-case corpus passes 30/30 native property mutations, final-shape propagation and 219/219 geometry-stage restores; partdesign-plain has classified 2 recovered naming stages as allowed native evolution from two deterministic runs with stable resave, while 10 PartDesign cases/26 recovered naming stages remain unclassified; the five-stage chain still has 3/5 generic Shape proxies, no rotate mutation family, 5 semantic topology restore drifts, and only 4/361 ordered operation pairs classified"] }
|
{ "id": "EX-TSN-04", "title": "Close topology naming across all feature edits and FCStd round-trips", "priority": "P0", "status": "in_progress", "dependencies": ["EX-TSN-02", "EX-TSN-03"], "deliverables": ["Cross-feature mutation matrix", "ElementMap2 history migration", "Long-chain LinkSub stability report"], "acceptance": ["Wrong bindings, unexplained relations and name drift are zero for the exhaustive corpus"], "evidence": ["check:freecad-isomorphic-provenance", "check:freecad-composite-history-elementmap", "check:freecad-tsn-stage-correlation", "check:freecad-fcstd-roundtrip", "check:freecad-exact-history-elementmap-gate", "check:freecad-recovered-naming-classification", "check:freecad-production-drift-classification", "check:freecad-ordered-operation-pairs"], "exactBlockedBy": ["The locked 30-case corpus passes 30/30 native property mutations, final-shape propagation and 219/219 geometry-stage restores; all 11 PartDesign recovered-naming cases/28 stages and both production restore-topology cases/5 stages are classified as allowed native evolution from independent deterministic replays with stable resave; the five-stage chain still has 3/5 generic Shape proxies and no registered rotate mutation family, while only 8/361 ordered operation pairs are classified and replayed"] }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"wrong-document-root": 77
|
"wrong-document-root": 77
|
||||||
},
|
},
|
||||||
"timing": {
|
"timing": {
|
||||||
"p95Ms": 0.126,
|
"p95Ms": 0.179,
|
||||||
"maxMs": 2.592
|
"maxMs": 3.391
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
"zero-revolution-axis": 67
|
"zero-revolution-axis": 67
|
||||||
},
|
},
|
||||||
"timing": {
|
"timing": {
|
||||||
"p95Ms": 0.02,
|
"p95Ms": 0.023,
|
||||||
"maxMs": 0.928
|
"maxMs": 1.521
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"invalid": 800
|
"invalid": 800
|
||||||
},
|
},
|
||||||
"timing": {
|
"timing": {
|
||||||
"p95Ms": 0.029,
|
"p95Ms": 0.035,
|
||||||
"maxMs": 0.662
|
"maxMs": 0.893
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -390,7 +390,7 @@
|
|||||||
{
|
{
|
||||||
"path": "sw.js",
|
"path": "sw.js",
|
||||||
"bytes": 1390,
|
"bytes": 1390,
|
||||||
"sha256": "8b0477955514535bb11cef3733135b67422cc8c085b4331c3b9cb1a1adc9d852"
|
"sha256": "98ec667a774f8370ed654e457b86d4943b2f1eb89e228bd4e7e652b31a51b982"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"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": "ad5f25aeb7e1382b3172d9919357a9831ac198841e54304a6789665cd21cda31",
|
"payloadSha256": "5172b35d4d194483ac1934a1653259b1c7f5bb78c5ab4a68f7e5033cf2a22b86",
|
||||||
"signature": "c8xaS8E7BOThrQKOK9WlCLpMazuqlBZ6eMKbCTt+tzeC0b4TyEEaiVvjelUtFDjo5PK0fVYPeYISrS2895LTDA=="
|
"signature": "FoaYFhliT+/njf8hXECKj5IoCeHPj1MnpbTBIw/FxzYpfyrgQ01nuPkwslM4okUk3d97cncjaXnEkDA7lZBtDw=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1961,3 +1961,27 @@ recovery 进程从两段 open-wire Sketch 启动 Pad,首次接受捕获 `Input
|
|||||||
活动队列已机器前移为 119 completed、1 in_progress、367 pending,唯一下一项为 `TSN-DRIFT-002`,即只解释 `partdesign-reverse` 的恢复命名演进。`EX-TSN-04` 仍为 in_progress:11 个 PartDesign case/28 个恢复命名阶段中已关闭 2 个 case/4 个阶段,剩余 9/24,系统 exact 与模块等级均不提升。
|
活动队列已机器前移为 119 completed、1 in_progress、367 pending,唯一下一项为 `TSN-DRIFT-002`,即只解释 `partdesign-reverse` 的恢复命名演进。`EX-TSN-04` 仍为 in_progress:11 个 PartDesign case/28 个恢复命名阶段中已关闭 2 个 case/4 个阶段,剩余 9/24,系统 exact 与模块等级均不提升。
|
||||||
|
|
||||||
本轮聚焦分类、30-case composite、TSN correlation、exact history、执行计划与队列门禁均通过;完整 `./npmw run verify` 以退出码 0 完成,包含 199 项 Facade 测试、生产构建、79 个签名发布文件、34 模块 release closure 和 Ed25519 验签。验证后 `git diff --check`、310 个 JSON 解析与发布产物一致性复核再次通过。
|
本轮聚焦分类、30-case composite、TSN correlation、exact history、执行计划与队列门禁均通过;完整 `./npmw run verify` 以退出码 0 完成,包含 199 项 Facade 测试、生产构建、79 个签名发布文件、34 模块 release closure 和 Ed25519 验签。验证后 `git diff --check`、310 个 JSON 解析与发布产物一致性复核再次通过。
|
||||||
|
|
||||||
|
## 251. 2026-08-15 计划重审与 TSN-DRIFT-002 Reverse Pad 恢复命名分类
|
||||||
|
|
||||||
|
执行总计划新增可机器核对的完成度仪表盘,重申 83/83 兼容实现不等于 exact;当前 exact 仍为 5/52,34 模块仍为 0 exact、26 compatible、5 proxy、3 development。TSN 恢复漂移队列已将 11 个 PartDesign case 全部锁定到具体 target property、before/edited/restored 值、drift ordinal 和阶段数;每个 case 再按 contract、独立复跑、三摘要指纹、几何恢复、持久化和唯一决策拆为 A-F 六个最小检查点。
|
||||||
|
|
||||||
|
`partdesign-reverse` 在锁定 FreeCAD 1.1.1 中编辑 `Pad12.Length`,属性轨迹为 `5 -> 5.75 -> 5`。第二个独立原生进程再次完成 30/30 case;Body12 与 Pad12 的 geometry digest 在恢复后与 before 精确一致,relation/semantic-name digest 则演进到 restored/nominal 状态。锁定参考与独立复跑的 before/edited/restored 三相指纹逐字段一致,且演进值在 save/reopen/resave 三态中不再变化。
|
||||||
|
|
||||||
|
该差异因此唯一分类为 `allowed_evolution`,`implementationDefect=false`。分类账本现包含连续前缀 `TSN-DRIFT-000..002`,共 3 case/6 stage,剩余 8 case/22 stage。队列生成器已自动前移为 120 completed、1 in_progress、366 pending,唯一后继为 `TSN-DRIFT-003 partdesign-taper`;系统 exact 与模块等级均不提升。
|
||||||
|
|
||||||
|
## 252. 2026-08-15 TSN-DRIFT-003 Tapered Pad 恢复命名分类
|
||||||
|
|
||||||
|
`partdesign-taper` 在锁定 FreeCAD 1.1.1 中编辑 `Pad13.Length`,属性轨迹为 `6 -> 6.75 -> 6`。第二个独立原生进程再次完成 30/30 case;Body13 与 Pad13 的 geometry digest 在恢复后与 before 精确一致,relation/semantic-name digest 则演进到 restored/nominal 状态。锁定参考与独立复跑的 before/edited/restored 三相指纹逐字段一致,且演进值在 save/reopen/resave 三态中不再变化。
|
||||||
|
|
||||||
|
该差异因此唯一分类为 `allowed_evolution`,`implementationDefect=false`。分类账本现包含连续前缀 `TSN-DRIFT-000..003`,共 4 case/8 stage,剩余 7 case/20 stage。队列生成器已自动前移为 121 completed、1 in_progress、365 pending,唯一后继为 `TSN-DRIFT-004 partdesign-twoside`;`EX-TSN-04` 仍为 in_progress,系统 exact 与模块等级均不提升。
|
||||||
|
|
||||||
|
本轮聚焦 composite、TSN correlation、exact history、生产命名与 199 项 Facade 测试均通过;完整 `./npmw run verify` 以退出码 0 完成,包含 5000 个确定性 fuzz 样本、生产构建、79 个签名发布文件、34 模块 release closure 和 Ed25519 验签。
|
||||||
|
|
||||||
|
## 253. 2026-08-15 TSN-PAIR fuse->rotate 跨族分类
|
||||||
|
|
||||||
|
有序操作对执行器已从 Boolean 后继扩展到单输入 Rotate。第二阶段直接调用生产 OCCT WASM 的 `rotateHistoryFromStep`,报告锁定 `historyProvider=occt-native`、`builder=BRepBuilderAPI_Transform` 与 `inputCount=1`;Rotate 名义态采集 187 条 transform history,分类为 11 个稳定结果与 49 个歧义结果,上游 Fuse 的候选 provenance 通过生产 `nativeNamingAbi` 路径继续传播。
|
||||||
|
|
||||||
|
Rotate 使用只编辑第二操作的角度轨迹 `15 -> 22.5 -> 15`。22.5 度阶段改变包围盒,恢复后 Shape 摘要、原生 history SHA-256 与语义命名 SHA-256 精确回到 15 度基线;最终 Shape 和 23836 字节命名证据在 FreeCAD 1.1.1 的 save/reopen/resave 三态保持稳定。检查器同时锁定执行器自身、命名矩阵、FCStd resave harness 与三项 OCCT 产物的 bytes/SHA-256,防止旧报告通过。
|
||||||
|
|
||||||
|
`fuse->rotate` 因此以 accepted 关闭。TSN correlation 当前覆盖 8/361 对,剩余 353 对;活动队列为 134 completed、1 in_progress、352 pending,唯一下一项为 `TSN-PAIR-fuse-pad`。这条独立 Rotate 变异证据不等于全局注册 rotate mutation family 已关闭,`EX-TSN-04` 继续保持 in_progress。
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ EX-DOC-01 -> EX-DOC-03 ---------^
|
|||||||
|
|
||||||
### P0-B:关闭跨特征拓扑命名
|
### P0-B:关闭跨特征拓扑命名
|
||||||
|
|
||||||
对应 `EX-KER-01`、`EX-TSN-04`。锁定 30-case corpus 已按 `9 Boolean + 11 PartDesign + 6 复合 Boolean + 4 dress-up` 逐案例执行原生属性编辑,30/30 都传播到最终 Shape,219/219 阶段几何恢复,657 条 before/edited/restored 阶段记录完成 fail-closed 对账;恢复状态再保存、重开、二次保存后的错误绑定、未解释关系和名称漂移均为零。FreeCAD 重算使 11 个 PartDesign 案例的 28 个 mutation 恢复阶段产生原生命名摘要演进;其中 `partdesign-plain` 与 `partdesign-midplane` 的 Body/Pad 共 4 个阶段已用第二次独立原生复跑分类为允许演进,恢复几何与初值一致且演进命名在 save/reopen/resave 后稳定,剩余 9 个案例/24 个阶段待解释。生产 Worker 五阶段链另有 5/5 几何编辑恢复,但顺序链只有 2/5 原生 builder,3/5 为通用 Shape 代理,rotate 缺少原生 mutation family,2/5 恢复用例的 5 个下游语义拓扑摘要发生变化,19 类生产操作的 361 个有序组合仅分类回放 4 个,因此门禁继续 fail-closed。
|
对应 `EX-KER-01`、`EX-TSN-04`。锁定 30-case corpus 已按 `9 Boolean + 11 PartDesign + 6 复合 Boolean + 4 dress-up` 逐案例执行原生属性编辑,30/30 都传播到最终 Shape,219/219 阶段几何恢复,657 条 before/edited/restored 阶段记录完成 fail-closed 对账;恢复状态再保存、重开、二次保存后的错误绑定、未解释关系和名称漂移均为零。11 个 PartDesign 案例/28 个恢复命名阶段与生产链 2 个恢复拓扑案例/5 个下游阶段均已通过独立原生复跑分类为允许演进,恢复几何与初值一致且演进命名在 save/reopen/resave 后稳定。生产 Worker 五阶段顺序链仍只有 2/5 原生 builder,3/5 为通用 Shape 代理,rotate 仍缺注册 mutation family;19 类生产操作的 361 个有序组合现覆盖回放 8 个,其中 `fuse->rotate` 使用单输入 `BRepBuilderAPI_Transform` 和 15→22.5→15 独立角度变异,因此门禁继续 fail-closed。
|
||||||
|
|
||||||
### P0-C:关闭 App 文档语义
|
### P0-C:关闭 App 文档语义
|
||||||
|
|
||||||
@@ -101,8 +101,8 @@ P1/P2 的 GUI 全量对标、其他工作台、代理模块和跨浏览器发布
|
|||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| M0 | 收口当前工作树 | `completed` | 将 TSN、Property、CAM/LinuxCNC 三组已有增量分别核对证据和边界,不再混入新功能 | 聚焦门禁、完整 `verify`、`git diff --check`、全部 JSON 解析通过;计划与报告无陈旧哈希 |
|
| M0 | 收口当前工作树 | `completed` | 将 TSN、Property、CAM/LinuxCNC 三组已有增量分别核对证据和边界,不再混入新功能 | 聚焦门禁、完整 `verify`、`git diff --check`、全部 JSON 解析通过;计划与报告无陈旧哈希 |
|
||||||
| M1 | `EX-ORA-01` 运行时清册闭合 | `in_progress` | 对 352 个注册对象、1111 个启动 GUI command、19 个 source-only command、2 个 context-only command 和 GUI 工作流状态生成差异账本 | 每个候选均为 runtime-backed 或有机器可读排除原因;成功/禁用/失败/取消/恢复工作流未知项为零 |
|
| M1 | `EX-ORA-01` 运行时清册闭合 | `in_progress` | 对 352 个注册对象、1111 个启动 GUI command、19 个 source-only command、2 个 context-only command 和 GUI 工作流状态生成差异账本 | 每个候选均为 runtime-backed 或有机器可读排除原因;成功/禁用/失败/取消/恢复工作流未知项为零 |
|
||||||
| M2 | `EX-TSN-04A` 漂移判定 | `in_progress` | 逐项解释 11 个 PartDesign case 的 28 个恢复命名摘要演进,以及五阶段链的 5 个恢复拓扑变化 | 每个差异都有 FreeCAD 复跑证据并被判定为稳定语义、允许演进或实现缺陷;未知项为零,缺陷有回归测试 |
|
| M2 | `EX-TSN-04A` 漂移判定 | `completed` | 逐项解释 11 个 PartDesign case 的 28 个恢复命名摘要演进,以及五阶段链的 5 个恢复拓扑变化 | 每个差异都有 FreeCAD 复跑证据并被判定为稳定语义、允许演进或实现缺陷;未知项为零,缺陷有回归测试 |
|
||||||
| M3 | `EX-TSN-04B` 转换矩阵闭合 | `after-M2` | 将 19×19 的 361 个有序操作对按原生输入/输出类型分类;原生允许的组合使用真实 builder 回放,原生拒绝的组合保存失败 oracle | 361/361 已分类;可执行组合的 history/naming/mutation/resave 通过;不可执行组合的原生错误可复现;不再用通用 Shape 代理冒充 feature builder |
|
| M3 | `EX-TSN-04B` 转换矩阵闭合 | `in_progress` | 将 19×19 的 361 个有序操作对按原生输入/输出类型分类;原生允许的组合使用真实 builder 回放,原生拒绝的组合保存失败 oracle | 361/361 已分类;可执行组合的 history/naming/mutation/resave 通过;不可执行组合的原生错误可复现;不再用通用 Shape 代理冒充 feature builder |
|
||||||
| M4 | `EX-DOC-01` Property 批次 | `after-M1` | 先做高复用 App 类型与链接/列表类型,再处理 Material、File、PythonObject 等带安全或工作台边界的类型 | 每批均具备原生值/状态/editor oracle、Facade codec、FCStd reopen/resave、Undo/Redo 和 Chrome 证据;opaque 数量只按机器报告下降 |
|
| M4 | `EX-DOC-01` Property 批次 | `after-M1` | 先做高复用 App 类型与链接/列表类型,再处理 Material、File、PythonObject 等带安全或工作台边界的类型 | 每批均具备原生值/状态/editor oracle、Facade codec、FCStd reopen/resave、Undo/Redo 和 Chrome 证据;opaque 数量只按机器报告下降 |
|
||||||
| M5 | `EX-DOC-02/03` 文档闭环 | `after-M3+M4` | observer 顺序、事务 abort、局部重算失败、Extension、FeaturePython、copy/clone/delete/relink | 原生与浏览器事件序列一致;失败不污染最后有效状态;资源归零;随后再推进 `EX-DOC-04` |
|
| M5 | `EX-DOC-02/03` 文档闭环 | `after-M3+M4` | observer 顺序、事务 abort、局部重算失败、Extension、FeaturePython、copy/clone/delete/relink | 原生与浏览器事件序列一致;失败不污染最后有效状态;资源归零;随后再推进 `EX-DOC-04` |
|
||||||
| M6 | `EX-ORA-02/KER/PART/PD/SK` 纵向切片 | `after-M2+M5` | 由 oracle 差异报告选择一个特征族,一次完成参数、失败、恢复、history、命名、FCStd 和 UI Task 生命周期 | 单特征全部证据通过后才选择下一族;不按整个工作台批量提升 exact |
|
| M6 | `EX-ORA-02/KER/PART/PD/SK` 纵向切片 | `after-M2+M5` | 由 oracle 差异报告选择一个特征族,一次完成参数、失败、恢复、history、命名、FCStd 和 UI Task 生命周期 | 单特征全部证据通过后才选择下一族;不按整个工作台批量提升 exact |
|
||||||
@@ -113,18 +113,18 @@ M3 不要求把 FreeCAD 本身拒绝的组合强行实现为顺序特征链。
|
|||||||
|
|
||||||
### 6.1 微任务队列
|
### 6.1 微任务队列
|
||||||
|
|
||||||
机器真值为 `config/freecad-active-work-queue.json`,由 `generate:freecad-active-work-queue` 从原生报告生成,并由 `check:freecad-active-work-queue` fail-closed 校验。当前共 487 个微任务:119 `completed`、1 `in_progress`、367 `pending`;`maxInProgress=1`,唯一下一任务是 `TSN-DRIFT-002`。
|
机器真值为 `config/freecad-active-work-queue.json`,由 `generate:freecad-active-work-queue` 从原生报告生成,并由 `check:freecad-active-work-queue` fail-closed 校验。当前共 487 个微任务:134 `completed`、1 `in_progress`、352 `pending`;`maxInProgress=1`,唯一下一任务是 `TSN-PAIR-fuse-pad`。
|
||||||
|
|
||||||
| 微里程碑 | 任务粒度 | 数量 | 状态 | 下一退出条件 |
|
| 微里程碑 | 任务粒度 | 数量 | 状态 | 下一退出条件 |
|
||||||
| --- | --- | ---: | --- | --- |
|
| --- | --- | ---: | --- | --- |
|
||||||
| `ORA-GUI-BASELINE` | 1 个配置边界或 1 个 GUI 命令分片 | 106 | 106 completed | 已关闭:100/100 分片、1111/1111 命令状态、2 个上下文延迟命令均有证据 |
|
| `ORA-GUI-BASELINE` | 1 个配置边界或 1 个 GUI 命令分片 | 106 | 106 completed | 已关闭:100/100 分片、1111/1111 命令状态、2 个上下文延迟命令均有证据 |
|
||||||
| `ORA-GUI-WORKFLOWS` | 1 个命令族的 1 种工作流状态 | 7 | 7 completed | `PartDesign_Pad` 五态原生工作流、聚焦断言和 exact blocker 更新已关闭 |
|
| `ORA-GUI-WORKFLOWS` | 1 个命令族的 1 种工作流状态 | 7 | 7 completed | `PartDesign_Pad` 五态原生工作流、聚焦断言和 exact blocker 更新已关闭 |
|
||||||
| `TSN-RECOVERY-DRIFT` | 1 个原生 case 或 1 个生产 mutation | 13 | 2 completed / 1 in_progress / 10 pending | `partdesign-plain` 与 `partdesign-midplane` 已分类为允许演进;当前只解释 `partdesign-reverse` |
|
| `TSN-RECOVERY-DRIFT` | 1 个原生 case 或 1 个生产 mutation | 13 | 13 completed | 11 个 PartDesign case 与生产 `cut`/`rotate` 漂移均已分类为允许演进 |
|
||||||
| `TSN-ORDERED-PAIRS` | 1 个有序操作对 | 361 | 4 completed / 357 pending | 每次只分类并回放一个 `from->to`,不按特征族批量关闭 |
|
| `TSN-ORDERED-PAIRS` | 1 个有序操作对 | 361 | 8 completed / 1 in_progress / 352 pending | `fuse->rotate` 已关闭;当前只分类 `fuse->pad` |
|
||||||
|
|
||||||
`ORA-GUI-WORKFLOWS` 已按七步关闭:选定命令族、成功、禁用、失败、取消、恢复、更新 blocker/门禁。一步只新增一种原生状态证据,前一步未通过时不启动后一步。
|
`ORA-GUI-WORKFLOWS` 已按七步关闭:选定命令族、成功、禁用、失败、取消、恢复、更新 blocker/门禁。一步只新增一种原生状态证据,前一步未通过时不启动后一步。
|
||||||
|
|
||||||
`TSN-RECOVERY-DRIFT` 的 13 个独立任务按以下顺序执行:`partdesign-plain`(已完成,允许演进)、`partdesign-midplane`(已完成,允许演进)、`partdesign-reverse`(当前)、`partdesign-taper`、`partdesign-twoside`、`partdesign-pocket`、`partdesign-pocket-through`、`partdesign-pocket-midplane`、`partdesign-pocket-twoside`、`partdesign-pocket-taper`、`partdesign-pocket-up-to-face`、生产 `cut`、生产 `rotate`。每个任务只允许一种结论:稳定语义、允许演进或实现缺陷;不得以几何恢复代替命名解释。分类账本为 `config/freecad-recovered-naming-classification.json`,其原生 harness 哈希、两次运行一致性和持久化稳定性由 `check:freecad-recovered-naming-classification` 校验。
|
`TSN-RECOVERY-DRIFT` 的 13 个独立任务已全部关闭;11 个 PartDesign case 记录在 `config/freecad-recovered-naming-classification.json`,生产 `cut`/`rotate` 记录在 `config/freecad-production-drift-classification.json`。两类 checker 都锁定原生 harness 哈希、两次运行一致性和持久化稳定性,且每项只有稳定语义、允许演进或实现缺陷一种结论。
|
||||||
|
|
||||||
100 个 GUI 分片分别对应 `ORA-GUI-SHARD-000..099`,每片覆盖排序命令全集中的 11 或 12 个命令。每片有独立报告、SHA-256、起止索引和退出条件;合并器要求 100 个区间连续、1111 个 ID 唯一且全集哈希一致。
|
100 个 GUI 分片分别对应 `ORA-GUI-SHARD-000..099`,每片覆盖排序命令全集中的 11 或 12 个命令。每片有独立报告、SHA-256、起止索引和退出条件;合并器要求 100 个区间连续、1111 个 ID 唯一且全集哈希一致。
|
||||||
|
|
||||||
|
|||||||
@@ -48,13 +48,32 @@
|
|||||||
- Oracle:352 个注册对象、348 个可实例化对象、4 个不可实例化对象、1111 个启动 GUI command、19 个 source-only command 和 2 个 context-only command 已分类;命令族的成功、禁用、失败、取消、恢复流程仍未穷尽。
|
- Oracle:352 个注册对象、348 个可实例化对象、4 个不可实例化对象、1111 个启动 GUI command、19 个 source-only command 和 2 个 context-only command 已分类;命令族的成功、禁用、失败、取消、恢复流程仍未穷尽。
|
||||||
- Property:85 种运行时类型、5510 条记录中,22 种/4304 条为通用原生 codec,5 种/683 条为专用 codec,58 种/523 条仍为 opaque proxy。
|
- Property:85 种运行时类型、5510 条记录中,22 种/4304 条为通用原生 codec,5 种/683 条为专用 codec,58 种/523 条仍为 opaque proxy。
|
||||||
- Property status:15 类已观察状态均已进入类型化 Facade 行为;`LockDynamic` 和 `PartialTrigger` 已有原生事务证据,但完整 observer 与局部重算序列未关闭。
|
- Property status:15 类已观察状态均已进入类型化 Facade 行为;`LockDynamic` 和 `PartialTrigger` 已有原生事务证据,但完整 observer 与局部重算序列未关闭。
|
||||||
- TSN:30/30 原生 mutation、219/219 几何阶段恢复通过;`partdesign-plain` 与 `partdesign-midplane` 的 4 个恢复命名阶段已通过第二次独立原生复跑分类为允许演进,剩余 9 个 PartDesign case/24 个阶段待解释。
|
- TSN:30/30 原生 mutation、219/219 几何阶段恢复通过;11 个 PartDesign case/28 个恢复命名阶段均已通过第二次独立原生复跑分类为允许演进。
|
||||||
- 生产命名链:五阶段 5/5 几何恢复,但仍有 3/5 通用 Shape 代理、缺 rotate mutation family、5 个下游语义拓扑恢复漂移。
|
- 生产命名链:五阶段 5/5 几何恢复,2 个恢复拓扑 case/5 个下游阶段已分类为允许演进;仍有 3/5 通用 Shape 代理并缺注册 rotate mutation family。
|
||||||
- 有序操作:19×19 共 361 对,仅 4 对已有分类回放,357 对待原生接受/拒绝判定。
|
- 有序操作:19×19 共 361 对,8 对已有分类回放,353 对待原生接受/拒绝判定。
|
||||||
- FCStd:支持的原生 codec 与未知资源保留已有证据,但所有对象/属性/Extension/Shape/ElementMap2/StringHasher 的 FreeCAD-Web-FreeCAD 双向变异未穷尽。
|
- FCStd:支持的原生 codec 与未知资源保留已有证据,但所有对象/属性/Extension/Shape/ElementMap2/StringHasher 的 FreeCAD-Web-FreeCAD 双向变异未穷尽。
|
||||||
- GUI:应用壳和代表性工作流已有浏览器证据,但动态命令、Task、对话框、焦点、上下文和逐工作台流程没有完整原生对照。
|
- GUI:应用壳和代表性工作流已有浏览器证据,但动态命令、Task、对话框、焦点、上下文和逐工作台流程没有完整原生对照。
|
||||||
- 发布:系统级 exact 为 false,`EX-REL-01` 为 pending,跨浏览器、长期运行和全模块 exact promotion 尚未开始。
|
- 发布:系统级 exact 为 false,`EX-REL-01` 为 pending,跨浏览器、长期运行和全模块 exact promotion 尚未开始。
|
||||||
|
|
||||||
|
### 2.4 可机器核对的完成度仪表盘
|
||||||
|
|
||||||
|
| 范围 | 当前值 | 已完成代表什么 | 下一个可关闭单元 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 兼容实现计划 | 83/83 completed | 已有可运行 Web 实现、门禁和能力边界 | 不再用该数字表示 exact 进度 |
|
||||||
|
| exact 计划 | 5/52 completed,36 in_progress,11 pending | 仅 `EX-TSN-00..03` 与 `EX-PD-02` 达到自身验收范围 | `EX-TSN-04` 的恢复漂移与有序组合 |
|
||||||
|
| 模块能力 | 0 exact / 26 compatible / 5 proxy / 3 development | 34 模块均有明确对外等级,无 unexplained | 任一模块提升前必须关闭其 exact task |
|
||||||
|
| 原生 GUI 清册 | 1111 runtime / 19 source-only / 2 context-only | 命令 ID 和三种激活上下文已分类 | 选择下一命令族并逐个关闭五态 |
|
||||||
|
| Pad GUI 工作流 | 7/7 completed | success/disabled/failure/cancel/recovery 和 blocker 已对齐 | 不因单命令族完成而关闭 `EX-ORA-01` |
|
||||||
|
| TSN 30-case corpus | 30/30 mutation,219/219 几何恢复 | 几何传播与恢复已闭环 | 逐 case 解释 11 个命名漂移 |
|
||||||
|
| TSN 恢复命名 | 11/11 case,28/28 stage 已分类 | 全部具备第二次原生复跑与稳定 resave | 已关闭该队列,保持分类门禁 |
|
||||||
|
| 生产五阶段链 | 5/5 几何恢复,2/2 漂移 case 已分类,2/5 原生 builder | 漂移已解释且不错绑 | 逐 stage 去代理并补 rotate mutation family |
|
||||||
|
| 19x19 有序组合 | 8/361 已分类回放 | 4 条五阶段转换与 4 条 `fuse->*` 已覆盖 | `TSN-PAIR-fuse-pad` |
|
||||||
|
| Property codec | 27/85 类原生 codec,58 类 opaque | 4987/5510 记录可结构化处理 | 按 M04 顺序一次关闭 1 类 |
|
||||||
|
| FCStd | 23 个往返场景,未知差异 0 | 已支持范围内的当前样本稳定 | 对每种对象/Property/资源做双向 mutation |
|
||||||
|
| 活动微任务 | 487 项:134 completed / 1 in_progress / 352 pending | 队列满足 `maxInProgress=1` | 只允许执行 `TSN-PAIR-fuse-pad` |
|
||||||
|
|
||||||
|
仪表盘的任何数字变化都必须由配置/报告生成器证明;文档不能单独改变状态。
|
||||||
|
|
||||||
## 3. 目标架构和不可破坏边界
|
## 3. 目标架构和不可破坏边界
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -120,29 +139,42 @@ FCStd / STEP / IGES / mesh / CAM / engineering resources
|
|||||||
- `ORA-GUI-WF-005`:失败后在同一 Task 内修复 profile、提交、Undo/Redo、保存重开和二次保存,已完成。
|
- `ORA-GUI-WF-005`:失败后在同一 Task 内修复 profile、提交、Undo/Redo、保存重开和二次保存,已完成。
|
||||||
- `ORA-GUI-WF-006`:exact blocker、聚焦门禁和后继 TSN 队列已更新,已完成。
|
- `ORA-GUI-WF-006`:exact blocker、聚焦门禁和后继 TSN 队列已更新,已完成。
|
||||||
|
|
||||||
### 5.3 TSN 恢复漂移,13 项,执行中
|
### 5.3 TSN 恢复漂移,13 项,已完成
|
||||||
|
|
||||||
按以下顺序一次解释一个 case:
|
按以下顺序一次解释一个 case:
|
||||||
|
|
||||||
1. `partdesign-plain`,已完成,分类为允许演进
|
| 队列 ID | case | 唯一 mutation 轨迹 | 漂移 ordinal | 阶段数 | 状态 |
|
||||||
2. `partdesign-midplane`,已完成,分类为允许演进
|
| --- | --- | --- | --- | ---: | --- |
|
||||||
3. `partdesign-reverse`,当前唯一执行项
|
| `TSN-DRIFT-000` | `partdesign-plain` | `Pad10.Length: 7 -> 7.75 -> 7` | `0,9` | 2 | completed / allowed_evolution |
|
||||||
4. `partdesign-taper`
|
| `TSN-DRIFT-001` | `partdesign-midplane` | `Pad11.Length: 8 -> 8.75 -> 8` | `0,9` | 2 | completed / allowed_evolution |
|
||||||
5. `partdesign-twoside`
|
| `TSN-DRIFT-002` | `partdesign-reverse` | `Pad12.Length: 5 -> 5.75 -> 5` | `0,9` | 2 | completed / allowed_evolution |
|
||||||
6. `partdesign-pocket`
|
| `TSN-DRIFT-003` | `partdesign-taper` | `Pad13.Length: 6 -> 6.75 -> 6` | `0,9` | 2 | completed / allowed_evolution |
|
||||||
7. `partdesign-pocket-through`
|
| `TSN-DRIFT-004` | `partdesign-twoside` | `Pad14.Length: 7 -> 7.75 -> 7` | `0,9` | 2 | completed / allowed_evolution |
|
||||||
8. `partdesign-pocket-midplane`
|
| `TSN-DRIFT-005` | `partdesign-pocket` | `Pad15.Length: 8 -> 8.75 -> 8` | `0,9,11` | 3 | completed / allowed_evolution |
|
||||||
9. `partdesign-pocket-twoside`
|
| `TSN-DRIFT-006` | `partdesign-pocket-through` | `Pad16.Length: 5 -> 5.75 -> 5` | `0,9,11` | 3 | completed / allowed_evolution |
|
||||||
10. `partdesign-pocket-taper`
|
| `TSN-DRIFT-007` | `partdesign-pocket-midplane` | `Pad17.Length: 6 -> 6.75 -> 6` | `0,9,11` | 3 | completed / allowed_evolution |
|
||||||
11. `partdesign-pocket-up-to-face`
|
| `TSN-DRIFT-008` | `partdesign-pocket-twoside` | `Pad18.Length: 7 -> 7.75 -> 7` | `0,9,11` | 3 | completed / allowed_evolution |
|
||||||
12. 生产 `cut`
|
| `TSN-DRIFT-009` | `partdesign-pocket-taper` | `Pad19.Length: 8 -> 8.75 -> 8` | `0,9,11` | 3 | completed / allowed_evolution |
|
||||||
13. 生产 `rotate`
|
| `TSN-DRIFT-010` | `partdesign-pocket-up-to-face` | `Pad20.Length: 5 -> 5.75 -> 5` | `0,9,11` | 3 | completed / allowed_evolution |
|
||||||
|
| `TSN-PROD-DRIFT-000` | 生产 `cut` | 五阶段链 cut 参数编辑/恢复 | 由生产报告锁定 | - | completed / allowed_evolution |
|
||||||
|
| `TSN-PROD-DRIFT-001` | 生产 `rotate` | 五阶段链 rotate 参数编辑/恢复 | 由生产报告锁定 | - | completed / allowed_evolution |
|
||||||
|
|
||||||
每项必须得到且只能得到一种结论:FreeCAD 稳定语义、允许的命名演进、实现缺陷。实现缺陷必须增加回归测试;未知不能作为结论。
|
每项必须得到且只能得到一种结论:FreeCAD 稳定语义、允许的命名演进、实现缺陷。实现缺陷必须增加回归测试;未知不能作为结论。
|
||||||
|
|
||||||
每个 case 再拆成六个不可合并的最小检查点:先锁定属性、初值/编辑值/恢复值和漂移 ordinal;再执行第二次独立 FreeCAD 1.1.1 探针;然后逐阶段比较 geometry/relation/semantic-name 三摘要;接着验证恢复阶段与保存前 nominal 一致;再验证 save/reopen/resave 三态不继续漂移;最后写入分类账本、运行聚焦 checker 并只推进一个队列项。任一检查点失败时,当前任务保持 `in_progress`,不得领取下一 case。
|
每个 case 再拆成六个不计入 487 项队列总数、但必须依次完成的最小检查点:
|
||||||
|
|
||||||
### 5.4 TSN 有序操作对,361 项,4 完成/357 待办
|
| 检查点 | 唯一产物 | fail-closed 验收 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `-A-contract` | case id、target object/type、property path/type、before/edited/restored、drift ordinal | 与锁定 30-case oracle 一致,属性确实可编辑 |
|
||||||
|
| `-B-replay` | 第二个独立 FreeCAD 1.1.1 进程报告 | 版本、commit、harness SHA-256 和运行状态锁定 |
|
||||||
|
| `-C-fingerprint` | 每个漂移阶段的 geometry/relation/semantic-name 三相摘要 | 参考与复跑的 before/edited/restored 逐字段一致 |
|
||||||
|
| `-D-restore` | property 恢复、geometry 恢复、restored-to-nominal 结论 | 任一阶段几何未恢复即停止并调查缺陷 |
|
||||||
|
| `-E-persistence` | initial/reopened/resaved 命名摘要 | roundtrip/resave drift 为 0,且三态与 restored 一致 |
|
||||||
|
| `-F-decision` | stable_semantics / allowed_evolution / implementation_defect 唯一分类 | 决策进入连续前缀账本,checker 通过,只推进直接后继 |
|
||||||
|
|
||||||
|
任一检查点失败时,当前任务保持 `in_progress`,不得领取下一 case。如果分类为 `implementation_defect`,还必须在同一队列项内完成最小修复、回归测试、原生/Web 对照和资源释放,不另行跳过。
|
||||||
|
|
||||||
|
### 5.4 TSN 有序操作对,361 项,8 完成/1 进行中/352 待办
|
||||||
|
|
||||||
操作全集为 Fuse、Cut、Common、Rotate、Pad、Pocket、Loft、Pipe、Revolution、Groove、Fillet、Chamfer、Hole、Draft、Thickness、LinearPattern、PolarPattern、Mirrored、MultiTransform。
|
操作全集为 Fuse、Cut、Common、Rotate、Pad、Pocket、Loft、Pipe、Revolution、Groove、Fillet、Chamfer、Hole、Draft、Thickness、LinearPattern、PolarPattern、Mirrored、MultiTransform。
|
||||||
|
|
||||||
@@ -157,7 +189,7 @@ FCStd / STEP / IGES / mesh / CAM / engineering resources
|
|||||||
7. 在生产 Worker 回放并检查释放。
|
7. 在生产 Worker 回放并检查释放。
|
||||||
8. 拒绝时固定原生错误类型和文档未污染证据。
|
8. 拒绝时固定原生错误类型和文档未污染证据。
|
||||||
|
|
||||||
已覆盖的四对为 `cut->rotate`、`rotate->fillet`、`fillet->mirrored`、`mirrored->linear-pattern`。其余严格按机器队列逐对领取。
|
已覆盖的八对为 `cut->rotate`、`rotate->fillet`、`fillet->mirrored`、`mirrored->linear-pattern`、`fuse->fuse`、`fuse->cut`、`fuse->common`、`fuse->rotate`。当前只处理 `fuse->pad`,其余严格按机器队列逐对领取。
|
||||||
|
|
||||||
## 6. 后续关键路径微里程碑
|
## 6. 后续关键路径微里程碑
|
||||||
|
|
||||||
@@ -183,11 +215,11 @@ FCStd / STEP / IGES / mesh / CAM / engineering resources
|
|||||||
|
|
||||||
### M02 `EX-TSN-04A` 恢复漂移闭合
|
### M02 `EX-TSN-04A` 恢复漂移闭合
|
||||||
|
|
||||||
状态:`TSN-DRIFT-000..001` 已完成,执行 `TSN-DRIFT-002`。
|
状态:13/13 已完成;11 个 PartDesign case/28 个阶段及 2 个生产 case/5 个阶段均完成独立复跑分类。
|
||||||
|
|
||||||
- M02.1-M02.11:11 个 PartDesign case,逐 case 解释 28 个命名摘要演进;当前完成 2/11 case、4/28 阶段,剩余 9/11 case、24/28 阶段。
|
- M02.1-M02.11:11 个 PartDesign case/28 个命名摘要演进已全部分类为允许演进。
|
||||||
- M02.12:生产 Cut 恢复拓扑漂移。
|
- M02.12:生产 Cut 恢复拓扑漂移已分类为允许演进。
|
||||||
- M02.13:生产 Rotate 恢复拓扑漂移。
|
- M02.13:生产 Rotate 恢复拓扑漂移已分类为允许演进。
|
||||||
- M02.14:若发现实现缺陷,只修改一个 operation/case 并补回归。
|
- M02.14:若发现实现缺陷,只修改一个 operation/case 并补回归。
|
||||||
- M02.15:汇总 zero-unknown drift gate,不直接提升系统 exact。
|
- M02.15:汇总 zero-unknown drift gate,不直接提升系统 exact。
|
||||||
|
|
||||||
@@ -195,7 +227,7 @@ FCStd / STEP / IGES / mesh / CAM / engineering resources
|
|||||||
|
|
||||||
### M03 `EX-TSN-04B` builder 与 19×19 转换矩阵
|
### M03 `EX-TSN-04B` builder 与 19×19 转换矩阵
|
||||||
|
|
||||||
状态:等待 M02。
|
状态:`in_progress`;已覆盖 8/361 对,当前执行 `TSN-PAIR-fuse-pad`。
|
||||||
|
|
||||||
- M03.1:用真实 builder 替换五阶段链中 Cut 之后的通用 Shape 代理,一次替换一个 stage。
|
- M03.1:用真实 builder 替换五阶段链中 Cut 之后的通用 Shape 代理,一次替换一个 stage。
|
||||||
- M03.2:增加 Rotate 原生 mutation family。
|
- M03.2:增加 Rotate 原生 mutation family。
|
||||||
@@ -241,7 +273,7 @@ FCStd / STEP / IGES / mesh / CAM / engineering resources
|
|||||||
|
|
||||||
### M06 `EX-KER-01/ORA-02` 内核纵向切片
|
### M06 `EX-KER-01/ORA-02` 内核纵向切片
|
||||||
|
|
||||||
状态:等待 M02+M05 的可消费证据。
|
状态:M02 证据已可消费,等待 M05 文档闭环。
|
||||||
|
|
||||||
按一个 builder/参数分支执行 A-I:Box、Cylinder、Cone、Sphere、Torus、Prism、Wedge、Helix、Ellipsoid;Extrusion、Revolution、Loft、Sweep;Fuse、Cut、Common;Fillet、Chamfer;随后是 tolerance、healing、validation 和失败诊断。
|
按一个 builder/参数分支执行 A-I:Box、Cylinder、Cone、Sphere、Torus、Prism、Wedge、Helix、Ellipsoid;Extrusion、Revolution、Loft、Sweep;Fuse、Cut、Common;Fillet、Chamfer;随后是 tolerance、healing、validation 和失败诊断。
|
||||||
|
|
||||||
@@ -386,4 +418,10 @@ M00
|
|||||||
|
|
||||||
`TSN-DRIFT-001` 已完成:`partdesign-midplane` 的 `Length 8 -> 8.75 -> 8` 在 Body11 和 Pad11 两个阶段恢复相同几何,关系与语义命名摘要演进为新的稳定历史。锁定报告与第二次独立 FreeCAD 1.1.1 复跑的逐阶段摘要一致,演进值在 save/reopen/resave 中保持,因此同样分类为 `allowed_evolution`,不是 Web 实现缺陷。
|
`TSN-DRIFT-001` 已完成:`partdesign-midplane` 的 `Length 8 -> 8.75 -> 8` 在 Body11 和 Pad11 两个阶段恢复相同几何,关系与语义命名摘要演进为新的稳定历史。锁定报告与第二次独立 FreeCAD 1.1.1 复跑的逐阶段摘要一致,演进值在 save/reopen/resave 中保持,因此同样分类为 `allowed_evolution`,不是 Web 实现缺陷。
|
||||||
|
|
||||||
当前唯一下一任务为 `TSN-DRIFT-002`:只解释 `partdesign-reverse` 的恢复命名阶段。退出条件仍是第二次原生复跑一致、恢复几何一致、持久化稳定,并且在稳定语义、允许演进、实现缺陷三者中得到唯一机器可读结论。
|
`TSN-DRIFT-002` 已完成:`partdesign-reverse` 的 `Length 5 -> 5.75 -> 5` 在 Body12 和 Pad12 两个阶段恢复相同几何,关系与语义命名摘要演进为新的稳定历史。锁定报告与第二次独立 FreeCAD 1.1.1 复跑的逐阶段摘要一致,演进值在 save/reopen/resave 中保持,因此同样分类为 `allowed_evolution`,不是 Web 实现缺陷。
|
||||||
|
|
||||||
|
`TSN-DRIFT-003` 已完成:`partdesign-taper` 的 `Length 6 -> 6.75 -> 6` 在 Body13 和 Pad13 两个阶段恢复相同几何,关系与语义命名摘要演进为新的稳定历史。锁定报告与第二次独立 FreeCAD 1.1.1 复跑的逐阶段摘要一致,演进值在 save/reopen/resave 中保持,因此同样分类为 `allowed_evolution`,不是 Web 实现缺陷。
|
||||||
|
|
||||||
|
`TSN-DRIFT-004..010` 与生产 `cut`/`rotate` 漂移均已完成独立复跑,并唯一分类为 `allowed_evolution`;恢复漂移队列因此以 13/13 关闭。`fuse->fuse`、`fuse->cut`、`fuse->common`、`fuse->rotate` 的新增分类与既有五阶段四条转换合计覆盖 8/361 对。
|
||||||
|
|
||||||
|
当前唯一下一任务为 `TSN-PAIR-fuse-pad`。退出条件是记录原生接受或拒绝;接受时必须具备真实 builder、mutation/restore、history/naming 与 FreeCAD save/reopen/resave 证据,拒绝时必须固定原生错误与无文档污染证据。
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"check:baseline": "node scripts/check-baseline.mjs",
|
"check:baseline": "node scripts/check-baseline.mjs",
|
||||||
"check:freecad-source": "node scripts/verify-freecad-source.mjs",
|
"check:freecad-source": "node scripts/verify-freecad-source.mjs",
|
||||||
"check:bitbybit-history": "node scripts/check-bitbybit-history-surface.mjs",
|
"check:bitbybit-history": "node scripts/check-bitbybit-history-surface.mjs",
|
||||||
"check:execution-plan": "node scripts/check-freecad-execution-plan.mjs && node scripts/check-freecad-web-exact-parity-plan.mjs && node scripts/check-freecad-web-exact-promotion.mjs && node scripts/check-freecad-oracle-coverage.mjs && node scripts/check-freecad-gui-workflow-plan.mjs && node scripts/check-freecad-gui-workflow-oracle.mjs && node scripts/check-freecad-golden-coverage.mjs && node scripts/check-freecad-core-parameter-mutation-oracle.mjs && node scripts/generate-freecad-parameter-mutation-report.mjs --check && node scripts/check-freecad-tsn-stage-evidence.mjs && node scripts/check-freecad-tsn-stage-correlation.mjs && node scripts/check-freecad-recovered-naming-classification.mjs && node scripts/generate-freecad-active-work-queue.mjs --check",
|
"check:execution-plan": "node scripts/check-freecad-execution-plan.mjs && node scripts/check-freecad-web-exact-parity-plan.mjs && node scripts/check-freecad-web-exact-promotion.mjs && node scripts/check-freecad-oracle-coverage.mjs && node scripts/check-freecad-gui-workflow-plan.mjs && node scripts/check-freecad-gui-workflow-oracle.mjs && node scripts/check-freecad-golden-coverage.mjs && node scripts/check-freecad-core-parameter-mutation-oracle.mjs && node scripts/generate-freecad-parameter-mutation-report.mjs --check && node scripts/check-freecad-tsn-stage-evidence.mjs && node scripts/check-freecad-recovered-naming-classification.mjs && node scripts/check-freecad-production-drift-classification.mjs && node scripts/check-freecad-ordered-operation-pair-classification.mjs && node scripts/check-freecad-tsn-stage-correlation.mjs && node scripts/generate-freecad-active-work-queue.mjs --check",
|
||||||
"generate:freecad-active-work-queue": "node scripts/generate-freecad-active-work-queue.mjs",
|
"generate:freecad-active-work-queue": "node scripts/generate-freecad-active-work-queue.mjs",
|
||||||
"check:freecad-active-work-queue": "node scripts/generate-freecad-active-work-queue.mjs --check",
|
"check:freecad-active-work-queue": "node scripts/generate-freecad-active-work-queue.mjs --check",
|
||||||
"check:freecad-web-exact-parity-plan": "node scripts/check-freecad-web-exact-parity-plan.mjs",
|
"check:freecad-web-exact-parity-plan": "node scripts/check-freecad-web-exact-parity-plan.mjs",
|
||||||
@@ -56,6 +56,10 @@
|
|||||||
"check:freecad-recovered-naming-classification": "node scripts/check-freecad-recovered-naming-classification.mjs",
|
"check:freecad-recovered-naming-classification": "node scripts/check-freecad-recovered-naming-classification.mjs",
|
||||||
"probe:freecad-tsn-stage-correlation": "node scripts/run-freecad-tsn-stage-correlation-oracle.mjs",
|
"probe:freecad-tsn-stage-correlation": "node scripts/run-freecad-tsn-stage-correlation-oracle.mjs",
|
||||||
"check:freecad-tsn-stage-correlation": "node scripts/check-freecad-tsn-stage-correlation.mjs",
|
"check:freecad-tsn-stage-correlation": "node scripts/check-freecad-tsn-stage-correlation.mjs",
|
||||||
|
"probe:freecad-production-drift-classification": "node scripts/run-freecad-production-drift-classification.mjs",
|
||||||
|
"check:freecad-production-drift-classification": "node scripts/check-freecad-production-drift-classification.mjs",
|
||||||
|
"probe:freecad-ordered-operation-pairs": "npx tsx scripts/run-freecad-ordered-operation-pair-classification.mjs",
|
||||||
|
"check:freecad-ordered-operation-pairs": "node scripts/check-freecad-ordered-operation-pair-classification.mjs",
|
||||||
"check:freecad-exact-history-elementmap-gate": "npx tsx scripts/check-freecad-exact-history-elementmap-gate.mjs",
|
"check:freecad-exact-history-elementmap-gate": "npx tsx scripts/check-freecad-exact-history-elementmap-gate.mjs",
|
||||||
"check:freecad-native-naming-evidence": "npx tsx scripts/check-freecad-native-naming-evidence.mjs",
|
"check:freecad-native-naming-evidence": "npx tsx scripts/check-freecad-native-naming-evidence.mjs",
|
||||||
"test:golden:freecad:failures": "node scripts/run-freecad-golden-failures.mjs",
|
"test:golden:freecad:failures": "node scripts/run-freecad-golden-failures.mjs",
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { createHash } from 'node:crypto'
|
||||||
|
import { readFile, stat } from 'node:fs/promises'
|
||||||
|
import { resolve } from 'node:path'
|
||||||
|
|
||||||
|
const root = resolve(new URL('..', import.meta.url).pathname)
|
||||||
|
const report = JSON.parse(await readFile(resolve(root, 'config/freecad-ordered-operation-pair-classification.json'), 'utf8'))
|
||||||
|
const fail = (message) => { throw new Error(`FreeCAD ordered operation pair classification: ${message}`) }
|
||||||
|
const sha256 = (value) => createHash('sha256').update(value).digest('hex')
|
||||||
|
if (report.schemaVersion !== 1 || report.baseline?.freecadVersion !== '1.1.1' || report.baseline.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || !/^8\./.test(report.baseline.occtVersion)) fail('baseline is invalid.')
|
||||||
|
for (const harness of [report.nativeProbe?.executor, report.nativeProbe?.matrix, report.nativeProbe?.resave]) {
|
||||||
|
const path = resolve(root, harness?.path ?? '')
|
||||||
|
const [content, bytes] = await Promise.all([readFile(path), stat(path).then(({ size }) => size)])
|
||||||
|
if (bytes !== harness.bytes || sha256(content) !== harness.sha256) fail(`${harness.path} provenance is stale.`)
|
||||||
|
}
|
||||||
|
for (const artifact of report.nativeProbe?.artifacts ?? []) {
|
||||||
|
const path = resolve(root, 'native/occt-history/dist', artifact.name)
|
||||||
|
const [content, bytes] = await Promise.all([readFile(path), stat(path).then(({ size }) => size)])
|
||||||
|
if (bytes !== artifact.bytes || sha256(content) !== artifact.sha256) fail(`${artifact.name} provenance is stale.`)
|
||||||
|
}
|
||||||
|
const expectedPairs = [
|
||||||
|
{ pair: 'fuse->fuse', secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [12, 11, 12] },
|
||||||
|
{ pair: 'fuse->cut', secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] },
|
||||||
|
{ pair: 'fuse->common', secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [10, 9, 10] },
|
||||||
|
{ pair: 'fuse->rotate', secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] },
|
||||||
|
]
|
||||||
|
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()) {
|
||||||
|
const expected = expectedPairs[index]
|
||||||
|
const secondOperation = expected.pair.split('->')[1]
|
||||||
|
if (entry.taskId !== `TSN-PAIR-${expected.pair.replace('->', '-')}` || entry.pair !== expected.pair || entry.classification !== 'accepted' || entry.nativeDecision !== 'accepted' || entry.first?.operation !== 'fuse' || entry.first.builder !== 'BRepAlgoAPI_Fuse' || entry.first.inputCount !== 2 || entry.second?.operation !== secondOperation || entry.second.builder !== expected.secondBuilder || entry.second.inputCount !== expected.secondInputCount || entry.first.historyProvider !== 'occt-native' || entry.second.historyProvider !== 'occt-native') fail(`${expected.pair} decision contract is invalid.`)
|
||||||
|
if (entry.first.summary?.isValid !== true || entry.second.summary?.isValid !== true || entry.first.historyRecords < 1 || entry.second.historyRecords < 1 || entry.mutation?.changed !== true || entry.mutation?.restoredExactly !== true) fail(`${expected.pair} builder or mutation evidence is incomplete.`)
|
||||||
|
if (entry.mutation.scope !== 'second-operation-only' || entry.mutation.parameter !== expected.mutationParameter || JSON.stringify(entry.mutation.trajectory) !== JSON.stringify(expected.mutationTrajectory) || entry.mutation.beforeValue !== expected.mutationTrajectory[0] || entry.mutation.editedValue !== expected.mutationTrajectory[1] || entry.mutation.restoredValue !== expected.mutationTrajectory[2]) fail(`${expected.pair} mutation trajectory is invalid.`)
|
||||||
|
if (entry.mutation.editedEvidence?.operation !== secondOperation || entry.mutation.restoredEvidence?.operation !== secondOperation || entry.mutation.editedEvidence?.builder !== expected.secondBuilder || entry.mutation.restoredEvidence?.builder !== expected.secondBuilder || entry.mutation.editedEvidence?.inputCount !== expected.secondInputCount || entry.mutation.restoredEvidence?.inputCount !== expected.secondInputCount || entry.mutation.editedEvidence?.historyProvider !== 'occt-native' || entry.mutation.restoredEvidence?.historyProvider !== 'occt-native') fail(`${expected.pair} mutation history provider is invalid.`)
|
||||||
|
if (entry.second.namingSemanticSha256 !== entry.mutation.restoredEvidence?.namingSemanticSha256) fail(`${expected.pair} semantic naming evidence did not restore to nominal.`)
|
||||||
|
if (entry.naming?.upstreamEvidenceRestored !== true || entry.naming?.downstreamEvidence !== true || entry.naming?.jsonRoundtripStable !== true) fail(`${expected.pair} naming evidence is incomplete.`)
|
||||||
|
if (entry.persistence?.status !== 'pass' || entry.persistence.pair !== entry.pair || entry.persistence.freecadVersion !== '1.1.1' || !Object.values(entry.persistence.checks ?? {}).every(Boolean)) fail(`${expected.pair} FCStd persistence evidence is incomplete.`)
|
||||||
|
const phases = entry.persistence.phases
|
||||||
|
if (JSON.stringify(phases?.initial) !== JSON.stringify(phases?.reopened) || JSON.stringify(phases?.initial) !== JSON.stringify(phases?.resaved) || phases.initial.namingEvidenceSha256 !== entry.second.namingEvidenceSha256) fail(`${expected.pair} FCStd phases changed Shape or naming evidence.`)
|
||||||
|
}
|
||||||
|
const expectedSummary = { registeredOperations: 19, orderedPairs: 361, classifiedPairs: 4, accepted: 4, rejected: 0, unknown: 357 }
|
||||||
|
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))
|
||||||
43
scripts/check-freecad-production-drift-classification.mjs
Normal file
43
scripts/check-freecad-production-drift-classification.mjs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { createHash } from 'node:crypto'
|
||||||
|
import { readFile, stat } from 'node:fs/promises'
|
||||||
|
import { resolve } from 'node:path'
|
||||||
|
import { buildProductionDriftSnapshot, productionDriftDecisions, same, validateProductionDriftSnapshot } from './freecad-production-drift-classification.mjs'
|
||||||
|
|
||||||
|
const root = resolve(new URL('..', import.meta.url).pathname)
|
||||||
|
const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse)
|
||||||
|
const fail = (message) => { throw new Error(`FreeCAD production drift classification: ${message}`) }
|
||||||
|
const [report, oracle] = await Promise.all([
|
||||||
|
load('config/freecad-production-drift-classification.json'),
|
||||||
|
load('config/freecad-tsn-stage-correlation-oracle.json'),
|
||||||
|
])
|
||||||
|
if (report.schemaVersion !== 1 || report.baseline?.freecadVersion !== '1.1.1' || report.baseline.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.baseline.oracleId !== oracle.baselineId) fail('baseline is invalid.')
|
||||||
|
const harnessPath = resolve(root, report.nativeProbe?.path ?? '')
|
||||||
|
const [harnessContent, harnessBytes] = await Promise.all([readFile(harnessPath), stat(harnessPath).then(({ size }) => size)])
|
||||||
|
if (report.nativeProbe.path !== 'scripts/freecad-tsn-stage-correlation-oracle.py' || report.nativeProbe.bytes !== harnessBytes || report.nativeProbe.sha256 !== createHash('sha256').update(harnessContent).digest('hex') || report.nativeProbe.independentRuns < 2) fail('native replay provenance is missing or stale.')
|
||||||
|
if (!Array.isArray(report.classifications) || report.classifications.length !== productionDriftDecisions.length) fail('classification report does not contain the complete serial decision prefix.')
|
||||||
|
|
||||||
|
let classifiedStages = 0
|
||||||
|
for (const [index, entry] of report.classifications.entries()) {
|
||||||
|
const decision = productionDriftDecisions[index]
|
||||||
|
if (!same({ taskId: entry.taskId, operation: entry.operation, classification: entry.classification, reasonCode: entry.reasonCode, rationale: entry.rationale }, decision) || entry.replayStable !== true || entry.implementationDefect !== (decision.classification === 'implementation_defect')) fail(`${decision.taskId} classification contract is invalid.`)
|
||||||
|
const expected = buildProductionDriftSnapshot(oracle, entry.operation)
|
||||||
|
validateProductionDriftSnapshot(expected)
|
||||||
|
validateProductionDriftSnapshot(entry.reference)
|
||||||
|
validateProductionDriftSnapshot(entry.replay)
|
||||||
|
if (!same(entry.reference, expected) || !same(entry.replay, expected)) fail(`${entry.operation} classification evidence is stale or the independent replay differs.`)
|
||||||
|
classifiedStages += expected.driftOrdinals.length
|
||||||
|
}
|
||||||
|
const driftCases = oracle.driftReplays.length
|
||||||
|
const countClassification = (classification) => productionDriftDecisions.filter((entry) => entry.classification === classification).length
|
||||||
|
const expectedSummary = { driftCases, classifiedCases: productionDriftDecisions.length, classifiedStages, stableSemantics: countClassification('stable_semantics'), allowedEvolution: countClassification('allowed_evolution'), implementationDefects: countClassification('implementation_defect'), unknown: driftCases - productionDriftDecisions.length }
|
||||||
|
if (!same(report.summary, expectedSummary)) fail('classification summary is inconsistent.')
|
||||||
|
|
||||||
|
console.log(JSON.stringify({
|
||||||
|
status: 'freecad-production-drift-classification-pass',
|
||||||
|
completedTasks: report.classifications.map(({ taskId }) => taskId),
|
||||||
|
cases: report.classifications.map(({ operation, classification }) => ({ operation, classification })),
|
||||||
|
independentRuns: report.nativeProbe.independentRuns,
|
||||||
|
classifiedCases: report.summary.classifiedCases,
|
||||||
|
classifiedStages: report.summary.classifiedStages,
|
||||||
|
remainingCases: report.summary.unknown,
|
||||||
|
}, null, 2))
|
||||||
@@ -6,7 +6,7 @@ import { validateCompositeMutationEvidence } from './freecad-composite-mutation-
|
|||||||
const root = resolve(new URL('..', import.meta.url).pathname)
|
const root = resolve(new URL('..', import.meta.url).pathname)
|
||||||
const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse)
|
const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse)
|
||||||
const fail = (message) => { throw new Error(`FreeCAD TSN stage correlation: ${message}`) }
|
const fail = (message) => { throw new Error(`FreeCAD TSN stage correlation: ${message}`) }
|
||||||
const [desktop, production, productionRegistry, composite, resave, mutations, recoveredNaming] = await Promise.all([
|
const [desktop, production, productionRegistry, composite, resave, mutations, recoveredNaming, productionDriftClassification, orderedPairClassification] = await Promise.all([
|
||||||
load('config/freecad-tsn-stage-correlation-oracle.json'),
|
load('config/freecad-tsn-stage-correlation-oracle.json'),
|
||||||
load('config/freecad-isomorphic-provenance-verification.json'),
|
load('config/freecad-isomorphic-provenance-verification.json'),
|
||||||
load('config/chrome-freecad-naming-production-verification.json'),
|
load('config/chrome-freecad-naming-production-verification.json'),
|
||||||
@@ -14,6 +14,8 @@ const [desktop, production, productionRegistry, composite, resave, mutations, re
|
|||||||
load('config/freecad-composite-history-resave-verification.json'),
|
load('config/freecad-composite-history-resave-verification.json'),
|
||||||
load('config/freecad-parameter-mutation-report.json'),
|
load('config/freecad-parameter-mutation-report.json'),
|
||||||
load('config/freecad-recovered-naming-classification.json'),
|
load('config/freecad-recovered-naming-classification.json'),
|
||||||
|
load('config/freecad-production-drift-classification.json'),
|
||||||
|
load('config/freecad-ordered-operation-pair-classification.json'),
|
||||||
])
|
])
|
||||||
const operations = ['cut', 'rotate', 'fillet', 'mirrored', 'linear-pattern']
|
const operations = ['cut', 'rotate', 'fillet', 'mirrored', 'linear-pattern']
|
||||||
if (desktop.schemaVersion !== 1 || desktop.baselineId !== 'freecad-1.1.1-tsn-stage-correlation' || desktop.freecadVersion !== '1.1.1' || desktop.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || desktop.status !== 'pass') fail('desktop oracle is not locked to FreeCAD 1.1.1.')
|
if (desktop.schemaVersion !== 1 || desktop.baselineId !== 'freecad-1.1.1-tsn-stage-correlation' || desktop.freecadVersion !== '1.1.1' || desktop.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || desktop.status !== 'pass') fail('desktop oracle is not locked to FreeCAD 1.1.1.')
|
||||||
@@ -77,13 +79,28 @@ const proxyStageOperations = desktop.stages.filter(({ nativeBuilder }) => native
|
|||||||
if (JSON.stringify(proxyStageOperations) !== '["rotate","mirrored","linear-pattern"]' || desktop.summary?.nativeBuilderStages !== 2 || desktop.summary?.proxyStages !== 3 || desktop.exactCorrelationReady !== false) fail('desktop native-builder/proxy boundary drifted.')
|
if (JSON.stringify(proxyStageOperations) !== '["rotate","mirrored","linear-pattern"]' || desktop.summary?.nativeBuilderStages !== 2 || desktop.summary?.proxyStages !== 3 || desktop.exactCorrelationReady !== false) fail('desktop native-builder/proxy boundary drifted.')
|
||||||
|
|
||||||
const registeredOperations = productionRegistry.operations || []
|
const registeredOperations = productionRegistry.operations || []
|
||||||
const coveredTransitions = operations.slice(1).map((operation, index) => `${operations[index]}->${operation}`)
|
const productionDriftMutations = desktop.mutations.filter(({ restoreTopologyDriftStages }) => restoreTopologyDriftStages > 0)
|
||||||
|
const productionDriftByOperation = new Map(productionDriftMutations.map((mutation) => [mutation.operation, mutation]))
|
||||||
|
const productionDriftClassifications = productionDriftClassification.classifications || []
|
||||||
|
if (productionDriftClassification.baseline?.freecadVersion !== desktop.freecadVersion || productionDriftClassification.baseline?.commit !== desktop.gitCommit || productionDriftClassifications.length !== new Set(productionDriftClassifications.map(({ operation }) => operation)).size) fail('production drift classifications have invalid baseline or duplicate operations.')
|
||||||
|
let classifiedProductionDriftStages = 0
|
||||||
|
for (const entry of productionDriftClassifications) {
|
||||||
|
const mutation = productionDriftByOperation.get(entry.operation)
|
||||||
|
if (!mutation || !['stable_semantics', 'allowed_evolution', 'implementation_defect'].includes(entry.classification) || entry.replayStable !== true) fail(`production drift classification ${entry.operation} is invalid.`)
|
||||||
|
classifiedProductionDriftStages += mutation.restoreTopologyDriftStages
|
||||||
|
}
|
||||||
|
const unclassifiedProductionDriftCases = productionDriftMutations.length - productionDriftClassifications.length
|
||||||
|
const unclassifiedProductionDriftStages = desktop.summary.mutationRestoreTopologyDriftStages - classifiedProductionDriftStages
|
||||||
|
const orderedPairClassifications = orderedPairClassification.classifications || []
|
||||||
|
if (orderedPairClassification.baseline?.freecadVersion !== desktop.freecadVersion || orderedPairClassification.baseline?.commit !== desktop.gitCommit || orderedPairClassifications.length !== new Set(orderedPairClassifications.map(({ pair }) => pair)).size) fail('ordered operation pair classifications have invalid baseline or duplicate pairs.')
|
||||||
|
for (const entry of orderedPairClassifications) if (!['accepted', 'rejected'].includes(entry.classification) || entry.nativeDecision !== entry.classification) fail(`ordered operation pair classification ${entry.pair} is invalid.`)
|
||||||
|
const coveredTransitions = [...new Set([...operations.slice(1).map((operation, index) => `${operations[index]}->${operation}`), ...orderedPairClassifications.map(({ pair }) => pair)])]
|
||||||
const orderedOperationPairs = registeredOperations.length * registeredOperations.length
|
const orderedOperationPairs = registeredOperations.length * registeredOperations.length
|
||||||
const blockers = [
|
const blockers = [
|
||||||
`Native desktop builder stages missing from the sequential chain: ${proxyStageOperations.join(', ')}`,
|
`Native desktop builder stages missing from the sequential chain: ${proxyStageOperations.join(', ')}`,
|
||||||
`Native parameter-mutation family missing for production operation: ${missingNativeMutationOperations.join(', ')}`,
|
`Native parameter-mutation family missing for production operation: ${missingNativeMutationOperations.join(', ')}`,
|
||||||
`${desktop.summary.mutationRestoreTopologyDriftCases}/5 edit/restore cases changed ${desktop.summary.mutationRestoreTopologyDriftStages} downstream semantic topology digests without wrong binding`,
|
`${unclassifiedProductionDriftCases}/${productionDriftMutations.length} production restore-topology cases and ${unclassifiedProductionDriftStages}/${desktop.summary.mutationRestoreTopologyDriftStages} downstream stages remain unclassified; ${productionDriftClassifications.length} ${productionDriftClassifications.length === 1 ? 'case is' : 'cases are'} classified from an independent native replay`,
|
||||||
`${unclassifiedNamingDriftCases}/${compositeMutation.mutationNamingRestoreDriftCases} native naming-drift cases and ${unclassifiedNamingDriftStages}/${compositeMutation.mutationNamingRestoreDriftStages} recovered naming stages remain unclassified; ${recoveredNamingClassifications.length} case is classified from an independent native replay`,
|
`${unclassifiedNamingDriftCases}/${compositeMutation.mutationNamingRestoreDriftCases} native naming-drift cases and ${unclassifiedNamingDriftStages}/${compositeMutation.mutationNamingRestoreDriftStages} recovered naming stages remain unclassified; ${recoveredNamingClassifications.length} ${recoveredNamingClassifications.length === 1 ? 'case is' : 'cases are'} classified from an independent native replay`,
|
||||||
`Only ${coveredTransitions.length}/${orderedOperationPairs} ordered production operation pairs are classified and replayed; ${orderedOperationPairs - coveredTransitions.length} remain unclassified for type compatibility`,
|
`Only ${coveredTransitions.length}/${orderedOperationPairs} ordered production operation pairs are classified and replayed; ${orderedOperationPairs - coveredTransitions.length} remain unclassified for type compatibility`,
|
||||||
]
|
]
|
||||||
console.log(JSON.stringify({
|
console.log(JSON.stringify({
|
||||||
@@ -94,7 +111,7 @@ console.log(JSON.stringify({
|
|||||||
nativeBuilderStages: desktop.summary.nativeBuilderStages,
|
nativeBuilderStages: desktop.summary.nativeBuilderStages,
|
||||||
proxyStageOperations,
|
proxyStageOperations,
|
||||||
compositeMutations: { cases: compositeMutation.mutationCases, passed: compositeMutation.mutationPassed, caseReconciliations: compositeCaseReconciliations, categoryCases: compositeMutation.categoryCases, stageRecords: compositeMutation.mutationStageRecords, phaseStageRecords: compositeMutation.mutationPhaseStageRecords, finalPropagationFailures: compositeMutation.mutationFinalPropagationFailures, geometryRestoreFailures: compositeMutation.mutationStageRestoreFailures, namingRestoreDriftCases: compositeMutation.mutationNamingRestoreDriftCases, namingRestoreDriftStages: compositeMutation.mutationNamingRestoreDriftStages, classifiedNamingDriftCases: recoveredNamingClassifications.length, classifiedNamingDriftStages, unclassifiedNamingDriftCases, unclassifiedNamingDriftStages },
|
compositeMutations: { cases: compositeMutation.mutationCases, passed: compositeMutation.mutationPassed, caseReconciliations: compositeCaseReconciliations, categoryCases: compositeMutation.categoryCases, stageRecords: compositeMutation.mutationStageRecords, phaseStageRecords: compositeMutation.mutationPhaseStageRecords, finalPropagationFailures: compositeMutation.mutationFinalPropagationFailures, geometryRestoreFailures: compositeMutation.mutationStageRestoreFailures, namingRestoreDriftCases: compositeMutation.mutationNamingRestoreDriftCases, namingRestoreDriftStages: compositeMutation.mutationNamingRestoreDriftStages, classifiedNamingDriftCases: recoveredNamingClassifications.length, classifiedNamingDriftStages, unclassifiedNamingDriftCases, unclassifiedNamingDriftStages },
|
||||||
mutations: { cases: desktop.summary.mutationCases, passed: desktop.summary.mutationPassed, nativeCorrelated: nativeMutationCorrelation.filter(({ complete }) => complete).length, missingNativeMutationOperations, restoreTopologyDriftCases: desktop.summary.mutationRestoreTopologyDriftCases, restoreTopologyDriftStages: desktop.summary.mutationRestoreTopologyDriftStages },
|
mutations: { cases: desktop.summary.mutationCases, passed: desktop.summary.mutationPassed, nativeCorrelated: nativeMutationCorrelation.filter(({ complete }) => complete).length, missingNativeMutationOperations, restoreTopologyDriftCases: desktop.summary.mutationRestoreTopologyDriftCases, restoreTopologyDriftStages: desktop.summary.mutationRestoreTopologyDriftStages, classifiedRestoreTopologyDriftCases: productionDriftClassifications.length, classifiedRestoreTopologyDriftStages: classifiedProductionDriftStages, unclassifiedRestoreTopologyDriftCases: unclassifiedProductionDriftCases, unclassifiedRestoreTopologyDriftStages: unclassifiedProductionDriftStages },
|
||||||
transitions: { registeredOperations: registeredOperations.length, orderedOperationPairs, covered: coveredTransitions.length, unclassified: orderedOperationPairs - coveredTransitions.length, coveredTransitions },
|
transitions: { registeredOperations: registeredOperations.length, orderedOperationPairs, covered: coveredTransitions.length, unclassified: orderedOperationPairs - coveredTransitions.length, coveredTransitions },
|
||||||
nativeDesktopResaveCases: resave.summary.nativeDesktopResaveCases + 1,
|
nativeDesktopResaveCases: resave.summary.nativeDesktopResaveCases + 1,
|
||||||
wrongBindings: desktop.summary.wrongBindings,
|
wrongBindings: desktop.summary.wrongBindings,
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ def relation_from_mapped_name(mapped_name):
|
|||||||
def normalize_mapped_name(mapped_name):
|
def normalize_mapped_name(mapped_name):
|
||||||
# StringHasher IDs are process-local. Preserve the token grammar while
|
# StringHasher IDs are process-local. Preserve the token grammar while
|
||||||
# removing only the volatile hash-table slot assigned in this process.
|
# removing only the volatile hash-table slot assigned in this process.
|
||||||
return re.sub(r":H[0-9a-fA-F]+", ":H#", mapped_name or "")
|
return re.sub(r":H-?[0-9a-fA-F]+", ":H#", mapped_name or "")
|
||||||
|
|
||||||
|
|
||||||
def source_element_name(mapped_name):
|
def source_element_name(mapped_name):
|
||||||
|
|||||||
113
scripts/freecad-ordered-operation-pair-resave.py
Normal file
113
scripts/freecad-ordered-operation-pair-resave.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
import FreeCAD as App
|
||||||
|
import Import
|
||||||
|
import Part
|
||||||
|
|
||||||
|
|
||||||
|
FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d"
|
||||||
|
|
||||||
|
|
||||||
|
def version_text():
|
||||||
|
return ".".join(str(value) for value in App.Version()[:3])
|
||||||
|
|
||||||
|
|
||||||
|
def shape_snapshot(feature):
|
||||||
|
shape = feature.Shape
|
||||||
|
if shape.isNull():
|
||||||
|
raise RuntimeError("ordered pair produced a null Shape")
|
||||||
|
bounds = shape.BoundBox
|
||||||
|
return {
|
||||||
|
"valid": bool(shape.isValid()),
|
||||||
|
"solids": len(shape.Solids),
|
||||||
|
"faces": len(shape.Faces),
|
||||||
|
"edges": len(shape.Edges),
|
||||||
|
"vertices": len(shape.Vertexes),
|
||||||
|
"volume": round(float(shape.Volume), 7),
|
||||||
|
"area": round(float(shape.Area), 7),
|
||||||
|
"bounds": [round(float(value), 7) for value in (bounds.XMin, bounds.YMin, bounds.ZMin, bounds.XMax, bounds.YMax, bounds.ZMax)],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def phase_snapshot(document):
|
||||||
|
feature = document.getObject("PairResult")
|
||||||
|
if feature is None:
|
||||||
|
raise RuntimeError("PairResult is absent after FCStd persistence")
|
||||||
|
evidence = str(feature.NamingEvidence)
|
||||||
|
return {
|
||||||
|
"pair": str(feature.OrderedPair),
|
||||||
|
"namingEvidenceBytes": len(evidence.encode("utf-8")),
|
||||||
|
"namingEvidenceSha256": hashlib.sha256(evidence.encode("utf-8")).hexdigest(),
|
||||||
|
"shape": shape_snapshot(feature),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def collect():
|
||||||
|
step_path = os.environ["FREECAD_PAIR_STEP_PATH"]
|
||||||
|
evidence_path = os.environ["FREECAD_PAIR_EVIDENCE_PATH"]
|
||||||
|
pair = os.environ["FREECAD_ORDERED_PAIR"]
|
||||||
|
output_directory = os.environ["FREECAD_PAIR_OUTPUT_DIRECTORY"]
|
||||||
|
with open(evidence_path, "r", encoding="utf-8") as evidence_file:
|
||||||
|
evidence = evidence_file.read()
|
||||||
|
document = App.newDocument("FreeCadOrderedPairResave")
|
||||||
|
try:
|
||||||
|
Import.insert(step_path, document.Name)
|
||||||
|
document.recompute()
|
||||||
|
source_shapes = [obj.Shape for obj in document.Objects if hasattr(obj, "Shape") and not obj.Shape.isNull()]
|
||||||
|
if not source_shapes:
|
||||||
|
raise RuntimeError("STEP import produced no Shape")
|
||||||
|
result = document.addObject("Part::Feature", "PairResult")
|
||||||
|
result.Shape = source_shapes[0].copy() if len(source_shapes) == 1 else Part.makeCompound([shape.copy() for shape in source_shapes])
|
||||||
|
result.addProperty("App::PropertyString", "OrderedPair", "Parity")
|
||||||
|
result.addProperty("App::PropertyString", "NamingEvidence", "Parity")
|
||||||
|
result.OrderedPair = pair
|
||||||
|
result.NamingEvidence = evidence
|
||||||
|
document.recompute()
|
||||||
|
initial = phase_snapshot(document)
|
||||||
|
initial_path = os.path.join(output_directory, "ordered-pair.FCStd")
|
||||||
|
resaved_path = os.path.join(output_directory, "ordered-pair-resaved.FCStd")
|
||||||
|
document.saveAs(initial_path)
|
||||||
|
App.closeDocument(document.Name)
|
||||||
|
reopened = App.openDocument(initial_path)
|
||||||
|
reopened.recompute()
|
||||||
|
reopened_snapshot = phase_snapshot(reopened)
|
||||||
|
reopened.saveAs(resaved_path)
|
||||||
|
App.closeDocument(reopened.Name)
|
||||||
|
resaved = App.openDocument(resaved_path)
|
||||||
|
resaved.recompute()
|
||||||
|
resaved_snapshot = phase_snapshot(resaved)
|
||||||
|
App.closeDocument(resaved.Name)
|
||||||
|
return {
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"baselineId": "freecad-1.1.1-ordered-operation-pair-resave",
|
||||||
|
"freecadVersion": version_text(),
|
||||||
|
"gitCommit": FREECAD_COMMIT,
|
||||||
|
"pair": pair,
|
||||||
|
"phases": {"initial": initial, "reopened": reopened_snapshot, "resaved": resaved_snapshot},
|
||||||
|
"checks": {
|
||||||
|
"shapeStable": initial["shape"] == reopened_snapshot["shape"] and initial["shape"] == resaved_snapshot["shape"],
|
||||||
|
"namingEvidenceStable": initial["namingEvidenceSha256"] == reopened_snapshot["namingEvidenceSha256"] and initial["namingEvidenceSha256"] == resaved_snapshot["namingEvidenceSha256"],
|
||||||
|
},
|
||||||
|
"status": "pass",
|
||||||
|
}
|
||||||
|
finally:
|
||||||
|
for name in list(App.listDocuments().keys()):
|
||||||
|
App.closeDocument(name)
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
report = collect()
|
||||||
|
except Exception as error:
|
||||||
|
report = {
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"baselineId": "freecad-1.1.1-ordered-operation-pair-resave",
|
||||||
|
"freecadVersion": version_text(),
|
||||||
|
"gitCommit": FREECAD_COMMIT,
|
||||||
|
"status": "failed",
|
||||||
|
"errorType": type(error).__name__,
|
||||||
|
"error": str(error),
|
||||||
|
}
|
||||||
|
|
||||||
|
print("FREECAD_ORDERED_OPERATION_PAIR_RESAVE_RESULT=" + json.dumps(report, sort_keys=True, separators=(",", ":")))
|
||||||
102
scripts/freecad-production-drift-classification.mjs
Normal file
102
scripts/freecad-production-drift-classification.mjs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
const sha256 = (value) => typeof value === 'string' && /^[0-9a-f]{64}$/.test(value)
|
||||||
|
const canonical = (value) => Array.isArray(value)
|
||||||
|
? value.map(canonical)
|
||||||
|
: value && typeof value === 'object'
|
||||||
|
? Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, canonical(entry)]))
|
||||||
|
: value
|
||||||
|
|
||||||
|
export const productionDriftDecisions = [
|
||||||
|
{
|
||||||
|
taskId: 'TSN-PROD-DRIFT-000',
|
||||||
|
operation: 'cut',
|
||||||
|
classification: 'allowed_evolution',
|
||||||
|
reasonCode: 'native-downstream-topology-stabilizes-after-edit-restore',
|
||||||
|
rationale: 'FreeCAD deterministically evolves the downstream Fillet, Mirrored, and LinearPattern semantic topology after a Pocket Length edit/restore while restoring their geometry; the evolved topology and mapped names remain stable through save, reopen, and resave.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
taskId: 'TSN-PROD-DRIFT-001',
|
||||||
|
operation: 'rotate',
|
||||||
|
classification: 'allowed_evolution',
|
||||||
|
reasonCode: 'native-downstream-topology-stabilizes-after-edit-restore',
|
||||||
|
rationale: 'FreeCAD deterministically evolves the downstream Mirrored and LinearPattern semantic topology after a Rotate Angle edit/restore while restoring their geometry; the evolved topology and mapped names remain stable through save, reopen, and resave.',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const same = (left, right) => JSON.stringify(canonical(left)) === JSON.stringify(canonical(right))
|
||||||
|
|
||||||
|
const stageFingerprint = (driftReplay, ordinal, phase) => {
|
||||||
|
const mutation = driftReplay.mutation
|
||||||
|
const persistence = driftReplay.persistence?.[phase]?.[ordinal]
|
||||||
|
if (!persistence) throw new Error(`${driftReplay.operation}/${ordinal} lacks ${phase} persistence evidence.`)
|
||||||
|
return {
|
||||||
|
geometrySignature: persistence.geometrySignature,
|
||||||
|
semanticTopologyDigest: persistence.semanticTopologyDigest,
|
||||||
|
mappedNames: persistence.mappedNames,
|
||||||
|
mappedNameDigest: persistence.mappedNameDigest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const buildProductionDriftSnapshot = (report, operation) => {
|
||||||
|
const driftReplay = report?.driftReplays?.find((entry) => entry.operation === operation)
|
||||||
|
if (!driftReplay) throw new Error(`${operation} has no isolated production drift replay.`)
|
||||||
|
const mutation = driftReplay.mutation
|
||||||
|
const ordinals = mutation.restoreTopologyDriftOrdinals
|
||||||
|
if (!Array.isArray(ordinals) || ordinals.length === 0) throw new Error(`${operation} has no recovered production topology drift.`)
|
||||||
|
const stages = ordinals.map((ordinal) => ({
|
||||||
|
ordinal,
|
||||||
|
operation: driftReplay.persistence.initial[ordinal].operation,
|
||||||
|
name: driftReplay.persistence.initial[ordinal].name,
|
||||||
|
before: {
|
||||||
|
geometrySignature: mutation.beforeGeometrySignatures[ordinal],
|
||||||
|
semanticTopologyDigest: mutation.beforeTopologyDigests[ordinal],
|
||||||
|
},
|
||||||
|
edited: {
|
||||||
|
geometrySignature: mutation.editedGeometrySignatures[ordinal],
|
||||||
|
semanticTopologyDigest: mutation.editedTopologyDigests[ordinal],
|
||||||
|
},
|
||||||
|
restored: {
|
||||||
|
geometrySignature: mutation.restoredGeometrySignatures[ordinal],
|
||||||
|
semanticTopologyDigest: mutation.restoredTopologyDigests[ordinal],
|
||||||
|
},
|
||||||
|
persistence: Object.fromEntries(['initial', 'reopened', 'resaved'].map((phase) => [phase, stageFingerprint(driftReplay, ordinal, phase)])),
|
||||||
|
}))
|
||||||
|
return {
|
||||||
|
operation,
|
||||||
|
contract: {
|
||||||
|
featureName: mutation.featureName,
|
||||||
|
typeId: mutation.typeId,
|
||||||
|
propertyPath: mutation.propertyPath,
|
||||||
|
},
|
||||||
|
values: {
|
||||||
|
before: mutation.beforeParameter,
|
||||||
|
edited: mutation.editedParameter,
|
||||||
|
restored: mutation.restoredParameter,
|
||||||
|
},
|
||||||
|
driftOrdinals: ordinals,
|
||||||
|
stages,
|
||||||
|
checks: {
|
||||||
|
parameterRestored: mutation.parameterChanged === true && same(mutation.beforeParameter, mutation.restoredParameter),
|
||||||
|
geometryRestored: mutation.restoredGeometrically === true && mutation.restoredExactly === true && same(mutation.beforeGeometrySignatures, mutation.restoredGeometrySignatures),
|
||||||
|
topologyEvolved: stages.every(({ before, restored }) => before.semanticTopologyDigest !== restored.semanticTopologyDigest),
|
||||||
|
restoredMatchesInitial: driftReplay.checks?.restoredMatchesInitial === true && stages.every(({ restored, persistence }) => same(restored.geometrySignature, persistence.initial.geometrySignature) && restored.semanticTopologyDigest === persistence.initial.semanticTopologyDigest),
|
||||||
|
persistenceStable: driftReplay.checks?.geometryStable === true && driftReplay.checks?.topologyStable === true && driftReplay.checks?.mappedNamesStable === true && stages.every(({ persistence }) => ['reopened', 'resaved'].every((phase) => same(persistence.initial, persistence[phase]))),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateProductionDriftSnapshot = (snapshot) => {
|
||||||
|
if (!snapshot || typeof snapshot.operation !== 'string' || !snapshot.operation) throw new Error('production drift snapshot has no operation identity.')
|
||||||
|
if (!Array.isArray(snapshot.driftOrdinals) || snapshot.driftOrdinals.length === 0 || snapshot.stages?.length !== snapshot.driftOrdinals.length) throw new Error(`${snapshot.operation} has an invalid drift-stage set.`)
|
||||||
|
if (!same(snapshot.stages.map(({ ordinal }) => ordinal), snapshot.driftOrdinals)) throw new Error(`${snapshot.operation} drift-stage identities are inconsistent.`)
|
||||||
|
for (const stage of snapshot.stages) {
|
||||||
|
if (!Number.isInteger(stage.ordinal) || !stage.operation || !stage.name) throw new Error(`${snapshot.operation} has an invalid stage identity.`)
|
||||||
|
for (const phase of ['before', 'edited', 'restored']) {
|
||||||
|
if (!Array.isArray(stage[phase]?.geometrySignature) || !sha256(stage[phase]?.semanticTopologyDigest)) throw new Error(`${snapshot.operation}/${stage.name}/${phase} has an invalid fingerprint.`)
|
||||||
|
}
|
||||||
|
for (const phase of ['initial', 'reopened', 'resaved']) {
|
||||||
|
const value = stage.persistence?.[phase]
|
||||||
|
if (!Array.isArray(value?.geometrySignature) || !value?.mappedNames || typeof value.mappedNames !== 'object' || !sha256(value?.semanticTopologyDigest) || !sha256(value?.mappedNameDigest)) throw new Error(`${snapshot.operation}/${stage.name}/${phase} has invalid persistence evidence.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!Object.values(snapshot.checks ?? {}).every((value) => value === true)) throw new Error(`${snapshot.operation} does not satisfy the allowed-evolution evidence contract.`)
|
||||||
|
}
|
||||||
@@ -20,6 +20,69 @@ export const recoveredNamingDecisions = [
|
|||||||
reasonCode: 'native-history-stabilizes-after-edit-restore',
|
reasonCode: 'native-history-stabilizes-after-edit-restore',
|
||||||
rationale: 'FreeCAD applies the same deterministic history evolution to a Midplane Pad Length edit/restore: Body and Pad geometry returns exactly, and the evolved names remain stable through save, reopen, and resave.',
|
rationale: 'FreeCAD applies the same deterministic history evolution to a Midplane Pad Length edit/restore: Body and Pad geometry returns exactly, and the evolved names remain stable through save, reopen, and resave.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
taskId: 'TSN-DRIFT-002',
|
||||||
|
caseId: 'partdesign-reverse',
|
||||||
|
classification: 'allowed_evolution',
|
||||||
|
reasonCode: 'native-history-stabilizes-after-edit-restore',
|
||||||
|
rationale: 'FreeCAD applies the same deterministic history evolution to a Reversed Pad Length edit/restore: Body and Pad geometry returns exactly, and the evolved names remain stable through save, reopen, and resave.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
taskId: 'TSN-DRIFT-003',
|
||||||
|
caseId: 'partdesign-taper',
|
||||||
|
classification: 'allowed_evolution',
|
||||||
|
reasonCode: 'native-history-stabilizes-after-edit-restore',
|
||||||
|
rationale: 'FreeCAD applies the same deterministic history evolution to a Tapered Pad Length edit/restore: Body and Pad geometry returns exactly, and the evolved names remain stable through save, reopen, and resave.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
taskId: 'TSN-DRIFT-004',
|
||||||
|
caseId: 'partdesign-twoside',
|
||||||
|
classification: 'allowed_evolution',
|
||||||
|
reasonCode: 'native-history-stabilizes-after-edit-restore',
|
||||||
|
rationale: 'FreeCAD applies the same deterministic history evolution to a Two Lengths Pad Length edit/restore: Body and Pad geometry returns exactly, and the evolved names remain stable through save, reopen, and resave.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
taskId: 'TSN-DRIFT-005',
|
||||||
|
caseId: 'partdesign-pocket',
|
||||||
|
classification: 'allowed_evolution',
|
||||||
|
reasonCode: 'native-history-stabilizes-after-edit-restore',
|
||||||
|
rationale: 'FreeCAD applies deterministic history evolution to an upstream Pad Length edit/restore: Body, Pad, and downstream Pocket geometry returns exactly, and the evolved names remain stable through save, reopen, and resave.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
taskId: 'TSN-DRIFT-006',
|
||||||
|
caseId: 'partdesign-pocket-through',
|
||||||
|
classification: 'allowed_evolution',
|
||||||
|
reasonCode: 'native-history-stabilizes-after-edit-restore',
|
||||||
|
rationale: 'FreeCAD applies deterministic history evolution through a Through All Pocket after an upstream Pad Length edit/restore: Body, Pad, and Pocket geometry returns exactly, and the evolved names remain stable through save, reopen, and resave.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
taskId: 'TSN-DRIFT-007',
|
||||||
|
caseId: 'partdesign-pocket-midplane',
|
||||||
|
classification: 'allowed_evolution',
|
||||||
|
reasonCode: 'native-history-stabilizes-after-edit-restore',
|
||||||
|
rationale: 'FreeCAD applies deterministic history evolution through a Midplane Pocket after an upstream Pad Length edit/restore: Body, Pad, and Pocket geometry returns exactly, and the evolved names remain stable through save, reopen, and resave.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
taskId: 'TSN-DRIFT-008',
|
||||||
|
caseId: 'partdesign-pocket-twoside',
|
||||||
|
classification: 'allowed_evolution',
|
||||||
|
reasonCode: 'native-history-stabilizes-after-edit-restore',
|
||||||
|
rationale: 'FreeCAD applies deterministic history evolution through a Two Lengths Pocket after an upstream Pad Length edit/restore: Body, Pad, and Pocket geometry returns exactly, and the evolved names remain stable through save, reopen, and resave.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
taskId: 'TSN-DRIFT-009',
|
||||||
|
caseId: 'partdesign-pocket-taper',
|
||||||
|
classification: 'allowed_evolution',
|
||||||
|
reasonCode: 'native-history-stabilizes-after-edit-restore',
|
||||||
|
rationale: 'FreeCAD applies deterministic history evolution through a Tapered Pocket after an upstream Pad Length edit/restore: Body, Pad, and Pocket geometry returns exactly, and the evolved names remain stable through save, reopen, and resave.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
taskId: 'TSN-DRIFT-010',
|
||||||
|
caseId: 'partdesign-pocket-up-to-face',
|
||||||
|
classification: 'allowed_evolution',
|
||||||
|
reasonCode: 'native-history-stabilizes-after-edit-restore',
|
||||||
|
rationale: 'FreeCAD applies deterministic history evolution through an Up To Face Pocket after an upstream Pad Length edit/restore: Body, Pad, and Pocket geometry returns exactly, and the evolved names remain stable through save, reopen, and resave.',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const same = (left, right) => JSON.stringify(canonical(left)) === JSON.stringify(canonical(right))
|
export const same = (left, right) => JSON.stringify(canonical(left)) === JSON.stringify(canonical(right))
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
import FreeCAD as App
|
import FreeCAD as App
|
||||||
@@ -56,7 +57,8 @@ def mapped_names(feature):
|
|||||||
indexed, _ = shape.getElementIndexedName(name, True)
|
indexed, _ = shape.getElementIndexedName(name, True)
|
||||||
except Exception:
|
except Exception:
|
||||||
indexed = ""
|
indexed = ""
|
||||||
result[name] = mapped or indexed or name
|
normalized = re.sub(r":H-?[0-9a-fA-F]+", ":H#", mapped or indexed or name)
|
||||||
|
result[name] = re.sub(r":H:-?[0-9a-fA-F]+(?=[,;])", ":H:#", normalized)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -192,14 +194,19 @@ def rebuild_derived(document, features):
|
|||||||
|
|
||||||
|
|
||||||
def topology_snapshot(features):
|
def topology_snapshot(features):
|
||||||
return [{
|
result = []
|
||||||
"operation": operation,
|
for operation, feature in zip(OPERATIONS, features):
|
||||||
"name": feature.Name,
|
names = mapped_names(feature)
|
||||||
"shape": shape_snapshot(feature),
|
result.append({
|
||||||
"mappedNameCount": len(mapped_names(feature)),
|
"operation": operation,
|
||||||
"mappedNameDigest": mapped_name_digest(feature),
|
"name": feature.Name,
|
||||||
"semanticTopologyDigest": semantic_topology_digest(feature),
|
"shape": shape_snapshot(feature),
|
||||||
} for operation, feature in zip(OPERATIONS, features)]
|
"mappedNames": names,
|
||||||
|
"mappedNameCount": len(names),
|
||||||
|
"mappedNameDigest": hashlib.sha256(json.dumps(names, sort_keys=True, separators=(",", ":")).encode("utf-8")).hexdigest(),
|
||||||
|
"semanticTopologyDigest": semantic_topology_digest(feature),
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def parameter_value(value):
|
def parameter_value(value):
|
||||||
@@ -230,10 +237,15 @@ def capture_mutation(document, features, operation, feature, property_name, edit
|
|||||||
restored_parameter = parameter_value(getattr(feature, property_name))
|
restored_parameter = parameter_value(getattr(feature, property_name))
|
||||||
restored = topology_snapshot(features)
|
restored = topology_snapshot(features)
|
||||||
before_digests = [stage["semanticTopologyDigest"] for stage in before]
|
before_digests = [stage["semanticTopologyDigest"] for stage in before]
|
||||||
|
edited_digests = [stage["semanticTopologyDigest"] for stage in edited]
|
||||||
restored_digests = [stage["semanticTopologyDigest"] for stage in restored]
|
restored_digests = [stage["semanticTopologyDigest"] for stage in restored]
|
||||||
|
drift_ordinals = [index for index, (before_digest, restored_digest) in enumerate(zip(before_digests, restored_digests)) if before_digest != restored_digest]
|
||||||
|
before_geometry = [geometry_signature(stage) for stage in before]
|
||||||
|
edited_geometry = [geometry_signature(stage) for stage in edited]
|
||||||
|
restored_geometry = [geometry_signature(stage) for stage in restored]
|
||||||
before_final = before[-1]["shape"]["brepSha256"]
|
before_final = before[-1]["shape"]["brepSha256"]
|
||||||
edited_final = edited[-1]["shape"]["brepSha256"]
|
edited_final = edited[-1]["shape"]["brepSha256"]
|
||||||
restored_geometrically = [geometry_signature(stage) for stage in before] == [geometry_signature(stage) for stage in restored]
|
restored_geometrically = before_geometry == restored_geometry
|
||||||
restored_topology_exactly = before_digests == restored_digests
|
restored_topology_exactly = before_digests == restored_digests
|
||||||
passed = before_parameter != edited_parameter and before_final != edited_final and before_parameter == restored_parameter and restored_geometrically
|
passed = before_parameter != edited_parameter and before_final != edited_final and before_parameter == restored_parameter and restored_geometrically
|
||||||
return {
|
return {
|
||||||
@@ -249,14 +261,98 @@ def capture_mutation(document, features, operation, feature, property_name, edit
|
|||||||
"restoredExactly": before_parameter == restored_parameter and restored_geometrically,
|
"restoredExactly": before_parameter == restored_parameter and restored_geometrically,
|
||||||
"restoredGeometrically": restored_geometrically,
|
"restoredGeometrically": restored_geometrically,
|
||||||
"restoredTopologyExactly": restored_topology_exactly,
|
"restoredTopologyExactly": restored_topology_exactly,
|
||||||
"restoreTopologyDriftStages": sum(1 for before_digest, restored_digest in zip(before_digests, restored_digests) if before_digest != restored_digest),
|
"restoreTopologyDriftStages": len(drift_ordinals),
|
||||||
|
"restoreTopologyDriftOrdinals": drift_ordinals,
|
||||||
|
"beforeGeometrySignatures": before_geometry,
|
||||||
|
"editedGeometrySignatures": edited_geometry,
|
||||||
|
"restoredGeometrySignatures": restored_geometry,
|
||||||
"beforeTopologyDigests": before_digests,
|
"beforeTopologyDigests": before_digests,
|
||||||
"editedTopologyDigests": [stage["semanticTopologyDigest"] for stage in edited],
|
"editedTopologyDigests": edited_digests,
|
||||||
"restoredTopologyDigests": restored_digests,
|
"restoredTopologyDigests": restored_digests,
|
||||||
"status": "pass" if passed else "failed",
|
"status": "pass" if passed else "failed",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def mutation_specs(features):
|
||||||
|
pocket, rotated, fillet, mirrored, pattern = features
|
||||||
|
return [
|
||||||
|
("cut", pocket, "Length", 2.5),
|
||||||
|
("rotate", rotated, "Angle", 22.5),
|
||||||
|
("fillet", fillet, "Radius", 0.35),
|
||||||
|
("mirrored", mirrored, "PlaneNormal", App.Vector(0, 0, 1)),
|
||||||
|
("linear-pattern", pattern, "Occurrences", 3),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def persistence_projection(features):
|
||||||
|
return [{
|
||||||
|
"operation": stage["operation"],
|
||||||
|
"name": stage["name"],
|
||||||
|
"geometrySignature": geometry_signature(stage),
|
||||||
|
"semanticTopologyDigest": stage["semanticTopologyDigest"],
|
||||||
|
"mappedNames": stage["mappedNames"],
|
||||||
|
"mappedNameDigest": stage["mappedNameDigest"],
|
||||||
|
} for stage in topology_snapshot(features)]
|
||||||
|
|
||||||
|
|
||||||
|
def collect_drift_replay(target_index):
|
||||||
|
target_operation = OPERATIONS[target_index]
|
||||||
|
document = App.newDocument("TsnStageCorrelation{}Replay".format(target_operation.title()))
|
||||||
|
try:
|
||||||
|
features = create_chain(document)
|
||||||
|
rebuild_derived(document, features)
|
||||||
|
mutations = []
|
||||||
|
for operation, feature, property_name, edited_value in mutation_specs(features)[:target_index + 1]:
|
||||||
|
mutations.append(capture_mutation(document, features, operation, feature, property_name, edited_value))
|
||||||
|
target_mutation = mutations[-1]
|
||||||
|
feature_names = [feature.Name for feature in features]
|
||||||
|
with tempfile.TemporaryDirectory(prefix="freecad-tsn-{}-drift-".format(target_operation)) as directory:
|
||||||
|
initial_path = os.path.join(directory, "{}-restored.FCStd".format(target_operation))
|
||||||
|
resaved_path = os.path.join(directory, "{}-restored-resaved.FCStd".format(target_operation))
|
||||||
|
initial = persistence_projection(features)
|
||||||
|
document.saveAs(initial_path)
|
||||||
|
App.closeDocument(document.Name)
|
||||||
|
reopened = App.openDocument(initial_path)
|
||||||
|
reopened.recompute()
|
||||||
|
reopened_features = [reopened.getObject(name) for name in feature_names]
|
||||||
|
reopened_projection = persistence_projection(reopened_features)
|
||||||
|
reopened.saveAs(resaved_path)
|
||||||
|
App.closeDocument(reopened.Name)
|
||||||
|
resaved = App.openDocument(resaved_path)
|
||||||
|
resaved.recompute()
|
||||||
|
resaved_features = [resaved.getObject(name) for name in feature_names]
|
||||||
|
resaved_projection = persistence_projection(resaved_features)
|
||||||
|
App.closeDocument(resaved.Name)
|
||||||
|
initial_topology = [stage["semanticTopologyDigest"] for stage in initial]
|
||||||
|
reopened_topology = [stage["semanticTopologyDigest"] for stage in reopened_projection]
|
||||||
|
resaved_topology = [stage["semanticTopologyDigest"] for stage in resaved_projection]
|
||||||
|
initial_names = [stage["mappedNameDigest"] for stage in initial]
|
||||||
|
reopened_names = [stage["mappedNameDigest"] for stage in reopened_projection]
|
||||||
|
resaved_names = [stage["mappedNameDigest"] for stage in resaved_projection]
|
||||||
|
initial_geometry = [stage["geometrySignature"] for stage in initial]
|
||||||
|
reopened_geometry = [stage["geometrySignature"] for stage in reopened_projection]
|
||||||
|
resaved_geometry = [stage["geometrySignature"] for stage in resaved_projection]
|
||||||
|
return {
|
||||||
|
"operation": target_operation,
|
||||||
|
"mutation": target_mutation,
|
||||||
|
"persistence": {
|
||||||
|
"initial": initial,
|
||||||
|
"reopened": reopened_projection,
|
||||||
|
"resaved": resaved_projection,
|
||||||
|
},
|
||||||
|
"checks": {
|
||||||
|
"restoredMatchesInitial": target_mutation["restoredTopologyDigests"] == initial_topology,
|
||||||
|
"geometryStable": initial_geometry == reopened_geometry and initial_geometry == resaved_geometry,
|
||||||
|
"topologyStable": initial_topology == reopened_topology and initial_topology == resaved_topology,
|
||||||
|
"mappedNamesStable": initial_names == reopened_names and initial_names == resaved_names,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
finally:
|
||||||
|
for name in list(App.listDocuments().keys()):
|
||||||
|
if name.startswith("TsnStageCorrelation{}Replay".format(target_operation.title())):
|
||||||
|
App.closeDocument(name)
|
||||||
|
|
||||||
|
|
||||||
def stage_report(operation, feature):
|
def stage_report(operation, feature):
|
||||||
sources, relations = history_sources(feature)
|
sources, relations = history_sources(feature)
|
||||||
names = mapped_names(feature)
|
names = mapped_names(feature)
|
||||||
@@ -279,14 +375,7 @@ def collect():
|
|||||||
try:
|
try:
|
||||||
features = create_chain(document)
|
features = create_chain(document)
|
||||||
rebuild_derived(document, features)
|
rebuild_derived(document, features)
|
||||||
pocket, rotated, fillet, mirrored, pattern = features
|
mutations = [capture_mutation(document, features, operation, feature, property_name, edited_value) for operation, feature, property_name, edited_value in mutation_specs(features)]
|
||||||
mutations = [
|
|
||||||
capture_mutation(document, features, "cut", pocket, "Length", 2.5),
|
|
||||||
capture_mutation(document, features, "rotate", rotated, "Angle", 22.5),
|
|
||||||
capture_mutation(document, features, "fillet", fillet, "Radius", 0.35),
|
|
||||||
capture_mutation(document, features, "mirrored", mirrored, "PlaneNormal", App.Vector(0, 0, 1)),
|
|
||||||
capture_mutation(document, features, "linear-pattern", pattern, "Occurrences", 3),
|
|
||||||
]
|
|
||||||
stages = [stage_report(operation, feature) for operation, feature in zip(OPERATIONS, features)]
|
stages = [stage_report(operation, feature) for operation, feature in zip(OPERATIONS, features)]
|
||||||
with tempfile.TemporaryDirectory(prefix="freecad-tsn-stage-correlation-") as directory:
|
with tempfile.TemporaryDirectory(prefix="freecad-tsn-stage-correlation-") as directory:
|
||||||
initial_path = os.path.join(directory, "tsn-stage-correlation.FCStd")
|
initial_path = os.path.join(directory, "tsn-stage-correlation.FCStd")
|
||||||
@@ -312,6 +401,7 @@ def collect():
|
|||||||
unexplained_relations += sum(1 for source in stage["historySources"] if source not in known_sources)
|
unexplained_relations += sum(1 for source in stage["historySources"] if source not in known_sources)
|
||||||
if stage["mappedNameCount"] <= 0:
|
if stage["mappedNameCount"] <= 0:
|
||||||
wrong_bindings += 1
|
wrong_bindings += 1
|
||||||
|
drift_replays = [collect_drift_replay(index) for index, mutation in enumerate(mutations) if mutation["restoreTopologyDriftStages"] > 0]
|
||||||
with open(__file__, "rb") as harness_file:
|
with open(__file__, "rb") as harness_file:
|
||||||
harness_content = harness_file.read()
|
harness_content = harness_file.read()
|
||||||
return {
|
return {
|
||||||
@@ -324,6 +414,7 @@ def collect():
|
|||||||
"reopenedStages": reopened_stages,
|
"reopenedStages": reopened_stages,
|
||||||
"resavedStages": resaved_stages,
|
"resavedStages": resaved_stages,
|
||||||
"mutations": mutations,
|
"mutations": mutations,
|
||||||
|
"driftReplays": drift_replays,
|
||||||
"summary": {
|
"summary": {
|
||||||
"stages": len(stages),
|
"stages": len(stages),
|
||||||
"nativeBuilderStages": sum(1 for stage in stages if stage["nativeBuilder"]),
|
"nativeBuilderStages": sum(1 for stage in stages if stage["nativeBuilder"]),
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ import { resolve } from 'node:path'
|
|||||||
const root = resolve(new URL('..', import.meta.url).pathname)
|
const root = resolve(new URL('..', import.meta.url).pathname)
|
||||||
const outputPath = resolve(root, 'config/freecad-active-work-queue.json')
|
const outputPath = resolve(root, 'config/freecad-active-work-queue.json')
|
||||||
const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse)
|
const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse)
|
||||||
const [gui, workflowPlan, composite, correlation, production, recoveredNaming] = await Promise.all([
|
const [gui, workflowPlan, composite, correlation, production, recoveredNaming, productionDriftClassification, orderedPairClassification] = await Promise.all([
|
||||||
load('.cache/freecad/reference-desktop-gui-commands.json'),
|
load('.cache/freecad/reference-desktop-gui-commands.json'),
|
||||||
load('config/freecad-gui-workflow-plan.json'),
|
load('config/freecad-gui-workflow-plan.json'),
|
||||||
load('config/freecad-composite-history-elementmap-oracle.json'),
|
load('config/freecad-composite-history-elementmap-oracle.json'),
|
||||||
load('config/freecad-tsn-stage-correlation-oracle.json'),
|
load('config/freecad-tsn-stage-correlation-oracle.json'),
|
||||||
load('config/chrome-freecad-naming-production-verification.json'),
|
load('config/chrome-freecad-naming-production-verification.json'),
|
||||||
load('config/freecad-recovered-naming-classification.json'),
|
load('config/freecad-recovered-naming-classification.json'),
|
||||||
|
load('config/freecad-production-drift-classification.json'),
|
||||||
|
load('config/freecad-ordered-operation-pair-classification.json'),
|
||||||
])
|
])
|
||||||
|
|
||||||
const guiShardTasks = gui.guiCommands.mergedShards.map((shard, index) => ({
|
const guiShardTasks = gui.guiCommands.mergedShards.map((shard, index) => ({
|
||||||
@@ -61,26 +63,47 @@ const driftTasks = driftCases.map((fixture, index) => ({
|
|||||||
...(classifications.has(fixture.id) ? { classification: classifications.get(fixture.id).classification, evidence: ['config/freecad-recovered-naming-classification.json', classifications.get(fixture.id).reasonCode] } : {}),
|
...(classifications.has(fixture.id) ? { classification: classifications.get(fixture.id).classification, evidence: ['config/freecad-recovered-naming-classification.json', classifications.get(fixture.id).reasonCode] } : {}),
|
||||||
exit: 'the case is classified as stable semantics, allowed evolution, or an implementation defect',
|
exit: 'the case is classified as stable semantics, allowed evolution, or an implementation defect',
|
||||||
}))
|
}))
|
||||||
|
const recoveredNamingClosed = completedDriftCases === driftCases.length
|
||||||
|
const productionDriftClassifications = new Map(productionDriftClassification.classifications.map((entry) => [entry.operation, entry]))
|
||||||
|
if (productionDriftClassifications.size !== productionDriftClassification.classifications.length) throw new Error('Production drift classifications contain duplicate operations.')
|
||||||
|
const productionDriftMutations = correlation.mutations.filter((mutation) => mutation.restoreTopologyDriftStages > 0)
|
||||||
|
const productionClassifiedPrefix = productionDriftMutations.findIndex(({ operation }) => !productionDriftClassifications.has(operation))
|
||||||
|
const completedProductionDrifts = productionClassifiedPrefix < 0 ? productionDriftMutations.length : productionClassifiedPrefix
|
||||||
|
if (productionDriftMutations.slice(completedProductionDrifts).some(({ operation }) => productionDriftClassifications.has(operation))) throw new Error('Production drift classifications must form a contiguous serial prefix.')
|
||||||
|
for (const entry of productionDriftClassification.classifications) {
|
||||||
|
if (!productionDriftMutations.some(({ operation }) => operation === entry.operation) || !['stable_semantics', 'allowed_evolution', 'implementation_defect'].includes(entry.classification)) throw new Error(`Production drift classification ${entry.operation} is invalid.`)
|
||||||
|
}
|
||||||
const productionDriftTasks = correlation.mutations
|
const productionDriftTasks = correlation.mutations
|
||||||
.filter((mutation) => mutation.restoreTopologyDriftStages > 0)
|
.filter((mutation) => mutation.restoreTopologyDriftStages > 0)
|
||||||
.map((mutation, index) => ({
|
.map((mutation, index) => ({
|
||||||
id: `TSN-PROD-DRIFT-${String(index).padStart(3, '0')}`,
|
id: `TSN-PROD-DRIFT-${String(index).padStart(3, '0')}`,
|
||||||
title: `Classify production restore topology drift for ${mutation.operation}`,
|
title: `Classify production restore topology drift for ${mutation.operation}`,
|
||||||
status: 'pending',
|
status: index < completedProductionDrifts ? 'completed' : recoveredNamingClosed && index === completedProductionDrifts ? 'in_progress' : 'pending',
|
||||||
dependencies: [index === 0 ? driftTasks.at(-1).id : `TSN-PROD-DRIFT-${String(index - 1).padStart(3, '0')}`],
|
dependencies: [index === 0 ? driftTasks.at(-1).id : `TSN-PROD-DRIFT-${String(index - 1).padStart(3, '0')}`],
|
||||||
operation: mutation.operation,
|
operation: mutation.operation,
|
||||||
driftStages: mutation.restoreTopologyDriftStages,
|
driftStages: mutation.restoreTopologyDriftStages,
|
||||||
|
...(productionDriftClassifications.has(mutation.operation) ? { classification: productionDriftClassifications.get(mutation.operation).classification, evidence: ['config/freecad-production-drift-classification.json', productionDriftClassifications.get(mutation.operation).reasonCode] } : {}),
|
||||||
exit: 'every changed downstream stage has a native comparison and classification',
|
exit: 'every changed downstream stage has a native comparison and classification',
|
||||||
}))
|
}))
|
||||||
const coveredTransitions = new Set(['cut->rotate', 'rotate->fillet', 'fillet->mirrored', 'mirrored->linear-pattern'])
|
const productionDriftClosed = completedProductionDrifts === productionDriftTasks.length
|
||||||
|
const orderedPairClassifications = new Map(orderedPairClassification.classifications.map((entry) => [entry.pair, entry]))
|
||||||
|
if (orderedPairClassifications.size !== orderedPairClassification.classifications.length) throw new Error('Ordered operation pair classifications contain duplicate pairs.')
|
||||||
|
for (const entry of orderedPairClassification.classifications) {
|
||||||
|
if (!['accepted', 'rejected'].includes(entry.classification) || entry.nativeDecision !== entry.classification) throw new Error(`Ordered operation pair classification ${entry.pair} is invalid.`)
|
||||||
|
}
|
||||||
|
const coveredTransitions = new Set(['cut->rotate', 'rotate->fillet', 'fillet->mirrored', 'mirrored->linear-pattern', ...orderedPairClassifications.keys()])
|
||||||
|
let nextTransitionSelected = false
|
||||||
const transitionTasks = production.operations.flatMap((from) => production.operations.map((to) => {
|
const transitionTasks = production.operations.flatMap((from) => production.operations.map((to) => {
|
||||||
const pair = `${from}->${to}`
|
const pair = `${from}->${to}`
|
||||||
|
const inProgress = productionDriftClosed && !coveredTransitions.has(pair) && !nextTransitionSelected
|
||||||
|
if (inProgress) nextTransitionSelected = true
|
||||||
return {
|
return {
|
||||||
id: `TSN-PAIR-${from}-${to}`,
|
id: `TSN-PAIR-${from}-${to}`,
|
||||||
title: `Classify ordered operation pair ${pair}`,
|
title: `Classify ordered operation pair ${pair}`,
|
||||||
status: coveredTransitions.has(pair) ? 'completed' : 'pending',
|
status: coveredTransitions.has(pair) ? 'completed' : inProgress ? 'in_progress' : 'pending',
|
||||||
dependencies: coveredTransitions.has(pair) ? [] : [productionDriftTasks.at(-1).id],
|
dependencies: coveredTransitions.has(pair) ? [] : [productionDriftTasks.at(-1).id],
|
||||||
pair,
|
pair,
|
||||||
|
...(orderedPairClassifications.has(pair) ? { classification: orderedPairClassifications.get(pair).classification, evidence: ['config/freecad-ordered-operation-pair-classification.json', orderedPairClassifications.get(pair).reasonCode] } : {}),
|
||||||
exit: 'native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence',
|
exit: 'native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence',
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
@@ -98,8 +121,8 @@ const closureTasks = [
|
|||||||
const milestones = [
|
const milestones = [
|
||||||
{ id: 'ORA-GUI-BASELINE', exactTask: 'EX-ORA-01', status: 'completed', tasks: [...setupTasks, ...guiShardTasks, ...closureTasks] },
|
{ id: 'ORA-GUI-BASELINE', exactTask: 'EX-ORA-01', status: 'completed', tasks: [...setupTasks, ...guiShardTasks, ...closureTasks] },
|
||||||
{ id: 'ORA-GUI-WORKFLOWS', exactTask: 'EX-ORA-01', status: workflowClosed ? 'completed' : 'in_progress', tasks: workflowTasks },
|
{ id: 'ORA-GUI-WORKFLOWS', exactTask: 'EX-ORA-01', status: workflowClosed ? 'completed' : 'in_progress', tasks: workflowTasks },
|
||||||
{ id: 'TSN-RECOVERY-DRIFT', exactTask: 'EX-TSN-04', status: workflowClosed ? 'in_progress' : 'pending', tasks: [...driftTasks, ...productionDriftTasks] },
|
{ id: 'TSN-RECOVERY-DRIFT', exactTask: 'EX-TSN-04', status: productionDriftClosed ? 'completed' : workflowClosed ? 'in_progress' : 'pending', tasks: [...driftTasks, ...productionDriftTasks] },
|
||||||
{ id: 'TSN-ORDERED-PAIRS', exactTask: 'EX-TSN-04', status: 'pending', tasks: transitionTasks },
|
{ id: 'TSN-ORDERED-PAIRS', exactTask: 'EX-TSN-04', status: productionDriftClosed ? 'in_progress' : 'pending', tasks: transitionTasks },
|
||||||
]
|
]
|
||||||
const allTasks = milestones.flatMap((milestone) => milestone.tasks)
|
const allTasks = milestones.flatMap((milestone) => milestone.tasks)
|
||||||
const count = (status) => allTasks.filter((task) => task.status === status).length
|
const count = (status) => allTasks.filter((task) => task.status === status).length
|
||||||
|
|||||||
220
scripts/run-freecad-ordered-operation-pair-classification.mjs
Normal file
220
scripts/run-freecad-ordered-operation-pair-classification.mjs
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
import { spawnSync } from 'node:child_process'
|
||||||
|
import { createHash } from 'node:crypto'
|
||||||
|
import { existsSync } from 'node:fs'
|
||||||
|
import { mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises'
|
||||||
|
import { tmpdir } from 'node:os'
|
||||||
|
import { join, resolve } from 'node:path'
|
||||||
|
import { pathToFileURL } from 'node:url'
|
||||||
|
import { captureFreeCadPrivateNamingEvidence, classifyFreeCadPrivateNamingHistory, createFreeCadPrivateNamingAbiRequest } from '../src/facade/nativeNamingAbi.ts'
|
||||||
|
|
||||||
|
const root = resolve(new URL('..', import.meta.url).pathname)
|
||||||
|
const dist = resolve(root, 'native/occt-history/dist')
|
||||||
|
const modulePath = resolve(dist, 'bitbybit-occt-history.js')
|
||||||
|
const freecad = process.env.FREECAD_CMD || resolve(root, '.cache/freecad/install-desktop/bin/FreeCADCmd')
|
||||||
|
const sysroot = resolve(root, '.cache/freecad/sysroot')
|
||||||
|
const executorPath = resolve(root, 'scripts/run-freecad-ordered-operation-pair-classification.mjs')
|
||||||
|
const resaveHarnessPath = resolve(root, 'scripts/freecad-ordered-operation-pair-resave.py')
|
||||||
|
const outputPath = resolve(root, 'config/freecad-ordered-operation-pair-classification.json')
|
||||||
|
const artifactNames = ['bitbybit-occt-history.js', 'bitbybit-occt-history.wasm', 'bitbybit-occt-history.data']
|
||||||
|
const fail = (message) => { throw new Error(`FreeCAD ordered operation pair classification: ${message}`) }
|
||||||
|
if (!existsSync(modulePath) || !existsSync(freecad)) fail('native OCCT or FreeCAD executable is missing.')
|
||||||
|
|
||||||
|
const sha256 = (value) => createHash('sha256').update(value).digest('hex')
|
||||||
|
const shapeStep = (module, method, ...args) => {
|
||||||
|
const shape = module[method](...args)
|
||||||
|
try { return module.shapeToStep(shape) }
|
||||||
|
finally { shape.delete?.() }
|
||||||
|
}
|
||||||
|
const input = (inputId, role, objectId, objectTag, step, namingEvidence) => ({ inputId, role, objectId, objectTag, step, ...(namingEvidence ? { namingEvidence } : {}) })
|
||||||
|
const serializableHistory = (response, records) => ({ provider: response.provider, occtVersion: response.occtVersion, records, hasModified: response.hasModified, hasGenerated: response.hasGenerated, hasDeleted: response.hasDeleted, resultStep: response.resultStep, resultBrep: response.resultBrep })
|
||||||
|
const namingSemanticSnapshot = (evidence) => (evidence?.mappedNames ?? []).map((entry) => ({
|
||||||
|
kind: entry.kind,
|
||||||
|
resultIndex: entry.resultIndex,
|
||||||
|
resultPersistentId: entry.resultPersistentId,
|
||||||
|
relation: entry.relation,
|
||||||
|
candidates: (entry.candidates ?? []).map((candidate) => ({ objectId: candidate.objectId, persistentId: candidate.persistentId, stageId: candidate.stageId, relation: candidate.relation })).sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right))),
|
||||||
|
})).sort((left, right) => `${left.kind}:${left.resultIndex}`.localeCompare(`${right.kind}:${right.resultIndex}`))
|
||||||
|
const canonicalSummary = (summary) => ({
|
||||||
|
isValid: summary.isValid,
|
||||||
|
solids: summary.solids,
|
||||||
|
faces: summary.faces,
|
||||||
|
edges: summary.edges,
|
||||||
|
vertices: summary.vertices,
|
||||||
|
volume: Number(summary.volume.toFixed(7)),
|
||||||
|
area: Number(summary.area.toFixed(7)),
|
||||||
|
bounds: [...summary.boundingBox.min, ...summary.boundingBox.max].map((value) => Number(value.toFixed(7))),
|
||||||
|
})
|
||||||
|
|
||||||
|
const operationSpecs = {
|
||||||
|
fuse: { builder: 'BRepAlgoAPI_Fuse', nominal: { toolSize: 5, toolOffset: 12 }, edited: { toolSize: 5, toolOffset: 11 }, parameter: 'toolOffsetX', beforeValue: 12, editedValue: 11 },
|
||||||
|
cut: { builder: 'BRepAlgoAPI_Cut', nominal: { toolSize: 4, toolOffset: 2 }, edited: { toolSize: 3, toolOffset: 2 }, parameter: 'toolSize', beforeValue: 4, editedValue: 3 },
|
||||||
|
common: { builder: 'BRepAlgoAPI_Common', nominal: { toolSize: 5, toolOffset: 10 }, edited: { toolSize: 5, toolOffset: 9 }, parameter: 'toolOffsetX', beforeValue: 10, editedValue: 9 },
|
||||||
|
rotate: { builder: 'BRepBuilderAPI_Transform', nominal: { angle: 15 }, edited: { angle: 22.5 }, parameter: 'angle', beforeValue: 15, editedValue: 22.5 },
|
||||||
|
}
|
||||||
|
|
||||||
|
const createOperation = (module, { operation, objectStep, toolSize, toolOffset, angle, stage }) => {
|
||||||
|
const baseStep = objectStep ?? shapeStep(module, 'makeBox', 10, 10, 10)
|
||||||
|
const objectInput = input('object', 'object', stage.objectId, stage.objectTag, baseStep, stage.namingEvidence)
|
||||||
|
if (operation === 'rotate') return { response: module.rotateHistoryFromStep(baseStep, 0, 0, 0, 0, 0, 1, angle), inputs: [objectInput] }
|
||||||
|
const toolStep = shapeStep(module, 'makeBoxPlaced', toolSize, toolSize, toolSize, toolOffset, 0, 0)
|
||||||
|
const inputs = [
|
||||||
|
objectInput,
|
||||||
|
input('tool', 'tool', `${stage.resultObjectId}:tool`, stage.objectTag + 1, toolStep),
|
||||||
|
]
|
||||||
|
return { response: module.booleanHistoryFromStep(baseStep, toolStep, operation), inputs }
|
||||||
|
}
|
||||||
|
|
||||||
|
const captureStage = (module, definition) => {
|
||||||
|
const { response, inputs } = createOperation(module, definition)
|
||||||
|
try {
|
||||||
|
const provenance = classifyFreeCadPrivateNamingHistory(response.records, inputs)
|
||||||
|
const stableRecords = provenance.records.filter(({ relation }) => relation !== 'deleted').length
|
||||||
|
if (response.provider !== 'occt-native' || !response.resultStep?.startsWith('ISO-10303-21;') || response.summary?.isValid !== true || (stableRecords < 1 && provenance.ambiguities.length < 1)) fail(`${definition.stage.stageId} native ${definition.operation} builder returned no usable result.`)
|
||||||
|
const request = createFreeCadPrivateNamingAbiRequest({
|
||||||
|
requestId: `${definition.stage.stageId}:request`,
|
||||||
|
documentId: 'ordered-operation-pair',
|
||||||
|
documentVersion: definition.stage.ordinal + 1,
|
||||||
|
operationId: definition.stage.stageId,
|
||||||
|
operation: definition.operation,
|
||||||
|
stageId: definition.stage.stageId,
|
||||||
|
resultObjectId: definition.stage.resultObjectId,
|
||||||
|
resultObjectTag: definition.stage.resultObjectTag,
|
||||||
|
inputs,
|
||||||
|
stages: [{ stageId: definition.stage.stageId, operation: definition.operation, inputIds: inputs.map(({ inputId }) => inputId), ordinal: definition.stage.ordinal }],
|
||||||
|
resultStep: response.resultStep,
|
||||||
|
resultBrep: response.resultBrep,
|
||||||
|
history: serializableHistory(response, response.records),
|
||||||
|
})
|
||||||
|
const namingEvidence = captureFreeCadPrivateNamingEvidence(module, request)
|
||||||
|
const mappedResults = stableRecords + provenance.ambiguities.length
|
||||||
|
if (!namingEvidence || !['native-evidence', 'ambiguous'].includes(namingEvidence.status) || namingEvidence.mappedNames?.length !== mappedResults) fail(`${definition.stage.stageId} FreeCAD naming callback evidence is incomplete: ${JSON.stringify(namingEvidence)}`)
|
||||||
|
return {
|
||||||
|
response,
|
||||||
|
namingEvidence,
|
||||||
|
report: {
|
||||||
|
operation: definition.operation,
|
||||||
|
builder: operationSpecs[definition.operation].builder,
|
||||||
|
inputCount: inputs.length,
|
||||||
|
historyProvider: response.provider,
|
||||||
|
namingStatus: namingEvidence.status,
|
||||||
|
summary: canonicalSummary(response.summary),
|
||||||
|
historyRecords: response.records.length,
|
||||||
|
selectedRecords: stableRecords,
|
||||||
|
ambiguousResults: provenance.ambiguities.length,
|
||||||
|
historySha256: sha256(JSON.stringify(response.records)),
|
||||||
|
namingEvidenceSha256: sha256(JSON.stringify(namingEvidence)),
|
||||||
|
namingSemanticSha256: sha256(JSON.stringify(namingSemanticSnapshot(namingEvidence))),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
response.result?.delete?.()
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createModule = (await import(pathToFileURL(modulePath).href)).default
|
||||||
|
const module = await createModule({ locateFile: (path) => resolve(dist, path) })
|
||||||
|
const persistAcceptedPair = async (pair, second) => {
|
||||||
|
const temporaryDirectory = await mkdtemp(join(tmpdir(), 'freecad-ordered-pair-'))
|
||||||
|
try {
|
||||||
|
const stepPath = join(temporaryDirectory, 'pair-result.step')
|
||||||
|
const evidencePath = join(temporaryDirectory, 'pair-naming.json')
|
||||||
|
await Promise.all([writeFile(stepPath, second.response.resultStep), writeFile(evidencePath, JSON.stringify(second.namingEvidence))])
|
||||||
|
const execution = spawnSync(freecad, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), resaveHarnessPath], {
|
||||||
|
cwd: root,
|
||||||
|
encoding: 'utf8',
|
||||||
|
timeout: 180_000,
|
||||||
|
maxBuffer: 40 * 1024 * 1024,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
FREECAD_ORDERED_PAIR: pair,
|
||||||
|
FREECAD_PAIR_STEP_PATH: stepPath,
|
||||||
|
FREECAD_PAIR_EVIDENCE_PATH: evidencePath,
|
||||||
|
FREECAD_PAIR_OUTPUT_DIRECTORY: temporaryDirectory,
|
||||||
|
PYTHONPATH: `${resolve(sysroot, 'usr/lib/python3/dist-packages')}${process.env.PYTHONPATH ? `:${process.env.PYTHONPATH}` : ''}`,
|
||||||
|
LD_LIBRARY_PATH: `${resolve(sysroot, 'usr/lib/x86_64-linux-gnu')}${process.env.LD_LIBRARY_PATH ? `:${process.env.LD_LIBRARY_PATH}` : ''}`,
|
||||||
|
MATPLOTLIBRC: resolve(sysroot, 'usr/share/matplotlib/mpl-data/matplotlibrc'),
|
||||||
|
MPLBACKEND: 'Agg',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const output = `${execution.stdout || ''}\n${execution.stderr || ''}`
|
||||||
|
const marker = 'FREECAD_ORDERED_OPERATION_PAIR_RESAVE_RESULT='
|
||||||
|
const markerIndex = output.indexOf(marker)
|
||||||
|
const payload = markerIndex >= 0 ? output.slice(markerIndex + marker.length).match(/\{.*\}/s)?.[0] : undefined
|
||||||
|
if (execution.error || execution.status !== 0 || !payload) fail(`FreeCAD FCStd replay exited with ${execution.status}: ${execution.error?.message || output.trim()}`)
|
||||||
|
const persistence = JSON.parse(payload)
|
||||||
|
if (persistence.status !== 'pass' || persistence.freecadVersion !== '1.1.1' || persistence.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || !Object.values(persistence.checks).every(Boolean)) fail(`FreeCAD FCStd replay failed: ${JSON.stringify(persistence)}`)
|
||||||
|
return persistence
|
||||||
|
} finally {
|
||||||
|
await rm(temporaryDirectory, { recursive: true, force: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const classifyFusePair = async (toOperation, pairIndex) => {
|
||||||
|
const pair = `fuse->${toOperation}`
|
||||||
|
const pairId = pair.replace('->', '-')
|
||||||
|
const first = captureStage(module, {
|
||||||
|
operation: 'fuse', toolSize: 5, toolOffset: 8,
|
||||||
|
stage: { stageId: `pair:${pairId}:first`, ordinal: 0, objectId: `pair:${pairId}:base`, objectTag: 1001 + pairIndex * 100, resultObjectId: `pair:${pairId}:first`, resultObjectTag: 1101 + pairIndex * 100 },
|
||||||
|
})
|
||||||
|
const spec = operationSpecs[toOperation]
|
||||||
|
const secondDefinition = {
|
||||||
|
operation: toOperation,
|
||||||
|
objectStep: first.response.resultStep,
|
||||||
|
...spec.nominal,
|
||||||
|
stage: { stageId: `pair:${pairId}:second`, ordinal: 1, objectId: `pair:${pairId}:first`, objectTag: 1101 + pairIndex * 100, resultObjectId: `pair:${pairId}:second`, resultObjectTag: 1201 + pairIndex * 100, namingEvidence: first.namingEvidence },
|
||||||
|
}
|
||||||
|
const second = captureStage(module, secondDefinition)
|
||||||
|
const mutated = captureStage(module, { ...secondDefinition, ...spec.edited })
|
||||||
|
const restored = captureStage(module, secondDefinition)
|
||||||
|
try {
|
||||||
|
const mutationChanged = JSON.stringify(second.report.summary) !== JSON.stringify(mutated.report.summary)
|
||||||
|
const restoredExactly = JSON.stringify(second.report.summary) === JSON.stringify(restored.report.summary) && second.report.historySha256 === restored.report.historySha256 && second.report.namingSemanticSha256 === restored.report.namingSemanticSha256
|
||||||
|
if (!mutationChanged || !restoredExactly) fail(`${pair} mutation did not change and restore native geometry/history.`)
|
||||||
|
const persistence = await persistAcceptedPair(pair, second)
|
||||||
|
return {
|
||||||
|
taskId: `TSN-PAIR-fuse-${toOperation}`,
|
||||||
|
pair,
|
||||||
|
classification: 'accepted',
|
||||||
|
reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass',
|
||||||
|
nativeDecision: 'accepted',
|
||||||
|
first: first.report,
|
||||||
|
second: second.report,
|
||||||
|
mutation: { scope: 'second-operation-only', parameter: spec.parameter, trajectory: [spec.beforeValue, spec.editedValue, spec.beforeValue], beforeValue: spec.beforeValue, editedValue: spec.editedValue, restoredValue: spec.beforeValue, changed: mutationChanged, restoredExactly, editedEvidence: mutated.report, restoredEvidence: restored.report },
|
||||||
|
naming: { upstreamEvidenceRestored: Boolean(secondDefinition.stage.namingEvidence), downstreamEvidence: Boolean(second.namingEvidence), jsonRoundtripStable: JSON.stringify(JSON.parse(JSON.stringify(second.namingEvidence))) === JSON.stringify(second.namingEvidence) },
|
||||||
|
persistence,
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
for (const capture of [first, second, mutated, restored]) capture.response.result?.delete?.()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const classifications = []
|
||||||
|
for (const [index, operation] of ['fuse', 'cut', 'common', 'rotate'].entries()) classifications.push(await classifyFusePair(operation, index))
|
||||||
|
|
||||||
|
const [artifacts, executorHarness, matrixHarness, resaveHarness] = await Promise.all([
|
||||||
|
Promise.all(artifactNames.map(async (name) => {
|
||||||
|
const path = resolve(dist, name)
|
||||||
|
const [content, bytes] = await Promise.all([readFile(path), stat(path).then(({ size }) => size)])
|
||||||
|
return { name, bytes, sha256: sha256(content) }
|
||||||
|
})),
|
||||||
|
readFile(executorPath),
|
||||||
|
readFile(resolve(root, 'scripts/freecad-naming-production-matrix.mjs')),
|
||||||
|
readFile(resaveHarnessPath),
|
||||||
|
])
|
||||||
|
const report = {
|
||||||
|
schemaVersion: 1,
|
||||||
|
baseline: { freecadVersion: '1.1.1', commit: '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d', occtVersion: module.occtVersion() },
|
||||||
|
generatedBy: './npmw run probe:freecad-ordered-operation-pairs',
|
||||||
|
checkedBy: './npmw run check:freecad-ordered-operation-pairs',
|
||||||
|
nativeProbe: {
|
||||||
|
executor: { path: 'scripts/run-freecad-ordered-operation-pair-classification.mjs', bytes: executorHarness.length, sha256: sha256(executorHarness) },
|
||||||
|
matrix: { path: 'scripts/freecad-naming-production-matrix.mjs', bytes: matrixHarness.length, sha256: sha256(matrixHarness) },
|
||||||
|
resave: { path: 'scripts/freecad-ordered-operation-pair-resave.py', bytes: resaveHarness.length, sha256: sha256(resaveHarness) },
|
||||||
|
artifacts,
|
||||||
|
},
|
||||||
|
classifications,
|
||||||
|
summary: { registeredOperations: 19, orderedPairs: 361, classifiedPairs: classifications.length, accepted: classifications.filter(({ classification }) => classification === 'accepted').length, rejected: classifications.filter(({ classification }) => classification === 'rejected').length, unknown: 361 - classifications.length },
|
||||||
|
}
|
||||||
|
await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`)
|
||||||
|
console.log(JSON.stringify({ status: 'freecad-ordered-operation-pair-classification-generated', pairs: classifications.map(({ pair, classification }) => ({ pair, classification })), nativeBuilderRuns: classifications.length * 4, fcstdPhases: classifications.length * 3, output: 'config/freecad-ordered-operation-pair-classification.json' }, null, 2))
|
||||||
105
scripts/run-freecad-production-drift-classification.mjs
Normal file
105
scripts/run-freecad-production-drift-classification.mjs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import { spawnSync } from 'node:child_process'
|
||||||
|
import { createHash } from 'node:crypto'
|
||||||
|
import { existsSync } from 'node:fs'
|
||||||
|
import { readFile, stat, writeFile } from 'node:fs/promises'
|
||||||
|
import { resolve } from 'node:path'
|
||||||
|
import { buildProductionDriftSnapshot, productionDriftDecisions, same, validateProductionDriftSnapshot } from './freecad-production-drift-classification.mjs'
|
||||||
|
|
||||||
|
const root = resolve(new URL('..', import.meta.url).pathname)
|
||||||
|
const executable = process.env.FREECAD_CMD || resolve(root, '.cache/freecad/install-desktop/bin/FreeCADCmd')
|
||||||
|
const sysroot = resolve(root, '.cache/freecad/sysroot')
|
||||||
|
const harnessPath = resolve(root, 'scripts/freecad-tsn-stage-correlation-oracle.py')
|
||||||
|
const oraclePath = resolve(root, 'config/freecad-tsn-stage-correlation-oracle.json')
|
||||||
|
const outputPath = resolve(root, 'config/freecad-production-drift-classification.json')
|
||||||
|
const fail = (message) => { throw new Error(`FreeCAD production drift classification: ${message}`) }
|
||||||
|
const collectDifferences = (reference, replay, path = '$', differences = []) => {
|
||||||
|
if (same(reference, replay)) return differences
|
||||||
|
if (Array.isArray(reference) && Array.isArray(replay)) {
|
||||||
|
for (let index = 0; index < Math.max(reference.length, replay.length); index += 1) collectDifferences(reference[index], replay[index], `${path}[${index}]`, differences)
|
||||||
|
return differences
|
||||||
|
}
|
||||||
|
if (reference && replay && typeof reference === 'object' && typeof replay === 'object') {
|
||||||
|
for (const key of new Set([...Object.keys(reference), ...Object.keys(replay)])) collectDifferences(reference[key], replay[key], `${path}.${key}`, differences)
|
||||||
|
return differences
|
||||||
|
}
|
||||||
|
differences.push({ path, reference, replay })
|
||||||
|
return differences
|
||||||
|
}
|
||||||
|
if (!existsSync(executable)) fail(`native executable is missing: ${executable}`)
|
||||||
|
|
||||||
|
const [reference, harnessContent, harnessBytes] = await Promise.all([
|
||||||
|
readFile(oraclePath, 'utf8').then(JSON.parse),
|
||||||
|
readFile(harnessPath),
|
||||||
|
stat(harnessPath).then(({ size }) => size),
|
||||||
|
])
|
||||||
|
const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), harnessPath], {
|
||||||
|
cwd: root,
|
||||||
|
encoding: 'utf8',
|
||||||
|
timeout: 180_000,
|
||||||
|
maxBuffer: 80 * 1024 * 1024,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
PYTHONPATH: `${resolve(sysroot, 'usr/lib/python3/dist-packages')}${process.env.PYTHONPATH ? `:${process.env.PYTHONPATH}` : ''}`,
|
||||||
|
LD_LIBRARY_PATH: `${resolve(sysroot, 'usr/lib/x86_64-linux-gnu')}${process.env.LD_LIBRARY_PATH ? `:${process.env.LD_LIBRARY_PATH}` : ''}`,
|
||||||
|
MATPLOTLIBRC: resolve(sysroot, 'usr/share/matplotlib/mpl-data/matplotlibrc'),
|
||||||
|
MPLBACKEND: 'Agg',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const output = `${execution.stdout || ''}\n${execution.stderr || ''}`
|
||||||
|
const marker = 'FREECAD_TSN_STAGE_CORRELATION_RESULT='
|
||||||
|
const markerIndex = output.indexOf(marker)
|
||||||
|
const payload = markerIndex >= 0 ? output.slice(markerIndex + marker.length).match(/\{.*\}/s)?.[0] : undefined
|
||||||
|
if (execution.error || execution.status !== 0 || !payload) fail(`native replay exited with ${execution.status}: ${execution.error?.message || output.trim()}`)
|
||||||
|
const replay = JSON.parse(payload)
|
||||||
|
if (reference.freecadVersion !== '1.1.1' || reference.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || replay.freecadVersion !== reference.freecadVersion || replay.gitCommit !== reference.gitCommit || replay.status !== 'pass') fail('native baseline or replay status is invalid.')
|
||||||
|
|
||||||
|
const classifications = productionDriftDecisions.map((decision) => {
|
||||||
|
const referenceSnapshot = buildProductionDriftSnapshot(reference, decision.operation)
|
||||||
|
const replaySnapshot = buildProductionDriftSnapshot(replay, decision.operation)
|
||||||
|
validateProductionDriftSnapshot(referenceSnapshot)
|
||||||
|
validateProductionDriftSnapshot(replaySnapshot)
|
||||||
|
if (!same(referenceSnapshot, replaySnapshot)) fail(`${decision.operation} fingerprints differ between the locked reference and independent native replay: ${JSON.stringify(collectDifferences(referenceSnapshot, replaySnapshot))}`)
|
||||||
|
return {
|
||||||
|
...decision,
|
||||||
|
reference: referenceSnapshot,
|
||||||
|
replay: replaySnapshot,
|
||||||
|
replayStable: true,
|
||||||
|
implementationDefect: decision.classification === 'implementation_defect',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const driftCases = reference.driftReplays.length
|
||||||
|
const countClassification = (classification) => classifications.filter((entry) => entry.classification === classification).length
|
||||||
|
const report = {
|
||||||
|
schemaVersion: 1,
|
||||||
|
baseline: {
|
||||||
|
freecadVersion: reference.freecadVersion,
|
||||||
|
commit: reference.gitCommit,
|
||||||
|
oracleId: reference.baselineId,
|
||||||
|
},
|
||||||
|
generatedBy: './npmw run probe:freecad-production-drift-classification',
|
||||||
|
checkedBy: './npmw run check:freecad-production-drift-classification',
|
||||||
|
nativeProbe: {
|
||||||
|
path: 'scripts/freecad-tsn-stage-correlation-oracle.py',
|
||||||
|
bytes: harnessBytes,
|
||||||
|
sha256: createHash('sha256').update(harnessContent).digest('hex'),
|
||||||
|
independentRuns: 2,
|
||||||
|
},
|
||||||
|
classifications,
|
||||||
|
summary: {
|
||||||
|
driftCases,
|
||||||
|
classifiedCases: classifications.length,
|
||||||
|
classifiedStages: classifications.reduce((sum, entry) => sum + entry.reference.driftOrdinals.length, 0),
|
||||||
|
stableSemantics: countClassification('stable_semantics'),
|
||||||
|
allowedEvolution: countClassification('allowed_evolution'),
|
||||||
|
implementationDefects: countClassification('implementation_defect'),
|
||||||
|
unknown: driftCases - classifications.length,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`)
|
||||||
|
console.log(JSON.stringify({
|
||||||
|
status: 'freecad-production-drift-classification-generated',
|
||||||
|
cases: report.classifications.map(({ taskId, operation, classification, reference: snapshot }) => ({ taskId, operation, classification, driftOrdinals: snapshot.driftOrdinals })),
|
||||||
|
independentRuns: report.nativeProbe.independentRuns,
|
||||||
|
output: 'config/freecad-production-drift-classification.json',
|
||||||
|
}, null, 2))
|
||||||
@@ -13,6 +13,19 @@ const oraclePath = resolve(root, 'config/freecad-composite-history-elementmap-or
|
|||||||
const resavePath = resolve(root, 'config/freecad-composite-history-resave-verification.json')
|
const resavePath = resolve(root, 'config/freecad-composite-history-resave-verification.json')
|
||||||
const outputPath = resolve(root, 'config/freecad-recovered-naming-classification.json')
|
const outputPath = resolve(root, 'config/freecad-recovered-naming-classification.json')
|
||||||
const fail = (message) => { throw new Error(`FreeCAD recovered naming classification: ${message}`) }
|
const fail = (message) => { throw new Error(`FreeCAD recovered naming classification: ${message}`) }
|
||||||
|
const collectDifferences = (reference, replay, path = '$', differences = []) => {
|
||||||
|
if (same(reference, replay)) return differences
|
||||||
|
if (Array.isArray(reference) && Array.isArray(replay)) {
|
||||||
|
for (let index = 0; index < Math.max(reference.length, replay.length); index += 1) collectDifferences(reference[index], replay[index], `${path}[${index}]`, differences)
|
||||||
|
return differences
|
||||||
|
}
|
||||||
|
if (reference && replay && typeof reference === 'object' && typeof replay === 'object') {
|
||||||
|
for (const key of new Set([...Object.keys(reference), ...Object.keys(replay)])) collectDifferences(reference[key], replay[key], `${path}.${key}`, differences)
|
||||||
|
return differences
|
||||||
|
}
|
||||||
|
differences.push({ path, reference, replay })
|
||||||
|
return differences
|
||||||
|
}
|
||||||
if (!existsSync(executable)) fail(`native executable is missing: ${executable}`)
|
if (!existsSync(executable)) fail(`native executable is missing: ${executable}`)
|
||||||
|
|
||||||
const [reference, referenceResave, harnessContent, harnessBytes] = await Promise.all([
|
const [reference, referenceResave, harnessContent, harnessBytes] = await Promise.all([
|
||||||
@@ -56,7 +69,7 @@ const classifications = recoveredNamingDecisions.map((decision) => {
|
|||||||
})
|
})
|
||||||
validateRecoveredNamingSnapshot(referenceSnapshot)
|
validateRecoveredNamingSnapshot(referenceSnapshot)
|
||||||
validateRecoveredNamingSnapshot(replaySnapshot)
|
validateRecoveredNamingSnapshot(replaySnapshot)
|
||||||
if (!same(referenceSnapshot, replaySnapshot)) fail(`${decision.caseId} fingerprints differ between the locked reference and independent native replay.`)
|
if (!same(referenceSnapshot, replaySnapshot)) fail(`${decision.caseId} fingerprints differ between the locked reference and independent native replay: ${JSON.stringify(collectDifferences(referenceSnapshot, replaySnapshot))}`)
|
||||||
return {
|
return {
|
||||||
...decision,
|
...decision,
|
||||||
reference: referenceSnapshot,
|
reference: referenceSnapshot,
|
||||||
|
|||||||
Reference in New Issue
Block a user