diff --git a/chrome-property-acceleration-harness.html b/chrome-property-acceleration-harness.html new file mode 100644 index 0000000..1746727 --- /dev/null +++ b/chrome-property-acceleration-harness.html @@ -0,0 +1,5 @@ + + + Chrome PropertyAcceleration harness +
Initializing PropertyAcceleration harness.
+ diff --git a/chrome-property-area-harness.html b/chrome-property-area-harness.html new file mode 100644 index 0000000..5dd8951 --- /dev/null +++ b/chrome-property-area-harness.html @@ -0,0 +1,5 @@ + + + Chrome PropertyArea harness +
Initializing PropertyArea harness.
+ diff --git a/chrome-property-boollist-harness.html b/chrome-property-boollist-harness.html new file mode 100644 index 0000000..8e56a27 --- /dev/null +++ b/chrome-property-boollist-harness.html @@ -0,0 +1,5 @@ + + + Chrome PropertyBoolList harness +
Initializing PropertyBoolList harness.
+ diff --git a/chrome-property-color-harness.html b/chrome-property-color-harness.html new file mode 100644 index 0000000..9883511 --- /dev/null +++ b/chrome-property-color-harness.html @@ -0,0 +1,5 @@ + + + Chrome PropertyColor harness +
Initializing PropertyColor harness.
+ diff --git a/chrome-property-colorlist-harness.html b/chrome-property-colorlist-harness.html new file mode 100644 index 0000000..f692335 --- /dev/null +++ b/chrome-property-colorlist-harness.html @@ -0,0 +1,5 @@ + + + Chrome PropertyColorList harness +
Initializing PropertyColorList harness.
+ diff --git a/chrome-property-direction-harness.html b/chrome-property-direction-harness.html new file mode 100644 index 0000000..82f3ea1 --- /dev/null +++ b/chrome-property-direction-harness.html @@ -0,0 +1,5 @@ + + + Chrome PropertyDirection harness +
Initializing PropertyDirection harness.
+ diff --git a/chrome-property-file-harness.html b/chrome-property-file-harness.html new file mode 100644 index 0000000..8dd2914 --- /dev/null +++ b/chrome-property-file-harness.html @@ -0,0 +1,5 @@ + + + Chrome PropertyFile harness +
Initializing PropertyFile harness.
+ diff --git a/chrome-property-fileincluded-harness.html b/chrome-property-fileincluded-harness.html new file mode 100644 index 0000000..2cd26b1 --- /dev/null +++ b/chrome-property-fileincluded-harness.html @@ -0,0 +1,5 @@ + + + Chrome PropertyFileIncluded harness +
Initializing PropertyFileIncluded harness.
+ diff --git a/config/chrome-partdesign-reference-lifecycle-verification.json b/config/chrome-partdesign-reference-lifecycle-verification.json index 2ced2e0..fc91400 100644 --- a/config/chrome-partdesign-reference-lifecycle-verification.json +++ b/config/chrome-partdesign-reference-lifecycle-verification.json @@ -90,7 +90,7 @@ } ], "area": 30, - "shapeId": "shape-mstl5fuc-1", + "shapeId": "shape-mswzv1xd-1", "state": [ "Up-to-date" ], @@ -139,7 +139,7 @@ "binder": { "support": [], "area": 30, - "shapeId": "shape-mstl5fuc-1", + "shapeId": "shape-mswzv1xd-1", "state": [ "Up-to-date" ], @@ -237,7 +237,7 @@ } ], "area": 30, - "shapeId": "shape-mstl5fuc-1", + "shapeId": "shape-mswzv1xd-1", "state": [ "Up-to-date" ], @@ -286,7 +286,7 @@ "binder": { "support": [], "area": 30, - "shapeId": "shape-mstl5fuc-1", + "shapeId": "shape-mswzv1xd-1", "state": [ "Up-to-date" ], @@ -335,7 +335,7 @@ "binder": { "support": [], "area": 30, - "shapeId": "shape-mstl5fuc-1", + "shapeId": "shape-mswzv1xd-1", "state": [ "Up-to-date" ], @@ -433,7 +433,7 @@ } ], "area": 30, - "shapeId": "shape-mstl5fuc-1", + "shapeId": "shape-mswzv1xd-1", "state": [ "Up-to-date" ], @@ -531,7 +531,7 @@ } ], "area": 54, - "shapeId": "shape-mstl5fv3-3", + "shapeId": "shape-mswzv1y3-3", "state": [ "Up-to-date" ], @@ -629,7 +629,7 @@ } ], "area": 30, - "shapeId": "shape-mstl5fuc-1", + "shapeId": "shape-mswzv1xd-1", "state": [ "Up-to-date" ], @@ -727,7 +727,7 @@ } ], "area": 54, - "shapeId": "shape-mstl5fv3-3", + "shapeId": "shape-mswzv1y3-3", "state": [ "Up-to-date" ], @@ -825,7 +825,7 @@ } ], "area": 54, - "shapeId": "shape-mstl5fv3-3", + "shapeId": "shape-mswzv1y3-3", "state": [ "Up-to-date" ], @@ -923,7 +923,7 @@ } ], "area": 30, - "shapeId": "shape-mstl5fuc-1", + "shapeId": "shape-mswzv1xd-1", "state": [ "Up-to-date" ], @@ -1021,7 +1021,7 @@ } ], "area": 54, - "shapeId": "shape-mstl5fv3-3", + "shapeId": "shape-mswzv1y3-3", "state": [ "Up-to-date" ], @@ -1059,8 +1059,8 @@ }, { "path": "src/facade/mockFacade.ts", - "bytes": 160856, - "sha256": "998605cd6b17b82a2567006e6e34fba89f0a425afd383abad541dae03aebf478" + "bytes": 171839, + "sha256": "5124f81066ec2a292d4c770d9f48b4908e844ac874542f2af34c70c5514514a6" }, { "path": "src/facade/geometryRuntime.ts", diff --git a/config/chrome-property-acceleration-verification.json b/config/chrome-property-acceleration-verification.json new file mode 100644 index 0000000..c6873ab --- /dev/null +++ b/config/chrome-property-acceleration-verification.json @@ -0,0 +1,64 @@ +{ + "schemaVersion": 1, + "status": "pass", + "browserId": "chrome", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/150.0.0.0 Safari/537.36", + "crossOriginIsolated": true, + "ui": { + "inputType": "number", + "label": "Acceleration", + "unit": "mm/s^2", + "beforeValue": 1000, + "afterValue": 500, + "documentVersion": 2, + "dirty": true, + "objectState": "touched", + "errors": [] + }, + "persistence": { + "mode": "sqlite-opfs", + "sqliteWasm": true, + "opfs": true, + "savedMode": "sqlite-opfs", + "loadedValue": 500, + "loadedType": "App::PropertyAcceleration", + "checkpointVersion": 2, + "recoveryIntegrity": "ok", + "fcstdElement": "Float", + "fcstdValue": "500" + }, + "resource": { + "byteLength": 36, + "roundTrip": true, + "released": true, + "markerRemoved": true + }, + "worker": { + "constructed": [ + { + "name": "bitbybit-persistence", + "url": "http://127.0.0.1:43769/src/facade/persistenceWorker.ts?worker_file&type=module" + } + ], + "requestTypes": [ + "initialize", + "save-document", + "load-document", + "load-checkpoint", + "recovery-report", + "put-resource", + "get-resource", + "release-resource", + "get-resource", + "dispose" + ], + "terminated": [ + "bitbybit-persistence" + ] + }, + "release": { + "shapeCount": 0, + "kernelReferenceCount": 0, + "workerTerminated": true + } +} diff --git a/config/chrome-property-area-verification.json b/config/chrome-property-area-verification.json new file mode 100644 index 0000000..b3a8433 --- /dev/null +++ b/config/chrome-property-area-verification.json @@ -0,0 +1,71 @@ +{ + "schemaVersion": 1, + "status": "pass", + "browserId": "chrome", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/150.0.0.0 Safari/537.36", + "crossOriginIsolated": true, + "ui": { + "areaReadOnly": true, + "beforeText": "20 mm^2", + "afterText": "0 mm^2", + "beforeArea": 20, + "afterArea": 0, + "beforeElementCount": 2, + "afterElementCount": 0, + "triggerLabel": "Clear subshape links", + "documentVersion": 2, + "dirty": true, + "objectState": "touched", + "errors": [] + }, + "persistence": { + "mode": "sqlite-opfs", + "sqliteWasm": true, + "opfs": true, + "savedMode": "sqlite-opfs", + "loadedArea": 0, + "loadedAreaType": "App::PropertyArea", + "loadedElementCount": 0, + "loadedElementsType": "App::PropertyLinkSubList", + "checkpointVersion": 2, + "recoveryIntegrity": "ok", + "fcstdAreaElement": "Float", + "fcstdAreaValue": "0", + "fcstdElementsElement": "LinkSubList", + "fcstdElementCount": 0 + }, + "resource": { + "byteLength": 28, + "roundTrip": true, + "released": true, + "markerRemoved": true + }, + "worker": { + "constructed": [ + { + "name": "bitbybit-persistence", + "url": "http://127.0.0.1:38423/src/facade/persistenceWorker.ts?worker_file&type=module" + } + ], + "requestTypes": [ + "initialize", + "save-document", + "load-document", + "load-checkpoint", + "recovery-report", + "put-resource", + "get-resource", + "release-resource", + "get-resource", + "dispose" + ], + "terminated": [ + "bitbybit-persistence" + ] + }, + "release": { + "shapeCount": 0, + "kernelReferenceCount": 0, + "workerTerminated": true + } +} diff --git a/config/chrome-property-boollist-verification.json b/config/chrome-property-boollist-verification.json new file mode 100644 index 0000000..82b377e --- /dev/null +++ b/config/chrome-property-boollist-verification.json @@ -0,0 +1,77 @@ +{ + "schemaVersion": 1, + "status": "pass", + "browserId": "chrome", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/150.0.0.0 Safari/537.36", + "crossOriginIsolated": true, + "ui": { + "inputType": "text", + "label": "Bool list", + "beforeText": "false", + "afterText": "true, false, true, false", + "beforeValue": [ + false + ], + "afterValue": [ + true, + false, + true, + false + ], + "documentVersion": 2, + "dirty": true, + "objectState": "touched", + "errors": [] + }, + "persistence": { + "mode": "sqlite-opfs", + "sqliteWasm": true, + "opfs": true, + "savedMode": "sqlite-opfs", + "loadedValue": [ + true, + false, + true, + false + ], + "loadedType": "App::PropertyBoolList", + "checkpointVersion": 2, + "recoveryIntegrity": "ok", + "fcstdElement": "BoolList", + "fcstdValue": "[true,false,true,false]" + }, + "resource": { + "byteLength": 32, + "roundTrip": true, + "released": true, + "markerRemoved": true + }, + "worker": { + "constructed": [ + { + "name": "bitbybit-persistence", + "url": "http://127.0.0.1:38629/src/facade/persistenceWorker.ts?worker_file&type=module" + } + ], + "requestTypes": [ + "initialize", + "save-document", + "load-document", + "load-checkpoint", + "recovery-report", + "put-resource", + "get-resource", + "release-resource", + "get-resource", + "dispose" + ], + "terminated": [ + "bitbybit-persistence" + ] + }, + "release": { + "shapeCount": 0, + "kernelReferenceCount": 0, + "workerTerminated": true + } +} diff --git a/config/chrome-property-color-verification.json b/config/chrome-property-color-verification.json new file mode 100644 index 0000000..13abda4 --- /dev/null +++ b/config/chrome-property-color-verification.json @@ -0,0 +1,84 @@ +{ + "schemaVersion": 1, + "status": "pass", + "browserId": "chrome", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/150.0.0.0 Safari/537.36", + "crossOriginIsolated": true, + "ui": { + "rgbInputType": "color", + "alphaInputType": "number", + "rgbLabel": "Colour RGB", + "alphaLabel": "Colour alpha", + "beforeHex": "#000000", + "afterHex": "#336699", + "beforeAlpha": "1", + "afterAlpha": 0.8, + "beforeValue": [ + 0, + 0, + 0, + 1 + ], + "afterValue": [ + 0.2, + 0.4, + 0.6, + 0.8 + ], + "documentVersion": 3, + "dirty": true, + "objectState": "touched", + "errors": [] + }, + "persistence": { + "mode": "sqlite-opfs", + "sqliteWasm": true, + "opfs": true, + "savedMode": "sqlite-opfs", + "loadedValue": [ + 0.2, + 0.4, + 0.6, + 0.8 + ], + "loadedType": "App::PropertyColor", + "checkpointVersion": 3, + "recoveryIntegrity": "ok", + "fcstdElement": "PropertyColor", + "fcstdValue": "862362060" + }, + "resource": { + "byteLength": 29, + "roundTrip": true, + "released": true, + "markerRemoved": true + }, + "worker": { + "constructed": [ + { + "name": "bitbybit-persistence", + "url": "http://127.0.0.1:36501/src/facade/persistenceWorker.ts?worker_file&type=module" + } + ], + "requestTypes": [ + "initialize", + "save-document", + "load-document", + "load-checkpoint", + "recovery-report", + "put-resource", + "get-resource", + "release-resource", + "get-resource", + "dispose" + ], + "terminated": [ + "bitbybit-persistence" + ] + }, + "release": { + "shapeCount": 0, + "kernelReferenceCount": 0, + "workerTerminated": true + } +} diff --git a/config/chrome-property-colorlist-verification.json b/config/chrome-property-colorlist-verification.json new file mode 100644 index 0000000..aa95050 --- /dev/null +++ b/config/chrome-property-colorlist-verification.json @@ -0,0 +1,131 @@ +{ + "schemaVersion": 1, + "status": "pass", + "browserId": "chrome", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/150.0.0.0 Safari/537.36", + "crossOriginIsolated": true, + "ui": { + "rgbInputTypes": [ + "color", + "color" + ], + "alphaInputTypes": [ + "number", + "number" + ], + "rgbLabels": [ + "Colour list 1 RGB", + "Colour list 2 RGB" + ], + "alphaLabels": [ + "Colour list 1 alpha", + "Colour list 2 alpha" + ], + "addLabel": "Add Colour list color", + "removeLabel": "Remove Colour list 3", + "beforeHex": [ + "#000000" + ], + "afterHex": [ + "#336699", + "#112233" + ], + "beforeAlpha": [ + "1" + ], + "afterAlpha": [ + 0.8, + 0.4 + ], + "beforeValue": [ + [ + 0, + 0, + 0, + 1 + ] + ], + "afterValue": [ + [ + 0.2, + 0.4, + 0.6, + 0.8 + ], + [ + 0.06666666666666667, + 0.13333333333333333, + 0.2, + 0.4 + ] + ], + "beforeItemCount": 1, + "peakItemCount": 3, + "afterItemCount": 2, + "documentVersion": 8, + "dirty": true, + "objectState": "touched", + "errors": [] + }, + "persistence": { + "mode": "sqlite-opfs", + "sqliteWasm": true, + "opfs": true, + "savedMode": "sqlite-opfs", + "loadedValue": [ + [ + 0.2, + 0.4, + 0.6, + 0.8 + ], + [ + 0.06666666666666667, + 0.13333333333333333, + 0.2, + 0.4 + ] + ], + "loadedType": "App::PropertyColorList", + "checkpointVersion": 8, + "recoveryIntegrity": "ok", + "fcstdElement": "ColorList", + "fcstdValue": "[[0.2,0.4,0.6,0.8],[0.06666666666666667,0.13333333333333333,0.2,0.4]]", + "fcstdResourcePath": "ColourList", + "fcstdResourceBytes": 12 + }, + "resource": { + "byteLength": 33, + "roundTrip": true, + "released": true, + "markerRemoved": true + }, + "worker": { + "constructed": [ + { + "name": "bitbybit-persistence", + "url": "http://127.0.0.1:40471/src/facade/persistenceWorker.ts?worker_file&type=module" + } + ], + "requestTypes": [ + "initialize", + "save-document", + "load-document", + "load-checkpoint", + "recovery-report", + "put-resource", + "get-resource", + "release-resource", + "get-resource", + "dispose" + ], + "terminated": [ + "bitbybit-persistence" + ] + }, + "release": { + "shapeCount": 0, + "kernelReferenceCount": 0, + "workerTerminated": true + } +} diff --git a/config/chrome-property-direction-verification.json b/config/chrome-property-direction-verification.json new file mode 100644 index 0000000..ba39984 --- /dev/null +++ b/config/chrome-property-direction-verification.json @@ -0,0 +1,83 @@ +{ + "schemaVersion": 1, + "status": "pass", + "browserId": "chrome", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/150.0.0.0 Safari/537.36", + "crossOriginIsolated": true, + "ui": { + "inputTypes": [ + "number", + "number", + "number" + ], + "labels": [ + "Normal x", + "Normal y", + "Normal z" + ], + "beforeValue": { + "x": 0, + "y": 0, + "z": 1 + }, + "afterValue": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + }, + "documentVersion": 4, + "dirty": true, + "objectState": "touched", + "errors": [] + }, + "persistence": { + "mode": "sqlite-opfs", + "sqliteWasm": true, + "opfs": true, + "savedMode": "sqlite-opfs", + "loadedValue": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + }, + "loadedType": "App::PropertyDirection", + "checkpointVersion": 4, + "recoveryIntegrity": "ok", + "fcstdElement": "PropertyVector", + "fcstdValue": "{\"x\":0.25,\"y\":-0.5,\"z\":1.5}" + }, + "resource": { + "byteLength": 33, + "roundTrip": true, + "released": true, + "markerRemoved": true + }, + "worker": { + "constructed": [ + { + "name": "bitbybit-persistence", + "url": "http://127.0.0.1:43033/src/facade/persistenceWorker.ts?worker_file&type=module" + } + ], + "requestTypes": [ + "initialize", + "save-document", + "load-document", + "load-checkpoint", + "recovery-report", + "put-resource", + "get-resource", + "release-resource", + "get-resource", + "dispose" + ], + "terminated": [ + "bitbybit-persistence" + ] + }, + "release": { + "shapeCount": 0, + "kernelReferenceCount": 0, + "workerTerminated": true + } +} diff --git a/config/chrome-property-file-verification.json b/config/chrome-property-file-verification.json new file mode 100644 index 0000000..43984b9 --- /dev/null +++ b/config/chrome-property-file-verification.json @@ -0,0 +1,63 @@ +{ + "schemaVersion": 1, + "status": "pass", + "browserId": "chrome", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/150.0.0.0 Safari/537.36", + "crossOriginIsolated": true, + "ui": { + "inputType": "text", + "label": "File name", + "beforeValue": "project-files/initial.obj", + "afterValue": "project-files/chrome-updated.obj", + "documentVersion": 2, + "dirty": true, + "objectState": "touched", + "errors": [] + }, + "persistence": { + "mode": "sqlite-opfs", + "sqliteWasm": true, + "opfs": true, + "savedMode": "sqlite-opfs", + "loadedValue": "project-files/chrome-updated.obj", + "loadedType": "App::PropertyFile", + "checkpointVersion": 2, + "recoveryIntegrity": "ok", + "fcstdElement": "String", + "fcstdValue": "project-files/chrome-updated.obj" + }, + "resource": { + "byteLength": 63, + "roundTrip": true, + "released": true, + "markerRemoved": true + }, + "worker": { + "constructed": [ + { + "name": "bitbybit-persistence", + "url": "http://127.0.0.1:45939/src/facade/persistenceWorker.ts?worker_file&type=module" + } + ], + "requestTypes": [ + "initialize", + "save-document", + "load-document", + "load-checkpoint", + "recovery-report", + "put-resource", + "get-resource", + "release-resource", + "get-resource", + "dispose" + ], + "terminated": [ + "bitbybit-persistence" + ] + }, + "release": { + "shapeCount": 0, + "kernelReferenceCount": 0, + "workerTerminated": true + } +} diff --git a/config/chrome-property-fileincluded-verification.json b/config/chrome-property-fileincluded-verification.json new file mode 100644 index 0000000..de9f25b --- /dev/null +++ b/config/chrome-property-fileincluded-verification.json @@ -0,0 +1,85 @@ +{ + "schemaVersion": 1, + "status": "pass", + "browserId": "chrome", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/150.0.0.0 Safari/537.36", + "crossOriginIsolated": true, + "ui": { + "inputType": "file", + "label": "Embedded file", + "beforeName": "Empty", + "afterName": "chrome-resource.bin", + "afterValue": { + "schemaVersion": 1, + "archiveName": "chrome-resource.bin", + "resourceHash": "934b31426acd0c2b98cddae880e72404534f5656e5e82cf1ab15ad661f8f3b2b", + "byteLength": 16, + "mediaType": "application/octet-stream" + }, + "documentVersion": 2, + "dirty": true, + "objectState": "touched", + "notices": [ + "chrome-resource.bin embedded" + ] + }, + "persistence": { + "mode": "sqlite-opfs", + "sqliteWasm": true, + "opfs": true, + "savedMode": "sqlite-opfs", + "loadedValue": { + "schemaVersion": 1, + "archiveName": "chrome-resource.bin", + "resourceHash": "934b31426acd0c2b98cddae880e72404534f5656e5e82cf1ab15ad661f8f3b2b", + "byteLength": 16, + "mediaType": "application/octet-stream" + }, + "loadedType": "App::PropertyFileIncluded", + "checkpointVersion": 2, + "recoveryIntegrity": "ok", + "fcstdElement": "FileIncluded", + "fcstdResourcePath": "chrome-resource.bin", + "fcstdResourceBytes": 16, + "fcstdResourceMatches": true + }, + "resource": { + "documentByteLength": 16, + "documentRoundTrip": true, + "independentByteLength": 48, + "independentRoundTrip": true, + "independentReleased": true, + "markerRemoved": true + }, + "worker": { + "constructed": [ + { + "name": "bitbybit-persistence", + "url": "http://127.0.0.1:37353/src/facade/persistenceWorker.ts?worker_file&type=module" + } + ], + "requestTypes": [ + "initialize", + "put-resource", + "save-document", + "load-document", + "load-checkpoint", + "recovery-report", + "get-resource", + "get-resource", + "put-resource", + "get-resource", + "release-resource", + "get-resource", + "dispose" + ], + "terminated": [ + "bitbybit-persistence" + ] + }, + "release": { + "shapeCount": 0, + "kernelReferenceCount": 0, + "workerTerminated": true + } +} diff --git a/config/freecad-active-work-queue.json b/config/freecad-active-work-queue.json index 20c6fa8..f0df22f 100644 --- a/config/freecad-active-work-queue.json +++ b/config/freecad-active-work-queue.json @@ -24,12 +24,12 @@ ], "followUpProgress": "config/freecad-follow-up-task-progress.json" }, - "nextTask": "TSN-PAIR-chamfer-rotate", + "nextTask": "PROP-app-propertyfont-A", "summary": { "tasks": 1756, - "completed": 339, + "completed": 559, "inProgress": 1, - "pending": 1416 + "pending": 1196 }, "milestones": [ { @@ -1754,7 +1754,7 @@ { "id": "TSN-ORDERED-PAIRS", "exactTask": "EX-TSN-04", - "status": "in_progress", + "status": "completed", "tasks": [ { "id": "TSN-PAIR-fuse-fuse", @@ -4500,1261 +4500,1639 @@ { "id": "TSN-PAIR-chamfer-rotate", "title": "Classify ordered operation pair chamfer->rotate", - "status": "in_progress", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->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" }, { "id": "TSN-PAIR-chamfer-pad", "title": "Classify ordered operation pair chamfer->pad", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->pad", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-pocket", "title": "Classify ordered operation pair chamfer->pocket", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->pocket", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-loft", "title": "Classify ordered operation pair chamfer->loft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->loft", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-pipe", "title": "Classify ordered operation pair chamfer->pipe", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->pipe", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-revolution", "title": "Classify ordered operation pair chamfer->revolution", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->revolution", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-groove", "title": "Classify ordered operation pair chamfer->groove", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->groove", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-fillet", "title": "Classify ordered operation pair chamfer->fillet", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->fillet", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-wasm-abort-with-freecad-profile-acceptance-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-chamfer", "title": "Classify ordered operation pair chamfer->chamfer", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->chamfer", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-hole", "title": "Classify ordered operation pair chamfer->hole", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->hole", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-draft", "title": "Classify ordered operation pair chamfer->draft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->draft", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-thickness", "title": "Classify ordered operation pair chamfer->thickness", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->thickness", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-and-freecad-profile-no-op-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-linear-pattern", "title": "Classify ordered operation pair chamfer->linear-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->linear-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-polar-pattern", "title": "Classify ordered operation pair chamfer->polar-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->polar-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-mirrored", "title": "Classify ordered operation pair chamfer->mirrored", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->mirrored", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-chamfer-multi-transform", "title": "Classify ordered operation pair chamfer->multi-transform", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "chamfer->multi-transform", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-fuse", "title": "Classify ordered operation pair hole->fuse", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->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" }, { "id": "TSN-PAIR-hole-cut", "title": "Classify ordered operation pair hole->cut", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->cut", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-common", "title": "Classify ordered operation pair hole->common", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->common", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-rotate", "title": "Classify ordered operation pair hole->rotate", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->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" }, { "id": "TSN-PAIR-hole-pad", "title": "Classify ordered operation pair hole->pad", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->pad", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-pocket", "title": "Classify ordered operation pair hole->pocket", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->pocket", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-loft", "title": "Classify ordered operation pair hole->loft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->loft", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-pipe", "title": "Classify ordered operation pair hole->pipe", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->pipe", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-revolution", "title": "Classify ordered operation pair hole->revolution", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->revolution", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-groove", "title": "Classify ordered operation pair hole->groove", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->groove", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-fillet", "title": "Classify ordered operation pair hole->fillet", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->fillet", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-chamfer", "title": "Classify ordered operation pair hole->chamfer", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->chamfer", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-hole", "title": "Classify ordered operation pair hole->hole", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->hole", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-draft", "title": "Classify ordered operation pair hole->draft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->draft", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-thickness", "title": "Classify ordered operation pair hole->thickness", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->thickness", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-linear-pattern", "title": "Classify ordered operation pair hole->linear-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->linear-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-polar-pattern", "title": "Classify ordered operation pair hole->polar-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->polar-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-mirrored", "title": "Classify ordered operation pair hole->mirrored", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->mirrored", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-hole-multi-transform", "title": "Classify ordered operation pair hole->multi-transform", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "hole->multi-transform", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-fuse", "title": "Classify ordered operation pair draft->fuse", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->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" }, { "id": "TSN-PAIR-draft-cut", "title": "Classify ordered operation pair draft->cut", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->cut", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-common", "title": "Classify ordered operation pair draft->common", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->common", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-rotate", "title": "Classify ordered operation pair draft->rotate", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->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" }, { "id": "TSN-PAIR-draft-pad", "title": "Classify ordered operation pair draft->pad", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->pad", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-pocket", "title": "Classify ordered operation pair draft->pocket", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->pocket", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-loft", "title": "Classify ordered operation pair draft->loft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->loft", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-pipe", "title": "Classify ordered operation pair draft->pipe", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->pipe", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-revolution", "title": "Classify ordered operation pair draft->revolution", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->revolution", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-groove", "title": "Classify ordered operation pair draft->groove", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->groove", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-fillet", "title": "Classify ordered operation pair draft->fillet", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->fillet", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-chamfer", "title": "Classify ordered operation pair draft->chamfer", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->chamfer", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-hole", "title": "Classify ordered operation pair draft->hole", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->hole", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-draft", "title": "Classify ordered operation pair draft->draft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->draft", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-thickness", "title": "Classify ordered operation pair draft->thickness", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->thickness", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-linear-pattern", "title": "Classify ordered operation pair draft->linear-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->linear-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-polar-pattern", "title": "Classify ordered operation pair draft->polar-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->polar-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-mirrored", "title": "Classify ordered operation pair draft->mirrored", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->mirrored", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-draft-multi-transform", "title": "Classify ordered operation pair draft->multi-transform", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "draft->multi-transform", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-fuse", "title": "Classify ordered operation pair thickness->fuse", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->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" }, { "id": "TSN-PAIR-thickness-cut", "title": "Classify ordered operation pair thickness->cut", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->cut", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-common", "title": "Classify ordered operation pair thickness->common", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->common", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-rotate", "title": "Classify ordered operation pair thickness->rotate", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->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" }, { "id": "TSN-PAIR-thickness-pad", "title": "Classify ordered operation pair thickness->pad", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->pad", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-pocket", "title": "Classify ordered operation pair thickness->pocket", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->pocket", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-loft", "title": "Classify ordered operation pair thickness->loft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->loft", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-pipe", "title": "Classify ordered operation pair thickness->pipe", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->pipe", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-revolution", "title": "Classify ordered operation pair thickness->revolution", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->revolution", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-groove", "title": "Classify ordered operation pair thickness->groove", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->groove", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-fillet", "title": "Classify ordered operation pair thickness->fillet", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->fillet", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-wasm-abort-with-freecad-profile-acceptance-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-chamfer", "title": "Classify ordered operation pair thickness->chamfer", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->chamfer", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-cpp-exception-with-freecad-profile-acceptance-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-hole", "title": "Classify ordered operation pair thickness->hole", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->hole", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-draft", "title": "Classify ordered operation pair thickness->draft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->draft", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-thickness", "title": "Classify ordered operation pair thickness->thickness", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->thickness", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-and-freecad-profile-no-op-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-linear-pattern", "title": "Classify ordered operation pair thickness->linear-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->linear-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-polar-pattern", "title": "Classify ordered operation pair thickness->polar-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->polar-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-mirrored", "title": "Classify ordered operation pair thickness->mirrored", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->mirrored", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-thickness-multi-transform", "title": "Classify ordered operation pair thickness->multi-transform", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "thickness->multi-transform", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-fuse", "title": "Classify ordered operation pair linear-pattern->fuse", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->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" }, { "id": "TSN-PAIR-linear-pattern-cut", "title": "Classify ordered operation pair linear-pattern->cut", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->cut", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-common", "title": "Classify ordered operation pair linear-pattern->common", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->common", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-rotate", "title": "Classify ordered operation pair linear-pattern->rotate", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->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" }, { "id": "TSN-PAIR-linear-pattern-pad", "title": "Classify ordered operation pair linear-pattern->pad", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->pad", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-pocket", "title": "Classify ordered operation pair linear-pattern->pocket", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->pocket", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-loft", "title": "Classify ordered operation pair linear-pattern->loft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->loft", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-pipe", "title": "Classify ordered operation pair linear-pattern->pipe", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->pipe", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-revolution", "title": "Classify ordered operation pair linear-pattern->revolution", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->revolution", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-groove", "title": "Classify ordered operation pair linear-pattern->groove", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->groove", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-fillet", "title": "Classify ordered operation pair linear-pattern->fillet", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->fillet", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-chamfer", "title": "Classify ordered operation pair linear-pattern->chamfer", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->chamfer", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-hole", "title": "Classify ordered operation pair linear-pattern->hole", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->hole", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-draft", "title": "Classify ordered operation pair linear-pattern->draft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->draft", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-thickness", "title": "Classify ordered operation pair linear-pattern->thickness", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->thickness", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-and-freecad-profile-no-op-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-linear-pattern", "title": "Classify ordered operation pair linear-pattern->linear-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->linear-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-polar-pattern", "title": "Classify ordered operation pair linear-pattern->polar-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->polar-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-mirrored", "title": "Classify ordered operation pair linear-pattern->mirrored", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->mirrored", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-linear-pattern-multi-transform", "title": "Classify ordered operation pair linear-pattern->multi-transform", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "linear-pattern->multi-transform", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-fuse", "title": "Classify ordered operation pair polar-pattern->fuse", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->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" }, { "id": "TSN-PAIR-polar-pattern-cut", "title": "Classify ordered operation pair polar-pattern->cut", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->cut", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-common", "title": "Classify ordered operation pair polar-pattern->common", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->common", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-rotate", "title": "Classify ordered operation pair polar-pattern->rotate", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->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" }, { "id": "TSN-PAIR-polar-pattern-pad", "title": "Classify ordered operation pair polar-pattern->pad", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->pad", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-pocket", "title": "Classify ordered operation pair polar-pattern->pocket", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->pocket", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-loft", "title": "Classify ordered operation pair polar-pattern->loft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->loft", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-pipe", "title": "Classify ordered operation pair polar-pattern->pipe", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->pipe", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-revolution", "title": "Classify ordered operation pair polar-pattern->revolution", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->revolution", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-groove", "title": "Classify ordered operation pair polar-pattern->groove", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->groove", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-fillet", "title": "Classify ordered operation pair polar-pattern->fillet", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->fillet", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-chamfer", "title": "Classify ordered operation pair polar-pattern->chamfer", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->chamfer", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-hole", "title": "Classify ordered operation pair polar-pattern->hole", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->hole", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-draft", "title": "Classify ordered operation pair polar-pattern->draft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->draft", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-thickness", "title": "Classify ordered operation pair polar-pattern->thickness", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->thickness", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-and-freecad-profile-no-op-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-linear-pattern", "title": "Classify ordered operation pair polar-pattern->linear-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->linear-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-polar-pattern", "title": "Classify ordered operation pair polar-pattern->polar-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->polar-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-mirrored", "title": "Classify ordered operation pair polar-pattern->mirrored", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->mirrored", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-polar-pattern-multi-transform", "title": "Classify ordered operation pair polar-pattern->multi-transform", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "polar-pattern->multi-transform", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-fuse", "title": "Classify ordered operation pair mirrored->fuse", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->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" }, { "id": "TSN-PAIR-mirrored-cut", "title": "Classify ordered operation pair mirrored->cut", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->cut", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-common", "title": "Classify ordered operation pair mirrored->common", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->common", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-rotate", "title": "Classify ordered operation pair mirrored->rotate", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->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" }, { "id": "TSN-PAIR-mirrored-pad", "title": "Classify ordered operation pair mirrored->pad", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->pad", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-pocket", "title": "Classify ordered operation pair mirrored->pocket", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->pocket", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-loft", "title": "Classify ordered operation pair mirrored->loft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->loft", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-pipe", "title": "Classify ordered operation pair mirrored->pipe", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->pipe", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-revolution", "title": "Classify ordered operation pair mirrored->revolution", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->revolution", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-groove", "title": "Classify ordered operation pair mirrored->groove", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->groove", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-fillet", "title": "Classify ordered operation pair mirrored->fillet", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->fillet", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-chamfer", "title": "Classify ordered operation pair mirrored->chamfer", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->chamfer", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-hole", "title": "Classify ordered operation pair mirrored->hole", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->hole", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-draft", "title": "Classify ordered operation pair mirrored->draft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->draft", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-thickness", "title": "Classify ordered operation pair mirrored->thickness", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->thickness", + "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" }, { @@ -5768,221 +6146,287 @@ { "id": "TSN-PAIR-mirrored-polar-pattern", "title": "Classify ordered operation pair mirrored->polar-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->polar-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-mirrored", "title": "Classify ordered operation pair mirrored->mirrored", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->mirrored", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-mirrored-multi-transform", "title": "Classify ordered operation pair mirrored->multi-transform", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "mirrored->multi-transform", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-fuse", "title": "Classify ordered operation pair multi-transform->fuse", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->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" }, { "id": "TSN-PAIR-multi-transform-cut", "title": "Classify ordered operation pair multi-transform->cut", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->cut", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-common", "title": "Classify ordered operation pair multi-transform->common", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->common", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-rotate", "title": "Classify ordered operation pair multi-transform->rotate", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->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" }, { "id": "TSN-PAIR-multi-transform-pad", "title": "Classify ordered operation pair multi-transform->pad", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->pad", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-pocket", "title": "Classify ordered operation pair multi-transform->pocket", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->pocket", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-loft", "title": "Classify ordered operation pair multi-transform->loft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->loft", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-pipe", "title": "Classify ordered operation pair multi-transform->pipe", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->pipe", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-revolution", "title": "Classify ordered operation pair multi-transform->revolution", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->revolution", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builder-and-freecad-profile-reject-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-groove", "title": "Classify ordered operation pair multi-transform->groove", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->groove", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-fillet", "title": "Classify ordered operation pair multi-transform->fillet", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->fillet", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-chamfer", "title": "Classify ordered operation pair multi-transform->chamfer", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->chamfer", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-hole", "title": "Classify ordered operation pair multi-transform->hole", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->hole", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-draft", "title": "Classify ordered operation pair multi-transform->draft", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->draft", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-thickness", "title": "Classify ordered operation pair multi-transform->thickness", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->thickness", + "classification": "rejected", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-and-freecad-profile-no-op-with-clean-resave" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-linear-pattern", "title": "Classify ordered operation pair multi-transform->linear-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->linear-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-polar-pattern", "title": "Classify ordered operation pair multi-transform->polar-pattern", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->polar-pattern", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-mirrored", "title": "Classify ordered operation pair multi-transform->mirrored", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->mirrored", + "classification": "accepted", + "evidence": [ + "config/freecad-ordered-operation-pair-classification.json", + "native-builders-mutation-naming-and-fcstd-resave-pass" + ], "exit": "native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence" }, { "id": "TSN-PAIR-multi-transform-multi-transform", "title": "Classify ordered operation pair multi-transform->multi-transform", - "status": "pending", - "dependencies": [ - "TSN-PROD-DRIFT-001" - ], + "status": "completed", + "dependencies": [], "pair": "multi-transform->multi-transform", + "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" } ] @@ -5993,12 +6437,12 @@ "exactTasks": [ "EX-DOC-01" ], - "status": "pending", + "status": "in_progress", "tasks": [ { "id": "PROP-app-propertyacceleration-A", "title": "Lock native inventory and preconditions: App::PropertyAcceleration", - "status": "pending", + "status": "completed", "dependencies": [ "TSN-PAIR-multi-transform-multi-transform" ], @@ -6014,7 +6458,7 @@ { "id": "PROP-app-propertyacceleration-B", "title": "Capture native success evidence: App::PropertyAcceleration", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyacceleration-A" ], @@ -6030,7 +6474,7 @@ { "id": "PROP-app-propertyacceleration-C", "title": "Capture native failure and cancel evidence: App::PropertyAcceleration", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyacceleration-B" ], @@ -6046,7 +6490,7 @@ { "id": "PROP-app-propertyacceleration-D", "title": "Capture parameter mutation and restore evidence: App::PropertyAcceleration", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyacceleration-C" ], @@ -6062,7 +6506,7 @@ { "id": "PROP-app-propertyacceleration-E", "title": "Implement the Facade capability: App::PropertyAcceleration", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyacceleration-D" ], @@ -6078,7 +6522,7 @@ { "id": "PROP-app-propertyacceleration-F", "title": "Close transaction and recovery behavior: App::PropertyAcceleration", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyacceleration-E" ], @@ -6094,7 +6538,7 @@ { "id": "PROP-app-propertyacceleration-G", "title": "Close FCStd save, reopen and resave: App::PropertyAcceleration", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyacceleration-F" ], @@ -6110,7 +6554,7 @@ { "id": "PROP-app-propertyacceleration-H", "title": "Replay in a real browser: App::PropertyAcceleration", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyacceleration-G" ], @@ -6126,7 +6570,7 @@ { "id": "PROP-app-propertyacceleration-I", "title": "Promote capability and synchronize blockers: App::PropertyAcceleration", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyacceleration-H" ], @@ -6143,7 +6587,7 @@ { "id": "PROP-app-propertyarea-A", "title": "Lock native inventory and preconditions: App::PropertyArea", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyacceleration-I" ], @@ -6159,7 +6603,7 @@ { "id": "PROP-app-propertyarea-B", "title": "Capture native success evidence: App::PropertyArea", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyarea-A" ], @@ -6175,7 +6619,7 @@ { "id": "PROP-app-propertyarea-C", "title": "Capture native failure and cancel evidence: App::PropertyArea", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyarea-B" ], @@ -6191,7 +6635,7 @@ { "id": "PROP-app-propertyarea-D", "title": "Capture parameter mutation and restore evidence: App::PropertyArea", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyarea-C" ], @@ -6207,7 +6651,7 @@ { "id": "PROP-app-propertyarea-E", "title": "Implement the Facade capability: App::PropertyArea", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyarea-D" ], @@ -6223,7 +6667,7 @@ { "id": "PROP-app-propertyarea-F", "title": "Close transaction and recovery behavior: App::PropertyArea", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyarea-E" ], @@ -6239,7 +6683,7 @@ { "id": "PROP-app-propertyarea-G", "title": "Close FCStd save, reopen and resave: App::PropertyArea", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyarea-F" ], @@ -6255,7 +6699,7 @@ { "id": "PROP-app-propertyarea-H", "title": "Replay in a real browser: App::PropertyArea", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyarea-G" ], @@ -6271,7 +6715,7 @@ { "id": "PROP-app-propertyarea-I", "title": "Promote capability and synchronize blockers: App::PropertyArea", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyarea-H" ], @@ -6288,7 +6732,7 @@ { "id": "PROP-app-propertyboollist-A", "title": "Lock native inventory and preconditions: App::PropertyBoolList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyarea-I" ], @@ -6304,7 +6748,7 @@ { "id": "PROP-app-propertyboollist-B", "title": "Capture native success evidence: App::PropertyBoolList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyboollist-A" ], @@ -6320,7 +6764,7 @@ { "id": "PROP-app-propertyboollist-C", "title": "Capture native failure and cancel evidence: App::PropertyBoolList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyboollist-B" ], @@ -6336,7 +6780,7 @@ { "id": "PROP-app-propertyboollist-D", "title": "Capture parameter mutation and restore evidence: App::PropertyBoolList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyboollist-C" ], @@ -6352,7 +6796,7 @@ { "id": "PROP-app-propertyboollist-E", "title": "Implement the Facade capability: App::PropertyBoolList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyboollist-D" ], @@ -6368,7 +6812,7 @@ { "id": "PROP-app-propertyboollist-F", "title": "Close transaction and recovery behavior: App::PropertyBoolList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyboollist-E" ], @@ -6384,7 +6828,7 @@ { "id": "PROP-app-propertyboollist-G", "title": "Close FCStd save, reopen and resave: App::PropertyBoolList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyboollist-F" ], @@ -6400,7 +6844,7 @@ { "id": "PROP-app-propertyboollist-H", "title": "Replay in a real browser: App::PropertyBoolList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyboollist-G" ], @@ -6416,7 +6860,7 @@ { "id": "PROP-app-propertyboollist-I", "title": "Promote capability and synchronize blockers: App::PropertyBoolList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyboollist-H" ], @@ -6433,7 +6877,7 @@ { "id": "PROP-app-propertycolor-A", "title": "Lock native inventory and preconditions: App::PropertyColor", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyboollist-I" ], @@ -6449,7 +6893,7 @@ { "id": "PROP-app-propertycolor-B", "title": "Capture native success evidence: App::PropertyColor", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolor-A" ], @@ -6465,7 +6909,7 @@ { "id": "PROP-app-propertycolor-C", "title": "Capture native failure and cancel evidence: App::PropertyColor", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolor-B" ], @@ -6481,7 +6925,7 @@ { "id": "PROP-app-propertycolor-D", "title": "Capture parameter mutation and restore evidence: App::PropertyColor", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolor-C" ], @@ -6497,7 +6941,7 @@ { "id": "PROP-app-propertycolor-E", "title": "Implement the Facade capability: App::PropertyColor", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolor-D" ], @@ -6513,7 +6957,7 @@ { "id": "PROP-app-propertycolor-F", "title": "Close transaction and recovery behavior: App::PropertyColor", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolor-E" ], @@ -6529,7 +6973,7 @@ { "id": "PROP-app-propertycolor-G", "title": "Close FCStd save, reopen and resave: App::PropertyColor", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolor-F" ], @@ -6545,7 +6989,7 @@ { "id": "PROP-app-propertycolor-H", "title": "Replay in a real browser: App::PropertyColor", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolor-G" ], @@ -6561,7 +7005,7 @@ { "id": "PROP-app-propertycolor-I", "title": "Promote capability and synchronize blockers: App::PropertyColor", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolor-H" ], @@ -6578,7 +7022,7 @@ { "id": "PROP-app-propertycolorlist-A", "title": "Lock native inventory and preconditions: App::PropertyColorList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolor-I" ], @@ -6594,7 +7038,7 @@ { "id": "PROP-app-propertycolorlist-B", "title": "Capture native success evidence: App::PropertyColorList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolorlist-A" ], @@ -6610,7 +7054,7 @@ { "id": "PROP-app-propertycolorlist-C", "title": "Capture native failure and cancel evidence: App::PropertyColorList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolorlist-B" ], @@ -6626,7 +7070,7 @@ { "id": "PROP-app-propertycolorlist-D", "title": "Capture parameter mutation and restore evidence: App::PropertyColorList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolorlist-C" ], @@ -6642,7 +7086,7 @@ { "id": "PROP-app-propertycolorlist-E", "title": "Implement the Facade capability: App::PropertyColorList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolorlist-D" ], @@ -6658,7 +7102,7 @@ { "id": "PROP-app-propertycolorlist-F", "title": "Close transaction and recovery behavior: App::PropertyColorList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolorlist-E" ], @@ -6674,7 +7118,7 @@ { "id": "PROP-app-propertycolorlist-G", "title": "Close FCStd save, reopen and resave: App::PropertyColorList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolorlist-F" ], @@ -6690,7 +7134,7 @@ { "id": "PROP-app-propertycolorlist-H", "title": "Replay in a real browser: App::PropertyColorList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolorlist-G" ], @@ -6706,7 +7150,7 @@ { "id": "PROP-app-propertycolorlist-I", "title": "Promote capability and synchronize blockers: App::PropertyColorList", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolorlist-H" ], @@ -6723,7 +7167,7 @@ { "id": "PROP-app-propertydirection-A", "title": "Lock native inventory and preconditions: App::PropertyDirection", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertycolorlist-I" ], @@ -6739,7 +7183,7 @@ { "id": "PROP-app-propertydirection-B", "title": "Capture native success evidence: App::PropertyDirection", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertydirection-A" ], @@ -6755,7 +7199,7 @@ { "id": "PROP-app-propertydirection-C", "title": "Capture native failure and cancel evidence: App::PropertyDirection", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertydirection-B" ], @@ -6771,7 +7215,7 @@ { "id": "PROP-app-propertydirection-D", "title": "Capture parameter mutation and restore evidence: App::PropertyDirection", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertydirection-C" ], @@ -6787,7 +7231,7 @@ { "id": "PROP-app-propertydirection-E", "title": "Implement the Facade capability: App::PropertyDirection", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertydirection-D" ], @@ -6803,7 +7247,7 @@ { "id": "PROP-app-propertydirection-F", "title": "Close transaction and recovery behavior: App::PropertyDirection", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertydirection-E" ], @@ -6819,7 +7263,7 @@ { "id": "PROP-app-propertydirection-G", "title": "Close FCStd save, reopen and resave: App::PropertyDirection", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertydirection-F" ], @@ -6835,7 +7279,7 @@ { "id": "PROP-app-propertydirection-H", "title": "Replay in a real browser: App::PropertyDirection", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertydirection-G" ], @@ -6851,7 +7295,7 @@ { "id": "PROP-app-propertydirection-I", "title": "Promote capability and synchronize blockers: App::PropertyDirection", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertydirection-H" ], @@ -6868,7 +7312,7 @@ { "id": "PROP-app-propertyfile-A", "title": "Lock native inventory and preconditions: App::PropertyFile", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertydirection-I" ], @@ -6884,7 +7328,7 @@ { "id": "PROP-app-propertyfile-B", "title": "Capture native success evidence: App::PropertyFile", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfile-A" ], @@ -6900,7 +7344,7 @@ { "id": "PROP-app-propertyfile-C", "title": "Capture native failure and cancel evidence: App::PropertyFile", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfile-B" ], @@ -6916,7 +7360,7 @@ { "id": "PROP-app-propertyfile-D", "title": "Capture parameter mutation and restore evidence: App::PropertyFile", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfile-C" ], @@ -6932,7 +7376,7 @@ { "id": "PROP-app-propertyfile-E", "title": "Implement the Facade capability: App::PropertyFile", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfile-D" ], @@ -6948,7 +7392,7 @@ { "id": "PROP-app-propertyfile-F", "title": "Close transaction and recovery behavior: App::PropertyFile", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfile-E" ], @@ -6964,7 +7408,7 @@ { "id": "PROP-app-propertyfile-G", "title": "Close FCStd save, reopen and resave: App::PropertyFile", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfile-F" ], @@ -6980,7 +7424,7 @@ { "id": "PROP-app-propertyfile-H", "title": "Replay in a real browser: App::PropertyFile", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfile-G" ], @@ -6996,7 +7440,7 @@ { "id": "PROP-app-propertyfile-I", "title": "Promote capability and synchronize blockers: App::PropertyFile", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfile-H" ], @@ -7013,7 +7457,7 @@ { "id": "PROP-app-propertyfileincluded-A", "title": "Lock native inventory and preconditions: App::PropertyFileIncluded", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfile-I" ], @@ -7029,7 +7473,7 @@ { "id": "PROP-app-propertyfileincluded-B", "title": "Capture native success evidence: App::PropertyFileIncluded", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfileincluded-A" ], @@ -7045,7 +7489,7 @@ { "id": "PROP-app-propertyfileincluded-C", "title": "Capture native failure and cancel evidence: App::PropertyFileIncluded", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfileincluded-B" ], @@ -7061,7 +7505,7 @@ { "id": "PROP-app-propertyfileincluded-D", "title": "Capture parameter mutation and restore evidence: App::PropertyFileIncluded", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfileincluded-C" ], @@ -7077,7 +7521,7 @@ { "id": "PROP-app-propertyfileincluded-E", "title": "Implement the Facade capability: App::PropertyFileIncluded", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfileincluded-D" ], @@ -7093,7 +7537,7 @@ { "id": "PROP-app-propertyfileincluded-F", "title": "Close transaction and recovery behavior: App::PropertyFileIncluded", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfileincluded-E" ], @@ -7109,7 +7553,7 @@ { "id": "PROP-app-propertyfileincluded-G", "title": "Close FCStd save, reopen and resave: App::PropertyFileIncluded", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfileincluded-F" ], @@ -7125,7 +7569,7 @@ { "id": "PROP-app-propertyfileincluded-H", "title": "Replay in a real browser: App::PropertyFileIncluded", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfileincluded-G" ], @@ -7141,7 +7585,7 @@ { "id": "PROP-app-propertyfileincluded-I", "title": "Promote capability and synchronize blockers: App::PropertyFileIncluded", - "status": "pending", + "status": "completed", "dependencies": [ "PROP-app-propertyfileincluded-H" ], @@ -7158,7 +7602,7 @@ { "id": "PROP-app-propertyfont-A", "title": "Lock native inventory and preconditions: App::PropertyFont", - "status": "pending", + "status": "in_progress", "dependencies": [ "PROP-app-propertyfileincluded-I" ], diff --git a/config/freecad-follow-up-task-progress.json b/config/freecad-follow-up-task-progress.json index f2784ab..30fd93b 100644 --- a/config/freecad-follow-up-task-progress.json +++ b/config/freecad-follow-up-task-progress.json @@ -8,5 +8,540 @@ "ordering": "completed task IDs must form a contiguous prefix of the generated follow-up queue", "evidence": "every completed task must name at least one machine-checkable artifact or focused check" }, - "completedTasks": [] + "completedTasks": [ + { + "id": "PROP-app-propertyacceleration-A", + "evidence": [ + "config/freecad-property-acceleration-inventory.json", + "check:freecad-property-acceleration-inventory" + ] + }, + { + "id": "PROP-app-propertyacceleration-B", + "evidence": [ + "config/freecad-property-acceleration-success.json", + "check:freecad-property-acceleration-success" + ] + }, + { + "id": "PROP-app-propertyacceleration-C", + "evidence": [ + "config/freecad-property-acceleration-failure.json", + "check:freecad-property-acceleration-failure" + ] + }, + { + "id": "PROP-app-propertyacceleration-D", + "evidence": [ + "config/freecad-property-acceleration-mutation.json", + "check:freecad-property-acceleration-mutation" + ] + }, + { + "id": "PROP-app-propertyacceleration-E", + "evidence": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "test:freecad-property-acceleration-facade" + ] + }, + { + "id": "PROP-app-propertyacceleration-F", + "evidence": [ + "tests/propertyAccelerationTransaction.test.ts", + "test:freecad-property-acceleration-transaction" + ] + }, + { + "id": "PROP-app-propertyacceleration-G", + "evidence": [ + "config/freecad-property-acceleration-roundtrip.json", + "check:freecad-property-acceleration-roundtrip" + ] + }, + { + "id": "PROP-app-propertyacceleration-H", + "evidence": [ + "config/chrome-property-acceleration-verification.json", + "check:chrome-property-acceleration" + ] + }, + { + "id": "PROP-app-propertyacceleration-I", + "evidence": [ + "config/freecad-property-acceleration-promotion.json", + "check:freecad-property-acceleration-promotion" + ] + }, + { + "id": "PROP-app-propertyarea-A", + "evidence": [ + "config/freecad-property-area-inventory.json", + "check:freecad-property-area-inventory" + ] + }, + { + "id": "PROP-app-propertyarea-B", + "evidence": [ + "config/freecad-property-area-success.json", + "check:freecad-property-area-success" + ] + }, + { + "id": "PROP-app-propertyarea-C", + "evidence": [ + "config/freecad-property-area-failure.json", + "check:freecad-property-area-failure" + ] + }, + { + "id": "PROP-app-propertyarea-D", + "evidence": [ + "config/freecad-property-area-mutation.json", + "check:freecad-property-area-mutation" + ] + }, + { + "id": "PROP-app-propertyarea-E", + "evidence": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "tests/propertyAreaFacade.test.ts", + "test:freecad-property-area-facade" + ] + }, + { + "id": "PROP-app-propertyarea-F", + "evidence": [ + "tests/propertyAreaTransaction.test.ts", + "test:freecad-property-area-transaction" + ] + }, + { + "id": "PROP-app-propertyarea-G", + "evidence": [ + "config/freecad-property-area-roundtrip.json", + "check:freecad-property-area-roundtrip" + ] + }, + { + "id": "PROP-app-propertyarea-H", + "evidence": [ + "config/chrome-property-area-verification.json", + "check:chrome-property-area" + ] + }, + { + "id": "PROP-app-propertyarea-I", + "evidence": [ + "config/freecad-property-area-promotion.json", + "check:freecad-property-area-promotion" + ] + }, + { + "id": "PROP-app-propertyboollist-A", + "evidence": [ + "config/freecad-property-boollist-inventory.json", + "check:freecad-property-boollist-inventory" + ] + }, + { + "id": "PROP-app-propertyboollist-B", + "evidence": [ + "config/freecad-property-boollist-success.json", + "check:freecad-property-boollist-success" + ] + }, + { + "id": "PROP-app-propertyboollist-C", + "evidence": [ + "config/freecad-property-boollist-failure.json", + "check:freecad-property-boollist-failure" + ] + }, + { + "id": "PROP-app-propertyboollist-D", + "evidence": [ + "config/freecad-property-boollist-mutation.json", + "check:freecad-property-boollist-mutation" + ] + }, + { + "id": "PROP-app-propertyboollist-E", + "evidence": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyBoolListFacade.test.ts", + "test:freecad-property-boollist-facade" + ] + }, + { + "id": "PROP-app-propertyboollist-F", + "evidence": [ + "tests/propertyBoolListTransaction.test.ts", + "test:freecad-property-boollist-transaction" + ] + }, + { + "id": "PROP-app-propertyboollist-G", + "evidence": [ + "config/freecad-property-boollist-roundtrip.json", + "check:freecad-property-boollist-roundtrip" + ] + }, + { + "id": "PROP-app-propertyboollist-H", + "evidence": [ + "config/chrome-property-boollist-verification.json", + "check:chrome-property-boollist" + ] + }, + { + "id": "PROP-app-propertyboollist-I", + "evidence": [ + "config/freecad-property-boollist-promotion.json", + "check:freecad-property-boollist-promotion" + ] + }, + { + "id": "PROP-app-propertycolor-A", + "evidence": [ + "config/freecad-property-color-inventory.json", + "check:freecad-property-color-inventory" + ] + }, + { + "id": "PROP-app-propertycolor-B", + "evidence": [ + "config/freecad-property-color-success.json", + "check:freecad-property-color-success" + ] + }, + { + "id": "PROP-app-propertycolor-C", + "evidence": [ + "config/freecad-property-color-failure.json", + "check:freecad-property-color-failure" + ] + }, + { + "id": "PROP-app-propertycolor-D", + "evidence": [ + "config/freecad-property-color-mutation.json", + "check:freecad-property-color-mutation" + ] + }, + { + "id": "PROP-app-propertycolor-E", + "evidence": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyColorFacade.test.ts", + "test:freecad-property-color-facade" + ] + }, + { + "id": "PROP-app-propertycolor-F", + "evidence": [ + "tests/propertyColorTransaction.test.ts", + "test:freecad-property-color-transaction" + ] + }, + { + "id": "PROP-app-propertycolor-G", + "evidence": [ + "config/freecad-property-color-roundtrip.json", + "check:freecad-property-color-roundtrip" + ] + }, + { + "id": "PROP-app-propertycolor-H", + "evidence": [ + "config/chrome-property-color-verification.json", + "check:chrome-property-color" + ] + }, + { + "id": "PROP-app-propertycolor-I", + "evidence": [ + "config/freecad-property-color-promotion.json", + "check:freecad-property-color-promotion" + ] + }, + { + "id": "PROP-app-propertycolorlist-A", + "evidence": [ + "config/freecad-property-colorlist-inventory.json", + "check:freecad-property-colorlist-inventory" + ] + }, + { + "id": "PROP-app-propertycolorlist-B", + "evidence": [ + "config/freecad-property-colorlist-success.json", + "check:freecad-property-colorlist-success" + ] + }, + { + "id": "PROP-app-propertycolorlist-C", + "evidence": [ + "config/freecad-property-colorlist-failure.json", + "check:freecad-property-colorlist-failure" + ] + }, + { + "id": "PROP-app-propertycolorlist-D", + "evidence": [ + "config/freecad-property-colorlist-mutation.json", + "check:freecad-property-colorlist-mutation" + ] + }, + { + "id": "PROP-app-propertycolorlist-E", + "evidence": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyColorListFacade.test.ts", + "test:freecad-property-colorlist-facade" + ] + }, + { + "id": "PROP-app-propertycolorlist-F", + "evidence": [ + "tests/propertyColorListTransaction.test.ts", + "test:freecad-property-colorlist-transaction" + ] + }, + { + "id": "PROP-app-propertycolorlist-G", + "evidence": [ + "config/freecad-property-colorlist-roundtrip.json", + "check:freecad-property-colorlist-roundtrip" + ] + }, + { + "id": "PROP-app-propertycolorlist-H", + "evidence": [ + "config/chrome-property-colorlist-verification.json", + "check:chrome-property-colorlist" + ] + }, + { + "id": "PROP-app-propertycolorlist-I", + "evidence": [ + "config/freecad-property-colorlist-promotion.json", + "check:freecad-property-colorlist-promotion" + ] + }, + { + "id": "PROP-app-propertydirection-A", + "evidence": [ + "config/freecad-property-direction-inventory.json", + "check:freecad-property-direction-inventory" + ] + }, + { + "id": "PROP-app-propertydirection-B", + "evidence": [ + "config/freecad-property-direction-success.json", + "check:freecad-property-direction-success" + ] + }, + { + "id": "PROP-app-propertydirection-C", + "evidence": [ + "config/freecad-property-direction-failure.json", + "check:freecad-property-direction-failure" + ] + }, + { + "id": "PROP-app-propertydirection-D", + "evidence": [ + "config/freecad-property-direction-mutation.json", + "check:freecad-property-direction-mutation" + ] + }, + { + "id": "PROP-app-propertydirection-E", + "evidence": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyDirectionFacade.test.ts", + "test:freecad-property-direction-facade" + ] + }, + { + "id": "PROP-app-propertydirection-F", + "evidence": [ + "tests/propertyDirectionTransaction.test.ts", + "test:freecad-property-direction-transaction" + ] + }, + { + "id": "PROP-app-propertydirection-G", + "evidence": [ + "config/freecad-property-direction-roundtrip.json", + "check:freecad-property-direction-roundtrip" + ] + }, + { + "id": "PROP-app-propertydirection-H", + "evidence": [ + "config/chrome-property-direction-verification.json", + "check:chrome-property-direction" + ] + }, + { + "id": "PROP-app-propertydirection-I", + "evidence": [ + "config/freecad-property-direction-promotion.json", + "check:freecad-property-direction-promotion" + ] + }, + { + "id": "PROP-app-propertyfile-A", + "evidence": [ + "config/freecad-property-file-inventory.json", + "check:freecad-property-file-inventory" + ] + }, + { + "id": "PROP-app-propertyfile-B", + "evidence": [ + "config/freecad-property-file-success.json", + "check:freecad-property-file-success" + ] + }, + { + "id": "PROP-app-propertyfile-C", + "evidence": [ + "config/freecad-property-file-failure.json", + "check:freecad-property-file-failure" + ] + }, + { + "id": "PROP-app-propertyfile-D", + "evidence": [ + "config/freecad-property-file-mutation.json", + "check:freecad-property-file-mutation" + ] + }, + { + "id": "PROP-app-propertyfile-E", + "evidence": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyFileFacade.test.ts", + "test:freecad-property-file-facade" + ] + }, + { + "id": "PROP-app-propertyfile-F", + "evidence": [ + "tests/propertyFileTransaction.test.ts", + "test:freecad-property-file-transaction" + ] + }, + { + "id": "PROP-app-propertyfile-G", + "evidence": [ + "config/freecad-property-file-roundtrip.json", + "check:freecad-property-file-roundtrip" + ] + }, + { + "id": "PROP-app-propertyfile-H", + "evidence": [ + "config/chrome-property-file-verification.json", + "check:chrome-property-file" + ] + }, + { + "id": "PROP-app-propertyfile-I", + "evidence": [ + "config/freecad-property-file-promotion.json", + "check:freecad-property-file-promotion" + ] + }, + { + "id": "PROP-app-propertyfileincluded-A", + "evidence": [ + "config/freecad-property-fileincluded-inventory.json", + "check:freecad-property-fileincluded-inventory" + ] + }, + { + "id": "PROP-app-propertyfileincluded-B", + "evidence": [ + "config/freecad-property-fileincluded-success.json", + "check:freecad-property-fileincluded-success" + ] + }, + { + "id": "PROP-app-propertyfileincluded-C", + "evidence": [ + "config/freecad-property-fileincluded-failure.json", + "check:freecad-property-fileincluded-failure" + ] + }, + { + "id": "PROP-app-propertyfileincluded-D", + "evidence": [ + "config/freecad-property-fileincluded-mutation.json", + "check:freecad-property-fileincluded-mutation" + ] + }, + { + "id": "PROP-app-propertyfileincluded-E", + "evidence": [ + "src/facade/includedFile.ts", + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyFileIncludedFacade.test.ts", + "test:freecad-property-fileincluded-facade" + ] + }, + { + "id": "PROP-app-propertyfileincluded-F", + "evidence": [ + "tests/propertyFileIncludedTransaction.test.ts", + "test:freecad-property-fileincluded-transaction" + ] + }, + { + "id": "PROP-app-propertyfileincluded-G", + "evidence": [ + "config/freecad-property-fileincluded-roundtrip.json", + "check:freecad-property-fileincluded-roundtrip" + ] + }, + { + "id": "PROP-app-propertyfileincluded-H", + "evidence": [ + "config/chrome-property-fileincluded-verification.json", + "check:chrome-property-fileincluded" + ] + }, + { + "id": "PROP-app-propertyfileincluded-I", + "evidence": [ + "config/freecad-property-fileincluded-promotion.json", + "check:freecad-property-fileincluded-promotion" + ] + } + ] } diff --git a/config/freecad-native-property-semantics.json b/config/freecad-native-property-semantics.json index 2a964fe..7f264da 100644 --- a/config/freecad-native-property-semantics.json +++ b/config/freecad-native-property-semantics.json @@ -7,8 +7,8 @@ }, "source": { "path": ".cache/freecad/reference-desktop.json", - "bytes": 4699380, - "sha256": "30ffbbdb4139a682486e6fed482a8d8d8a88c287a38dfec8d814e38f4e70fc80" + "bytes": 2298709, + "sha256": "082400ec7379e8efc2af16709032d45890d7092277967b714acb05761fd1c2a7" }, "runtime": { "registeredObjectTypes": 352, @@ -37,22 +37,22 @@ }, "supportSummary": { "native-editable-codec": { - "typeCount": 22, - "recordCount": 4304 + "typeCount": 30, + "recordCount": 4361 }, "native-specialized-codec": { "typeCount": 5, "recordCount": 683 }, "opaque-fcstd-proxy": { - "typeCount": 58, - "recordCount": 523 + "typeCount": 50, + "recordCount": 466 } }, "types": [ { "typeId": "App::PropertyAcceleration", - "support": "opaque-fcstd-proxy", + "support": "native-editable-codec", "recordCount": 1, "objectTypeCount": 1, "statusNames": [] @@ -71,7 +71,7 @@ }, { "typeId": "App::PropertyArea", - "support": "opaque-fcstd-proxy", + "support": "native-editable-codec", "recordCount": 1, "objectTypeCount": 1, "statusNames": [ @@ -100,7 +100,7 @@ }, { "typeId": "App::PropertyBoolList", - "support": "opaque-fcstd-proxy", + "support": "native-editable-codec", "recordCount": 7, "objectTypeCount": 7, "statusNames": [ @@ -111,21 +111,21 @@ }, { "typeId": "App::PropertyColor", - "support": "opaque-fcstd-proxy", + "support": "native-editable-codec", "recordCount": 8, "objectTypeCount": 8, "statusNames": [] }, { "typeId": "App::PropertyColorList", - "support": "opaque-fcstd-proxy", + "support": "native-editable-codec", "recordCount": 2, "objectTypeCount": 2, "statusNames": [] }, { "typeId": "App::PropertyDirection", - "support": "opaque-fcstd-proxy", + "support": "native-editable-codec", "recordCount": 2, "objectTypeCount": 2, "statusNames": [] @@ -165,14 +165,14 @@ }, { "typeId": "App::PropertyFile", - "support": "opaque-fcstd-proxy", + "support": "native-editable-codec", "recordCount": 16, "objectTypeCount": 12, "statusNames": [] }, { "typeId": "App::PropertyFileIncluded", - "support": "opaque-fcstd-proxy", + "support": "native-editable-codec", "recordCount": 20, "objectTypeCount": 15, "statusNames": [ @@ -902,10 +902,10 @@ }, "harness": { "path": "scripts/run-freecad-native-property-semantics.mjs", - "bytes": 6166, - "sha256": "f6fcab14a46c9e7597f10808b31eb10cd5196bd90144c5b6a7a50e6993a1c3f6" + "bytes": 6615, + "sha256": "fad232fd5a013d40639069df2f8752f04fc5d373c6a7a7ece8ed3276612af9f3" }, "exactPromotionReady": false, - "exactBlocker": "58 runtime property types and 523 records remain opaque-only; complete native document and property semantics", - "generatedAt": "2026-08-14T22:37:52.376Z" + "exactBlocker": "50 runtime property types and 466 records remain opaque-only; complete native document and property semantics", + "generatedAt": "2026-08-17T08:49:24.621Z" } diff --git a/config/freecad-ordered-operation-pair-classification.json b/config/freecad-ordered-operation-pair-classification.json index 5f84ac6..0c84111 100644 --- a/config/freecad-ordered-operation-pair-classification.json +++ b/config/freecad-ordered-operation-pair-classification.json @@ -10,8 +10,8 @@ "nativeProbe": { "executor": { "path": "scripts/run-freecad-ordered-operation-pair-classification.mjs", - "bytes": 45217, - "sha256": "f89493cbe219c3dc91ef7fa360dc393fdb6bbe9ecbbc40a26199a63462f02790" + "bytes": 57057, + "sha256": "8d5461884dd0e1b829ec10fd16fbf040bc5f3696ce8cc1672a9590cbad7a813f" }, "matrix": { "path": "scripts/freecad-naming-production-matrix.mjs", @@ -20,8 +20,8 @@ }, "resave": { "path": "scripts/freecad-ordered-operation-pair-resave.py", - "bytes": 20178, - "sha256": "d1340dcac2f364dc3cc1fa5fe51758fac6b960ebfa5ca3ed4526b6fb663d128b" + "bytes": 21991, + "sha256": "e5b849fe5b23f51bd0c3a8d92e8af41386f4cf76b8545cab0352cf61d0dde4f0" }, "artifacts": [ { @@ -56389,14 +56389,40051 @@ "schemaVersion": 1, "status": "pass" } + }, + { + "taskId": "TSN-PAIR-chamfer-rotate", + "pair": "chamfer->rotate", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "e53805c4bd6bde5a42eda4c4a19dcc73874c4dc7bb0ebf828d9e453b3db6cc60", + "namingSemanticSha256": "1d0609060a5a7a50fee2dc95e4be2456da13fbad8b03023b7504e1e78ad1365e" + }, + "second": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -2.4846629, + 0.1035275, + -1e-7, + 9.5557307, + 12.1439212, + 10.0000001 + ] + }, + "historyRecords": 314, + "selectedRecords": 6, + "ambiguousResults": 92, + "historySha256": "043a85bce6ca9e2be06444356fd8655c6d00d73131b91620965bbaaaa2e87e8a", + "namingEvidenceSha256": "d5ff71d25d2548bf8e6546f13b58d200c634d202f35ed8cbe52b88f720d194b0", + "namingSemanticSha256": "9ff5ba51dc15194bc22ae20b6f8effb73a1ffea910946f7a71757f97ebbc2142" + }, + "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": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -3.6737611, + 0.1530733, + -1e-7, + 9.0857221, + 12.9125564, + 10.0000001 + ] + }, + "historyRecords": 314, + "selectedRecords": 6, + "ambiguousResults": 92, + "historySha256": "043a85bce6ca9e2be06444356fd8655c6d00d73131b91620965bbaaaa2e87e8a", + "namingEvidenceSha256": "b08975df3142b9355e28570bd4ea7f28b07380e535a2964e656744f688f729c2", + "namingSemanticSha256": "9ff5ba51dc15194bc22ae20b6f8effb73a1ffea910946f7a71757f97ebbc2142" + }, + "restoredEvidence": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -2.4846629, + 0.1035275, + -1e-7, + 9.5557307, + 12.1439212, + 10.0000001 + ] + }, + "historyRecords": 314, + "selectedRecords": 6, + "ambiguousResults": 92, + "historySha256": "043a85bce6ca9e2be06444356fd8655c6d00d73131b91620965bbaaaa2e87e8a", + "namingEvidenceSha256": "26cb266dc4b98293ba5f1726c947aab03be92c85f9226345d4921497880df39f", + "namingSemanticSha256": "9ff5ba51dc15194bc22ae20b6f8effb73a1ffea910946f7a71757f97ebbc2142" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "chamfer->rotate", + "phases": { + "initial": { + "namingEvidenceBytes": 39723, + "namingEvidenceSha256": "d5ff71d25d2548bf8e6546f13b58d200c634d202f35ed8cbe52b88f720d194b0", + "pair": "chamfer->rotate", + "shape": { + "area": 571.4001834, + "bounds": [ + -2.4846628, + 0.1035276, + 0, + 9.5557306, + 12.1439211, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "reopened": { + "namingEvidenceBytes": 39723, + "namingEvidenceSha256": "d5ff71d25d2548bf8e6546f13b58d200c634d202f35ed8cbe52b88f720d194b0", + "pair": "chamfer->rotate", + "shape": { + "area": 571.4001834, + "bounds": [ + -2.4846628, + 0.1035276, + 0, + 9.5557306, + 12.1439211, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "resaved": { + "namingEvidenceBytes": 39723, + "namingEvidenceSha256": "d5ff71d25d2548bf8e6546f13b58d200c634d202f35ed8cbe52b88f720d194b0", + "pair": "chamfer->rotate", + "shape": { + "area": 571.4001834, + "bounds": [ + -2.4846628, + 0.1035276, + 0, + 9.5557306, + 12.1439211, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-chamfer-pad", + "pair": "chamfer->pad", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "ca8c3f72b53f7278828fbd53dfeb0db9e6c2223a029ac9db135d3b050177eb5d", + "namingSemanticSha256": "713d2fa30bc0770215789ec9ae2451a8e4652650cc4eacee4bc2003f6700c2c0" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "length", + "trajectory": [ + 5, + 7.5, + 5 + ], + "stable": true, + "attempts": [ + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 7.5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "nativeTypeId": "PartDesign::Pad", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Body", + "typeId": "PartDesign::Body" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + }, + { + "name": "PairResult", + "typeId": "PartDesign::Pad" + } + ], + "parameter": { + "name": "length", + "value": 5 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "FeatureExtrusion: Length: Could not extrude the sketch!" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "PartDesign::Pad", + "operation": "pad", + "pair": "chamfer->pad", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + } + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-chamfer-pocket", + "pair": "chamfer->pocket", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "1ddc92ddeac4cf956a886a2cbfb4af6b9a01d89c64aaeae207a583af97640971", + "namingSemanticSha256": "e937be5af2bfcb36d700e09bad497fe063f93e10b21f70a081f5f865399b0dfd" + }, + "second": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 28, + "edges": 57, + "vertices": 31, + "volume": 961.4986667, + "area": 573.5635876, + "bounds": [ + -2e-7, + -2e-7, + -2e-7, + 10.0000002, + 10.0000002, + 10.0000001 + ] + }, + "historyRecords": 97, + "selectedRecords": 6, + "ambiguousResults": 15, + "historySha256": "63599ae2f637e4a32fdc0ed387dd70a64901928cde36e879fb72f0f4a745a85c", + "namingEvidenceSha256": "0292a471b76d843a659f8280a927482faaaa3470a4cb7fba62ebcd593e49c1fc", + "namingSemanticSha256": "e518729f30134415b8d56f634e82d8b07d7e08a1d37a19882d2989985a87c055" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "length", + "trajectory": [ + 5, + 4, + 5 + ], + "beforeValue": 5, + "editedValue": 4, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 28, + "edges": 57, + "vertices": 31, + "volume": 967.4186667, + "area": 573.3292731, + "bounds": [ + -2e-7, + -2e-7, + -2e-7, + 10.0000002, + 10.0000002, + 10.0000001 + ] + }, + "historyRecords": 97, + "selectedRecords": 6, + "ambiguousResults": 15, + "historySha256": "63599ae2f637e4a32fdc0ed387dd70a64901928cde36e879fb72f0f4a745a85c", + "namingEvidenceSha256": "f5c9658655a6fadcf1c300770352f8d3f862c3ff88df42bfec6381798eedeafe", + "namingSemanticSha256": "e518729f30134415b8d56f634e82d8b07d7e08a1d37a19882d2989985a87c055" + }, + "restoredEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 28, + "edges": 57, + "vertices": 31, + "volume": 961.4986667, + "area": 573.5635876, + "bounds": [ + -2e-7, + -2e-7, + -2e-7, + 10.0000002, + 10.0000002, + 10.0000001 + ] + }, + "historyRecords": 97, + "selectedRecords": 6, + "ambiguousResults": 15, + "historySha256": "63599ae2f637e4a32fdc0ed387dd70a64901928cde36e879fb72f0f4a745a85c", + "namingEvidenceSha256": "edf4805995b4dce58f07689ff545b0ed64a4703b531efef48deab3ddbd828f6a", + "namingSemanticSha256": "e518729f30134415b8d56f634e82d8b07d7e08a1d37a19882d2989985a87c055" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "chamfer->pocket", + "phases": { + "initial": { + "namingEvidenceBytes": 7381, + "namingEvidenceSha256": "0292a471b76d843a659f8280a927482faaaa3470a4cb7fba62ebcd593e49c1fc", + "pair": "chamfer->pocket", + "shape": { + "area": 573.5635876, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 57, + "faces": 28, + "solids": 1, + "valid": true, + "vertices": 31, + "volume": 961.4986667 + } + }, + "reopened": { + "namingEvidenceBytes": 7381, + "namingEvidenceSha256": "0292a471b76d843a659f8280a927482faaaa3470a4cb7fba62ebcd593e49c1fc", + "pair": "chamfer->pocket", + "shape": { + "area": 573.5635876, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 57, + "faces": 28, + "solids": 1, + "valid": true, + "vertices": 31, + "volume": 961.4986667 + } + }, + "resaved": { + "namingEvidenceBytes": 7381, + "namingEvidenceSha256": "0292a471b76d843a659f8280a927482faaaa3470a4cb7fba62ebcd593e49c1fc", + "pair": "chamfer->pocket", + "shape": { + "area": 573.5635876, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 57, + "faces": 28, + "solids": 1, + "valid": true, + "vertices": 31, + "volume": 961.4986667 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-chamfer-loft", + "pair": "chamfer->loft", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "a8d8184dc0347541eb79573ce2676e57bd29b47bb22636f78aa596930e6001c4", + "namingSemanticSha256": "569655cbfdc2ad6b95776b2cededdc1503917484ed23056cbd27f409c352e6a8" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "ruled", + "trajectory": [ + false, + true, + false + ], + "kernelAttempts": [ + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 704.4, + "area": 552.5525865, + "bounds": [ + -1e-7, + -1e-7, + 0.3999999, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": true, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 704.4, + "area": 552.5525865, + "bounds": [ + -1e-7, + -1e-7, + 0.3999999, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 704.4, + "area": 552.5525865, + "bounds": [ + -1e-7, + -1e-7, + 0.3999999, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + } + ] + }, + "inputShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "nativeTypeId": "Part::Loft", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Loft" + } + ], + "parameter": { + "name": "ruled", + "value": false + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Profile shape is not a single vertex, edge, wire nor face." + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Loft", + "operation": "loft", + "pair": "chamfer->loft", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + } + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-chamfer-pipe", + "pair": "chamfer->pipe", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "0edfa03654aa7579d94396d4ab21250343b7511b2c4dbaf316690c2683d273ea", + "namingSemanticSha256": "63a9bf0e5cbd21173dab4c694805a63eb05195a356bb818fe28f6ac37e283c1c" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "spineLength", + "trajectory": [ + 15, + 12, + 15 + ], + "kernelAttempts": [ + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 445.28, + "bounds": [ + -1e-7, + 0.3999999, + 0.3999999, + 1e-7, + 9.6000001, + 24.6000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 12, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 390.08, + "bounds": [ + -1e-7, + 0.3999999, + 0.3999999, + 1e-7, + 9.6000001, + 21.6000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 445.28, + "bounds": [ + -1e-7, + 0.3999999, + 0.3999999, + 1e-7, + 9.6000001, + 24.6000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "spine": { + "name": "Spine", + "subelements": [], + "typeId": "Part::Feature" + } + }, + "inputShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "nativeTypeId": "Part::Sweep", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Spine", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Sweep" + } + ], + "parameter": { + "name": "spineLength", + "value": 15 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "A fatal error occurred when making the sweep" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Sweep", + "operation": "pipe", + "pair": "chamfer->pipe", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + } + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-chamfer-revolution", + "pair": "chamfer->revolution", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "6df04c80add013dde457f826963431a7efb83ddd0cde3481503343b34bf84507", + "namingSemanticSha256": "f7c27d21d4985dc507ac4cd98ca2c228029734459435da1c9ff94b1032bbe1e5" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "angle", + "trajectory": [ + 360, + 270, + 360 + ], + "stable": true, + "attempts": [ + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 270, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "nativeTypeId": "Part::Revolution", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Revolution" + } + ], + "parameter": { + "name": "angle", + "value": 360 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Solids are not Processed" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Revolution", + "operation": "revolution", + "pair": "chamfer->revolution", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + } + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-chamfer-groove", + "pair": "chamfer->groove", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "ad701a160782bd4f6c617dcb5a339adce08593024daef190c31a62cff89a4172", + "namingSemanticSha256": "d791b448dbfb3dfcede43dd74e3f26458e0d09709b3ce6c71b68f99441a75513" + }, + "second": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 30, + "edges": 60, + "vertices": 32, + "volume": 986.0289444, + "area": 577.966554, + "bounds": [ + -2e-7, + -2e-7, + -2e-7, + 10.0000002, + 10.0000002, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "892b3438bfa8143f0215f0b98050b4f811a4f8a4cbebbcbfeb4f79ac9c98c140", + "namingEvidenceSha256": "d8501450f198de5a5f03c842c677e859346b415f4a1a3c5cf5d2f9b4622846dc", + "namingSemanticSha256": "b909d1158e2d7afa9c32d8203639414f560ce5f2caf8591e47328bd6a8c6d65b" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 360, + 180, + 360 + ], + "beforeValue": 360, + "editedValue": 180, + "restoredValue": 360, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 27, + "edges": 52, + "vertices": 28, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 56, + "selectedRecords": 1, + "ambiguousResults": 5, + "historySha256": "6191ab9787fad8914b3bdb1ba6da79b791b1b39533d6da574286e54384a91124", + "namingEvidenceSha256": "baa288fc58aa81a7ff947ae4bce689252bd251afeb2e76c2b0c8d9cd47cea691", + "namingSemanticSha256": "4a29952160f54d0f71391436d681dd197f6757eb9d40380bcb34daa300475258" + }, + "restoredEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 30, + "edges": 60, + "vertices": 32, + "volume": 986.0289444, + "area": 577.966554, + "bounds": [ + -2e-7, + -2e-7, + -2e-7, + 10.0000002, + 10.0000002, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "892b3438bfa8143f0215f0b98050b4f811a4f8a4cbebbcbfeb4f79ac9c98c140", + "namingEvidenceSha256": "fbdbe76a1519ecc5f8a26890e21b34824bce3af7f341bf2007c06969e690738d", + "namingSemanticSha256": "b909d1158e2d7afa9c32d8203639414f560ce5f2caf8591e47328bd6a8c6d65b" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "chamfer->groove", + "phases": { + "initial": { + "namingEvidenceBytes": 5028, + "namingEvidenceSha256": "d8501450f198de5a5f03c842c677e859346b415f4a1a3c5cf5d2f9b4622846dc", + "pair": "chamfer->groove", + "shape": { + "area": 577.966554, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 60, + "faces": 30, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 986.0289444 + } + }, + "reopened": { + "namingEvidenceBytes": 5028, + "namingEvidenceSha256": "d8501450f198de5a5f03c842c677e859346b415f4a1a3c5cf5d2f9b4622846dc", + "pair": "chamfer->groove", + "shape": { + "area": 577.966554, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 60, + "faces": 30, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 986.0289444 + } + }, + "resaved": { + "namingEvidenceBytes": 5028, + "namingEvidenceSha256": "d8501450f198de5a5f03c842c677e859346b415f4a1a3c5cf5d2f9b4622846dc", + "pair": "chamfer->groove", + "shape": { + "area": 577.966554, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 60, + "faces": 30, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 986.0289444 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-chamfer-fillet", + "pair": "chamfer->fillet", + "classification": "rejected", + "reasonCode": "native-builder-wasm-abort-with-freecad-profile-acceptance-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "454b658a2f6015ad4fcc7533f7fc611d356f1a8b2f9f79d2563b5a92844157b7", + "namingSemanticSha256": "4fc5a5a99180b17572866762f599a4e622b4da237249977f2d53b6b8e7635b97" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "radius", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "stable": true, + "attempts": [ + { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "parameter": "radius", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "memory access out of bounds" + }, + { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "parameter": "radius", + "parameterValue": 0.6, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "memory access out of bounds" + }, + { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "parameter": "radius", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "memory access out of bounds" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": true, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": false, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "nativeTypeId": "Part::Fillet", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Fillet" + } + ], + "parameter": { + "name": "radius", + "value": 0.4 + }, + "recomputeResult": true, + "resultShape": { + "area": 567.3942825, + "bounds": [ + -0.0111299, + -0.0111299, + -0.0111299, + 10.0111299, + 10.0111299, + 10.0111299 + ], + "edges": 192, + "faces": 98, + "solids": 1, + "valid": true, + "vertices": 96, + "volume": 989.9595415 + }, + "shapeNull": false, + "shapeValid": true, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Fillet", + "operation": "fillet", + "pair": "chamfer->fillet", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + } + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-chamfer-chamfer", + "pair": "chamfer->chamfer", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "7d14e2abd626b47959a1538478ee13b4b7c9412fa204de79b402f3f4a93e2694", + "namingSemanticSha256": "220b2cfa28c101f5a2b40d66f6187e0b4b3b1cf4da4f3f8fb9f8598758e1103c" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "distance", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "stable": true, + "attempts": [ + { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "parameter": "distance", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "memory access out of bounds" + }, + { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "parameter": "distance", + "parameterValue": 0.6, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "memory access out of bounds" + }, + { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "parameter": "distance", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "memory access out of bounds" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "nativeTypeId": "Part::Chamfer", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Chamfer" + } + ], + "parameter": { + "name": "distance", + "value": 0.4 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "BRep_API: command not done" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Chamfer", + "operation": "chamfer", + "pair": "chamfer->chamfer", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + } + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-chamfer-hole", + "pair": "chamfer->hole", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "222a652c9c8edc335c477ce39c9d764bbb488bcc4c475e4247e2c1ce46d7cf72", + "namingSemanticSha256": "01f5fd46d81e4a42f993c4d809bec7af6833d058366e7ee2c5a8800b415f4cee" + }, + "second": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 27, + "edges": 51, + "vertices": 26, + "volume": 959.3254068, + "area": 627.9488512, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "1465970370441b34d000fdfe825ec6366d6262de3c4671cd1ad5ec84f367932a", + "namingEvidenceSha256": "c09894a0b699f285cdcc05799f9bdd683d6f30f5248ecc723ff53f18318e4b42", + "namingSemanticSha256": "02b879d6dc6bb73fea4f32b7e5c92f2b0b0766ee854fab7ad98f531cc6430e86" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 1, + 1.5, + 1 + ], + "beforeValue": 1, + "editedValue": 1.5, + "restoredValue": 1, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 27, + "edges": 51, + "vertices": 26, + "volume": 920.0554986, + "area": 651.5107961, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "1465970370441b34d000fdfe825ec6366d6262de3c4671cd1ad5ec84f367932a", + "namingEvidenceSha256": "da5ed9a5552bc89fc444b1631cf9898cff09008736b09e0e59ceab87555fa802", + "namingSemanticSha256": "02b879d6dc6bb73fea4f32b7e5c92f2b0b0766ee854fab7ad98f531cc6430e86" + }, + "restoredEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 27, + "edges": 51, + "vertices": 26, + "volume": 959.3254068, + "area": 627.9488512, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "1465970370441b34d000fdfe825ec6366d6262de3c4671cd1ad5ec84f367932a", + "namingEvidenceSha256": "668a0099f720e99532d126ccab47d7ef7cf52fdc9347bd57fd25d1072320feac", + "namingSemanticSha256": "02b879d6dc6bb73fea4f32b7e5c92f2b0b0766ee854fab7ad98f531cc6430e86" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "chamfer->hole", + "phases": { + "initial": { + "namingEvidenceBytes": 1845, + "namingEvidenceSha256": "c09894a0b699f285cdcc05799f9bdd683d6f30f5248ecc723ff53f18318e4b42", + "pair": "chamfer->hole", + "shape": { + "area": 627.9488512, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 51, + "faces": 27, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 959.3254068 + } + }, + "reopened": { + "namingEvidenceBytes": 1845, + "namingEvidenceSha256": "c09894a0b699f285cdcc05799f9bdd683d6f30f5248ecc723ff53f18318e4b42", + "pair": "chamfer->hole", + "shape": { + "area": 627.9488512, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 51, + "faces": 27, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 959.3254068 + } + }, + "resaved": { + "namingEvidenceBytes": 1845, + "namingEvidenceSha256": "c09894a0b699f285cdcc05799f9bdd683d6f30f5248ecc723ff53f18318e4b42", + "pair": "chamfer->hole", + "shape": { + "area": 627.9488512, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 51, + "faces": 27, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 959.3254068 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-chamfer-draft", + "pair": "chamfer->draft", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "146e437ca4f6a353ba3b3e65b7a3840d5c163a2584f572335eb617ba717c98a8", + "namingSemanticSha256": "5d9f9843bc5e34d85b65b73b0abe69aa49a871037722ca3bee0d36982d0d648f" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "angle", + "trajectory": [ + 5, + 8, + 5 + ], + "stable": true, + "attempts": [ + { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 8, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "draftBaseBrepSha256": "0c5bf84b5cae1e76d9196aa3d533ccc1badf4ee7d5b7dc26fec1b391235c754d", + "name": "DraftBase", + "shapeSummaryTransferredExactly": true, + "sourceBrepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "sourceName": "Part__Feature", + "subelements": [ + "Face1" + ], + "typeId": "PartDesign::Feature" + }, + "inputShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "nativeTypeId": "PartDesign::Draft", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Body", + "typeId": "PartDesign::Body" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + }, + { + "name": "DraftBase", + "typeId": "PartDesign::Feature" + }, + { + "name": "DatumPlane", + "typeId": "PartDesign::Plane" + }, + { + "name": "DatumLine", + "typeId": "PartDesign::Line" + }, + { + "name": "PairResult", + "typeId": "PartDesign::Draft" + } + ], + "parameter": { + "name": "angle", + "value": 5 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "PartDesign::Draft", + "operation": "draft", + "pair": "chamfer->draft", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + } + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-chamfer-thickness", + "pair": "chamfer->thickness", + "classification": "rejected", + "reasonCode": "native-and-freecad-profile-no-op-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "2c42b68a69676d881e8db3887b8e57ac9c21f51cf6c328174dddba1ec073368d", + "namingSemanticSha256": "7d2e80cf791840af08d05cdcca97da93cc899e8e13f535abffa1e974a1a012ad" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-no-op", + "parameter": "offset", + "trajectory": [ + -0.4, + -0.6, + -0.4 + ], + "kernelAttempts": [ + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.4, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "c442a112b466339b076bd24c5b22da267b9def534d603c38621f27914a9c78fc", + "authority": "kernel-no-op" + }, + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.6, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "c442a112b466339b076bd24c5b22da267b9def534d603c38621f27914a9c78fc", + "authority": "kernel-no-op" + }, + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.4, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "c442a112b466339b076bd24c5b22da267b9def534d603c38621f27914a9c78fc", + "authority": "kernel-no-op" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "freecadProfileNoOp": true, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": false, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": false, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [ + "Face2" + ], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "nativeTypeId": "Part::Thickness", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Thickness" + } + ], + "parameter": { + "name": "offset", + "value": -0.4 + }, + "recomputeResult": true, + "resultShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "shapeNull": false, + "shapeValid": true, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Thickness", + "operation": "thickness", + "pair": "chamfer->thickness", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "0c4fbfd854938e5ecae5296d79e645fc5934b57fd5d96a2ffcd533250e664324", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "sourceBrepReserialized": true, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "fa5d7bd743a84ee6ef4e8515509324550461b59caf39640c185cf48c7cdee988", + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-chamfer-linear-pattern", + "pair": "chamfer->linear-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "427e1b1e37ab67de55cbed376a70b3658e71be1367b4c1ea0a571c1c1f69183c", + "namingSemanticSha256": "dbaf6ba32907df1bcdb8673ec76c2a3e5cd94d5217aff3b488434b325d711828" + }, + "second": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 80, + "vertices": 40, + "volume": 1788.1813333, + "area": 883.902117, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 258, + "selectedRecords": 8, + "ambiguousResults": 32, + "historySha256": "65d1badddf73c766f1117ce0a91b69ed685c520d03dbfd770ed16b812584aded", + "namingEvidenceSha256": "0de890180b7752a26c3147aeea02b304bfd26f085c5c6342d1baf04ecd64b5fe", + "namingSemanticSha256": "f034af78617fa2ed357cbacd34dcf97fc66caa53279419666a9b1c656bef4132" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "translationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 80, + "vertices": 40, + "volume": 1887.8613333, + "area": 922.9648587, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 19.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 258, + "selectedRecords": 8, + "ambiguousResults": 32, + "historySha256": "65d1badddf73c766f1117ce0a91b69ed685c520d03dbfd770ed16b812584aded", + "namingEvidenceSha256": "57cb0adaa03e71e72db59de49525d80fef004fd405c71838a5a19b0a2d3655b7", + "namingSemanticSha256": "f034af78617fa2ed357cbacd34dcf97fc66caa53279419666a9b1c656bef4132" + }, + "restoredEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 80, + "vertices": 40, + "volume": 1788.1813333, + "area": 883.902117, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 258, + "selectedRecords": 8, + "ambiguousResults": 32, + "historySha256": "65d1badddf73c766f1117ce0a91b69ed685c520d03dbfd770ed16b812584aded", + "namingEvidenceSha256": "366de051098fa9956f6268036977d6c22d0ab168b8beaf22b2d1b7a8bd863eff", + "namingSemanticSha256": "f034af78617fa2ed357cbacd34dcf97fc66caa53279419666a9b1c656bef4132" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "chamfer->linear-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 13293, + "namingEvidenceSha256": "0de890180b7752a26c3147aeea02b304bfd26f085c5c6342d1baf04ecd64b5fe", + "pair": "chamfer->linear-pattern", + "shape": { + "area": 883.902117, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 80, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1788.1813333 + } + }, + "reopened": { + "namingEvidenceBytes": 13293, + "namingEvidenceSha256": "0de890180b7752a26c3147aeea02b304bfd26f085c5c6342d1baf04ecd64b5fe", + "pair": "chamfer->linear-pattern", + "shape": { + "area": 883.902117, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 80, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1788.1813333 + } + }, + "resaved": { + "namingEvidenceBytes": 13293, + "namingEvidenceSha256": "0de890180b7752a26c3147aeea02b304bfd26f085c5c6342d1baf04ecd64b5fe", + "pair": "chamfer->linear-pattern", + "shape": { + "area": 883.902117, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 80, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1788.1813333 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-chamfer-polar-pattern", + "pair": "chamfer->polar-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "04c8f89bbf68257dcccd416db8b18a73e092934c6bdf48bb38d9d984ac4a8075", + "namingSemanticSha256": "620a4407f074d6739a7cfe2e5089c1946074079e2dda906b6f991e965010eb95" + }, + "second": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 46, + "edges": 90, + "vertices": 46, + "volume": 1411.0585231, + "area": 735.5718725, + "bounds": [ + -4.8000001, + -2e-7, + -2e-7, + 10.0000002, + 13.4602542, + 10.0000002 + ] + }, + "historyRecords": 228, + "selectedRecords": 5, + "ambiguousResults": 21, + "historySha256": "eee87895ab04b75e3f9fe14d81a69511866311864ea5782bc8d13d053e77b95f", + "namingEvidenceSha256": "271f87be56b4e4d3631720d53227553cc7ea1867612e008f79931f21f89116a8", + "namingSemanticSha256": "7ef9d1f7cb38368f97778a5986bafa118ebbdd2c604d3433690864a505d5765a" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 30, + 45, + 30 + ], + "beforeValue": 30, + "editedValue": 45, + "restoredValue": 30, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 46, + "edges": 90, + "vertices": 46, + "volume": 1573.5395566, + "area": 800.1036018, + "bounds": [ + -6.7882252, + -2e-7, + -2e-7, + 10.0000002, + 13.8592931, + 10.0000002 + ] + }, + "historyRecords": 228, + "selectedRecords": 5, + "ambiguousResults": 21, + "historySha256": "eee87895ab04b75e3f9fe14d81a69511866311864ea5782bc8d13d053e77b95f", + "namingEvidenceSha256": "f561cdf15ee1baeb89e54b470dacbeb71636ca27ba66975eb3d60d9e0e6bcf35", + "namingSemanticSha256": "7ef9d1f7cb38368f97778a5986bafa118ebbdd2c604d3433690864a505d5765a" + }, + "restoredEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 46, + "edges": 90, + "vertices": 46, + "volume": 1411.0585231, + "area": 735.5718725, + "bounds": [ + -4.8000001, + -2e-7, + -2e-7, + 10.0000002, + 13.4602542, + 10.0000002 + ] + }, + "historyRecords": 228, + "selectedRecords": 5, + "ambiguousResults": 21, + "historySha256": "eee87895ab04b75e3f9fe14d81a69511866311864ea5782bc8d13d053e77b95f", + "namingEvidenceSha256": "bbb5b10d91ce8e8dd87c221d0d7e85b8aa673a6fc5198ffebc8117efdf17638c", + "namingSemanticSha256": "7ef9d1f7cb38368f97778a5986bafa118ebbdd2c604d3433690864a505d5765a" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "chamfer->polar-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 10679, + "namingEvidenceSha256": "271f87be56b4e4d3631720d53227553cc7ea1867612e008f79931f21f89116a8", + "pair": "chamfer->polar-pattern", + "shape": { + "area": 735.5718725, + "bounds": [ + -4.8, + 0, + 0, + 10, + 13.460254, + 10 + ], + "edges": 90, + "faces": 46, + "solids": 1, + "valid": true, + "vertices": 46, + "volume": 1411.0585231 + } + }, + "reopened": { + "namingEvidenceBytes": 10679, + "namingEvidenceSha256": "271f87be56b4e4d3631720d53227553cc7ea1867612e008f79931f21f89116a8", + "pair": "chamfer->polar-pattern", + "shape": { + "area": 735.5718725, + "bounds": [ + -4.8, + 0, + 0, + 10, + 13.460254, + 10 + ], + "edges": 90, + "faces": 46, + "solids": 1, + "valid": true, + "vertices": 46, + "volume": 1411.0585231 + } + }, + "resaved": { + "namingEvidenceBytes": 10679, + "namingEvidenceSha256": "271f87be56b4e4d3631720d53227553cc7ea1867612e008f79931f21f89116a8", + "pair": "chamfer->polar-pattern", + "shape": { + "area": 735.5718725, + "bounds": [ + -4.8, + 0, + 0, + 10, + 13.460254, + 10 + ], + "edges": 90, + "faces": 46, + "solids": 1, + "valid": true, + "vertices": 46, + "volume": 1411.0585231 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-chamfer-mirrored", + "pair": "chamfer->mirrored", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "de9d8bb6edefce8855f4d951c7640d0ed5fcd3725ea5a2477376b497e6e506ff", + "namingSemanticSha256": "873b5ac754dfdbf6c6b068d6c16c398218e997b6936ef4a3ab93f82909fe430c" + }, + "second": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 80, + "vertices": 40, + "volume": 1190.1013333, + "area": 649.5256668, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 12.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 258, + "selectedRecords": 8, + "ambiguousResults": 32, + "historySha256": "9b3d80f02806d2ae4d5cbfbe31b94d1de479bba4104edb4f6367be90b5ba8073", + "namingEvidenceSha256": "f63fc775963630e55847b9b46b0d3e62b085c7a1633cce933930ea4b1df3934c", + "namingSemanticSha256": "8ab542be7d62e8bcdc0fa71e96552ed299d702dd06f4b3a8df63a859bffbb266" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "planeOriginX", + "trajectory": [ + 6, + 7, + 6 + ], + "beforeValue": 6, + "editedValue": 7, + "restoredValue": 6, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 80, + "vertices": 40, + "volume": 1389.4613333, + "area": 727.6511502, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 14.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 258, + "selectedRecords": 8, + "ambiguousResults": 32, + "historySha256": "9b3d80f02806d2ae4d5cbfbe31b94d1de479bba4104edb4f6367be90b5ba8073", + "namingEvidenceSha256": "6c8d8057d70773f62d5dc3429a5c9d51bd9c189f8844c0f45aab6779d925e8e7", + "namingSemanticSha256": "8ab542be7d62e8bcdc0fa71e96552ed299d702dd06f4b3a8df63a859bffbb266" + }, + "restoredEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 80, + "vertices": 40, + "volume": 1190.1013333, + "area": 649.5256668, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 12.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 258, + "selectedRecords": 8, + "ambiguousResults": 32, + "historySha256": "9b3d80f02806d2ae4d5cbfbe31b94d1de479bba4104edb4f6367be90b5ba8073", + "namingEvidenceSha256": "e895fb82169da29ff4abd9f406ae3d0c133e9d23412f53322ee047e7b74fbb2d", + "namingSemanticSha256": "8ab542be7d62e8bcdc0fa71e96552ed299d702dd06f4b3a8df63a859bffbb266" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "chamfer->mirrored", + "phases": { + "initial": { + "namingEvidenceBytes": 12779, + "namingEvidenceSha256": "f63fc775963630e55847b9b46b0d3e62b085c7a1633cce933930ea4b1df3934c", + "pair": "chamfer->mirrored", + "shape": { + "area": 649.5256668, + "bounds": [ + 0, + 0, + 0, + 12, + 10, + 10 + ], + "edges": 80, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1190.1013333 + } + }, + "reopened": { + "namingEvidenceBytes": 12779, + "namingEvidenceSha256": "f63fc775963630e55847b9b46b0d3e62b085c7a1633cce933930ea4b1df3934c", + "pair": "chamfer->mirrored", + "shape": { + "area": 649.5256668, + "bounds": [ + 0, + 0, + 0, + 12, + 10, + 10 + ], + "edges": 80, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1190.1013333 + } + }, + "resaved": { + "namingEvidenceBytes": 12779, + "namingEvidenceSha256": "f63fc775963630e55847b9b46b0d3e62b085c7a1633cce933930ea4b1df3934c", + "pair": "chamfer->mirrored", + "shape": { + "area": 649.5256668, + "bounds": [ + 0, + 0, + 0, + 12, + 10, + 10 + ], + "edges": 80, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1190.1013333 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-chamfer-multi-transform", + "pair": "chamfer->multi-transform", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "174a5a268c990440fa62f4ec119f35cc7514c7cdb33b8345baf0559b418dac62", + "namingEvidenceSha256": "26d04def78b7bf0927a7ea150b76a55272b5fd4e36b194b3eafbd15894e385a5", + "namingSemanticSha256": "f7c603495e3e668327ba539f721c251fb6362572d4990a714bcfa491e048bec5" + }, + "second": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 58, + "edges": 112, + "vertices": 56, + "volume": 2585.6213333, + "area": 1196.4040506, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1027, + "selectedRecords": 22, + "ambiguousResults": 204, + "historySha256": "6e468bc8381f6e4d17a5413bf4962de8051606c6a7a90d4089b5c12bce10632f", + "namingEvidenceSha256": "9abb2623b8ee2bcf482b28ced5f5e33eb9ddb8a4fcda2f7c9480e751040e79a2", + "namingSemanticSha256": "d87a18b5526680f4c79bfc97e33bfa60378aeff0a1dfb0da35af072d05798c6c" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "multiTranslationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 58, + "edges": 112, + "vertices": 56, + "volume": 2784.9813333, + "area": 1274.529534, + "bounds": [ + -9.0000001, + -1e-7, + -1e-7, + 19.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1027, + "selectedRecords": 22, + "ambiguousResults": 204, + "historySha256": "6e468bc8381f6e4d17a5413bf4962de8051606c6a7a90d4089b5c12bce10632f", + "namingEvidenceSha256": "39fb96629e0b76f8698efce037932078bbc449ed97068d8de4e724048670cdcd", + "namingSemanticSha256": "d87a18b5526680f4c79bfc97e33bfa60378aeff0a1dfb0da35af072d05798c6c" + }, + "restoredEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 58, + "edges": 112, + "vertices": 56, + "volume": 2585.6213333, + "area": 1196.4040506, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1027, + "selectedRecords": 22, + "ambiguousResults": 204, + "historySha256": "6e468bc8381f6e4d17a5413bf4962de8051606c6a7a90d4089b5c12bce10632f", + "namingEvidenceSha256": "58dcbe1a9835c17636ab762cebaf6770630e102e38c313fdefc44adb554833dc", + "namingSemanticSha256": "d87a18b5526680f4c79bfc97e33bfa60378aeff0a1dfb0da35af072d05798c6c" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "chamfer->multi-transform", + "phases": { + "initial": { + "namingEvidenceBytes": 114084, + "namingEvidenceSha256": "9abb2623b8ee2bcf482b28ced5f5e33eb9ddb8a4fcda2f7c9480e751040e79a2", + "pair": "chamfer->multi-transform", + "shape": { + "area": 1196.4040506, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 112, + "faces": 58, + "solids": 1, + "valid": true, + "vertices": 56, + "volume": 2585.6213333 + } + }, + "reopened": { + "namingEvidenceBytes": 114084, + "namingEvidenceSha256": "9abb2623b8ee2bcf482b28ced5f5e33eb9ddb8a4fcda2f7c9480e751040e79a2", + "pair": "chamfer->multi-transform", + "shape": { + "area": 1196.4040506, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 112, + "faces": 58, + "solids": 1, + "valid": true, + "vertices": 56, + "volume": 2585.6213333 + } + }, + "resaved": { + "namingEvidenceBytes": 114084, + "namingEvidenceSha256": "9abb2623b8ee2bcf482b28ced5f5e33eb9ddb8a4fcda2f7c9480e751040e79a2", + "pair": "chamfer->multi-transform", + "shape": { + "area": 1196.4040506, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 112, + "faces": 58, + "solids": 1, + "valid": true, + "vertices": 56, + "volume": 2585.6213333 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-fuse", + "pair": "hole->fuse", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "1d21bc5b9a95b51294c876c3609e920e24ddcb2b71c76490827757195d99f1dd", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 32, + "vertices": 20, + "volume": 1043.5840735, + "area": 716.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 13.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "1a5fc04016eb2ff53827ffc0d8f46f091f7e7d38a9dec12247b15f6bfba90994", + "namingEvidenceSha256": "91e34b16e64e4c8d2b08fa20bd4d5b47b8bcda2d2dcb058ef868b3029ea3b2e5", + "namingSemanticSha256": "d02aa5d31bf060cc44725c06de7c85196645ae483ff6f9a81ce08204c34c9964" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 8, + 7, + 8 + ], + "beforeValue": 8, + "editedValue": 7, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 32, + "vertices": 20, + "volume": 1018.5840735, + "area": 696.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 12.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "1a5fc04016eb2ff53827ffc0d8f46f091f7e7d38a9dec12247b15f6bfba90994", + "namingEvidenceSha256": "ee46e91177d3a9dd407a11dc6237b57f594487c6a13be871a5acfdbfa7acbeaa", + "namingSemanticSha256": "d02aa5d31bf060cc44725c06de7c85196645ae483ff6f9a81ce08204c34c9964" + }, + "restoredEvidence": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 32, + "vertices": 20, + "volume": 1043.5840735, + "area": 716.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 13.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "1a5fc04016eb2ff53827ffc0d8f46f091f7e7d38a9dec12247b15f6bfba90994", + "namingEvidenceSha256": "717ff5389b706d8d166a84139ea80156812bbd5ae537ff436bc6de68b0139c47", + "namingSemanticSha256": "d02aa5d31bf060cc44725c06de7c85196645ae483ff6f9a81ce08204c34c9964" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->fuse", + "phases": { + "initial": { + "namingEvidenceBytes": 7797, + "namingEvidenceSha256": "91e34b16e64e4c8d2b08fa20bd4d5b47b8bcda2d2dcb058ef868b3029ea3b2e5", + "pair": "hole->fuse", + "shape": { + "area": 716.5486678, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 32, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 1043.5840735 + } + }, + "reopened": { + "namingEvidenceBytes": 7797, + "namingEvidenceSha256": "91e34b16e64e4c8d2b08fa20bd4d5b47b8bcda2d2dcb058ef868b3029ea3b2e5", + "pair": "hole->fuse", + "shape": { + "area": 716.5486678, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 32, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 1043.5840735 + } + }, + "resaved": { + "namingEvidenceBytes": 7797, + "namingEvidenceSha256": "91e34b16e64e4c8d2b08fa20bd4d5b47b8bcda2d2dcb058ef868b3029ea3b2e5", + "pair": "hole->fuse", + "shape": { + "area": 716.5486678, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 32, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 1043.5840735 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-cut", + "pair": "hole->cut", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "e99a2f4fb2e10f6024d96778b94316709a8f96e8e843be028e12e1163c4899f1", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 31, + "vertices": 20, + "volume": 904.5840735, + "area": 688.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 36, + "selectedRecords": 6, + "ambiguousResults": 13, + "historySha256": "d736723e7b66e9da212d502514523ed29d36c0dcd5217c45fccd45d9615b9a48", + "namingEvidenceSha256": "a115b41afa314ebf3c3737300747cb8e01c3d31ce5b689f1d49223eb91791b95", + "namingSemanticSha256": "5638e001174c587df81edaae7059e4eb113c5616b428ee84b5850de8dc4c58d3" + }, + "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": 11, + "edges": 27, + "vertices": 18, + "volume": 941.5840735, + "area": 674.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 22, + "selectedRecords": 2, + "ambiguousResults": 8, + "historySha256": "4c7f022272b945258c91787fcce83c42dd50e9790325e1d47d722cdcaf166a6e", + "namingEvidenceSha256": "abd8a7fcc9e23a70009f4ad396108533cd2f2ae8e41d855d53991a8bd6b0d288", + "namingSemanticSha256": "314f55e5417b698e0d0d2aac9f8ac1f1109dfa8c23682b195a2e440ecaf6246d" + }, + "restoredEvidence": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 31, + "vertices": 20, + "volume": 904.5840735, + "area": 688.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 36, + "selectedRecords": 6, + "ambiguousResults": 13, + "historySha256": "d736723e7b66e9da212d502514523ed29d36c0dcd5217c45fccd45d9615b9a48", + "namingEvidenceSha256": "31c97218fbf8e6391846532cdc1b56e5e537e36360eb1feebfb48341757218b2", + "namingSemanticSha256": "5638e001174c587df81edaae7059e4eb113c5616b428ee84b5850de8dc4c58d3" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->cut", + "phases": { + "initial": { + "namingEvidenceBytes": 6537, + "namingEvidenceSha256": "a115b41afa314ebf3c3737300747cb8e01c3d31ce5b689f1d49223eb91791b95", + "pair": "hole->cut", + "shape": { + "area": 688.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 31, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 904.5840735 + } + }, + "reopened": { + "namingEvidenceBytes": 6537, + "namingEvidenceSha256": "a115b41afa314ebf3c3737300747cb8e01c3d31ce5b689f1d49223eb91791b95", + "pair": "hole->cut", + "shape": { + "area": 688.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 31, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 904.5840735 + } + }, + "resaved": { + "namingEvidenceBytes": 6537, + "namingEvidenceSha256": "a115b41afa314ebf3c3737300747cb8e01c3d31ce5b689f1d49223eb91791b95", + "pair": "hole->cut", + "shape": { + "area": 688.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 31, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 904.5840735 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-common", + "pair": "hole->common", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "0a838043fb2e6464aa0af9a8d96063278306d9ecb00df734b3f952fea0f55c86", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "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": [ + 6.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 140, + "selectedRecords": 3, + "ambiguousResults": 10, + "historySha256": "3fc95684319273a9b419c3e1ac5f7efd5b34714594f5dd109e912af2b91f3e88", + "namingEvidenceSha256": "7202e4312a4d3bd1ded71497200704f1d4255ea09c0b64967595e58f698c2ae2", + "namingSemanticSha256": "eb747e1dba1aa909dd444536977aa25c44fe6d02779c49126e15eb0a0b1ea289" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 7, + 6, + 7 + ], + "beforeValue": 7, + "editedValue": 6, + "restoredValue": 7, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "common", + "builder": "BRepAlgoAPI_Common", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 100, + "area": 130, + "bounds": [ + 5.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 149, + "selectedRecords": 4, + "ambiguousResults": 12, + "historySha256": "f40cffe9bf35dacc92ff13f1e929a1e2640058fec7b599bc1e8d4284ca4d9108", + "namingEvidenceSha256": "318ce73bbfbb7ea708a35464815ebde33e6c7085fdc86e7c7aad3faac1d7792f", + "namingSemanticSha256": "3dff7057dac7e22585ac447a5f8feb60a52b31f435bda0dde54b9adc4b47f54a" + }, + "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": [ + 6.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 140, + "selectedRecords": 3, + "ambiguousResults": 10, + "historySha256": "3fc95684319273a9b419c3e1ac5f7efd5b34714594f5dd109e912af2b91f3e88", + "namingEvidenceSha256": "d251e5454fd736ae249696d0b52ac44f2ca09945463ac9b6cb7531b85f69547b", + "namingSemanticSha256": "eb747e1dba1aa909dd444536977aa25c44fe6d02779c49126e15eb0a0b1ea289" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->common", + "phases": { + "initial": { + "namingEvidenceBytes": 4531, + "namingEvidenceSha256": "7202e4312a4d3bd1ded71497200704f1d4255ea09c0b64967595e58f698c2ae2", + "pair": "hole->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 75 + } + }, + "reopened": { + "namingEvidenceBytes": 4531, + "namingEvidenceSha256": "7202e4312a4d3bd1ded71497200704f1d4255ea09c0b64967595e58f698c2ae2", + "pair": "hole->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 75 + } + }, + "resaved": { + "namingEvidenceBytes": 4531, + "namingEvidenceSha256": "7202e4312a4d3bd1ded71497200704f1d4255ea09c0b64967595e58f698c2ae2", + "pair": "hole->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 75 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-rotate", + "pair": "hole->rotate", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "9f8cec450c66b21d9a7720f198d03f84d38643bd3a2304456a5568c5da081bc7", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -2.5881906, + -1e-7, + -1e-7, + 9.6592584, + 12.2474488, + 10.0000001 + ] + }, + "historyRecords": 97, + "selectedRecords": 7, + "ambiguousResults": 25, + "historySha256": "a42f7075c4be94caad7694af256ddbb6ff9bf7566e6694011b0c5b86f4380922", + "namingEvidenceSha256": "99df97fe6a3a506faebfccc0fc0ead922e73212884a0923feed1c5c68e0da8a4", + "namingSemanticSha256": "07b36ea0204d5bff3e06607b0d369fa84fcb12faae5f8105127d0f19654a0697" + }, + "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": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -3.8268344, + -1e-7, + -1e-7, + 9.2387954, + 13.0656297, + 10.0000001 + ] + }, + "historyRecords": 97, + "selectedRecords": 7, + "ambiguousResults": 25, + "historySha256": "a42f7075c4be94caad7694af256ddbb6ff9bf7566e6694011b0c5b86f4380922", + "namingEvidenceSha256": "60558722958db6f043e0b1536e17d14cce4d7ac93e08293071948fadb4f3f7fe", + "namingSemanticSha256": "07b36ea0204d5bff3e06607b0d369fa84fcb12faae5f8105127d0f19654a0697" + }, + "restoredEvidence": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -2.5881906, + -1e-7, + -1e-7, + 9.6592584, + 12.2474488, + 10.0000001 + ] + }, + "historyRecords": 97, + "selectedRecords": 7, + "ambiguousResults": 25, + "historySha256": "a42f7075c4be94caad7694af256ddbb6ff9bf7566e6694011b0c5b86f4380922", + "namingEvidenceSha256": "ae70eb3a8126b9369ab7ab4b6f726b7c30c952e92391aa199fcffa67e3b63e91", + "namingSemanticSha256": "07b36ea0204d5bff3e06607b0d369fa84fcb12faae5f8105127d0f19654a0697" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->rotate", + "phases": { + "initial": { + "namingEvidenceBytes": 12303, + "namingEvidenceSha256": "99df97fe6a3a506faebfccc0fc0ead922e73212884a0923feed1c5c68e0da8a4", + "pair": "hole->rotate", + "shape": { + "area": 656.5486678, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "reopened": { + "namingEvidenceBytes": 12303, + "namingEvidenceSha256": "99df97fe6a3a506faebfccc0fc0ead922e73212884a0923feed1c5c68e0da8a4", + "pair": "hole->rotate", + "shape": { + "area": 656.5486678, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "resaved": { + "namingEvidenceBytes": 12303, + "namingEvidenceSha256": "99df97fe6a3a506faebfccc0fc0ead922e73212884a0923feed1c5c68e0da8a4", + "pair": "hole->rotate", + "shape": { + "area": 656.5486678, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-pad", + "pair": "hole->pad", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "0d7e508fc41e7bafc175c598476027d8c4592ba3c12c9bd741cdedd80b5f594c", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "length", + "trajectory": [ + 5, + 7.5, + 5 + ], + "stable": true, + "attempts": [ + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 7.5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "nativeTypeId": "PartDesign::Pad", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Body", + "typeId": "PartDesign::Body" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + }, + { + "name": "PairResult", + "typeId": "PartDesign::Pad" + } + ], + "parameter": { + "name": "length", + "value": 5 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "FeatureExtrusion: Length: Could not extrude the sketch!" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "PartDesign::Pad", + "operation": "pad", + "pair": "hole->pad", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-hole-pocket", + "pair": "hole->pocket", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "72f03958601948935e919b1cd9668b1be4320e35bd94451a9880683fb2569b6f", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 10, + "edges": 24, + "vertices": 16, + "volume": 938.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 3, + "ambiguousResults": 9, + "historySha256": "346297e1dd9c00586d1219991d5047f834c7066472e0ba08f471003d21aa1eae", + "namingEvidenceSha256": "e47fa1222a5aa2ea204575c19c8c952142012fa1fcdd467c620ed884746b6706", + "namingSemanticSha256": "81538dd4ed2f0c55c0abf6c9f543a8f97274d82b1ec9c6249e191b60cf989076" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "length", + "trajectory": [ + 5, + 4, + 5 + ], + "beforeValue": 5, + "editedValue": 4, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 10, + "edges": 24, + "vertices": 16, + "volume": 944.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 3, + "ambiguousResults": 9, + "historySha256": "346297e1dd9c00586d1219991d5047f834c7066472e0ba08f471003d21aa1eae", + "namingEvidenceSha256": "4b541ec4df461139e9e9ea3096e579b50e6c4ed8c4c99ae84bbf3f0d416c49ff", + "namingSemanticSha256": "81538dd4ed2f0c55c0abf6c9f543a8f97274d82b1ec9c6249e191b60cf989076" + }, + "restoredEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 10, + "edges": 24, + "vertices": 16, + "volume": 938.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 3, + "ambiguousResults": 9, + "historySha256": "346297e1dd9c00586d1219991d5047f834c7066472e0ba08f471003d21aa1eae", + "namingEvidenceSha256": "2cdca1505bc3832fd5ab2ba794800bf5b656f8ce8a1e1524508f17bbd7225659", + "namingSemanticSha256": "81538dd4ed2f0c55c0abf6c9f543a8f97274d82b1ec9c6249e191b60cf989076" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->pocket", + "phases": { + "initial": { + "namingEvidenceBytes": 4336, + "namingEvidenceSha256": "e47fa1222a5aa2ea204575c19c8c952142012fa1fcdd467c620ed884746b6706", + "pair": "hole->pocket", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 938.5840735 + } + }, + "reopened": { + "namingEvidenceBytes": 4336, + "namingEvidenceSha256": "e47fa1222a5aa2ea204575c19c8c952142012fa1fcdd467c620ed884746b6706", + "pair": "hole->pocket", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 938.5840735 + } + }, + "resaved": { + "namingEvidenceBytes": 4336, + "namingEvidenceSha256": "e47fa1222a5aa2ea204575c19c8c952142012fa1fcdd467c620ed884746b6706", + "pair": "hole->pocket", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 938.5840735 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-loft", + "pair": "hole->loft", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "1e2350f3b5f531194a4c14eddaddb064f0efcea66c34209c73d5b819bea47941", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "ruled", + "trajectory": [ + false, + true, + false + ], + "kernelAttempts": [ + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": true, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + } + ] + }, + "inputShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "nativeTypeId": "Part::Loft", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Loft" + } + ], + "parameter": { + "name": "ruled", + "value": false + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Profile shape is not a single vertex, edge, wire nor face." + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Loft", + "operation": "loft", + "pair": "hole->loft", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-hole-pipe", + "pair": "hole->pipe", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "885f9a7720d24d22973d5b90f3a04e1581bf7106e1f8c53cac694d7045477761", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "spineLength", + "trajectory": [ + 15, + 12, + 15 + ], + "kernelAttempts": [ + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 25.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 12, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 440, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 22.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 25.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "spine": { + "name": "Spine", + "subelements": [], + "typeId": "Part::Feature" + } + }, + "inputShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "nativeTypeId": "Part::Sweep", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Spine", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Sweep" + } + ], + "parameter": { + "name": "spineLength", + "value": 15 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "A fatal error occurred when making the sweep" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Sweep", + "operation": "pipe", + "pair": "hole->pipe", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-hole-revolution", + "pair": "hole->revolution", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "8f5f7895cbe0f6b00e78ed70dcbd0340f001d6c9076eb2c58990d98e98e98bfa", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "angle", + "trajectory": [ + 360, + 270, + 360 + ], + "stable": true, + "attempts": [ + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 270, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "nativeTypeId": "Part::Revolution", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Revolution" + } + ], + "parameter": { + "name": "angle", + "value": 360 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Solids are not Processed" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Revolution", + "operation": "revolution", + "pair": "hole->revolution", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "d3a3dd337d46b2959491c828a3343ece65feabf05fe9ae0d74f57683b2b5c573", + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-hole-groove", + "pair": "hole->groove", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "ca8a4a757dc5ead522bb2dc5063dd826821eeee148586002563c8116a65a05d3", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 27, + "vertices": 18, + "volume": 963.8716845, + "area": 663.1150384, + "bounds": [ + -2e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "c2339e5a5661f0cfaeb92afc74d62ba318b0ceba059d5c362625dc37e030872c", + "namingEvidenceSha256": "05e968b8e07be03cd2eb101cc7b15be558eec028d1cb7b80e845fe875cea81ae", + "namingSemanticSha256": "dd868eabe25a2881291c4a4c40113cca9dce249a1f769d3eca485f8115a98418" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 360, + 180, + 360 + ], + "beforeValue": 360, + "editedValue": 180, + "restoredValue": 360, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 8, + "edges": 19, + "vertices": 14, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 56, + "selectedRecords": 1, + "ambiguousResults": 5, + "historySha256": "35b7d1faa5aa355f4da98ab8456b0bb04d0b052cba5d4ce8ff478dd3affa0b53", + "namingEvidenceSha256": "d787c5101d2272cd7352d45e0237e3bdf3d0b7510a13ba78fcff7d6f23a8c1ec", + "namingSemanticSha256": "8eac24ed9b7ea4453c30f3a457e71aa9d6ae30e4d539bb30178010c65752e3c3" + }, + "restoredEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 27, + "vertices": 18, + "volume": 963.8716845, + "area": 663.1150384, + "bounds": [ + -2e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "c2339e5a5661f0cfaeb92afc74d62ba318b0ceba059d5c362625dc37e030872c", + "namingEvidenceSha256": "05e968b8e07be03cd2eb101cc7b15be558eec028d1cb7b80e845fe875cea81ae", + "namingSemanticSha256": "dd868eabe25a2881291c4a4c40113cca9dce249a1f769d3eca485f8115a98418" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->groove", + "phases": { + "initial": { + "namingEvidenceBytes": 4764, + "namingEvidenceSha256": "05e968b8e07be03cd2eb101cc7b15be558eec028d1cb7b80e845fe875cea81ae", + "pair": "hole->groove", + "shape": { + "area": 663.1150384, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 27, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 963.8716845 + } + }, + "reopened": { + "namingEvidenceBytes": 4764, + "namingEvidenceSha256": "05e968b8e07be03cd2eb101cc7b15be558eec028d1cb7b80e845fe875cea81ae", + "pair": "hole->groove", + "shape": { + "area": 663.1150384, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 27, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 963.8716845 + } + }, + "resaved": { + "namingEvidenceBytes": 4764, + "namingEvidenceSha256": "05e968b8e07be03cd2eb101cc7b15be558eec028d1cb7b80e845fe875cea81ae", + "pair": "hole->groove", + "shape": { + "area": 663.1150384, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 27, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 963.8716845 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-fillet", + "pair": "hole->fillet", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "5b0fd30285fae94acb180f8017c891011d42abdaacbb47835b11e7dd11cf5032", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 63, + "vertices": 28, + "volume": 964.0793949, + "area": 633.7505843, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 173, + "selectedRecords": 7, + "ambiguousResults": 23, + "historySha256": "c2b44cccef9aed3a614702f7c84fac2598ea72782ddb94987d457b1bacba6bf2", + "namingEvidenceSha256": "6313804f6b60268b3d798a3fc2cf6a7afd6bd05ed5e91cdeaf870e1dd1097c85", + "namingSemanticSha256": "56ceeff9e418231d8afbefa7ad6380783f25a5f822e3491b54b9e13e0d765908" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "beforeValue": 0.4, + "editedValue": 0.6, + "restoredValue": 0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 63, + "vertices": 28, + "volume": 958.5016007, + "area": 622.322372, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 173, + "selectedRecords": 7, + "ambiguousResults": 23, + "historySha256": "c2b44cccef9aed3a614702f7c84fac2598ea72782ddb94987d457b1bacba6bf2", + "namingEvidenceSha256": "586aa93d9551d80f9aba3ded0a1aa658113b0b2adeb0f3a86a466ee96594540d", + "namingSemanticSha256": "56ceeff9e418231d8afbefa7ad6380783f25a5f822e3491b54b9e13e0d765908" + }, + "restoredEvidence": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 63, + "vertices": 28, + "volume": 964.0793949, + "area": 633.7505843, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 173, + "selectedRecords": 7, + "ambiguousResults": 23, + "historySha256": "c2b44cccef9aed3a614702f7c84fac2598ea72782ddb94987d457b1bacba6bf2", + "namingEvidenceSha256": "34db603ca87fcf6b60567e8df20bbfe3488b4acf804703e243160457f127594e", + "namingSemanticSha256": "56ceeff9e418231d8afbefa7ad6380783f25a5f822e3491b54b9e13e0d765908" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->fillet", + "phases": { + "initial": { + "namingEvidenceBytes": 12058, + "namingEvidenceSha256": "6313804f6b60268b3d798a3fc2cf6a7afd6bd05ed5e91cdeaf870e1dd1097c85", + "pair": "hole->fillet", + "shape": { + "area": 633.7505843, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 63, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 964.0793949 + } + }, + "reopened": { + "namingEvidenceBytes": 12058, + "namingEvidenceSha256": "6313804f6b60268b3d798a3fc2cf6a7afd6bd05ed5e91cdeaf870e1dd1097c85", + "pair": "hole->fillet", + "shape": { + "area": 633.7505843, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 63, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 964.0793949 + } + }, + "resaved": { + "namingEvidenceBytes": 12058, + "namingEvidenceSha256": "6313804f6b60268b3d798a3fc2cf6a7afd6bd05ed5e91cdeaf870e1dd1097c85", + "pair": "hole->fillet", + "shape": { + "area": 633.7505843, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 63, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 964.0793949 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-chamfer", + "pair": "hole->chamfer", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "c8c5b4d578dadcaad617d59e556ccf13cb9bba4029d5df391d571ebbd0aad108", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 55, + "vertices": 28, + "volume": 958.1860559, + "area": 625.4207803, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 173, + "selectedRecords": 7, + "ambiguousResults": 23, + "historySha256": "5feb72609bdf4d73508ba7deb3a856acdaa722b739cee1e502e7a9265182bad3", + "namingEvidenceSha256": "b92826391d34a2cafa93fa3fc33e24294325b7ebe94d521b985689bc15127775", + "namingSemanticSha256": "ca9ce4b8e6693af348d0c46bd8d29a443e7b99133d430b927e7f50034660d867" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "distance", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "beforeValue": 0.4, + "editedValue": 0.6, + "restoredValue": 0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 55, + "vertices": 28, + "volume": 945.4217374, + "area": 609.8075956, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 173, + "selectedRecords": 7, + "ambiguousResults": 23, + "historySha256": "5feb72609bdf4d73508ba7deb3a856acdaa722b739cee1e502e7a9265182bad3", + "namingEvidenceSha256": "38a046b24f52e7d14c5ddf09c94455f9011b46252cc54689fa0fa781fd86e9c5", + "namingSemanticSha256": "ca9ce4b8e6693af348d0c46bd8d29a443e7b99133d430b927e7f50034660d867" + }, + "restoredEvidence": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 55, + "vertices": 28, + "volume": 958.1860559, + "area": 625.4207803, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 173, + "selectedRecords": 7, + "ambiguousResults": 23, + "historySha256": "5feb72609bdf4d73508ba7deb3a856acdaa722b739cee1e502e7a9265182bad3", + "namingEvidenceSha256": "0f485bcb158805d26c23c88caf829437a2e9971b93b923af2370b5090bd7d4e6", + "namingSemanticSha256": "ca9ce4b8e6693af348d0c46bd8d29a443e7b99133d430b927e7f50034660d867" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->chamfer", + "phases": { + "initial": { + "namingEvidenceBytes": 12153, + "namingEvidenceSha256": "b92826391d34a2cafa93fa3fc33e24294325b7ebe94d521b985689bc15127775", + "pair": "hole->chamfer", + "shape": { + "area": 625.4207803, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 55, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 958.1860559 + } + }, + "reopened": { + "namingEvidenceBytes": 12153, + "namingEvidenceSha256": "b92826391d34a2cafa93fa3fc33e24294325b7ebe94d521b985689bc15127775", + "pair": "hole->chamfer", + "shape": { + "area": 625.4207803, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 55, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 958.1860559 + } + }, + "resaved": { + "namingEvidenceBytes": 12153, + "namingEvidenceSha256": "b92826391d34a2cafa93fa3fc33e24294325b7ebe94d521b985689bc15127775", + "pair": "hole->chamfer", + "shape": { + "area": 625.4207803, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 55, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 958.1860559 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-hole", + "pair": "hole->hole", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "24fe71a62fb63c7923d7eee243c0a5bd778007c2066d5bd142a206173ca29dec", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 8, + "edges": 18, + "vertices": 12, + "volume": 937.1681469, + "area": 713.0973355, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "71fc5c19d47e1a0b9d8779dd1b655676afb9e29f752f2a6f10af15a747bcee52", + "namingEvidenceSha256": "daeee873b751f90c3fbb9f3981525213453d8c480995bb2dc0f7c03a4035f128", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 1, + 1.5, + 1 + ], + "beforeValue": 1, + "editedValue": 1.5, + "restoredValue": 1, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 8, + "edges": 18, + "vertices": 12, + "volume": 897.8982388, + "area": 736.6592804, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "71fc5c19d47e1a0b9d8779dd1b655676afb9e29f752f2a6f10af15a747bcee52", + "namingEvidenceSha256": "cbaeae9875b4dc486274097ebaf3b5ed93652e04e226b630733335effba6aba9", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "restoredEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 8, + "edges": 18, + "vertices": 12, + "volume": 937.1681469, + "area": 713.0973355, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "71fc5c19d47e1a0b9d8779dd1b655676afb9e29f752f2a6f10af15a747bcee52", + "namingEvidenceSha256": "eaec73c79df1fc5d3c2e6cccfc370b53dfd50c4f900e624e7bc0fcada3e8ee43", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->hole", + "phases": { + "initial": { + "namingEvidenceBytes": 1511, + "namingEvidenceSha256": "daeee873b751f90c3fbb9f3981525213453d8c480995bb2dc0f7c03a4035f128", + "pair": "hole->hole", + "shape": { + "area": 713.0973355, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 18, + "faces": 8, + "solids": 1, + "valid": true, + "vertices": 12, + "volume": 937.1681469 + } + }, + "reopened": { + "namingEvidenceBytes": 1511, + "namingEvidenceSha256": "daeee873b751f90c3fbb9f3981525213453d8c480995bb2dc0f7c03a4035f128", + "pair": "hole->hole", + "shape": { + "area": 713.0973355, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 18, + "faces": 8, + "solids": 1, + "valid": true, + "vertices": 12, + "volume": 937.1681469 + } + }, + "resaved": { + "namingEvidenceBytes": 1511, + "namingEvidenceSha256": "daeee873b751f90c3fbb9f3981525213453d8c480995bb2dc0f7c03a4035f128", + "pair": "hole->hole", + "shape": { + "area": 713.0973355, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 18, + "faces": 8, + "solids": 1, + "valid": true, + "vertices": 12, + "volume": 937.1681469 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-draft", + "pair": "hole->draft", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "664e0e5d2f33811ed056e3f61a86c3e14f85b7260829d34fbe1a5ee7bbeb88af", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 924.8397417, + "area": 639.4329188, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "7e449b85053025972825cb23c7f4c61378b619b6fcb93e5256bc588a987e5599", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 5, + 8, + 5 + ], + "beforeValue": 5, + "editedValue": 8, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 898.3136561, + "area": 629.4232581, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "3ed3a59fbd0b40cc44008de092d1c9d14f0c4106b2563114b0b99a48c0e78aae", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + }, + "restoredEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 924.8397417, + "area": 639.4329188, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "7e449b85053025972825cb23c7f4c61378b619b6fcb93e5256bc588a987e5599", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->draft", + "phases": { + "initial": { + "namingEvidenceBytes": 2498, + "namingEvidenceSha256": "7e449b85053025972825cb23c7f4c61378b619b6fcb93e5256bc588a987e5599", + "pair": "hole->draft", + "shape": { + "area": 639.4329188, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 924.8397417 + } + }, + "reopened": { + "namingEvidenceBytes": 2498, + "namingEvidenceSha256": "7e449b85053025972825cb23c7f4c61378b619b6fcb93e5256bc588a987e5599", + "pair": "hole->draft", + "shape": { + "area": 639.4329188, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 924.8397417 + } + }, + "resaved": { + "namingEvidenceBytes": 2498, + "namingEvidenceSha256": "7e449b85053025972825cb23c7f4c61378b619b6fcb93e5256bc588a987e5599", + "pair": "hole->draft", + "shape": { + "area": 639.4329188, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 924.8397417 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-thickness", + "pair": "hole->thickness", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "dae290808d9d5c02783a369479fed3f61c3462444c167f70544174c9b1ddd718", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 30, + "vertices": 20, + "volume": 212.6892722, + "area": 1078.4410513, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 55, + "selectedRecords": 7, + "ambiguousResults": 10, + "historySha256": "3876114a9e6e6ec37ccbd24459315a2f73abca30813912ef667b16007fe94bf8", + "namingEvidenceSha256": "49370f179042dd5ade923fe68ff6cd1acca355fefa4760eec8c11d74b9464141", + "namingSemanticSha256": "dfbdcaa180e13415749d26cc9c54ab2e397742dc0f0bd82aac4dc4047f6a81d2" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "offset", + "trajectory": [ + -0.4, + -0.6, + -0.4 + ], + "beforeValue": -0.4, + "editedValue": -0.6, + "restoredValue": -0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 30, + "vertices": 20, + "volume": 311.4218728, + "area": 1059.8109625, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 55, + "selectedRecords": 7, + "ambiguousResults": 10, + "historySha256": "3876114a9e6e6ec37ccbd24459315a2f73abca30813912ef667b16007fe94bf8", + "namingEvidenceSha256": "b0070ef2090ba96de209c5158d7445cc8089c9b40c0424afcdb29fbde53640d3", + "namingSemanticSha256": "dfbdcaa180e13415749d26cc9c54ab2e397742dc0f0bd82aac4dc4047f6a81d2" + }, + "restoredEvidence": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 30, + "vertices": 20, + "volume": 212.6892722, + "area": 1078.4410513, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 55, + "selectedRecords": 7, + "ambiguousResults": 10, + "historySha256": "3876114a9e6e6ec37ccbd24459315a2f73abca30813912ef667b16007fe94bf8", + "namingEvidenceSha256": "49370f179042dd5ade923fe68ff6cd1acca355fefa4760eec8c11d74b9464141", + "namingSemanticSha256": "dfbdcaa180e13415749d26cc9c54ab2e397742dc0f0bd82aac4dc4047f6a81d2" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->thickness", + "phases": { + "initial": { + "namingEvidenceBytes": 8036, + "namingEvidenceSha256": "49370f179042dd5ade923fe68ff6cd1acca355fefa4760eec8c11d74b9464141", + "pair": "hole->thickness", + "shape": { + "area": 1078.4410513, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 30, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 212.6892722 + } + }, + "reopened": { + "namingEvidenceBytes": 8036, + "namingEvidenceSha256": "49370f179042dd5ade923fe68ff6cd1acca355fefa4760eec8c11d74b9464141", + "pair": "hole->thickness", + "shape": { + "area": 1078.4410513, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 30, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 212.6892722 + } + }, + "resaved": { + "namingEvidenceBytes": 8036, + "namingEvidenceSha256": "49370f179042dd5ade923fe68ff6cd1acca355fefa4760eec8c11d74b9464141", + "pair": "hole->thickness", + "shape": { + "area": 1078.4410513, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 30, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 212.6892722 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-linear-pattern", + "pair": "hole->linear-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "82c48d2c59f55cb2a9c8283ac18544168677d0261fe1149b34cf0b70f2b1f47a", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 34, + "vertices": 20, + "volume": 1737.1681469, + "area": 1033.0973355, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "96c574e2885d58fd077abbf03a9c665eb4d3451dbb9d35286403ea93d832d80e", + "namingEvidenceSha256": "5d31d94ff1b79a488aacf25fc4b6a4a0e6b6feb2bcec6b68d656818a136dd902", + "namingSemanticSha256": "92810b52074e178802b5bc917ad81fbdc52cbcb94cb61e875a8f9f928817ab06" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "translationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 34, + "vertices": 20, + "volume": 1837.1681469, + "area": 1073.0973355, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 19.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "96c574e2885d58fd077abbf03a9c665eb4d3451dbb9d35286403ea93d832d80e", + "namingEvidenceSha256": "acf268fa5f989ad123745a0111acb140fff0b40f68b5c307eaa4e25dce74d291", + "namingSemanticSha256": "92810b52074e178802b5bc917ad81fbdc52cbcb94cb61e875a8f9f928817ab06" + }, + "restoredEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 34, + "vertices": 20, + "volume": 1737.1681469, + "area": 1033.0973355, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "96c574e2885d58fd077abbf03a9c665eb4d3451dbb9d35286403ea93d832d80e", + "namingEvidenceSha256": "a9051fae7baaf7c934090bab32ac935b29779322a2da90f369c5c97b54fd9bbf", + "namingSemanticSha256": "92810b52074e178802b5bc917ad81fbdc52cbcb94cb61e875a8f9f928817ab06" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->linear-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 7199, + "namingEvidenceSha256": "5d31d94ff1b79a488aacf25fc4b6a4a0e6b6feb2bcec6b68d656818a136dd902", + "pair": "hole->linear-pattern", + "shape": { + "area": 1033.0973355, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 34, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 1737.1681469 + } + }, + "reopened": { + "namingEvidenceBytes": 7199, + "namingEvidenceSha256": "5d31d94ff1b79a488aacf25fc4b6a4a0e6b6feb2bcec6b68d656818a136dd902", + "pair": "hole->linear-pattern", + "shape": { + "area": 1033.0973355, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 34, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 1737.1681469 + } + }, + "resaved": { + "namingEvidenceBytes": 7199, + "namingEvidenceSha256": "5d31d94ff1b79a488aacf25fc4b6a4a0e6b6feb2bcec6b68d656818a136dd902", + "pair": "hole->linear-pattern", + "shape": { + "area": 1033.0973355, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 34, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 1737.1681469 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-polar-pattern", + "pair": "hole->polar-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "4468b1ad4e1dd0280321c5f4eba5a1d7ae5b94f91a987e50ad14f4307d8875e1", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 30, + "vertices": 20, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 96, + "selectedRecords": 8, + "ambiguousResults": 13, + "historySha256": "2153cc0e0436ffe48811276fd1c9cc05ec609f9dfcc7fc3ba82df1e847a63b95", + "namingEvidenceSha256": "f773ce341fbd00ebe5433de883263b5c56b0570873256b12f748f2fe58821ce2", + "namingSemanticSha256": "e9d5f7c70767f89a7b3474decbb283b45f505921351e8c40eb3a8161ea7878fc" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 30, + 45, + 30 + ], + "beforeValue": 30, + "editedValue": 45, + "restoredValue": 30, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 21, + "edges": 51, + "vertices": 28, + "volume": 1554.3705111, + "area": 930.8632428, + "bounds": [ + -7.071068, + -1e-7, + -1e-7, + 10.0000001, + 14.1421358, + 10.0000001 + ] + }, + "historyRecords": 127, + "selectedRecords": 11, + "ambiguousResults": 21, + "historySha256": "36c7f008ca701b9a38b3554100a49bedc2ee1ac7990145ff4a40b831a513d0ab", + "namingEvidenceSha256": "13247ad9a89461a64cfe493ae1a8f6ed06a3bf1b549d6304b31af66eeba338cd", + "namingSemanticSha256": "994804f168263ccd2783e5af625f7adf6eec6a8180980f9542d940d4eac540b7" + }, + "restoredEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 30, + "vertices": 20, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 96, + "selectedRecords": 8, + "ambiguousResults": 13, + "historySha256": "2153cc0e0436ffe48811276fd1c9cc05ec609f9dfcc7fc3ba82df1e847a63b95", + "namingEvidenceSha256": "f69ecb1113e7b75d413ec35dca65a4315138423926cba93e25a27b585ecd6953", + "namingSemanticSha256": "e9d5f7c70767f89a7b3474decbb283b45f505921351e8c40eb3a8161ea7878fc" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->polar-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 8275, + "namingEvidenceSha256": "f773ce341fbd00ebe5433de883263b5c56b0570873256b12f748f2fe58821ce2", + "pair": "hole->polar-pattern", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 30, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 1422.6497308 + } + }, + "reopened": { + "namingEvidenceBytes": 8275, + "namingEvidenceSha256": "f773ce341fbd00ebe5433de883263b5c56b0570873256b12f748f2fe58821ce2", + "pair": "hole->polar-pattern", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 30, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 1422.6497308 + } + }, + "resaved": { + "namingEvidenceBytes": 8275, + "namingEvidenceSha256": "f773ce341fbd00ebe5433de883263b5c56b0570873256b12f748f2fe58821ce2", + "pair": "hole->polar-pattern", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 30, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 1422.6497308 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-mirrored", + "pair": "hole->mirrored", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "8d67c4089f701cd71a3f43f714060fcd37954f5be6f7be8120181cab5e45068f", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 18, + "edges": 32, + "vertices": 18, + "volume": 1200, + "area": 680, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 12.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 108, + "selectedRecords": 10, + "ambiguousResults": 16, + "historySha256": "4a2e9e672cacfb4776fb51d2ffd010b3786d52ca56aa5b2a058bfbec2f5418b7", + "namingEvidenceSha256": "ff14b8f04dbd83c51e4f16c38e0f84018b07260981654c3d82f717cfb533a829", + "namingSemanticSha256": "34b47bcabeee6d1689ae8ba0a3ef3ca9bf6c6d5fc0db13c667c5194628bfd459" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "planeOriginX", + "trajectory": [ + 6, + 7, + 6 + ], + "beforeValue": 6, + "editedValue": 7, + "restoredValue": 6, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 18, + "edges": 40, + "vertices": 24, + "volume": 1400, + "area": 760, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 14.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 100, + "selectedRecords": 10, + "ambiguousResults": 18, + "historySha256": "1195e185c6538b989e02d27145420af98785a76bfb79d0b569f304676f297136", + "namingEvidenceSha256": "54d856c75433fd3d286d7270fd5d1bf38c35b834bcda8f974ab26e4505a6fd01", + "namingSemanticSha256": "60e77764ba802107c9e022db8733e0cb25c21c8c1f72c94abdd4e39916c6a9d7" + }, + "restoredEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 18, + "edges": 32, + "vertices": 18, + "volume": 1200, + "area": 680, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 12.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 108, + "selectedRecords": 10, + "ambiguousResults": 16, + "historySha256": "4a2e9e672cacfb4776fb51d2ffd010b3786d52ca56aa5b2a058bfbec2f5418b7", + "namingEvidenceSha256": "fc6cf43f541fec6ec4792dd3c0da6edfe609b846e2cbdae370def0e9f27b7657", + "namingSemanticSha256": "34b47bcabeee6d1689ae8ba0a3ef3ca9bf6c6d5fc0db13c667c5194628bfd459" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->mirrored", + "phases": { + "initial": { + "namingEvidenceBytes": 9465, + "namingEvidenceSha256": "ff14b8f04dbd83c51e4f16c38e0f84018b07260981654c3d82f717cfb533a829", + "pair": "hole->mirrored", + "shape": { + "area": 680, + "bounds": [ + 0, + 0, + 0, + 12, + 10, + 10 + ], + "edges": 32, + "faces": 18, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1200 + } + }, + "reopened": { + "namingEvidenceBytes": 9465, + "namingEvidenceSha256": "ff14b8f04dbd83c51e4f16c38e0f84018b07260981654c3d82f717cfb533a829", + "pair": "hole->mirrored", + "shape": { + "area": 680, + "bounds": [ + 0, + 0, + 0, + 12, + 10, + 10 + ], + "edges": 32, + "faces": 18, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1200 + } + }, + "resaved": { + "namingEvidenceBytes": 9465, + "namingEvidenceSha256": "ff14b8f04dbd83c51e4f16c38e0f84018b07260981654c3d82f717cfb533a829", + "pair": "hole->mirrored", + "shape": { + "area": 680, + "bounds": [ + 0, + 0, + 0, + 12, + 10, + 10 + ], + "edges": 32, + "faces": 18, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1200 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-hole-multi-transform", + "pair": "hole->multi-transform", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "e3487d78f8688534a326d3d17590df256734c7e8df07b79dc5b73a3beb896513", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "second": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 56, + "vertices": 32, + "volume": 2505.7522204, + "area": 1409.6460033, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 441, + "selectedRecords": 26, + "ambiguousResults": 88, + "historySha256": "1f10c95a00ed6610b6d698414bd96b0e48bfa103d4ebe6cd84905c32e2b47b3b", + "namingEvidenceSha256": "a4b7e760b9c952b38bfbc4900fcfc8aee3c01456511eeecc623b4037acb2655e", + "namingSemanticSha256": "d8c250a8d4018548a9a6a01346ae4ca990ddc0e0e1e068c01dd31ddad3db0c29" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "multiTranslationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 56, + "vertices": 32, + "volume": 2705.7522204, + "area": 1489.6460033, + "bounds": [ + -9.0000001, + -1e-7, + -1e-7, + 19.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 441, + "selectedRecords": 26, + "ambiguousResults": 88, + "historySha256": "1f10c95a00ed6610b6d698414bd96b0e48bfa103d4ebe6cd84905c32e2b47b3b", + "namingEvidenceSha256": "d4d7c1b120fe4c0f6b31a0595707caf63b678ba69b1ed95aff9e1364adc68342", + "namingSemanticSha256": "d8c250a8d4018548a9a6a01346ae4ca990ddc0e0e1e068c01dd31ddad3db0c29" + }, + "restoredEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 56, + "vertices": 32, + "volume": 2505.7522204, + "area": 1409.6460033, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 441, + "selectedRecords": 26, + "ambiguousResults": 88, + "historySha256": "1f10c95a00ed6610b6d698414bd96b0e48bfa103d4ebe6cd84905c32e2b47b3b", + "namingEvidenceSha256": "fb4dee6c7fe1cb337d9ffe37f9a62ad1ef23cb98d8ac0f4bd3a85e5fbd082f65", + "namingSemanticSha256": "d8c250a8d4018548a9a6a01346ae4ca990ddc0e0e1e068c01dd31ddad3db0c29" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "hole->multi-transform", + "phases": { + "initial": { + "namingEvidenceBytes": 51400, + "namingEvidenceSha256": "a4b7e760b9c952b38bfbc4900fcfc8aee3c01456511eeecc623b4037acb2655e", + "pair": "hole->multi-transform", + "shape": { + "area": 1409.6460033, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 2505.7522204 + } + }, + "reopened": { + "namingEvidenceBytes": 51400, + "namingEvidenceSha256": "a4b7e760b9c952b38bfbc4900fcfc8aee3c01456511eeecc623b4037acb2655e", + "pair": "hole->multi-transform", + "shape": { + "area": 1409.6460033, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 2505.7522204 + } + }, + "resaved": { + "namingEvidenceBytes": 51400, + "namingEvidenceSha256": "a4b7e760b9c952b38bfbc4900fcfc8aee3c01456511eeecc623b4037acb2655e", + "pair": "hole->multi-transform", + "shape": { + "area": 1409.6460033, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 2505.7522204 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-fuse", + "pair": "draft->fuse", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "a4260b721c525e507b9179f8f91be43e0a4acf0e9b381eed7a02649f7b11f631", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 29, + "vertices": 18, + "volume": 1031.2556682, + "area": 642.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 13.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "3c9d5be39dd201d2a637810cc9ae644ee5c056f7eab523ab3480a74c7dc5c427", + "namingEvidenceSha256": "ac6770c893a0fd474f0d5e5a0c8e0ee3a93cd2ad530266bde3a66587553d98eb", + "namingSemanticSha256": "05dd0f0687d2db8820896df90009987b5c3ba8659c4c904c33b9f6ea7b0bc126" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 8, + 7, + 8 + ], + "beforeValue": 8, + "editedValue": 7, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 29, + "vertices": 18, + "volume": 1006.2556682, + "area": 622.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 12.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "3c9d5be39dd201d2a637810cc9ae644ee5c056f7eab523ab3480a74c7dc5c427", + "namingEvidenceSha256": "5463e1bc367997d7565ae15f4aac160fc113b3449967529685686589f44451ab", + "namingSemanticSha256": "05dd0f0687d2db8820896df90009987b5c3ba8659c4c904c33b9f6ea7b0bc126" + }, + "restoredEvidence": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 29, + "vertices": 18, + "volume": 1031.2556682, + "area": 642.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 13.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "3c9d5be39dd201d2a637810cc9ae644ee5c056f7eab523ab3480a74c7dc5c427", + "namingEvidenceSha256": "dea241e210b93c18666cc37dd9b84bf3b32bdc0a96fb804044b6353b8c10db28", + "namingSemanticSha256": "05dd0f0687d2db8820896df90009987b5c3ba8659c4c904c33b9f6ea7b0bc126" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->fuse", + "phases": { + "initial": { + "namingEvidenceBytes": 7800, + "namingEvidenceSha256": "ac6770c893a0fd474f0d5e5a0c8e0ee3a93cd2ad530266bde3a66587553d98eb", + "pair": "draft->fuse", + "shape": { + "area": 642.884251, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 29, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1031.2556682 + } + }, + "reopened": { + "namingEvidenceBytes": 7800, + "namingEvidenceSha256": "ac6770c893a0fd474f0d5e5a0c8e0ee3a93cd2ad530266bde3a66587553d98eb", + "pair": "draft->fuse", + "shape": { + "area": 642.884251, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 29, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1031.2556682 + } + }, + "resaved": { + "namingEvidenceBytes": 7800, + "namingEvidenceSha256": "ac6770c893a0fd474f0d5e5a0c8e0ee3a93cd2ad530266bde3a66587553d98eb", + "pair": "draft->fuse", + "shape": { + "area": 642.884251, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 29, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1031.2556682 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-cut", + "pair": "draft->cut", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "d170925da1f985015206463a0a32f6d99df925515c17a879a984e26e8ee627aa", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 10, + "edges": 24, + "vertices": 16, + "volume": 892.2556682, + "area": 614.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 22, + "selectedRecords": 2, + "ambiguousResults": 8, + "historySha256": "b65277e3e865693bad596c66f74681f349245de069db73565af5ff1944bfc7ee", + "namingEvidenceSha256": "092779b61d0369c38d66c143e9514388a8a662ce4478c872066a25873ed3193c", + "namingSemanticSha256": "e8a58a96c1a537849240a5fc4d88faa52e60293b130d98ac8eab54d735ea20b5" + }, + "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": 10, + "edges": 24, + "vertices": 16, + "volume": 929.2556682, + "area": 600.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 22, + "selectedRecords": 2, + "ambiguousResults": 8, + "historySha256": "b65277e3e865693bad596c66f74681f349245de069db73565af5ff1944bfc7ee", + "namingEvidenceSha256": "34cc19916cfca4af20caee071f0c868039a7e099513ab6f315ad50c6386794ae", + "namingSemanticSha256": "e8a58a96c1a537849240a5fc4d88faa52e60293b130d98ac8eab54d735ea20b5" + }, + "restoredEvidence": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 10, + "edges": 24, + "vertices": 16, + "volume": 892.2556682, + "area": 614.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 22, + "selectedRecords": 2, + "ambiguousResults": 8, + "historySha256": "b65277e3e865693bad596c66f74681f349245de069db73565af5ff1944bfc7ee", + "namingEvidenceSha256": "58ad8b04c88213e4c4bffd40574cf10d0a03741b599cd5e532b8eb838d94527c", + "namingSemanticSha256": "e8a58a96c1a537849240a5fc4d88faa52e60293b130d98ac8eab54d735ea20b5" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->cut", + "phases": { + "initial": { + "namingEvidenceBytes": 3603, + "namingEvidenceSha256": "092779b61d0369c38d66c143e9514388a8a662ce4478c872066a25873ed3193c", + "pair": "draft->cut", + "shape": { + "area": 614.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 892.2556682 + } + }, + "reopened": { + "namingEvidenceBytes": 3603, + "namingEvidenceSha256": "092779b61d0369c38d66c143e9514388a8a662ce4478c872066a25873ed3193c", + "pair": "draft->cut", + "shape": { + "area": 614.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 892.2556682 + } + }, + "resaved": { + "namingEvidenceBytes": 3603, + "namingEvidenceSha256": "092779b61d0369c38d66c143e9514388a8a662ce4478c872066a25873ed3193c", + "pair": "draft->cut", + "shape": { + "area": 614.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 892.2556682 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-common", + "pair": "draft->common", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "589103180669b05f43db1902efac165dc4349fe994c74844dbf9184bd9d14639", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "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": [ + 6.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 121, + "selectedRecords": 3, + "ambiguousResults": 10, + "historySha256": "671b80def84912c5908978511baca536be2385c87a50285d7f26412124792e57", + "namingEvidenceSha256": "6bafa6dc800ab0f22c26c64e10e3668ed72ca9dd3c2fc2fd5f2a54b78d6d732e", + "namingSemanticSha256": "8e549420a5bd1d3ac90968e37203754482d2beacf4b4d4c9f50e99bc785fb69b" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 7, + 6, + 7 + ], + "beforeValue": 7, + "editedValue": 6, + "restoredValue": 7, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "common", + "builder": "BRepAlgoAPI_Common", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 100, + "area": 130, + "bounds": [ + 5.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 121, + "selectedRecords": 3, + "ambiguousResults": 10, + "historySha256": "671b80def84912c5908978511baca536be2385c87a50285d7f26412124792e57", + "namingEvidenceSha256": "6bafa6dc800ab0f22c26c64e10e3668ed72ca9dd3c2fc2fd5f2a54b78d6d732e", + "namingSemanticSha256": "8e549420a5bd1d3ac90968e37203754482d2beacf4b4d4c9f50e99bc785fb69b" + }, + "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": [ + 6.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 121, + "selectedRecords": 3, + "ambiguousResults": 10, + "historySha256": "671b80def84912c5908978511baca536be2385c87a50285d7f26412124792e57", + "namingEvidenceSha256": "4f0793888f7861e22559572666c06997bf23cea0e6a6d4116cb1d39fe6effc27", + "namingSemanticSha256": "8e549420a5bd1d3ac90968e37203754482d2beacf4b4d4c9f50e99bc785fb69b" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->common", + "phases": { + "initial": { + "namingEvidenceBytes": 4557, + "namingEvidenceSha256": "6bafa6dc800ab0f22c26c64e10e3668ed72ca9dd3c2fc2fd5f2a54b78d6d732e", + "pair": "draft->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 75 + } + }, + "reopened": { + "namingEvidenceBytes": 4557, + "namingEvidenceSha256": "6bafa6dc800ab0f22c26c64e10e3668ed72ca9dd3c2fc2fd5f2a54b78d6d732e", + "pair": "draft->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 75 + } + }, + "resaved": { + "namingEvidenceBytes": 4557, + "namingEvidenceSha256": "6bafa6dc800ab0f22c26c64e10e3668ed72ca9dd3c2fc2fd5f2a54b78d6d732e", + "pair": "draft->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 75 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-rotate", + "pair": "draft->rotate", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "847b29701678674c9373b267705626c6479bb2949906457e5db5038d374c6903", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -2.5881906, + -1e-7, + -1e-7, + 9.6592584, + 12.2474488, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "bee8c3d39b2e8d137b532235248b0ee9a41c8520722e8170cec260ce103d23e8", + "namingEvidenceSha256": "cceb25e84029de3b36e8501735c810ccd892fb58708b364de6736f934bd444f8", + "namingSemanticSha256": "bb9b23ee81c82547395dfa051c7a7598d3a96a4ae57edbdbe263be97431d9f66" + }, + "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": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -3.8268344, + -1e-7, + -1e-7, + 9.2387954, + 13.0656297, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "bee8c3d39b2e8d137b532235248b0ee9a41c8520722e8170cec260ce103d23e8", + "namingEvidenceSha256": "7c347d4904b2f4002c841d90ac3325401330475e54563f2969479addb9c6eb30", + "namingSemanticSha256": "bb9b23ee81c82547395dfa051c7a7598d3a96a4ae57edbdbe263be97431d9f66" + }, + "restoredEvidence": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -2.5881906, + -1e-7, + -1e-7, + 9.6592584, + 12.2474488, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "bee8c3d39b2e8d137b532235248b0ee9a41c8520722e8170cec260ce103d23e8", + "namingEvidenceSha256": "91a8a7e853ab57c085d8b23bd1343d1c848a7198bd560523ef249a5df149323c", + "namingSemanticSha256": "bb9b23ee81c82547395dfa051c7a7598d3a96a4ae57edbdbe263be97431d9f66" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->rotate", + "phases": { + "initial": { + "namingEvidenceBytes": 10374, + "namingEvidenceSha256": "cceb25e84029de3b36e8501735c810ccd892fb58708b364de6736f934bd444f8", + "pair": "draft->rotate", + "shape": { + "area": 582.884251, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "reopened": { + "namingEvidenceBytes": 10374, + "namingEvidenceSha256": "cceb25e84029de3b36e8501735c810ccd892fb58708b364de6736f934bd444f8", + "pair": "draft->rotate", + "shape": { + "area": 582.884251, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "resaved": { + "namingEvidenceBytes": 10374, + "namingEvidenceSha256": "cceb25e84029de3b36e8501735c810ccd892fb58708b364de6736f934bd444f8", + "pair": "draft->rotate", + "shape": { + "area": 582.884251, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-pad", + "pair": "draft->pad", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "8e9bf35162eff7003db08143f007ffac0c347ed30261e40ad38df17fb923fdc0", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "length", + "trajectory": [ + 5, + 7.5, + 5 + ], + "stable": true, + "attempts": [ + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 7.5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "nativeTypeId": "PartDesign::Pad", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Body", + "typeId": "PartDesign::Body" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + }, + { + "name": "PairResult", + "typeId": "PartDesign::Pad" + } + ], + "parameter": { + "name": "length", + "value": 5 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "FeatureExtrusion: Length: Could not extrude the sketch!" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "PartDesign::Pad", + "operation": "pad", + "pair": "draft->pad", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-draft-pocket", + "pair": "draft->pocket", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "3e3821e7dd02f74b0b1d55c1c811082f1c138749a962d690a2a12f317be54cb9", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 9, + "edges": 21, + "vertices": 14, + "volume": 929.5364931, + "area": 581.5146235, + "bounds": [ + -2e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 58, + "selectedRecords": 5, + "ambiguousResults": 8, + "historySha256": "c08ae6f3e88b6dd2f2b6e17211bc29121b064042a60dcf77ac779ce1770aafa7", + "namingEvidenceSha256": "d487a42171fa43d53268a52edb7a311fdd21ced1cf8754e0f693bfd56e1e3e69", + "namingSemanticSha256": "3d220b56e8399009372264b93de5d451479b5ba443b48d569ff65e3e888bc2fe" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "length", + "trajectory": [ + 5, + 4, + 5 + ], + "beforeValue": 5, + "editedValue": 4, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 9, + "edges": 21, + "vertices": 14, + "volume": 934.3553962, + "area": 581.788549, + "bounds": [ + -2e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 58, + "selectedRecords": 5, + "ambiguousResults": 8, + "historySha256": "c08ae6f3e88b6dd2f2b6e17211bc29121b064042a60dcf77ac779ce1770aafa7", + "namingEvidenceSha256": "5cbd2daefb0b246f7d1502f717d880611cb4f8c9eb0e8e1832a72d51e6806acc", + "namingSemanticSha256": "3d220b56e8399009372264b93de5d451479b5ba443b48d569ff65e3e888bc2fe" + }, + "restoredEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 9, + "edges": 21, + "vertices": 14, + "volume": 929.5364931, + "area": 581.5146235, + "bounds": [ + -2e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 58, + "selectedRecords": 5, + "ambiguousResults": 8, + "historySha256": "c08ae6f3e88b6dd2f2b6e17211bc29121b064042a60dcf77ac779ce1770aafa7", + "namingEvidenceSha256": "69a7e50b17ab1927e21d01a2d62da94467de2daa3f9f8615e3f63d5ccdfec691", + "namingSemanticSha256": "3d220b56e8399009372264b93de5d451479b5ba443b48d569ff65e3e888bc2fe" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->pocket", + "phases": { + "initial": { + "namingEvidenceBytes": 5021, + "namingEvidenceSha256": "d487a42171fa43d53268a52edb7a311fdd21ced1cf8754e0f693bfd56e1e3e69", + "pair": "draft->pocket", + "shape": { + "area": 581.5146235, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 21, + "faces": 9, + "solids": 1, + "valid": true, + "vertices": 14, + "volume": 929.5364931 + } + }, + "reopened": { + "namingEvidenceBytes": 5021, + "namingEvidenceSha256": "d487a42171fa43d53268a52edb7a311fdd21ced1cf8754e0f693bfd56e1e3e69", + "pair": "draft->pocket", + "shape": { + "area": 581.5146235, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 21, + "faces": 9, + "solids": 1, + "valid": true, + "vertices": 14, + "volume": 929.5364931 + } + }, + "resaved": { + "namingEvidenceBytes": 5021, + "namingEvidenceSha256": "d487a42171fa43d53268a52edb7a311fdd21ced1cf8754e0f693bfd56e1e3e69", + "pair": "draft->pocket", + "shape": { + "area": 581.5146235, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 21, + "faces": 9, + "solids": 1, + "valid": true, + "vertices": 14, + "volume": 929.5364931 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-loft", + "pair": "draft->loft", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "5926c9d50cd8d0019dd06a07b8c3407d24878c998559bbf6bbd464c6833f9667", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "ruled", + "trajectory": [ + false, + true, + false + ], + "kernelAttempts": [ + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 315.6164976, + "area": 549.6140595, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "d8dcd64a2cfd2e21dcaae30cb20f969c962b93528488f3aa5945277353502a45", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": true, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 315.6164976, + "area": 549.6140595, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "d8dcd64a2cfd2e21dcaae30cb20f969c962b93528488f3aa5945277353502a45", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 315.6164976, + "area": 549.6140595, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "d8dcd64a2cfd2e21dcaae30cb20f969c962b93528488f3aa5945277353502a45", + "authority": "kernel-superset-only" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + } + ] + }, + "inputShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "nativeTypeId": "Part::Loft", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Loft" + } + ], + "parameter": { + "name": "ruled", + "value": false + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Profile shape is not a single vertex, edge, wire nor face." + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Loft", + "operation": "loft", + "pair": "draft->loft", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-draft-pipe", + "pair": "draft->pipe", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "d3875c27f17427b8e80b0f6c07ee53a92071ea545d475d574d1a3a80b72e1b81", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "spineLength", + "trajectory": [ + 15, + 12, + 15 + ], + "kernelAttempts": [ + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 131.2329953, + "area": 527.0105666, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 0.8748867, + 10.0000001, + 25.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-superset-only" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 12, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 104.9863962, + "area": 461.7612468, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 0.8748867, + 10.0000001, + 22.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-superset-only" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 131.2329953, + "area": 527.0105666, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 0.8748867, + 10.0000001, + 25.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-superset-only" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "spine": { + "name": "Spine", + "subelements": [], + "typeId": "Part::Feature" + } + }, + "inputShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "nativeTypeId": "Part::Sweep", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Spine", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Sweep" + } + ], + "parameter": { + "name": "spineLength", + "value": 15 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "A fatal error occurred when making the sweep" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Sweep", + "operation": "pipe", + "pair": "draft->pipe", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-draft-revolution", + "pair": "draft->revolution", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "4e5855c1156c026304632f3e30759195c4ee8544828af2d418fa358516df3c72", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "angle", + "trajectory": [ + 360, + 270, + 360 + ], + "stable": true, + "attempts": [ + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 270, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "nativeTypeId": "Part::Revolution", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Revolution" + } + ], + "parameter": { + "name": "angle", + "value": 360 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Solids are not Processed" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Revolution", + "operation": "revolution", + "pair": "draft->revolution", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a18f0adb8f2f22db1306148d60dca00b62ec127ffb55db28a9a77c93e6c9466a", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-draft-groove", + "pair": "draft->groove", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "d0c2b8227a99830f3bf97579a90954bf598df0a9dcb2c42e49bd6848a9710efd", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 10, + "edges": 24, + "vertices": 16, + "volume": 951.8050786, + "area": 588.75249, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "27178e896a90b674464ea8cdfbd25a369b8ca785bb2c8e6716d298999eb87f75", + "namingEvidenceSha256": "7f3be10caec3f9ae6fabc5a6249ac48402b63330513df1770f7878c8c8165593", + "namingSemanticSha256": "92bc6b880505d9b837f7b6c59ccf4ebcd072f137732a6c21a171534f2f4402a4" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 360, + 180, + 360 + ], + "beforeValue": 360, + "editedValue": 180, + "restoredValue": 360, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 16, + "vertices": 12, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 56, + "selectedRecords": 1, + "ambiguousResults": 5, + "historySha256": "8af07b9662aa724cc965a854b74d64efd6ac4b7bea049f709d3d264c37233098", + "namingEvidenceSha256": "5aab432ad88b05fcd923d2ea7d972e858b030f528e11639886bb3a1e0f492757", + "namingSemanticSha256": "06e2be985d4f9ce553f18b059fe1a93f4c5ac6588c44f0084e12faaf62606ca6" + }, + "restoredEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 10, + "edges": 24, + "vertices": 16, + "volume": 951.8050786, + "area": 588.75249, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "27178e896a90b674464ea8cdfbd25a369b8ca785bb2c8e6716d298999eb87f75", + "namingEvidenceSha256": "469813042ed25076aa84f56f91bd6d2fc8813950adb05eb0d3ef955900308b0a", + "namingSemanticSha256": "92bc6b880505d9b837f7b6c59ccf4ebcd072f137732a6c21a171534f2f4402a4" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->groove", + "phases": { + "initial": { + "namingEvidenceBytes": 4949, + "namingEvidenceSha256": "7f3be10caec3f9ae6fabc5a6249ac48402b63330513df1770f7878c8c8165593", + "pair": "draft->groove", + "shape": { + "area": 588.75249, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 951.8050786 + } + }, + "reopened": { + "namingEvidenceBytes": 4949, + "namingEvidenceSha256": "7f3be10caec3f9ae6fabc5a6249ac48402b63330513df1770f7878c8c8165593", + "pair": "draft->groove", + "shape": { + "area": 588.75249, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 951.8050786 + } + }, + "resaved": { + "namingEvidenceBytes": 4949, + "namingEvidenceSha256": "7f3be10caec3f9ae6fabc5a6249ac48402b63330513df1770f7878c8c8165593", + "pair": "draft->groove", + "shape": { + "area": 588.75249, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 951.8050786 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-fillet", + "pair": "draft->fillet", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "1758e47d349c046bd595dd128b112201a5d06eef68843fcaa3e03d3194476c2e", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 56, + "vertices": 24, + "volume": 952.2666777, + "area": 562.3270603, + "bounds": [ + 0.0365233, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "64b4ae71d2176315953fe2a9aa80b0249ae26620a797486eed7f9eb54a91d517", + "namingEvidenceSha256": "03590c567554821296063d25b5cf161e8092bba167192b0a8d8d5833409b98aa", + "namingSemanticSha256": "3a13519e515c07c1b9e8bee4917e00038ecbfdcf2ae7bc80c55038d42af529e3" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "beforeValue": 0.4, + "editedValue": 0.6, + "restoredValue": 0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 56, + "vertices": 24, + "volume": 947.3773367, + "area": 551.9122764, + "bounds": [ + 0.054785, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "64b4ae71d2176315953fe2a9aa80b0249ae26620a797486eed7f9eb54a91d517", + "namingEvidenceSha256": "accdd093a8fe8630ab3619ef713af0f2e6c4745569455126b1d0303632dc5906", + "namingSemanticSha256": "3a13519e515c07c1b9e8bee4917e00038ecbfdcf2ae7bc80c55038d42af529e3" + }, + "restoredEvidence": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 56, + "vertices": 24, + "volume": 952.2666777, + "area": 562.3270603, + "bounds": [ + 0.0365233, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "64b4ae71d2176315953fe2a9aa80b0249ae26620a797486eed7f9eb54a91d517", + "namingEvidenceSha256": "dfc711834ec14b73c5a2479d76a6fc1d6730e9d286144c89ebb46fa24675f4d8", + "namingSemanticSha256": "3a13519e515c07c1b9e8bee4917e00038ecbfdcf2ae7bc80c55038d42af529e3" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->fillet", + "phases": { + "initial": { + "namingEvidenceBytes": 11057, + "namingEvidenceSha256": "03590c567554821296063d25b5cf161e8092bba167192b0a8d8d5833409b98aa", + "pair": "draft->fillet", + "shape": { + "area": 562.3270603, + "bounds": [ + 0.0365234, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 952.2666777 + } + }, + "reopened": { + "namingEvidenceBytes": 11057, + "namingEvidenceSha256": "03590c567554821296063d25b5cf161e8092bba167192b0a8d8d5833409b98aa", + "pair": "draft->fillet", + "shape": { + "area": 562.3270603, + "bounds": [ + 0.0365234, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 952.2666777 + } + }, + "resaved": { + "namingEvidenceBytes": 11057, + "namingEvidenceSha256": "03590c567554821296063d25b5cf161e8092bba167192b0a8d8d5833409b98aa", + "pair": "draft->fillet", + "shape": { + "area": 562.3270603, + "bounds": [ + 0.0365234, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 952.2666777 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-chamfer", + "pair": "draft->chamfer", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "a9c366730203fa517fccf791ddbbd1b7d55e02ec7d810edf355ee048f97bf63a", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 947.1369614, + "area": 554.6660823, + "bounds": [ + 0.0348622, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "c5b5332006f3dba66b90edef2b07e2c6c45e13c04d46bb2a49b3eb6d3b33812b", + "namingEvidenceSha256": "86475869e4e5ea3bd9759a0e71d175d413ddcedc1e5d950bb069ddec98bffc00", + "namingSemanticSha256": "4d3e2b61ab033e417ab12caff077cb9fe832566a91653bbc5e118eec7d902c0e" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "distance", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "beforeValue": 0.4, + "editedValue": 0.6, + "restoredValue": 0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 936.1225793, + "area": 540.1956869, + "bounds": [ + 0.0522933, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "c5b5332006f3dba66b90edef2b07e2c6c45e13c04d46bb2a49b3eb6d3b33812b", + "namingEvidenceSha256": "d614655be618e3d5eb997502f6a996c71c1de2f1297b761b1bcc7012e3c31fe7", + "namingSemanticSha256": "4d3e2b61ab033e417ab12caff077cb9fe832566a91653bbc5e118eec7d902c0e" + }, + "restoredEvidence": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 947.1369614, + "area": 554.6660823, + "bounds": [ + 0.0348622, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "c5b5332006f3dba66b90edef2b07e2c6c45e13c04d46bb2a49b3eb6d3b33812b", + "namingEvidenceSha256": "33b700c98e49e2b5444a76d6d6d5b9c331d8c717cc69aeea9c4977937c436ac7", + "namingSemanticSha256": "4d3e2b61ab033e417ab12caff077cb9fe832566a91653bbc5e118eec7d902c0e" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->chamfer", + "phases": { + "initial": { + "namingEvidenceBytes": 11145, + "namingEvidenceSha256": "86475869e4e5ea3bd9759a0e71d175d413ddcedc1e5d950bb069ddec98bffc00", + "pair": "draft->chamfer", + "shape": { + "area": 554.6660823, + "bounds": [ + 0.0348623, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 947.1369614 + } + }, + "reopened": { + "namingEvidenceBytes": 11145, + "namingEvidenceSha256": "86475869e4e5ea3bd9759a0e71d175d413ddcedc1e5d950bb069ddec98bffc00", + "pair": "draft->chamfer", + "shape": { + "area": 554.6660823, + "bounds": [ + 0.0348623, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 947.1369614 + } + }, + "resaved": { + "namingEvidenceBytes": 11145, + "namingEvidenceSha256": "86475869e4e5ea3bd9759a0e71d175d413ddcedc1e5d950bb069ddec98bffc00", + "pair": "draft->chamfer", + "shape": { + "area": 554.6660823, + "bounds": [ + 0.0348623, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 947.1369614 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-hole", + "pair": "draft->hole", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "b8b411cfbbb59a5daede1eef69d63ee930dd0544de715b982efad591a24f663a", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 924.8397417, + "area": 639.4329188, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "4d76f9b3590508b2dd29fc24032e5c1d5237e5c9c56e2ff3f794221baccfac00", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 1, + 1.5, + 1 + ], + "beforeValue": 1, + "editedValue": 1.5, + "restoredValue": 1, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 885.5698335, + "area": 662.9948637, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "eaa00d365ba17bd36fc2f8558226cbd2440c32df1995540b4bcd37e28dfd11fc", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "restoredEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 924.8397417, + "area": 639.4329188, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "d1972e3483239376cb0fb991ebda681ac22a347229cbc632dba631bdcf527bb7", + "namingEvidenceSha256": "05f0a2b8d487fcfed4e36239055199318fc3a5d8b28c62eb04d26bce610298c9", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->hole", + "phases": { + "initial": { + "namingEvidenceBytes": 1517, + "namingEvidenceSha256": "4d76f9b3590508b2dd29fc24032e5c1d5237e5c9c56e2ff3f794221baccfac00", + "pair": "draft->hole", + "shape": { + "area": 639.4329188, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 924.8397417 + } + }, + "reopened": { + "namingEvidenceBytes": 1517, + "namingEvidenceSha256": "4d76f9b3590508b2dd29fc24032e5c1d5237e5c9c56e2ff3f794221baccfac00", + "pair": "draft->hole", + "shape": { + "area": 639.4329188, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 924.8397417 + } + }, + "resaved": { + "namingEvidenceBytes": 1517, + "namingEvidenceSha256": "4d76f9b3590508b2dd29fc24032e5c1d5237e5c9c56e2ff3f794221baccfac00", + "pair": "draft->hole", + "shape": { + "area": 639.4329188, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 924.8397417 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-draft", + "pair": "draft->draft", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "c36dbbd3f3ffbee9ec3514fa817a1ef31c95a348c87c7a0eae3405addbd4981b", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "selectedRecords": 1, + "ambiguousResults": 0, + "historySha256": "b08877773f704695b511cc1b48578435a4badbd00e6a47fe6f2cdf1e120366e3", + "namingEvidenceSha256": "1e36c08179c961a83ea96087fd2b9189323c824cdcc4827a0b5e5fb619eb2c72", + "namingSemanticSha256": "0caa8efd458f28a30b8489d9fbd4fc4f71d2560ea8c5d5faafa4d6b1442cb4b0" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 5, + 8, + 5 + ], + "beforeValue": 5, + "editedValue": 8, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 929.7295826, + "area": 572.8745903, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "afbae7bb84960ccafda7ba7adfd9cae162e5d7f42127f400966cc9068e2c4c4c", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "restoredEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "selectedRecords": 1, + "ambiguousResults": 0, + "historySha256": "b08877773f704695b511cc1b48578435a4badbd00e6a47fe6f2cdf1e120366e3", + "namingEvidenceSha256": "365becb0c7e2b03bb7b24201a31961b633fcef0ea908af7d266737f7fb3c71f7", + "namingSemanticSha256": "0caa8efd458f28a30b8489d9fbd4fc4f71d2560ea8c5d5faafa4d6b1442cb4b0" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->draft", + "phases": { + "initial": { + "namingEvidenceBytes": 1047, + "namingEvidenceSha256": "1e36c08179c961a83ea96087fd2b9189323c824cdcc4827a0b5e5fb619eb2c72", + "pair": "draft->draft", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "reopened": { + "namingEvidenceBytes": 1047, + "namingEvidenceSha256": "1e36c08179c961a83ea96087fd2b9189323c824cdcc4827a0b5e5fb619eb2c72", + "pair": "draft->draft", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "resaved": { + "namingEvidenceBytes": 1047, + "namingEvidenceSha256": "1e36c08179c961a83ea96087fd2b9189323c824cdcc4827a0b5e5fb619eb2c72", + "pair": "draft->draft", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-thickness", + "pair": "draft->thickness", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "288367bac7b33a1ba5c0a9b241d6ded06545d7550956999c84b5942dcf8778cd", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 180.8661951, + "area": 920.33342, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "502f0c676943c2004b509e3f4ef34ab8ec2551884b5e8714c39ae0327793114c", + "namingSemanticSha256": "25b4cbc2ea981fc1050070c64d5f1e389fd7eb5cadd4f9d1a50f78da25824d20" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "offset", + "trajectory": [ + -0.4, + -0.6, + -0.4 + ], + "beforeValue": -0.4, + "editedValue": -0.6, + "restoredValue": -0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 262.3727637, + "area": 898.5813795, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "9067873732db13652c689b4f4823049e80000e70d9bc0c6146076c4628c1b390", + "namingSemanticSha256": "25b4cbc2ea981fc1050070c64d5f1e389fd7eb5cadd4f9d1a50f78da25824d20" + }, + "restoredEvidence": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 180.8661951, + "area": 920.33342, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "e45324fac8801af1da6e133fea3a7f66ae9848425492b7db6d7dbfd00beb6d6d", + "namingSemanticSha256": "25b4cbc2ea981fc1050070c64d5f1e389fd7eb5cadd4f9d1a50f78da25824d20" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->thickness", + "phases": { + "initial": { + "namingEvidenceBytes": 6636, + "namingEvidenceSha256": "502f0c676943c2004b509e3f4ef34ab8ec2551884b5e8714c39ae0327793114c", + "pair": "draft->thickness", + "shape": { + "area": 920.33342, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 180.8661951 + } + }, + "reopened": { + "namingEvidenceBytes": 6636, + "namingEvidenceSha256": "502f0c676943c2004b509e3f4ef34ab8ec2551884b5e8714c39ae0327793114c", + "pair": "draft->thickness", + "shape": { + "area": 920.33342, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 180.8661951 + } + }, + "resaved": { + "namingEvidenceBytes": 6636, + "namingEvidenceSha256": "502f0c676943c2004b509e3f4ef34ab8ec2551884b5e8714c39ae0327793114c", + "pair": "draft->thickness", + "shape": { + "area": 920.33342, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 180.8661951 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-linear-pattern", + "pair": "draft->linear-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "27f0c5314099a351d5bb19af9c09a7800beae279023d1b179acda3b15aef0a56", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1756.2556682, + "area": 902.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "35cb7d6b211d1847e3cde2846d76bae84d3e6b02ae40db267a8d9013fcabe83a", + "namingSemanticSha256": "2cad5f3d39969ca851285df1ec02cd676fd114bfe7d1896ee54e371184eb4ed6" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "translationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1856.2556682, + "area": 942.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 19.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "5979a79afa2f1b8af280d56ca2938c472dacc7885e90fb322c8f89b330e31e11", + "namingSemanticSha256": "2cad5f3d39969ca851285df1ec02cd676fd114bfe7d1896ee54e371184eb4ed6" + }, + "restoredEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1756.2556682, + "area": 902.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "f9bd4f34056f1d030ac277f6489dd597b1351fb5190a07b92af72ab2730ebcbe", + "namingSemanticSha256": "2cad5f3d39969ca851285df1ec02cd676fd114bfe7d1896ee54e371184eb4ed6" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->linear-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 7198, + "namingEvidenceSha256": "35cb7d6b211d1847e3cde2846d76bae84d3e6b02ae40db267a8d9013fcabe83a", + "pair": "draft->linear-pattern", + "shape": { + "area": 902.884251, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1756.2556682 + } + }, + "reopened": { + "namingEvidenceBytes": 7198, + "namingEvidenceSha256": "35cb7d6b211d1847e3cde2846d76bae84d3e6b02ae40db267a8d9013fcabe83a", + "pair": "draft->linear-pattern", + "shape": { + "area": 902.884251, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1756.2556682 + } + }, + "resaved": { + "namingEvidenceBytes": 7198, + "namingEvidenceSha256": "35cb7d6b211d1847e3cde2846d76bae84d3e6b02ae40db267a8d9013fcabe83a", + "pair": "draft->linear-pattern", + "shape": { + "area": 902.884251, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1756.2556682 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-polar-pattern", + "pair": "draft->polar-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "981aedc30f5cd463663ee946fef2736377ab203925a4aebd8017198e65d4be4a", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 30, + "vertices": 18, + "volume": 1378.1688669, + "area": 754.9351384, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 7, + "ambiguousResults": 10, + "historySha256": "f77cead6553447892fbb5f80d22995c8d8be886f3f67cef728cf9904cdf8b974", + "namingEvidenceSha256": "d1dd374cb1eed998cb6fff703fc52a8dd8bb12040331bc2b851492ec1adec5fa", + "namingSemanticSha256": "4c52f996dfbe6ad1694f9c91995b53a01f8037e14c6b1aa757bf7bb3aae95d21" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 30, + 45, + 30 + ], + "beforeValue": 30, + "editedValue": 45, + "restoredValue": 30, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 30, + "vertices": 18, + "volume": 1540.7663948, + "area": 823.0192051, + "bounds": [ + -7.071068, + -1e-7, + -1e-7, + 10.0000001, + 14.1421358, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 7, + "ambiguousResults": 10, + "historySha256": "f77cead6553447892fbb5f80d22995c8d8be886f3f67cef728cf9904cdf8b974", + "namingEvidenceSha256": "662a5e4769c49e8f4ac122e170d8481717b385299354193aa53c7c984231ebdc", + "namingSemanticSha256": "4c52f996dfbe6ad1694f9c91995b53a01f8037e14c6b1aa757bf7bb3aae95d21" + }, + "restoredEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 30, + "vertices": 18, + "volume": 1378.1688669, + "area": 754.9351384, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 7, + "ambiguousResults": 10, + "historySha256": "f77cead6553447892fbb5f80d22995c8d8be886f3f67cef728cf9904cdf8b974", + "namingEvidenceSha256": "1b25689402b797c3310be3d9c7782db2f03d346ed69f597d1ae01f6cc4e1c5a6", + "namingSemanticSha256": "4c52f996dfbe6ad1694f9c91995b53a01f8037e14c6b1aa757bf7bb3aae95d21" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->polar-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 6933, + "namingEvidenceSha256": "d1dd374cb1eed998cb6fff703fc52a8dd8bb12040331bc2b851492ec1adec5fa", + "pair": "draft->polar-pattern", + "shape": { + "area": 754.9351384, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 30, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1378.1688669 + } + }, + "reopened": { + "namingEvidenceBytes": 6933, + "namingEvidenceSha256": "d1dd374cb1eed998cb6fff703fc52a8dd8bb12040331bc2b851492ec1adec5fa", + "pair": "draft->polar-pattern", + "shape": { + "area": 754.9351384, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 30, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1378.1688669 + } + }, + "resaved": { + "namingEvidenceBytes": 6933, + "namingEvidenceSha256": "d1dd374cb1eed998cb6fff703fc52a8dd8bb12040331bc2b851492ec1adec5fa", + "pair": "draft->polar-pattern", + "shape": { + "area": 754.9351384, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 30, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1378.1688669 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-mirrored", + "pair": "draft->mirrored", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "12f64590f4eb08aea384fce10b52dc6fdd16fb87dc801bdf6bca36e2ef912264", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 22, + "vertices": 12, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 118, + "selectedRecords": 8, + "ambiguousResults": 17, + "historySha256": "96a0e7643c09f6d63b0a3b7d8971687a82ef002da51136dc0d46e201196375aa", + "namingEvidenceSha256": "7a5113cda6f16f495bf4f8dac0647cdf02dd8e14e5d26c87fbdd599b77604d37", + "namingSemanticSha256": "67c96706ef047e88e2f72b6bf219900c1419101c60e5fc963ed576520defbc5b" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "planeOriginX", + "trajectory": [ + 5, + 6, + 5 + ], + "beforeValue": 5, + "editedValue": 6, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1112.5113365, + "area": 645.7685021, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 12.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "19477605d954f0b26c8b8c24844d34e810b62311b3b9976f2bedae16022c6abd", + "namingEvidenceSha256": "b7b4e1e8b7b36f48a3e2bf25f54c55ea680a4875e64c4118d5133cbeabca52c1", + "namingSemanticSha256": "9410f10226e09e76b0dc13548ec7f6755140caf85a74214c8f950b599e33eee1" + }, + "restoredEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 22, + "vertices": 12, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 118, + "selectedRecords": 8, + "ambiguousResults": 17, + "historySha256": "96a0e7643c09f6d63b0a3b7d8971687a82ef002da51136dc0d46e201196375aa", + "namingEvidenceSha256": "7a5113cda6f16f495bf4f8dac0647cdf02dd8e14e5d26c87fbdd599b77604d37", + "namingSemanticSha256": "67c96706ef047e88e2f72b6bf219900c1419101c60e5fc963ed576520defbc5b" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->mirrored", + "phases": { + "initial": { + "namingEvidenceBytes": 9429, + "namingEvidenceSha256": "7a5113cda6f16f495bf4f8dac0647cdf02dd8e14e5d26c87fbdd599b77604d37", + "pair": "draft->mirrored", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 22, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 12, + "volume": 1000 + } + }, + "reopened": { + "namingEvidenceBytes": 9429, + "namingEvidenceSha256": "7a5113cda6f16f495bf4f8dac0647cdf02dd8e14e5d26c87fbdd599b77604d37", + "pair": "draft->mirrored", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 22, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 12, + "volume": 1000 + } + }, + "resaved": { + "namingEvidenceBytes": 9429, + "namingEvidenceSha256": "7a5113cda6f16f495bf4f8dac0647cdf02dd8e14e5d26c87fbdd599b77604d37", + "pair": "draft->mirrored", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 22, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 12, + "volume": 1000 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-draft-multi-transform", + "pair": "draft->multi-transform", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "892f032e032350527d18612c7f3a1ada59c5014cb063799a04dcb1fb8edd5dad", + "namingEvidenceSha256": "96258a6e2f36da6881713abffe2881162e2eeff2c73fe37d967e1bc2fd04f76d", + "namingSemanticSha256": "6636aed479189b16c13eb001989ae18e80bc403f90afe5fc0f09c4c439de17ff" + }, + "second": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 28, + "edges": 54, + "vertices": 28, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 376, + "selectedRecords": 28, + "ambiguousResults": 82, + "historySha256": "8bf2cf4af08f00d2ea61fb048f569bc4766e39a87f390c7cf609a66f08234deb", + "namingEvidenceSha256": "bed9f818bcc787a3b2fc2946e0a8f7eeb1121c1a4208ff4dddbc024eeaef2545", + "namingSemanticSha256": "493108948e954b8cc5475afa1f638b409597c67cfdb3cb8c24ae93aa6752f9ff" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "multiTranslationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 32, + "edges": 62, + "vertices": 32, + "volume": 2800, + "area": 1320, + "bounds": [ + -9.0000001, + -1e-7, + -1e-7, + 19.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 386, + "selectedRecords": 32, + "ambiguousResults": 90, + "historySha256": "b16bc5362c491482fc117a2e2d27f01355f4f6616aaa982cbd2c7bf496192174", + "namingEvidenceSha256": "9da1edb43992132a51a5ec9b71adc8518f47785eed431affeee154610b68a6cf", + "namingSemanticSha256": "4f0b6aa9fb55e90a4e1e928a62f449d294f5e32cb5b1b5aae83d3e024624e194" + }, + "restoredEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 28, + "edges": 54, + "vertices": 28, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 376, + "selectedRecords": 28, + "ambiguousResults": 82, + "historySha256": "8bf2cf4af08f00d2ea61fb048f569bc4766e39a87f390c7cf609a66f08234deb", + "namingEvidenceSha256": "70609df4d6b5fa8398af55446ba80f4e5311d7097b1260d141df7881be985953", + "namingSemanticSha256": "493108948e954b8cc5475afa1f638b409597c67cfdb3cb8c24ae93aa6752f9ff" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "draft->multi-transform", + "phases": { + "initial": { + "namingEvidenceBytes": 46879, + "namingEvidenceSha256": "bed9f818bcc787a3b2fc2946e0a8f7eeb1121c1a4208ff4dddbc024eeaef2545", + "pair": "draft->multi-transform", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 54, + "faces": 28, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 2600 + } + }, + "reopened": { + "namingEvidenceBytes": 46879, + "namingEvidenceSha256": "bed9f818bcc787a3b2fc2946e0a8f7eeb1121c1a4208ff4dddbc024eeaef2545", + "pair": "draft->multi-transform", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 54, + "faces": 28, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 2600 + } + }, + "resaved": { + "namingEvidenceBytes": 46879, + "namingEvidenceSha256": "bed9f818bcc787a3b2fc2946e0a8f7eeb1121c1a4208ff4dddbc024eeaef2545", + "pair": "draft->multi-transform", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 54, + "faces": 28, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 2600 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-fuse", + "pair": "thickness->fuse", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "98f0c08183ada66a2e96d53c419fc6fa4946d3a9e551085bd0b3af3da34a6082", + "namingSemanticSha256": "7dc359e9644c2586e6589cc4d47567f707f9a385ea7f9d29a92c207200051b2e" + }, + "second": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 19, + "edges": 47, + "vertices": 30, + "volume": 304.776, + "area": 1055.6, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 13.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 58, + "selectedRecords": 10, + "ambiguousResults": 20, + "historySha256": "4b62cb5afd60b667efff060c46977b0f8d7f22f4b6043fd09f7e2e19ec426035", + "namingEvidenceSha256": "01b473d6fefcfedbcf65b97f627755c8202bc429b221d0e0ddd73bedf8e35657", + "namingSemanticSha256": "b38b404a5ddc466b7c9d39f47d15323d94e96e90bcbed91ffb685dcdf19f6131" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 8, + 7, + 8 + ], + "beforeValue": 8, + "editedValue": 7, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 19, + "edges": 47, + "vertices": 30, + "volume": 300.936, + "area": 1035.6, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 12.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 58, + "selectedRecords": 10, + "ambiguousResults": 20, + "historySha256": "4b62cb5afd60b667efff060c46977b0f8d7f22f4b6043fd09f7e2e19ec426035", + "namingEvidenceSha256": "ec6381e4e9b977ecc3695d6eb9da2146a6b75d3c2bb1c3bcced738d834f9fd63", + "namingSemanticSha256": "b38b404a5ddc466b7c9d39f47d15323d94e96e90bcbed91ffb685dcdf19f6131" + }, + "restoredEvidence": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 19, + "edges": 47, + "vertices": 30, + "volume": 304.776, + "area": 1055.6, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 13.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 58, + "selectedRecords": 10, + "ambiguousResults": 20, + "historySha256": "4b62cb5afd60b667efff060c46977b0f8d7f22f4b6043fd09f7e2e19ec426035", + "namingEvidenceSha256": "12d7e18d39ee7b180ba77684ccd5180b6c8275736a69ab08f058a38e91c0fabb", + "namingSemanticSha256": "b38b404a5ddc466b7c9d39f47d15323d94e96e90bcbed91ffb685dcdf19f6131" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->fuse", + "phases": { + "initial": { + "namingEvidenceBytes": 10543, + "namingEvidenceSha256": "01b473d6fefcfedbcf65b97f627755c8202bc429b221d0e0ddd73bedf8e35657", + "pair": "thickness->fuse", + "shape": { + "area": 1055.6, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 47, + "faces": 19, + "solids": 1, + "valid": true, + "vertices": 30, + "volume": 304.776 + } + }, + "reopened": { + "namingEvidenceBytes": 10543, + "namingEvidenceSha256": "01b473d6fefcfedbcf65b97f627755c8202bc429b221d0e0ddd73bedf8e35657", + "pair": "thickness->fuse", + "shape": { + "area": 1055.6, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 47, + "faces": 19, + "solids": 1, + "valid": true, + "vertices": 30, + "volume": 304.776 + } + }, + "resaved": { + "namingEvidenceBytes": 10543, + "namingEvidenceSha256": "01b473d6fefcfedbcf65b97f627755c8202bc429b221d0e0ddd73bedf8e35657", + "pair": "thickness->fuse", + "shape": { + "area": 1055.6, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 47, + "faces": 19, + "solids": 1, + "valid": true, + "vertices": 30, + "volume": 304.776 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-cut", + "pair": "thickness->cut", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "834aa0f626008a047aab004b18c16b6145e1ec957c26d06a07ebdc94a6d4fdd9", + "namingSemanticSha256": "e6c7a0be31fc23ee9ef2874c09bc708ee81eaa88e7b6d388d7b202fe92fb3909" + }, + "second": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 15, + "edges": 42, + "vertices": 28, + "volume": 175.296, + "area": 901.76, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 54, + "selectedRecords": 8, + "ambiguousResults": 14, + "historySha256": "00a8aaab15c605c3551fea606ab6429cd5e3b98284f8d515f9f0e2691f799bda", + "namingEvidenceSha256": "79adb65a35d10c8872c649a2902e25b0d59454f192286ea157ea16d6f95b8b48", + "namingSemanticSha256": "266ac765b8a8cfb91ea90b92495abcb5a29c8dd2dd07478cff58fe809cdc647c" + }, + "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": 15, + "edges": 42, + "vertices": 28, + "volume": 180.736, + "area": 926.56, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 54, + "selectedRecords": 8, + "ambiguousResults": 14, + "historySha256": "00a8aaab15c605c3551fea606ab6429cd5e3b98284f8d515f9f0e2691f799bda", + "namingEvidenceSha256": "4e6257c6b41d724d2984b4ef935e8a725091b3e9ed6881539cfe405043278829", + "namingSemanticSha256": "266ac765b8a8cfb91ea90b92495abcb5a29c8dd2dd07478cff58fe809cdc647c" + }, + "restoredEvidence": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 15, + "edges": 42, + "vertices": 28, + "volume": 175.296, + "area": 901.76, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 54, + "selectedRecords": 8, + "ambiguousResults": 14, + "historySha256": "00a8aaab15c605c3551fea606ab6429cd5e3b98284f8d515f9f0e2691f799bda", + "namingEvidenceSha256": "b886761a7f3afdb34635eca2dc203a101b4519ab2a0a422c002e8fac41194606", + "namingSemanticSha256": "266ac765b8a8cfb91ea90b92495abcb5a29c8dd2dd07478cff58fe809cdc647c" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->cut", + "phases": { + "initial": { + "namingEvidenceBytes": 7609, + "namingEvidenceSha256": "79adb65a35d10c8872c649a2902e25b0d59454f192286ea157ea16d6f95b8b48", + "pair": "thickness->cut", + "shape": { + "area": 901.76, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 42, + "faces": 15, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 175.296 + } + }, + "reopened": { + "namingEvidenceBytes": 7609, + "namingEvidenceSha256": "79adb65a35d10c8872c649a2902e25b0d59454f192286ea157ea16d6f95b8b48", + "pair": "thickness->cut", + "shape": { + "area": 901.76, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 42, + "faces": 15, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 175.296 + } + }, + "resaved": { + "namingEvidenceBytes": 7609, + "namingEvidenceSha256": "79adb65a35d10c8872c649a2902e25b0d59454f192286ea157ea16d6f95b8b48", + "pair": "thickness->cut", + "shape": { + "area": 901.76, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 42, + "faces": 15, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 175.296 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-common", + "pair": "thickness->common", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "524b476f84b7f0f3ef2daddb5d64746ef722243bfa1d756257e26affdbe18dcc", + "namingSemanticSha256": "68dd77aa7c160be1d964d6b3fd3025e38874e450d0e9666d92804f4abd6555f5" + }, + "second": { + "operation": "common", + "builder": "BRepAlgoAPI_Common", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 8, + "edges": 18, + "vertices": 12, + "volume": 11.52, + "area": 67.68, + "bounds": [ + 6.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 203, + "selectedRecords": 6, + "ambiguousResults": 14, + "historySha256": "17189a6727c2d7119ec46541084724230fd97587c45c7734229929bbe34086df", + "namingEvidenceSha256": "154480ab47b5c8e230fcee1bb68ce7f52f6ea271af0c83f5e924ddea7f8de8ad", + "namingSemanticSha256": "4368360c55e8e27ba4c8600e5abdbcecd9e3e7504f99c3ad6c38f347ff69a61d" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 7, + 6, + 7 + ], + "beforeValue": 7, + "editedValue": 6, + "restoredValue": 7, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "common", + "builder": "BRepAlgoAPI_Common", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 8, + "edges": 18, + "vertices": 12, + "volume": 15.36, + "area": 87.68, + "bounds": [ + 5.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 203, + "selectedRecords": 6, + "ambiguousResults": 14, + "historySha256": "17189a6727c2d7119ec46541084724230fd97587c45c7734229929bbe34086df", + "namingEvidenceSha256": "fdadd41d68f1fc643eaafb244a1632aa0f52012e3b8ff67b31d3d11de01eb17b", + "namingSemanticSha256": "4368360c55e8e27ba4c8600e5abdbcecd9e3e7504f99c3ad6c38f347ff69a61d" + }, + "restoredEvidence": { + "operation": "common", + "builder": "BRepAlgoAPI_Common", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 8, + "edges": 18, + "vertices": 12, + "volume": 11.52, + "area": 67.68, + "bounds": [ + 6.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 203, + "selectedRecords": 6, + "ambiguousResults": 14, + "historySha256": "17189a6727c2d7119ec46541084724230fd97587c45c7734229929bbe34086df", + "namingEvidenceSha256": "7f6c32e062238c2b4daea7a4d2f2c31eefc44fd730a38272f262b66490c3e6ec", + "namingSemanticSha256": "4368360c55e8e27ba4c8600e5abdbcecd9e3e7504f99c3ad6c38f347ff69a61d" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->common", + "phases": { + "initial": { + "namingEvidenceBytes": 7330, + "namingEvidenceSha256": "154480ab47b5c8e230fcee1bb68ce7f52f6ea271af0c83f5e924ddea7f8de8ad", + "pair": "thickness->common", + "shape": { + "area": 67.68, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 18, + "faces": 8, + "solids": 1, + "valid": true, + "vertices": 12, + "volume": 11.52 + } + }, + "reopened": { + "namingEvidenceBytes": 7330, + "namingEvidenceSha256": "154480ab47b5c8e230fcee1bb68ce7f52f6ea271af0c83f5e924ddea7f8de8ad", + "pair": "thickness->common", + "shape": { + "area": 67.68, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 18, + "faces": 8, + "solids": 1, + "valid": true, + "vertices": 12, + "volume": 11.52 + } + }, + "resaved": { + "namingEvidenceBytes": 7330, + "namingEvidenceSha256": "154480ab47b5c8e230fcee1bb68ce7f52f6ea271af0c83f5e924ddea7f8de8ad", + "pair": "thickness->common", + "shape": { + "area": 67.68, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 18, + "faces": 8, + "solids": 1, + "valid": true, + "vertices": 12, + "volume": 11.52 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-rotate", + "pair": "thickness->rotate", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "32ca81fa2e3faf71473355aae734af9edec25dd2622d780166ec58324e6fb141", + "namingSemanticSha256": "6f820730dfc4bab1ef7c362a3bc170283bf1470a6558e2370f093945a202a93d" + }, + "second": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -2.5881906, + -1e-7, + -1e-7, + 9.6592584, + 12.2474488, + 10.0000001 + ] + }, + "historyRecords": 155, + "selectedRecords": 11, + "ambiguousResults": 40, + "historySha256": "42ddfca50340b92821dcb413442442837ceaf5b0d824a0ad348637aaaa2e8a77", + "namingEvidenceSha256": "14f107e198ed8a5ae10ce88a64dc0945c90ce436cdb1ff62502f9cdd66beb6f7", + "namingSemanticSha256": "140859effa80dabc550a5329d24de00d775de762562339e7d41315767eb64ab0" + }, + "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": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -3.8268344, + -1e-7, + -1e-7, + 9.2387954, + 13.0656297, + 10.0000001 + ] + }, + "historyRecords": 155, + "selectedRecords": 11, + "ambiguousResults": 40, + "historySha256": "42ddfca50340b92821dcb413442442837ceaf5b0d824a0ad348637aaaa2e8a77", + "namingEvidenceSha256": "1a62eb8fac115b8e9551bce37633ce4d7f5013a0a2e3bad2684860c6d1d60fda", + "namingSemanticSha256": "140859effa80dabc550a5329d24de00d775de762562339e7d41315767eb64ab0" + }, + "restoredEvidence": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -2.5881906, + -1e-7, + -1e-7, + 9.6592584, + 12.2474488, + 10.0000001 + ] + }, + "historyRecords": 155, + "selectedRecords": 11, + "ambiguousResults": 40, + "historySha256": "42ddfca50340b92821dcb413442442837ceaf5b0d824a0ad348637aaaa2e8a77", + "namingEvidenceSha256": "67402e342113bbf0190426eb061152232aba8155bbb5a7a5584d9832723d9a10", + "namingSemanticSha256": "140859effa80dabc550a5329d24de00d775de762562339e7d41315767eb64ab0" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->rotate", + "phases": { + "initial": { + "namingEvidenceBytes": 21746, + "namingEvidenceSha256": "14f107e198ed8a5ae10ce88a64dc0945c90ce436cdb1ff62502f9cdd66beb6f7", + "pair": "thickness->rotate", + "shape": { + "area": 953.28, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "reopened": { + "namingEvidenceBytes": 21746, + "namingEvidenceSha256": "14f107e198ed8a5ae10ce88a64dc0945c90ce436cdb1ff62502f9cdd66beb6f7", + "pair": "thickness->rotate", + "shape": { + "area": 953.28, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "resaved": { + "namingEvidenceBytes": 21746, + "namingEvidenceSha256": "14f107e198ed8a5ae10ce88a64dc0945c90ce436cdb1ff62502f9cdd66beb6f7", + "pair": "thickness->rotate", + "shape": { + "area": 953.28, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-pad", + "pair": "thickness->pad", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "755445fa4b9aa088225fcef6612f6aa04367c2214054c7badb8718cc2122f30e", + "namingSemanticSha256": "70b18a707401bbcc861cb417fa4c2a6f858087621b401ec4cf6337284080df69" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "length", + "trajectory": [ + 5, + 7.5, + 5 + ], + "stable": true, + "attempts": [ + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 7.5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "nativeTypeId": "PartDesign::Pad", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Body", + "typeId": "PartDesign::Body" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + }, + { + "name": "PairResult", + "typeId": "PartDesign::Pad" + } + ], + "parameter": { + "name": "length", + "value": 5 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "FeatureExtrusion: Length: Could not extrude the sketch!" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "PartDesign::Pad", + "operation": "pad", + "pair": "thickness->pad", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-thickness-pocket", + "pair": "thickness->pocket", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "158f351106d0b3e4656ffb17aa7f9148d37d4fad0cbcdfa0fc47552f0e7dafea", + "namingSemanticSha256": "0327d8ab41c0097953c2e929905ad449f8562453d884294ef3225713e7bc65b7" + }, + "second": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 39, + "vertices": 26, + "volume": 176.592, + "area": 906.32, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 72, + "selectedRecords": 9, + "ambiguousResults": 15, + "historySha256": "431f1ebda32b44a28795d3d668c8f35cef570d461d4eb6480336161e67ed27d3", + "namingEvidenceSha256": "6cb055654da1a4b727c2184dca1a3aea62a6947308d6647fb989bc019e2cf1d6", + "namingSemanticSha256": "bfd5c5bdf5f07236219703c31916358108310052cd165059dc045f3d541395a8" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "length", + "trajectory": [ + 5, + 4, + 5 + ], + "beforeValue": 5, + "editedValue": 4, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 39, + "vertices": 26, + "volume": 178.432, + "area": 914.72, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 72, + "selectedRecords": 9, + "ambiguousResults": 15, + "historySha256": "431f1ebda32b44a28795d3d668c8f35cef570d461d4eb6480336161e67ed27d3", + "namingEvidenceSha256": "3f44561123a3ad80949f415ebf0669560381387114eab8bf4ef3153945898dca", + "namingSemanticSha256": "bfd5c5bdf5f07236219703c31916358108310052cd165059dc045f3d541395a8" + }, + "restoredEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 39, + "vertices": 26, + "volume": 176.592, + "area": 906.32, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 72, + "selectedRecords": 9, + "ambiguousResults": 15, + "historySha256": "431f1ebda32b44a28795d3d668c8f35cef570d461d4eb6480336161e67ed27d3", + "namingEvidenceSha256": "8a822cc88e565885781dc9a02ed90e9fd241d0b4a05cf8098412a9b4610795c5", + "namingSemanticSha256": "bfd5c5bdf5f07236219703c31916358108310052cd165059dc045f3d541395a8" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->pocket", + "phases": { + "initial": { + "namingEvidenceBytes": 8390, + "namingEvidenceSha256": "6cb055654da1a4b727c2184dca1a3aea62a6947308d6647fb989bc019e2cf1d6", + "pair": "thickness->pocket", + "shape": { + "area": 906.32, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 39, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 176.592 + } + }, + "reopened": { + "namingEvidenceBytes": 8390, + "namingEvidenceSha256": "6cb055654da1a4b727c2184dca1a3aea62a6947308d6647fb989bc019e2cf1d6", + "pair": "thickness->pocket", + "shape": { + "area": 906.32, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 39, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 176.592 + } + }, + "resaved": { + "namingEvidenceBytes": 8390, + "namingEvidenceSha256": "6cb055654da1a4b727c2184dca1a3aea62a6947308d6647fb989bc019e2cf1d6", + "pair": "thickness->pocket", + "shape": { + "area": 906.32, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 39, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 176.592 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-loft", + "pair": "thickness->loft", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "cae1c197f0d16797ffa1f45614bf690f919fbe96cbdcf271c0af2d161f17c88c", + "namingSemanticSha256": "86d67e3875bfa70a8c9b4bd622bb5ac1c7dd1c443381b2cff05e6d540493432c" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "ruled", + "trajectory": [ + false, + true, + false + ], + "kernelAttempts": [ + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": true, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + } + ] + }, + "inputShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "nativeTypeId": "Part::Loft", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Loft" + } + ], + "parameter": { + "name": "ruled", + "value": false + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Profile shape is not a single vertex, edge, wire nor face." + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Loft", + "operation": "loft", + "pair": "thickness->loft", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-thickness-pipe", + "pair": "thickness->pipe", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "91d15558a1378ab05e49554482dbc47f5388998013da82d55f00e259c44e3fb5", + "namingSemanticSha256": "5d23fc53d5e87d61978569df1f086be05900c64abbfd7ee1b011a08e56e16c2e" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "spineLength", + "trajectory": [ + 15, + 12, + 15 + ], + "kernelAttempts": [ + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 25.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 12, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 440, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 22.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 25.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "spine": { + "name": "Spine", + "subelements": [], + "typeId": "Part::Feature" + } + }, + "inputShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "nativeTypeId": "Part::Sweep", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Spine", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Sweep" + } + ], + "parameter": { + "name": "spineLength", + "value": 15 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "A fatal error occurred when making the sweep" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Sweep", + "operation": "pipe", + "pair": "thickness->pipe", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-thickness-revolution", + "pair": "thickness->revolution", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "feea7885850de1676867a572febb019e7cebf5d4cac5382198474741f5fca793", + "namingSemanticSha256": "9c01ed0f4f6fec33ec91c27d7b606c4bd8eb087f0bccc2f2d1b6d4d0292a6374" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "angle", + "trajectory": [ + 360, + 270, + 360 + ], + "stable": true, + "attempts": [ + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 270, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "nativeTypeId": "Part::Revolution", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Revolution" + } + ], + "parameter": { + "name": "angle", + "value": 360 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Solids are not Processed" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Revolution", + "operation": "revolution", + "pair": "thickness->revolution", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-thickness-groove", + "pair": "thickness->groove", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "eb93ff3a73a6af3d932bfbbc9731370fa66722fb570c0340f2a181e0d5c22846", + "namingSemanticSha256": "d8762bcedf30c5e85c9b521e5e386defd93087184d0807916e8ec4a7b097fa78" + }, + "second": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 45, + "vertices": 30, + "volume": 184.9681824, + "area": 947.4500354, + "bounds": [ + -2e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 29, + "selectedRecords": 9, + "ambiguousResults": 10, + "historySha256": "b6de70b83486bd5124b6af415d6d94969f21c973a718c668967401bd794d4b0c", + "namingEvidenceSha256": "3aeb73544e8fe5faa5cfc793ec7a001079884058af709f169972c834ea98c5be", + "namingSemanticSha256": "5aa9883ee31f3a543ee7a5a3676b91ce4bc0695ce9c6c4a6507c3522c74066e2" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 360, + 180, + 360 + ], + "beforeValue": 360, + "editedValue": 180, + "restoredValue": 360, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 28, + "vertices": 20, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 56, + "selectedRecords": 1, + "ambiguousResults": 5, + "historySha256": "8ad56defce25986876f3c5086e85656717b25fee7b4fa0b7dc1fef1e978cab07", + "namingEvidenceSha256": "ac8b43968ecf455e8d9b58870d2ee66dda4843696564425c5fe32043d3a0c907", + "namingSemanticSha256": "bf7a86c3cac7ed68cb965b227e526b00507a0fd297e6590b8e20b13fed9608ca" + }, + "restoredEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 45, + "vertices": 30, + "volume": 184.9681824, + "area": 947.4500354, + "bounds": [ + -2e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 29, + "selectedRecords": 9, + "ambiguousResults": 10, + "historySha256": "b6de70b83486bd5124b6af415d6d94969f21c973a718c668967401bd794d4b0c", + "namingEvidenceSha256": "f2bb9930e9cb850862f538cfbcbaca54be489d3c5b6ea2c28fe8e41e2e4284ee", + "namingSemanticSha256": "5aa9883ee31f3a543ee7a5a3676b91ce4bc0695ce9c6c4a6507c3522c74066e2" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->groove", + "phases": { + "initial": { + "namingEvidenceBytes": 7142, + "namingEvidenceSha256": "3aeb73544e8fe5faa5cfc793ec7a001079884058af709f169972c834ea98c5be", + "pair": "thickness->groove", + "shape": { + "area": 947.4500354, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 45, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 30, + "volume": 184.9681824 + } + }, + "reopened": { + "namingEvidenceBytes": 7142, + "namingEvidenceSha256": "3aeb73544e8fe5faa5cfc793ec7a001079884058af709f169972c834ea98c5be", + "pair": "thickness->groove", + "shape": { + "area": 947.4500354, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 45, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 30, + "volume": 184.9681824 + } + }, + "resaved": { + "namingEvidenceBytes": 7142, + "namingEvidenceSha256": "3aeb73544e8fe5faa5cfc793ec7a001079884058af709f169972c834ea98c5be", + "pair": "thickness->groove", + "shape": { + "area": 947.4500354, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 45, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 30, + "volume": 184.9681824 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-fillet", + "pair": "thickness->fillet", + "classification": "rejected", + "reasonCode": "native-builder-wasm-abort-with-freecad-profile-acceptance-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "8b06cfe0912ff68b72dec0a20618b2ec9450ae196a1f91d8c782644c9d57472f", + "namingSemanticSha256": "83825adf7e0d7af358320933636ab154c7ee5a9566ae8a88870a1d996fd9bd1b" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "radius", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "stable": true, + "attempts": [ + { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "parameter": "radius", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "null function or function signature mismatch" + }, + { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "parameter": "radius", + "parameterValue": 0.6, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "null function or function signature mismatch" + }, + { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "parameter": "radius", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "null function or function signature mismatch" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": true, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": false, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "selectedEdges": [ + 1 + ], + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "nativeTypeId": "Part::Fillet", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Fillet" + } + ], + "parameter": { + "name": "radius", + "value": 0.4 + }, + "recomputeResult": true, + "resultShape": { + "area": 951.4945127, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 27, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 187.1126371 + }, + "shapeNull": false, + "shapeValid": true, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Fillet", + "operation": "fillet", + "pair": "thickness->fillet", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-thickness-chamfer", + "pair": "thickness->chamfer", + "classification": "rejected", + "reasonCode": "native-builder-cpp-exception-with-freecad-profile-acceptance-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "86118b23d992c9de2ca97f5f9d02353ae9f2d0531f71e36e6ecc1657a1bec926", + "namingSemanticSha256": "debb34e1857783aa434df4075889a8bc0fbe4c55b08c7460324582393b3ee119" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "distance", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "stable": true, + "attempts": [ + { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "parameter": "distance", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "parameter": "distance", + "parameterValue": 0.6, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "parameter": "distance", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": true, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": false, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "selectedEdges": [ + 1 + ], + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "nativeTypeId": "Part::Chamfer", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Chamfer" + } + ], + "parameter": { + "name": "distance", + "value": 0.4 + }, + "recomputeResult": true, + "resultShape": { + "area": 950.7768542, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 27, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 186.656 + }, + "shapeNull": false, + "shapeValid": true, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Chamfer", + "operation": "chamfer", + "pair": "thickness->chamfer", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-thickness-hole", + "pair": "thickness->hole", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "41c8d37b8b8a4c63885f3bf17e4f55c239892991b0b7601a2998383034e52367", + "namingSemanticSha256": "876853063a04ae6cbafc2614de8695448c5379d653e2abbd16f63046f38451be" + }, + "second": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 30, + "vertices": 20, + "volume": 184.9427259, + "area": 945.7401776, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 28, + "selectedRecords": 4, + "ambiguousResults": 0, + "historySha256": "a899d76a2e3538013749bf0e3c152cd6d3a2d7574f573be9af9eae7193b0e46e", + "namingEvidenceSha256": "6d68be45a1cec9489344fda0525505eee16efe476dff6e0210d91a7cc13fc4dd", + "namingSemanticSha256": "b281b5228cfd72fdddc50db75fe7f9ee32d58729d46c19aa6257d5da72dd631a" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 1, + 1.5, + 1 + ], + "beforeValue": 1, + "editedValue": 1.5, + "restoredValue": 1, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 30, + "vertices": 20, + "volume": 181.8011332, + "area": 932.5454885, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 28, + "selectedRecords": 4, + "ambiguousResults": 0, + "historySha256": "a899d76a2e3538013749bf0e3c152cd6d3a2d7574f573be9af9eae7193b0e46e", + "namingEvidenceSha256": "26bd8b8252e3acf2644452bda161c888b0ca2188dfd97747fb62e7729b6aec36", + "namingSemanticSha256": "b281b5228cfd72fdddc50db75fe7f9ee32d58729d46c19aa6257d5da72dd631a" + }, + "restoredEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 30, + "vertices": 20, + "volume": 184.9427259, + "area": 945.7401776, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 28, + "selectedRecords": 4, + "ambiguousResults": 0, + "historySha256": "a899d76a2e3538013749bf0e3c152cd6d3a2d7574f573be9af9eae7193b0e46e", + "namingEvidenceSha256": "bae6e05854a4668a7d447c97fccb743235edf0041734255156564a8d634d7a8a", + "namingSemanticSha256": "b281b5228cfd72fdddc50db75fe7f9ee32d58729d46c19aa6257d5da72dd631a" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->hole", + "phases": { + "initial": { + "namingEvidenceBytes": 2462, + "namingEvidenceSha256": "6d68be45a1cec9489344fda0525505eee16efe476dff6e0210d91a7cc13fc4dd", + "pair": "thickness->hole", + "shape": { + "area": 945.7401776, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 30, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 184.9427259 + } + }, + "reopened": { + "namingEvidenceBytes": 2462, + "namingEvidenceSha256": "6d68be45a1cec9489344fda0525505eee16efe476dff6e0210d91a7cc13fc4dd", + "pair": "thickness->hole", + "shape": { + "area": 945.7401776, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 30, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 184.9427259 + } + }, + "resaved": { + "namingEvidenceBytes": 2462, + "namingEvidenceSha256": "6d68be45a1cec9489344fda0525505eee16efe476dff6e0210d91a7cc13fc4dd", + "pair": "thickness->hole", + "shape": { + "area": 945.7401776, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 30, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 20, + "volume": 184.9427259 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-draft", + "pair": "thickness->draft", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "f1521b3a87c1e870ca852e3058b9cb99ef4d371447aea0acc4abc6df3a796aef", + "namingSemanticSha256": "15bdf8b8c04ccbac6d839a14675ce3c596dfea1a09d51626986d222ae9eb5100" + }, + "second": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 143.7116682, + "area": 936.164251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "facf324ceebdb8d2326624c0ea67b8c18795fe0c7da69f4c61056f53e9bd330f", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 5, + 8, + 5 + ], + "beforeValue": 5, + "editedValue": 8, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 117.1855826, + "area": 926.1545903, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "5f54050864387440c58a375634d61a5e5dd3e19760a8c52217a0d3109ebf9a32", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + }, + "restoredEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 143.7116682, + "area": 936.164251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "7008094e861c354216a758455e41c67a9d8ee15b88a0cadeb401c729633b99b8", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->draft", + "phases": { + "initial": { + "namingEvidenceBytes": 2310, + "namingEvidenceSha256": "facf324ceebdb8d2326624c0ea67b8c18795fe0c7da69f4c61056f53e9bd330f", + "pair": "thickness->draft", + "shape": { + "area": 936.164251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 143.7116682 + } + }, + "reopened": { + "namingEvidenceBytes": 2310, + "namingEvidenceSha256": "facf324ceebdb8d2326624c0ea67b8c18795fe0c7da69f4c61056f53e9bd330f", + "pair": "thickness->draft", + "shape": { + "area": 936.164251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 143.7116682 + } + }, + "resaved": { + "namingEvidenceBytes": 2310, + "namingEvidenceSha256": "facf324ceebdb8d2326624c0ea67b8c18795fe0c7da69f4c61056f53e9bd330f", + "pair": "thickness->draft", + "shape": { + "area": 936.164251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 143.7116682 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-thickness", + "pair": "thickness->thickness", + "classification": "rejected", + "reasonCode": "native-and-freecad-profile-no-op-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "91f6c3b23ad679f45f013b6431a5375ac01121037fd8955a17338ea52d4c2f79", + "namingSemanticSha256": "5998d637433094036d86c027bd97d11db9855fe4483ec48bd2464a45f9931503" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-no-op", + "parameter": "offset", + "trajectory": [ + -0.4, + -0.6, + -0.4 + ], + "kernelAttempts": [ + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.4, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "fc6c63f8a04dc8e90ef35000546f4a96faeb01dfca8db877204f32a995a32256", + "authority": "kernel-no-op" + }, + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.6, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "fc6c63f8a04dc8e90ef35000546f4a96faeb01dfca8db877204f32a995a32256", + "authority": "kernel-no-op" + }, + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.4, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "fc6c63f8a04dc8e90ef35000546f4a96faeb01dfca8db877204f32a995a32256", + "authority": "kernel-no-op" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "freecadProfileNoOp": true, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": false, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [ + "Face2" + ], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "nativeTypeId": "Part::Thickness", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Thickness" + } + ], + "parameter": { + "name": "offset", + "value": -0.4 + }, + "recomputeResult": true, + "resultShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "shapeNull": false, + "shapeValid": true, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Thickness", + "operation": "thickness", + "pair": "thickness->thickness", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "eafb7b897994f24397f8950428ddc2d4b569b87daa9f19dbcb9fbb115fdd6e0e", + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-thickness-linear-pattern", + "pair": "thickness->linear-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "9801998fc4cddcf8c66444bebf77e862e0ff8c4bc4ffa8d70f8e584f4eb0c581", + "namingSemanticSha256": "4428580f164028822ce6d05322cf25a20303e657d6b2b9ff3e78fc92c617204b" + }, + "second": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 60, + "vertices": 36, + "volume": 344.192, + "area": 1722.24, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 130, + "selectedRecords": 16, + "ambiguousResults": 24, + "historySha256": "c24d917998539613f5d98238ad41114771953e4c4374b4d7be2b448019abbb90", + "namingEvidenceSha256": "52354b963d5498854e8dc378c5aeaa6e5484f066e51cae9c25cc2f6e6686de00", + "namingSemanticSha256": "08a27a69fc88d2bbf3acebe201b314eaacbfe2ea018bcbcd1aa4a09cbd8f839d" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "translationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 60, + "vertices": 36, + "volume": 359.552, + "area": 1799.04, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 19.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 130, + "selectedRecords": 16, + "ambiguousResults": 24, + "historySha256": "c24d917998539613f5d98238ad41114771953e4c4374b4d7be2b448019abbb90", + "namingEvidenceSha256": "bbefa24d197e1407e8f0ee426e6da712e127c9bfcbac07b71ef20883e96de010", + "namingSemanticSha256": "08a27a69fc88d2bbf3acebe201b314eaacbfe2ea018bcbcd1aa4a09cbd8f839d" + }, + "restoredEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 60, + "vertices": 36, + "volume": 344.192, + "area": 1722.24, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 130, + "selectedRecords": 16, + "ambiguousResults": 24, + "historySha256": "c24d917998539613f5d98238ad41114771953e4c4374b4d7be2b448019abbb90", + "namingEvidenceSha256": "c5096904d2acf271c7328a27cd9de13929d8337f88cbfd9c6b37364653fdaccc", + "namingSemanticSha256": "08a27a69fc88d2bbf3acebe201b314eaacbfe2ea018bcbcd1aa4a09cbd8f839d" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->linear-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 14555, + "namingEvidenceSha256": "52354b963d5498854e8dc378c5aeaa6e5484f066e51cae9c25cc2f6e6686de00", + "pair": "thickness->linear-pattern", + "shape": { + "area": 1722.24, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 60, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 36, + "volume": 344.192 + } + }, + "reopened": { + "namingEvidenceBytes": 14555, + "namingEvidenceSha256": "52354b963d5498854e8dc378c5aeaa6e5484f066e51cae9c25cc2f6e6686de00", + "pair": "thickness->linear-pattern", + "shape": { + "area": 1722.24, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 60, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 36, + "volume": 344.192 + } + }, + "resaved": { + "namingEvidenceBytes": 14555, + "namingEvidenceSha256": "52354b963d5498854e8dc378c5aeaa6e5484f066e51cae9c25cc2f6e6686de00", + "pair": "thickness->linear-pattern", + "shape": { + "area": 1722.24, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 60, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 36, + "volume": 344.192 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-polar-pattern", + "pair": "thickness->polar-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "3cc5c57d8bad3d3bd5b38c8c5a1353e7205e66ddfc199abead763b6c23e99dfc", + "namingSemanticSha256": "b1e8c898bdbffb7ec08e5b24950f58d4b4be4c6bc5914d5c63d175ebdc21e5ac" + }, + "second": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 27, + "edges": 66, + "vertices": 42, + "volume": 326.5688209, + "area": 1625.3550126, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 152, + "selectedRecords": 14, + "ambiguousResults": 20, + "historySha256": "cfa52baa6e35c19f3c5373ad6f2df404665a5819246958658889b796a383013d", + "namingEvidenceSha256": "60e3972b15d8ca477fddc36be91216bdfc00329f69d76d3679c5d2638b90bc2e", + "namingSemanticSha256": "39e73f7b26bc2bb0e793cdcb9216509289ce43b289d15c58d4728c0bac925920" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 30, + 45, + 30 + ], + "beforeValue": 30, + "editedValue": 45, + "restoredValue": 30, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 27, + "edges": 66, + "vertices": 42, + "volume": 339.6931926, + "area": 1697.8824828, + "bounds": [ + -7.071068, + -1e-7, + -1e-7, + 10.0000001, + 14.1421358, + 10.0000001 + ] + }, + "historyRecords": 118, + "selectedRecords": 13, + "ambiguousResults": 19, + "historySha256": "5d820f45e11f882dce0badec90ee80b8bd15b64c83e1f1e8a99d235c27e2d77e", + "namingEvidenceSha256": "871772df10e5aa02b0f66076ac86f5e7921bc7c668e8b5ec9055dc3dd6ad1c27", + "namingSemanticSha256": "f11a65011ef7b323cbb13290b1c47b584ec257a301f29b0f90dd7a6097b1c194" + }, + "restoredEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 27, + "edges": 66, + "vertices": 42, + "volume": 326.5688209, + "area": 1625.3550126, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 152, + "selectedRecords": 14, + "ambiguousResults": 20, + "historySha256": "cfa52baa6e35c19f3c5373ad6f2df404665a5819246958658889b796a383013d", + "namingEvidenceSha256": "368ff31664d569ea835193360e3559b9aea525319b62b02f1c411ba37af6f42b", + "namingSemanticSha256": "39e73f7b26bc2bb0e793cdcb9216509289ce43b289d15c58d4728c0bac925920" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->polar-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 12807, + "namingEvidenceSha256": "60e3972b15d8ca477fddc36be91216bdfc00329f69d76d3679c5d2638b90bc2e", + "pair": "thickness->polar-pattern", + "shape": { + "area": 1625.3550126, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 66, + "faces": 27, + "solids": 1, + "valid": true, + "vertices": 42, + "volume": 326.5688209 + } + }, + "reopened": { + "namingEvidenceBytes": 12807, + "namingEvidenceSha256": "60e3972b15d8ca477fddc36be91216bdfc00329f69d76d3679c5d2638b90bc2e", + "pair": "thickness->polar-pattern", + "shape": { + "area": 1625.3550126, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 66, + "faces": 27, + "solids": 1, + "valid": true, + "vertices": 42, + "volume": 326.5688209 + } + }, + "resaved": { + "namingEvidenceBytes": 12807, + "namingEvidenceSha256": "60e3972b15d8ca477fddc36be91216bdfc00329f69d76d3679c5d2638b90bc2e", + "pair": "thickness->polar-pattern", + "shape": { + "area": 1625.3550126, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 66, + "faces": 27, + "solids": 1, + "valid": true, + "vertices": 42, + "volume": 326.5688209 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-mirrored", + "pair": "thickness->mirrored", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "9f87dc3f54f8b19da0d8e2210ea9116153d2020d87dc08b066b2ec9f5f289036", + "namingSemanticSha256": "db6d6c84ae2d35c3242d07a4835c2e7fa1e3948afaa5a0a30f310756f4b9aa77" + }, + "second": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 32, + "vertices": 24, + "volume": 221.312, + "area": 1107.84, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 214, + "selectedRecords": 11, + "ambiguousResults": 32, + "historySha256": "4c0c4377b53a8f3714e6f82cf42e113f36cc46e720a3e3e9fdd15a619b53341b", + "namingEvidenceSha256": "11e17aea66ff072ceb8c44e88c3c5803cf48a1a1e1cb50df49db9c96269757c1", + "namingSemanticSha256": "d656391ce5ecf06377e7df4a1126f1efff3e14a893a3a8ec4b3cd456f9907d93" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "planeOriginX", + "trajectory": [ + 5, + 6, + 5 + ], + "beforeValue": 5, + "editedValue": 6, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 28, + "edges": 56, + "vertices": 32, + "volume": 252.032, + "area": 1261.44, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 12.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 130, + "selectedRecords": 16, + "ambiguousResults": 24, + "historySha256": "8d37f3fa4d6b12263eaa0454c2ae5e01f61bc72820699f4586ba8bfea23e98ff", + "namingEvidenceSha256": "171c034008a09d6f567454fcf06c4f3d424884fbc4b8729ea05b5db132aa1533", + "namingSemanticSha256": "eeb80a4d5cfa51cf267af9b714d4a52ef4cd5e0f0cd627819a9bd2889a2b0536" + }, + "restoredEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 32, + "vertices": 24, + "volume": 221.312, + "area": 1107.84, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 214, + "selectedRecords": 11, + "ambiguousResults": 32, + "historySha256": "4c0c4377b53a8f3714e6f82cf42e113f36cc46e720a3e3e9fdd15a619b53341b", + "namingEvidenceSha256": "151ff5558d434e13db9f4d59ad19f135045fa4054ad3fd6fcc2a87900cab5649", + "namingSemanticSha256": "d656391ce5ecf06377e7df4a1126f1efff3e14a893a3a8ec4b3cd456f9907d93" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->mirrored", + "phases": { + "initial": { + "namingEvidenceBytes": 16388, + "namingEvidenceSha256": "11e17aea66ff072ceb8c44e88c3c5803cf48a1a1e1cb50df49db9c96269757c1", + "pair": "thickness->mirrored", + "shape": { + "area": 1107.84, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 32, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 221.312 + } + }, + "reopened": { + "namingEvidenceBytes": 16388, + "namingEvidenceSha256": "11e17aea66ff072ceb8c44e88c3c5803cf48a1a1e1cb50df49db9c96269757c1", + "pair": "thickness->mirrored", + "shape": { + "area": 1107.84, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 32, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 221.312 + } + }, + "resaved": { + "namingEvidenceBytes": 16388, + "namingEvidenceSha256": "11e17aea66ff072ceb8c44e88c3c5803cf48a1a1e1cb50df49db9c96269757c1", + "pair": "thickness->mirrored", + "shape": { + "area": 1107.84, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 32, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 221.312 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-thickness-multi-transform", + "pair": "thickness->multi-transform", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "aa204d4aa6adb782dfbd8caa8fe653c41371d2e03c06a44a33e252a8077384b6", + "namingEvidenceSha256": "271d419ffb2d39b6e4c4c4ccc6f42c12e1b8a434a169e17bc4c470a632250b90", + "namingSemanticSha256": "f53ed38ca273c5bf9868d7eaa1491ea889435ecbc019823fa6283b7ce18e08a4" + }, + "second": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 50, + "edges": 104, + "vertices": 64, + "volume": 534.784, + "area": 2645.76, + "bounds": [ + -8.0000002, + -2e-7, + -2e-7, + 18.0000002, + 10.0000002, + 10.0000002 + ] + }, + "historyRecords": 714, + "selectedRecords": 50, + "ambiguousResults": 152, + "historySha256": "1b5a6aaccff5f974eb2e29673893e572d49b8d2de129dc5fac07293b77a927dc", + "namingEvidenceSha256": "9b00aefd65818e5f93f466a35b422ba0a35e2ceab8721e6226a2df69666c6540", + "namingSemanticSha256": "ccab0c9e173a6447c63c7070ad16aa66c9fc83aaf6cf7b728a0f7ba66c28b570" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "multiTranslationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 50, + "edges": 104, + "vertices": 64, + "volume": 565.504, + "area": 2799.36, + "bounds": [ + -9.0000002, + -2e-7, + -2e-7, + 19.0000002, + 10.0000002, + 10.0000002 + ] + }, + "historyRecords": 714, + "selectedRecords": 50, + "ambiguousResults": 152, + "historySha256": "1b5a6aaccff5f974eb2e29673893e572d49b8d2de129dc5fac07293b77a927dc", + "namingEvidenceSha256": "6cbc1e42aed5c54a397cc30b95174d9cad8e06a65fde2c9ef86e72a3882bbbae", + "namingSemanticSha256": "ccab0c9e173a6447c63c7070ad16aa66c9fc83aaf6cf7b728a0f7ba66c28b570" + }, + "restoredEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 50, + "edges": 104, + "vertices": 64, + "volume": 534.784, + "area": 2645.76, + "bounds": [ + -8.0000002, + -2e-7, + -2e-7, + 18.0000002, + 10.0000002, + 10.0000002 + ] + }, + "historyRecords": 714, + "selectedRecords": 50, + "ambiguousResults": 152, + "historySha256": "1b5a6aaccff5f974eb2e29673893e572d49b8d2de129dc5fac07293b77a927dc", + "namingEvidenceSha256": "9eb35244812d6d3eac0028f850558a9db5f6b845d263413732901bcd292d704e", + "namingSemanticSha256": "ccab0c9e173a6447c63c7070ad16aa66c9fc83aaf6cf7b728a0f7ba66c28b570" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "thickness->multi-transform", + "phases": { + "initial": { + "namingEvidenceBytes": 97626, + "namingEvidenceSha256": "9b00aefd65818e5f93f466a35b422ba0a35e2ceab8721e6226a2df69666c6540", + "pair": "thickness->multi-transform", + "shape": { + "area": 2645.76, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 104, + "faces": 50, + "solids": 1, + "valid": true, + "vertices": 64, + "volume": 534.784 + } + }, + "reopened": { + "namingEvidenceBytes": 97626, + "namingEvidenceSha256": "9b00aefd65818e5f93f466a35b422ba0a35e2ceab8721e6226a2df69666c6540", + "pair": "thickness->multi-transform", + "shape": { + "area": 2645.76, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 104, + "faces": 50, + "solids": 1, + "valid": true, + "vertices": 64, + "volume": 534.784 + } + }, + "resaved": { + "namingEvidenceBytes": 97626, + "namingEvidenceSha256": "9b00aefd65818e5f93f466a35b422ba0a35e2ceab8721e6226a2df69666c6540", + "pair": "thickness->multi-transform", + "shape": { + "area": 2645.76, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 104, + "faces": 50, + "solids": 1, + "valid": true, + "vertices": 64, + "volume": 534.784 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-fuse", + "pair": "linear-pattern->fuse", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "5050fb3048ce131ca9a42a41cb3fcf669878bb9393d1b876e7f68bc67c206bfa", + "namingSemanticSha256": "1b75342438793aaf06c80943d900d95be8d81159055cca27d091fdeb8f832133" + }, + "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": 1875, + "area": 980, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 21.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "e76399acc6cea462fe70443f1c03d9004c38183aabf8ee3e274c028994dc6158", + "namingEvidenceSha256": "2834ea3b45cc05a23e0ca599c594cd6c57839b3ac8b7cb8feed4fa3d0cfc565b", + "namingSemanticSha256": "cd20eff8ce6330f194d1213c5566fbf20da37c3a52e51dafa2264762042c2257" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 16, + 15, + 16 + ], + "beforeValue": 16, + "editedValue": 15, + "restoredValue": 16, + "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": 1850, + "area": 960, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 20.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "e76399acc6cea462fe70443f1c03d9004c38183aabf8ee3e274c028994dc6158", + "namingEvidenceSha256": "92180cc12b64dd069e8eb948e9174f0d08cf98b463704970c99da9f1af58f708", + "namingSemanticSha256": "cd20eff8ce6330f194d1213c5566fbf20da37c3a52e51dafa2264762042c2257" + }, + "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": 1875, + "area": 980, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 21.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "e76399acc6cea462fe70443f1c03d9004c38183aabf8ee3e274c028994dc6158", + "namingEvidenceSha256": "833e00b0e4ba6bfc679cd98c56352b263902e32d7878fd5167c7d3203093b574", + "namingSemanticSha256": "cd20eff8ce6330f194d1213c5566fbf20da37c3a52e51dafa2264762042c2257" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->fuse", + "phases": { + "initial": { + "namingEvidenceBytes": 8317, + "namingEvidenceSha256": "2834ea3b45cc05a23e0ca599c594cd6c57839b3ac8b7cb8feed4fa3d0cfc565b", + "pair": "linear-pattern->fuse", + "shape": { + "area": 980, + "bounds": [ + 0, + 0, + 0, + 21, + 10, + 10 + ], + "edges": 45, + "faces": 21, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1875 + } + }, + "reopened": { + "namingEvidenceBytes": 8317, + "namingEvidenceSha256": "2834ea3b45cc05a23e0ca599c594cd6c57839b3ac8b7cb8feed4fa3d0cfc565b", + "pair": "linear-pattern->fuse", + "shape": { + "area": 980, + "bounds": [ + 0, + 0, + 0, + 21, + 10, + 10 + ], + "edges": 45, + "faces": 21, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1875 + } + }, + "resaved": { + "namingEvidenceBytes": 8317, + "namingEvidenceSha256": "2834ea3b45cc05a23e0ca599c594cd6c57839b3ac8b7cb8feed4fa3d0cfc565b", + "pair": "linear-pattern->fuse", + "shape": { + "area": 980, + "bounds": [ + 0, + 0, + 0, + 21, + 10, + 10 + ], + "edges": 45, + "faces": 21, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1875 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-cut", + "pair": "linear-pattern->cut", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "b943c3abe7fb06ba6f581b92214dc8989e07b6d1b06514818f369f9afe9f43ea", + "namingSemanticSha256": "8b3f84ca25c975484d9e88d2a9eeb62a3f8dbbf889eb9c7d379057108b98eb31" + }, + "second": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 18, + "edges": 40, + "vertices": 24, + "volume": 1736, + "area": 952, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 22, + "selectedRecords": 2, + "ambiguousResults": 8, + "historySha256": "4c7f022272b945258c91787fcce83c42dd50e9790325e1d47d722cdcaf166a6e", + "namingEvidenceSha256": "2c8836f557ba3e940431641a73513bd10d2f11c5178216e66c983d93f6682954", + "namingSemanticSha256": "08854beaa755b81385da1d015c7e3ffe28fbbb425dffb365be4485204f7ed0a1" + }, + "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": 18, + "edges": 40, + "vertices": 24, + "volume": 1773, + "area": 938, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 22, + "selectedRecords": 2, + "ambiguousResults": 8, + "historySha256": "4c7f022272b945258c91787fcce83c42dd50e9790325e1d47d722cdcaf166a6e", + "namingEvidenceSha256": "36177e76d761a675959b8c94f8f2793118bed7fdc6ff11e882b0ed97a913ea58", + "namingSemanticSha256": "08854beaa755b81385da1d015c7e3ffe28fbbb425dffb365be4485204f7ed0a1" + }, + "restoredEvidence": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 18, + "edges": 40, + "vertices": 24, + "volume": 1736, + "area": 952, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 22, + "selectedRecords": 2, + "ambiguousResults": 8, + "historySha256": "4c7f022272b945258c91787fcce83c42dd50e9790325e1d47d722cdcaf166a6e", + "namingEvidenceSha256": "f30941090e20fc930182dbf37547448d6d08692b561425d485e287af7c192144", + "namingSemanticSha256": "08854beaa755b81385da1d015c7e3ffe28fbbb425dffb365be4485204f7ed0a1" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->cut", + "phases": { + "initial": { + "namingEvidenceBytes": 4071, + "namingEvidenceSha256": "2c8836f557ba3e940431641a73513bd10d2f11c5178216e66c983d93f6682954", + "pair": "linear-pattern->cut", + "shape": { + "area": 952, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 40, + "faces": 18, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 1736 + } + }, + "reopened": { + "namingEvidenceBytes": 4071, + "namingEvidenceSha256": "2c8836f557ba3e940431641a73513bd10d2f11c5178216e66c983d93f6682954", + "pair": "linear-pattern->cut", + "shape": { + "area": 952, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 40, + "faces": 18, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 1736 + } + }, + "resaved": { + "namingEvidenceBytes": 4071, + "namingEvidenceSha256": "2c8836f557ba3e940431641a73513bd10d2f11c5178216e66c983d93f6682954", + "pair": "linear-pattern->cut", + "shape": { + "area": 952, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 40, + "faces": 18, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 1736 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-common", + "pair": "linear-pattern->common", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "45bd87c162a69dbfc0f2d21d03f8c11091ac4cdc305666b70bb1654abdb2e794", + "namingSemanticSha256": "08ae709a140b68c6ac71f1a21e826774e21f387f7a4fb379875049ed85f5765d" + }, + "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": 125, + "area": 150, + "bounds": [ + 9.9999999, + -1e-7, + -1e-7, + 15.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 205, + "selectedRecords": 1, + "ambiguousResults": 10, + "historySha256": "a0a31dd3bd150e2a0791ac7ec4fef1b4e455133f55a1758f56388a77c7ea3c3e", + "namingEvidenceSha256": "655fa2c54602f52569d56ed331c66ecd7e306f3a76ae93abb837b66d7d91c3cd", + "namingSemanticSha256": "53c20b31d6a824f7e4b1d039cbc00417b114a19c03b277f6b4262116d473d896" + }, + "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": 8, + "edges": 17, + "vertices": 11, + "volume": 125, + "area": 150, + "bounds": [ + 8.9999999, + -1e-7, + -1e-7, + 14.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 200, + "selectedRecords": 2, + "ambiguousResults": 16, + "historySha256": "41ad610b22f198465c93d7c9bf0ca70ad5b8181f7a59d92b209c5711d274fd76", + "namingEvidenceSha256": "008722fa18e262108e9520eff112eb3b291042334b8e6dbe9a8f7585a7b0282c", + "namingSemanticSha256": "0f173139adc3ff50bd84d6aa0b8039dffe72304f3de7821ee1bbd98422a496d0" + }, + "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": 125, + "area": 150, + "bounds": [ + 9.9999999, + -1e-7, + -1e-7, + 15.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 205, + "selectedRecords": 1, + "ambiguousResults": 10, + "historySha256": "a0a31dd3bd150e2a0791ac7ec4fef1b4e455133f55a1758f56388a77c7ea3c3e", + "namingEvidenceSha256": "71c0120e2268ed348ba6531a6c63f069aca7cbe90f0911ebe8c01e19e95cdbb1", + "namingSemanticSha256": "53c20b31d6a824f7e4b1d039cbc00417b114a19c03b277f6b4262116d473d896" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->common", + "phases": { + "initial": { + "namingEvidenceBytes": 5221, + "namingEvidenceSha256": "655fa2c54602f52569d56ed331c66ecd7e306f3a76ae93abb837b66d7d91c3cd", + "pair": "linear-pattern->common", + "shape": { + "area": 150, + "bounds": [ + 10, + 0, + 0, + 15, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 125 + } + }, + "reopened": { + "namingEvidenceBytes": 5221, + "namingEvidenceSha256": "655fa2c54602f52569d56ed331c66ecd7e306f3a76ae93abb837b66d7d91c3cd", + "pair": "linear-pattern->common", + "shape": { + "area": 150, + "bounds": [ + 10, + 0, + 0, + 15, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 125 + } + }, + "resaved": { + "namingEvidenceBytes": 5221, + "namingEvidenceSha256": "655fa2c54602f52569d56ed331c66ecd7e306f3a76ae93abb837b66d7d91c3cd", + "pair": "linear-pattern->common", + "shape": { + "area": 150, + "bounds": [ + 10, + 0, + 0, + 15, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 125 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-rotate", + "pair": "linear-pattern->rotate", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "b02f5a0b86b9b8b97b89e2c8dd5c0a34cbff392bb53e0c62e5b79a111341ec14", + "namingSemanticSha256": "06945ffeb2542075e3b959eb19445a8aa26359b6fff371d716636672625f6be5" + }, + "second": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -2.5881906, + -1e-7, + -1e-7, + 17.386665, + 14.3180012, + 10.0000001 + ] + }, + "historyRecords": 182, + "selectedRecords": 14, + "ambiguousResults": 44, + "historySha256": "1a440efa562b7f1915e59b8e1bd76b4f2374af1faaa4d5c59831b49c9df4ec2e", + "namingEvidenceSha256": "aceb3c19fbd7f3fcc70ffd927a187a58cd2aaf895fb7cbba6f57456cc1b0efe6", + "namingSemanticSha256": "3817bf772d84f0c1419f72e28aa760a7da4b03414b248d86530afa49c947f56e" + }, + "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": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -3.8268344, + -1e-7, + -1e-7, + 16.6298317, + 16.1270972, + 10.0000001 + ] + }, + "historyRecords": 182, + "selectedRecords": 14, + "ambiguousResults": 44, + "historySha256": "1a440efa562b7f1915e59b8e1bd76b4f2374af1faaa4d5c59831b49c9df4ec2e", + "namingEvidenceSha256": "f036e755be1d064d9560e528a342f02bccf70b26ebf2c92700e7933b5218ea68", + "namingSemanticSha256": "3817bf772d84f0c1419f72e28aa760a7da4b03414b248d86530afa49c947f56e" + }, + "restoredEvidence": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -2.5881906, + -1e-7, + -1e-7, + 17.386665, + 14.3180012, + 10.0000001 + ] + }, + "historyRecords": 182, + "selectedRecords": 14, + "ambiguousResults": 44, + "historySha256": "1a440efa562b7f1915e59b8e1bd76b4f2374af1faaa4d5c59831b49c9df4ec2e", + "namingEvidenceSha256": "2e41140a43dab028761c8a6362d4e746a49ab5fd28a0e6e68c0783695a9d24cf", + "namingSemanticSha256": "3817bf772d84f0c1419f72e28aa760a7da4b03414b248d86530afa49c947f56e" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->rotate", + "phases": { + "initial": { + "namingEvidenceBytes": 25213, + "namingEvidenceSha256": "aceb3c19fbd7f3fcc70ffd927a187a58cd2aaf895fb7cbba6f57456cc1b0efe6", + "pair": "linear-pattern->rotate", + "shape": { + "area": 920, + "bounds": [ + -2.5881905, + 0, + 0, + 17.3866649, + 14.3180011, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "reopened": { + "namingEvidenceBytes": 25213, + "namingEvidenceSha256": "aceb3c19fbd7f3fcc70ffd927a187a58cd2aaf895fb7cbba6f57456cc1b0efe6", + "pair": "linear-pattern->rotate", + "shape": { + "area": 920, + "bounds": [ + -2.5881905, + 0, + 0, + 17.3866649, + 14.3180011, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "resaved": { + "namingEvidenceBytes": 25213, + "namingEvidenceSha256": "aceb3c19fbd7f3fcc70ffd927a187a58cd2aaf895fb7cbba6f57456cc1b0efe6", + "pair": "linear-pattern->rotate", + "shape": { + "area": 920, + "bounds": [ + -2.5881905, + 0, + 0, + 17.3866649, + 14.3180011, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-pad", + "pair": "linear-pattern->pad", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "6d21c28e96d1f0ae010d8bb4940a518e5edb5bec6361867e4d633ad71e1e1377", + "namingSemanticSha256": "fecf478c3fbebb406963e5c3a464994d3e2a3202287ce7143de665b4e3eee593" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "length", + "trajectory": [ + 5, + 7.5, + 5 + ], + "stable": true, + "attempts": [ + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 7.5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "nativeTypeId": "PartDesign::Pad", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Body", + "typeId": "PartDesign::Body" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + }, + { + "name": "PairResult", + "typeId": "PartDesign::Pad" + } + ], + "parameter": { + "name": "length", + "value": 5 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "FeatureExtrusion: Length: Could not extrude the sketch!" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "PartDesign::Pad", + "operation": "pad", + "pair": "linear-pattern->pad", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-pocket", + "pair": "linear-pattern->pocket", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "1164939c6fa4770ffcd10d43d113f28a3bdfb0689a16c37d08a18f8ac950bc4c", + "namingSemanticSha256": "721f3b81de44d29f6cb65a906337a9adf1987e0db770d96148ebf3939eb3b761" + }, + "second": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 17, + "edges": 37, + "vertices": 22, + "volume": 1770, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 3, + "ambiguousResults": 9, + "historySha256": "4495b8b386cb012ef7663bb6c0d3fb9d5a12238abd0503cc935e956cf2495c36", + "namingEvidenceSha256": "b06bd539d3f0a4cecb4d36fb2b8165703635ee3b7ee604f8c32bcf23e15742a5", + "namingSemanticSha256": "456b9e93e5db42eb24bba9ced9031c4d63b1a1f1070f32f5685f0e7bff999443" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "length", + "trajectory": [ + 5, + 4, + 5 + ], + "beforeValue": 5, + "editedValue": 4, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 17, + "edges": 37, + "vertices": 22, + "volume": 1776, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 3, + "ambiguousResults": 9, + "historySha256": "4495b8b386cb012ef7663bb6c0d3fb9d5a12238abd0503cc935e956cf2495c36", + "namingEvidenceSha256": "8390ce40539a1152c214ee4e89d09c148a5e16f3d92fec49235dd70402ba9e7f", + "namingSemanticSha256": "456b9e93e5db42eb24bba9ced9031c4d63b1a1f1070f32f5685f0e7bff999443" + }, + "restoredEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 17, + "edges": 37, + "vertices": 22, + "volume": 1770, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 3, + "ambiguousResults": 9, + "historySha256": "4495b8b386cb012ef7663bb6c0d3fb9d5a12238abd0503cc935e956cf2495c36", + "namingEvidenceSha256": "d5c655e565562c3490bcc71793f2970431d755a92e10e8bb59732fc38813258a", + "namingSemanticSha256": "456b9e93e5db42eb24bba9ced9031c4d63b1a1f1070f32f5685f0e7bff999443" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->pocket", + "phases": { + "initial": { + "namingEvidenceBytes": 4729, + "namingEvidenceSha256": "b06bd539d3f0a4cecb4d36fb2b8165703635ee3b7ee604f8c32bcf23e15742a5", + "pair": "linear-pattern->pocket", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 37, + "faces": 17, + "solids": 1, + "valid": true, + "vertices": 22, + "volume": 1770 + } + }, + "reopened": { + "namingEvidenceBytes": 4729, + "namingEvidenceSha256": "b06bd539d3f0a4cecb4d36fb2b8165703635ee3b7ee604f8c32bcf23e15742a5", + "pair": "linear-pattern->pocket", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 37, + "faces": 17, + "solids": 1, + "valid": true, + "vertices": 22, + "volume": 1770 + } + }, + "resaved": { + "namingEvidenceBytes": 4729, + "namingEvidenceSha256": "b06bd539d3f0a4cecb4d36fb2b8165703635ee3b7ee604f8c32bcf23e15742a5", + "pair": "linear-pattern->pocket", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 37, + "faces": 17, + "solids": 1, + "valid": true, + "vertices": 22, + "volume": 1770 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-loft", + "pair": "linear-pattern->loft", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "64cd3b717c5faf5cdff304bc890d88c0ca5ca2c6d3c58676ccf9b4dfbef769be", + "namingSemanticSha256": "17fb0139c14a4ba00eebeffa164c79dd1cadaa2965ede892af6245589f6a6bad" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "ruled", + "trajectory": [ + false, + true, + false + ], + "kernelAttempts": [ + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": true, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + } + ] + }, + "inputShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "nativeTypeId": "Part::Loft", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Loft" + } + ], + "parameter": { + "name": "ruled", + "value": false + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Profile shape is not a single vertex, edge, wire nor face." + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Loft", + "operation": "loft", + "pair": "linear-pattern->loft", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-pipe", + "pair": "linear-pattern->pipe", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "13b796f1a97b857fa572efaa4ff81802dc37c66381e2e270184efcad37cd7559", + "namingSemanticSha256": "f73f431a346b093906a998ab9973c757f0f5a2228075c1cf2860c056862050fe" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "spineLength", + "trajectory": [ + 15, + 12, + 15 + ], + "kernelAttempts": [ + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 25.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 12, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 440, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 22.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 25.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "spine": { + "name": "Spine", + "subelements": [], + "typeId": "Part::Feature" + } + }, + "inputShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "nativeTypeId": "Part::Sweep", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Spine", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Sweep" + } + ], + "parameter": { + "name": "spineLength", + "value": 15 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "A fatal error occurred when making the sweep" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Sweep", + "operation": "pipe", + "pair": "linear-pattern->pipe", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-revolution", + "pair": "linear-pattern->revolution", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "667492a2778b126a4ddcf5e363f874e821d83d5330b621cc43078ee7930a1953", + "namingSemanticSha256": "97e97fffecc0aadab9f7fccb99efb4b914a096c34bbd9d8432cd7bab791d7ed5" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "angle", + "trajectory": [ + 360, + 270, + 360 + ], + "stable": true, + "attempts": [ + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 270, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "nativeTypeId": "Part::Revolution", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Revolution" + } + ], + "parameter": { + "name": "angle", + "value": 360 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Solids are not Processed" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Revolution", + "operation": "revolution", + "pair": "linear-pattern->revolution", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-groove", + "pair": "linear-pattern->groove", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "1f902e1aa190891daeb796fcdb21ded3af1512885f5540f8a3e81e40b72431c8", + "namingSemanticSha256": "bcb6033f7ac9ad95a1d34bb44d62dd03f7f8ba267d40835212dc1bdade96df50" + }, + "second": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 18, + "edges": 40, + "vertices": 24, + "volume": 1795.287611, + "area": 926.5663706, + "bounds": [ + -2e-7, + -1e-7, + -1e-7, + 18.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "af516227420b3c0413aaba9b51458df190806683c9cf8ae57c720f4707045537", + "namingEvidenceSha256": "1200720cdfe02019685439666dc8d6781e61de6fd94495ae65201cf83b977462", + "namingSemanticSha256": "1cac4b35dcead587d3b105c66ab2ccae3462b5f0bb19986aaf1006b634827881" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 360, + 180, + 360 + ], + "beforeValue": 360, + "editedValue": 180, + "restoredValue": 360, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 15, + "edges": 32, + "vertices": 20, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 56, + "selectedRecords": 1, + "ambiguousResults": 5, + "historySha256": "35b7d1faa5aa355f4da98ab8456b0bb04d0b052cba5d4ce8ff478dd3affa0b53", + "namingEvidenceSha256": "7fa7c4fa6c22d555937946466109da90b62ac578aa2600f1741f30bf472f1ceb", + "namingSemanticSha256": "29f696e9b5751d026b033655d425be665350d30160e3cb958b0cf1c476280b61" + }, + "restoredEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 18, + "edges": 40, + "vertices": 24, + "volume": 1795.287611, + "area": 926.5663706, + "bounds": [ + -2e-7, + -1e-7, + -1e-7, + 18.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "af516227420b3c0413aaba9b51458df190806683c9cf8ae57c720f4707045537", + "namingEvidenceSha256": "2ca8ae8505e3391cd62a625f3904a76907eb17d202518a732de3cce7bd8681e4", + "namingSemanticSha256": "1cac4b35dcead587d3b105c66ab2ccae3462b5f0bb19986aaf1006b634827881" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->groove", + "phases": { + "initial": { + "namingEvidenceBytes": 4986, + "namingEvidenceSha256": "1200720cdfe02019685439666dc8d6781e61de6fd94495ae65201cf83b977462", + "pair": "linear-pattern->groove", + "shape": { + "area": 926.5663706, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 40, + "faces": 18, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 1795.287611 + } + }, + "reopened": { + "namingEvidenceBytes": 4986, + "namingEvidenceSha256": "1200720cdfe02019685439666dc8d6781e61de6fd94495ae65201cf83b977462", + "pair": "linear-pattern->groove", + "shape": { + "area": 926.5663706, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 40, + "faces": 18, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 1795.287611 + } + }, + "resaved": { + "namingEvidenceBytes": 4986, + "namingEvidenceSha256": "1200720cdfe02019685439666dc8d6781e61de6fd94495ae65201cf83b977462", + "pair": "linear-pattern->groove", + "shape": { + "area": 926.5663706, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 40, + "faces": 18, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 1795.287611 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-fillet", + "pair": "linear-pattern->fillet", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "923b0410a1f03a02f31b5b311f603bdecaf33cf826ea2cec7d6071aae0d8de0a", + "namingSemanticSha256": "51edc96832e77969a3c9410c1fc2077269e7c6d5c6d90183f74edbab74442b0e" + }, + "second": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 88, + "vertices": 40, + "volume": 1794.8665943, + "area": 893.7231781, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 270, + "selectedRecords": 14, + "ambiguousResults": 36, + "historySha256": "b01bf01c72f4e5fb61abca83dd35acef66430b428fdb5ef52ec13f0939f7a10c", + "namingEvidenceSha256": "b22c4cbd417e6c5c97910245211d0fe8d52ace493808ee42154463791b9bf98e", + "namingSemanticSha256": "92597ed2a4c10a03327caa3e576f316f38d439260c84731e2497fabd6ecd93b4" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "beforeValue": 0.4, + "editedValue": 0.6, + "restoredValue": 0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 88, + "vertices": 40, + "volume": 1788.5462621, + "area": 880.4488382, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 270, + "selectedRecords": 14, + "ambiguousResults": 36, + "historySha256": "b01bf01c72f4e5fb61abca83dd35acef66430b428fdb5ef52ec13f0939f7a10c", + "namingEvidenceSha256": "75f76048384ad6deb48444f82554a9be14a764c42831278389af75a9c6a39353", + "namingSemanticSha256": "92597ed2a4c10a03327caa3e576f316f38d439260c84731e2497fabd6ecd93b4" + }, + "restoredEvidence": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 88, + "vertices": 40, + "volume": 1794.8665943, + "area": 893.7231781, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 270, + "selectedRecords": 14, + "ambiguousResults": 36, + "historySha256": "b01bf01c72f4e5fb61abca83dd35acef66430b428fdb5ef52ec13f0939f7a10c", + "namingEvidenceSha256": "f066deb4530c4f20cae25c34bc9a453c28b9c0fa7c8e40ba3331a1ff365dabcc", + "namingSemanticSha256": "92597ed2a4c10a03327caa3e576f316f38d439260c84731e2497fabd6ecd93b4" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->fillet", + "phases": { + "initial": { + "namingEvidenceBytes": 20374, + "namingEvidenceSha256": "b22c4cbd417e6c5c97910245211d0fe8d52ace493808ee42154463791b9bf98e", + "pair": "linear-pattern->fillet", + "shape": { + "area": 893.7231781, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 88, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1794.8665943 + } + }, + "reopened": { + "namingEvidenceBytes": 20374, + "namingEvidenceSha256": "b22c4cbd417e6c5c97910245211d0fe8d52ace493808ee42154463791b9bf98e", + "pair": "linear-pattern->fillet", + "shape": { + "area": 893.7231781, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 88, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1794.8665943 + } + }, + "resaved": { + "namingEvidenceBytes": 20374, + "namingEvidenceSha256": "b22c4cbd417e6c5c97910245211d0fe8d52ace493808ee42154463791b9bf98e", + "pair": "linear-pattern->fillet", + "shape": { + "area": 893.7231781, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 88, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1794.8665943 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-chamfer", + "pair": "linear-pattern->chamfer", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "f559ee4332ed12eacc44c6086e062e2466b72c659ea013a747b52c1f75f8b89b", + "namingSemanticSha256": "8b8e9ba7ff3f9426725be4599eaf93999063f8db0eb94932c88be95ceda1a5f4" + }, + "second": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 80, + "vertices": 40, + "volume": 1788.1813333, + "area": 883.902117, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 270, + "selectedRecords": 14, + "ambiguousResults": 36, + "historySha256": "56d637add2e2b0d88027ae046c3b460293ca96044de7f325ed32f3ba17d1542c", + "namingEvidenceSha256": "a68b7d31f4481be79e25863794cd6c7a06bbb0cafa14429abc20858636649c90", + "namingSemanticSha256": "cd2f581407856ea4ef3f91763fe5283ddb0a51ca5f8379660f8643b7d47f60bf" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "distance", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "beforeValue": 0.4, + "editedValue": 0.6, + "restoredValue": 0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 80, + "vertices": 40, + "volume": 1773.792, + "area": 865.4916249, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 270, + "selectedRecords": 14, + "ambiguousResults": 36, + "historySha256": "56d637add2e2b0d88027ae046c3b460293ca96044de7f325ed32f3ba17d1542c", + "namingEvidenceSha256": "9658f80bc1642cc440d213bfc65eb972c3a88ba8908b35ed7e2c927175ffa21e", + "namingSemanticSha256": "cd2f581407856ea4ef3f91763fe5283ddb0a51ca5f8379660f8643b7d47f60bf" + }, + "restoredEvidence": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 42, + "edges": 80, + "vertices": 40, + "volume": 1788.1813333, + "area": 883.902117, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 270, + "selectedRecords": 14, + "ambiguousResults": 36, + "historySha256": "56d637add2e2b0d88027ae046c3b460293ca96044de7f325ed32f3ba17d1542c", + "namingEvidenceSha256": "9658f80bc1642cc440d213bfc65eb972c3a88ba8908b35ed7e2c927175ffa21e", + "namingSemanticSha256": "cd2f581407856ea4ef3f91763fe5283ddb0a51ca5f8379660f8643b7d47f60bf" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->chamfer", + "phases": { + "initial": { + "namingEvidenceBytes": 20521, + "namingEvidenceSha256": "a68b7d31f4481be79e25863794cd6c7a06bbb0cafa14429abc20858636649c90", + "pair": "linear-pattern->chamfer", + "shape": { + "area": 883.902117, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 80, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1788.1813333 + } + }, + "reopened": { + "namingEvidenceBytes": 20521, + "namingEvidenceSha256": "a68b7d31f4481be79e25863794cd6c7a06bbb0cafa14429abc20858636649c90", + "pair": "linear-pattern->chamfer", + "shape": { + "area": 883.902117, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 80, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1788.1813333 + } + }, + "resaved": { + "namingEvidenceBytes": 20521, + "namingEvidenceSha256": "a68b7d31f4481be79e25863794cd6c7a06bbb0cafa14429abc20858636649c90", + "pair": "linear-pattern->chamfer", + "shape": { + "area": 883.902117, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 80, + "faces": 42, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 1788.1813333 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-hole", + "pair": "linear-pattern->hole", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "d16c44ee49ef696c04ddff558ebbcbc2af92388cdb692ee9a9863ff2d43a4043", + "namingSemanticSha256": "c2ca58fbad53e8332114a23c13dab78afcd14ba572ef44e286f8d89d0aa13a91" + }, + "second": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 15, + "edges": 31, + "vertices": 18, + "volume": 1768.5840735, + "area": 976.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "24e93bc3ea53df5de2300a4276652200741acf31f98a5da56b25b093d7f824e8", + "namingEvidenceSha256": "c92719e07914d950624d52b3cba1450448f41be37fcb2da59c090c6d2703cc0a", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 1, + 1.5, + 1 + ], + "beforeValue": 1, + "editedValue": 1.5, + "restoredValue": 1, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 15, + "edges": 31, + "vertices": 18, + "volume": 1729.3141653, + "area": 1000.1106127, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "24e93bc3ea53df5de2300a4276652200741acf31f98a5da56b25b093d7f824e8", + "namingEvidenceSha256": "5021da212c5d3a3e9d40d86bbdb4c80d6db3aa0c87ac3ab5806679836e81710f", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "restoredEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 15, + "edges": 31, + "vertices": 18, + "volume": 1768.5840735, + "area": 976.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "24e93bc3ea53df5de2300a4276652200741acf31f98a5da56b25b093d7f824e8", + "namingEvidenceSha256": "bb2af71108adf1adf96d832f43cfd6c49b1b326a4333d6eca48293a06f5a4b9f", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->hole", + "phases": { + "initial": { + "namingEvidenceBytes": 1573, + "namingEvidenceSha256": "c92719e07914d950624d52b3cba1450448f41be37fcb2da59c090c6d2703cc0a", + "pair": "linear-pattern->hole", + "shape": { + "area": 976.5486678, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 31, + "faces": 15, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1768.5840735 + } + }, + "reopened": { + "namingEvidenceBytes": 1573, + "namingEvidenceSha256": "c92719e07914d950624d52b3cba1450448f41be37fcb2da59c090c6d2703cc0a", + "pair": "linear-pattern->hole", + "shape": { + "area": 976.5486678, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 31, + "faces": 15, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1768.5840735 + } + }, + "resaved": { + "namingEvidenceBytes": 1573, + "namingEvidenceSha256": "c92719e07914d950624d52b3cba1450448f41be37fcb2da59c090c6d2703cc0a", + "pair": "linear-pattern->hole", + "shape": { + "area": 976.5486678, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 31, + "faces": 15, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1768.5840735 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-draft", + "pair": "linear-pattern->draft", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "7bb63c62dfb51546b561f1ab6d567c6268ae70ef1e0d4e94d42a7b2fe631db50", + "namingSemanticSha256": "14e4e2ead18b6cd84e2372fd781dc43f9f898f8feda6f580246ce30aad497a0a" + }, + "second": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1756.2556682, + "area": 902.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "43f06ae08f633cd2418b3b8b03087a763bf9e421bb4172cf835193ec7d664778", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 5, + 8, + 5 + ], + "beforeValue": 5, + "editedValue": 8, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1729.7295826, + "area": 892.8745903, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "970df36b85e1f9b1e6b7d05020ce8dcb30863ebf3c3cf40971340a9eb017114b", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + }, + "restoredEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1756.2556682, + "area": 902.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "31abf99131adec5347f83e94328156901125d4fde52d8ba14bf872b45f7264e6", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->draft", + "phases": { + "initial": { + "namingEvidenceBytes": 2592, + "namingEvidenceSha256": "43f06ae08f633cd2418b3b8b03087a763bf9e421bb4172cf835193ec7d664778", + "pair": "linear-pattern->draft", + "shape": { + "area": 902.884251, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1756.2556682 + } + }, + "reopened": { + "namingEvidenceBytes": 2592, + "namingEvidenceSha256": "43f06ae08f633cd2418b3b8b03087a763bf9e421bb4172cf835193ec7d664778", + "pair": "linear-pattern->draft", + "shape": { + "area": 902.884251, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1756.2556682 + } + }, + "resaved": { + "namingEvidenceBytes": 2592, + "namingEvidenceSha256": "43f06ae08f633cd2418b3b8b03087a763bf9e421bb4172cf835193ec7d664778", + "pair": "linear-pattern->draft", + "shape": { + "area": 902.884251, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1756.2556682 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-thickness", + "pair": "linear-pattern->thickness", + "classification": "rejected", + "reasonCode": "native-and-freecad-profile-no-op-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "a16895713f6503bb8981f6c55949195ae71a89839dc5bfd1ce45347c478482f9", + "namingSemanticSha256": "728ee97b239566d9ea9c8aaf0722d6cf3aa97d5d4abdac4875852351b72ec587" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-no-op", + "parameter": "offset", + "trajectory": [ + -0.4, + -0.6, + -0.4 + ], + "kernelAttempts": [ + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.4, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "d688520dd3b7aa2560afc7f9649e40f136cc4f86869cbfd912e76c26756b71b6", + "authority": "kernel-no-op" + }, + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.6, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "d688520dd3b7aa2560afc7f9649e40f136cc4f86869cbfd912e76c26756b71b6", + "authority": "kernel-no-op" + }, + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.4, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "d688520dd3b7aa2560afc7f9649e40f136cc4f86869cbfd912e76c26756b71b6", + "authority": "kernel-no-op" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "freecadProfileNoOp": true, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": false, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": false, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [ + "Face2" + ], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "nativeTypeId": "Part::Thickness", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Thickness" + } + ], + "parameter": { + "name": "offset", + "value": -0.4 + }, + "recomputeResult": true, + "resultShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "shapeNull": false, + "shapeValid": true, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Thickness", + "operation": "thickness", + "pair": "linear-pattern->thickness", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "aa2fbaf66929da6ed6494cb8b93b02fc0aeb767be98f3e7944f0d71c51bc0a1b", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + } + }, + "sourceBrepReserialized": true, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 920, + "bounds": [ + 0, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3294bb877d10187d69c859cf2fcea1f4ef2bf0950bb1b3605161adf6208f9517", + "edges": 28, + "faces": 14, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1800 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-linear-pattern", + "pair": "linear-pattern->linear-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "5dd3630aba9f02648c55fe33659a3bbaa5e04aa5f47a0e3f12485e1566f624ae", + "namingSemanticSha256": "43885f7caaaa28c8fe9a4fb5a37baf0f2ad6243cb3f1c03362d76a133631c38c" + }, + "second": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 26.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 258, + "selectedRecords": 16, + "ambiguousResults": 36, + "historySha256": "dcdb169abb026ab593696756ffd00f068b090183b9a871bc8bf4834d0e2e8404", + "namingEvidenceSha256": "d86c008da71f25032bddb5a57665cfcd99f700274fefd39b3cd1f8f16ba0b748", + "namingSemanticSha256": "9c7fc16ff9301bfee1ae99039568174b8cdefce3c855d5919ff60955d8e4ea42" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "translationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 30, + "edges": 60, + "vertices": 32, + "volume": 2700, + "area": 1280, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 27.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 130, + "selectedRecords": 16, + "ambiguousResults": 24, + "historySha256": "f3d2f94747f9c61272368634f7b90988dd73939c9694dee22cdc5b30b42967a8", + "namingEvidenceSha256": "8a1dbe39e26d04c2df8bcd196baf2ff4bdb9345d022b5b7f617530e1de3ccecb", + "namingSemanticSha256": "04cc8c55f026246b115c26664853e600e93c4de4e1b2a3553180b5f54a8b0e00" + }, + "restoredEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 26.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 258, + "selectedRecords": 16, + "ambiguousResults": 36, + "historySha256": "dcdb169abb026ab593696756ffd00f068b090183b9a871bc8bf4834d0e2e8404", + "namingEvidenceSha256": "7df926ef5dea9f0d674c0e9c382e866d6a9161f5d29af84f11b592f2144265e7", + "namingSemanticSha256": "9c7fc16ff9301bfee1ae99039568174b8cdefce3c855d5919ff60955d8e4ea42" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->linear-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 22143, + "namingEvidenceSha256": "d86c008da71f25032bddb5a57665cfcd99f700274fefd39b3cd1f8f16ba0b748", + "pair": "linear-pattern->linear-pattern", + "shape": { + "area": 1240, + "bounds": [ + 0, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "reopened": { + "namingEvidenceBytes": 22143, + "namingEvidenceSha256": "d86c008da71f25032bddb5a57665cfcd99f700274fefd39b3cd1f8f16ba0b748", + "pair": "linear-pattern->linear-pattern", + "shape": { + "area": 1240, + "bounds": [ + 0, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "resaved": { + "namingEvidenceBytes": 22143, + "namingEvidenceSha256": "d86c008da71f25032bddb5a57665cfcd99f700274fefd39b3cd1f8f16ba0b748", + "pair": "linear-pattern->linear-pattern", + "shape": { + "area": 1240, + "bounds": [ + 0, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-polar-pattern", + "pair": "linear-pattern->polar-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "7aa1447e37a2e4e2929f3b9cb7e5e71167d3ffcb6b9421221f74126d3503a90f", + "namingSemanticSha256": "5bf1f13a8140a6351feb5327526de3f831d5fb3ab0fbdd981e68651d13b30f8c" + }, + "second": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 34, + "edges": 74, + "vertices": 42, + "volume": 2745.5216016, + "area": 1227.4462449, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 18.0000002, + 17.6602542, + 10.0000001 + ] + }, + "historyRecords": 190, + "selectedRecords": 20, + "ambiguousResults": 29, + "historySha256": "020546d3a329e3ce5d510244667d62f9ba83a57649e853be49413837ef23ba08", + "namingEvidenceSha256": "786f8db04d92dad1fd7b04875b1c2cba9fabbe3b6e44e14ddec232bf8523e672", + "namingSemanticSha256": "cdf92dc08f0bc55e1fd67d8136aa55e99fc692bdb8fc10547c464daf5e7cbc5c" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 30, + 45, + 30 + ], + "beforeValue": 30, + "editedValue": 45, + "restoredValue": 30, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 31, + "edges": 65, + "vertices": 36, + "volume": 3100, + "area": 1398.5786438, + "bounds": [ + -7.0710679, + -1e-7, + -1e-7, + 18.0000001, + 19.79899, + 10.0000001 + ] + }, + "historyRecords": 144, + "selectedRecords": 13, + "ambiguousResults": 20, + "historySha256": "4c94015c5b48baf7a7318d792ff32d64828114cad5aa424fde54a56c460a6535", + "namingEvidenceSha256": "d8f89fd2563d8201806f892c3a9b49bb5b035e046bbc5859bcc3386094ad5c9c", + "namingSemanticSha256": "ea681dec3d522247a70e09f0b92a46d4181d147b0c7cb583b89932add61a2dcd" + }, + "restoredEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 34, + "edges": 74, + "vertices": 42, + "volume": 2745.5216016, + "area": 1227.4462449, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 18.0000002, + 17.6602542, + 10.0000001 + ] + }, + "historyRecords": 190, + "selectedRecords": 20, + "ambiguousResults": 29, + "historySha256": "020546d3a329e3ce5d510244667d62f9ba83a57649e853be49413837ef23ba08", + "namingEvidenceSha256": "b9eb482a99b867461338bc3974eb4736de84bc74e45a863095f490cb4eb67799", + "namingSemanticSha256": "cdf92dc08f0bc55e1fd67d8136aa55e99fc692bdb8fc10547c464daf5e7cbc5c" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->polar-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 19355, + "namingEvidenceSha256": "786f8db04d92dad1fd7b04875b1c2cba9fabbe3b6e44e14ddec232bf8523e672", + "pair": "linear-pattern->polar-pattern", + "shape": { + "area": 1227.4462449, + "bounds": [ + -5, + 0, + 0, + 18, + 17.660254, + 10 + ], + "edges": 74, + "faces": 34, + "solids": 1, + "valid": true, + "vertices": 42, + "volume": 2745.5216016 + } + }, + "reopened": { + "namingEvidenceBytes": 19355, + "namingEvidenceSha256": "786f8db04d92dad1fd7b04875b1c2cba9fabbe3b6e44e14ddec232bf8523e672", + "pair": "linear-pattern->polar-pattern", + "shape": { + "area": 1227.4462449, + "bounds": [ + -5, + 0, + 0, + 18, + 17.660254, + 10 + ], + "edges": 74, + "faces": 34, + "solids": 1, + "valid": true, + "vertices": 42, + "volume": 2745.5216016 + } + }, + "resaved": { + "namingEvidenceBytes": 19355, + "namingEvidenceSha256": "786f8db04d92dad1fd7b04875b1c2cba9fabbe3b6e44e14ddec232bf8523e672", + "pair": "linear-pattern->polar-pattern", + "shape": { + "area": 1227.4462449, + "bounds": [ + -5, + 0, + 0, + 18, + 17.660254, + 10 + ], + "edges": 74, + "faces": 34, + "solids": 1, + "valid": true, + "vertices": 42, + "volume": 2745.5216016 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-mirrored", + "pair": "linear-pattern->mirrored", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "c12d2dc8be760b87fe6598af5879c2d9f001f7b0ee7160bd5c4c8fc956e85946", + "namingSemanticSha256": "e13c71a0458515ddae8b5de4937ac19b5ac71890244e2d0b9bf31b133abf20e4" + }, + "second": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 258, + "selectedRecords": 16, + "ambiguousResults": 36, + "historySha256": "84f9cb5ab9b5ed822e3511aec44c6e075fcd01fc1edc81b95d753b1a88770da2", + "namingEvidenceSha256": "027719405b2d043382f5ee5f47d0992912bc24bfdc032d40fa1d3c159be61576", + "namingSemanticSha256": "e329a665ae6aba5dc85b901e99ed88136db9d74a50bb0147bec0067416abc0b5" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "planeOriginX", + "trajectory": [ + 5, + 6, + 5 + ], + "beforeValue": 5, + "editedValue": 6, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 30, + "edges": 60, + "vertices": 32, + "volume": 2400, + "area": 1160, + "bounds": [ + -6.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 194, + "selectedRecords": 24, + "ambiguousResults": 36, + "historySha256": "2baeff3bd6f9e7eecfd8eeaf503a27d71a6a3357be72493d358b199e0cb9c210", + "namingEvidenceSha256": "e86d4cd59879bdebd3b45c3fd139eba90f2f050a47771f8e928b713a91faee07", + "namingSemanticSha256": "96b8bc3576291d66acb61b4636b1ff0feeea8a7994561009e214144ed6097918" + }, + "restoredEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 258, + "selectedRecords": 16, + "ambiguousResults": 36, + "historySha256": "84f9cb5ab9b5ed822e3511aec44c6e075fcd01fc1edc81b95d753b1a88770da2", + "namingEvidenceSha256": "86426840fa2f7fedecc50d3b5fee6f27b7939e42f890d09127bf49734c3428f9", + "namingSemanticSha256": "e329a665ae6aba5dc85b901e99ed88136db9d74a50bb0147bec0067416abc0b5" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->mirrored", + "phases": { + "initial": { + "namingEvidenceBytes": 21593, + "namingEvidenceSha256": "027719405b2d043382f5ee5f47d0992912bc24bfdc032d40fa1d3c159be61576", + "pair": "linear-pattern->mirrored", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "reopened": { + "namingEvidenceBytes": 21593, + "namingEvidenceSha256": "027719405b2d043382f5ee5f47d0992912bc24bfdc032d40fa1d3c159be61576", + "pair": "linear-pattern->mirrored", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "resaved": { + "namingEvidenceBytes": 21593, + "namingEvidenceSha256": "027719405b2d043382f5ee5f47d0992912bc24bfdc032d40fa1d3c159be61576", + "pair": "linear-pattern->mirrored", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-linear-pattern-multi-transform", + "pair": "linear-pattern->multi-transform", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1800, + "area": 920, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "777335aae7dc5c90e6c4b998820327f02354e64ae4d2647f026d99a2a24ba6b7", + "namingEvidenceSha256": "a9707e550b06a8d15ff021d56f52b65539d8fde29aa1eac0aac27724380366b0", + "namingSemanticSha256": "771708d6d5d93d957d9735b206e1dc3965e9f725e2ee3af4e4e200dd98236f35" + }, + "second": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 38, + "edges": 76, + "vertices": 40, + "volume": 4200, + "area": 1880, + "bounds": [ + -16.0000001, + -1e-7, + -1e-7, + 26.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 783, + "selectedRecords": 14, + "ambiguousResults": 140, + "historySha256": "2752d6535a0ed10840949da8f195b16beafe41b54d457156524c14ff543003b5", + "namingEvidenceSha256": "7770e81b7b87de2f189fad40d041deb54b05304781045c92ced0cfddd9617881", + "namingSemanticSha256": "09d187e30dbf42b78569a74ae8d4501da5811a424dc85479b6ffac6ee2140fdf" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "multiTranslationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 54, + "edges": 108, + "vertices": 56, + "volume": 4400, + "area": 1960, + "bounds": [ + -17.0000001, + -1e-7, + -1e-7, + 27.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 855, + "selectedRecords": 22, + "ambiguousResults": 196, + "historySha256": "1d9830110de8282488ad4cde80f2e6cc93a06eac925b1de7bdb18a6df26377a7", + "namingEvidenceSha256": "d4d603ab813f3644d9ae3442e5c2c51a8ebfb30334e5d8ab376a9aa18428029d", + "namingSemanticSha256": "70ae7c1b80fc8005589b70afe5dae5426c6e9a05d3d8c6ded89724c4b91ee69e" + }, + "restoredEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 38, + "edges": 76, + "vertices": 40, + "volume": 4200, + "area": 1880, + "bounds": [ + -16.0000001, + -1e-7, + -1e-7, + 26.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 783, + "selectedRecords": 14, + "ambiguousResults": 140, + "historySha256": "2752d6535a0ed10840949da8f195b16beafe41b54d457156524c14ff543003b5", + "namingEvidenceSha256": "40001842876c59587870901d49eaf0552bb6cceab467c99e520f27fe9b33cbaa", + "namingSemanticSha256": "09d187e30dbf42b78569a74ae8d4501da5811a424dc85479b6ffac6ee2140fdf" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "linear-pattern->multi-transform", + "phases": { + "initial": { + "namingEvidenceBytes": 92836, + "namingEvidenceSha256": "7770e81b7b87de2f189fad40d041deb54b05304781045c92ced0cfddd9617881", + "pair": "linear-pattern->multi-transform", + "shape": { + "area": 1880, + "bounds": [ + -16, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 76, + "faces": 38, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 4200 + } + }, + "reopened": { + "namingEvidenceBytes": 92836, + "namingEvidenceSha256": "7770e81b7b87de2f189fad40d041deb54b05304781045c92ced0cfddd9617881", + "pair": "linear-pattern->multi-transform", + "shape": { + "area": 1880, + "bounds": [ + -16, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 76, + "faces": 38, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 4200 + } + }, + "resaved": { + "namingEvidenceBytes": 92836, + "namingEvidenceSha256": "7770e81b7b87de2f189fad40d041deb54b05304781045c92ced0cfddd9617881", + "pair": "linear-pattern->multi-transform", + "shape": { + "area": 1880, + "bounds": [ + -16, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 76, + "faces": 38, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 4200 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-fuse", + "pair": "polar-pattern->fuse", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "c7384b3a38b6a75c8ff8a2285d37b2d8e223b41d5437c0858bf539f424fc7efb", + "namingSemanticSha256": "eae160b105b0d463ad7afdd805a6e02ecdc1a7e6ebb13ef2802b5251f766822b" + }, + "second": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 21, + "edges": 46, + "vertices": 27, + "volume": 1497.6497308, + "area": 829.0598923, + "bounds": [ + -5.0000002, + -1e-7, + -1e-7, + 13.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 64, + "selectedRecords": 9, + "ambiguousResults": 21, + "historySha256": "98521a08bb436df67d0db0199a4563f7c767f512795818d4995e01d9037df540", + "namingEvidenceSha256": "7edcf0776ed0aca7c69d3168f8bc3bacaa204ee2fb17d10bf88f3243f0c9f5fd", + "namingSemanticSha256": "ad891d82864fdcae85387f704a2b202b535fbd6fa01ce3e50e0bf68a7119caa7" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 8, + 7, + 8 + ], + "beforeValue": 8, + "editedValue": 7, + "restoredValue": 8, + "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": 46, + "vertices": 27, + "volume": 1472.6497308, + "area": 809.0598923, + "bounds": [ + -5.0000002, + -1e-7, + -1e-7, + 12.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 64, + "selectedRecords": 9, + "ambiguousResults": 21, + "historySha256": "98521a08bb436df67d0db0199a4563f7c767f512795818d4995e01d9037df540", + "namingEvidenceSha256": "d3316d29fdb23f9f2e775a03d4213e9d9afd2a54ffeadd9ebc10a6eb65974a0f", + "namingSemanticSha256": "ad891d82864fdcae85387f704a2b202b535fbd6fa01ce3e50e0bf68a7119caa7" + }, + "restoredEvidence": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 21, + "edges": 46, + "vertices": 27, + "volume": 1497.6497308, + "area": 829.0598923, + "bounds": [ + -5.0000002, + -1e-7, + -1e-7, + 13.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 64, + "selectedRecords": 9, + "ambiguousResults": 21, + "historySha256": "98521a08bb436df67d0db0199a4563f7c767f512795818d4995e01d9037df540", + "namingEvidenceSha256": "f1ca8fc64bdcae448c33322cecc18bf5b9e9daa2e373692792947587e194e25c", + "namingSemanticSha256": "ad891d82864fdcae85387f704a2b202b535fbd6fa01ce3e50e0bf68a7119caa7" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "polar-pattern->fuse", + "phases": { + "initial": { + "namingEvidenceBytes": 11030, + "namingEvidenceSha256": "7edcf0776ed0aca7c69d3168f8bc3bacaa204ee2fb17d10bf88f3243f0c9f5fd", + "pair": "polar-pattern->fuse", + "shape": { + "area": 829.0598923, + "bounds": [ + -5, + 0, + 0, + 13, + 13.660254, + 10 + ], + "edges": 46, + "faces": 21, + "solids": 1, + "valid": true, + "vertices": 27, + "volume": 1497.6497308 + } + }, + "reopened": { + "namingEvidenceBytes": 11030, + "namingEvidenceSha256": "7edcf0776ed0aca7c69d3168f8bc3bacaa204ee2fb17d10bf88f3243f0c9f5fd", + "pair": "polar-pattern->fuse", + "shape": { + "area": 829.0598923, + "bounds": [ + -5, + 0, + 0, + 13, + 13.660254, + 10 + ], + "edges": 46, + "faces": 21, + "solids": 1, + "valid": true, + "vertices": 27, + "volume": 1497.6497308 + } + }, + "resaved": { + "namingEvidenceBytes": 11030, + "namingEvidenceSha256": "7edcf0776ed0aca7c69d3168f8bc3bacaa204ee2fb17d10bf88f3243f0c9f5fd", + "pair": "polar-pattern->fuse", + "shape": { + "area": 829.0598923, + "bounds": [ + -5, + 0, + 0, + 13, + 13.660254, + 10 + ], + "edges": 46, + "faces": 21, + "solids": 1, + "valid": true, + "vertices": 27, + "volume": 1497.6497308 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-cut", + "pair": "polar-pattern->cut", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "69b507063f4ea71117862e2e7fcc80b199c253e38ebc38fe43253fc564f05cda", + "namingSemanticSha256": "bbd5660cf1f1f35446dd14543920a6d44346f5942643ada1b12d2eaa76eb812a" + }, + "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": 1358.6497308, + "area": 801.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 34, + "selectedRecords": 6, + "ambiguousResults": 12, + "historySha256": "758f2b71ca3dbfcec8074831ad884c1ec9b1fd46b57239517247356561801f2d", + "namingEvidenceSha256": "567c4970bb664c236a41c514425b6dd8033aa51341106f28c579dbde437b01e8", + "namingSemanticSha256": "cfb1b60b90831e3f3cb616529049c356c587a2b842566f80d7d0218fdffc02fd" + }, + "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": 1395.6497308, + "area": 787.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 34, + "selectedRecords": 6, + "ambiguousResults": 12, + "historySha256": "758f2b71ca3dbfcec8074831ad884c1ec9b1fd46b57239517247356561801f2d", + "namingEvidenceSha256": "3a85c78dd1adaf4f2faa72b2ef9935f9471a104f17b6f74a68d84c73444d1128", + "namingSemanticSha256": "cfb1b60b90831e3f3cb616529049c356c587a2b842566f80d7d0218fdffc02fd" + }, + "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": 1358.6497308, + "area": 801.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 34, + "selectedRecords": 6, + "ambiguousResults": 12, + "historySha256": "758f2b71ca3dbfcec8074831ad884c1ec9b1fd46b57239517247356561801f2d", + "namingEvidenceSha256": "1cf353d2ca0e8094e4a08a07d1ba080b2ea02d44624e1dd39d5e258a33061d10", + "namingSemanticSha256": "cfb1b60b90831e3f3cb616529049c356c587a2b842566f80d7d0218fdffc02fd" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "polar-pattern->cut", + "phases": { + "initial": { + "namingEvidenceBytes": 6931, + "namingEvidenceSha256": "567c4970bb664c236a41c514425b6dd8033aa51341106f28c579dbde437b01e8", + "pair": "polar-pattern->cut", + "shape": { + "area": 801.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 41, + "faces": 17, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1358.6497308 + } + }, + "reopened": { + "namingEvidenceBytes": 6931, + "namingEvidenceSha256": "567c4970bb664c236a41c514425b6dd8033aa51341106f28c579dbde437b01e8", + "pair": "polar-pattern->cut", + "shape": { + "area": 801.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 41, + "faces": 17, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1358.6497308 + } + }, + "resaved": { + "namingEvidenceBytes": 6931, + "namingEvidenceSha256": "567c4970bb664c236a41c514425b6dd8033aa51341106f28c579dbde437b01e8", + "pair": "polar-pattern->cut", + "shape": { + "area": 801.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 41, + "faces": 17, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1358.6497308 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-common", + "pair": "polar-pattern->common", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "3243151880a1de281ea8140ac5f5c8c51a70bc3bab7120a6b44f9d0025fb78a1", + "namingSemanticSha256": "4d8ce120ec0e16a9d1d594579875bc185cd27f1b1b916840c7f0788d4bd8e2f4" + }, + "second": { + "operation": "common", + "builder": "BRepAlgoAPI_Common", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 75, + "area": 110, + "bounds": [ + 6.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000002, + 5.0000001 + ] + }, + "historyRecords": 213, + "selectedRecords": 4, + "ambiguousResults": 14, + "historySha256": "060789a897d41d361d10617974cf82a867e4589bfbbd0b704e85bdb6fa3aa5dd", + "namingEvidenceSha256": "726029e76f1cc57e37a8997c0427322eed2415e12a7fcafbd70d8f80867a2dd3", + "namingSemanticSha256": "c5a2e119410853257019122dc21c209554e834e9587597de74adcf9741fcb75d" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 7, + 6, + 7 + ], + "beforeValue": 7, + "editedValue": 6, + "restoredValue": 7, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "common", + "builder": "BRepAlgoAPI_Common", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 100, + "area": 130, + "bounds": [ + 5.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000002, + 5.0000001 + ] + }, + "historyRecords": 213, + "selectedRecords": 4, + "ambiguousResults": 14, + "historySha256": "060789a897d41d361d10617974cf82a867e4589bfbbd0b704e85bdb6fa3aa5dd", + "namingEvidenceSha256": "944bd43009e94e91ca8d5c6894e6167c53818a40993ceb7506ed1874e4387c0c", + "namingSemanticSha256": "c5a2e119410853257019122dc21c209554e834e9587597de74adcf9741fcb75d" + }, + "restoredEvidence": { + "operation": "common", + "builder": "BRepAlgoAPI_Common", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 75, + "area": 110, + "bounds": [ + 6.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000002, + 5.0000001 + ] + }, + "historyRecords": 213, + "selectedRecords": 4, + "ambiguousResults": 14, + "historySha256": "060789a897d41d361d10617974cf82a867e4589bfbbd0b704e85bdb6fa3aa5dd", + "namingEvidenceSha256": "915574804bd5881c12207f4ccf3d63c963472b5ecc2948360c5684e37c413018", + "namingSemanticSha256": "c5a2e119410853257019122dc21c209554e834e9587597de74adcf9741fcb75d" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "polar-pattern->common", + "phases": { + "initial": { + "namingEvidenceBytes": 6410, + "namingEvidenceSha256": "726029e76f1cc57e37a8997c0427322eed2415e12a7fcafbd70d8f80867a2dd3", + "pair": "polar-pattern->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 75 + } + }, + "reopened": { + "namingEvidenceBytes": 6410, + "namingEvidenceSha256": "726029e76f1cc57e37a8997c0427322eed2415e12a7fcafbd70d8f80867a2dd3", + "pair": "polar-pattern->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 75 + } + }, + "resaved": { + "namingEvidenceBytes": 6410, + "namingEvidenceSha256": "726029e76f1cc57e37a8997c0427322eed2415e12a7fcafbd70d8f80867a2dd3", + "pair": "polar-pattern->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 75 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-rotate", + "pair": "polar-pattern->rotate", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "2a34ef6d7da36c36471370ad19961d448b46a25c5b4c2a9874849b4c22147974", + "namingSemanticSha256": "0d0cd6cc6f405528ed7a995e2531269622e7f55a360bce42f6c67a67308eab6b" + }, + "second": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -7.0710679, + -1e-7, + -1e-7, + 9.6592584, + 14.1421357, + 10.0000001 + ] + }, + "historyRecords": 168, + "selectedRecords": 12, + "ambiguousResults": 42, + "historySha256": "0275f99a29bee0041b5f30682c4472848a745987bbba0e7f586536498af91ed2", + "namingEvidenceSha256": "0f073ae2b76eac1f11cb7fb6881a3d8d165ac4e2900fd78f78d7be561b70b5de", + "namingSemanticSha256": "fe23b437305b2eddc37e3c0a3b813564980bb8b18d1a99355774584bba9cf534" + }, + "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": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -7.9335335, + -1e-7, + -1e-7, + 9.2387954, + 14.0211478, + 10.0000001 + ] + }, + "historyRecords": 168, + "selectedRecords": 12, + "ambiguousResults": 42, + "historySha256": "0275f99a29bee0041b5f30682c4472848a745987bbba0e7f586536498af91ed2", + "namingEvidenceSha256": "83592d085e04d9a4a450ccea1824e99be845b6ed053629bc68d091b9c29d7293", + "namingSemanticSha256": "fe23b437305b2eddc37e3c0a3b813564980bb8b18d1a99355774584bba9cf534" + }, + "restoredEvidence": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -7.0710679, + -1e-7, + -1e-7, + 9.6592584, + 14.1421357, + 10.0000001 + ] + }, + "historyRecords": 168, + "selectedRecords": 12, + "ambiguousResults": 42, + "historySha256": "0275f99a29bee0041b5f30682c4472848a745987bbba0e7f586536498af91ed2", + "namingEvidenceSha256": "4706685e1403ec5a69a21b852f24159aec26e79340764882ed46224a20b0eecf", + "namingSemanticSha256": "fe23b437305b2eddc37e3c0a3b813564980bb8b18d1a99355774584bba9cf534" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "polar-pattern->rotate", + "phases": { + "initial": { + "namingEvidenceBytes": 23631, + "namingEvidenceSha256": "0f073ae2b76eac1f11cb7fb6881a3d8d165ac4e2900fd78f78d7be561b70b5de", + "pair": "polar-pattern->rotate", + "shape": { + "area": 769.0598923, + "bounds": [ + -7.0710678, + 0, + 0, + 9.6592583, + 14.1421356, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "reopened": { + "namingEvidenceBytes": 23631, + "namingEvidenceSha256": "0f073ae2b76eac1f11cb7fb6881a3d8d165ac4e2900fd78f78d7be561b70b5de", + "pair": "polar-pattern->rotate", + "shape": { + "area": 769.0598923, + "bounds": [ + -7.0710678, + 0, + 0, + 9.6592583, + 14.1421356, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "resaved": { + "namingEvidenceBytes": 23631, + "namingEvidenceSha256": "0f073ae2b76eac1f11cb7fb6881a3d8d165ac4e2900fd78f78d7be561b70b5de", + "pair": "polar-pattern->rotate", + "shape": { + "area": 769.0598923, + "bounds": [ + -7.0710678, + 0, + 0, + 9.6592583, + 14.1421356, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-pad", + "pair": "polar-pattern->pad", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "148e0427e55ea9f66de0fcf69a4ede361e93dad7a47e7f1d8411a94def783fec", + "namingSemanticSha256": "c987465af98d414cf176eff655fd70f7d3b018e901c3bdc816f445487774b010" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "length", + "trajectory": [ + 5, + 7.5, + 5 + ], + "stable": true, + "attempts": [ + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 7.5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "nativeTypeId": "PartDesign::Pad", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Body", + "typeId": "PartDesign::Body" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + }, + { + "name": "PairResult", + "typeId": "PartDesign::Pad" + } + ], + "parameter": { + "name": "length", + "value": 5 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "FeatureExtrusion: Length: Could not extrude the sketch!" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "PartDesign::Pad", + "operation": "pad", + "pair": "polar-pattern->pad", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-pocket", + "pair": "polar-pattern->pocket", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "f20dd337ab39e85d8d6da63f29d6c626314957610ff1590996929b04d7888bcf", + "namingSemanticSha256": "7b1542f0055374b3661777c16d63c0cda30c380d918b26cdd00ea382003a4f3e" + }, + "second": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 38, + "vertices": 24, + "volume": 1392.6497308, + "area": 799.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 55, + "selectedRecords": 7, + "ambiguousResults": 13, + "historySha256": "55051e95232e9fe4ad1f578c3fd9d6930e69f66c4cf7293ab4ce1b6208591862", + "namingEvidenceSha256": "c0fb0f578a888915f1605c8f9b746d10139a5c525aa6da43c930d98561275746", + "namingSemanticSha256": "bf8635ac2e0690b9698b487b21900db37d151adf045d147e3d01686221e49483" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "length", + "trajectory": [ + 5, + 4, + 5 + ], + "beforeValue": 5, + "editedValue": 4, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 38, + "vertices": 24, + "volume": 1398.6497308, + "area": 793.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 55, + "selectedRecords": 7, + "ambiguousResults": 13, + "historySha256": "55051e95232e9fe4ad1f578c3fd9d6930e69f66c4cf7293ab4ce1b6208591862", + "namingEvidenceSha256": "bacd7649f36b00b1c8a1e0834b7f156d18437888033b7935c0471c840de6ad5e", + "namingSemanticSha256": "bf8635ac2e0690b9698b487b21900db37d151adf045d147e3d01686221e49483" + }, + "restoredEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 38, + "vertices": 24, + "volume": 1392.6497308, + "area": 799.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 55, + "selectedRecords": 7, + "ambiguousResults": 13, + "historySha256": "55051e95232e9fe4ad1f578c3fd9d6930e69f66c4cf7293ab4ce1b6208591862", + "namingEvidenceSha256": "31881bcf7a13331d505f2f191ff8addd5c3a4282714afebdf2f75327604cd141", + "namingSemanticSha256": "bf8635ac2e0690b9698b487b21900db37d151adf045d147e3d01686221e49483" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "polar-pattern->pocket", + "phases": { + "initial": { + "namingEvidenceBytes": 9556, + "namingEvidenceSha256": "c0fb0f578a888915f1605c8f9b746d10139a5c525aa6da43c930d98561275746", + "pair": "polar-pattern->pocket", + "shape": { + "area": 799.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 38, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 1392.6497308 + } + }, + "reopened": { + "namingEvidenceBytes": 9556, + "namingEvidenceSha256": "c0fb0f578a888915f1605c8f9b746d10139a5c525aa6da43c930d98561275746", + "pair": "polar-pattern->pocket", + "shape": { + "area": 799.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 38, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 1392.6497308 + } + }, + "resaved": { + "namingEvidenceBytes": 9556, + "namingEvidenceSha256": "c0fb0f578a888915f1605c8f9b746d10139a5c525aa6da43c930d98561275746", + "pair": "polar-pattern->pocket", + "shape": { + "area": 799.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 38, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 1392.6497308 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-loft", + "pair": "polar-pattern->loft", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "dc4adcbf4a0198e18093df4d6ab91ed6ceb0721c3af7e47e6f541b6819feab84", + "namingSemanticSha256": "eaa676dac05e810d7db7648a39a3c2c1ee1fa124592c50a3f97d2e74a943a123" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "ruled", + "trajectory": [ + false, + true, + false + ], + "kernelAttempts": [ + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": -250, + "area": 556.1837862, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": true, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": -250, + "area": 556.1837862, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": -250, + "area": 556.1837862, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + } + ] + }, + "inputShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "nativeTypeId": "Part::Loft", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Loft" + } + ], + "parameter": { + "name": "ruled", + "value": false + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Profile shape is not a single vertex, edge, wire nor face." + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Loft", + "operation": "loft", + "pair": "polar-pattern->loft", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-pipe", + "pair": "polar-pattern->pipe", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "cd4dee4afe40e83a382efd1cd618f2129184123e7870bf65bcb9d69935370f6d", + "namingSemanticSha256": "917a990420b02c97eb11b6fcc15d2dfce53e70319b23c04e17d8d4ff316c4544" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "spineLength", + "trajectory": [ + 15, + 12, + 15 + ], + "kernelAttempts": [ + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + 9.9999999, + -1e-7, + -15.0000001, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "ad682ce8340b8e2d1d1322e16d97c5e10739ec1f7ab48e99071f78123ea1242c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 12, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 440, + "bounds": [ + 9.9999999, + -1e-7, + -12.0000001, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "ad682ce8340b8e2d1d1322e16d97c5e10739ec1f7ab48e99071f78123ea1242c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + 9.9999999, + -1e-7, + -15.0000001, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "ad682ce8340b8e2d1d1322e16d97c5e10739ec1f7ab48e99071f78123ea1242c", + "authority": "kernel-invalid-result" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "spine": { + "name": "Spine", + "subelements": [], + "typeId": "Part::Feature" + } + }, + "inputShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "nativeTypeId": "Part::Sweep", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Spine", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Sweep" + } + ], + "parameter": { + "name": "spineLength", + "value": 15 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "A fatal error occurred when making the sweep" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Sweep", + "operation": "pipe", + "pair": "polar-pattern->pipe", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-revolution", + "pair": "polar-pattern->revolution", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "87473f91c220df4a40e22cb9b23369259beb0ab17058af45aaba2e2b644174f7", + "namingSemanticSha256": "edb6a2e8514c8f223e0c67d4c7499ffa64dbe412ccc65ec47a7c56a0deafa1ad" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "angle", + "trajectory": [ + 360, + 270, + 360 + ], + "stable": true, + "attempts": [ + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 270, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "nativeTypeId": "Part::Revolution", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Revolution" + } + ], + "parameter": { + "name": "angle", + "value": 360 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "BRep_API: command not done" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Revolution", + "operation": "revolution", + "pair": "polar-pattern->revolution", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-groove", + "pair": "polar-pattern->groove", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "309b56be60bcc9c07ce5e597dbd2117ee5d61f44d353b4261ad89333fd644734", + "namingSemanticSha256": "31a4e98451da3a8b6d059581d29dc9330e7d26b6377563bec55e24a7fd20b34d" + }, + "second": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 41, + "vertices": 26, + "volume": 1413.279598, + "area": 787.2071345, + "bounds": [ + -5.0000002, + -1e-7, + -2e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 7, + "ambiguousResults": 8, + "historySha256": "311126d2983ae5876e481c80e4ebf1897cf850e01e5801a139b932d775dfa087", + "namingEvidenceSha256": "bbb3977c389a1d03e56586dfe260bab5f26f1f557383d096f719b9b158f574ca", + "namingSemanticSha256": "56b8428bf6d1755b9f1c42841590c796f617b037cbf3fb60900ab620f4732e62" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 360, + 180, + 360 + ], + "beforeValue": 360, + "editedValue": 180, + "restoredValue": 360, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 36, + "vertices": 25, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 47, + "selectedRecords": 3, + "ambiguousResults": 13, + "historySha256": "ede8abac8dccdb33146996330d1c357c04c1e52ff0c20910c42700bf85dfd89f", + "namingEvidenceSha256": "ba28a6ce2cb21b4945a720c4ad8f76b33fdd915818f568bc5e24ae76dcdf41b1", + "namingSemanticSha256": "ce6d4afa3a9826c17c1829dce8fee61729e6e1839fb30f4618d64bb949e9eb5a" + }, + "restoredEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 16, + "edges": 41, + "vertices": 26, + "volume": 1413.279598, + "area": 787.2071345, + "bounds": [ + -5.0000002, + -1e-7, + -2e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 7, + "ambiguousResults": 8, + "historySha256": "311126d2983ae5876e481c80e4ebf1897cf850e01e5801a139b932d775dfa087", + "namingEvidenceSha256": "05eb65615bd1b03e259ea1098ba66c3c5076681e12c159d516a7b9ad580b8b93", + "namingSemanticSha256": "56b8428bf6d1755b9f1c42841590c796f617b037cbf3fb60900ab620f4732e62" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "polar-pattern->groove", + "phases": { + "initial": { + "namingEvidenceBytes": 5792, + "namingEvidenceSha256": "bbb3977c389a1d03e56586dfe260bab5f26f1f557383d096f719b9b158f574ca", + "pair": "polar-pattern->groove", + "shape": { + "area": 787.2071345, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 41, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1413.279598 + } + }, + "reopened": { + "namingEvidenceBytes": 5792, + "namingEvidenceSha256": "bbb3977c389a1d03e56586dfe260bab5f26f1f557383d096f719b9b158f574ca", + "pair": "polar-pattern->groove", + "shape": { + "area": 787.2071345, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 41, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1413.279598 + } + }, + "resaved": { + "namingEvidenceBytes": 5792, + "namingEvidenceSha256": "bbb3977c389a1d03e56586dfe260bab5f26f1f557383d096f719b9b158f574ca", + "pair": "polar-pattern->groove", + "shape": { + "area": 787.2071345, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 41, + "faces": 16, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1413.279598 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-fillet", + "pair": "polar-pattern->fillet", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "040328940ba46d4a548602878328dd87b57bd333952d4df2e414f9d297693cea", + "namingSemanticSha256": "c2bf6069d8378e7b5433bf6a7d2314ec75e9272795d45e3f1183fa7b888b3820" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "radius", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "stable": true, + "attempts": [ + { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "parameter": "radius", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "null function or function signature mismatch" + }, + { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "parameter": "radius", + "parameterValue": 0.6, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "null function or function signature mismatch" + }, + { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "parameter": "radius", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-wasm-abort", + "thrownType": "RuntimeError", + "crashSignature": "null function or function signature mismatch" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "selectedEdges": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "nativeTypeId": "Part::Fillet", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Fillet" + } + ], + "parameter": { + "name": "radius", + "value": 0.4 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "BRep_API: command not done" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Fillet", + "operation": "fillet", + "pair": "polar-pattern->fillet", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-chamfer", + "pair": "polar-pattern->chamfer", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "8d14c55526d24e8bf7cee745369fbab3f53cc0681d9aaf1787afa52f0c3d9b6f", + "namingSemanticSha256": "96abe1da4ac25539d62fbbef0b9e64f8e4a0d055543ebfb5072ca70c61629b5e" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "distance", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "stable": true, + "attempts": [ + { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "parameter": "distance", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "parameter": "distance", + "parameterValue": 0.6, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "parameter": "distance", + "parameterValue": 0.4, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "selectedEdges": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "nativeTypeId": "Part::Chamfer", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Chamfer" + } + ], + "parameter": { + "name": "distance", + "value": 0.4 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "BRep_API: command not done" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Chamfer", + "operation": "chamfer", + "pair": "polar-pattern->chamfer", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-hole", + "pair": "polar-pattern->hole", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "607de8e161b62a359907c38bab099cee85841a479038c730699e299987546265", + "namingSemanticSha256": "9586650c491ea85bb62dfb7248ef327390f7fe4afd00fa5c0a55962f94ae9a30" + }, + "second": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 29, + "vertices": 18, + "volume": 1391.2338043, + "area": 825.6085601, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "c9b075a0bdd3c86aea5de5e908788672717a1b456fb1d4866cbbc09aac5629f6", + "namingEvidenceSha256": "826487854eec242568cfb64f6afba3844da8553ee2b61b6e91dcac744a2e4841", + "namingSemanticSha256": "c8176a8041f44c1ce812915e1f68cb27623fa3302416f69a23576e31289c40c6" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 1, + 1.5, + 1 + ], + "beforeValue": 1, + "editedValue": 1.5, + "restoredValue": 1, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 29, + "vertices": 18, + "volume": 1351.9638961, + "area": 849.170505, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "c9b075a0bdd3c86aea5de5e908788672717a1b456fb1d4866cbbc09aac5629f6", + "namingEvidenceSha256": "a31b369790722079fa94a4ae4c5c010322ff3f1dc7c208f559f0b88e39a88bde", + "namingSemanticSha256": "c8176a8041f44c1ce812915e1f68cb27623fa3302416f69a23576e31289c40c6" + }, + "restoredEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 29, + "vertices": 18, + "volume": 1391.2338043, + "area": 825.6085601, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "c9b075a0bdd3c86aea5de5e908788672717a1b456fb1d4866cbbc09aac5629f6", + "namingEvidenceSha256": "c0a4cde6e34536718e37cefe2c1ec2e338b7eb0bd3921b44ee8c9bd20418aa23", + "namingSemanticSha256": "c8176a8041f44c1ce812915e1f68cb27623fa3302416f69a23576e31289c40c6" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "polar-pattern->hole", + "phases": { + "initial": { + "namingEvidenceBytes": 1806, + "namingEvidenceSha256": "826487854eec242568cfb64f6afba3844da8553ee2b61b6e91dcac744a2e4841", + "pair": "polar-pattern->hole", + "shape": { + "area": 825.6085601, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 29, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1391.2338043 + } + }, + "reopened": { + "namingEvidenceBytes": 1806, + "namingEvidenceSha256": "826487854eec242568cfb64f6afba3844da8553ee2b61b6e91dcac744a2e4841", + "pair": "polar-pattern->hole", + "shape": { + "area": 825.6085601, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 29, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1391.2338043 + } + }, + "resaved": { + "namingEvidenceBytes": 1806, + "namingEvidenceSha256": "826487854eec242568cfb64f6afba3844da8553ee2b61b6e91dcac744a2e4841", + "pair": "polar-pattern->hole", + "shape": { + "area": 825.6085601, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 29, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1391.2338043 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-draft", + "pair": "polar-pattern->draft", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "d871f32820598ea2437371a8245e3e9e697053e7bddf1a5e3fe3ee457f4fa6ac", + "namingSemanticSha256": "74f4590c3a26e7dc96b12670693915d3aeb85d7a0a25673c6fe18c326e940663" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "angle", + "trajectory": [ + 5, + 8, + 5 + ], + "stable": true, + "attempts": [ + { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 8, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "draftBaseBrepSha256": "4babc3ae0c75b22c1a31f4c0dfa72cd18dd352ed22e7067cbcd63b03ea2a1006", + "name": "DraftBase", + "shapeSummaryTransferredExactly": true, + "sourceBrepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "sourceName": "Part__Feature", + "subelements": [ + "Face1" + ], + "typeId": "PartDesign::Feature" + }, + "inputShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "nativeTypeId": "PartDesign::Draft", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Body", + "typeId": "PartDesign::Body" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + }, + { + "name": "DraftBase", + "typeId": "PartDesign::Feature" + }, + { + "name": "DatumPlane", + "typeId": "PartDesign::Plane" + }, + { + "name": "DatumLine", + "typeId": "PartDesign::Line" + }, + { + "name": "PairResult", + "typeId": "PartDesign::Draft" + } + ], + "parameter": { + "name": "angle", + "value": 5 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "PartDesign::Draft", + "operation": "draft", + "pair": "polar-pattern->draft", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-thickness", + "pair": "polar-pattern->thickness", + "classification": "rejected", + "reasonCode": "native-and-freecad-profile-no-op-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "acb4c3b09dde2e7ed6fa2522b3321d1daf7a61bbd58be2378830534c3933b6d7", + "namingSemanticSha256": "af4c673148fc077fae701564a813020d64f56ea96e472deeb192e5b892252950" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-no-op", + "parameter": "offset", + "trajectory": [ + -0.4, + -0.6, + -0.4 + ], + "kernelAttempts": [ + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.4, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "e6b17a471199af3f1e5f7d4d1ad88c789006504865f36edc1f11bb2d0a227cdc", + "authority": "kernel-no-op", + "noOpComparison": "topology-and-metrics-within-1e-6" + }, + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.6, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "e6b17a471199af3f1e5f7d4d1ad88c789006504865f36edc1f11bb2d0a227cdc", + "authority": "kernel-no-op", + "noOpComparison": "topology-and-metrics-within-1e-6" + }, + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.4, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "e6b17a471199af3f1e5f7d4d1ad88c789006504865f36edc1f11bb2d0a227cdc", + "authority": "kernel-no-op", + "noOpComparison": "topology-and-metrics-within-1e-6" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "freecadProfileNoOp": true, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": false, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": false, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [ + "Face2" + ], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "nativeTypeId": "Part::Thickness", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Thickness" + } + ], + "parameter": { + "name": "offset", + "value": -0.4 + }, + "recomputeResult": true, + "resultShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "shapeNull": false, + "shapeValid": true, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Thickness", + "operation": "thickness", + "pair": "polar-pattern->thickness", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "3258844f37adf246a921f24b77c0474a191390a6f6bcc837ee3e46d505668dc4", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "sourceBrepReserialized": true, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "brepSha256": "35c40a356cdc4a6c4cfda29e7760e8c6db16df3b36cc22a4c4935c26b963d3c5", + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-linear-pattern", + "pair": "polar-pattern->linear-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "372fe17158d7884b3863a99e5c1b52922bd9160cf1f1a9215f39dd3dc80f00a5", + "namingSemanticSha256": "e3bb7f20e3c0e3a7a76595e11ca3976c148a5c91d49bad5b219d70e8d2952019" + }, + "second": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 36, + "edges": 78, + "vertices": 44, + "volume": 2376.9059892, + "area": 1149.1931763, + "bounds": [ + -5.0000002, + -1e-7, + -1e-7, + 18.0000002, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 175, + "selectedRecords": 23, + "ambiguousResults": 31, + "historySha256": "bf7510b4aa42dccd49b6a1f4e1ee05be954ad03022e6a49fde254219409770e3", + "namingEvidenceSha256": "fa130287b0014f747b4d242d77b920262de2b499ac56b2e9753fb05eecfa9df6", + "namingSemanticSha256": "db46332e83f6632038dac1a3ae6dd3c9d716170e839284ffff81b58beaff9cc3" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "translationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 33, + "edges": 71, + "vertices": 40, + "volume": 2477.3502692, + "area": 1190.9401077, + "bounds": [ + -5.0000002, + -1e-7, + -1e-7, + 19.0000002, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 136, + "selectedRecords": 17, + "ambiguousResults": 23, + "historySha256": "663310057692e8481c462f078e876d23e1f7f334be5f80dff9f39190b558eec7", + "namingEvidenceSha256": "597c36f8658ddd40a235b9380e7e94eb4005986cccf2e356e01fcf0aa0166d9b", + "namingSemanticSha256": "452b40118fbb3a899c8a82a84625fc47804bbf19bc7b460984690a8f01d9ec5a" + }, + "restoredEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 36, + "edges": 78, + "vertices": 44, + "volume": 2376.9059892, + "area": 1149.1931763, + "bounds": [ + -5.0000002, + -1e-7, + -1e-7, + 18.0000002, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 175, + "selectedRecords": 23, + "ambiguousResults": 31, + "historySha256": "bf7510b4aa42dccd49b6a1f4e1ee05be954ad03022e6a49fde254219409770e3", + "namingEvidenceSha256": "12d32705d55cc87fe139150fabcfb19613fbfee6d3b33a2b21ed23b922fba2c8", + "namingSemanticSha256": "db46332e83f6632038dac1a3ae6dd3c9d716170e839284ffff81b58beaff9cc3" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "polar-pattern->linear-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 20600, + "namingEvidenceSha256": "fa130287b0014f747b4d242d77b920262de2b499ac56b2e9753fb05eecfa9df6", + "pair": "polar-pattern->linear-pattern", + "shape": { + "area": 1149.1931763, + "bounds": [ + -5, + 0, + 0, + 18, + 13.660254, + 10 + ], + "edges": 78, + "faces": 36, + "solids": 1, + "valid": true, + "vertices": 44, + "volume": 2376.9059892 + } + }, + "reopened": { + "namingEvidenceBytes": 20600, + "namingEvidenceSha256": "fa130287b0014f747b4d242d77b920262de2b499ac56b2e9753fb05eecfa9df6", + "pair": "polar-pattern->linear-pattern", + "shape": { + "area": 1149.1931763, + "bounds": [ + -5, + 0, + 0, + 18, + 13.660254, + 10 + ], + "edges": 78, + "faces": 36, + "solids": 1, + "valid": true, + "vertices": 44, + "volume": 2376.9059892 + } + }, + "resaved": { + "namingEvidenceBytes": 20600, + "namingEvidenceSha256": "fa130287b0014f747b4d242d77b920262de2b499ac56b2e9753fb05eecfa9df6", + "pair": "polar-pattern->linear-pattern", + "shape": { + "area": 1149.1931763, + "bounds": [ + -5, + 0, + 0, + 18, + 13.660254, + 10 + ], + "edges": 78, + "faces": 36, + "solids": 1, + "valid": true, + "vertices": 44, + "volume": 2376.9059892 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-polar-pattern", + "pair": "polar-pattern->polar-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "2976589ef8cfd370d13827e279e36cf46ea50d7ba7b451ad9667fe80bbbd45dd", + "namingSemanticSha256": "dbce77d8a3d1c3729fa4d9346f51e7f78fbf785ecb7f1867d039dea42568b2dc" + }, + "second": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 20, + "edges": 44, + "vertices": 26, + "volume": 1845.2994616, + "area": 938.1197846, + "bounds": [ + -8.6602541, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 228, + "selectedRecords": 13, + "ambiguousResults": 31, + "historySha256": "e4d7d36ca10ae6778f4f17c742e0d959e52812b4f18a38504b99a9143457a093", + "namingEvidenceSha256": "47e7c088e25a5c5b706caf6757a460e6eb4a188ddf0f30b961acfeccc913f6d4", + "namingSemanticSha256": "7f9ea38630a3e4552a9d9f1cc30f57013016f66f8562e1c529c3c7be593afa41" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 30, + 45, + 30 + ], + "beforeValue": 30, + "editedValue": 45, + "restoredValue": 30, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 30, + "edges": 66, + "vertices": 38, + "volume": 2077.9724736, + "area": 1031.1889895, + "bounds": [ + -9.6592584, + -1e-7, + -1e-7, + 10.0000001, + 14.1421358, + 10.0000001 + ] + }, + "historyRecords": 162, + "selectedRecords": 16, + "ambiguousResults": 23, + "historySha256": "ee72986f1541ad6a07970128c0482f27be7e57d5db049690661488d129a5650e", + "namingEvidenceSha256": "bd7ebecef0b53b06374448cfe455e1bb0cee5d6012450e2e65567fab2cb40fe2", + "namingSemanticSha256": "822bd168fb4cce2f1617ba40a6dde3dee0363d27792519cc368243777d779ac5" + }, + "restoredEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 20, + "edges": 44, + "vertices": 26, + "volume": 1845.2994616, + "area": 938.1197846, + "bounds": [ + -8.6602541, + -1e-7, + -1e-7, + 10.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 228, + "selectedRecords": 13, + "ambiguousResults": 31, + "historySha256": "e4d7d36ca10ae6778f4f17c742e0d959e52812b4f18a38504b99a9143457a093", + "namingEvidenceSha256": "95f82b3fd0ec56b261cd487efd3f801dca3fa465de8e795a69492bbbac5002b6", + "namingSemanticSha256": "7f9ea38630a3e4552a9d9f1cc30f57013016f66f8562e1c529c3c7be593afa41" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "polar-pattern->polar-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 19583, + "namingEvidenceSha256": "47e7c088e25a5c5b706caf6757a460e6eb4a188ddf0f30b961acfeccc913f6d4", + "pair": "polar-pattern->polar-pattern", + "shape": { + "area": 938.1197846, + "bounds": [ + -8.660254, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 44, + "faces": 20, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1845.2994616 + } + }, + "reopened": { + "namingEvidenceBytes": 19583, + "namingEvidenceSha256": "47e7c088e25a5c5b706caf6757a460e6eb4a188ddf0f30b961acfeccc913f6d4", + "pair": "polar-pattern->polar-pattern", + "shape": { + "area": 938.1197846, + "bounds": [ + -8.660254, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 44, + "faces": 20, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1845.2994616 + } + }, + "resaved": { + "namingEvidenceBytes": 19583, + "namingEvidenceSha256": "47e7c088e25a5c5b706caf6757a460e6eb4a188ddf0f30b961acfeccc913f6d4", + "pair": "polar-pattern->polar-pattern", + "shape": { + "area": 938.1197846, + "bounds": [ + -8.660254, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 44, + "faces": 20, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 1845.2994616 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-mirrored", + "pair": "polar-pattern->mirrored", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "9b61860a94bd6114568f70bc19cf489bafcaf27dea327063bf16f69454dad652", + "namingSemanticSha256": "b0ac191f5fefdd027f4c51daded558b3fce64a583a69e9f6400cf03d86355ac4" + }, + "second": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 21, + "edges": 47, + "vertices": 28, + "volume": 1834.9364905, + "area": 920.5771366, + "bounds": [ + -5.0000002, + -1e-7, + -1e-7, + 15.0000002, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 250, + "selectedRecords": 15, + "ambiguousResults": 34, + "historySha256": "d559a9304ab85fe802bf89dce57c0ede80e503b13223968b0407737558054ccf", + "namingEvidenceSha256": "72f0a2e0f8faa23f6912c039bc56790433f80a067bb97bb099e4a7a661052105", + "namingSemanticSha256": "0f7afd578284d1165142cc09ccddb637a0ff312685e2e277a1317c27282846e6" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "planeOriginX", + "trajectory": [ + 5, + 6, + 5 + ], + "beforeValue": 5, + "editedValue": 6, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 32, + "edges": 70, + "vertices": 40, + "volume": 2045.2994616, + "area": 1018.1197846, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 17.0000001, + 13.6602541, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 19, + "ambiguousResults": 28, + "historySha256": "a929200cd3975e61d582c6ee7cc2168313281bfa1268fcfae65d7a8b51812a43", + "namingEvidenceSha256": "33681b868783d2c423af3a5869c3c1ec30fdd5f91d653dfd2bf45193dba79bad", + "namingSemanticSha256": "3e23b45ae838c2ee7186518bcfc68420435d4aebcd0bb9066dae8106b3af69b9" + }, + "restoredEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 21, + "edges": 47, + "vertices": 28, + "volume": 1834.9364905, + "area": 920.5771366, + "bounds": [ + -5.0000002, + -1e-7, + -1e-7, + 15.0000002, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 250, + "selectedRecords": 15, + "ambiguousResults": 34, + "historySha256": "d559a9304ab85fe802bf89dce57c0ede80e503b13223968b0407737558054ccf", + "namingEvidenceSha256": "60da4201220f19ae46c3ade4a5c451205c20b565d3a671e7ea93044a15ba3465", + "namingSemanticSha256": "0f7afd578284d1165142cc09ccddb637a0ff312685e2e277a1317c27282846e6" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "polar-pattern->mirrored", + "phases": { + "initial": { + "namingEvidenceBytes": 20526, + "namingEvidenceSha256": "72f0a2e0f8faa23f6912c039bc56790433f80a067bb97bb099e4a7a661052105", + "pair": "polar-pattern->mirrored", + "shape": { + "area": 920.5771366, + "bounds": [ + -5, + 0, + 0, + 15, + 13.660254, + 10 + ], + "edges": 47, + "faces": 21, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 1834.9364905 + } + }, + "reopened": { + "namingEvidenceBytes": 20526, + "namingEvidenceSha256": "72f0a2e0f8faa23f6912c039bc56790433f80a067bb97bb099e4a7a661052105", + "pair": "polar-pattern->mirrored", + "shape": { + "area": 920.5771366, + "bounds": [ + -5, + 0, + 0, + 15, + 13.660254, + 10 + ], + "edges": 47, + "faces": 21, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 1834.9364905 + } + }, + "resaved": { + "namingEvidenceBytes": 20526, + "namingEvidenceSha256": "72f0a2e0f8faa23f6912c039bc56790433f80a067bb97bb099e4a7a661052105", + "pair": "polar-pattern->mirrored", + "shape": { + "area": 920.5771366, + "bounds": [ + -5, + 0, + 0, + 15, + 13.660254, + 10 + ], + "edges": 47, + "faces": 21, + "solids": 1, + "valid": true, + "vertices": 28, + "volume": 1834.9364905 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-polar-pattern-multi-transform", + "pair": "polar-pattern->multi-transform", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "b0850da2a12eb332ca50406d24100dab526caa133add05ba8a36c44cb8c007f6", + "namingEvidenceSha256": "ea4d996809693ca4dbcd8acfbd69264b0450e6c64d8adc12103cb3b6ee26b7b7", + "namingSemanticSha256": "0121a057d7e04cc63d8d71a862b5603add9a7070ca33c885d2a68687b7be50cf" + }, + "second": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 115, + "edges": 241, + "vertices": 128, + "volume": 3052.108193, + "area": 1415.9432402, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000002, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 1187, + "selectedRecords": 61, + "ambiguousResults": 348, + "historySha256": "d4d7bbaf49fe918673e349b6e27ddffa701d275a5a5165fc1e3b9746ba7bcfe4", + "namingEvidenceSha256": "2fe760a0f6d336e11c10f8575ef9c647ac2ee601119187a7871f753b3b4d6880", + "namingSemanticSha256": "f33cc84fce0ef3b844f40024978bb545f6e24eb61068254ecd3124fb862b3b3f" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "multiTranslationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 91, + "edges": 193, + "vertices": 104, + "volume": 3291.7085548, + "area": 1506.9573233, + "bounds": [ + -9.0000001, + -1e-7, + -1e-7, + 19.0000002, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 1035, + "selectedRecords": 49, + "ambiguousResults": 288, + "historySha256": "7e9880afe5de100e39f44da418db9b4d11aec4ff42f43abcfd0281cfc5ccae42", + "namingEvidenceSha256": "d272509fb23db48265751ff67a6c56d7f1a51a1b226fb8175e36095fc531d222", + "namingSemanticSha256": "1485a68eaf9e64c3c93444e9ca5fa9666b789b5cf9c9ccda4fc7fe4812f6763d" + }, + "restoredEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 115, + "edges": 241, + "vertices": 128, + "volume": 3052.108193, + "area": 1415.9432402, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000002, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 1187, + "selectedRecords": 61, + "ambiguousResults": 348, + "historySha256": "d4d7bbaf49fe918673e349b6e27ddffa701d275a5a5165fc1e3b9746ba7bcfe4", + "namingEvidenceSha256": "7886323614aadbfa5f38ca79448cedb4373d120829f0c0651cfb02e3ff955f33", + "namingSemanticSha256": "f33cc84fce0ef3b844f40024978bb545f6e24eb61068254ecd3124fb862b3b3f" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "polar-pattern->multi-transform", + "phases": { + "initial": { + "namingEvidenceBytes": 173318, + "namingEvidenceSha256": "2fe760a0f6d336e11c10f8575ef9c647ac2ee601119187a7871f753b3b4d6880", + "pair": "polar-pattern->multi-transform", + "shape": { + "area": 1415.9432402, + "bounds": [ + -8, + 0, + 0, + 18, + 13.660254, + 10 + ], + "edges": 241, + "faces": 115, + "solids": 1, + "valid": true, + "vertices": 128, + "volume": 3052.108193 + } + }, + "reopened": { + "namingEvidenceBytes": 173318, + "namingEvidenceSha256": "2fe760a0f6d336e11c10f8575ef9c647ac2ee601119187a7871f753b3b4d6880", + "pair": "polar-pattern->multi-transform", + "shape": { + "area": 1415.9432402, + "bounds": [ + -8, + 0, + 0, + 18, + 13.660254, + 10 + ], + "edges": 241, + "faces": 115, + "solids": 1, + "valid": true, + "vertices": 128, + "volume": 3052.108193 + } + }, + "resaved": { + "namingEvidenceBytes": 173318, + "namingEvidenceSha256": "2fe760a0f6d336e11c10f8575ef9c647ac2ee601119187a7871f753b3b4d6880", + "pair": "polar-pattern->multi-transform", + "shape": { + "area": 1415.9432402, + "bounds": [ + -8, + 0, + 0, + 18, + 13.660254, + 10 + ], + "edges": 241, + "faces": 115, + "solids": 1, + "valid": true, + "vertices": 128, + "volume": 3052.108193 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-fuse", + "pair": "mirrored->fuse", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "6ad4637dc11e38d6df1738bde42b845f9a4d5978d41939b73c0805688dce628a", + "namingSemanticSha256": "d5cd73eac1b0d0cd00d3224d3817089628c7e886e6a512e7b8cbcd534ab3cbdf" + }, + "second": { + "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": "a7ba4ce01c0b9837eb21e5c6df1aa49dd831f583af510c5266e53ca47e7eb704", + "namingEvidenceSha256": "79a9b1faa46b36f74818396890f334443ee003e99fa0e10ed87b703f48493aa6", + "namingSemanticSha256": "81cd158a4d30f3b87294bcccdaa9ff32358966eb4ff3bda3a22dc5c0cc527208" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 8, + 7, + 8 + ], + "beforeValue": 8, + "editedValue": 7, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 13, + "edges": 29, + "vertices": 18, + "volume": 1050, + "area": 640, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 12.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "a7ba4ce01c0b9837eb21e5c6df1aa49dd831f583af510c5266e53ca47e7eb704", + "namingEvidenceSha256": "4d28c61b4a96d61b046fbe4ce6af02e0074a88ef9613c5ee8bbb4763baa44894", + "namingSemanticSha256": "81cd158a4d30f3b87294bcccdaa9ff32358966eb4ff3bda3a22dc5c0cc527208" + }, + "restoredEvidence": { + "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": "a7ba4ce01c0b9837eb21e5c6df1aa49dd831f583af510c5266e53ca47e7eb704", + "namingEvidenceSha256": "c6de67b94d5385a273a9e137092e4f47ec6de836da0d3232f82ed43422e3cc62", + "namingSemanticSha256": "81cd158a4d30f3b87294bcccdaa9ff32358966eb4ff3bda3a22dc5c0cc527208" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->fuse", + "phases": { + "initial": { + "namingEvidenceBytes": 8308, + "namingEvidenceSha256": "79a9b1faa46b36f74818396890f334443ee003e99fa0e10ed87b703f48493aa6", + "pair": "mirrored->fuse", + "shape": { + "area": 660, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 29, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1075 + } + }, + "reopened": { + "namingEvidenceBytes": 8308, + "namingEvidenceSha256": "79a9b1faa46b36f74818396890f334443ee003e99fa0e10ed87b703f48493aa6", + "pair": "mirrored->fuse", + "shape": { + "area": 660, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 29, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1075 + } + }, + "resaved": { + "namingEvidenceBytes": 8308, + "namingEvidenceSha256": "79a9b1faa46b36f74818396890f334443ee003e99fa0e10ed87b703f48493aa6", + "pair": "mirrored->fuse", + "shape": { + "area": 660, + "bounds": [ + 0, + 0, + 0, + 13, + 10, + 10 + ], + "edges": 29, + "faces": 13, + "solids": 1, + "valid": true, + "vertices": 18, + "volume": 1075 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-cut", + "pair": "mirrored->cut", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "43d2d2eb1c68a6d7b85503eda0877bd6dc3a3eed4ae825b6e70d3950f5521927", + "namingSemanticSha256": "5a8f04d994012ea89c812cd1c8cbc7530446e542a561068decc1a9b40c7443cb" + }, + "second": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 10, + "edges": 24, + "vertices": 16, + "volume": 936, + "area": 632, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 22, + "selectedRecords": 2, + "ambiguousResults": 8, + "historySha256": "4c7f022272b945258c91787fcce83c42dd50e9790325e1d47d722cdcaf166a6e", + "namingEvidenceSha256": "20a01c32bcfc18226ee8fdfa3418c40412d4d1f5622fa7160c1e3bb25c953941", + "namingSemanticSha256": "9396b638cf7c8a20c3b12888f091b67a767bfe709672e55aa575277ef66416d6" + }, + "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": 10, + "edges": 24, + "vertices": 16, + "volume": 973, + "area": 618, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 22, + "selectedRecords": 2, + "ambiguousResults": 8, + "historySha256": "4c7f022272b945258c91787fcce83c42dd50e9790325e1d47d722cdcaf166a6e", + "namingEvidenceSha256": "20a01c32bcfc18226ee8fdfa3418c40412d4d1f5622fa7160c1e3bb25c953941", + "namingSemanticSha256": "9396b638cf7c8a20c3b12888f091b67a767bfe709672e55aa575277ef66416d6" + }, + "restoredEvidence": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 10, + "edges": 24, + "vertices": 16, + "volume": 936, + "area": 632, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 22, + "selectedRecords": 2, + "ambiguousResults": 8, + "historySha256": "4c7f022272b945258c91787fcce83c42dd50e9790325e1d47d722cdcaf166a6e", + "namingEvidenceSha256": "ec1b695ae2af44232fbb2af448ca365e53adada851d18389cc7dbde0d2e9402e", + "namingSemanticSha256": "9396b638cf7c8a20c3b12888f091b67a767bfe709672e55aa575277ef66416d6" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->cut", + "phases": { + "initial": { + "namingEvidenceBytes": 3791, + "namingEvidenceSha256": "20a01c32bcfc18226ee8fdfa3418c40412d4d1f5622fa7160c1e3bb25c953941", + "pair": "mirrored->cut", + "shape": { + "area": 632, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 936 + } + }, + "reopened": { + "namingEvidenceBytes": 3791, + "namingEvidenceSha256": "20a01c32bcfc18226ee8fdfa3418c40412d4d1f5622fa7160c1e3bb25c953941", + "pair": "mirrored->cut", + "shape": { + "area": 632, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 936 + } + }, + "resaved": { + "namingEvidenceBytes": 3791, + "namingEvidenceSha256": "20a01c32bcfc18226ee8fdfa3418c40412d4d1f5622fa7160c1e3bb25c953941", + "pair": "mirrored->cut", + "shape": { + "area": 632, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 936 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-common", + "pair": "mirrored->common", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "d9925dd205294417cfd6fea70d6d658bb723ad11a85ce079194de3df440e1848", + "namingSemanticSha256": "1291eb2527258a6cdbfc61716e684109feff5f5897bbee8818fca0d6efa40d3e" + }, + "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": [ + 6.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 121, + "selectedRecords": 3, + "ambiguousResults": 10, + "historySha256": "1e52ee025e105d3aa350f629dd4714ff522ffe76e903edd331304ded67e138bf", + "namingEvidenceSha256": "0e46d8968ef108c9ed4abd2b0be7c1db191a12dfbada6fd27b4b8e5adcb324dd", + "namingSemanticSha256": "a8bbb2d58769cf6f07e584bb341212dfcf9020066eaca9e29dd6e2d62472319a" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 7, + 6, + 7 + ], + "beforeValue": 7, + "editedValue": 6, + "restoredValue": 7, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "common", + "builder": "BRepAlgoAPI_Common", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 100, + "area": 130, + "bounds": [ + 5.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 121, + "selectedRecords": 3, + "ambiguousResults": 10, + "historySha256": "1e52ee025e105d3aa350f629dd4714ff522ffe76e903edd331304ded67e138bf", + "namingEvidenceSha256": "0d15cbe441fbcaf60c011a8386d31aa87441883bfee9586cc298a9f992088121", + "namingSemanticSha256": "a8bbb2d58769cf6f07e584bb341212dfcf9020066eaca9e29dd6e2d62472319a" + }, + "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": [ + 6.9999999, + -1e-7, + -1e-7, + 10.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 121, + "selectedRecords": 3, + "ambiguousResults": 10, + "historySha256": "1e52ee025e105d3aa350f629dd4714ff522ffe76e903edd331304ded67e138bf", + "namingEvidenceSha256": "edb2b16fd26bdd16dc22d5d010702c12adc3d308d35515dcda78eeba22f72fb1", + "namingSemanticSha256": "a8bbb2d58769cf6f07e584bb341212dfcf9020066eaca9e29dd6e2d62472319a" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->common", + "phases": { + "initial": { + "namingEvidenceBytes": 5060, + "namingEvidenceSha256": "0e46d8968ef108c9ed4abd2b0be7c1db191a12dfbada6fd27b4b8e5adcb324dd", + "pair": "mirrored->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 75 + } + }, + "reopened": { + "namingEvidenceBytes": 5060, + "namingEvidenceSha256": "0e46d8968ef108c9ed4abd2b0be7c1db191a12dfbada6fd27b4b8e5adcb324dd", + "pair": "mirrored->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 75 + } + }, + "resaved": { + "namingEvidenceBytes": 5060, + "namingEvidenceSha256": "0e46d8968ef108c9ed4abd2b0be7c1db191a12dfbada6fd27b4b8e5adcb324dd", + "pair": "mirrored->common", + "shape": { + "area": 110, + "bounds": [ + 7, + 0, + 0, + 10, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 75 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-rotate", + "pair": "mirrored->rotate", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "217f693417bd5ac8e080b646b4bb02093cfabd41bd1c991330219047340055c8", + "namingSemanticSha256": "7d676fe27f56c24611ac4fe77861bb448b34e1623bdaa12c8716ba9aa7ad1a8c" + }, + "second": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -2.5881906, + -1e-7, + -1e-7, + 9.6592584, + 12.2474488, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "6bdb408cb4ef5c2c786bf136dec46159ea09f544afcba87950047fea9ab00973", + "namingEvidenceSha256": "2267188ff9091422691b0ece5b6c618b77f02cc66d3d26c7044133e146f2d1fe", + "namingSemanticSha256": "c5c22c8a233309a8e3929828e80b7d4a469b039f6735c0b43c8f53cc90912a99" + }, + "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": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -3.8268344, + -1e-7, + -1e-7, + 9.2387954, + 13.0656297, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "6bdb408cb4ef5c2c786bf136dec46159ea09f544afcba87950047fea9ab00973", + "namingEvidenceSha256": "2697c20f3f5f9b999b281ce2a88d07a075d966ec7e897c9c5fc95696d6fe606c", + "namingSemanticSha256": "c5c22c8a233309a8e3929828e80b7d4a469b039f6735c0b43c8f53cc90912a99" + }, + "restoredEvidence": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -2.5881906, + -1e-7, + -1e-7, + 9.6592584, + 12.2474488, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "6bdb408cb4ef5c2c786bf136dec46159ea09f544afcba87950047fea9ab00973", + "namingEvidenceSha256": "e5d9841d0edcfd0810646baf1c16ca5ec2f638b1518b30420d929444e2612a8c", + "namingSemanticSha256": "c5c22c8a233309a8e3929828e80b7d4a469b039f6735c0b43c8f53cc90912a99" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->rotate", + "phases": { + "initial": { + "namingEvidenceBytes": 13901, + "namingEvidenceSha256": "2267188ff9091422691b0ece5b6c618b77f02cc66d3d26c7044133e146f2d1fe", + "pair": "mirrored->rotate", + "shape": { + "area": 600, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "reopened": { + "namingEvidenceBytes": 13901, + "namingEvidenceSha256": "2267188ff9091422691b0ece5b6c618b77f02cc66d3d26c7044133e146f2d1fe", + "pair": "mirrored->rotate", + "shape": { + "area": 600, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "resaved": { + "namingEvidenceBytes": 13901, + "namingEvidenceSha256": "2267188ff9091422691b0ece5b6c618b77f02cc66d3d26c7044133e146f2d1fe", + "pair": "mirrored->rotate", + "shape": { + "area": 600, + "bounds": [ + -2.5881905, + 0, + 0, + 9.6592583, + 12.2474487, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-pad", + "pair": "mirrored->pad", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "67a82c2dca510408d9e7255b0e2ade7b7c388ede59876c42351dd286fb73ffc0", + "namingSemanticSha256": "ced8d58c14710573778f300baf7d70fa1f6b3b895f46e2dca14161c5a1ad8da7" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "length", + "trajectory": [ + 5, + 7.5, + 5 + ], + "stable": true, + "attempts": [ + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 7.5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "nativeTypeId": "PartDesign::Pad", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Body", + "typeId": "PartDesign::Body" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + }, + { + "name": "PairResult", + "typeId": "PartDesign::Pad" + } + ], + "parameter": { + "name": "length", + "value": 5 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "FeatureExtrusion: Length: Could not extrude the sketch!" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "PartDesign::Pad", + "operation": "pad", + "pair": "mirrored->pad", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-mirrored-pocket", + "pair": "mirrored->pocket", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "c58cf7adef4ec959041bf571ec3941ff70b97c2c2b93401b241ec389532806dc", + "namingSemanticSha256": "db2f5220d42a379f8345b5fa6c148c418422cda0f24f95b463e5e59549c3ec72" + }, + "second": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 9, + "edges": 21, + "vertices": 14, + "volume": 970, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 3, + "ambiguousResults": 9, + "historySha256": "4495b8b386cb012ef7663bb6c0d3fb9d5a12238abd0503cc935e956cf2495c36", + "namingEvidenceSha256": "41a368e2c2366158756ca83f30a2b3afd97ac67602b0e185cba7d4f3b2d8dfaf", + "namingSemanticSha256": "be1955ba57da5203fceecc5b9d36d58ad0cdf542fa07d88df6adf3537745c0f5" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "length", + "trajectory": [ + 5, + 4, + 5 + ], + "beforeValue": 5, + "editedValue": 4, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 9, + "edges": 21, + "vertices": 14, + "volume": 976, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 3, + "ambiguousResults": 9, + "historySha256": "4495b8b386cb012ef7663bb6c0d3fb9d5a12238abd0503cc935e956cf2495c36", + "namingEvidenceSha256": "f5ecde9f8479823578cfd709d6a01680da335e5ae6dd7e80f44f71794fc61a0b", + "namingSemanticSha256": "be1955ba57da5203fceecc5b9d36d58ad0cdf542fa07d88df6adf3537745c0f5" + }, + "restoredEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 9, + "edges": 21, + "vertices": 14, + "volume": 970, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 42, + "selectedRecords": 3, + "ambiguousResults": 9, + "historySha256": "4495b8b386cb012ef7663bb6c0d3fb9d5a12238abd0503cc935e956cf2495c36", + "namingEvidenceSha256": "6d3ebf2b2dc731f57fbf4fb1ba64a1855a984c82428fbd65baa64b8df1f798ab", + "namingSemanticSha256": "be1955ba57da5203fceecc5b9d36d58ad0cdf542fa07d88df6adf3537745c0f5" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->pocket", + "phases": { + "initial": { + "namingEvidenceBytes": 4630, + "namingEvidenceSha256": "41a368e2c2366158756ca83f30a2b3afd97ac67602b0e185cba7d4f3b2d8dfaf", + "pair": "mirrored->pocket", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 21, + "faces": 9, + "solids": 1, + "valid": true, + "vertices": 14, + "volume": 970 + } + }, + "reopened": { + "namingEvidenceBytes": 4630, + "namingEvidenceSha256": "41a368e2c2366158756ca83f30a2b3afd97ac67602b0e185cba7d4f3b2d8dfaf", + "pair": "mirrored->pocket", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 21, + "faces": 9, + "solids": 1, + "valid": true, + "vertices": 14, + "volume": 970 + } + }, + "resaved": { + "namingEvidenceBytes": 4630, + "namingEvidenceSha256": "41a368e2c2366158756ca83f30a2b3afd97ac67602b0e185cba7d4f3b2d8dfaf", + "pair": "mirrored->pocket", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 21, + "faces": 9, + "solids": 1, + "valid": true, + "vertices": 14, + "volume": 970 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-loft", + "pair": "mirrored->loft", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "a06519e571df55b23a82655ea6b021ba62381cfb54c4bcc954e0661ce1c2e1c1", + "namingSemanticSha256": "ee4e5ead9a21b3ab9a286e56be7784bcd5e539c4ac7bb551efdf7e674e4886a0" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "ruled", + "trajectory": [ + false, + true, + false + ], + "kernelAttempts": [ + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": true, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 750, + "area": 580.2775638, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + } + ] + }, + "inputShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "nativeTypeId": "Part::Loft", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Loft" + } + ], + "parameter": { + "name": "ruled", + "value": false + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Profile shape is not a single vertex, edge, wire nor face." + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Loft", + "operation": "loft", + "pair": "mirrored->loft", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-mirrored-pipe", + "pair": "mirrored->pipe", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "ee5eeba9856ee2330b4a316f5e542a929790e7a37dd150e89709ec607f9f8732", + "namingSemanticSha256": "1bedd17b68d3dc145ee2438bec40773365c2631ba3f2c662075b23658e360a29" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "spineLength", + "trajectory": [ + 15, + 12, + 15 + ], + "kernelAttempts": [ + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 25.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 12, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 440, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 22.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 1e-7, + 10.0000001, + 25.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "spine": { + "name": "Spine", + "subelements": [], + "typeId": "Part::Feature" + } + }, + "inputShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "nativeTypeId": "Part::Sweep", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Spine", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Sweep" + } + ], + "parameter": { + "name": "spineLength", + "value": 15 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "A fatal error occurred when making the sweep" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Sweep", + "operation": "pipe", + "pair": "mirrored->pipe", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-mirrored-revolution", + "pair": "mirrored->revolution", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "0106797201b3de42b6dba1e32fd3fa6fba7a83c48cb2cebd286f4ebeb9147de3", + "namingSemanticSha256": "d6b15c756846b1aa7d8b2aa91b93b325f7434f88e825b1ce15374e34e93c7c40" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "angle", + "trajectory": [ + 360, + 270, + 360 + ], + "stable": true, + "attempts": [ + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 270, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "nativeTypeId": "Part::Revolution", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Revolution" + } + ], + "parameter": { + "name": "angle", + "value": 360 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Solids are not Processed" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Revolution", + "operation": "revolution", + "pair": "mirrored->revolution", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "brepSha256": "a7a1463754da5fac3510fc127cb1e6f943341ee403a991ba12f1860108141c94", + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-mirrored-groove", + "pair": "mirrored->groove", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "4c4f62b6f598dfef78c34e73b59475a2b7435bb5ade461ec228f5ff10b3e08de", + "namingSemanticSha256": "7010d923498bb47a8136dde58e8973471eb3fb600ec96c467b1eed717c405cfa" + }, + "second": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 10, + "edges": 24, + "vertices": 16, + "volume": 995.287611, + "area": 606.5663706, + "bounds": [ + -2e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "af516227420b3c0413aaba9b51458df190806683c9cf8ae57c720f4707045537", + "namingEvidenceSha256": "dc3dd5eb0ad365182bf881f0849f1d172a80614d9cf0659db8dc90322e4af5c0", + "namingSemanticSha256": "50907912fa19086d66c97840e508bd502344e62d785c34b9c5ce8109b9535cb4" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 360, + 180, + 360 + ], + "beforeValue": 360, + "editedValue": 180, + "restoredValue": 360, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 16, + "vertices": 12, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 56, + "selectedRecords": 1, + "ambiguousResults": 5, + "historySha256": "35b7d1faa5aa355f4da98ab8456b0bb04d0b052cba5d4ce8ff478dd3affa0b53", + "namingEvidenceSha256": "7d1b221f4dc063f109c9d4f53f76f5326f5a8d98371052d278c8b45b86b76311", + "namingSemanticSha256": "17f437ccace7bdf05ded6f1631734b5bc4bf5a66dadaa1a50556488d74d1d244" + }, + "restoredEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 10, + "edges": 24, + "vertices": 16, + "volume": 995.287611, + "area": 606.5663706, + "bounds": [ + -2e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "af516227420b3c0413aaba9b51458df190806683c9cf8ae57c720f4707045537", + "namingEvidenceSha256": "2499ff07c105f037f0cac7ef6cd7939efda7b3cfba22e52e6ecf96d4217077b4", + "namingSemanticSha256": "50907912fa19086d66c97840e508bd502344e62d785c34b9c5ce8109b9535cb4" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->groove", + "phases": { + "initial": { + "namingEvidenceBytes": 4853, + "namingEvidenceSha256": "dc3dd5eb0ad365182bf881f0849f1d172a80614d9cf0659db8dc90322e4af5c0", + "pair": "mirrored->groove", + "shape": { + "area": 606.5663706, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 995.287611 + } + }, + "reopened": { + "namingEvidenceBytes": 4853, + "namingEvidenceSha256": "dc3dd5eb0ad365182bf881f0849f1d172a80614d9cf0659db8dc90322e4af5c0", + "pair": "mirrored->groove", + "shape": { + "area": 606.5663706, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 995.287611 + } + }, + "resaved": { + "namingEvidenceBytes": 4853, + "namingEvidenceSha256": "dc3dd5eb0ad365182bf881f0849f1d172a80614d9cf0659db8dc90322e4af5c0", + "pair": "mirrored->groove", + "shape": { + "area": 606.5663706, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 10, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 995.287611 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-fillet", + "pair": "mirrored->fillet", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "8b476d5bcad90a13024b8c577b0e52fa37e320f434844f141d84baf76072cab7", + "namingSemanticSha256": "ab8a4a93db2be6393938df18e2c28ed2a1d9a7d16ff83e46b6931973c87177ec" + }, + "second": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 56, + "vertices": 24, + "volume": 995.9653557, + "area": 579.2169851, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "9576813a65562d6331b798aff40ee4f5e0b958b1be41b0d61a9a876ce89100f9", + "namingEvidenceSha256": "fdf15e219a7859e64d2a59dea9b2c619ddb37748c96ad01c6b89e5a073c032ac", + "namingSemanticSha256": "7c0f63112076abc5098ad395dc4347826bf3d0f625b138cd2e424450b0b329e9" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "beforeValue": 0.4, + "editedValue": 0.6, + "restoredValue": 0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 56, + "vertices": 24, + "volume": 991.0184753, + "area": 568.6895487, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "9576813a65562d6331b798aff40ee4f5e0b958b1be41b0d61a9a876ce89100f9", + "namingEvidenceSha256": "1504af038bc2d8029b46876d3dcf1f057d7397db9e111b5580d5cccfe623e1ae", + "namingSemanticSha256": "7c0f63112076abc5098ad395dc4347826bf3d0f625b138cd2e424450b0b329e9" + }, + "restoredEvidence": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 56, + "vertices": 24, + "volume": 995.9653557, + "area": 579.2169851, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "9576813a65562d6331b798aff40ee4f5e0b958b1be41b0d61a9a876ce89100f9", + "namingEvidenceSha256": "8815f48a82df31d071bd7f0c9c3906451b40a01b09d57dc251a789285ae2c784", + "namingSemanticSha256": "7c0f63112076abc5098ad395dc4347826bf3d0f625b138cd2e424450b0b329e9" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->fillet", + "phases": { + "initial": { + "namingEvidenceBytes": 14576, + "namingEvidenceSha256": "fdf15e219a7859e64d2a59dea9b2c619ddb37748c96ad01c6b89e5a073c032ac", + "pair": "mirrored->fillet", + "shape": { + "area": 579.2169851, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 995.9653557 + } + }, + "reopened": { + "namingEvidenceBytes": 14576, + "namingEvidenceSha256": "fdf15e219a7859e64d2a59dea9b2c619ddb37748c96ad01c6b89e5a073c032ac", + "pair": "mirrored->fillet", + "shape": { + "area": 579.2169851, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 995.9653557 + } + }, + "resaved": { + "namingEvidenceBytes": 14576, + "namingEvidenceSha256": "fdf15e219a7859e64d2a59dea9b2c619ddb37748c96ad01c6b89e5a073c032ac", + "pair": "mirrored->fillet", + "shape": { + "area": 579.2169851, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 995.9653557 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-chamfer", + "pair": "mirrored->chamfer", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "ac34fdbfe05e1b40990580e6e07fdc2c711ef24c538e5a4019baf66291d5d7c4", + "namingSemanticSha256": "8d53c167fdbb3ca99241120d69736c3349e9032f43eb730fbfcf86f2ef0e8b0d" + }, + "second": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "9576813a65562d6331b798aff40ee4f5e0b958b1be41b0d61a9a876ce89100f9", + "namingEvidenceSha256": "167858fc2d4634c075b0563fdd2a001cbfb946793fd267e1b05268b8dd71677e", + "namingSemanticSha256": "8b980a72cef743417c4b057ab5d4ba0524fe1df5d42925540db4fb9a9679dcef" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "distance", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "beforeValue": 0.4, + "editedValue": 0.6, + "restoredValue": 0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 979.552, + "area": 556.7387245, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "9576813a65562d6331b798aff40ee4f5e0b958b1be41b0d61a9a876ce89100f9", + "namingEvidenceSha256": "83ab18464eedde9a1e06a6233d2917f602ade94cbfd218e54bd1146ec7102df0", + "namingSemanticSha256": "8b980a72cef743417c4b057ab5d4ba0524fe1df5d42925540db4fb9a9679dcef" + }, + "restoredEvidence": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 48, + "vertices": 24, + "volume": 990.7413333, + "area": 571.4001834, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 150, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "9576813a65562d6331b798aff40ee4f5e0b958b1be41b0d61a9a876ce89100f9", + "namingEvidenceSha256": "9661aae1e44d9a4766713dfc763306cb156289ff2d879f64f2221be1d9963eeb", + "namingSemanticSha256": "8b980a72cef743417c4b057ab5d4ba0524fe1df5d42925540db4fb9a9679dcef" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->chamfer", + "phases": { + "initial": { + "namingEvidenceBytes": 14715, + "namingEvidenceSha256": "167858fc2d4634c075b0563fdd2a001cbfb946793fd267e1b05268b8dd71677e", + "pair": "mirrored->chamfer", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "reopened": { + "namingEvidenceBytes": 14715, + "namingEvidenceSha256": "167858fc2d4634c075b0563fdd2a001cbfb946793fd267e1b05268b8dd71677e", + "pair": "mirrored->chamfer", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + }, + "resaved": { + "namingEvidenceBytes": 14715, + "namingEvidenceSha256": "167858fc2d4634c075b0563fdd2a001cbfb946793fd267e1b05268b8dd71677e", + "pair": "mirrored->chamfer", + "shape": { + "area": 571.4001834, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 48, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 990.7413333 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-hole", + "pair": "mirrored->hole", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "c174f8196e78c2651ec2f1b513ccb50eed986aa44c5402ad9de9f23207bc1732", + "namingSemanticSha256": "32b3d0d2d1ad4d29b08cbf80a33ca5126a36ef3a0b4f02bd7d84b363305d85b0" + }, + "second": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "2b9206895321e344232cad8b1e13b31bc58777fb99596254327c7f0d4c381783", + "namingEvidenceSha256": "676552c44f780e5fed1148feee2f26b892f2879868c2e7baa5c5464f77f38357", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 1, + 1.5, + 1 + ], + "beforeValue": 1, + "editedValue": 1.5, + "restoredValue": 1, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 929.3141653, + "area": 680.1106127, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "2b9206895321e344232cad8b1e13b31bc58777fb99596254327c7f0d4c381783", + "namingEvidenceSha256": "605e0c848dda8fcf9326d7995b981fc5c243bb0ddcc2d86aa12d271970633c4a", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + }, + "restoredEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 7, + "edges": 15, + "vertices": 10, + "volume": 968.5840735, + "area": 656.5486678, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "2b9206895321e344232cad8b1e13b31bc58777fb99596254327c7f0d4c381783", + "namingEvidenceSha256": "87f803e3b567df9ddd9b6c989c2bcb19212bd7a0983be7669a026aed60247309", + "namingSemanticSha256": "83842a5b5e9e5640e8546b1d69dfa761d5f731898f1e02eb890d063a7089efaf" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->hole", + "phases": { + "initial": { + "namingEvidenceBytes": 1535, + "namingEvidenceSha256": "676552c44f780e5fed1148feee2f26b892f2879868c2e7baa5c5464f77f38357", + "pair": "mirrored->hole", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "reopened": { + "namingEvidenceBytes": 1535, + "namingEvidenceSha256": "676552c44f780e5fed1148feee2f26b892f2879868c2e7baa5c5464f77f38357", + "pair": "mirrored->hole", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + }, + "resaved": { + "namingEvidenceBytes": 1535, + "namingEvidenceSha256": "676552c44f780e5fed1148feee2f26b892f2879868c2e7baa5c5464f77f38357", + "pair": "mirrored->hole", + "shape": { + "area": 656.5486678, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 15, + "faces": 7, + "solids": 1, + "valid": true, + "vertices": 10, + "volume": 968.5840735 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-draft", + "pair": "mirrored->draft", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "285dda3df32aa7fbc0f40e2699053bb201d50bb11e47352955ec76cbd4d04dec", + "namingSemanticSha256": "8945042a77d58de44b5091d12cf60335131d285688a44b2a2188d25ddf7bacdf" + }, + "second": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "e187fbca3911819da15ecc10aa192f9ce9c1c404f912c1173ab554ee022a8a0f", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 5, + 8, + 5 + ], + "beforeValue": 5, + "editedValue": 8, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 929.7295826, + "area": 572.8745903, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "350466120c5594aedc6faf5a0be8c11194862a65319e0affba8ae161cc4a7c41", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + }, + "restoredEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 956.2556682, + "area": 582.884251, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 5, + "selectedRecords": 5, + "ambiguousResults": 0, + "historySha256": "382606c9d5b8b29b560437d914a6e3b33f1d1a3073cd9c0c3fcb59edc8adaa14", + "namingEvidenceSha256": "185d06fb3e17903564b4cd0f0d441e0c6c4061cfd27a013ffca6f0fe29e05dc8", + "namingSemanticSha256": "9051293e9338c3c07394e762c427bdc308d2c1f6a678e5dee1059cc428e55f9b" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->draft", + "phases": { + "initial": { + "namingEvidenceBytes": 2537, + "namingEvidenceSha256": "e187fbca3911819da15ecc10aa192f9ce9c1c404f912c1173ab554ee022a8a0f", + "pair": "mirrored->draft", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "reopened": { + "namingEvidenceBytes": 2537, + "namingEvidenceSha256": "e187fbca3911819da15ecc10aa192f9ce9c1c404f912c1173ab554ee022a8a0f", + "pair": "mirrored->draft", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + }, + "resaved": { + "namingEvidenceBytes": 2537, + "namingEvidenceSha256": "e187fbca3911819da15ecc10aa192f9ce9c1c404f912c1173ab554ee022a8a0f", + "pair": "mirrored->draft", + "shape": { + "area": 582.884251, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 956.2556682 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-thickness", + "pair": "mirrored->thickness", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "9e7b3a893635d70027ea80cb4a65bbfd59a532fa6b94389c23a76bc722b00e2e", + "namingSemanticSha256": "a4e4c19f4257ea1758e191ffda9d963902e610166b092a9ef72a41fd164d60bc" + }, + "second": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "c5842e0aea2aae1bab3b1fb33a9891a3c7fb3822d1cb60265a27fc257c8b516a", + "namingEvidenceSha256": "42ff0285de0492d56ef55f736e5a35cd4e29183b7270d299b4678ed94da8d80e", + "namingSemanticSha256": "163a673be0fdce9ddced0ca098e724cec43c739f86f05ca0150b22784e64d283" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "offset", + "trajectory": [ + -0.4, + -0.6, + -0.4 + ], + "beforeValue": -0.4, + "editedValue": -0.6, + "restoredValue": -0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 272.064, + "area": 930.88, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "c5842e0aea2aae1bab3b1fb33a9891a3c7fb3822d1cb60265a27fc257c8b516a", + "namingEvidenceSha256": "f7de11de7a27c9d67120e5cd739f8e1c9190f8961b8bd0cc46e71eb0bffd90a0", + "namingSemanticSha256": "163a673be0fdce9ddced0ca098e724cec43c739f86f05ca0150b22784e64d283" + }, + "restoredEvidence": { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 11, + "edges": 24, + "vertices": 16, + "volume": 187.456, + "area": 953.28, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 38, + "selectedRecords": 6, + "ambiguousResults": 8, + "historySha256": "c5842e0aea2aae1bab3b1fb33a9891a3c7fb3822d1cb60265a27fc257c8b516a", + "namingEvidenceSha256": "3bfba95bed1686556479b5d4ce415f95cf67dc19de5b7eb92b1188e6419aff31", + "namingSemanticSha256": "163a673be0fdce9ddced0ca098e724cec43c739f86f05ca0150b22784e64d283" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->thickness", + "phases": { + "initial": { + "namingEvidenceBytes": 8258, + "namingEvidenceSha256": "42ff0285de0492d56ef55f736e5a35cd4e29183b7270d299b4678ed94da8d80e", + "pair": "mirrored->thickness", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "reopened": { + "namingEvidenceBytes": 8258, + "namingEvidenceSha256": "42ff0285de0492d56ef55f736e5a35cd4e29183b7270d299b4678ed94da8d80e", + "pair": "mirrored->thickness", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + }, + "resaved": { + "namingEvidenceBytes": 8258, + "namingEvidenceSha256": "42ff0285de0492d56ef55f736e5a35cd4e29183b7270d299b4678ed94da8d80e", + "pair": "mirrored->thickness", + "shape": { + "area": 953.28, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 24, + "faces": 11, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 187.456 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-polar-pattern", + "pair": "mirrored->polar-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "0375051ae75a5fbe0de52dd29a5a5f10b78b5602322078f114b0f84ea7a2d419", + "namingSemanticSha256": "93b2ed892e4ccdffbfc0b7ee7e4adea2a52eb19db4fc7608d1b5f0dfc4142fb4" + }, + "second": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "41cfb0e4b4a57f3b7e781d26acfd40b4d8f74b5223bf50045f040ba44551f9aa", + "namingEvidenceSha256": "d24473db6bed23e42b242c4bfd21dc335e1a8e13e981212a5018d805a79b604f", + "namingSemanticSha256": "ea4f67ec10bc8d517687344dbc75f559ac0e7a9156c6158fa44327bcf3037f52" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 30, + 45, + 30 + ], + "beforeValue": 30, + "editedValue": 45, + "restoredValue": 30, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1585.7864376, + "area": 834.3145751, + "bounds": [ + -7.071068, + -1e-7, + -1e-7, + 10.0000001, + 14.1421358, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "41cfb0e4b4a57f3b7e781d26acfd40b4d8f74b5223bf50045f040ba44551f9aa", + "namingEvidenceSha256": "66cd988de719d89dbd0f15e8e8d9648a46310ea290cc4b02411fa29d4973dc7a", + "namingSemanticSha256": "ea4f67ec10bc8d517687344dbc75f559ac0e7a9156c6158fa44327bcf3037f52" + }, + "restoredEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 12, + "edges": 26, + "vertices": 16, + "volume": 1422.6497308, + "area": 769.0598923, + "bounds": [ + -5.0000001, + -1e-7, + -1e-7, + 10.0000001, + 13.6602542, + 10.0000001 + ] + }, + "historyRecords": 78, + "selectedRecords": 6, + "ambiguousResults": 11, + "historySha256": "41cfb0e4b4a57f3b7e781d26acfd40b4d8f74b5223bf50045f040ba44551f9aa", + "namingEvidenceSha256": "89c4e83217eb76bf3e77baed42449703beb71f01751d9c2101c7a91d469ac38b", + "namingSemanticSha256": "ea4f67ec10bc8d517687344dbc75f559ac0e7a9156c6158fa44327bcf3037f52" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->polar-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 8410, + "namingEvidenceSha256": "d24473db6bed23e42b242c4bfd21dc335e1a8e13e981212a5018d805a79b604f", + "pair": "mirrored->polar-pattern", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "reopened": { + "namingEvidenceBytes": 8410, + "namingEvidenceSha256": "d24473db6bed23e42b242c4bfd21dc335e1a8e13e981212a5018d805a79b604f", + "pair": "mirrored->polar-pattern", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + }, + "resaved": { + "namingEvidenceBytes": 8410, + "namingEvidenceSha256": "d24473db6bed23e42b242c4bfd21dc335e1a8e13e981212a5018d805a79b604f", + "pair": "mirrored->polar-pattern", + "shape": { + "area": 769.0598923, + "bounds": [ + -5, + 0, + 0, + 10, + 13.660254, + 10 + ], + "edges": 26, + "faces": 12, + "solids": 1, + "valid": true, + "vertices": 16, + "volume": 1422.6497308 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-mirrored", + "pair": "mirrored->mirrored", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "b265367205e00e10e8e4c57e0435ee0213afc82b7f349799b15f4bce2fe59efc", + "namingSemanticSha256": "f32475eeea91a3ad8e225a581f2e09ee02776731b2e30df71466b4e2f737815c" + }, + "second": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "035ed9c077de37fee2c44a29125bd9b314bc6f1679dc582e108fdae2197868b4", + "namingEvidenceSha256": "a4b701c6a1294efabfc266992cc0ae61f2c00c76d2583d0ab08356693fe487f1", + "namingSemanticSha256": "f9ca43fdc181b6927f2e79a4b5fff8ea8d05d9abc5e746b49edb1446ef4fe6f0" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "planeOriginX", + "trajectory": [ + 5, + 6, + 5 + ], + "beforeValue": 5, + "editedValue": 6, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 14, + "edges": 28, + "vertices": 16, + "volume": 1200, + "area": 680, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 12.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 66, + "selectedRecords": 8, + "ambiguousResults": 12, + "historySha256": "53995cbe48b0a963a304dbafb66586a90b718d8ecf6fedd75b27ad63c699e88a", + "namingEvidenceSha256": "3a5ac19ceb00fd3c3c19d6c40a3b1a676aaec6506b8cd7f69811aecfefbadd8e", + "namingSemanticSha256": "0bfceb55f5075a2d911b1f8d2ade861fc405c6223d5f1b3aa8598fd46d2876c3" + }, + "restoredEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "035ed9c077de37fee2c44a29125bd9b314bc6f1679dc582e108fdae2197868b4", + "namingEvidenceSha256": "91b3f095538cb97c7bdb72a89b9d1586fc196b817886344ef96d416455feccb3", + "namingSemanticSha256": "f9ca43fdc181b6927f2e79a4b5fff8ea8d05d9abc5e746b49edb1446ef4fe6f0" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->mirrored", + "phases": { + "initial": { + "namingEvidenceBytes": 14179, + "namingEvidenceSha256": "a4b701c6a1294efabfc266992cc0ae61f2c00c76d2583d0ab08356693fe487f1", + "pair": "mirrored->mirrored", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "reopened": { + "namingEvidenceBytes": 14179, + "namingEvidenceSha256": "a4b701c6a1294efabfc266992cc0ae61f2c00c76d2583d0ab08356693fe487f1", + "pair": "mirrored->mirrored", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + }, + "resaved": { + "namingEvidenceBytes": 14179, + "namingEvidenceSha256": "a4b701c6a1294efabfc266992cc0ae61f2c00c76d2583d0ab08356693fe487f1", + "pair": "mirrored->mirrored", + "shape": { + "area": 600, + "bounds": [ + 0, + 0, + 0, + 10, + 10, + 10 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 1000 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-mirrored-multi-transform", + "pair": "mirrored->multi-transform", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1000, + "area": 600, + "bounds": [ + -1e-7, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 156, + "selectedRecords": 6, + "ambiguousResults": 20, + "historySha256": "dd3cfb5dd8f9441de2eb6542b6de56eb28929c1b1aa73620dcbc86776e887244", + "namingEvidenceSha256": "e560dace68e2c6931a7e825f531b449420123b5e39fb2617e89b2ed943e8efd0", + "namingSemanticSha256": "269685d2439e2c453b74c2bec4f3be3a2aa9bbb8bb60f4f72b5fc2ae4ab913c3" + }, + "second": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "1f583a142f533b77bc12e823635d685a8be2da31a79b47cbf2bbc216cba01549", + "namingEvidenceSha256": "7daca50c6b9e477cd6883ea88974fab6509e2b4cee90c335a43746de2aaf5436", + "namingSemanticSha256": "997320143ffd4d27861c1e133824f8b8d3aed8f86b8a4fe90590db36f07b1b9c" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "multiTranslationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2800, + "area": 1320, + "bounds": [ + -9.0000001, + -1e-7, + -1e-7, + 19.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "1f583a142f533b77bc12e823635d685a8be2da31a79b47cbf2bbc216cba01549", + "namingEvidenceSha256": "35e6b5e27a5883c059c19c8d7c11831a336f5f60ef931f9a125d75c131f9bbf2", + "namingSemanticSha256": "997320143ffd4d27861c1e133824f8b8d3aed8f86b8a4fe90590db36f07b1b9c" + }, + "restoredEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "1f583a142f533b77bc12e823635d685a8be2da31a79b47cbf2bbc216cba01549", + "namingEvidenceSha256": "d98cae2c5bdfe0dc2a2e3431381584586984694e6fb70d26d5522ec447d5b0cb", + "namingSemanticSha256": "997320143ffd4d27861c1e133824f8b8d3aed8f86b8a4fe90590db36f07b1b9c" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "mirrored->multi-transform", + "phases": { + "initial": { + "namingEvidenceBytes": 59585, + "namingEvidenceSha256": "7daca50c6b9e477cd6883ea88974fab6509e2b4cee90c335a43746de2aaf5436", + "pair": "mirrored->multi-transform", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "reopened": { + "namingEvidenceBytes": 59585, + "namingEvidenceSha256": "7daca50c6b9e477cd6883ea88974fab6509e2b4cee90c335a43746de2aaf5436", + "pair": "mirrored->multi-transform", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "resaved": { + "namingEvidenceBytes": 59585, + "namingEvidenceSha256": "7daca50c6b9e477cd6883ea88974fab6509e2b4cee90c335a43746de2aaf5436", + "pair": "mirrored->multi-transform", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-fuse", + "pair": "multi-transform->fuse", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "3514593cd72216287a181cf91c3d1fcfdd65b37e67890ea5b1db17fae139d77e", + "namingSemanticSha256": "af3455b333f9b895dcfb5fe2de8f671e5c9525102648e00306568d214a0ba5cf" + }, + "second": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 61, + "vertices": 34, + "volume": 2675, + "area": 1300, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 21.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "f2793eeacc4195cc5f42dfefa7279353099d5539daea8896bde4613c2047b6d2", + "namingEvidenceSha256": "89d7ded3221bde6980300dff512b1ae7b6b1f8a54149aaf69744f6d2f5633503", + "namingSemanticSha256": "d1725ff7717fef6a2196cc18bcaaeafe8157eb587a2c83d391b4c2fcfd0077ad" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "toolOffsetX", + "trajectory": [ + 16, + 15, + 16 + ], + "beforeValue": 16, + "editedValue": 15, + "restoredValue": 16, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 61, + "vertices": 34, + "volume": 2650, + "area": 1280, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 20.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "f2793eeacc4195cc5f42dfefa7279353099d5539daea8896bde4613c2047b6d2", + "namingEvidenceSha256": "7cd30b64d47fbfea0fa013e0b575b13a1a4e5dc823f6076e32659e78369e4e50", + "namingSemanticSha256": "d1725ff7717fef6a2196cc18bcaaeafe8157eb587a2c83d391b4c2fcfd0077ad" + }, + "restoredEvidence": { + "operation": "fuse", + "builder": "BRepAlgoAPI_Fuse", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 29, + "edges": 61, + "vertices": 34, + "volume": 2675, + "area": 1300, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 21.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 52, + "selectedRecords": 7, + "ambiguousResults": 16, + "historySha256": "f2793eeacc4195cc5f42dfefa7279353099d5539daea8896bde4613c2047b6d2", + "namingEvidenceSha256": "63079fe9b0c6a13380afee6397b16c5715f8786b1db7e0b25d25ee33dd4e000d", + "namingSemanticSha256": "d1725ff7717fef6a2196cc18bcaaeafe8157eb587a2c83d391b4c2fcfd0077ad" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->fuse", + "phases": { + "initial": { + "namingEvidenceBytes": 9340, + "namingEvidenceSha256": "89d7ded3221bde6980300dff512b1ae7b6b1f8a54149aaf69744f6d2f5633503", + "pair": "multi-transform->fuse", + "shape": { + "area": 1300, + "bounds": [ + -8, + 0, + 0, + 21, + 10, + 10 + ], + "edges": 61, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 34, + "volume": 2675 + } + }, + "reopened": { + "namingEvidenceBytes": 9340, + "namingEvidenceSha256": "89d7ded3221bde6980300dff512b1ae7b6b1f8a54149aaf69744f6d2f5633503", + "pair": "multi-transform->fuse", + "shape": { + "area": 1300, + "bounds": [ + -8, + 0, + 0, + 21, + 10, + 10 + ], + "edges": 61, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 34, + "volume": 2675 + } + }, + "resaved": { + "namingEvidenceBytes": 9340, + "namingEvidenceSha256": "89d7ded3221bde6980300dff512b1ae7b6b1f8a54149aaf69744f6d2f5633503", + "pair": "multi-transform->fuse", + "shape": { + "area": 1300, + "bounds": [ + -8, + 0, + 0, + 21, + 10, + 10 + ], + "edges": 61, + "faces": 29, + "solids": 1, + "valid": true, + "vertices": 34, + "volume": 2675 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-cut", + "pair": "multi-transform->cut", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "ed19c437e52fcc46822c45fd72395eb8e3a42005648edaaae58536a241b3f146", + "namingSemanticSha256": "3d2dbb028d94e6ea91b799cd8be3165a836202d94b214335d84272a3d85cb6d1" + }, + "second": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 55, + "vertices": 31, + "volume": 2536, + "area": 1272, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 47, + "selectedRecords": 5, + "ambiguousResults": 11, + "historySha256": "86cd40665beafe8b5b955284ea85995e9609aec4a3abd648ba03012b1dadd1ad", + "namingEvidenceSha256": "d9529dc97da11d55521d5d917dbd1466b3b8dd085e1d373ffe04b823fad19414", + "namingSemanticSha256": "69d1359acc7dbbc608e21d4e11708cdf192d27a4ac18ffff435b078caa1ed5db" + }, + "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": 26, + "edges": 55, + "vertices": 31, + "volume": 2573, + "area": 1258, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 47, + "selectedRecords": 5, + "ambiguousResults": 11, + "historySha256": "86cd40665beafe8b5b955284ea85995e9609aec4a3abd648ba03012b1dadd1ad", + "namingEvidenceSha256": "2865d95396a6dad8e1dce1d6d421bc5e67c681be19eb7e203a285589f319b4ac", + "namingSemanticSha256": "69d1359acc7dbbc608e21d4e11708cdf192d27a4ac18ffff435b078caa1ed5db" + }, + "restoredEvidence": { + "operation": "cut", + "builder": "BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 55, + "vertices": 31, + "volume": 2536, + "area": 1272, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 47, + "selectedRecords": 5, + "ambiguousResults": 11, + "historySha256": "86cd40665beafe8b5b955284ea85995e9609aec4a3abd648ba03012b1dadd1ad", + "namingEvidenceSha256": "b672643e84cdc939d1c2eac6267ff02e2b0811b06f186628e44a79eb10f37d01", + "namingSemanticSha256": "69d1359acc7dbbc608e21d4e11708cdf192d27a4ac18ffff435b078caa1ed5db" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->cut", + "phases": { + "initial": { + "namingEvidenceBytes": 8587, + "namingEvidenceSha256": "d9529dc97da11d55521d5d917dbd1466b3b8dd085e1d373ffe04b823fad19414", + "pair": "multi-transform->cut", + "shape": { + "area": 1272, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 55, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 31, + "volume": 2536 + } + }, + "reopened": { + "namingEvidenceBytes": 8587, + "namingEvidenceSha256": "d9529dc97da11d55521d5d917dbd1466b3b8dd085e1d373ffe04b823fad19414", + "pair": "multi-transform->cut", + "shape": { + "area": 1272, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 55, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 31, + "volume": 2536 + } + }, + "resaved": { + "namingEvidenceBytes": 8587, + "namingEvidenceSha256": "d9529dc97da11d55521d5d917dbd1466b3b8dd085e1d373ffe04b823fad19414", + "pair": "multi-transform->cut", + "shape": { + "area": 1272, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 55, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 31, + "volume": 2536 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-common", + "pair": "multi-transform->common", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "1be5a5876a3a26d6d948dd85411a596bac4563b0865e97178df3c3fd9bd408ac", + "namingSemanticSha256": "1f0d54e735671a96b248487b47035c85f281de38774bff422e87d89b91adfda2" + }, + "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": 125, + "area": 150, + "bounds": [ + 9.9999999, + -1e-7, + -1e-7, + 15.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 309, + "selectedRecords": 1, + "ambiguousResults": 10, + "historySha256": "8354ec1e0123ef2aa72cc62a02ed9993eccdd589a690cbefb1de5dc08430dd35", + "namingEvidenceSha256": "09387999ac8c7864bb0e479f9e3b1a1116185ec898ba93c8b0842f3cec7d36be", + "namingSemanticSha256": "7565f06938e39fef7b40fdde587b24596964638b94fc5818cc0ba02928e419a3" + }, + "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": 8, + "edges": 17, + "vertices": 11, + "volume": 125, + "area": 150, + "bounds": [ + 8.9999999, + -1e-7, + -1e-7, + 14.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 304, + "selectedRecords": 2, + "ambiguousResults": 16, + "historySha256": "60f4ac8b0dbd565a88c26436823d16939cb259d41422856a66db3e089e68a5db", + "namingEvidenceSha256": "d113d2b5e619ba694918c715535a308b14afb29a9bb5f77d9d0ac675450ba58c", + "namingSemanticSha256": "02b2acd0e1a744a68a550f932c1e2d1e9d8824ac75beab23f037578ee65267d2" + }, + "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": 125, + "area": 150, + "bounds": [ + 9.9999999, + -1e-7, + -1e-7, + 15.0000001, + 5.0000001, + 5.0000001 + ] + }, + "historyRecords": 309, + "selectedRecords": 1, + "ambiguousResults": 10, + "historySha256": "8354ec1e0123ef2aa72cc62a02ed9993eccdd589a690cbefb1de5dc08430dd35", + "namingEvidenceSha256": "96c6500ee6dda0e2f267ca3c4e89fc0896510d876909a9c669f0f169ac9ace88", + "namingSemanticSha256": "7565f06938e39fef7b40fdde587b24596964638b94fc5818cc0ba02928e419a3" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->common", + "phases": { + "initial": { + "namingEvidenceBytes": 7243, + "namingEvidenceSha256": "09387999ac8c7864bb0e479f9e3b1a1116185ec898ba93c8b0842f3cec7d36be", + "pair": "multi-transform->common", + "shape": { + "area": 150, + "bounds": [ + 10, + 0, + 0, + 15, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 125 + } + }, + "reopened": { + "namingEvidenceBytes": 7243, + "namingEvidenceSha256": "09387999ac8c7864bb0e479f9e3b1a1116185ec898ba93c8b0842f3cec7d36be", + "pair": "multi-transform->common", + "shape": { + "area": 150, + "bounds": [ + 10, + 0, + 0, + 15, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 125 + } + }, + "resaved": { + "namingEvidenceBytes": 7243, + "namingEvidenceSha256": "09387999ac8c7864bb0e479f9e3b1a1116185ec898ba93c8b0842f3cec7d36be", + "pair": "multi-transform->common", + "shape": { + "area": 150, + "bounds": [ + 10, + 0, + 0, + 15, + 5, + 5 + ], + "edges": 12, + "faces": 6, + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 125 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-rotate", + "pair": "multi-transform->rotate", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "e715edc9e408068374129292bf7a606431e3f20309c6137641fef3f5437d9b32", + "namingSemanticSha256": "02af293d77e711253c9fcd7de313e4eca78c6766b16280e199b39c3d2e843ba4" + }, + "second": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -10.3155972, + -2.0705525, + -1e-7, + 17.386665, + 14.3180012, + 10.0000001 + ] + }, + "historyRecords": 286, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "dd5f49cbb351129f5263f6dec015801fd64e9386dd34f9fc24de3cd639835597", + "namingEvidenceSha256": "6309013fed1ba1e98e9f0181373ec3ec02ae04e6be66ed1c6dcd19789ecbfbc5", + "namingSemanticSha256": "d6244e895fc441127bd41617b1ed35666b5734d0c2d7e960c1cfb19576996e10" + }, + "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": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -11.2178707, + -3.0614676, + -1e-7, + 16.6298317, + 16.1270972, + 10.0000001 + ] + }, + "historyRecords": 286, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "dd5f49cbb351129f5263f6dec015801fd64e9386dd34f9fc24de3cd639835597", + "namingEvidenceSha256": "72cba338c714ec3029884e198126c2e2c30ff74ebc3bf002d6f3c5bed619c923", + "namingSemanticSha256": "d6244e895fc441127bd41617b1ed35666b5734d0c2d7e960c1cfb19576996e10" + }, + "restoredEvidence": { + "operation": "rotate", + "builder": "BRepBuilderAPI_Transform", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -10.3155972, + -2.0705525, + -1e-7, + 17.386665, + 14.3180012, + 10.0000001 + ] + }, + "historyRecords": 286, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "dd5f49cbb351129f5263f6dec015801fd64e9386dd34f9fc24de3cd639835597", + "namingEvidenceSha256": "5af3033d2480162daa6854d3d44ce069550626f658ce5d1997b9321356f7ad4e", + "namingSemanticSha256": "d6244e895fc441127bd41617b1ed35666b5734d0c2d7e960c1cfb19576996e10" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->rotate", + "phases": { + "initial": { + "namingEvidenceBytes": 53982, + "namingEvidenceSha256": "6309013fed1ba1e98e9f0181373ec3ec02ae04e6be66ed1c6dcd19789ecbfbc5", + "pair": "multi-transform->rotate", + "shape": { + "area": 1240, + "bounds": [ + -10.3155971, + -2.0705524, + 0, + 17.3866649, + 14.3180011, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "reopened": { + "namingEvidenceBytes": 53982, + "namingEvidenceSha256": "6309013fed1ba1e98e9f0181373ec3ec02ae04e6be66ed1c6dcd19789ecbfbc5", + "pair": "multi-transform->rotate", + "shape": { + "area": 1240, + "bounds": [ + -10.3155971, + -2.0705524, + 0, + 17.3866649, + 14.3180011, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "resaved": { + "namingEvidenceBytes": 53982, + "namingEvidenceSha256": "6309013fed1ba1e98e9f0181373ec3ec02ae04e6be66ed1c6dcd19789ecbfbc5", + "pair": "multi-transform->rotate", + "shape": { + "area": 1240, + "bounds": [ + -10.3155971, + -2.0705524, + 0, + 17.3866649, + 14.3180011, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-pad", + "pair": "multi-transform->pad", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "bd6f06e1eee44fd27ab7068d7f9f2f2d6c7722b11d9dfba8e7ecfe28bed47451", + "namingSemanticSha256": "cfbec6dde4e54ae04c13206e5a15fca14c2739403716d21bd6ec9d3a2e2acad8" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "length", + "trajectory": [ + 5, + 7.5, + 5 + ], + "stable": true, + "attempts": [ + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 7.5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "pad", + "builder": "BRepPrimAPI_MakePrism", + "inputCount": 1, + "parameter": "length", + "parameterValue": 5, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "nativeTypeId": "PartDesign::Pad", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Body", + "typeId": "PartDesign::Body" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + }, + { + "name": "PairResult", + "typeId": "PartDesign::Pad" + } + ], + "parameter": { + "name": "length", + "value": 5 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "FeatureExtrusion: Length: Could not extrude the sketch!" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "PartDesign::Pad", + "operation": "pad", + "pair": "multi-transform->pad", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-multi-transform-pocket", + "pair": "multi-transform->pocket", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "44e9014b5430966056979e81f5df5ededeaaaac1db478bd8f619f6c9fc915cd6", + "namingSemanticSha256": "884c31dace01e47eab222fb09a4ecc2e51c23cf3688e6514139bfea7972a66af" + }, + "second": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 54, + "vertices": 30, + "volume": 2570, + "area": 1270, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 74, + "selectedRecords": 8, + "ambiguousResults": 14, + "historySha256": "ee7d4348c13ae2c185cb6791121140045e18c1ad6db4644dce47d73103695911", + "namingEvidenceSha256": "54344de3b84e60e8db583c8564c35de7d28da97c1ae8b127b687cc8e00089a56", + "namingSemanticSha256": "e7d4094d05fd6494197877863e8882d095b6d5eaae6bb16fe2d5e9f5da5e5799" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "length", + "trajectory": [ + 5, + 4, + 5 + ], + "beforeValue": 5, + "editedValue": 4, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 54, + "vertices": 30, + "volume": 2576, + "area": 1264, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 74, + "selectedRecords": 8, + "ambiguousResults": 14, + "historySha256": "ee7d4348c13ae2c185cb6791121140045e18c1ad6db4644dce47d73103695911", + "namingEvidenceSha256": "c9083fe1ce37e4b7af2ba7dd1ed88f389c80358041f943a8301aaa4a25270df8", + "namingSemanticSha256": "e7d4094d05fd6494197877863e8882d095b6d5eaae6bb16fe2d5e9f5da5e5799" + }, + "restoredEvidence": { + "operation": "pocket", + "builder": "BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 54, + "vertices": 30, + "volume": 2570, + "area": 1270, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 74, + "selectedRecords": 8, + "ambiguousResults": 14, + "historySha256": "ee7d4348c13ae2c185cb6791121140045e18c1ad6db4644dce47d73103695911", + "namingEvidenceSha256": "895139872798c073c6d5116b69fa5f0e1062f0e0215302d1ecd91878e59898ad", + "namingSemanticSha256": "e7d4094d05fd6494197877863e8882d095b6d5eaae6bb16fe2d5e9f5da5e5799" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->pocket", + "phases": { + "initial": { + "namingEvidenceBytes": 14127, + "namingEvidenceSha256": "54344de3b84e60e8db583c8564c35de7d28da97c1ae8b127b687cc8e00089a56", + "pair": "multi-transform->pocket", + "shape": { + "area": 1270, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 54, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 30, + "volume": 2570 + } + }, + "reopened": { + "namingEvidenceBytes": 14127, + "namingEvidenceSha256": "54344de3b84e60e8db583c8564c35de7d28da97c1ae8b127b687cc8e00089a56", + "pair": "multi-transform->pocket", + "shape": { + "area": 1270, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 54, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 30, + "volume": 2570 + } + }, + "resaved": { + "namingEvidenceBytes": 14127, + "namingEvidenceSha256": "54344de3b84e60e8db583c8564c35de7d28da97c1ae8b127b687cc8e00089a56", + "pair": "multi-transform->pocket", + "shape": { + "area": 1270, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 54, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 30, + "volume": 2570 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-loft", + "pair": "multi-transform->loft", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "ce8795e885277c821f74e0f86af933c3e852a0e386dc950a24aaea18ff9256cf", + "namingSemanticSha256": "a0a6cda5edc1e629da7ed536c00b6c5c3672e8f6d6d0134aec195e63b0e9592f" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "ruled", + "trajectory": [ + false, + true, + false + ], + "kernelAttempts": [ + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1150, + "area": 758.6473016, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": true, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1150, + "area": 758.6473016, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + }, + { + "operation": "loft", + "builder": "BRepOffsetAPI_ThruSections", + "inputCount": 2, + "parameter": "ruled", + "parameterValue": false, + "runtime": "occt-native", + "outcome": "accepted", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 1150, + "area": 758.6473016, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 10.0000001, + 10.0000001, + 15.0000001 + ] + }, + "historyRecords": 24, + "historySha256": "9f0ec53f6c7b6a6704cd926e6d16c24c51625ef328c2d89275f86d0ccda2ace7", + "authority": "kernel-superset-only" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + } + ] + }, + "inputShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "nativeTypeId": "Part::Loft", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Section", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Loft" + } + ], + "parameter": { + "name": "ruled", + "value": false + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Profile shape is not a single vertex, edge, wire nor face." + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Loft", + "operation": "loft", + "pair": "multi-transform->loft", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-multi-transform-pipe", + "pair": "multi-transform->pipe", + "classification": "rejected", + "reasonCode": "freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "0b0fc783c03e775533479f17b1732da37a8accbaf916e06a1a4da23487523c19", + "namingSemanticSha256": "ae4a32feb0cd34a005a15af808813e87a335a34dd3dfe756f52ba51c42e4bdca" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "freecad-document", + "parameter": "spineLength", + "trajectory": [ + 15, + 12, + 15 + ], + "kernelAttempts": [ + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + -8.0000001, + -1e-7, + -15.0000001, + -7.9999999, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 12, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 440, + "bounds": [ + -8.0000001, + -1e-7, + -12.0000001, + -7.9999999, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + }, + { + "operation": "pipe", + "builder": "BRepOffsetAPI_MakePipe", + "inputCount": 2, + "parameter": "spineLength", + "parameterValue": 15, + "runtime": "occt-native", + "outcome": "invalid-result", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": false, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": false, + "solids": 1, + "faces": 6, + "edges": 12, + "vertices": 8, + "volume": 0, + "area": 500, + "bounds": [ + -8.0000001, + -1e-7, + -15.0000001, + -7.9999999, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 28, + "historySha256": "0b29085cd086854553f7e799c787527dddb9e1e7e798579dbb78cb09bb5d9d7c", + "authority": "kernel-invalid-result" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "sections": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "spine": { + "name": "Spine", + "subelements": [], + "typeId": "Part::Feature" + } + }, + "inputShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "nativeTypeId": "Part::Sweep", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "Spine", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Sweep" + } + ], + "parameter": { + "name": "spineLength", + "value": 15 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "A fatal error occurred when making the sweep" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Sweep", + "operation": "pipe", + "pair": "multi-transform->pipe", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-multi-transform-revolution", + "pair": "multi-transform->revolution", + "classification": "rejected", + "reasonCode": "native-builder-and-freecad-profile-reject-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "ddb74d4b711d2218f285d808c0d36f5a2cb04bfcbd098db92df91bba2332f51d", + "namingSemanticSha256": "b9aac3413b2deef4b0eb2af3806365409f1f592092ae5a853770ff13bd774bd2" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-builder", + "parameter": "angle", + "trajectory": [ + 360, + 270, + 360 + ], + "stable": true, + "attempts": [ + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 270, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + }, + { + "operation": "revolution", + "builder": "BRepPrimAPI_MakeRevol", + "inputCount": 1, + "parameter": "angle", + "parameterValue": 360, + "runtime": "occt-native", + "outcome": "rejected", + "resultProduced": false, + "shapeProduced": false, + "historyProduced": false, + "rejectionStage": "builder", + "exceptionTransport": "emscripten-cpp-exception", + "thrownType": "number" + } + ], + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": true, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": true, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "nativeTypeId": "Part::Revolution", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Revolution" + } + ], + "parameter": { + "name": "angle", + "value": 360 + }, + "recomputeResult": true, + "shapeNull": true, + "shapeValid": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "BRep_API: command not done" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Revolution", + "operation": "revolution", + "pair": "multi-transform->revolution", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "sourceBrepReserialized": false, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-multi-transform-groove", + "pair": "multi-transform->groove", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "dbe4d2b4078ce9231f6d9a912960e17174bbd51e7affd5f969759e10b5cf52cc", + "namingSemanticSha256": "4bf1057816b2c0aa08fd45e6b500fb044acb81cc7f383b8001829c013ff6d601" + }, + "second": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 56, + "vertices": 32, + "volume": 2590.575222, + "area": 1259.1327412, + "bounds": [ + -8.0000001, + -1e-7, + -2e-7, + 18.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "8e1162f40aaac89109d9e9cbe212888f98ef67bef54569c2781ed4da7725410e", + "namingEvidenceSha256": "7e1cca710b45fdbf923de232e6c2585589252218b352b19ca613505088d2c671", + "namingSemanticSha256": "be789296b9332ef3fec739e4e0d515ff5191f76c173fcd1f452bc8415bf3825d" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 360, + 180, + 360 + ], + "beforeValue": 360, + "editedValue": 180, + "restoredValue": 360, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 24, + "edges": 52, + "vertices": 32, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 34, + "selectedRecords": 2, + "ambiguousResults": 10, + "historySha256": "7f2cc890aa04821aa80c567cac16675793e6d70b0fbca18bd801bcc84c2f12bf", + "namingEvidenceSha256": "0da2c9bcda3f9a443341886a68f892da6233b7edeb4a26cb34b02ebafd938dfa", + "namingSemanticSha256": "6758827c064a22bf043c931481a8ef7180f3dc599bb2526a69c86407fe3f7884" + }, + "restoredEvidence": { + "operation": "groove", + "builder": "BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut", + "inputCount": 2, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 26, + "edges": 56, + "vertices": 32, + "volume": 2590.575222, + "area": 1259.1327412, + "bounds": [ + -8.0000001, + -1e-7, + -2e-7, + 18.0000002, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 18, + "selectedRecords": 6, + "ambiguousResults": 6, + "historySha256": "8e1162f40aaac89109d9e9cbe212888f98ef67bef54569c2781ed4da7725410e", + "namingEvidenceSha256": "a7927c361acb122cfaf6fd17fe38e303dc6e0c0cdbf6ea41e9b229976eca03b0", + "namingSemanticSha256": "be789296b9332ef3fec739e4e0d515ff5191f76c173fcd1f452bc8415bf3825d" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->groove", + "phases": { + "initial": { + "namingEvidenceBytes": 5314, + "namingEvidenceSha256": "7e1cca710b45fdbf923de232e6c2585589252218b352b19ca613505088d2c671", + "pair": "multi-transform->groove", + "shape": { + "area": 1259.1327412, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 2590.575222 + } + }, + "reopened": { + "namingEvidenceBytes": 5314, + "namingEvidenceSha256": "7e1cca710b45fdbf923de232e6c2585589252218b352b19ca613505088d2c671", + "pair": "multi-transform->groove", + "shape": { + "area": 1259.1327412, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 2590.575222 + } + }, + "resaved": { + "namingEvidenceBytes": 5314, + "namingEvidenceSha256": "7e1cca710b45fdbf923de232e6c2585589252218b352b19ca613505088d2c671", + "pair": "multi-transform->groove", + "shape": { + "area": 1259.1327412, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 56, + "faces": 26, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 2590.575222 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-fillet", + "pair": "multi-transform->fillet", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "760f6f600198a15c0383735f052822a81528459e595d20c9c636cfc97dc39a27", + "namingSemanticSha256": "98411e9b4e239b0c252cddc281b96a6ff154b50360cfcc2d6df1114938ce600f" + }, + "second": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 58, + "edges": 120, + "vertices": 56, + "volume": 2593.7678329, + "area": 1208.2293711, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 390, + "selectedRecords": 22, + "ambiguousResults": 52, + "historySha256": "d5f2511d232804f6c627911fcf2542b7aa62ad9605ef4c49a3cb5b9c490a4718", + "namingEvidenceSha256": "9a6a00ac52f1e5e434e252af634c538d82da29b577fea1769a7182d600c18c47", + "namingSemanticSha256": "e070a7fe8cb86dc2bc0566349001c1a4576e290164bfd836bd114d423f831a9e" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "beforeValue": 0.4, + "editedValue": 0.6, + "restoredValue": 0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 58, + "edges": 120, + "vertices": 56, + "volume": 2586.0740489, + "area": 1192.2081276, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 390, + "selectedRecords": 22, + "ambiguousResults": 52, + "historySha256": "d5f2511d232804f6c627911fcf2542b7aa62ad9605ef4c49a3cb5b9c490a4718", + "namingEvidenceSha256": "940e959cce876baad8bf5c774ff3f03e15fa6871a16e377df259701b3d673db1", + "namingSemanticSha256": "e070a7fe8cb86dc2bc0566349001c1a4576e290164bfd836bd114d423f831a9e" + }, + "restoredEvidence": { + "operation": "fillet", + "builder": "BRepFilletAPI_MakeFillet", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 58, + "edges": 120, + "vertices": 56, + "volume": 2593.7678329, + "area": 1208.2293711, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 390, + "selectedRecords": 22, + "ambiguousResults": 52, + "historySha256": "d5f2511d232804f6c627911fcf2542b7aa62ad9605ef4c49a3cb5b9c490a4718", + "namingEvidenceSha256": "f7dbecbf760abf11cc8c6d4a3606d6fc0f3be7fe14cbbceb6d0af4f2892ea1ac", + "namingSemanticSha256": "e070a7fe8cb86dc2bc0566349001c1a4576e290164bfd836bd114d423f831a9e" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->fillet", + "phases": { + "initial": { + "namingEvidenceBytes": 34178, + "namingEvidenceSha256": "9a6a00ac52f1e5e434e252af634c538d82da29b577fea1769a7182d600c18c47", + "pair": "multi-transform->fillet", + "shape": { + "area": 1208.2293711, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 120, + "faces": 58, + "solids": 1, + "valid": true, + "vertices": 56, + "volume": 2593.7678329 + } + }, + "reopened": { + "namingEvidenceBytes": 34178, + "namingEvidenceSha256": "9a6a00ac52f1e5e434e252af634c538d82da29b577fea1769a7182d600c18c47", + "pair": "multi-transform->fillet", + "shape": { + "area": 1208.2293711, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 120, + "faces": 58, + "solids": 1, + "valid": true, + "vertices": 56, + "volume": 2593.7678329 + } + }, + "resaved": { + "namingEvidenceBytes": 34178, + "namingEvidenceSha256": "9a6a00ac52f1e5e434e252af634c538d82da29b577fea1769a7182d600c18c47", + "pair": "multi-transform->fillet", + "shape": { + "area": 1208.2293711, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 120, + "faces": 58, + "solids": 1, + "valid": true, + "vertices": 56, + "volume": 2593.7678329 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-chamfer", + "pair": "multi-transform->chamfer", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "2a5528164b76aafe40b4429ebe148dea9bc2b9fa1a50b07474cbad14519a95ae", + "namingSemanticSha256": "86e28e5a195eea83b1693f5ab74d33d5a9883b9bd7072aaf552853e0e1120ea2" + }, + "second": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 58, + "edges": 112, + "vertices": 56, + "volume": 2585.6213333, + "area": 1196.4040506, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 390, + "selectedRecords": 22, + "ambiguousResults": 52, + "historySha256": "1d2211114ac6eda1b1fb29b62592ea52ca02949bb633761a3b79d834b3a9d275", + "namingEvidenceSha256": "0e83ffacf7be22a28281e1001e1ca145e7c4d706bae45f572b9491b8834ebf04", + "namingSemanticSha256": "bbeef16c49360df69947335d0764d9740e1d1ae8c42cbe015fda6342d72e0483" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "distance", + "trajectory": [ + 0.4, + 0.6, + 0.4 + ], + "beforeValue": 0.4, + "editedValue": 0.6, + "restoredValue": 0.4, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 58, + "edges": 112, + "vertices": 56, + "volume": 2568.032, + "area": 1174.2445253, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 390, + "selectedRecords": 22, + "ambiguousResults": 52, + "historySha256": "1d2211114ac6eda1b1fb29b62592ea52ca02949bb633761a3b79d834b3a9d275", + "namingEvidenceSha256": "a3049ac1bbd44e48cccf87eefd02e67eb583749d84f432a889306c6eaf72c451", + "namingSemanticSha256": "bbeef16c49360df69947335d0764d9740e1d1ae8c42cbe015fda6342d72e0483" + }, + "restoredEvidence": { + "operation": "chamfer", + "builder": "BRepFilletAPI_MakeChamfer", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 58, + "edges": 112, + "vertices": 56, + "volume": 2585.6213333, + "area": 1196.4040506, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 390, + "selectedRecords": 22, + "ambiguousResults": 52, + "historySha256": "1d2211114ac6eda1b1fb29b62592ea52ca02949bb633761a3b79d834b3a9d275", + "namingEvidenceSha256": "1da4ad3dc94a80e1736d445cccdd5710f06d69fcafc842e63cefa8c1d9beedb4", + "namingSemanticSha256": "bbeef16c49360df69947335d0764d9740e1d1ae8c42cbe015fda6342d72e0483" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->chamfer", + "phases": { + "initial": { + "namingEvidenceBytes": 34447, + "namingEvidenceSha256": "0e83ffacf7be22a28281e1001e1ca145e7c4d706bae45f572b9491b8834ebf04", + "pair": "multi-transform->chamfer", + "shape": { + "area": 1196.4040506, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 112, + "faces": 58, + "solids": 1, + "valid": true, + "vertices": 56, + "volume": 2585.6213333 + } + }, + "reopened": { + "namingEvidenceBytes": 34447, + "namingEvidenceSha256": "0e83ffacf7be22a28281e1001e1ca145e7c4d706bae45f572b9491b8834ebf04", + "pair": "multi-transform->chamfer", + "shape": { + "area": 1196.4040506, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 112, + "faces": 58, + "solids": 1, + "valid": true, + "vertices": 56, + "volume": 2585.6213333 + } + }, + "resaved": { + "namingEvidenceBytes": 34447, + "namingEvidenceSha256": "0e83ffacf7be22a28281e1001e1ca145e7c4d706bae45f572b9491b8834ebf04", + "pair": "multi-transform->chamfer", + "shape": { + "area": 1196.4040506, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 112, + "faces": 58, + "solids": 1, + "valid": true, + "vertices": 56, + "volume": 2585.6213333 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-hole", + "pair": "multi-transform->hole", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "dc4fd56c9ce42f69d95779847bbbd40c7030d8aeda34b37dceb0d02fbadfd3ac", + "namingSemanticSha256": "56bb9c779a7c9457c8871ab7966e46c333b96e3902abd0b6aeb0e583a2b27cc3" + }, + "second": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 23, + "edges": 47, + "vertices": 26, + "volume": 2568.5840735, + "area": 1296.5486678, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "9b51714e5341888f0b0675d74d1d69ffef41c802e39453b45101caf5871dec5b", + "namingEvidenceSha256": "e44576e22071d6cb3f9e4b1466f84e7c260aee2e88922543c1459b00d9ceb0dd", + "namingSemanticSha256": "3aeb840bc90524e2343e4ac1b5febceed094c75b3acfd1945fa12d6a3ec70bd6" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "radius", + "trajectory": [ + 1, + 1.5, + 1 + ], + "beforeValue": 1, + "editedValue": 1.5, + "restoredValue": 1, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 23, + "edges": 47, + "vertices": 26, + "volume": 2529.3141653, + "area": 1320.1106127, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "9b51714e5341888f0b0675d74d1d69ffef41c802e39453b45101caf5871dec5b", + "namingEvidenceSha256": "07f3fcde5f2be752167844c7b7370325167d38ad87fbe92bed3f1897a94fbbfa", + "namingSemanticSha256": "3aeb840bc90524e2343e4ac1b5febceed094c75b3acfd1945fa12d6a3ec70bd6" + }, + "restoredEvidence": { + "operation": "hole", + "builder": "BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 23, + "edges": 47, + "vertices": 26, + "volume": 2568.5840735, + "area": 1296.5486678, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 23, + "selectedRecords": 2, + "ambiguousResults": 0, + "historySha256": "9b51714e5341888f0b0675d74d1d69ffef41c802e39453b45101caf5871dec5b", + "namingEvidenceSha256": "b5cec3ddae056d4e96757a83ceeaa55c41bb3b948d20899d57edce6af0a81ca4", + "namingSemanticSha256": "3aeb840bc90524e2343e4ac1b5febceed094c75b3acfd1945fa12d6a3ec70bd6" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->hole", + "phases": { + "initial": { + "namingEvidenceBytes": 1818, + "namingEvidenceSha256": "e44576e22071d6cb3f9e4b1466f84e7c260aee2e88922543c1459b00d9ceb0dd", + "pair": "multi-transform->hole", + "shape": { + "area": 1296.5486678, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 47, + "faces": 23, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 2568.5840735 + } + }, + "reopened": { + "namingEvidenceBytes": 1818, + "namingEvidenceSha256": "e44576e22071d6cb3f9e4b1466f84e7c260aee2e88922543c1459b00d9ceb0dd", + "pair": "multi-transform->hole", + "shape": { + "area": 1296.5486678, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 47, + "faces": 23, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 2568.5840735 + } + }, + "resaved": { + "namingEvidenceBytes": 1818, + "namingEvidenceSha256": "e44576e22071d6cb3f9e4b1466f84e7c260aee2e88922543c1459b00d9ceb0dd", + "pair": "multi-transform->hole", + "shape": { + "area": 1296.5486678, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 47, + "faces": 23, + "solids": 1, + "valid": true, + "vertices": 26, + "volume": 2568.5840735 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-draft", + "pair": "multi-transform->draft", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "a8acdefc6cd5608908b2be9eae6e25a25269eacdabac25150a471257b0c5f30c", + "namingSemanticSha256": "585e5650e1f3392be42c7be8369a234a683532be6004eb5b7979887bcd2829fe" + }, + "second": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2486.2647374, + "area": 1209.4972389, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 17, + "selectedRecords": 17, + "ambiguousResults": 0, + "historySha256": "f1fdce96f5586a8599f7f82e5394de91d2ed981679ac697a744d43cbd5d11fad", + "namingEvidenceSha256": "3027a08991dcd758f4877e9294082468fb00030a319ac18f9fff51510cc45e8e", + "namingSemanticSha256": "95e69fcb8e6dee52bc7b5db83b78fcb171bcef32a429781eb9c92be349827ee9" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 5, + 8, + 5 + ], + "beforeValue": 5, + "editedValue": 8, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2417.2969149, + "area": 1191.9604684, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 17, + "selectedRecords": 17, + "ambiguousResults": 0, + "historySha256": "f1fdce96f5586a8599f7f82e5394de91d2ed981679ac697a744d43cbd5d11fad", + "namingEvidenceSha256": "fc1aa81bbb2a8a4195bbbf7d46fd3d40908db383bf9b21d1b408d7a1a03dee9d", + "namingSemanticSha256": "95e69fcb8e6dee52bc7b5db83b78fcb171bcef32a429781eb9c92be349827ee9" + }, + "restoredEvidence": { + "operation": "draft", + "builder": "BRepOffsetAPI_DraftAngle", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "native-evidence", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2486.2647374, + "area": 1209.4972389, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 17, + "selectedRecords": 17, + "ambiguousResults": 0, + "historySha256": "f1fdce96f5586a8599f7f82e5394de91d2ed981679ac697a744d43cbd5d11fad", + "namingEvidenceSha256": "2fcf54e53f91452f0d1039700c257a550e030211ba4c5f4be702fe75fc28b755", + "namingSemanticSha256": "95e69fcb8e6dee52bc7b5db83b78fcb171bcef32a429781eb9c92be349827ee9" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->draft", + "phases": { + "initial": { + "namingEvidenceBytes": 7981, + "namingEvidenceSha256": "3027a08991dcd758f4877e9294082468fb00030a319ac18f9fff51510cc45e8e", + "pair": "multi-transform->draft", + "shape": { + "area": 1209.4972389, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2486.2647374 + } + }, + "reopened": { + "namingEvidenceBytes": 7981, + "namingEvidenceSha256": "3027a08991dcd758f4877e9294082468fb00030a319ac18f9fff51510cc45e8e", + "pair": "multi-transform->draft", + "shape": { + "area": 1209.4972389, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2486.2647374 + } + }, + "resaved": { + "namingEvidenceBytes": 7981, + "namingEvidenceSha256": "3027a08991dcd758f4877e9294082468fb00030a319ac18f9fff51510cc45e8e", + "pair": "multi-transform->draft", + "shape": { + "area": 1209.4972389, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2486.2647374 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-thickness", + "pair": "multi-transform->thickness", + "classification": "rejected", + "reasonCode": "native-and-freecad-profile-no-op-with-clean-resave", + "nativeDecision": "rejected", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "f2a5edaef4a300aeb4e7466ac1c8b0c8851027e71f1b55f3da4afcc2796d6f2c", + "namingSemanticSha256": "17f114a837bb65fc5e577feebe51934789120f797d9ba7f8d2ba4727af65f932" + }, + "rejection": { + "scope": "second-operation-only", + "authority": "occt-no-op", + "parameter": "offset", + "trajectory": [ + -0.4, + -0.6, + -0.4 + ], + "kernelAttempts": [ + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.4, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "013f02688f59982b165e184600922e17cacbb0ec02a57f2431d514b33b23641c", + "authority": "kernel-no-op" + }, + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.6, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "013f02688f59982b165e184600922e17cacbb0ec02a57f2431d514b33b23641c", + "authority": "kernel-no-op" + }, + { + "operation": "thickness", + "builder": "BRepOffsetAPI_MakeThickSolid", + "inputCount": 1, + "parameter": "offset", + "parameterValue": -0.4, + "runtime": "occt-native", + "outcome": "no-op", + "resultProduced": true, + "shapeProduced": true, + "validShapeProduced": true, + "historyProduced": true, + "historyProvider": "occt-native", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1, + "historySha256": "013f02688f59982b165e184600922e17cacbb0ec02a57f2431d514b33b23641c", + "authority": "kernel-no-op" + } + ], + "kernelRestoredExactly": true, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "documentStable": true, + "documentUnpolluted": true, + "freecadProfileAccepted": false, + "freecadProfileNoOp": true, + "fuseSolidUsedAsInput": true, + "nativeFeatureConstructed": true, + "nativeFeatureRejected": false, + "objectSetRestored": true, + "recomputeStatusCaptured": true, + "sourceShapeGeometricallyRestored": true, + "sourceShapeRestored": false, + "sourceShapeSummaryRestored": true + }, + "decision": "rejected", + "diagnostic": { + "exception": null, + "exceptionType": null, + "input": { + "name": "Part__Feature", + "subelements": [ + "Face2" + ], + "typeId": "Part::Feature" + }, + "inputShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "nativeTypeId": "Part::Thickness", + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + }, + { + "name": "PairResult", + "typeId": "Part::Thickness" + } + ], + "parameter": { + "name": "offset", + "value": -0.4 + }, + "recomputeResult": true, + "resultShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "shapeNull": false, + "shapeValid": true, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "nativeTypeId": "Part::Thickness", + "operation": "thickness", + "pair": "multi-transform->thickness", + "phases": { + "initial": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + }, + "reopened": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + }, + "resaved": { + "objects": [ + { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + } + ] + } + }, + "rollback": { + "after": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "3231d3f035aa3913e55007e83625f8abadc16cf34a28d1534dda4ce34d71e35f", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "before": { + "objects": [ + { + "name": "Part__Feature", + "typeId": "Part::Feature" + } + ], + "sourceShape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "sourceBrepReserialized": true, + "sourceShapeSymmetricDifference": { + "afterMinusBeforeVolume": 0, + "beforeMinusAfterVolume": 0 + }, + "sourceShapeTopologicallyEqual": false + }, + "schemaVersion": 1, + "source": { + "name": "Part__Feature", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "brepSha256": "77e9b4530db958be16c28c45e38fde96276324ecaad6971119289c04575ac322", + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + }, + "typeId": "Part::Feature" + }, + "status": "pass" + } + } + }, + { + "taskId": "TSN-PAIR-multi-transform-linear-pattern", + "pair": "multi-transform->linear-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "faa70f05bdcd7e4d9b17f3c8cb627eb37d027055505769e9a3ed582b5b88520e", + "namingSemanticSha256": "23b7861181646088dae1ad0bb3b2dc8c877975f31f845c9fb5326323f8c03b77" + }, + "second": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 30, + "edges": 60, + "vertices": 32, + "volume": 3400, + "area": 1560, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 26.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 466, + "selectedRecords": 24, + "ambiguousResults": 60, + "historySha256": "05de7ec1b9ca9707aa95e832b1d8da504f3b02860394a019434691f06f819e9f", + "namingEvidenceSha256": "b394abb85573fe25f00cdc4dc476c1f1d5fc6197c2ab3815b872eff89bcb5871", + "namingSemanticSha256": "d201c45fe495e58b4fa2f3c7e009fa70c6a8243db0cd439729104242f82ddf0f" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "translationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 46, + "edges": 92, + "vertices": 48, + "volume": 3500, + "area": 1600, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 27.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 258, + "selectedRecords": 32, + "ambiguousResults": 48, + "historySha256": "a590f19fb8d1d956dda6773a5ca5e93b52b0fb1e09188d0117f5573306470a84", + "namingEvidenceSha256": "9316f9d690ee344d46ad0daef639b7fa2fe5f34fe9fd752237abe73c9a5a87a6", + "namingSemanticSha256": "9fd0331df6eb7b28d4f058231994d6422dcd463788d09b9a5f1d881ce563d72a" + }, + "restoredEvidence": { + "operation": "linear-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 30, + "edges": 60, + "vertices": 32, + "volume": 3400, + "area": 1560, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 26.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 466, + "selectedRecords": 24, + "ambiguousResults": 60, + "historySha256": "05de7ec1b9ca9707aa95e832b1d8da504f3b02860394a019434691f06f819e9f", + "namingEvidenceSha256": "969772992e9c56885c16862d6815800c02c94dc7726a95d0b0aaa49a6e75be83", + "namingSemanticSha256": "d201c45fe495e58b4fa2f3c7e009fa70c6a8243db0cd439729104242f82ddf0f" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->linear-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 50583, + "namingEvidenceSha256": "b394abb85573fe25f00cdc4dc476c1f1d5fc6197c2ab3815b872eff89bcb5871", + "pair": "multi-transform->linear-pattern", + "shape": { + "area": 1560, + "bounds": [ + -8, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 60, + "faces": 30, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 3400 + } + }, + "reopened": { + "namingEvidenceBytes": 50583, + "namingEvidenceSha256": "b394abb85573fe25f00cdc4dc476c1f1d5fc6197c2ab3815b872eff89bcb5871", + "pair": "multi-transform->linear-pattern", + "shape": { + "area": 1560, + "bounds": [ + -8, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 60, + "faces": 30, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 3400 + } + }, + "resaved": { + "namingEvidenceBytes": 50583, + "namingEvidenceSha256": "b394abb85573fe25f00cdc4dc476c1f1d5fc6197c2ab3815b872eff89bcb5871", + "pair": "multi-transform->linear-pattern", + "shape": { + "area": 1560, + "bounds": [ + -8, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 60, + "faces": 30, + "solids": 1, + "valid": true, + "vertices": 32, + "volume": 3400 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-polar-pattern", + "pair": "multi-transform->polar-pattern", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "3524e64c63d7caae8636380045e81f4e4c3f4aca50c846b952f7bffcfdcb9457", + "namingSemanticSha256": "712c40fcd4c02363c9afccaae87b622661c220245daaea064a942e498bcb57a9" + }, + "second": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 55, + "edges": 119, + "vertices": 66, + "volume": 3627.2391992, + "area": 1586.2768775, + "bounds": [ + -11.9282034, + -4.0000001, + -1e-7, + 18.0000002, + 17.6602542, + 10.0000001 + ] + }, + "historyRecords": 317, + "selectedRecords": 36, + "ambiguousResults": 47, + "historySha256": "4bf91995de45e71a747e4106927b308b37f1615e92dfef00321f176a688622d7", + "namingEvidenceSha256": "9b336c1a8cd055c69e17088795645c71032880763188d82f4d3e168907ecff0b", + "namingSemanticSha256": "b5f128ca7a0b2c64c649c3d20851efcf1a28a6c4fe916c735a9f680b764d0c3f" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "angle", + "trajectory": [ + 30, + 45, + 30 + ], + "beforeValue": 30, + "editedValue": 45, + "restoredValue": 30, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 54, + "edges": 114, + "vertices": 62, + "volume": 3974.4155877, + "area": 1756.0606076, + "bounds": [ + -12.7279222, + -5.6568544, + -1e-7, + 18.0000002, + 19.79899, + 10.0000001 + ] + }, + "historyRecords": 283, + "selectedRecords": 31, + "ambiguousResults": 40, + "historySha256": "1b892efc826f45339ce37e1ebdef3d05b098f6451f9a6b7700b29cfa3c9753ea", + "namingEvidenceSha256": "90d7f09ec9ff9e0e164cdc97c8b231fea99e99f73a5680c5b063d47a4782bebd", + "namingSemanticSha256": "27204c975ee5475a2fa5c5083daa2a6c55627c78d11c13260e670311f277fd33" + }, + "restoredEvidence": { + "operation": "polar-pattern", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 55, + "edges": 119, + "vertices": 66, + "volume": 3627.2391992, + "area": 1586.2768775, + "bounds": [ + -11.9282034, + -4.0000001, + -1e-7, + 18.0000002, + 17.6602542, + 10.0000001 + ] + }, + "historyRecords": 317, + "selectedRecords": 36, + "ambiguousResults": 47, + "historySha256": "4bf91995de45e71a747e4106927b308b37f1615e92dfef00321f176a688622d7", + "namingEvidenceSha256": "933bb62d25778eb751e87a96244def8a76af03a44aea3409a8146aa2f1e23ede", + "namingSemanticSha256": "b5f128ca7a0b2c64c649c3d20851efcf1a28a6c4fe916c735a9f680b764d0c3f" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->polar-pattern", + "phases": { + "initial": { + "namingEvidenceBytes": 36475, + "namingEvidenceSha256": "9b336c1a8cd055c69e17088795645c71032880763188d82f4d3e168907ecff0b", + "pair": "multi-transform->polar-pattern", + "shape": { + "area": 1586.2768775, + "bounds": [ + -11.9282032, + -4, + 0, + 18, + 17.660254, + 10 + ], + "edges": 119, + "faces": 55, + "solids": 1, + "valid": true, + "vertices": 66, + "volume": 3627.2391992 + } + }, + "reopened": { + "namingEvidenceBytes": 36475, + "namingEvidenceSha256": "9b336c1a8cd055c69e17088795645c71032880763188d82f4d3e168907ecff0b", + "pair": "multi-transform->polar-pattern", + "shape": { + "area": 1586.2768775, + "bounds": [ + -11.9282032, + -4, + 0, + 18, + 17.660254, + 10 + ], + "edges": 119, + "faces": 55, + "solids": 1, + "valid": true, + "vertices": 66, + "volume": 3627.2391992 + } + }, + "resaved": { + "namingEvidenceBytes": 36475, + "namingEvidenceSha256": "9b336c1a8cd055c69e17088795645c71032880763188d82f4d3e168907ecff0b", + "pair": "multi-transform->polar-pattern", + "shape": { + "area": 1586.2768775, + "bounds": [ + -11.9282032, + -4, + 0, + 18, + 17.660254, + 10 + ], + "edges": 119, + "faces": 55, + "solids": 1, + "valid": true, + "vertices": 66, + "volume": 3627.2391992 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-mirrored", + "pair": "multi-transform->mirrored", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "5ab04ab8bafda88b602464a38c01523502616667dd29ea4202ff09ff3184dff6", + "namingSemanticSha256": "a45bbad09d8f2f3e9944d13886f2e80b9bba274d71875c992fb1ce7efb087ee7" + }, + "second": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 572, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "6ebbafdf067496613e49fdc29fc3af013d3a491d67f8c5fe050cb714b228582b", + "namingEvidenceSha256": "a8d686199c1ba0c8e40f0b3f4efd6c471527362c66acfd3f9fd7e4c99b896b07", + "namingSemanticSha256": "28e61adfc8c8e42d6dea1722456798135b5830b0048041b798675dee061f645b" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "planeOriginX", + "trajectory": [ + 5, + 6, + 5 + ], + "beforeValue": 5, + "editedValue": 6, + "restoredValue": 5, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 38, + "edges": 76, + "vertices": 40, + "volume": 2800, + "area": 1320, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 20.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 402, + "selectedRecords": 32, + "ambiguousResults": 60, + "historySha256": "73d62f0d1c6c1ea198da7318b5c73b1b2bf4ce99fdd255bdfd0583c0108865f6", + "namingEvidenceSha256": "e22f1857cb01ab2e09325dce12a7c6db910d51c13572667aadc335202b4f870a", + "namingSemanticSha256": "f65b099b8ef68cf4bec78ae2efe9ea08496fece7b2fbadcb30ec11259db70c8c" + }, + "restoredEvidence": { + "operation": "mirrored", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 572, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "6ebbafdf067496613e49fdc29fc3af013d3a491d67f8c5fe050cb714b228582b", + "namingEvidenceSha256": "7baeb6d13c96ba2419c9f2651ab439a249259ed451a599df306d9f537f1ffdda", + "namingSemanticSha256": "28e61adfc8c8e42d6dea1722456798135b5830b0048041b798675dee061f645b" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->mirrored", + "phases": { + "initial": { + "namingEvidenceBytes": 55028, + "namingEvidenceSha256": "a8d686199c1ba0c8e40f0b3f4efd6c471527362c66acfd3f9fd7e4c99b896b07", + "pair": "multi-transform->mirrored", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "reopened": { + "namingEvidenceBytes": 55028, + "namingEvidenceSha256": "a8d686199c1ba0c8e40f0b3f4efd6c471527362c66acfd3f9fd7e4c99b896b07", + "pair": "multi-transform->mirrored", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + }, + "resaved": { + "namingEvidenceBytes": 55028, + "namingEvidenceSha256": "a8d686199c1ba0c8e40f0b3f4efd6c471527362c66acfd3f9fd7e4c99b896b07", + "pair": "multi-transform->mirrored", + "shape": { + "area": 1240, + "bounds": [ + -8, + 0, + 0, + 18, + 10, + 10 + ], + "edges": 44, + "faces": 22, + "solids": 1, + "valid": true, + "vertices": 24, + "volume": 2600 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } + }, + { + "taskId": "TSN-PAIR-multi-transform-multi-transform", + "pair": "multi-transform->multi-transform", + "classification": "accepted", + "reasonCode": "native-builders-mutation-naming-and-fcstd-resave-pass", + "nativeDecision": "accepted", + "first": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 22, + "edges": 44, + "vertices": 24, + "volume": 2600, + "area": 1240, + "bounds": [ + -8.0000001, + -1e-7, + -1e-7, + 18.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 355, + "selectedRecords": 22, + "ambiguousResults": 68, + "historySha256": "43a529a45527c7dbb04f1c871e2b9b4c851ac22855e3036665a13c5717b8a29d", + "namingEvidenceSha256": "b092e6c046b096fa23e1d1f16766d4dffa8b8a307825ff49c4a9517cf91cf7bf", + "namingSemanticSha256": "536f057a6bf78fccf992346b86da26cc905b4e29b2de6def52e8848d684d8834" + }, + "second": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 38, + "edges": 76, + "vertices": 40, + "volume": 4200, + "area": 1880, + "bounds": [ + -16.0000001, + -1e-7, + -1e-7, + 26.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1187, + "selectedRecords": 10, + "ambiguousResults": 144, + "historySha256": "e7b824fb5bee0d2841fda6033b74c852f840819756c5338eae2213605d22b70d", + "namingEvidenceSha256": "ce7e7e2afb3a10c9f142246cda2620f195d652e8f27135457fbf1e980ee650bc", + "namingSemanticSha256": "fda9f237688323451a110e6e20cfbdcd36296a1deb50058c08d3129d2f4cac30" + }, + "mutation": { + "scope": "second-operation-only", + "parameter": "multiTranslationX", + "trajectory": [ + 8, + 9, + 8 + ], + "beforeValue": 8, + "editedValue": 9, + "restoredValue": 8, + "changed": true, + "restoredExactly": true, + "editedEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 62, + "edges": 124, + "vertices": 64, + "volume": 4400, + "area": 1960, + "bounds": [ + -17.0000001, + -1e-7, + -1e-7, + 27.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1331, + "selectedRecords": 18, + "ambiguousResults": 232, + "historySha256": "23c7b058f339ae535a76c1358f9440d9f284eb6ca80972ae342ac9e3c96b0b52", + "namingEvidenceSha256": "124314d603bcd218949383d0aa20c6ac877483a34d800e74750781024dbd1c74", + "namingSemanticSha256": "1786a2b47d42fcf534443bac35b8f2fe6c18046fdd3112a399aa587db67d6b76" + }, + "restoredEvidence": { + "operation": "multi-transform", + "builder": "BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)", + "inputCount": 1, + "historyProvider": "occt-native", + "namingStatus": "ambiguous", + "summary": { + "isValid": true, + "solids": 1, + "faces": 38, + "edges": 76, + "vertices": 40, + "volume": 4200, + "area": 1880, + "bounds": [ + -16.0000001, + -1e-7, + -1e-7, + 26.0000001, + 10.0000001, + 10.0000001 + ] + }, + "historyRecords": 1187, + "selectedRecords": 10, + "ambiguousResults": 144, + "historySha256": "e7b824fb5bee0d2841fda6033b74c852f840819756c5338eae2213605d22b70d", + "namingEvidenceSha256": "a8c503980c589634e86cd8fe2f6c8fb44c51fe94ccc24b50fb603669d2d5b25d", + "namingSemanticSha256": "fda9f237688323451a110e6e20cfbdcd36296a1deb50058c08d3129d2f4cac30" + } + }, + "naming": { + "upstreamEvidenceRestored": true, + "downstreamEvidence": true, + "jsonRoundtripStable": true + }, + "persistence": { + "baselineId": "freecad-1.1.1-ordered-operation-pair-resave", + "checks": { + "namingEvidenceStable": true, + "shapeStable": true + }, + "decision": "accepted", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "pair": "multi-transform->multi-transform", + "phases": { + "initial": { + "namingEvidenceBytes": 174718, + "namingEvidenceSha256": "ce7e7e2afb3a10c9f142246cda2620f195d652e8f27135457fbf1e980ee650bc", + "pair": "multi-transform->multi-transform", + "shape": { + "area": 1880, + "bounds": [ + -16, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 76, + "faces": 38, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 4200 + } + }, + "reopened": { + "namingEvidenceBytes": 174718, + "namingEvidenceSha256": "ce7e7e2afb3a10c9f142246cda2620f195d652e8f27135457fbf1e980ee650bc", + "pair": "multi-transform->multi-transform", + "shape": { + "area": 1880, + "bounds": [ + -16, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 76, + "faces": 38, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 4200 + } + }, + "resaved": { + "namingEvidenceBytes": 174718, + "namingEvidenceSha256": "ce7e7e2afb3a10c9f142246cda2620f195d652e8f27135457fbf1e980ee650bc", + "pair": "multi-transform->multi-transform", + "shape": { + "area": 1880, + "bounds": [ + -16, + 0, + 0, + 26, + 10, + 10 + ], + "edges": 76, + "faces": 38, + "solids": 1, + "valid": true, + "vertices": 40, + "volume": 4200 + } + } + }, + "schemaVersion": 1, + "status": "pass" + } } ], "summary": { "registeredOperations": 19, "orderedPairs": 361, - "classifiedPairs": 209, - "accepted": 157, - "rejected": 52, - "unknown": 152 + "classifiedPairs": 357, + "accepted": 260, + "rejected": 97, + "unknown": 4 } } diff --git a/config/freecad-property-acceleration-failure.json b/config/freecad-property-acceleration-failure.json new file mode 100644 index 0000000..e9d1c5c --- /dev/null +++ b/config/freecad-property-acceleration-failure.json @@ -0,0 +1,193 @@ +{ + "baselineId": "freecad-1.1.1-property-acceleration-failure", + "cancellationBoundary": { + "classification": "synchronous-property-setter", + "reason": "no-native-cancel-hook", + "replacement": "abort-active-document-transaction", + "supported": false + }, + "disabled": { + "after": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + }, + "afterObjects": [ + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "before": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + }, + "beforeObjects": [ + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "classification": "editor-read-only-and-python-immutable", + "editorMode": [ + "ReadOnly" + ], + "exception": { + "message": "Object attribute 'Acceleration' is read-only", + "type": "AttributeError" + }, + "objectsPreserved": true, + "requested": "750 mm/s^2", + "restoredEditorMode": [], + "restoredStatus": [], + "status": [ + "Immutable", + "ReadOnly" + ], + "valuePreserved": true + }, + "documentIntegrity": { + "finalObjects": [ + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "initialObjects": [ + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "objectCount": 1, + "objectsPreserved": true + }, + "failures": [ + { + "after": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + }, + "afterObjects": [ + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "before": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + }, + "beforeObjects": [ + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "exception": { + "message": "Not matching Unit!", + "type": "ArithmeticError" + }, + "id": "wrong-dimension", + "objectsPreserved": true, + "polluted": false, + "requested": "5 mm", + "valuePreserved": true + }, + { + "after": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + }, + "afterObjects": [ + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "before": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + }, + "beforeObjects": [ + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "exception": { + "message": "syntax error", + "type": "ParserError" + }, + "id": "malformed-text", + "objectsPreserved": true, + "polluted": false, + "requested": "not-a-quantity", + "valuePreserved": true + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "initial": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + }, + "object": { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + }, + "property": { + "name": "Acceleration", + "typeId": "App::PropertyAcceleration" + }, + "schemaVersion": 1, + "status": "pass", + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 1, + "name": "property-acceleration-cancel" + }, + "afterAbort": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + }, + "before": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + }, + "edited": { + "numeric": 250, + "raw": "250.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + }, + "objectsAfter": [ + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "objectsBefore": [ + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "objectsRestored": true, + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "restored": true, + "undoMode": 1 + } +} diff --git a/config/freecad-property-acceleration-inventory.json b/config/freecad-property-acceleration-inventory.json new file mode 100644 index 0000000..61fc664 --- /dev/null +++ b/config/freecad-property-acceleration-inventory.json @@ -0,0 +1,49 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyAcceleration", + "recordCount": 1, + "records": [ + { + "objectTypeId": "Robot::TrajectoryDressUpObject", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Acceleration", + "group": "TrajectoryDressUp", + "status": [], + "defaultRaw": "1000.0 mm/s^2", + "valueModel": { + "kind": "quantity", + "dimension": "length/time^2", + "defaultValue": 1000, + "defaultUnit": "mm/s^2", + "acceptedBoundaryEvidence": "inventory-only; value and boundary acceptance remain pending in phase B/C" + }, + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "Robot::TrajectoryDressUpObject", + "source": "Document.supportedTypes runtime inventory" + } + } + ], + "source": { + "path": ".cache/freecad/reference-desktop.json", + "bytes": 2298709, + "sha256": "082400ec7379e8efc2af16709032d45890d7092277967b714acb05761fd1c2a7" + }, + "classification": "opaque-fcstd-proxy", + "nextPhases": [ + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I" + ] +} diff --git a/config/freecad-property-acceleration-mutation.json b/config/freecad-property-acceleration-mutation.json new file mode 100644 index 0000000..f8c7c30 --- /dev/null +++ b/config/freecad-property-acceleration-mutation.json @@ -0,0 +1,347 @@ +{ + "baselineId": "freecad-1.1.1-property-acceleration-mutation", + "before": { + "editorMode": [], + "mustExecute": false, + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "shape": { + "applicable": false + }, + "source": { + "name": "SourceTrajectory", + "typeId": "Robot::TrajectoryObject" + }, + "statusString": "Valid", + "trajectory": { + "contentSha256": "1a29d89dac9b062e0ea210375b9aeb1f7ada2ed763939e339eb31c05d4ee678f", + "duration": 0.141421356, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 1000, + "base": 0, + "continuous": false, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 1000, + "base": 0, + "continuous": false, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + } + ] + }, + "useAcceleration": true, + "value": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + } + }, + "classification": { + "geometry": "not-applicable-no-shape-property", + "propertyChanged": true, + "propertyRestored": true, + "semanticStateRestored": true, + "trajectoryChanged": true, + "trajectoryRestored": true + }, + "document": { + "objectsBefore": [ + { + "name": "SourceTrajectory", + "typeId": "Robot::TrajectoryObject" + }, + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "objectsPreserved": true, + "objectsRestored": [ + { + "name": "SourceTrajectory", + "typeId": "Robot::TrajectoryObject" + }, + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ] + }, + "edited": { + "editorMode": [], + "mustExecute": false, + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "shape": { + "applicable": false + }, + "source": { + "name": "SourceTrajectory", + "typeId": "Robot::TrajectoryObject" + }, + "statusString": "Valid", + "trajectory": { + "contentSha256": "a7febf338d0c6527d9ad31e709f379092fd6f0144714ee29f973cd77567ecf2c", + "duration": 0.2, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 500, + "base": 0, + "continuous": false, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 500, + "base": 0, + "continuous": false, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + } + ] + }, + "useAcceleration": true, + "value": { + "numeric": 500, + "raw": "500.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + } + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "object": { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + }, + "property": { + "name": "Acceleration", + "typeId": "App::PropertyAcceleration" + }, + "recompute": { + "edit": 1, + "initial": 2, + "restore": 1 + }, + "restored": { + "editorMode": [], + "mustExecute": false, + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "shape": { + "applicable": false + }, + "source": { + "name": "SourceTrajectory", + "typeId": "Robot::TrajectoryObject" + }, + "statusString": "Valid", + "trajectory": { + "contentSha256": "1a29d89dac9b062e0ea210375b9aeb1f7ada2ed763939e339eb31c05d4ee678f", + "duration": 0.141421356, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 1000, + "base": 0, + "continuous": false, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 1000, + "base": 0, + "continuous": false, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + } + ] + }, + "useAcceleration": true, + "value": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + } + }, + "schemaVersion": 1, + "source": { + "before": { + "contentSha256": "cb93c2855ce67ed800416d985edfe22d80035a3313015573d78252bc17619db9", + "duration": 0.447213595, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 100, + "base": 0, + "continuous": false, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 100, + "base": 0, + "continuous": false, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + } + ] + }, + "edited": { + "contentSha256": "cb93c2855ce67ed800416d985edfe22d80035a3313015573d78252bc17619db9", + "duration": 0.447213595, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 100, + "base": 0, + "continuous": false, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 100, + "base": 0, + "continuous": false, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + } + ] + }, + "preserved": true, + "restored": { + "contentSha256": "cb93c2855ce67ed800416d985edfe22d80035a3313015573d78252bc17619db9", + "duration": 0.447213595, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 100, + "base": 0, + "continuous": false, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 100, + "base": 0, + "continuous": false, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "tool": 0, + "type": "LIN", + "velocity": 2000 + } + ] + } + }, + "status": "pass", + "touchedAfterEdit": { + "mustExecute": false, + "objectState": [ + "Touched" + ], + "value": { + "numeric": 500, + "raw": "500.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + } + } +} diff --git a/config/freecad-property-acceleration-promotion.json b/config/freecad-property-acceleration-promotion.json new file mode 100644 index 0000000..ad2b8f7 --- /dev/null +++ b/config/freecad-property-acceleration-promotion.json @@ -0,0 +1,66 @@ +{ + "schemaVersion": 1, + "status": "pass", + "taskId": "PROP-app-propertyacceleration-I", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyAcceleration", + "recordCount": 1, + "phaseEvidence": { + "A": [ + "config/freecad-property-acceleration-inventory.json", + "check:freecad-property-acceleration-inventory" + ], + "B": [ + "config/freecad-property-acceleration-success.json", + "check:freecad-property-acceleration-success" + ], + "C": [ + "config/freecad-property-acceleration-failure.json", + "check:freecad-property-acceleration-failure" + ], + "D": [ + "config/freecad-property-acceleration-mutation.json", + "check:freecad-property-acceleration-mutation" + ], + "E": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "test:freecad-property-acceleration-facade" + ], + "F": [ + "tests/propertyAccelerationTransaction.test.ts", + "test:freecad-property-acceleration-transaction" + ], + "G": [ + "config/freecad-property-acceleration-roundtrip.json", + "check:freecad-property-acceleration-roundtrip" + ], + "H": [ + "config/chrome-property-acceleration-verification.json", + "check:chrome-property-acceleration" + ] + }, + "promotion": { + "from": "opaque-fcstd-proxy", + "to": "native-editable-codec", + "facadeValueModel": "finite-number-mm/s^2", + "fcstdElement": "Float", + "nativeRoundTripValue": 500, + "browserRoundTripValue": 500, + "zeroUnknownDrift": true + }, + "exactBlockerSync": { + "nativeEditableTypes": 30, + "nativeEditableRecords": 4361, + "opaqueTypes": 50, + "opaqueRecords": 466, + "exactPromotionReady": false, + "exactBlocker": "50 runtime property types and 466 records remain opaque-only; complete native document and property semantics" + }, + "systemExact": false, + "generatedAt": "2026-08-17T08:49:33.800Z" +} diff --git a/config/freecad-property-acceleration-roundtrip.json b/config/freecad-property-acceleration-roundtrip.json new file mode 100644 index 0000000..472fcaf --- /dev/null +++ b/config/freecad-property-acceleration-roundtrip.json @@ -0,0 +1,331 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-acceleration-roundtrip", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "archives": { + "nativeInitial": { + "path": ".cache/freecad/property-acceleration-roundtrip/native-initial.FCStd", + "bytes": 1625, + "sha256": "121b9ef55520cbea76f85d4a462791f22593743680c7c8813c84a06ed092695e" + }, + "webEdited": { + "path": ".cache/freecad/property-acceleration-roundtrip/web-edited.FCStd", + "bytes": 1455, + "sha256": "6c9f69279012adfaba3e3093448d343a5829a5c34df7fc3f2f3799a625fb8a70" + }, + "nativeResaved": { + "path": ".cache/freecad/property-acceleration-roundtrip/native-resaved.FCStd", + "bytes": 1629, + "sha256": "0a6d34aba0c69b6dd52424f3d1c35bc096b8ca6087e96903b9ada9a1b257cbd9" + } + }, + "nativeInitial": { + "object": { + "editorMode": [], + "name": "AccelerationProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyAcceleration", + "source": { + "name": "SourceTrajectory", + "typeId": "Robot::TrajectoryObject" + }, + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "trajectory": { + "contentSha256": "1a29d89dac9b062e0ea210375b9aeb1f7ada2ed763939e339eb31c05d4ee678f", + "duration": 0.141421356, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 1000, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 1000, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "type": "LIN", + "velocity": 2000 + } + ] + }, + "typeId": "Robot::TrajectoryDressUpObject", + "useAcceleration": true, + "value": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + } + }, + "objectSet": [ + { + "name": "SourceTrajectory", + "typeId": "Robot::TrajectoryObject" + }, + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "sourceTrajectory": { + "contentSha256": "cb93c2855ce67ed800416d985edfe22d80035a3313015573d78252bc17619db9", + "duration": 0.447213595, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 100, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 100, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "type": "LIN", + "velocity": 2000 + } + ] + } + }, + "web": { + "before": { + "name": "Acceleration", + "typeId": "App::PropertyAcceleration", + "element": "Float", + "value": "1000.0000000000000000" + }, + "after": { + "name": "Acceleration", + "typeId": "App::PropertyAcceleration", + "element": "Float", + "value": "500" + }, + "objectSetPreserved": true, + "semanticObjectsPreserved": true, + "opaquePathsPreserved": 0, + "opaqueEntriesPreserved": true + }, + "nativeAfter": { + "reopened": { + "object": { + "editorMode": [], + "name": "AccelerationProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyAcceleration", + "source": { + "name": "SourceTrajectory", + "typeId": "Robot::TrajectoryObject" + }, + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "trajectory": { + "contentSha256": "a7febf338d0c6527d9ad31e709f379092fd6f0144714ee29f973cd77567ecf2c", + "duration": 0.2, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 500, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 500, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "type": "LIN", + "velocity": 2000 + } + ] + }, + "typeId": "Robot::TrajectoryDressUpObject", + "useAcceleration": true, + "value": { + "numeric": 500, + "raw": "500.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + } + }, + "objectSet": [ + { + "name": "SourceTrajectory", + "typeId": "Robot::TrajectoryObject" + }, + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "sourceTrajectory": { + "contentSha256": "cb93c2855ce67ed800416d985edfe22d80035a3313015573d78252bc17619db9", + "duration": 0.447213595, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 100, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 100, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "type": "LIN", + "velocity": 2000 + } + ] + } + }, + "resaved": { + "object": { + "editorMode": [], + "name": "AccelerationProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyAcceleration", + "source": { + "name": "SourceTrajectory", + "typeId": "Robot::TrajectoryObject" + }, + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "trajectory": { + "contentSha256": "a7febf338d0c6527d9ad31e709f379092fd6f0144714ee29f973cd77567ecf2c", + "duration": 0.2, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 500, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 500, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "type": "LIN", + "velocity": 2000 + } + ] + }, + "typeId": "Robot::TrajectoryDressUpObject", + "useAcceleration": true, + "value": { + "numeric": 500, + "raw": "500.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + } + }, + "objectSet": [ + { + "name": "SourceTrajectory", + "typeId": "Robot::TrajectoryObject" + }, + { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + } + ], + "sourceTrajectory": { + "contentSha256": "cb93c2855ce67ed800416d985edfe22d80035a3313015573d78252bc17619db9", + "duration": 0.447213595, + "length": 5, + "waypointCount": 2, + "waypoints": [ + { + "acceleration": 100, + "name": "Pt", + "position": [ + 1, + 2, + 3 + ], + "type": "LIN", + "velocity": 2000 + }, + { + "acceleration": 100, + "name": "Pt1", + "position": [ + 4, + 6, + 3 + ], + "type": "LIN", + "velocity": 2000 + } + ] + } + } + }, + "classification": { + "webValue": "500", + "reopenedValue": 500, + "resavedValue": 500, + "nativeOutputMatches": true, + "unknownSemanticDrift": false, + "zeroUnknownDrift": true + } +} diff --git a/config/freecad-property-acceleration-success.json b/config/freecad-property-acceleration-success.json new file mode 100644 index 0000000..89410f8 --- /dev/null +++ b/config/freecad-property-acceleration-success.json @@ -0,0 +1,101 @@ +{ + "baselineId": "freecad-1.1.1-property-acceleration-success", + "cases": [ + { + "editorMode": [], + "group": "TrajectoryDressUp", + "id": "default", + "objectState": [ + "Up-to-date" + ], + "requested": null, + "shape": { + "applicable": false + }, + "status": [], + "typeId": "App::PropertyAcceleration", + "value": { + "numeric": 1000, + "raw": "1000.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + } + }, + { + "editorMode": [], + "group": "TrajectoryDressUp", + "id": "nominal", + "objectState": [ + "Touched", + "Invalid" + ], + "requested": "500 mm/s^2", + "shape": { + "applicable": false + }, + "status": [], + "typeId": "App::PropertyAcceleration", + "value": { + "numeric": 500, + "raw": "500.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + } + }, + { + "editorMode": [], + "group": "TrajectoryDressUp", + "id": "lower-bound", + "objectState": [ + "Touched", + "Invalid" + ], + "requested": "0 mm/s^2", + "shape": { + "applicable": false + }, + "status": [], + "typeId": "App::PropertyAcceleration", + "value": { + "numeric": 0, + "raw": "0.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + } + }, + { + "editorMode": [], + "group": "TrajectoryDressUp", + "id": "negative-boundary", + "objectState": [ + "Touched", + "Invalid" + ], + "requested": "-500 mm/s^2", + "shape": { + "applicable": false + }, + "status": [], + "typeId": "App::PropertyAcceleration", + "value": { + "numeric": -500, + "raw": "-500.0 mm/s^2", + "unit": "Unit: mm/s^2 (1,0,-2,0,0,0,0,0) [Acceleration]" + } + } + ], + "diagnostics": { + "documentObjectCount": 1, + "exception": null + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "object": { + "name": "AccelerationProbe", + "typeId": "Robot::TrajectoryDressUpObject" + }, + "property": { + "group": "TrajectoryDressUp", + "name": "Acceleration", + "typeId": "App::PropertyAcceleration" + }, + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-area-failure.json b/config/freecad-property-area-failure.json new file mode 100644 index 0000000..5f36198 --- /dev/null +++ b/config/freecad-property-area-failure.json @@ -0,0 +1,544 @@ +{ + "baselineId": "freecad-1.1.1-property-area-failure", + "cancellationBoundary": { + "classification": "synchronous-measure-recompute", + "reason": "no-native-cancel-hook", + "replacement": "abort-active-document-transaction", + "supported": false + }, + "disabled": { + "before": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "classification": "editor-readonly-python-mutable-until-immutable", + "editorMode": [ + "ReadOnly" + ], + "editorReadOnlyAfter": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 20, + "raw": "20.0 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "editorReadOnlyException": null, + "editorReadOnlyRequested": "20 mm^2", + "immutableAfter": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 20, + "raw": "20.0 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "immutableException": { + "message": "Object attribute 'Area' is read-only", + "type": "AttributeError" + }, + "immutableRequested": "30 mm^2", + "immutableStatus": [ + "Immutable", + "24", + "27" + ], + "immutableValuePreserved": true, + "objectsPreserved": true, + "propertyStatus": [ + "24", + "27" + ], + "pythonBypassesEditorReadOnly": true, + "restored": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "restoredEditorMode": [ + "ReadOnly" + ], + "restoredStatus": [ + "24", + "27" + ], + "valueRestored": true + }, + "documentIntegrity": { + "finalObjects": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaCylinder", + "typeId": "Part::Cylinder" + }, + { + "name": "AreaPoint", + "typeId": "Part::Feature" + }, + { + "name": "AreaLine", + "typeId": "Part::Feature" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "initialObjects": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaCylinder", + "typeId": "Part::Cylinder" + }, + { + "name": "AreaPoint", + "typeId": "Part::Feature" + }, + { + "name": "AreaLine", + "typeId": "Part::Feature" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "objectCount": 5, + "objectsPreserved": true + }, + "failures": [ + { + "after": { + "elements": [ + { + "object": "AreaPoint", + "subElements": [ + "Vertex1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Cannot calculate area", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "afterObjects": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaCylinder", + "typeId": "Part::Cylinder" + }, + { + "name": "AreaPoint", + "typeId": "Part::Feature" + }, + { + "name": "AreaLine", + "typeId": "Part::Feature" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "assignmentException": null, + "before": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "beforeObjects": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaCylinder", + "typeId": "Part::Cylinder" + }, + { + "name": "AreaPoint", + "typeId": "Part::Feature" + }, + { + "name": "AreaLine", + "typeId": "Part::Feature" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "expectedDiagnostic": "Cannot calculate area", + "id": "unsupported-point", + "objectsPreserved": true, + "recomputeException": null, + "recomputeResult": true, + "recovered": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "recoveredExactly": true, + "source": { + "name": "AreaPoint", + "shapeType": "Vertex", + "subElement": "Vertex1", + "typeId": "Part::Feature" + }, + "valuePreserved": true + }, + { + "after": { + "elements": [ + { + "object": "AreaLine", + "subElements": [ + "Edge1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Touched", + "Invalid" + ], + "statusString": "Cannot calculate area", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "afterObjects": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaCylinder", + "typeId": "Part::Cylinder" + }, + { + "name": "AreaPoint", + "typeId": "Part::Feature" + }, + { + "name": "AreaLine", + "typeId": "Part::Feature" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "assignmentException": null, + "before": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "beforeObjects": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaCylinder", + "typeId": "Part::Cylinder" + }, + { + "name": "AreaPoint", + "typeId": "Part::Feature" + }, + { + "name": "AreaLine", + "typeId": "Part::Feature" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "expectedDiagnostic": "Cannot calculate area", + "id": "unsupported-line", + "objectsPreserved": true, + "recomputeException": null, + "recomputeResult": true, + "recovered": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "recoveredExactly": true, + "source": { + "name": "AreaLine", + "shapeType": "Edge", + "subElement": "Edge1", + "typeId": "Part::Feature" + }, + "valuePreserved": true + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "initial": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "input": { + "name": "Elements", + "typeId": "App::PropertyLinkSubList" + }, + "object": { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + }, + "property": { + "name": "Area", + "typeId": "App::PropertyArea" + }, + "schemaVersion": 1, + "status": "pass", + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 1, + "name": "property-area-cancel" + }, + "afterAbort": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Touched" + ], + "statusString": "Touched", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "afterRecompute": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "before": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 10, + "raw": "10.0 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "edited": { + "elements": [ + { + "object": "AreaCylinder", + "subElements": [ + "Face1" + ] + } + ], + "numeric": 75.398223877, + "raw": "75.39822387695312 mm^2", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "objectsAfter": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaCylinder", + "typeId": "Part::Cylinder" + }, + { + "name": "AreaPoint", + "typeId": "Part::Feature" + }, + { + "name": "AreaLine", + "typeId": "Part::Feature" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "objectsBefore": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaCylinder", + "typeId": "Part::Cylinder" + }, + { + "name": "AreaPoint", + "typeId": "Part::Feature" + }, + { + "name": "AreaLine", + "typeId": "Part::Feature" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "objectsRestored": true, + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "restored": true, + "undoMode": 1 + } +} diff --git a/config/freecad-property-area-inventory.json b/config/freecad-property-area-inventory.json new file mode 100644 index 0000000..e17ee92 --- /dev/null +++ b/config/freecad-property-area-inventory.json @@ -0,0 +1,108 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyArea", + "recordCount": 1, + "records": [ + { + "objectTypeId": "Measure::MeasureArea", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Area", + "group": "Measurement", + "status": [ + 24, + 27 + ], + "normalizedStatus": [ + "PropReadOnly", + "PropOutput" + ], + "defaultRaw": "0.0 mm^2", + "valueModel": { + "kind": "quantity", + "dimension": "length^2", + "defaultValue": 0, + "defaultUnit": "mm^2", + "derived": true, + "writable": false + }, + "inputs": [ + { + "propertyName": "Elements", + "typeId": "App::PropertyLinkSubList", + "group": "Measurement", + "defaultValue": [], + "scope": "Global", + "allowExternal": true, + "cardinality": "one-or-more" + } + ], + "dependencies": [ + { + "sourceProperty": "Elements", + "targetProperty": "Area", + "relation": "link-sub-list", + "effect": "immediate-recompute-on-change" + } + ], + "applicability": { + "selectionMustBeNonEmpty": true, + "everyElementMustBeValid": true, + "supportedMeasureElementTypes": [ + "PLANE", + "CYLINDER", + "SURFACE", + "VOLUME" + ], + "unsupportedMeasureElementTypes": [ + "INVALID", + "POINT", + "LINE", + "CURVE" + ], + "externalDocumentElementsAllowed": true + }, + "execution": { + "aggregation": "sum-area", + "resultProperty": "Area", + "invalidGeometryDiagnostic": "Cannot calculate area", + "shape": "not-applicable-derived-measurement" + } + } + ], + "provenance": { + "runtime": { + "path": ".cache/freecad/reference-desktop.json", + "bytes": 2298709, + "sha256": "082400ec7379e8efc2af16709032d45890d7092277967b714acb05761fd1c2a7" + }, + "sources": [ + { + "path": ".cache/freecad/FreeCAD/src/Mod/Measure/App/MeasureArea.cpp", + "bytes": 5328, + "sha256": "86506348c36a9a440881da0b605a74c38079c3c606ca6f7660df53665eda5281" + }, + { + "path": ".cache/freecad/FreeCAD/src/Mod/Measure/App/MeasureArea.h", + "bytes": 3125, + "sha256": "5bae7a21e82e73490a8b63cc234f1bd17e019df0d7cfcf7aa23fe91d2dc13305" + } + ] + }, + "classification": "opaque-fcstd-proxy", + "nextPhases": [ + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I" + ] +} diff --git a/config/freecad-property-area-mutation.json b/config/freecad-property-area-mutation.json new file mode 100644 index 0000000..67adeb4 --- /dev/null +++ b/config/freecad-property-area-mutation.json @@ -0,0 +1,342 @@ +{ + "baselineId": "freecad-1.1.1-property-area-mutation", + "before": { + "editorMode": [ + "ReadOnly" + ], + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ], + "typeId": "Part::Box" + } + ], + "mustExecute": false, + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "statusString": "Valid", + "value": { + "numeric": 10, + "raw": "10.0 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + } + }, + "classification": { + "derivedValueChanged": true, + "derivedValueRestored": true, + "geometry": "source-shapes-preserved-derived-measurement-has-no-shape", + "inputChanged": true, + "inputRestored": true, + "semanticStateRestored": true, + "sourceGeometryPreserved": true + }, + "document": { + "objectsBefore": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaCylinder", + "typeId": "Part::Cylinder" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "objectsPreserved": true, + "objectsRestored": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaCylinder", + "typeId": "Part::Cylinder" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ] + }, + "edited": { + "editorMode": [ + "ReadOnly" + ], + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1", + "Face2" + ], + "typeId": "Part::Box" + }, + { + "object": "AreaCylinder", + "subElements": [ + "Face1" + ], + "typeId": "Part::Cylinder" + } + ], + "mustExecute": false, + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "statusString": "Valid", + "value": { + "numeric": 95.398223877, + "raw": "95.39822387695312 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + } + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "input": { + "name": "Elements", + "typeId": "App::PropertyLinkSubList" + }, + "object": { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + }, + "property": { + "name": "Area", + "typeId": "App::PropertyArea" + }, + "recompute": { + "edit": 1, + "initial": 3, + "restore": 1 + }, + "restored": { + "editorMode": [ + "ReadOnly" + ], + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ], + "typeId": "Part::Box" + } + ], + "mustExecute": false, + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "statusString": "Valid", + "value": { + "numeric": 10, + "raw": "10.0 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + } + }, + "schemaVersion": 1, + "sources": { + "before": [ + { + "area": 160, + "bounds": [ + 0, + 0, + 0, + 10, + 5, + 2 + ], + "edges": 12, + "faces": 6, + "name": "AreaBox", + "shapeType": "Solid", + "solids": 1, + "typeId": "Part::Box", + "valid": true, + "vertices": 8, + "volume": 100 + }, + { + "area": 131.946891451, + "bounds": [ + -3, + -3, + 0, + 3, + 3, + 4 + ], + "edges": 3, + "faces": 3, + "name": "AreaCylinder", + "shapeType": "Solid", + "solids": 1, + "typeId": "Part::Cylinder", + "valid": true, + "vertices": 2, + "volume": 113.097335529 + } + ], + "edited": [ + { + "area": 160, + "bounds": [ + 0, + 0, + 0, + 10, + 5, + 2 + ], + "edges": 12, + "faces": 6, + "name": "AreaBox", + "shapeType": "Solid", + "solids": 1, + "typeId": "Part::Box", + "valid": true, + "vertices": 8, + "volume": 100 + }, + { + "area": 131.946891451, + "bounds": [ + -3, + -3, + 0, + 3, + 3, + 4 + ], + "edges": 3, + "faces": 3, + "name": "AreaCylinder", + "shapeType": "Solid", + "solids": 1, + "typeId": "Part::Cylinder", + "valid": true, + "vertices": 2, + "volume": 113.097335529 + } + ], + "preserved": true, + "restored": [ + { + "area": 160, + "bounds": [ + 0, + 0, + 0, + 10, + 5, + 2 + ], + "edges": 12, + "faces": 6, + "name": "AreaBox", + "shapeType": "Solid", + "solids": 1, + "typeId": "Part::Box", + "valid": true, + "vertices": 8, + "volume": 100 + }, + { + "area": 131.946891451, + "bounds": [ + -3, + -3, + 0, + 3, + 3, + 4 + ], + "edges": 3, + "faces": 3, + "name": "AreaCylinder", + "shapeType": "Solid", + "solids": 1, + "typeId": "Part::Cylinder", + "valid": true, + "vertices": 2, + "volume": 113.097335529 + } + ] + }, + "status": "pass", + "touchedAfterEdit": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1", + "Face2" + ], + "typeId": "Part::Box" + }, + { + "object": "AreaCylinder", + "subElements": [ + "Face1" + ], + "typeId": "Part::Cylinder" + } + ], + "mustExecute": false, + "objectState": [ + "Touched" + ], + "value": { + "numeric": 95.398223877, + "raw": "95.39822387695312 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + } + }, + "touchedAfterRestore": { + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ], + "typeId": "Part::Box" + } + ], + "mustExecute": false, + "objectState": [ + "Touched" + ], + "value": { + "numeric": 10, + "raw": "10.0 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + } + } +} diff --git a/config/freecad-property-area-promotion.json b/config/freecad-property-area-promotion.json new file mode 100644 index 0000000..39bbf14 --- /dev/null +++ b/config/freecad-property-area-promotion.json @@ -0,0 +1,71 @@ +{ + "schemaVersion": 1, + "status": "pass", + "taskId": "PROP-app-propertyarea-I", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyArea", + "recordCount": 1, + "phaseEvidence": { + "A": [ + "config/freecad-property-area-inventory.json", + "check:freecad-property-area-inventory" + ], + "B": [ + "config/freecad-property-area-success.json", + "check:freecad-property-area-success" + ], + "C": [ + "config/freecad-property-area-failure.json", + "check:freecad-property-area-failure" + ], + "D": [ + "config/freecad-property-area-mutation.json", + "check:freecad-property-area-mutation" + ], + "E": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "tests/propertyAreaFacade.test.ts", + "test:freecad-property-area-facade" + ], + "F": [ + "tests/propertyAreaTransaction.test.ts", + "test:freecad-property-area-transaction" + ], + "G": [ + "config/freecad-property-area-roundtrip.json", + "check:freecad-property-area-roundtrip" + ], + "H": [ + "config/chrome-property-area-verification.json", + "check:chrome-property-area" + ] + }, + "promotion": { + "from": "opaque-fcstd-proxy", + "to": "native-editable-codec", + "facadeValueModel": "read-only-derived-mm^2-with-link-sub-list-input", + "inputType": "App::PropertyLinkSubList", + "fcstdAreaElement": "Float", + "fcstdElementsElement": "LinkSubList", + "nativeRoundTripArea": 20, + "browserRoundTripArea": 0, + "browserRoundTripElementCount": 0, + "sourceGeometryPreserved": true, + "zeroUnknownDrift": true + }, + "exactBlockerSync": { + "nativeEditableTypes": 30, + "nativeEditableRecords": 4361, + "opaqueTypes": 50, + "opaqueRecords": 466, + "exactPromotionReady": false, + "exactBlocker": "50 runtime property types and 466 records remain opaque-only; complete native document and property semantics" + }, + "systemExact": false, + "generatedAt": "2026-08-17T08:49:33.776Z" +} diff --git a/config/freecad-property-area-roundtrip.json b/config/freecad-property-area-roundtrip.json new file mode 100644 index 0000000..47e8856 --- /dev/null +++ b/config/freecad-property-area-roundtrip.json @@ -0,0 +1,305 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-area-roundtrip", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "archives": { + "nativeInitial": { + "path": ".cache/freecad/property-area-roundtrip/native-initial.FCStd", + "bytes": 2635, + "sha256": "2c50a95d69ab8069be75a92dbd35531cb6089ce2bb2fe420cff1e8e4ca523bd4" + }, + "webEdited": { + "path": ".cache/freecad/property-area-roundtrip/web-edited.FCStd", + "bytes": 2523, + "sha256": "3b37fb932987756ea69c4f6ee784056ade0625f7c6504c11fb59bca55b95b595" + }, + "nativeResaved": { + "path": ".cache/freecad/property-area-roundtrip/native-resaved.FCStd", + "bytes": 2650, + "sha256": "09b15d8d030c15dddc20f9a89b8a1244ecd2e279eb973ab2b572e382dcc062d0" + } + }, + "nativeInitial": { + "measure": { + "area": { + "numeric": 10, + "raw": "10.0 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "areaTypeId": "App::PropertyArea", + "editorMode": [ + "ReadOnly" + ], + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1" + ], + "typeId": "Part::Box" + } + ], + "elementsTypeId": "App::PropertyLinkSubList", + "name": "AreaProbe", + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "Measure::MeasureArea" + }, + "objectSet": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "source": { + "area": 160, + "bounds": [ + 0, + 0, + 0, + 10, + 5, + 2 + ], + "edges": 12, + "faces": 6, + "height": 2, + "length": 10, + "name": "AreaBox", + "shapeType": "Solid", + "solids": 1, + "typeId": "Part::Box", + "valid": true, + "vertices": 8, + "volume": 100, + "width": 5 + } + }, + "web": { + "before": { + "area": { + "name": "Area", + "typeId": "App::PropertyArea", + "element": "Float", + "value": "10.0000000000000000", + "nativeStatus": 150994944, + "statusNames": [ + "PropReadOnly", + "PropOutput" + ] + }, + "elements": { + "name": "Elements", + "typeId": "App::PropertyLinkSubList", + "element": "LinkSubList", + "value": "{\"schemaVersion\":1,\"entries\":[{\"objectId\":\"AreaBox\",\"subElement\":\"Face1\"}]}", + "linkSubs": [ + { + "objectId": "AreaBox", + "subElement": "Face1" + } + ] + } + }, + "after": { + "area": { + "name": "Area", + "typeId": "App::PropertyArea", + "element": "Float", + "value": "20", + "nativeStatus": 150994944, + "statusNames": [ + "PropReadOnly", + "PropOutput" + ] + }, + "elements": { + "name": "Elements", + "typeId": "App::PropertyLinkSubList", + "element": "LinkSubList", + "value": "{\"schemaVersion\":1,\"entries\":[{\"objectId\":\"AreaBox\",\"subElement\":\"Face1\"},{\"objectId\":\"AreaBox\",\"subElement\":\"Face2\"}]}", + "linkSubs": [ + { + "objectId": "AreaBox", + "subElement": "Face1" + }, + { + "objectId": "AreaBox", + "subElement": "Face2" + } + ] + } + }, + "objectSetPreserved": true, + "semanticObjectsPreserved": true, + "opaquePathsPreserved": 1, + "opaqueEntriesPreserved": true + }, + "nativeAfter": { + "reopened": { + "measure": { + "area": { + "numeric": 20, + "raw": "20.0 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "areaTypeId": "App::PropertyArea", + "editorMode": [ + "ReadOnly" + ], + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1", + "Face2" + ], + "typeId": "Part::Box" + } + ], + "elementsTypeId": "App::PropertyLinkSubList", + "name": "AreaProbe", + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "Measure::MeasureArea" + }, + "objectSet": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "source": { + "area": 160, + "bounds": [ + 0, + 0, + 0, + 10, + 5, + 2 + ], + "edges": 12, + "faces": 6, + "height": 2, + "length": 10, + "name": "AreaBox", + "shapeType": "Solid", + "solids": 1, + "typeId": "Part::Box", + "valid": true, + "vertices": 8, + "volume": 100, + "width": 5 + } + }, + "resaved": { + "measure": { + "area": { + "numeric": 20, + "raw": "20.0 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + }, + "areaTypeId": "App::PropertyArea", + "editorMode": [ + "ReadOnly" + ], + "elements": [ + { + "object": "AreaBox", + "subElements": [ + "Face1", + "Face2" + ], + "typeId": "Part::Box" + } + ], + "elementsTypeId": "App::PropertyLinkSubList", + "name": "AreaProbe", + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "Measure::MeasureArea" + }, + "objectSet": [ + { + "name": "AreaBox", + "typeId": "Part::Box" + }, + { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + } + ], + "source": { + "area": 160, + "bounds": [ + 0, + 0, + 0, + 10, + 5, + 2 + ], + "edges": 12, + "faces": 6, + "height": 2, + "length": 10, + "name": "AreaBox", + "shapeType": "Solid", + "solids": 1, + "typeId": "Part::Box", + "valid": true, + "vertices": 8, + "volume": 100, + "width": 5 + } + } + }, + "classification": { + "webArea": 20, + "webElementCount": 2, + "reopenedArea": 20, + "resavedArea": 20, + "nativeOutputMatches": true, + "sourceGeometryPreserved": true, + "unknownSemanticDrift": false, + "zeroUnknownDrift": true + } +} diff --git a/config/freecad-property-area-success.json b/config/freecad-property-area-success.json new file mode 100644 index 0000000..95958c4 --- /dev/null +++ b/config/freecad-property-area-success.json @@ -0,0 +1,315 @@ +{ + "baselineId": "freecad-1.1.1-property-area-success", + "cases": [ + { + "areaTypeId": "App::PropertyArea", + "editorMode": [ + "ReadOnly" + ], + "elements": [], + "elementsTypeId": "App::PropertyLinkSubList", + "expectedArea": 0, + "id": "empty-default", + "object": { + "name": "AreaProbe", + "state": [ + "Up-to-date" + ], + "status": "Valid", + "typeId": "Measure::MeasureArea" + }, + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "value": { + "numeric": 0, + "raw": "0.0 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + } + }, + { + "areaTypeId": "App::PropertyArea", + "editorMode": [ + "ReadOnly" + ], + "elements": [ + { + "area": 10, + "edges": 4, + "faces": 1, + "object": "AreaBox", + "shapeNull": false, + "shapeType": "Face", + "shapeValid": true, + "subElement": "Face1", + "vertices": 4 + } + ], + "elementsTypeId": "App::PropertyLinkSubList", + "expectedArea": 10, + "id": "planar-face", + "object": { + "name": "AreaProbe", + "state": [ + "Up-to-date" + ], + "status": "Valid", + "typeId": "Measure::MeasureArea" + }, + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "value": { + "numeric": 10, + "raw": "10.0 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + } + }, + { + "areaTypeId": "App::PropertyArea", + "editorMode": [ + "ReadOnly" + ], + "elements": [ + { + "area": 75.398223686, + "edges": 3, + "faces": 1, + "object": "AreaCylinder", + "shapeNull": false, + "shapeType": "Face", + "shapeValid": true, + "subElement": "Face1", + "vertices": 2 + } + ], + "elementsTypeId": "App::PropertyLinkSubList", + "expectedArea": 75.398223686, + "id": "cylindrical-face", + "object": { + "name": "AreaProbe", + "state": [ + "Up-to-date" + ], + "status": "Valid", + "typeId": "Measure::MeasureArea" + }, + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "value": { + "numeric": 75.398223877, + "raw": "75.39822387695312 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + } + }, + { + "areaTypeId": "App::PropertyArea", + "editorMode": [ + "ReadOnly" + ], + "elements": [ + { + "area": 50.265482457, + "edges": 3, + "faces": 1, + "object": "AreaSphere", + "shapeNull": false, + "shapeType": "Face", + "shapeValid": true, + "subElement": "Face1", + "vertices": 2 + } + ], + "elementsTypeId": "App::PropertyLinkSubList", + "expectedArea": 50.265482457, + "id": "surface-face", + "object": { + "name": "AreaProbe", + "state": [ + "Up-to-date" + ], + "status": "Valid", + "typeId": "Measure::MeasureArea" + }, + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "value": { + "numeric": 50.265483856, + "raw": "50.26548385620117 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + } + }, + { + "areaTypeId": "App::PropertyArea", + "editorMode": [ + "ReadOnly" + ], + "elements": [ + { + "area": 160, + "edges": 12, + "faces": 6, + "object": "AreaBox", + "shapeNull": false, + "shapeType": "Solid", + "shapeValid": true, + "subElement": "", + "vertices": 8 + } + ], + "elementsTypeId": "App::PropertyLinkSubList", + "expectedArea": 160, + "id": "solid-volume", + "object": { + "name": "AreaProbe", + "state": [ + "Up-to-date" + ], + "status": "Valid", + "typeId": "Measure::MeasureArea" + }, + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "value": { + "numeric": 160, + "raw": "160.0 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + } + }, + { + "areaTypeId": "App::PropertyArea", + "editorMode": [ + "ReadOnly" + ], + "elements": [ + { + "area": 10, + "edges": 4, + "faces": 1, + "object": "AreaBox", + "shapeNull": false, + "shapeType": "Face", + "shapeValid": true, + "subElement": "Face1", + "vertices": 4 + }, + { + "area": 10, + "edges": 4, + "faces": 1, + "object": "AreaBox", + "shapeNull": false, + "shapeType": "Face", + "shapeValid": true, + "subElement": "Face2", + "vertices": 4 + }, + { + "area": 75.398223686, + "edges": 3, + "faces": 1, + "object": "AreaCylinder", + "shapeNull": false, + "shapeType": "Face", + "shapeValid": true, + "subElement": "Face1", + "vertices": 2 + } + ], + "elementsTypeId": "App::PropertyLinkSubList", + "expectedArea": 95.398223686, + "id": "multi-element-sum", + "object": { + "name": "AreaProbe", + "state": [ + "Up-to-date" + ], + "status": "Valid", + "typeId": "Measure::MeasureArea" + }, + "propertyStatus": [ + "24", + "27" + ], + "shape": { + "applicable": false + }, + "value": { + "numeric": 95.398223877, + "raw": "95.39822387695312 mm^2", + "unit": "Unit: mm^2 (2,0,0,0,0,0,0,0) [Area]" + } + } + ], + "diagnostics": { + "documentObjectCount": 4, + "exception": null + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "input": { + "group": "Measurement", + "name": "Elements", + "typeId": "App::PropertyLinkSubList" + }, + "object": { + "name": "AreaProbe", + "typeId": "Measure::MeasureArea" + }, + "property": { + "group": "Measurement", + "name": "Area", + "typeId": "App::PropertyArea" + }, + "schemaVersion": 1, + "sources": [ + { + "name": "AreaBox", + "state": [ + "Up-to-date" + ], + "status": "Valid", + "typeId": "Part::Box" + }, + { + "name": "AreaCylinder", + "state": [ + "Up-to-date" + ], + "status": "Valid", + "typeId": "Part::Cylinder" + }, + { + "name": "AreaSphere", + "state": [ + "Up-to-date" + ], + "status": "Valid", + "typeId": "Part::Sphere" + } + ], + "status": "pass" +} diff --git a/config/freecad-property-boollist-failure.json b/config/freecad-property-boollist-failure.json new file mode 100644 index 0000000..9184995 --- /dev/null +++ b/config/freecad-property-boollist-failure.json @@ -0,0 +1,729 @@ +{ + "baselineId": "freecad-1.1.1-property-boollist-failure", + "cancellationBoundary": { + "classification": "synchronous-property-setter-and-link-extension", + "reason": "no-native-cancel-hook", + "replacement": "abort-active-document-transaction", + "supported": false + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "links": [ + { + "directWrite": { + "after": [ + true, + true + ], + "exception": { + "message": "Object attribute 'VisibilityList' is read-only", + "type": "AttributeError" + }, + "preserved": true, + "requested": [ + false, + true + ] + }, + "editorMode": [ + "Hidden" + ], + "initial": [ + true, + true + ], + "invalidElement": { + "after": [ + true, + true + ], + "name": "MissingElement", + "preserved": true, + "result": -1 + }, + "objectState": [ + "Up-to-date" + ], + "objectTypeId": "App::Link", + "objectsAfter": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkProbe", + "typeId": "App::Link" + } + ], + "objectsBefore": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkProbe", + "typeId": "App::Link" + } + ], + "objectsPreserved": true, + "propertyTypeId": "App::PropertyBoolList", + "status": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "statusString": "Valid", + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 2, + "name": "property-boollist-link-cancel" + }, + "afterAbort": [ + true, + true + ], + "before": [ + true, + true + ], + "edited": [ + false, + true + ], + "hideResult": 1, + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "recoveryRecomputeResult": true, + "restored": true, + "stateAfterAbort": [ + "Touched" + ], + "stateAfterRecovery": [ + "Up-to-date" + ], + "statusAfterAbort": "Touched", + "statusAfterRecovery": "Valid" + } + }, + { + "directWrite": { + "after": [ + true, + true + ], + "exception": { + "message": "Object attribute 'VisibilityList' is read-only", + "type": "AttributeError" + }, + "preserved": true, + "requested": [ + false, + true + ] + }, + "editorMode": [ + "Hidden" + ], + "initial": [ + true, + true + ], + "invalidElement": { + "after": [ + true, + true + ], + "name": "MissingElement", + "preserved": true, + "result": -1 + }, + "objectState": [ + "Up-to-date" + ], + "objectTypeId": "App::LinkGroup", + "objectsAfter": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupProbe", + "typeId": "App::LinkGroup" + } + ], + "objectsBefore": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupProbe", + "typeId": "App::LinkGroup" + } + ], + "objectsPreserved": true, + "propertyTypeId": "App::PropertyBoolList", + "status": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "statusString": "Valid", + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 3, + "name": "property-boollist-link-cancel" + }, + "afterAbort": [ + true, + true + ], + "before": [ + true, + true + ], + "edited": [ + false, + true + ], + "hideResult": 1, + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "recoveryRecomputeResult": true, + "restored": true, + "stateAfterAbort": [ + "Touched" + ], + "stateAfterRecovery": [ + "Up-to-date" + ], + "statusAfterAbort": "Touched", + "statusAfterRecovery": "Valid" + } + }, + { + "directWrite": { + "after": [ + true, + true + ], + "exception": { + "message": "Object attribute 'VisibilityList' is read-only", + "type": "AttributeError" + }, + "preserved": true, + "requested": [ + false, + true + ] + }, + "editorMode": [ + "Hidden" + ], + "initial": [ + true, + true + ], + "invalidElement": { + "after": [ + true, + true + ], + "name": "MissingElement", + "preserved": true, + "result": -1 + }, + "objectState": [ + "Up-to-date" + ], + "objectTypeId": "App::LinkGroupPython", + "objectsAfter": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupPythonProbe", + "typeId": "App::LinkGroupPython" + } + ], + "objectsBefore": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupPythonProbe", + "typeId": "App::LinkGroupPython" + } + ], + "objectsPreserved": true, + "propertyTypeId": "App::PropertyBoolList", + "status": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "statusString": "Valid", + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 4, + "name": "property-boollist-link-cancel" + }, + "afterAbort": [ + true, + true + ], + "before": [ + true, + true + ], + "edited": [ + false, + true + ], + "hideResult": 1, + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "recoveryRecomputeResult": true, + "restored": true, + "stateAfterAbort": [ + "Touched" + ], + "stateAfterRecovery": [ + "Up-to-date" + ], + "statusAfterAbort": "Touched", + "statusAfterRecovery": "Valid" + } + }, + { + "directWrite": { + "after": [ + true, + true + ], + "exception": { + "message": "Object attribute 'VisibilityList' is read-only", + "type": "AttributeError" + }, + "preserved": true, + "requested": [ + false, + true + ] + }, + "editorMode": [ + "Hidden" + ], + "initial": [ + true, + true + ], + "invalidElement": { + "after": [ + true, + true + ], + "name": "MissingElement", + "preserved": true, + "result": -1 + }, + "objectState": [ + "Up-to-date" + ], + "objectTypeId": "App::LinkPython", + "objectsAfter": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkPythonProbe", + "typeId": "App::LinkPython" + } + ], + "objectsBefore": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkPythonProbe", + "typeId": "App::LinkPython" + } + ], + "objectsPreserved": true, + "propertyTypeId": "App::PropertyBoolList", + "status": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "statusString": "Valid", + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 5, + "name": "property-boollist-link-cancel" + }, + "afterAbort": [ + true, + true + ], + "before": [ + true, + true + ], + "edited": [ + false, + true + ], + "hideResult": 1, + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "recoveryRecomputeResult": true, + "restored": true, + "stateAfterAbort": [ + "Touched" + ], + "stateAfterRecovery": [ + "Up-to-date" + ], + "statusAfterAbort": "Touched", + "statusAfterRecovery": "Valid" + } + } + ], + "propertyType": "App::PropertyBoolList", + "schemaVersion": 1, + "status": "pass", + "writable": { + "acceptedCoercions": [ + { + "after": [ + true + ], + "afterObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + false + ], + "beforeObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "scalar-integer", + "objectsPreserved": true, + "requested": "7" + }, + { + "after": [ + true, + false, + false, + false, + true + ], + "afterObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + false + ], + "beforeObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "bitstring", + "objectsPreserved": true, + "requested": "'10201'" + } + ], + "disabled": { + "after": [ + false + ], + "afterObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + false + ], + "beforeObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "classification": "editor-read-only-and-python-immutable", + "editorMode": [ + "ReadOnly" + ], + "exception": { + "message": "Object attribute 'BoolList' is read-only", + "type": "AttributeError" + }, + "objectsPreserved": true, + "requested": [ + true, + false + ], + "restoredEditorMode": [], + "restoredStatus": [], + "status": [ + "Immutable", + "ReadOnly" + ], + "valuePreserved": true + }, + "documentIntegrity": { + "finalObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "initialObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectsPreserved": true + }, + "failures": [ + { + "after": [ + false + ], + "afterObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + false + ], + "beforeObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type in list must be bool or int, not NoneType", + "type": "TypeError" + }, + "id": "none", + "objectsPreserved": true, + "polluted": false, + "requested": "None", + "valuePreserved": true + }, + { + "after": [ + false + ], + "afterObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + false + ], + "beforeObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type in list must be bool or int, not float", + "type": "TypeError" + }, + "id": "float-item", + "objectsPreserved": true, + "polluted": false, + "requested": "[True, 1.5]", + "valuePreserved": true + }, + { + "after": [ + false + ], + "afterObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + false + ], + "beforeObjects": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type in list must be bool or int, not str", + "type": "TypeError" + }, + "id": "string-item", + "objectsPreserved": true, + "polluted": false, + "requested": "[False, 'bad']", + "valuePreserved": true + } + ], + "initial": [ + false + ], + "object": { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + }, + "property": { + "name": "BoolList", + "typeId": "App::PropertyBoolList" + }, + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 1, + "name": "property-boollist-cancel" + }, + "afterAbort": [ + false + ], + "before": [ + false + ], + "edited": [ + true, + false, + true + ], + "objectsAfter": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectsBefore": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectsRestored": true, + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "restored": true, + "undoMode": 1 + } + } +} diff --git a/config/freecad-property-boollist-inventory.json b/config/freecad-property-boollist-inventory.json new file mode 100644 index 0000000..a95a61c --- /dev/null +++ b/config/freecad-property-boollist-inventory.json @@ -0,0 +1,190 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyBoolList", + "recordCount": 7, + "records": [ + { + "objectTypeId": "App::FeatureTest", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "BoolList", + "group": "", + "status": [], + "defaultValue": [ + false + ], + "valueModel": { + "kind": "boolean-list", + "writable": true, + "elementType": "bool", + "cardinality": "variable" + }, + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "App::FeatureTest", + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "App::FeatureTestException", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "BoolList", + "group": "", + "status": [], + "defaultValue": [ + false + ], + "valueModel": { + "kind": "boolean-list", + "writable": true, + "elementType": "bool", + "cardinality": "variable" + }, + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "App::FeatureTestException", + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "App::Link", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "VisibilityList", + "group": " Link", + "status": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "defaultValue": [], + "valueModel": { + "kind": "boolean-list", + "writable": false, + "elementType": "bool", + "cardinality": "variable" + }, + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "App::Link", + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "App::LinkGroup", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "VisibilityList", + "group": " Link", + "status": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "defaultValue": [], + "valueModel": { + "kind": "boolean-list", + "writable": false, + "elementType": "bool", + "cardinality": "variable" + }, + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "App::LinkGroup", + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "App::LinkGroupPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "VisibilityList", + "group": " Link", + "status": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "defaultValue": [], + "valueModel": { + "kind": "boolean-list", + "writable": false, + "elementType": "bool", + "cardinality": "variable" + }, + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "App::LinkGroupPython", + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "App::LinkPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "VisibilityList", + "group": " Link", + "status": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "defaultValue": [], + "valueModel": { + "kind": "boolean-list", + "writable": false, + "elementType": "bool", + "cardinality": "variable" + }, + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "App::LinkPython", + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "Surface::GeomFillSurface", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "ReversedList", + "group": "", + "status": [], + "defaultValue": [ + false + ], + "valueModel": { + "kind": "boolean-list", + "writable": true, + "elementType": "bool", + "cardinality": "variable" + }, + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "Surface::GeomFillSurface", + "source": "Document.supportedTypes runtime inventory" + } + } + ], + "source": { + "path": ".cache/freecad/reference-desktop.json", + "bytes": 2298709, + "sha256": "082400ec7379e8efc2af16709032d45890d7092277967b714acb05761fd1c2a7" + }, + "classification": "opaque-fcstd-proxy", + "nextPhases": [ + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I" + ] +} diff --git a/config/freecad-property-boollist-mutation.json b/config/freecad-property-boollist-mutation.json new file mode 100644 index 0000000..81f1934 --- /dev/null +++ b/config/freecad-property-boollist-mutation.json @@ -0,0 +1,1470 @@ +{ + "baselineId": "freecad-1.1.1-property-boollist-mutation", + "caseCount": 7, + "cases": [ + { + "before": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "FeatureTestProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false + ] + }, + "editRecompute": true, + "edited": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "FeatureTestProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + false, + true + ] + }, + "hostExecution": "normal", + "mode": "direct-native-property-setter", + "objectName": "FeatureTestProbe", + "objectTypeId": "App::FeatureTest", + "objectsRestored": true, + "propertyName": "BoolList", + "restoreRecompute": true, + "restored": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "FeatureTestProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false + ] + }, + "shapeRestored": true, + "touchedAfterEdit": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "FeatureTestProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + true, + false, + true + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "FeatureTestProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + false + ] + }, + "valueRestored": true + }, + { + "before": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "FeatureTestExceptionProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false + ] + }, + "editRecompute": true, + "edited": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "FeatureTestExceptionProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + true, + false, + true + ] + }, + "hostExecution": "intrinsic-test-exception", + "mode": "direct-native-property-setter", + "objectName": "FeatureTestExceptionProbe", + "objectTypeId": "App::FeatureTestException", + "objectsRestored": true, + "propertyName": "BoolList", + "restoreRecompute": true, + "restored": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "FeatureTestExceptionProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + false + ] + }, + "shapeRestored": true, + "touchedAfterEdit": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "FeatureTestExceptionProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + true, + false, + true + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "FeatureTestExceptionProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + false + ] + }, + "valueRestored": true + }, + { + "before": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "GeomFillSurfaceProbe", + "typeId": "Surface::GeomFillSurface" + }, + { + "name": "Boundary1", + "typeId": "Part::Feature" + }, + { + "name": "Boundary2", + "typeId": "Part::Feature" + }, + { + "name": "Boundary3", + "typeId": "Part::Feature" + }, + { + "name": "Boundary4", + "typeId": "Part::Feature" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": true, + "area": 100.0, + "bounds": [ + 0.0, + 0.0, + 0.0, + 10.0, + 10.0, + 0.0 + ], + "brepSha256": "ea7baeb09dfba0e28fbad95fd848846544ac48dae846b00f1d84d24b0bc0ace5", + "edges": 4, + "faces": 1, + "isNull": false, + "shapeType": "Face", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + false + ] + }, + "editRecompute": true, + "edited": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "GeomFillSurfaceProbe", + "typeId": "Surface::GeomFillSurface" + }, + { + "name": "Boundary1", + "typeId": "Part::Feature" + }, + { + "name": "Boundary2", + "typeId": "Part::Feature" + }, + { + "name": "Boundary3", + "typeId": "Part::Feature" + }, + { + "name": "Boundary4", + "typeId": "Part::Feature" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": true, + "area": 100.0, + "bounds": [ + 0.0, + 0.0, + 0.0, + 10.0, + 10.0, + 0.0 + ], + "brepSha256": "f6c587bb853fe39ad50a98d03d04f5c8347b52d4e46c751b336b8cfd8d10c637", + "edges": 4, + "faces": 1, + "isNull": false, + "shapeType": "Face", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + true, + false, + false, + false + ] + }, + "hostExecution": "normal", + "mode": "direct-native-property-setter", + "objectName": "GeomFillSurfaceProbe", + "objectTypeId": "Surface::GeomFillSurface", + "objectsRestored": true, + "propertyName": "ReversedList", + "restoreRecompute": true, + "restored": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "GeomFillSurfaceProbe", + "typeId": "Surface::GeomFillSurface" + }, + { + "name": "Boundary1", + "typeId": "Part::Feature" + }, + { + "name": "Boundary2", + "typeId": "Part::Feature" + }, + { + "name": "Boundary3", + "typeId": "Part::Feature" + }, + { + "name": "Boundary4", + "typeId": "Part::Feature" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": true, + "area": 100.0, + "bounds": [ + 0.0, + 0.0, + 0.0, + 10.0, + 10.0, + 0.0 + ], + "brepSha256": "ea7baeb09dfba0e28fbad95fd848846544ac48dae846b00f1d84d24b0bc0ace5", + "edges": 4, + "faces": 1, + "isNull": false, + "shapeType": "Face", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + false + ] + }, + "shapeRestored": true, + "touchedAfterEdit": { + "editorMode": [], + "mustExecute": true, + "objectSet": [ + { + "name": "GeomFillSurfaceProbe", + "typeId": "Surface::GeomFillSurface" + }, + { + "name": "Boundary1", + "typeId": "Part::Feature" + }, + { + "name": "Boundary2", + "typeId": "Part::Feature" + }, + { + "name": "Boundary3", + "typeId": "Part::Feature" + }, + { + "name": "Boundary4", + "typeId": "Part::Feature" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": true, + "area": 100.0, + "bounds": [ + 0.0, + 0.0, + 0.0, + 10.0, + 10.0, + 0.0 + ], + "brepSha256": "ea7baeb09dfba0e28fbad95fd848846544ac48dae846b00f1d84d24b0bc0ace5", + "edges": 4, + "faces": 1, + "isNull": false, + "shapeType": "Face", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Touched", + "value": [ + true, + false, + false, + false + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "mustExecute": true, + "objectSet": [ + { + "name": "GeomFillSurfaceProbe", + "typeId": "Surface::GeomFillSurface" + }, + { + "name": "Boundary1", + "typeId": "Part::Feature" + }, + { + "name": "Boundary2", + "typeId": "Part::Feature" + }, + { + "name": "Boundary3", + "typeId": "Part::Feature" + }, + { + "name": "Boundary4", + "typeId": "Part::Feature" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": true, + "area": 100.0, + "bounds": [ + 0.0, + 0.0, + 0.0, + 10.0, + 10.0, + 0.0 + ], + "brepSha256": "f6c587bb853fe39ad50a98d03d04f5c8347b52d4e46c751b336b8cfd8d10c637", + "edges": 4, + "faces": 1, + "isNull": false, + "shapeType": "Face", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Touched", + "value": [ + false + ] + }, + "valueRestored": true + }, + { + "before": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkProbe", + "typeId": "App::Link" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "editRecompute": true, + "edited": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkProbe", + "typeId": "App::Link" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false, + true + ] + }, + "hideResult": 1, + "mode": "link-base-extension-element-visibility", + "objectName": "LinkProbe", + "objectTypeId": "App::Link", + "objectsRestored": true, + "propertyName": "VisibilityList", + "restoreRecompute": true, + "restored": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkProbe", + "typeId": "App::Link" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "setupProperty": "LinkedObject", + "shapeRestored": true, + "showResult": 1, + "touchedAfterEdit": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkProbe", + "typeId": "App::Link" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + false, + true + ] + }, + "touchedAfterRestore": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkProbe", + "typeId": "App::Link" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + true, + true + ] + }, + "valueRestored": true + }, + { + "before": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupProbe", + "typeId": "App::LinkGroup" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "editRecompute": true, + "edited": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupProbe", + "typeId": "App::LinkGroup" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false, + true + ] + }, + "hideResult": 1, + "mode": "link-base-extension-element-visibility", + "objectName": "LinkGroupProbe", + "objectTypeId": "App::LinkGroup", + "objectsRestored": true, + "propertyName": "VisibilityList", + "restoreRecompute": true, + "restored": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupProbe", + "typeId": "App::LinkGroup" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "setupProperty": "ElementList", + "shapeRestored": true, + "showResult": 1, + "touchedAfterEdit": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupProbe", + "typeId": "App::LinkGroup" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + false, + true + ] + }, + "touchedAfterRestore": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupProbe", + "typeId": "App::LinkGroup" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + true, + true + ] + }, + "valueRestored": true + }, + { + "before": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupPythonProbe", + "typeId": "App::LinkGroupPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "editRecompute": true, + "edited": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupPythonProbe", + "typeId": "App::LinkGroupPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false, + true + ] + }, + "hideResult": 1, + "mode": "link-base-extension-element-visibility", + "objectName": "LinkGroupPythonProbe", + "objectTypeId": "App::LinkGroupPython", + "objectsRestored": true, + "propertyName": "VisibilityList", + "restoreRecompute": true, + "restored": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupPythonProbe", + "typeId": "App::LinkGroupPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "setupProperty": "ElementList", + "shapeRestored": true, + "showResult": 1, + "touchedAfterEdit": { + "editorMode": [ + "Hidden" + ], + "mustExecute": true, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupPythonProbe", + "typeId": "App::LinkGroupPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + false, + true + ] + }, + "touchedAfterRestore": { + "editorMode": [ + "Hidden" + ], + "mustExecute": true, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupPythonProbe", + "typeId": "App::LinkGroupPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + true, + true + ] + }, + "valueRestored": true + }, + { + "before": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkPythonProbe", + "typeId": "App::LinkPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "editRecompute": true, + "edited": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkPythonProbe", + "typeId": "App::LinkPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false, + true + ] + }, + "hideResult": 1, + "mode": "link-base-extension-element-visibility", + "objectName": "LinkPythonProbe", + "objectTypeId": "App::LinkPython", + "objectsRestored": true, + "propertyName": "VisibilityList", + "restoreRecompute": true, + "restored": { + "editorMode": [ + "Hidden" + ], + "mustExecute": false, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkPythonProbe", + "typeId": "App::LinkPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "setupProperty": "LinkedObject", + "shapeRestored": true, + "showResult": 1, + "touchedAfterEdit": { + "editorMode": [ + "Hidden" + ], + "mustExecute": true, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkPythonProbe", + "typeId": "App::LinkPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + false, + true + ] + }, + "touchedAfterRestore": { + "editorMode": [ + "Hidden" + ], + "mustExecute": true, + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkPythonProbe", + "typeId": "App::LinkPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + true, + true + ] + }, + "valueRestored": true + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyBoolList", + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-boollist-promotion.json b/config/freecad-property-boollist-promotion.json new file mode 100644 index 0000000..3b28bd2 --- /dev/null +++ b/config/freecad-property-boollist-promotion.json @@ -0,0 +1,80 @@ +{ + "schemaVersion": 1, + "status": "pass", + "taskId": "PROP-app-propertyboollist-I", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyBoolList", + "recordCount": 7, + "phaseEvidence": { + "A": [ + "config/freecad-property-boollist-inventory.json", + "check:freecad-property-boollist-inventory" + ], + "B": [ + "config/freecad-property-boollist-success.json", + "check:freecad-property-boollist-success" + ], + "C": [ + "config/freecad-property-boollist-failure.json", + "check:freecad-property-boollist-failure" + ], + "D": [ + "config/freecad-property-boollist-mutation.json", + "check:freecad-property-boollist-mutation" + ], + "E": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyBoolListFacade.test.ts", + "test:freecad-property-boollist-facade" + ], + "F": [ + "tests/propertyBoolListTransaction.test.ts", + "test:freecad-property-boollist-transaction" + ], + "G": [ + "config/freecad-property-boollist-roundtrip.json", + "check:freecad-property-boollist-roundtrip" + ], + "H": [ + "config/chrome-property-boollist-verification.json", + "check:chrome-property-boollist" + ] + }, + "promotion": { + "from": "opaque-fcstd-proxy", + "to": "native-editable-codec", + "facadeValueModel": "variable-boolean-array", + "writableRecords": 3, + "immutableHiddenRecords": 4, + "fcstdElement": "BoolList", + "nativeRoundTripValue": [ + true, + false, + true, + false + ], + "browserRoundTripValue": [ + true, + false, + true, + false + ], + "zeroUnknownDrift": true + }, + "exactBlockerSync": { + "nativeEditableTypes": 30, + "nativeEditableRecords": 4361, + "opaqueTypes": 50, + "opaqueRecords": 466, + "exactPromotionReady": false, + "exactBlocker": "50 runtime property types and 466 records remain opaque-only; complete native document and property semantics" + }, + "systemExact": false, + "generatedAt": "2026-08-17T08:49:33.825Z" +} diff --git a/config/freecad-property-boollist-roundtrip.json b/config/freecad-property-boollist-roundtrip.json new file mode 100644 index 0000000..354e126 --- /dev/null +++ b/config/freecad-property-boollist-roundtrip.json @@ -0,0 +1,137 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-boollist-roundtrip", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "archives": { + "nativeInitial": { + "path": ".cache/freecad/property-boollist-roundtrip/native-initial.FCStd", + "bytes": 2508, + "sha256": "8522c2c4b77c177deb9f19be98ecb8367ee1b803e8da1ec752f1406c0cc87e8d" + }, + "webEdited": { + "path": ".cache/freecad/property-boollist-roundtrip/web-edited.FCStd", + "bytes": 2326, + "sha256": "1e351de85a66dfa7946422387a035ac9b05b337842db453360a0b7296b69b2c5" + }, + "nativeResaved": { + "path": ".cache/freecad/property-boollist-roundtrip/native-resaved.FCStd", + "bytes": 2508, + "sha256": "a496ce0e2c5f987c11515e53d3bc8ff8b52471b2087483e1ef123373ac508293" + } + }, + "nativeInitial": { + "object": { + "editorMode": [], + "hasShapeProperty": false, + "name": "BoolListProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::FeatureTest", + "value": [ + false + ] + }, + "objectSet": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ] + }, + "web": { + "before": { + "name": "BoolList", + "typeId": "App::PropertyBoolList", + "element": "BoolList", + "value": "[false]" + }, + "after": { + "name": "BoolList", + "typeId": "App::PropertyBoolList", + "element": "BoolList", + "value": "[true,false,true,false]" + }, + "objectSetPreserved": true, + "semanticObjectsPreserved": true, + "opaquePathsPreserved": 4, + "opaqueEntriesPreserved": true + }, + "nativeAfter": { + "reopened": { + "object": { + "editorMode": [], + "hasShapeProperty": false, + "name": "BoolListProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::FeatureTest", + "value": [ + true, + false, + true, + false + ] + }, + "objectSet": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ] + }, + "resaved": { + "object": { + "editorMode": [], + "hasShapeProperty": false, + "name": "BoolListProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::FeatureTest", + "value": [ + true, + false, + true, + false + ] + }, + "objectSet": [ + { + "name": "BoolListProbe", + "typeId": "App::FeatureTest" + } + ] + } + }, + "classification": { + "webValue": "[true,false,true,false]", + "reopenedValue": [ + true, + false, + true, + false + ], + "resavedValue": [ + true, + false, + true, + false + ], + "nativeOutputMatches": true, + "unknownSemanticDrift": false, + "zeroUnknownDrift": true + } +} diff --git a/config/freecad-property-boollist-success.json b/config/freecad-property-boollist-success.json new file mode 100644 index 0000000..6070a92 --- /dev/null +++ b/config/freecad-property-boollist-success.json @@ -0,0 +1,1683 @@ +{ + "baselineId": "freecad-1.1.1-property-boollist-success", + "caseCount": 7, + "cases": [ + { + "defaultValue": [ + false + ], + "hostExecution": "normal", + "mode": "direct-native-property-setter", + "objectName": "FeatureTestProbe", + "objectTypeId": "App::FeatureTest", + "phases": { + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": false, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false + ] + }, + "empty": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [] + }, + "large": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false + ] + }, + "mixed": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + false, + true, + false + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false + ] + }, + "singleton": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "BoolList" + }, + { + "defaultValue": [ + false + ], + "hostExecution": "intrinsic-test-exception", + "mode": "direct-native-property-setter", + "objectName": "FeatureTestExceptionProbe", + "objectTypeId": "App::FeatureTestException", + "phases": { + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": false, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false + ] + }, + "empty": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [] + }, + "large": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false + ] + }, + "mixed": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + true, + false, + true, + false + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + false + ] + }, + "singleton": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + true + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "BoolList" + }, + { + "defaultValue": [ + false + ], + "hostExecution": "normal", + "mode": "direct-native-property-setter", + "objectName": "GeomFillSurfaceProbe", + "objectTypeId": "Surface::GeomFillSurface", + "phases": { + "allFalse": { + "editorMode": [], + "objectSet": [ + { + "name": "GeomFillSurfaceProbe", + "typeId": "Surface::GeomFillSurface" + }, + { + "name": "Boundary1", + "typeId": "Part::Feature" + }, + { + "name": "Boundary2", + "typeId": "Part::Feature" + }, + { + "name": "Boundary3", + "typeId": "Part::Feature" + }, + { + "name": "Boundary4", + "typeId": "Part::Feature" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": true, + "edges": 4, + "faces": 1, + "isNull": false, + "shapeType": "Face", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "statusString": "Valid", + "value": [ + false, + false, + false, + false + ] + }, + "allReversed": { + "editorMode": [], + "objectSet": [ + { + "name": "GeomFillSurfaceProbe", + "typeId": "Surface::GeomFillSurface" + }, + { + "name": "Boundary1", + "typeId": "Part::Feature" + }, + { + "name": "Boundary2", + "typeId": "Part::Feature" + }, + { + "name": "Boundary3", + "typeId": "Part::Feature" + }, + { + "name": "Boundary4", + "typeId": "Part::Feature" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": true, + "edges": 4, + "faces": 1, + "isNull": false, + "shapeType": "Face", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "statusString": "Valid", + "value": [ + true, + true, + true, + true + ] + }, + "alternating": { + "editorMode": [], + "objectSet": [ + { + "name": "GeomFillSurfaceProbe", + "typeId": "Surface::GeomFillSurface" + }, + { + "name": "Boundary1", + "typeId": "Part::Feature" + }, + { + "name": "Boundary2", + "typeId": "Part::Feature" + }, + { + "name": "Boundary3", + "typeId": "Part::Feature" + }, + { + "name": "Boundary4", + "typeId": "Part::Feature" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": true, + "edges": 4, + "faces": 1, + "isNull": false, + "shapeType": "Face", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "statusString": "Valid", + "value": [ + true, + false, + true, + false + ] + }, + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "GeomFillSurfaceProbe", + "typeId": "Surface::GeomFillSurface" + }, + { + "name": "Boundary1", + "typeId": "Part::Feature" + }, + { + "name": "Boundary2", + "typeId": "Part::Feature" + }, + { + "name": "Boundary3", + "typeId": "Part::Feature" + }, + { + "name": "Boundary4", + "typeId": "Part::Feature" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": true, + "edges": 4, + "faces": 1, + "isNull": false, + "shapeType": "Face", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "statusString": "Valid", + "value": [ + false + ] + }, + "oneReversed": { + "editorMode": [], + "objectSet": [ + { + "name": "GeomFillSurfaceProbe", + "typeId": "Surface::GeomFillSurface" + }, + { + "name": "Boundary1", + "typeId": "Part::Feature" + }, + { + "name": "Boundary2", + "typeId": "Part::Feature" + }, + { + "name": "Boundary3", + "typeId": "Part::Feature" + }, + { + "name": "Boundary4", + "typeId": "Part::Feature" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": true, + "edges": 4, + "faces": 1, + "isNull": false, + "shapeType": "Face", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "statusString": "Valid", + "value": [ + true, + false, + false, + false + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "GeomFillSurfaceProbe", + "typeId": "Surface::GeomFillSurface" + }, + { + "name": "Boundary1", + "typeId": "Part::Feature" + }, + { + "name": "Boundary2", + "typeId": "Part::Feature" + }, + { + "name": "Boundary3", + "typeId": "Part::Feature" + }, + { + "name": "Boundary4", + "typeId": "Part::Feature" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": true, + "edges": 4, + "faces": 1, + "isNull": false, + "shapeType": "Face", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "statusString": "Valid", + "value": [ + false + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "ReversedList" + }, + { + "hideResult": 1, + "hostExecution": "normal", + "mode": "link-base-extension-element-visibility", + "objectName": "LinkProbe", + "objectTypeId": "App::Link", + "phases": { + "hidden": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkProbe", + "typeId": "App::Link" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false, + true + ] + }, + "linked": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkProbe", + "typeId": "App::Link" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "restored": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkProbe", + "typeId": "App::Link" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "VisibilityList", + "setupProperty": "LinkedObject", + "showResult": 1 + }, + { + "hideResult": 1, + "hostExecution": "normal", + "mode": "link-base-extension-element-visibility", + "objectName": "LinkGroupProbe", + "objectTypeId": "App::LinkGroup", + "phases": { + "hidden": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupProbe", + "typeId": "App::LinkGroup" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false, + true + ] + }, + "linked": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupProbe", + "typeId": "App::LinkGroup" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "restored": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupProbe", + "typeId": "App::LinkGroup" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "VisibilityList", + "setupProperty": "ElementList", + "showResult": 1 + }, + { + "hideResult": 1, + "hostExecution": "normal", + "mode": "link-base-extension-element-visibility", + "objectName": "LinkGroupPythonProbe", + "objectTypeId": "App::LinkGroupPython", + "phases": { + "hidden": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupPythonProbe", + "typeId": "App::LinkGroupPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false, + true + ] + }, + "linked": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupPythonProbe", + "typeId": "App::LinkGroupPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "restored": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkGroupPythonProbe", + "typeId": "App::LinkGroupPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "VisibilityList", + "setupProperty": "ElementList", + "showResult": 1 + }, + { + "hideResult": 1, + "hostExecution": "normal", + "mode": "link-base-extension-element-visibility", + "objectName": "LinkPythonProbe", + "objectTypeId": "App::LinkPython", + "phases": { + "hidden": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkPythonProbe", + "typeId": "App::LinkPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + false, + true + ] + }, + "linked": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkPythonProbe", + "typeId": "App::LinkPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + }, + "restored": { + "editorMode": [ + "Hidden" + ], + "objectSet": [ + { + "name": "TargetA", + "typeId": "Part::Feature" + }, + { + "name": "TargetB", + "typeId": "Part::Feature" + }, + { + "name": "TargetGroup", + "typeId": "App::DocumentObjectGroup" + }, + { + "name": "LinkPythonProbe", + "typeId": "App::LinkPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "Immutable", + "Hidden", + "LockDynamic" + ], + "propertyTypeId": "App::PropertyBoolList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + true, + true + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "VisibilityList", + "setupProperty": "LinkedObject", + "showResult": 1 + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyBoolList", + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-color-failure.json b/config/freecad-property-color-failure.json new file mode 100644 index 0000000..b3ea5e6 --- /dev/null +++ b/config/freecad-property-color-failure.json @@ -0,0 +1,639 @@ +{ + "baselineId": "freecad-1.1.1-property-color-failure", + "cancellationBoundary": { + "classification": "synchronous-property-setter", + "reason": "no-native-cancel-hook", + "replacement": "abort-active-document-transaction", + "supported": false + }, + "coercions": [ + { + "accepted": true, + "after": [ + 2.0, + -1.0, + 0.5, + 1.5 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "float-out-of-range", + "objectsPreserved": true, + "requested": "(2.0, -1.0, 0.5, 1.5)", + "valuePreserved": false + }, + { + "accepted": true, + "after": [ + -0.003921569, + 1.003921628, + 2.003921509, + -1.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "integer-out-of-range", + "objectsPreserved": true, + "requested": "(-1, 256, 511, -255)", + "valuePreserved": false + }, + { + "accepted": true, + "after": [ + 0.003921569, + 0.0, + 0.003921569, + 0.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "boolean-tuple", + "objectsPreserved": true, + "requested": "(True, False, True, False)", + "valuePreserved": false + }, + { + "accepted": true, + "after": [ + 1.0, + 1.0, + 1.0, + 1.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "packed-max", + "objectsPreserved": true, + "requested": "4294967295", + "valuePreserved": false + }, + { + "accepted": true, + "after": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "packed-wrap", + "objectsPreserved": true, + "requested": "4294967296", + "valuePreserved": false + }, + { + "accepted": true, + "after": [ + 1.0, + 1.0, + 1.0, + 1.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "packed-negative", + "objectsPreserved": true, + "requested": "-1", + "valuePreserved": false + } + ], + "disabled": { + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "classification": "editor-readonly-python-mutable-until-immutable", + "editorMode": [ + "ReadOnly" + ], + "editorReadOnlyAfter": [ + 0.200000003, + 0.300000012, + 0.400000006, + 0.5 + ], + "editorReadOnlyException": null, + "editorReadOnlyRequested": [ + 0.2, + 0.3, + 0.4, + 0.5 + ], + "immutableAfter": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "immutableException": { + "message": "Object attribute 'Colour' is read-only", + "type": "AttributeError" + }, + "immutableRequested": [ + 0.6, + 0.7, + 0.8, + 0.9 + ], + "immutableStatus": [ + "Immutable", + "ReadOnly" + ], + "immutableValuePreserved": true, + "objectsPreserved": true, + "pythonBypassesEditorReadOnly": true, + "restoredEditorMode": [], + "restoredStatus": [] + }, + "documentIntegrity": { + "finalObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "initialObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "objectsPreserved": true + }, + "failures": [ + { + "after": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not NoneType", + "type": "TypeError" + }, + "id": "none", + "objectsPreserved": true, + "polluted": false, + "requested": "None", + "valuePreserved": true + }, + { + "after": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not list", + "type": "TypeError" + }, + "id": "list", + "objectsPreserved": true, + "polluted": false, + "requested": "[0.1, 0.2, 0.3]", + "valuePreserved": true + }, + { + "after": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not tuple", + "type": "TypeError" + }, + "id": "short-tuple", + "objectsPreserved": true, + "polluted": false, + "requested": "(0.1, 0.2)", + "valuePreserved": true + }, + { + "after": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not tuple", + "type": "TypeError" + }, + "id": "long-tuple", + "objectsPreserved": true, + "polluted": false, + "requested": "(0.1, 0.2, 0.3, 0.4, 0.5)", + "valuePreserved": true + }, + { + "after": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "Type in tuple must be float or integer", + "type": "TypeError" + }, + "id": "string-first", + "objectsPreserved": true, + "polluted": false, + "requested": "('bad', 0.2, 0.3)", + "valuePreserved": true + }, + { + "after": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "Type in tuple must be consistent (float)", + "type": "TypeError" + }, + "id": "mixed-after-float", + "objectsPreserved": true, + "polluted": false, + "requested": "(0.1, 2, 0.3)", + "valuePreserved": true + }, + { + "after": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "Type in tuple must be consistent (integer)", + "type": "TypeError" + }, + "id": "mixed-after-integer", + "objectsPreserved": true, + "polluted": false, + "requested": "(1, 0.2, 3)", + "valuePreserved": true + }, + { + "after": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "afterObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "beforeObjects": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not float", + "type": "TypeError" + }, + "id": "scalar-float", + "objectsPreserved": true, + "polluted": false, + "requested": "0.5", + "valuePreserved": true + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "initial": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "object": { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + }, + "property": { + "name": "Colour", + "typeId": "App::PropertyColor" + }, + "propertyType": "App::PropertyColor", + "schemaVersion": 1, + "status": "pass", + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 1, + "name": "property-color-cancel" + }, + "afterAbort": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "afterRecompute": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "before": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "edited": [ + 0.75, + 0.5, + 0.25, + 0.125 + ], + "objectsAfter": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "objectsBefore": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ], + "objectsRestored": true, + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "recoveryRecomputeResult": true, + "restored": true, + "stateAfterAbort": { + "state": [ + "Touched" + ], + "statusString": "Touched" + }, + "stateAfterEdit": { + "state": [ + "Touched" + ], + "statusString": "Touched" + }, + "stateAfterRecompute": { + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "undoMode": 1 + } +} diff --git a/config/freecad-property-color-inventory.json b/config/freecad-property-color-inventory.json new file mode 100644 index 0000000..9ee7743 --- /dev/null +++ b/config/freecad-property-color-inventory.json @@ -0,0 +1,523 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyColor", + "recordCount": 8, + "records": [ + { + "objectTypeId": "App::FeatureTest", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Colour", + "group": "", + "status": [], + "defaultValue": [ + 0, + 0, + 0, + 1 + ], + "valueModel": { + "kind": "rgba-color", + "channels": [ + "red", + "green", + "blue", + "alpha" + ], + "canonicalRepresentation": "four-channel-float-tuple", + "packedRepresentation": "0xRRGGBBAA", + "alphaSemantics": "1-opaque-0-transparent", + "writable": true + }, + "inputs": [ + { + "kind": "float-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "omittedAlpha": 1 + }, + { + "kind": "integer-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "normalizationDivisor": 255, + "omittedAlpha": 1 + }, + { + "kind": "packed-integer", + "encoding": "0xRRGGBBAA" + } + ], + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "App::FeatureTest", + "source": "Document.supportedTypes runtime inventory", + "shapeRequired": false + } + }, + { + "objectTypeId": "App::FeatureTestException", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Colour", + "group": "", + "status": [], + "defaultValue": [ + 0, + 0, + 0, + 1 + ], + "valueModel": { + "kind": "rgba-color", + "channels": [ + "red", + "green", + "blue", + "alpha" + ], + "canonicalRepresentation": "four-channel-float-tuple", + "packedRepresentation": "0xRRGGBBAA", + "alphaSemantics": "1-opaque-0-transparent", + "writable": true + }, + "inputs": [ + { + "kind": "float-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "omittedAlpha": 1 + }, + { + "kind": "integer-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "normalizationDivisor": 255, + "omittedAlpha": 1 + }, + { + "kind": "packed-integer", + "encoding": "0xRRGGBBAA" + } + ], + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "App::FeatureTestException", + "source": "Document.supportedTypes runtime inventory", + "shapeRequired": false + } + }, + { + "objectTypeId": "App::Part", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Color", + "group": "", + "status": [], + "defaultValue": [ + 1, + 1, + 1, + 0 + ], + "valueModel": { + "kind": "rgba-color", + "channels": [ + "red", + "green", + "blue", + "alpha" + ], + "canonicalRepresentation": "four-channel-float-tuple", + "packedRepresentation": "0xRRGGBBAA", + "alphaSemantics": "1-opaque-0-transparent", + "writable": true + }, + "inputs": [ + { + "kind": "float-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "omittedAlpha": 1 + }, + { + "kind": "integer-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "normalizationDivisor": 255, + "omittedAlpha": 1 + }, + { + "kind": "packed-integer", + "encoding": "0xRRGGBBAA" + } + ], + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "App::Part", + "source": "Document.supportedTypes runtime inventory", + "shapeRequired": false + } + }, + { + "objectTypeId": "Assembly::AssemblyLink", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Color", + "group": "", + "status": [], + "defaultValue": [ + 1, + 1, + 1, + 0 + ], + "valueModel": { + "kind": "rgba-color", + "channels": [ + "red", + "green", + "blue", + "alpha" + ], + "canonicalRepresentation": "four-channel-float-tuple", + "packedRepresentation": "0xRRGGBBAA", + "alphaSemantics": "1-opaque-0-transparent", + "writable": true + }, + "inputs": [ + { + "kind": "float-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "omittedAlpha": 1 + }, + { + "kind": "integer-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "normalizationDivisor": 255, + "omittedAlpha": 1 + }, + { + "kind": "packed-integer", + "encoding": "0xRRGGBBAA" + } + ], + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "Assembly::AssemblyLink", + "source": "Document.supportedTypes runtime inventory", + "shapeRequired": false + } + }, + { + "objectTypeId": "Assembly::AssemblyObject", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Color", + "group": "", + "status": [], + "defaultValue": [ + 1, + 1, + 1, + 0 + ], + "valueModel": { + "kind": "rgba-color", + "channels": [ + "red", + "green", + "blue", + "alpha" + ], + "canonicalRepresentation": "four-channel-float-tuple", + "packedRepresentation": "0xRRGGBBAA", + "alphaSemantics": "1-opaque-0-transparent", + "writable": true + }, + "inputs": [ + { + "kind": "float-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "omittedAlpha": 1 + }, + { + "kind": "integer-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "normalizationDivisor": 255, + "omittedAlpha": 1 + }, + { + "kind": "packed-integer", + "encoding": "0xRRGGBBAA" + } + ], + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "Assembly::AssemblyObject", + "source": "Document.supportedTypes runtime inventory", + "shapeRequired": false + } + }, + { + "objectTypeId": "TechDraw::DrawViewAnnotation", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "TextColor", + "group": "Annotation", + "status": [], + "defaultValue": [ + 0, + 0, + 0, + 1 + ], + "valueModel": { + "kind": "rgba-color", + "channels": [ + "red", + "green", + "blue", + "alpha" + ], + "canonicalRepresentation": "four-channel-float-tuple", + "packedRepresentation": "0xRRGGBBAA", + "alphaSemantics": "1-opaque-0-transparent", + "writable": true + }, + "inputs": [ + { + "kind": "float-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "omittedAlpha": 1 + }, + { + "kind": "integer-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "normalizationDivisor": 255, + "omittedAlpha": 1 + }, + { + "kind": "packed-integer", + "encoding": "0xRRGGBBAA" + } + ], + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewAnnotation", + "source": "Document.supportedTypes runtime inventory", + "shapeRequired": false + } + }, + { + "objectTypeId": "TechDraw::DrawViewDraft", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Color", + "group": "Draft view", + "status": [], + "defaultValue": [ + 0, + 0, + 0, + 1 + ], + "valueModel": { + "kind": "rgba-color", + "channels": [ + "red", + "green", + "blue", + "alpha" + ], + "canonicalRepresentation": "four-channel-float-tuple", + "packedRepresentation": "0xRRGGBBAA", + "alphaSemantics": "1-opaque-0-transparent", + "writable": true + }, + "inputs": [ + { + "kind": "float-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "omittedAlpha": 1 + }, + { + "kind": "integer-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "normalizationDivisor": 255, + "omittedAlpha": 1 + }, + { + "kind": "packed-integer", + "encoding": "0xRRGGBBAA" + } + ], + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewDraft", + "source": "Document.supportedTypes runtime inventory", + "shapeRequired": false + } + }, + { + "objectTypeId": "TechDraw::DrawViewSpreadsheet", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "TextColor", + "group": "Spreadsheet", + "status": [], + "defaultValue": [ + 0, + 0, + 0, + 1 + ], + "valueModel": { + "kind": "rgba-color", + "channels": [ + "red", + "green", + "blue", + "alpha" + ], + "canonicalRepresentation": "four-channel-float-tuple", + "packedRepresentation": "0xRRGGBBAA", + "alphaSemantics": "1-opaque-0-transparent", + "writable": true + }, + "inputs": [ + { + "kind": "float-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "omittedAlpha": 1 + }, + { + "kind": "integer-tuple", + "cardinality": [ + 3, + 4 + ], + "componentsMustHaveSameType": true, + "normalizationDivisor": 255, + "omittedAlpha": 1 + }, + { + "kind": "packed-integer", + "encoding": "0xRRGGBBAA" + } + ], + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewSpreadsheet", + "source": "Document.supportedTypes runtime inventory", + "shapeRequired": false + } + } + ], + "storage": { + "xmlElement": "PropertyColor", + "attribute": "value", + "encoding": "unsigned-decimal-packed-0xRRGGBBAA", + "legacyBeforeVersion": "1.1", + "legacyConversion": "invert-alpha-byte" + }, + "provenance": { + "runtime": { + "path": ".cache/freecad/reference-desktop.json", + "bytes": 2298709, + "sha256": "082400ec7379e8efc2af16709032d45890d7092277967b714acb05761fd1c2a7" + }, + "sources": [ + { + "path": ".cache/freecad/FreeCAD/src/App/PropertyStandard.h", + "bytes": 37529, + "sha256": "3555ab386b4815329b09604bbd70626c2b24b66f90a7ff2c31052b55fd3c9244" + }, + { + "path": ".cache/freecad/FreeCAD/src/App/PropertyStandard.cpp", + "bytes": 99757, + "sha256": "eeefbbd7020c85c21e2e6b5f777088261668492845cf4d172e31f600fe9b96fd" + }, + { + "path": ".cache/freecad/FreeCAD/src/Base/Color.h", + "bytes": 8885, + "sha256": "4d4630c87209f0df85db30608026fc4389936719a301136c3eb389f0e48bf864" + }, + { + "path": ".cache/freecad/FreeCAD/src/Base/Color.cpp", + "bytes": 5857, + "sha256": "19f55140ccc547a194fcf49b090a7648089e4ea1ee0406d4f0a591dd5abc6d7c" + } + ] + }, + "classification": "opaque-fcstd-proxy", + "nextPhases": [ + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I" + ] +} diff --git a/config/freecad-property-color-mutation.json b/config/freecad-property-color-mutation.json new file mode 100644 index 0000000..afa389b --- /dev/null +++ b/config/freecad-property-color-mutation.json @@ -0,0 +1,1668 @@ +{ + "baselineId": "freecad-1.1.1-property-color-mutation", + "caseCount": 8, + "cases": [ + { + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorMutation", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "editRecomputeResult": true, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorMutation", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "hostExecution": "normal", + "mutationDetected": true, + "objectName": "FeatureTestColorMutation", + "objectTypeId": "App::FeatureTest", + "propertyName": "Colour", + "restoreRecomputeResult": true, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorMutation", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "restoredExactly": true, + "setup": { + "kind": "none" + }, + "target": [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + "touchedAfterEdit": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorMutation", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorMutation", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + } + }, + { + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorMutation", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "editRecomputeResult": true, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorMutation", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "hostExecution": "intrinsic-test-exception", + "mutationDetected": true, + "objectName": "FeatureTestExceptionColorMutation", + "objectTypeId": "App::FeatureTestException", + "propertyName": "Colour", + "restoreRecomputeResult": true, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorMutation", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "restoredExactly": true, + "setup": { + "kind": "none" + }, + "target": [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + "touchedAfterEdit": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorMutation", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorMutation", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + } + }, + { + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorMutation", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "editRecomputeResult": true, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorMutation", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "hostExecution": "normal", + "mutationDetected": true, + "objectName": "PartColorMutation", + "objectTypeId": "App::Part", + "propertyName": "Color", + "restoreRecomputeResult": true, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorMutation", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "restoredExactly": true, + "setup": { + "kind": "none" + }, + "target": [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + "touchedAfterEdit": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorMutation", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorMutation", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + } + }, + { + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorMutation", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "editRecomputeResult": true, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorMutation", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "hostExecution": "normal", + "mutationDetected": true, + "objectName": "AssemblyLinkColorMutation", + "objectTypeId": "Assembly::AssemblyLink", + "propertyName": "Color", + "restoreRecomputeResult": true, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorMutation", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "restoredExactly": true, + "setup": { + "kind": "none" + }, + "target": [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + "touchedAfterEdit": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorMutation", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorMutation", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + } + }, + { + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorMutation", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "editRecomputeResult": true, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorMutation", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "hostExecution": "normal", + "mutationDetected": true, + "objectName": "AssemblyObjectColorMutation", + "objectTypeId": "Assembly::AssemblyObject", + "propertyName": "Color", + "restoreRecomputeResult": true, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorMutation", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "restoredExactly": true, + "setup": { + "kind": "none" + }, + "target": [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + "touchedAfterEdit": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorMutation", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorMutation", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + } + }, + { + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorMutation", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "editRecomputeResult": true, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorMutation", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "hostExecution": "normal", + "mutationDetected": true, + "objectName": "AnnotationColorMutation", + "objectTypeId": "TechDraw::DrawViewAnnotation", + "propertyName": "TextColor", + "restoreRecomputeResult": true, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorMutation", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "restoredExactly": true, + "setup": { + "kind": "none" + }, + "target": [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + "touchedAfterEdit": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorMutation", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorMutation", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + } + }, + { + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorMutation", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "editRecomputeResult": true, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorMutation", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "hostExecution": "normal", + "mutationDetected": true, + "objectName": "DraftColorMutation", + "objectTypeId": "TechDraw::DrawViewDraft", + "propertyName": "Color", + "restoreRecomputeResult": true, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorMutation", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "restoredExactly": true, + "setup": { + "kind": "none" + }, + "target": [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + "touchedAfterEdit": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorMutation", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorMutation", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + } + }, + { + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorMutation", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "MutationSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "editRecomputeResult": true, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorMutation", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "MutationSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "hostExecution": "normal", + "mutationDetected": true, + "objectName": "SpreadsheetColorMutation", + "objectTypeId": "TechDraw::DrawViewSpreadsheet", + "propertyName": "TextColor", + "restoreRecomputeResult": true, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorMutation", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "MutationSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "restoredExactly": true, + "setup": { + "kind": "spreadsheet-source", + "objectName": "MutationSource", + "objectTypeId": "Spreadsheet::Sheet" + }, + "target": [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + "touchedAfterEdit": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorMutation", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "MutationSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.125, + 0.375, + 0.625, + 0.875 + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorMutation", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "MutationSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + } + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyColor", + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-color-promotion.json b/config/freecad-property-color-promotion.json new file mode 100644 index 0000000..75b5161 --- /dev/null +++ b/config/freecad-property-color-promotion.json @@ -0,0 +1,80 @@ +{ + "schemaVersion": 1, + "status": "pass", + "taskId": "PROP-app-propertycolor-I", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyColor", + "recordCount": 8, + "phaseEvidence": { + "A": [ + "config/freecad-property-color-inventory.json", + "check:freecad-property-color-inventory" + ], + "B": [ + "config/freecad-property-color-success.json", + "check:freecad-property-color-success" + ], + "C": [ + "config/freecad-property-color-failure.json", + "check:freecad-property-color-failure" + ], + "D": [ + "config/freecad-property-color-mutation.json", + "check:freecad-property-color-mutation" + ], + "E": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyColorFacade.test.ts", + "test:freecad-property-color-facade" + ], + "F": [ + "tests/propertyColorTransaction.test.ts", + "test:freecad-property-color-transaction" + ], + "G": [ + "config/freecad-property-color-roundtrip.json", + "check:freecad-property-color-roundtrip" + ], + "H": [ + "config/chrome-property-color-verification.json", + "check:chrome-property-color" + ] + }, + "promotion": { + "from": "opaque-fcstd-proxy", + "to": "native-editable-codec", + "facadeValueModel": "four-finite-rgba-channels-with-8-bit-fcstd-packing", + "writableRecords": 8, + "fcstdElement": "PropertyColor", + "fcstdPackedValue": "862362060", + "nativeRoundTripValue": [ + 0.200000003, + 0.400000006, + 0.600000024, + 0.800000012 + ], + "browserRoundTripValue": [ + 0.2, + 0.4, + 0.6, + 0.8 + ], + "zeroUnknownDrift": true + }, + "exactBlockerSync": { + "nativeEditableTypes": 30, + "nativeEditableRecords": 4361, + "opaqueTypes": 50, + "opaqueRecords": 466, + "exactPromotionReady": false, + "exactBlocker": "50 runtime property types and 466 records remain opaque-only; complete native document and property semantics" + }, + "systemExact": false, + "generatedAt": "2026-08-17T08:49:33.829Z" +} diff --git a/config/freecad-property-color-roundtrip.json b/config/freecad-property-color-roundtrip.json new file mode 100644 index 0000000..f499de9 --- /dev/null +++ b/config/freecad-property-color-roundtrip.json @@ -0,0 +1,146 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-color-roundtrip", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "archives": { + "nativeInitial": { + "path": ".cache/freecad/property-color-roundtrip/native-initial.FCStd", + "bytes": 2508, + "sha256": "93d6c2b60ffdd65f10bd4ca13e5dfcedf19c3a1b2c452d1e6a087e99be259c85" + }, + "webEdited": { + "path": ".cache/freecad/property-color-roundtrip/web-edited.FCStd", + "bytes": 2324, + "sha256": "0572127ba788503c7c2bbe8d2b0f1ae1796fb5946ddc6c3610d8d6b15fbba37d" + }, + "nativeResaved": { + "path": ".cache/freecad/property-color-roundtrip/native-resaved.FCStd", + "bytes": 2505, + "sha256": "e665faea155fb2d1aaa6a7c02bb07a060280098d4a92f52f568b8e37b5c3249d" + } + }, + "nativeInitial": { + "object": { + "editorMode": [], + "hasShapeProperty": false, + "name": "ColorProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::FeatureTest", + "value": [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + }, + "objectSet": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ] + }, + "web": { + "before": { + "name": "Colour", + "typeId": "App::PropertyColor", + "element": "PropertyColor", + "value": "287454020" + }, + "after": { + "name": "Colour", + "typeId": "App::PropertyColor", + "element": "PropertyColor", + "value": "862362060" + }, + "objectSetPreserved": true, + "semanticObjectsPreserved": true, + "opaquePathsPreserved": 4, + "opaqueEntriesPreserved": true + }, + "nativeAfter": { + "reopened": { + "object": { + "editorMode": [], + "hasShapeProperty": false, + "name": "ColorProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::FeatureTest", + "value": [ + 0.200000003, + 0.400000006, + 0.600000024, + 0.800000012 + ] + }, + "objectSet": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ] + }, + "resaved": { + "object": { + "editorMode": [], + "hasShapeProperty": false, + "name": "ColorProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::FeatureTest", + "value": [ + 0.200000003, + 0.400000006, + 0.600000024, + 0.800000012 + ] + }, + "objectSet": [ + { + "name": "ColorProbe", + "typeId": "App::FeatureTest" + } + ] + } + }, + "classification": { + "requestedValue": [ + 0.2, + 0.4, + 0.6, + 0.8 + ], + "webValue": "862362060", + "reopenedValue": [ + 0.200000003, + 0.400000006, + 0.600000024, + 0.800000012 + ], + "resavedValue": [ + 0.200000003, + 0.400000006, + 0.600000024, + 0.800000012 + ], + "nativeOutputMatches": true, + "unknownSemanticDrift": false, + "zeroUnknownDrift": true + } +} diff --git a/config/freecad-property-color-success.json b/config/freecad-property-color-success.json new file mode 100644 index 0000000..e58e9b8 --- /dev/null +++ b/config/freecad-property-color-success.json @@ -0,0 +1,2884 @@ +{ + "baselineId": "freecad-1.1.1-property-color-success", + "caseCount": 8, + "cases": [ + { + "defaultValue": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "hostExecution": "normal", + "mode": "direct-native-property-setter", + "objectName": "FeatureTestColorProbe", + "objectTypeId": "App::FeatureTest", + "phases": { + "byteRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.003921569, + 0.498039216, + 1.0, + 1.0 + ] + }, + "byteRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 0.501960814, + 0.0, + 0.250980407 + ] + }, + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": false, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "floatRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.25, + 0.5, + 0.75, + 1.0 + ] + }, + "floatRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.100000001, + 0.200000003, + 0.300000012, + 0.400000006 + ] + }, + "packedRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "transparentBoundary": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "Colour", + "requested": { + "byteRgb": [ + 1, + 127, + 255 + ], + "byteRgba": [ + 255, + 128, + 0, + 64 + ], + "floatRgb": [ + 0.25, + 0.5, + 0.75 + ], + "floatRgba": [ + 0.1, + 0.2, + 0.3, + 0.4 + ], + "packedRgba": 287454020, + "transparentBoundary": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "setup": { + "kind": "none" + } + }, + { + "defaultValue": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "hostExecution": "intrinsic-test-exception", + "mode": "direct-native-property-setter", + "objectName": "FeatureTestExceptionColorProbe", + "objectTypeId": "App::FeatureTestException", + "phases": { + "byteRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + 0.003921569, + 0.498039216, + 1.0, + 1.0 + ] + }, + "byteRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + 1.0, + 0.501960814, + 0.0, + 0.250980407 + ] + }, + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": false, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "floatRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + 0.25, + 0.5, + 0.75, + 1.0 + ] + }, + "floatRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + 0.100000001, + 0.200000003, + 0.300000012, + 0.400000006 + ] + }, + "packedRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "transparentBoundary": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "Colour", + "requested": { + "byteRgb": [ + 1, + 127, + 255 + ], + "byteRgba": [ + 255, + 128, + 0, + 64 + ], + "floatRgb": [ + 0.25, + 0.5, + 0.75 + ], + "floatRgba": [ + 0.1, + 0.2, + 0.3, + 0.4 + ], + "packedRgba": 287454020, + "transparentBoundary": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "setup": { + "kind": "none" + } + }, + { + "defaultValue": [ + 1.0, + 1.0, + 1.0, + 0.0 + ], + "hostExecution": "normal", + "mode": "direct-native-property-setter", + "objectName": "PartColorProbe", + "objectTypeId": "App::Part", + "phases": { + "byteRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorProbe", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.003921569, + 0.498039216, + 1.0, + 1.0 + ] + }, + "byteRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorProbe", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 0.501960814, + 0.0, + 0.250980407 + ] + }, + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorProbe", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "floatRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorProbe", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.25, + 0.5, + 0.75, + 1.0 + ] + }, + "floatRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorProbe", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.100000001, + 0.200000003, + 0.300000012, + 0.400000006 + ] + }, + "packedRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorProbe", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorProbe", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "transparentBoundary": { + "editorMode": [], + "objectSet": [ + { + "name": "PartColorProbe", + "typeId": "App::Part" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "Color", + "requested": { + "byteRgb": [ + 1, + 127, + 255 + ], + "byteRgba": [ + 255, + 128, + 0, + 64 + ], + "floatRgb": [ + 0.25, + 0.5, + 0.75 + ], + "floatRgba": [ + 0.1, + 0.2, + 0.3, + 0.4 + ], + "packedRgba": 287454020, + "transparentBoundary": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "setup": { + "kind": "none" + } + }, + { + "defaultValue": [ + 1.0, + 1.0, + 1.0, + 0.0 + ], + "hostExecution": "normal", + "mode": "direct-native-property-setter", + "objectName": "AssemblyLinkColorProbe", + "objectTypeId": "Assembly::AssemblyLink", + "phases": { + "byteRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorProbe", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.003921569, + 0.498039216, + 1.0, + 1.0 + ] + }, + "byteRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorProbe", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 0.501960814, + 0.0, + 0.250980407 + ] + }, + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorProbe", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "floatRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorProbe", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.25, + 0.5, + 0.75, + 1.0 + ] + }, + "floatRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorProbe", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.100000001, + 0.200000003, + 0.300000012, + 0.400000006 + ] + }, + "packedRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorProbe", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorProbe", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "transparentBoundary": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyLinkColorProbe", + "typeId": "Assembly::AssemblyLink" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "Color", + "requested": { + "byteRgb": [ + 1, + 127, + 255 + ], + "byteRgba": [ + 255, + 128, + 0, + 64 + ], + "floatRgb": [ + 0.25, + 0.5, + 0.75 + ], + "floatRgba": [ + 0.1, + 0.2, + 0.3, + 0.4 + ], + "packedRgba": 287454020, + "transparentBoundary": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "setup": { + "kind": "none" + } + }, + { + "defaultValue": [ + 1.0, + 1.0, + 1.0, + 0.0 + ], + "hostExecution": "normal", + "mode": "direct-native-property-setter", + "objectName": "AssemblyObjectColorProbe", + "objectTypeId": "Assembly::AssemblyObject", + "phases": { + "byteRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorProbe", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.003921569, + 0.498039216, + 1.0, + 1.0 + ] + }, + "byteRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorProbe", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 0.501960814, + 0.0, + 0.250980407 + ] + }, + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorProbe", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "floatRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorProbe", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.25, + 0.5, + 0.75, + 1.0 + ] + }, + "floatRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorProbe", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.100000001, + 0.200000003, + 0.300000012, + 0.400000006 + ] + }, + "packedRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorProbe", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorProbe", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 1.0, + 0.0 + ] + }, + "transparentBoundary": { + "editorMode": [], + "objectSet": [ + { + "name": "AssemblyObjectColorProbe", + "typeId": "Assembly::AssemblyObject" + }, + { + "name": "Origin", + "typeId": "App::Origin" + }, + { + "name": "X_Axis", + "typeId": "App::Line" + }, + { + "name": "Y_Axis", + "typeId": "App::Line" + }, + { + "name": "Z_Axis", + "typeId": "App::Line" + }, + { + "name": "XY_Plane", + "typeId": "App::Plane" + }, + { + "name": "XZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "YZ_Plane", + "typeId": "App::Plane" + }, + { + "name": "Origin001", + "typeId": "App::Point" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "Color", + "requested": { + "byteRgb": [ + 1, + 127, + 255 + ], + "byteRgba": [ + 255, + 128, + 0, + 64 + ], + "floatRgb": [ + 0.25, + 0.5, + 0.75 + ], + "floatRgba": [ + 0.1, + 0.2, + 0.3, + 0.4 + ], + "packedRgba": 287454020, + "transparentBoundary": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "setup": { + "kind": "none" + } + }, + { + "defaultValue": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "hostExecution": "normal", + "mode": "direct-native-property-setter", + "objectName": "AnnotationColorProbe", + "objectTypeId": "TechDraw::DrawViewAnnotation", + "phases": { + "byteRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorProbe", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.003921569, + 0.498039216, + 1.0, + 1.0 + ] + }, + "byteRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorProbe", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 0.501960814, + 0.0, + 0.250980407 + ] + }, + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorProbe", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "floatRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorProbe", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.25, + 0.5, + 0.75, + 1.0 + ] + }, + "floatRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorProbe", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.100000001, + 0.200000003, + 0.300000012, + 0.400000006 + ] + }, + "packedRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorProbe", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorProbe", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "transparentBoundary": { + "editorMode": [], + "objectSet": [ + { + "name": "AnnotationColorProbe", + "typeId": "TechDraw::DrawViewAnnotation" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "TextColor", + "requested": { + "byteRgb": [ + 1, + 127, + 255 + ], + "byteRgba": [ + 255, + 128, + 0, + 64 + ], + "floatRgb": [ + 0.25, + 0.5, + 0.75 + ], + "floatRgba": [ + 0.1, + 0.2, + 0.3, + 0.4 + ], + "packedRgba": 287454020, + "transparentBoundary": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "setup": { + "kind": "none" + } + }, + { + "defaultValue": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "hostExecution": "normal", + "mode": "direct-native-property-setter", + "objectName": "DraftColorProbe", + "objectTypeId": "TechDraw::DrawViewDraft", + "phases": { + "byteRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorProbe", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.003921569, + 0.498039216, + 1.0, + 1.0 + ] + }, + "byteRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorProbe", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 0.501960814, + 0.0, + 0.250980407 + ] + }, + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorProbe", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "floatRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorProbe", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.25, + 0.5, + 0.75, + 1.0 + ] + }, + "floatRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorProbe", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.100000001, + 0.200000003, + 0.300000012, + 0.400000006 + ] + }, + "packedRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorProbe", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorProbe", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "transparentBoundary": { + "editorMode": [], + "objectSet": [ + { + "name": "DraftColorProbe", + "typeId": "TechDraw::DrawViewDraft" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "Color", + "requested": { + "byteRgb": [ + 1, + 127, + 255 + ], + "byteRgba": [ + 255, + 128, + 0, + 64 + ], + "floatRgb": [ + 0.25, + 0.5, + 0.75 + ], + "floatRgba": [ + 0.1, + 0.2, + 0.3, + 0.4 + ], + "packedRgba": 287454020, + "transparentBoundary": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "setup": { + "kind": "none" + } + }, + { + "defaultValue": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "hostExecution": "normal", + "mode": "direct-native-property-setter", + "objectName": "SpreadsheetColorProbe", + "objectTypeId": "TechDraw::DrawViewSpreadsheet", + "phases": { + "byteRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorProbe", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "ColorSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.003921569, + 0.498039216, + 1.0, + 1.0 + ] + }, + "byteRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorProbe", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "ColorSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 1.0, + 0.501960814, + 0.0, + 0.250980407 + ] + }, + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorProbe", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "ColorSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "floatRgb": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorProbe", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "ColorSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.25, + 0.5, + 0.75, + 1.0 + ] + }, + "floatRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorProbe", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "ColorSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.100000001, + 0.200000003, + 0.300000012, + 0.400000006 + ] + }, + "packedRgba": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorProbe", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "ColorSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorProbe", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "ColorSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "transparentBoundary": { + "editorMode": [], + "objectSet": [ + { + "name": "SpreadsheetColorProbe", + "typeId": "TechDraw::DrawViewSpreadsheet" + }, + { + "name": "ColorSource", + "typeId": "Spreadsheet::Sheet" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColor", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "TextColor", + "requested": { + "byteRgb": [ + 1, + 127, + 255 + ], + "byteRgba": [ + 255, + 128, + 0, + 64 + ], + "floatRgb": [ + 0.25, + 0.5, + 0.75 + ], + "floatRgba": [ + 0.1, + 0.2, + 0.3, + 0.4 + ], + "packedRgba": 287454020, + "transparentBoundary": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "setup": { + "kind": "spreadsheet-source", + "objectName": "ColorSource", + "objectTypeId": "Spreadsheet::Sheet" + } + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyColor", + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-colorlist-failure.json b/config/freecad-property-colorlist-failure.json new file mode 100644 index 0000000..4b5d570 --- /dev/null +++ b/config/freecad-property-colorlist-failure.json @@ -0,0 +1,1104 @@ +{ + "baselineId": "freecad-1.1.1-property-colorlist-failure", + "cancellationBoundary": { + "classification": "synchronous-property-setter", + "reason": "no-native-cancel-hook", + "replacement": "abort-active-document-transaction", + "supported": false + }, + "coercions": [ + { + "accepted": true, + "after": [ + [ + 0.0, + 0.0, + 0.0, + 0.003921569 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "boolean-scalar", + "objectsPreserved": true, + "requested": "True", + "valuePreserved": false + }, + { + "accepted": true, + "after": [ + [ + 0.0, + 0.0, + 0.0, + 0.003921569 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "bytes-sequence", + "objectsPreserved": true, + "requested": "b'\\x01\\xff'", + "valuePreserved": false + }, + { + "accepted": true, + "after": [ + [ + 0.100000001, + 0.200000003, + 0.300000012, + 0.400000006 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "bare-float-tuple", + "objectsPreserved": true, + "requested": "(0.1, 0.2, 0.3, 0.4)", + "valuePreserved": false + }, + { + "accepted": true, + "after": [ + [ + 1.0, + 0.501960814, + 0.0, + 0.250980407 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "bare-integer-tuple", + "objectsPreserved": true, + "requested": "(255, 128, 0, 64)", + "valuePreserved": false + }, + { + "accepted": true, + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "tuple-packed-sequence", + "objectsPreserved": true, + "requested": "(287454020, 4294967295)", + "valuePreserved": true + }, + { + "accepted": true, + "after": [], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": null, + "id": "empty-dictionary", + "objectsPreserved": true, + "requested": "{}", + "valuePreserved": false + } + ], + "disabled": { + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "classification": "editor-readonly-python-mutable-until-immutable", + "editorMode": [ + "ReadOnly" + ], + "editorReadOnlyAfter": [ + [ + 0.200000003, + 0.300000012, + 0.400000006, + 0.5 + ] + ], + "editorReadOnlyException": null, + "editorReadOnlyRequested": [ + [ + 0.2, + 0.3, + 0.4, + 0.5 + ] + ], + "immutableAfter": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "immutableException": { + "message": "Object attribute 'ColourList' is read-only", + "type": "AttributeError" + }, + "immutableRequested": [ + [ + 0.6, + 0.7, + 0.8, + 0.9 + ] + ], + "immutableStatus": [ + "Immutable", + "ReadOnly" + ], + "immutableValuePreserved": true, + "objectsPreserved": true, + "pythonBypassesEditorReadOnly": true, + "restoredEditorMode": [], + "restoredStatus": [] + }, + "documentIntegrity": { + "finalObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "initialObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectsPreserved": true + }, + "failures": [ + { + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not NoneType", + "type": "TypeError" + }, + "id": "none", + "objectsPreserved": true, + "polluted": false, + "requested": "None", + "valuePreserved": true + }, + { + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not float", + "type": "TypeError" + }, + "id": "bare-float-list", + "objectsPreserved": true, + "polluted": false, + "requested": "[0.1, 0.2, 0.3, 0.4]", + "valuePreserved": true + }, + { + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not float", + "type": "TypeError" + }, + "id": "bare-mixed-tuple", + "objectsPreserved": true, + "polluted": false, + "requested": "(0.1, 2, 0.3)", + "valuePreserved": true + }, + { + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not tuple", + "type": "TypeError" + }, + "id": "nested-short-tuple", + "objectsPreserved": true, + "polluted": false, + "requested": "[(0.1, 0.2)]", + "valuePreserved": true + }, + { + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not NoneType", + "type": "TypeError" + }, + "id": "mixed-valid-none", + "objectsPreserved": true, + "polluted": false, + "requested": "[(0.1, 0.2, 0.3, 0.4), None]", + "valuePreserved": true + }, + { + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not float", + "type": "TypeError" + }, + "id": "scalar-float", + "objectsPreserved": true, + "polluted": false, + "requested": "0.5", + "valuePreserved": true + }, + { + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not str", + "type": "TypeError" + }, + "id": "string-sequence", + "objectsPreserved": true, + "polluted": false, + "requested": "'rgb'", + "valuePreserved": true + }, + { + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not list", + "type": "TypeError" + }, + "id": "nested-list", + "objectsPreserved": true, + "polluted": false, + "requested": "[[0.1, 0.2, 0.3, 0.4]]", + "valuePreserved": true + }, + { + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "expect key type to be integer", + "type": "TypeError" + }, + "id": "dictionary-string-key", + "objectsPreserved": true, + "polluted": false, + "requested": "{'0': 287454020}", + "valuePreserved": true + }, + { + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "index out of bound", + "type": "ValueError" + }, + "id": "dictionary-high-index", + "objectsPreserved": true, + "polluted": false, + "requested": "{3: 287454020}", + "valuePreserved": true + }, + { + "after": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "index out of bound", + "type": "ValueError" + }, + "id": "dictionary-negative-index", + "objectsPreserved": true, + "polluted": false, + "requested": "{-2: 287454020}", + "valuePreserved": true + }, + { + "after": [ + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "beforeObjects": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "exception": { + "message": "type must be integer or tuple of float or tuple integer, not NoneType", + "type": "TypeError" + }, + "id": "dictionary-partial-invalid", + "objectsPreserved": true, + "polluted": false, + "requested": "{0: 16909060, 1: None}", + "valuePreserved": false + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "initial": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "object": { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + }, + "property": { + "name": "ColourList", + "typeId": "App::PropertyColorList" + }, + "propertyType": "App::PropertyColorList", + "schemaVersion": 1, + "status": "pass", + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 1, + "name": "property-colorlist-cancel" + }, + "afterAbort": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "afterRecompute": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "before": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 1.0, + 1.0, + 1.0 + ] + ], + "edited": [ + [ + 0.75, + 0.5, + 0.25, + 0.125 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 0.0, + 1.0, + 0.0, + 0.501960814 + ] + ], + "objectsAfter": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectsBefore": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectsRestored": true, + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "recoveryRecomputeResult": true, + "restored": true, + "stateAfterAbort": { + "state": [ + "Touched" + ], + "statusString": "Touched" + }, + "stateAfterEdit": { + "state": [ + "Touched" + ], + "statusString": "Touched" + }, + "stateAfterRecompute": { + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "undoMode": 1 + } +} diff --git a/config/freecad-property-colorlist-inventory.json b/config/freecad-property-colorlist-inventory.json new file mode 100644 index 0000000..642f938 --- /dev/null +++ b/config/freecad-property-colorlist-inventory.json @@ -0,0 +1,174 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyColorList", + "recordCount": 2, + "records": [ + { + "objectTypeId": "App::FeatureTest", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "ColourList", + "group": "", + "status": [], + "defaultValue": [ + [ + 0, + 0, + 0, + 1 + ] + ], + "valueModel": { + "kind": "ordered-rgba-color-list", + "elementRepresentation": "four-channel-float-tuple", + "packedElementRepresentation": "0xRRGGBBAA", + "alphaSemantics": "1-opaque-0-transparent", + "writable": true + }, + "inputs": { + "collection": [ + "sequence", + "iterable", + "single-tuple-color-value", + "single-non-sequence-color-value", + "integer-index-dictionary" + ], + "dictionaryAppendIndexes": [ + -1, + "current-size" + ], + "elementSetters": [ + "float-tuple-3-or-4", + "integer-tuple-3-or-4", + "packed-integer-0xRRGGBBAA" + ] + }, + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "App::FeatureTest", + "source": "Document.supportedTypes runtime inventory", + "shapeRequired": false + } + }, + { + "objectTypeId": "App::FeatureTestException", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "ColourList", + "group": "", + "status": [], + "defaultValue": [ + [ + 0, + 0, + 0, + 1 + ] + ], + "valueModel": { + "kind": "ordered-rgba-color-list", + "elementRepresentation": "four-channel-float-tuple", + "packedElementRepresentation": "0xRRGGBBAA", + "alphaSemantics": "1-opaque-0-transparent", + "writable": true + }, + "inputs": { + "collection": [ + "sequence", + "iterable", + "single-tuple-color-value", + "single-non-sequence-color-value", + "integer-index-dictionary" + ], + "dictionaryAppendIndexes": [ + -1, + "current-size" + ], + "elementSetters": [ + "float-tuple-3-or-4", + "integer-tuple-3-or-4", + "packed-integer-0xRRGGBBAA" + ] + }, + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "App::FeatureTestException", + "source": "Document.supportedTypes runtime inventory", + "shapeRequired": false + } + } + ], + "storage": { + "xmlElement": "ColorList", + "fileAttribute": "file", + "nonEmptyExternalResourceName": "property-name", + "emptyResourceName": "", + "externalBinary": { + "byteOrder": "little-endian", + "count": "uint32", + "element": "uint32-packed-0xRRGGBBAA" + }, + "legacyBeforeVersion": "1.1", + "legacyConversion": "invert-alpha-channel" + }, + "provenance": { + "runtime": { + "path": ".cache/freecad/reference-desktop.json", + "bytes": 2298709, + "sha256": "082400ec7379e8efc2af16709032d45890d7092277967b714acb05761fd1c2a7" + }, + "sources": [ + { + "path": ".cache/freecad/FreeCAD/src/App/Property.h", + "bytes": 38213, + "sha256": "a1e7320ff880133a2131db148dc6c87659de5c765387c2d41995c9650f12d8b6" + }, + { + "path": ".cache/freecad/FreeCAD/src/App/Property.cpp", + "bytes": 12499, + "sha256": "7d229c0a781694f3c507afbdaae25c8ee7f316088ce25e8e487bb7112bff5c70" + }, + { + "path": ".cache/freecad/FreeCAD/src/App/PropertyStandard.h", + "bytes": 37529, + "sha256": "3555ab386b4815329b09604bbd70626c2b24b66f90a7ff2c31052b55fd3c9244" + }, + { + "path": ".cache/freecad/FreeCAD/src/App/PropertyStandard.cpp", + "bytes": 99757, + "sha256": "eeefbbd7020c85c21e2e6b5f777088261668492845cf4d172e31f600fe9b96fd" + }, + { + "path": ".cache/freecad/FreeCAD/src/Base/Color.h", + "bytes": 8885, + "sha256": "4d4630c87209f0df85db30608026fc4389936719a301136c3eb389f0e48bf864" + }, + { + "path": ".cache/freecad/FreeCAD/src/Base/Stream.h", + "bytes": 19302, + "sha256": "6e38309e26a986c4d6c6c09a78815c6e854ee40b9057590f992fc321525e4203" + }, + { + "path": ".cache/freecad/FreeCAD/src/Base/Stream.cpp", + "bytes": 22807, + "sha256": "52762550a00e94b737ebd866e6d649828a4517d143a1f0313844f57b7affa577" + } + ] + }, + "classification": "opaque-fcstd-proxy", + "nextPhases": [ + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I" + ] +} diff --git a/config/freecad-property-colorlist-mutation.json b/config/freecad-property-colorlist-mutation.json new file mode 100644 index 0000000..adf6a1e --- /dev/null +++ b/config/freecad-property-colorlist-mutation.json @@ -0,0 +1,418 @@ +{ + "baselineId": "freecad-1.1.1-property-colorlist-mutation", + "caseCount": 2, + "cases": [ + { + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListMutation", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ] + }, + "editRecomputeResult": true, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListMutation", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 0.0, + 0.501960814, + 0.250980407 + ], + [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + }, + "hostExecution": "normal", + "mutationDetected": true, + "objectName": "FeatureTestColorListMutation", + "objectTypeId": "App::FeatureTest", + "propertyName": "ColourList", + "restoreRecomputeResult": true, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListMutation", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ] + }, + "restoredExactly": true, + "target": [ + [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + 287454020, + [ + 255, + 0, + 128, + 64 + ], + [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + ], + "touchedAfterEdit": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListMutation", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 0.0, + 0.501960814, + 0.250980407 + ], + [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListMutation", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ] + } + }, + { + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListMutation", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ] + }, + "editRecomputeResult": true, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListMutation", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 0.0, + 0.501960814, + 0.250980407 + ], + [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + }, + "hostExecution": "intrinsic-test-exception", + "mutationDetected": true, + "objectName": "FeatureTestExceptionColorListMutation", + "objectTypeId": "App::FeatureTestException", + "propertyName": "ColourList", + "restoreRecomputeResult": true, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListMutation", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ] + }, + "restoredExactly": true, + "target": [ + [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + 287454020, + [ + 255, + 0, + 128, + 64 + ], + [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + ], + "touchedAfterEdit": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListMutation", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "value": [ + [ + 0.125, + 0.375, + 0.625, + 0.875 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 1.0, + 0.0, + 0.501960814, + 0.250980407 + ], + [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + }, + "touchedAfterRestore": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListMutation", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ] + } + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyColorList", + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-colorlist-promotion.json b/config/freecad-property-colorlist-promotion.json new file mode 100644 index 0000000..ba555d6 --- /dev/null +++ b/config/freecad-property-colorlist-promotion.json @@ -0,0 +1,97 @@ +{ + "schemaVersion": 1, + "status": "pass", + "taskId": "PROP-app-propertycolorlist-I", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyColorList", + "recordCount": 2, + "phaseEvidence": { + "A": [ + "config/freecad-property-colorlist-inventory.json", + "check:freecad-property-colorlist-inventory" + ], + "B": [ + "config/freecad-property-colorlist-success.json", + "check:freecad-property-colorlist-success" + ], + "C": [ + "config/freecad-property-colorlist-failure.json", + "check:freecad-property-colorlist-failure" + ], + "D": [ + "config/freecad-property-colorlist-mutation.json", + "check:freecad-property-colorlist-mutation" + ], + "E": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyColorListFacade.test.ts", + "test:freecad-property-colorlist-facade" + ], + "F": [ + "tests/propertyColorListTransaction.test.ts", + "test:freecad-property-colorlist-transaction" + ], + "G": [ + "config/freecad-property-colorlist-roundtrip.json", + "check:freecad-property-colorlist-roundtrip" + ], + "H": [ + "config/chrome-property-colorlist-verification.json", + "check:chrome-property-colorlist" + ] + }, + "promotion": { + "from": "opaque-fcstd-proxy", + "to": "native-editable-codec", + "facadeValueModel": "ordered-variable-rgba-array-with-external-8-bit-fcstd-packing", + "writableRecords": 2, + "fcstdElement": "ColorList", + "fcstdResourcePath": "ColourList", + "fcstdResourceBytes": 12, + "nativeRoundTripValue": [ + [ + 0.200000003, + 0.400000006, + 0.600000024, + 0.800000012 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + ], + "browserRoundTripValue": [ + [ + 0.2, + 0.4, + 0.6, + 0.8 + ], + [ + 0.06666666666666667, + 0.13333333333333333, + 0.2, + 0.4 + ] + ], + "zeroUnknownDrift": true + }, + "exactBlockerSync": { + "nativeEditableTypes": 30, + "nativeEditableRecords": 4361, + "opaqueTypes": 50, + "opaqueRecords": 466, + "exactPromotionReady": false, + "exactBlocker": "50 runtime property types and 466 records remain opaque-only; complete native document and property semantics" + }, + "systemExact": false, + "generatedAt": "2026-08-17T08:49:33.826Z" +} diff --git a/config/freecad-property-colorlist-roundtrip.json b/config/freecad-property-colorlist-roundtrip.json new file mode 100644 index 0000000..9cb987a --- /dev/null +++ b/config/freecad-property-colorlist-roundtrip.json @@ -0,0 +1,198 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-colorlist-roundtrip", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyColorList", + "archives": { + "nativeInitial": { + "path": ".cache/freecad/property-colorlist-roundtrip/native-initial.FCStd", + "bytes": 2510, + "sha256": "e4df2d68ecaae973613b1c8026e98502d69fc961943619fbb1624926f3b2e0af" + }, + "webEdited": { + "path": ".cache/freecad/property-colorlist-roundtrip/web-edited.FCStd", + "bytes": 2330, + "sha256": "1efb3343cf3c9eb3e3f843287fdab2890727a631aff8ea574b60eeaf955181ca" + }, + "nativeResaved": { + "path": ".cache/freecad/property-colorlist-roundtrip/native-resaved.FCStd", + "bytes": 2511, + "sha256": "0b14d095c2ecf85a19c588bf2b55bddea64f64a99f686fc2e837b98a2454a13f" + } + }, + "nativeInitial": { + "object": { + "editorMode": [], + "hasShapeProperty": false, + "name": "ColorListProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::FeatureTest", + "value": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + ] + }, + "objectSet": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ] + }, + "web": { + "before": { + "name": "ColourList", + "typeId": "App::PropertyColorList", + "element": "ColorList", + "value": "[[0.06666666666666667,0.13333333333333333,0.2,0.26666666666666666]]", + "resourcePath": "ColourList" + }, + "after": { + "name": "ColourList", + "typeId": "App::PropertyColorList", + "element": "ColorList", + "value": "[[0.2,0.4,0.6,0.8],[0.06666666666666667,0.13333333333333333,0.2,0.26666666666666666]]", + "resourcePath": "ColourList" + }, + "resource": { + "path": "ColourList", + "pathPreserved": true, + "beforeBytes": 8, + "afterBytes": 12, + "changed": true + }, + "objectSetPreserved": true, + "semanticObjectsPreserved": true, + "opaquePathsPreserved": 3, + "opaqueEntriesPreserved": true + }, + "nativeAfter": { + "reopened": { + "object": { + "editorMode": [], + "hasShapeProperty": false, + "name": "ColorListProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::FeatureTest", + "value": [ + [ + 0.200000003, + 0.400000006, + 0.600000024, + 0.800000012 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + ] + }, + "objectSet": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ] + }, + "resaved": { + "object": { + "editorMode": [], + "hasShapeProperty": false, + "name": "ColorListProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::FeatureTest", + "value": [ + [ + 0.200000003, + 0.400000006, + 0.600000024, + 0.800000012 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + ] + }, + "objectSet": [ + { + "name": "ColorListProbe", + "typeId": "App::FeatureTest" + } + ] + } + }, + "classification": { + "requestedValue": [ + [ + 0.2, + 0.4, + 0.6, + 0.8 + ], + [ + 0.06666666666666667, + 0.13333333333333333, + 0.2, + 0.26666666666666666 + ] + ], + "webValue": "[[0.2,0.4,0.6,0.8],[0.06666666666666667,0.13333333333333333,0.2,0.26666666666666666]]", + "reopenedValue": [ + [ + 0.200000003, + 0.400000006, + 0.600000024, + 0.800000012 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + ], + "resavedValue": [ + [ + 0.200000003, + 0.400000006, + 0.600000024, + 0.800000012 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + ], + "nativeOutputMatches": true, + "unknownSemanticDrift": false, + "zeroUnknownDrift": true + } +} diff --git a/config/freecad-property-colorlist-success.json b/config/freecad-property-colorlist-success.json new file mode 100644 index 0000000..2994b8a --- /dev/null +++ b/config/freecad-property-colorlist-success.json @@ -0,0 +1,3677 @@ +{ + "baselineId": "freecad-1.1.1-property-colorlist-success", + "caseCount": 2, + "cases": [ + { + "defaultValue": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "hostExecution": "normal", + "mode": "native-property-list-setter", + "objectName": "FeatureTestColorListProbe", + "objectTypeId": "App::FeatureTest", + "phases": { + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": false, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ] + }, + "empty": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [] + }, + "indexedDictionary": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 0.0, + 1.0, + 0.0, + 0.501960814 + ] + ] + }, + "iterable": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.0, + 0.25, + 0.5, + 0.75 + ], + [ + 1.0, + 0.75, + 0.5, + 0.25 + ] + ] + }, + "largeList": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ] + ] + }, + "mixedElements": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.100000001, + 0.200000003, + 0.300000012, + 0.400000006 + ], + [ + 1.0, + 0.501960814, + 0.0, + 0.250980407 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ] + }, + "singlePacked": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + ] + }, + "singletonFloat": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestColorListProbe", + "typeId": "App::FeatureTest" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.25, + 0.5, + 0.75, + 1.0 + ] + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "ColourList" + }, + { + "defaultValue": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "hostExecution": "intrinsic-test-exception", + "mode": "native-property-list-setter", + "objectName": "FeatureTestExceptionColorListProbe", + "objectTypeId": "App::FeatureTestException", + "phases": { + "default": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": false, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ] + }, + "empty": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [] + }, + "indexedDictionary": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ], + [ + 0.0, + 1.0, + 0.0, + 0.501960814 + ] + ] + }, + "iterable": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + [ + 0.0, + 0.25, + 0.5, + 0.75 + ], + [ + 1.0, + 0.75, + 0.5, + 0.25 + ] + ] + }, + "largeList": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ], + [ + 0.003921569, + 0.007843138, + 0.011764706, + 0.015686275 + ] + ] + }, + "mixedElements": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + [ + 0.100000001, + 0.200000003, + 0.300000012, + 0.400000006 + ], + [ + 1.0, + 0.501960814, + 0.0, + 0.250980407 + ], + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + ] + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ] + }, + "singlePacked": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + [ + 0.06666667, + 0.13333334, + 0.200000003, + 0.266666681 + ] + ] + }, + "singletonFloat": { + "editorMode": [], + "objectSet": [ + { + "name": "FeatureTestExceptionColorListProbe", + "typeId": "App::FeatureTestException" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyColorList", + "recomputeResult": true, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "FeatureTestException::execute(): Testexception ;-)", + "value": [ + [ + 0.25, + 0.5, + 0.75, + 1.0 + ] + ] + } + }, + "propertyAssignmentsAccepted": true, + "propertyName": "ColourList" + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyColorList", + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-direction-failure.json b/config/freecad-property-direction-failure.json new file mode 100644 index 0000000..25dabb5 --- /dev/null +++ b/config/freecad-property-direction-failure.json @@ -0,0 +1,1321 @@ +{ + "baselineId": "freecad-1.1.1-property-direction-failure", + "cancellationBoundary": { + "classification": "synchronous-property-setter", + "reason": "no-native-cancel-hook", + "replacement": "abort-active-document-transaction", + "supported": false + }, + "consumerFailures": [ + { + "afterRecompute": { + "objects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "shape": { + "brepSha256": "ba65608213dd700751777e936c8f7cdd2b84a9e043a4deeec8e57eec3614b69b", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8 + }, + "state": { + "mustExecute": true, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "gp_Dir() - input vector has zero norm" + }, + "value": [ + 0, + 0, + 0 + ] + }, + "afterSet": { + "shape": { + "brepSha256": "ba65608213dd700751777e936c8f7cdd2b84a9e043a4deeec8e57eec3614b69b", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8 + }, + "state": { + "mustExecute": true, + "state": [ + "Touched" + ], + "statusString": "Touched" + }, + "value": [ + 0, + 0, + 0 + ] + }, + "before": { + "objects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "shape": { + "brepSha256": "ba65608213dd700751777e936c8f7cdd2b84a9e043a4deeec8e57eec3614b69b", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8 + }, + "state": { + "mustExecute": false, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "value": [ + 0, + 0, + 1 + ] + }, + "id": "Mirroring-zero", + "initialRecomputeResult": true, + "objectTypeId": "Part::Mirroring", + "objectsPreserved": true, + "propertyName": "Normal", + "recomputeException": null, + "recomputeResult": true, + "requested": [ + 0, + 0, + 0 + ], + "setterException": null + }, + { + "afterRecompute": { + "objects": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "shape": { + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "state": { + "mustExecute": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "gp_Dir() - input vector has zero norm" + }, + "value": [ + 0, + 0, + 0 + ] + }, + "afterSet": { + "shape": { + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "state": { + "mustExecute": false, + "state": [ + "Touched" + ], + "statusString": "Touched" + }, + "value": [ + 0, + 0, + 0 + ] + }, + "before": { + "objects": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "shape": { + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "state": { + "mustExecute": false, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "value": [ + 0, + 0, + 1 + ] + }, + "id": "ProjectOnSurface-zero", + "initialRecomputeResult": true, + "objectTypeId": "Part::ProjectOnSurface", + "objectsPreserved": true, + "propertyName": "Direction", + "recomputeException": null, + "recomputeResult": true, + "requested": [ + 0, + 0, + 0 + ], + "setterException": null + } + ], + "dependencyFailures": [ + { + "afterRecompute": { + "objects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "shape": { + "brepSha256": "ba65608213dd700751777e936c8f7cdd2b84a9e043a4deeec8e57eec3614b69b", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8 + }, + "state": { + "mustExecute": true, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "No object linked" + }, + "value": [ + 0, + 0, + 1 + ] + }, + "before": { + "objects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "shape": { + "brepSha256": "ba65608213dd700751777e936c8f7cdd2b84a9e043a4deeec8e57eec3614b69b", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8 + }, + "state": { + "mustExecute": false, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "value": [ + 0, + 0, + 1 + ] + }, + "id": "Mirroring-no-source", + "objectTypeId": "Part::Mirroring", + "objectsPreserved": true, + "propertyName": "Normal", + "recomputeException": null, + "recomputeResult": true, + "removed": { + "property": "Source", + "value": null + } + }, + { + "afterRecompute": { + "objects": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "shape": { + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "state": { + "mustExecute": false, + "state": [ + "Touched", + "Invalid" + ], + "statusString": "No support face specified" + }, + "value": [ + 0, + 0, + 1 + ] + }, + "before": { + "objects": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "shape": { + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "state": { + "mustExecute": false, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "value": [ + 0, + 0, + 1 + ] + }, + "id": "ProjectOnSurface-no-support", + "objectTypeId": "Part::ProjectOnSurface", + "objectsPreserved": true, + "propertyName": "Direction", + "recomputeException": null, + "recomputeResult": true, + "removed": { + "property": "SupportFace", + "value": null + } + }, + { + "afterRecompute": { + "objects": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "shape": { + "edges": 0, + "faces": 0, + "isNull": true, + "shapeType": "Null", + "solids": 0, + "valid": false, + "vertices": 0 + }, + "state": { + "mustExecute": false, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "value": [ + 0, + 0, + 1 + ] + }, + "before": { + "objects": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "shape": { + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4 + }, + "state": { + "mustExecute": false, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "value": [ + 0, + 0, + 1 + ] + }, + "id": "ProjectOnSurface-no-projection", + "objectTypeId": "Part::ProjectOnSurface", + "objectsPreserved": true, + "propertyName": "Direction", + "recomputeException": null, + "recomputeResult": true, + "removed": { + "property": "Projection", + "value": [] + } + } + ], + "disabled": { + "before": [ + 0, + 0, + 1 + ], + "classification": "editor-readonly-python-mutable-until-immutable", + "editorAfter": [ + 1, + 0, + 1 + ], + "editorException": null, + "editorMode": [ + "ReadOnly" + ], + "editorRequested": [ + 1, + 0, + 1 + ], + "immutableAfter": [ + 0, + 0, + 1 + ], + "immutableException": { + "message": "Object attribute 'Normal' is read-only", + "type": "AttributeError" + }, + "immutableRequested": [ + 0, + 1, + 1 + ], + "immutableStatus": [ + "Immutable" + ], + "immutableValuePreserved": true, + "pythonBypassesEditorReadOnly": true, + "restoredEditorMode": [], + "restoredStatus": [] + }, + "documentIntegrity": { + "allObjectsPreserved": true, + "disabledAndTransaction": { + "finalObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "initialObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectsPreserved": true + }, + "setter": { + "finalObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "initialObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectsPreserved": true + } + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyDirection", + "schemaVersion": 1, + "setterBoundaries": { + "acceptedCoercions": [ + { + "accepted": true, + "after": [ + 1, + 0.5, + 2 + ], + "before": [ + 0, + 0, + 1 + ], + "exception": null, + "id": "mixed-numeric-tuple", + "objectsPreserved": true, + "requested": "(1, 0.5, 2)" + }, + { + "accepted": true, + "after": [ + 1, + 0, + 1 + ], + "before": [ + 0, + 0, + 1 + ], + "exception": null, + "id": "boolean-tuple", + "objectsPreserved": true, + "requested": "(True, False, True)" + } + ], + "baseline": [ + 0, + 0, + 1 + ], + "documentIntegrity": { + "finalObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "initialObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectsPreserved": true + }, + "failures": [ + { + "after": [ + 0, + 0, + 1 + ], + "afterObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "before": [ + 0, + 0, + 1 + ], + "beforeObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "exception": { + "message": "type must be 'Vector' or tuple of three floats, not NoneType", + "type": "TypeError" + }, + "id": "none", + "objectsPreserved": true, + "polluted": false, + "requested": "None", + "valuePreserved": true + }, + { + "after": [ + 0, + 0, + 1 + ], + "afterObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "before": [ + 0, + 0, + 1 + ], + "beforeObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "exception": { + "message": "type must be 'Vector' or tuple of three floats, not list", + "type": "TypeError" + }, + "id": "list", + "objectsPreserved": true, + "polluted": false, + "requested": "[0.0, 0.0, 1.0]", + "valuePreserved": true + }, + { + "after": [ + 0, + 0, + 1 + ], + "afterObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "before": [ + 0, + 0, + 1 + ], + "beforeObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "exception": { + "message": "type must be 'Vector' or tuple of three floats, not tuple", + "type": "TypeError" + }, + "id": "short-tuple", + "objectsPreserved": true, + "polluted": false, + "requested": "(0.0, 1.0)", + "valuePreserved": true + }, + { + "after": [ + 0, + 0, + 1 + ], + "afterObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "before": [ + 0, + 0, + 1 + ], + "beforeObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "exception": { + "message": "type must be 'Vector' or tuple of three floats, not tuple", + "type": "TypeError" + }, + "id": "long-tuple", + "objectsPreserved": true, + "polluted": false, + "requested": "(0.0, 0.0, 1.0, 2.0)", + "valuePreserved": true + }, + { + "after": [ + 0, + 0, + 1 + ], + "afterObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "before": [ + 0, + 0, + 1 + ], + "beforeObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "exception": { + "message": "Not allowed type used in tuple (float expected)...", + "type": "TypeError" + }, + "id": "string-component", + "objectsPreserved": true, + "polluted": false, + "requested": "(0.0, 'bad', 1.0)", + "valuePreserved": true + }, + { + "after": [ + 0, + 0, + 1 + ], + "afterObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "before": [ + 0, + 0, + 1 + ], + "beforeObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "exception": { + "message": "type must be 'Vector' or tuple of three floats, not float", + "type": "TypeError" + }, + "id": "scalar-float", + "objectsPreserved": true, + "polluted": false, + "requested": "1.0", + "valuePreserved": true + }, + { + "after": [ + 0, + 0, + 1 + ], + "afterObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "before": [ + 0, + 0, + 1 + ], + "beforeObjects": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "exception": { + "message": "type must be 'Vector' or tuple of three floats, not int", + "type": "TypeError" + }, + "id": "scalar-integer", + "objectsPreserved": true, + "polluted": false, + "requested": "1", + "valuePreserved": true + } + ], + "object": { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + }, + "property": { + "name": "Normal", + "typeId": "App::PropertyDirection" + } + }, + "status": "pass", + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 1, + "name": "property-direction-cancel" + }, + "afterAbort": [ + 0, + 0, + 1 + ], + "afterRecompute": [ + 0, + 0, + 1 + ], + "before": [ + 0, + 0, + 1 + ], + "edited": [ + 0.25, + -0.5, + 1.5 + ], + "objectsAfter": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectsBefore": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectsRestored": true, + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "recoveryRecomputeResult": true, + "restored": true, + "stateAfterAbort": { + "mustExecute": true, + "state": [ + "Touched" + ], + "statusString": "Touched" + }, + "stateAfterEdit": { + "mustExecute": true, + "state": [ + "Touched" + ], + "statusString": "Touched" + }, + "stateAfterRecompute": { + "mustExecute": false, + "state": [ + "Up-to-date" + ], + "statusString": "Valid" + }, + "undoMode": 1 + }, + "nonFiniteConsumerBoundaries": [ + { + "id": "Mirroring-nan", + "mode": "non-finite:Mirroring:nan", + "attemptCount": 2, + "attempts": [ + { + "attempt": 1, + "timeoutMs": 5000, + "elapsedMs": 5009, + "timedOut": true, + "exitStatus": null, + "signal": "SIGTERM", + "errorCode": "ETIMEDOUT", + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FREECAD_PROPERTY_DIRECTION_PROGRESS=Mirroring-nan" + ], + "completedCase": null, + "outcome": "timeout" + }, + { + "attempt": 2, + "timeoutMs": 5000, + "elapsedMs": 5007, + "timedOut": true, + "exitStatus": null, + "signal": "SIGTERM", + "errorCode": "ETIMEDOUT", + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FREECAD_PROPERTY_DIRECTION_PROGRESS=Mirroring-nan" + ], + "completedCase": null, + "outcome": "timeout" + } + ], + "stable": true, + "classification": "native-synchronous-consumer-timeout" + }, + { + "id": "Mirroring-positive-infinity", + "mode": "non-finite:Mirroring:positive-infinity", + "attemptCount": 2, + "attempts": [ + { + "attempt": 1, + "timeoutMs": 5000, + "elapsedMs": 5008, + "timedOut": true, + "exitStatus": null, + "signal": "SIGTERM", + "errorCode": "ETIMEDOUT", + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FREECAD_PROPERTY_DIRECTION_PROGRESS=Mirroring-positive-infinity" + ], + "completedCase": null, + "outcome": "timeout" + }, + { + "attempt": 2, + "timeoutMs": 5000, + "elapsedMs": 5009, + "timedOut": true, + "exitStatus": null, + "signal": "SIGTERM", + "errorCode": "ETIMEDOUT", + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FREECAD_PROPERTY_DIRECTION_PROGRESS=Mirroring-positive-infinity" + ], + "completedCase": null, + "outcome": "timeout" + } + ], + "stable": true, + "classification": "native-synchronous-consumer-timeout" + }, + { + "id": "Mirroring-negative-infinity", + "mode": "non-finite:Mirroring:negative-infinity", + "attemptCount": 2, + "attempts": [ + { + "attempt": 1, + "timeoutMs": 5000, + "elapsedMs": 5007, + "timedOut": true, + "exitStatus": null, + "signal": "SIGTERM", + "errorCode": "ETIMEDOUT", + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FREECAD_PROPERTY_DIRECTION_PROGRESS=Mirroring-negative-infinity" + ], + "completedCase": null, + "outcome": "timeout" + }, + { + "attempt": 2, + "timeoutMs": 5000, + "elapsedMs": 5009, + "timedOut": true, + "exitStatus": null, + "signal": "SIGTERM", + "errorCode": "ETIMEDOUT", + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FREECAD_PROPERTY_DIRECTION_PROGRESS=Mirroring-negative-infinity" + ], + "completedCase": null, + "outcome": "timeout" + } + ], + "stable": true, + "classification": "native-synchronous-consumer-timeout" + }, + { + "id": "ProjectOnSurface-nan", + "mode": "non-finite:ProjectOnSurface:nan", + "attemptCount": 2, + "attempts": [ + { + "attempt": 1, + "timeoutMs": 5000, + "elapsedMs": 190, + "timedOut": false, + "exitStatus": 0, + "signal": null, + "errorCode": null, + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FreeCAD 1.1.1, Libs: 1.1.1R14556 (Git)", + "(C) 2001-2026 FreeCAD contributors", + "FreeCAD is free and open-source software licensed under the terms of LGPL2+ license.", + "Recompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t(100 %)\t\r\t\t\t\t\t\t\t\t\rRecompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t\t\t\r", + " Courbes non jointives", + "DirectionProjection: Courbes non jointives" + ], + "completedCase": null, + "outcome": "process-exited-without-completion" + }, + { + "attempt": 2, + "timeoutMs": 5000, + "elapsedMs": 190, + "timedOut": false, + "exitStatus": 0, + "signal": null, + "errorCode": null, + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FreeCAD 1.1.1, Libs: 1.1.1R14556 (Git)", + "(C) 2001-2026 FreeCAD contributors", + "FreeCAD is free and open-source software licensed under the terms of LGPL2+ license.", + "Recompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t(100 %)\t\r\t\t\t\t\t\t\t\t\rRecompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t\t\t\r", + " Courbes non jointives", + "DirectionProjection: Courbes non jointives" + ], + "completedCase": null, + "outcome": "process-exited-without-completion" + } + ], + "stable": true, + "classification": "native-process-exit-without-probe-completion" + }, + { + "id": "ProjectOnSurface-positive-infinity", + "mode": "non-finite:ProjectOnSurface:positive-infinity", + "attemptCount": 2, + "attempts": [ + { + "attempt": 1, + "timeoutMs": 5000, + "elapsedMs": 196, + "timedOut": false, + "exitStatus": 0, + "signal": null, + "errorCode": null, + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FreeCAD 1.1.1, Libs: 1.1.1R14556 (Git)", + "(C) 2001-2026 FreeCAD contributors", + "FreeCAD is free and open-source software licensed under the terms of LGPL2+ license.", + "Recompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t(100 %)\t\r\t\t\t\t\t\t\t\t\rRecompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t\t\t\r", + " Courbes non jointives", + "DirectionProjection: Courbes non jointives" + ], + "completedCase": null, + "outcome": "process-exited-without-completion" + }, + { + "attempt": 2, + "timeoutMs": 5000, + "elapsedMs": 195, + "timedOut": false, + "exitStatus": 0, + "signal": null, + "errorCode": null, + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FreeCAD 1.1.1, Libs: 1.1.1R14556 (Git)", + "(C) 2001-2026 FreeCAD contributors", + "FreeCAD is free and open-source software licensed under the terms of LGPL2+ license.", + "Recompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t(100 %)\t\r\t\t\t\t\t\t\t\t\rRecompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t\t\t\r", + " Courbes non jointives", + "DirectionProjection: Courbes non jointives" + ], + "completedCase": null, + "outcome": "process-exited-without-completion" + } + ], + "stable": true, + "classification": "native-process-exit-without-probe-completion" + }, + { + "id": "ProjectOnSurface-negative-infinity", + "mode": "non-finite:ProjectOnSurface:negative-infinity", + "attemptCount": 2, + "attempts": [ + { + "attempt": 1, + "timeoutMs": 5000, + "elapsedMs": 203, + "timedOut": false, + "exitStatus": 0, + "signal": null, + "errorCode": null, + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FreeCAD 1.1.1, Libs: 1.1.1R14556 (Git)", + "(C) 2001-2026 FreeCAD contributors", + "FreeCAD is free and open-source software licensed under the terms of LGPL2+ license.", + "Recompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t(100 %)\t\r\t\t\t\t\t\t\t\t\rRecompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t\t\t\r", + " Courbes non jointives", + "DirectionProjection: Courbes non jointives" + ], + "completedCase": null, + "outcome": "process-exited-without-completion" + }, + { + "attempt": 2, + "timeoutMs": 5000, + "elapsedMs": 193, + "timedOut": false, + "exitStatus": 0, + "signal": null, + "errorCode": null, + "progressMarkerObserved": true, + "completionMarkerObserved": false, + "diagnostic": [ + "FreeCAD 1.1.1, Libs: 1.1.1R14556 (Git)", + "(C) 2001-2026 FreeCAD contributors", + "FreeCAD is free and open-source software licensed under the terms of LGPL2+ license.", + "Recompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t(100 %)\t\r\t\t\t\t\t\t\t\t\rRecompute......", + "\t\t\t\t\t\t(33 %)\t\r\t\t\t\t\t\t(66 %)\t\r\t\t\t\t\t\t\t\t\r", + " Courbes non jointives", + "DirectionProjection: Courbes non jointives" + ], + "completedCase": null, + "outcome": "process-exited-without-completion" + } + ], + "stable": true, + "classification": "native-process-exit-without-probe-completion" + } + ] +} diff --git a/config/freecad-property-direction-inventory.json b/config/freecad-property-direction-inventory.json new file mode 100644 index 0000000..8dec9db --- /dev/null +++ b/config/freecad-property-direction-inventory.json @@ -0,0 +1,201 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyDirection", + "recordCount": 2, + "records": [ + { + "objectTypeId": "Part::Mirroring", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Normal", + "group": "Plane", + "status": [], + "defaultDisplayValue": "Vector (0.0, 0.0, 1.0)", + "defaultValue": [ + 0, + 0, + 1 + ], + "valueModel": { + "kind": "three-component-direction-vector", + "representation": "Base::Vector3d", + "normalizationAtPropertyBoundary": "none", + "unit": "Length", + "writable": true + }, + "inputs": { + "accepted": [ + "Base.Vector", + "tuple-of-three-float-or-integer-components" + ], + "listAccepted": false, + "componentPaths": [ + "x", + "y", + "z" + ] + }, + "editor": "Gui::PropertyEditor::PropertyDirectionItem", + "dependencies": [ + { + "propertyName": "Source", + "role": "shape-source", + "requiredForExecution": true + }, + { + "propertyName": "Base", + "role": "plane-origin", + "requiredForExecution": true + }, + { + "propertyName": "MirrorPlane", + "role": "optional-plane-override", + "requiredForExecution": false, + "overrides": [ + "Base", + "Normal" + ], + "overriddenStatus": "ReadOnly" + } + ], + "applicability": { + "requiredObjectTypeId": "Part::Mirroring", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false, + "hostExecutionRequiresShapeInputs": true, + "nonZeroRequiredByConsumer": true, + "consumer": "gp_Ax2(gp_Pnt(Base), gp_Dir(Normal))" + } + }, + { + "objectTypeId": "Part::ProjectOnSurface", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Direction", + "group": "Projection", + "status": [], + "defaultDisplayValue": "Vector (0.0, 0.0, 1.0)", + "defaultValue": [ + 0, + 0, + 1 + ], + "valueModel": { + "kind": "three-component-direction-vector", + "representation": "Base::Vector3d", + "normalizationAtPropertyBoundary": "none", + "unit": "Length", + "writable": true + }, + "inputs": { + "accepted": [ + "Base.Vector", + "tuple-of-three-float-or-integer-components" + ], + "listAccepted": false, + "componentPaths": [ + "x", + "y", + "z" + ] + }, + "editor": "Gui::PropertyEditor::PropertyDirectionItem", + "dependencies": [ + { + "propertyName": "SupportFace", + "role": "single-support-face", + "requiredForExecution": true + }, + { + "propertyName": "Projection", + "role": "projected-shape-list", + "requiredForExecution": true + } + ], + "applicability": { + "requiredObjectTypeId": "Part::ProjectOnSurface", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false, + "hostExecutionRequiresShapeInputs": true, + "nonZeroRequiredByConsumer": true, + "consumer": "gp_Dir(Direction)" + } + } + ], + "storage": { + "inheritedFrom": "App::PropertyVector", + "xmlElement": "PropertyVector", + "attributes": [ + "valueX", + "valueY", + "valueZ" + ], + "scalarEncoding": "decimal-double", + "externalResource": false + }, + "provenance": { + "runtime": { + "path": ".cache/freecad/reference-desktop.json", + "bytes": 2298709, + "sha256": "082400ec7379e8efc2af16709032d45890d7092277967b714acb05761fd1c2a7" + }, + "sources": [ + { + "path": ".cache/freecad/FreeCAD/src/App/PropertyGeo.h", + "bytes": 15791, + "sha256": "641182ca1267b318af377b9d1cf22a9cc0c365939866bafc8e5b51dc26d9a928" + }, + { + "path": ".cache/freecad/FreeCAD/src/App/PropertyGeo.cpp", + "bytes": 43128, + "sha256": "9e1553f42f8c537c8aee4d64d3bd06d4b8be0abc93e7b258901ee543fc52c553" + }, + { + "path": ".cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.h", + "bytes": 41826, + "sha256": "aaade89f5386b5d061b1b2d09a4fd01e7a27e3c601117fc00e44e115f347d9ed" + }, + { + "path": ".cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.cpp", + "bytes": 142093, + "sha256": "bf2f7cb4c01034425f4ebd46f901ada03c5fa02dcffbc1d3936e49ef7bc43b52" + }, + { + "path": ".cache/freecad/FreeCAD/src/Mod/Part/App/FeatureMirroring.h", + "bytes": 2808, + "sha256": "f1d4bab8dccf115d1d81791afea90c4ac12768a0b07ce3cfcfc08718e1158876" + }, + { + "path": ".cache/freecad/FreeCAD/src/Mod/Part/App/FeatureMirroring.cpp", + "bytes": 14307, + "sha256": "ce26935b3326ff5ddaf5a6e67ac5a7c52c03c1e6adf2e4f37b162fc6b755830e" + }, + { + "path": ".cache/freecad/FreeCAD/src/Mod/Part/App/FeatureProjectOnSurface.h", + "bytes": 4249, + "sha256": "79a3a3126d696d43f29a12802df9c006bc29f4a8ac9b2fa4619806e57691435d" + }, + { + "path": ".cache/freecad/FreeCAD/src/Mod/Part/App/FeatureProjectOnSurface.cpp", + "bytes": 16425, + "sha256": "19b4edfdb60d219aa2c120e7a90b390ca3cda438ed0bff72f43fa8ed09d3e5ed" + } + ] + }, + "classification": "opaque-fcstd-proxy", + "nextPhases": [ + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I" + ] +} diff --git a/config/freecad-property-direction-mutation.json b/config/freecad-property-direction-mutation.json new file mode 100644 index 0000000..eaaa22a --- /dev/null +++ b/config/freecad-property-direction-mutation.json @@ -0,0 +1,527 @@ +{ + "baselineId": "freecad-1.1.1-property-direction-mutation", + "caseCount": 2, + "cases": [ + { + "caseId": "Mirroring", + "editedValue": [ + 0.25, + -0.5, + 1.5 + ], + "geometryChanged": true, + "geometryRestored": true, + "objectName": "DirectionMirror", + "objectTypeId": "Part::Mirroring", + "objectsPreserved": true, + "phases": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "area": 52.0, + "bounds": [ + -1.170731707, + 0.0, + -3.609756098, + 2.195121951, + 4.951219512, + 1.756097561 + ], + "brepSha256": "78c098a6fa65ccee51c306e1af3d908c067c4866d0a937f225b35e5c4f00ce7f", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Valid", + "value": [ + 0.25, + -0.5, + 1.5 + ] + }, + "afterRestoreRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "area": 52.0, + "bounds": [ + 0.0, + 0.0, + -4.0, + 2.0, + 3.0, + 0.0 + ], + "brepSha256": "ba65608213dd700751777e936c8f7cdd2b84a9e043a4deeec8e57eec3614b69b", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 1.0 + ] + }, + "afterRestoreSet": { + "editorMode": [], + "mustExecute": true, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": null, + "shape": { + "area": 52.0, + "bounds": [ + 0.0, + 0.0, + -4.0, + 2.0, + 3.0, + 0.0 + ], + "brepSha256": "ba65608213dd700751777e936c8f7cdd2b84a9e043a4deeec8e57eec3614b69b", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Touched", + "value": [ + 0.0, + 0.0, + 1.0 + ] + }, + "afterSet": { + "editorMode": [], + "mustExecute": true, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": null, + "shape": { + "area": 52.0, + "bounds": [ + -1.170731707, + 0.0, + -3.609756098, + 2.195121951, + 4.951219512, + 1.756097561 + ], + "brepSha256": "78c098a6fa65ccee51c306e1af3d908c067c4866d0a937f225b35e5c4f00ce7f", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Touched", + "value": [ + 0.25, + -0.5, + 1.5 + ] + }, + "before": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "area": 52.0, + "bounds": [ + 0.0, + 0.0, + -4.0, + 2.0, + 3.0, + 0.0 + ], + "brepSha256": "ba65608213dd700751777e936c8f7cdd2b84a9e043a4deeec8e57eec3614b69b", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 1.0 + ] + } + }, + "propertyName": "Normal", + "valueChanged": true, + "valueRestored": true + }, + { + "caseId": "ProjectOnSurface", + "editedValue": [ + 0.25, + -0.5, + 1.5 + ], + "geometryChanged": true, + "geometryRestored": true, + "objectName": "DirectionProjection", + "objectTypeId": "Part::ProjectOnSurface", + "objectsPreserved": true, + "phases": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "area": 0.0, + "bounds": [ + -3.166666667, + -4.666666667, + -0.0, + 4.833333333, + 1.333333333, + 0.0 + ], + "brepSha256": "3c78808d667362064af03623580275fc042383070d13822c577066173f4ea7d8", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + 0.25, + -0.5, + 1.5 + ] + }, + "afterRestoreRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "area": 0.0, + "bounds": [ + -4.0, + -3.0, + 0.0, + 4.0, + 3.0, + 0.0 + ], + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 1.0 + ] + }, + "afterRestoreSet": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": null, + "shape": { + "area": 0.0, + "bounds": [ + -3.166666667, + -4.666666667, + -0.0, + 4.833333333, + 1.333333333, + 0.0 + ], + "brepSha256": "3c78808d667362064af03623580275fc042383070d13822c577066173f4ea7d8", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Touched", + "value": [ + 0.0, + 0.0, + 1.0 + ] + }, + "afterSet": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": null, + "shape": { + "area": 0.0, + "bounds": [ + -4.0, + -3.0, + 0.0, + 4.0, + 3.0, + 0.0 + ], + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Touched", + "value": [ + 0.25, + -0.5, + 1.5 + ] + }, + "before": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "area": 0.0, + "bounds": [ + -4.0, + -3.0, + 0.0, + 4.0, + 3.0, + 0.0 + ], + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 1.0 + ] + } + }, + "propertyName": "Direction", + "valueChanged": true, + "valueRestored": true + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyDirection", + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-direction-promotion.json b/config/freecad-property-direction-promotion.json new file mode 100644 index 0000000..26a19f3 --- /dev/null +++ b/config/freecad-property-direction-promotion.json @@ -0,0 +1,77 @@ +{ + "schemaVersion": 1, + "status": "pass", + "taskId": "PROP-app-propertydirection-I", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyDirection", + "recordCount": 2, + "phaseEvidence": { + "A": [ + "config/freecad-property-direction-inventory.json", + "check:freecad-property-direction-inventory" + ], + "B": [ + "config/freecad-property-direction-success.json", + "check:freecad-property-direction-success" + ], + "C": [ + "config/freecad-property-direction-failure.json", + "check:freecad-property-direction-failure" + ], + "D": [ + "config/freecad-property-direction-mutation.json", + "check:freecad-property-direction-mutation" + ], + "E": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyDirectionFacade.test.ts", + "test:freecad-property-direction-facade" + ], + "F": [ + "tests/propertyDirectionTransaction.test.ts", + "test:freecad-property-direction-transaction" + ], + "G": [ + "config/freecad-property-direction-roundtrip.json", + "check:freecad-property-direction-roundtrip" + ], + "H": [ + "config/chrome-property-direction-verification.json", + "check:chrome-property-direction" + ] + }, + "promotion": { + "from": "opaque-fcstd-proxy", + "to": "native-editable-codec", + "facadeValueModel": "three-finite-vector-components-with-native-propertyvector-fcstd-payload", + "writableRecords": 2, + "fcstdElement": "PropertyVector", + "nativeRoundTripValue": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + }, + "browserRoundTripValue": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + }, + "zeroUnknownDrift": true + }, + "exactBlockerSync": { + "nativeEditableTypes": 30, + "nativeEditableRecords": 4361, + "opaqueTypes": 50, + "opaqueRecords": 466, + "exactPromotionReady": false, + "exactBlocker": "50 runtime property types and 466 records remain opaque-only; complete native document and property semantics" + }, + "systemExact": false, + "generatedAt": "2026-08-17T08:49:33.839Z" +} diff --git a/config/freecad-property-direction-roundtrip.json b/config/freecad-property-direction-roundtrip.json new file mode 100644 index 0000000..726a013 --- /dev/null +++ b/config/freecad-property-direction-roundtrip.json @@ -0,0 +1,328 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-direction-roundtrip", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyDirection", + "archives": { + "nativeInitial": { + "path": ".cache/freecad/property-direction-roundtrip/native-initial.FCStd", + "bytes": 3782, + "sha256": "e9e16561486feced5a81240c3815aca41ed2c13a1694119c053af6e1cb84a545" + }, + "webEdited": { + "path": ".cache/freecad/property-direction-roundtrip/web-edited.FCStd", + "bytes": 3722, + "sha256": "7249873d594722059ef328cb0513b8eb8e1f7aa14a46b21bef504b009b0dad21" + }, + "nativeResaved": { + "path": ".cache/freecad/property-direction-roundtrip/native-resaved.FCStd", + "bytes": 3981, + "sha256": "5f12251fbdf2a763d42838cc0ba109930fd452e5e48808f00506f34aececb874" + }, + "nativeRepeatResaved": { + "path": ".cache/freecad/property-direction-roundtrip/native-resaved-repeat.FCStd", + "bytes": 3990, + "sha256": "a455f01e576b6d481eb0474b3048e7657c017bc1165aa11c7ebb43d7ad065f2c" + } + }, + "nativeInitial": { + "object": { + "editorMode": [], + "name": "DirectionMirror", + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "shape": { + "area": 52, + "bounds": [ + 0, + 0, + -4, + 2, + 3, + 0 + ], + "brepSha256": "88b166d7ee48d61dfcfc8ff0331c32ab6dfe18f4fcfe9ca29ade01c15d6b9406", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24 + }, + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "Part::Mirroring", + "value": { + "x": 0, + "y": 0, + "z": 1 + } + }, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ] + }, + "web": { + "before": { + "name": "Normal", + "typeId": "App::PropertyDirection", + "element": "PropertyVector", + "value": "{\"x\":0,\"y\":0,\"z\":1}" + }, + "after": { + "name": "Normal", + "typeId": "App::PropertyDirection", + "element": "PropertyVector", + "value": "{\"x\":0.25,\"y\":-0.5,\"z\":1.5}" + }, + "targetMarkedTouched": true, + "webOutputMatches": true, + "objectSetPreserved": true, + "semanticObjectsPreserved": true, + "opaquePathsPreserved": 3, + "opaqueEntriesPreserved": true + }, + "nativeAfter": { + "reopened": { + "object": { + "editorMode": [], + "name": "DirectionMirror", + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "shape": { + "area": 52, + "bounds": [ + -1.170731707, + 0, + -3.609756098, + 2.195121951, + 4.951219512, + 1.756097561 + ], + "brepSha256": "78c098a6fa65ccee51c306e1af3d908c067c4866d0a937f225b35e5c4f00ce7f", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24 + }, + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "Part::Mirroring", + "value": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + } + }, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ] + }, + "resaved": { + "object": { + "editorMode": [], + "name": "DirectionMirror", + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "shape": { + "area": 52, + "bounds": [ + -1.170731707, + 0, + -3.609756098, + 2.195121951, + 4.951219512, + 1.756097561 + ], + "brepSha256": "d2f2dec7c559cb100c4966733f07f8313886144c3fdb22d4e6f4b5185bb549c6", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24 + }, + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "Part::Mirroring", + "value": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + } + }, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ] + } + }, + "nativeRepeat": { + "reopened": { + "object": { + "editorMode": [], + "name": "DirectionMirror", + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "shape": { + "area": 52, + "bounds": [ + -1.170731707, + 0, + -3.609756098, + 2.195121951, + 4.951219512, + 1.756097561 + ], + "brepSha256": "78c098a6fa65ccee51c306e1af3d908c067c4866d0a937f225b35e5c4f00ce7f", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24 + }, + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "Part::Mirroring", + "value": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + } + }, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ] + }, + "resaved": { + "object": { + "editorMode": [], + "name": "DirectionMirror", + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "shape": { + "area": 52, + "bounds": [ + -1.170731707, + 0, + -3.609756098, + 2.195121951, + 4.951219512, + 1.756097561 + ], + "brepSha256": "d2f2dec7c559cb100c4966733f07f8313886144c3fdb22d4e6f4b5185bb549c6", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24 + }, + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "Part::Mirroring", + "value": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + } + }, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ] + } + }, + "classification": { + "requestedValue": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + }, + "webValue": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + }, + "reopenedValue": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + }, + "resavedValue": { + "x": 0.25, + "y": -0.5, + "z": 1.5 + }, + "nativeOutputMatches": true, + "nativeShapeChanged": true, + "nativeShapeStructureStable": true, + "nativeBrepReserialized": true, + "nativeBrepEvolutionReproduced": true, + "nativeAllowedEvolution": { + "classification": "native-allowed-evolution", + "dimension": "brep-serialization", + "reason": "FreeCAD save/reopen reserializes the recomputed Shape while direction, bounds, topology, mass properties and validity remain stable." + }, + "unknownSemanticDrift": false, + "zeroUnknownDrift": true + } +} diff --git a/config/freecad-property-direction-success.json b/config/freecad-property-direction-success.json new file mode 100644 index 0000000..8cad9bf --- /dev/null +++ b/config/freecad-property-direction-success.json @@ -0,0 +1,1160 @@ +{ + "baselineId": "freecad-1.1.1-property-direction-success", + "caseCount": 2, + "cases": [ + { + "caseId": "Mirroring", + "defaultValue": [ + 0.0, + 0.0, + 1.0 + ], + "mode": "direct-native-property-setter-with-valid-host-geometry", + "objectName": "DirectionMirror", + "objectTypeId": "Part::Mirroring", + "phases": { + "axisZTuple": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 52.0, + "bounds": [ + 0.0, + 0.0, + -4.0, + 2.0, + 3.0, + 0.0 + ], + "brepSha256": "ba65608213dd700751777e936c8f7cdd2b84a9e043a4deeec8e57eec3614b69b", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 1.0 + ] + }, + "afterSet": { + "mustExecute": true, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 0.0, + 0.0, + 1.0 + ] + } + }, + "default": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 52.0, + "bounds": [ + 0.0, + 0.0, + -4.0, + 2.0, + 3.0, + 0.0 + ], + "brepSha256": "ba65608213dd700751777e936c8f7cdd2b84a9e043a4deeec8e57eec3614b69b", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 1.0 + ] + } + }, + "integerTuple": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 52.0, + "bounds": [ + -3.666666667, + -3.333333333, + -4.666666667, + 1.333333333, + 2.0, + 0.0 + ], + "brepSha256": "2983b6d9965eb70e4de231aabbc45e649a640fa563cce5f5326fb43bebd0afab", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 2.0 + ] + }, + "afterSet": { + "mustExecute": true, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 1.0, + 1.0, + 2.0 + ] + } + }, + "largeFiniteTuple": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 52.0, + "bounds": [ + -1.714285714, + 0.0, + -2.0, + 2.571428571, + 5.285714286, + 2.571428571 + ], + "brepSha256": "af54274b74d4c9a8036ffc439a6adf5820c5fa99521ea062ec769b1017de3b4f", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Valid", + "value": [ + 1000000.0, + -2000000.0, + 3000000.0 + ] + }, + "afterSet": { + "mustExecute": true, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 1000000.0, + -2000000.0, + 3000000.0 + ] + } + }, + "nearAxisTuple": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 52.0, + "bounds": [ + -8e-09, + 0.0, + -4.000000004, + 2.0, + 3.000000008, + 6e-09 + ], + "brepSha256": "225a223ce3c066abb1e176a49d0aa160939ca22d72fe94c66b75f2c4ccd55c61", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Valid", + "value": [ + 1e-09, + -1e-09, + 1.0 + ] + }, + "afterSet": { + "mustExecute": true, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 1e-09, + -1e-09, + 1.0 + ] + } + }, + "nonUnitFloatTuple": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 52.0, + "bounds": [ + -1.170731707, + 0.0, + -3.609756098, + 2.195121951, + 4.951219512, + 1.756097561 + ], + "brepSha256": "78c098a6fa65ccee51c306e1af3d908c067c4866d0a937f225b35e5c4f00ce7f", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Valid", + "value": [ + 0.25, + -0.5, + 1.5 + ] + }, + "afterSet": { + "mustExecute": true, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 0.25, + -0.5, + 1.5 + ] + } + }, + "restored": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 52.0, + "bounds": [ + 0.0, + 0.0, + -4.0, + 2.0, + 3.0, + 0.0 + ], + "brepSha256": "ba65608213dd700751777e936c8f7cdd2b84a9e043a4deeec8e57eec3614b69b", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 1.0 + ] + }, + "afterSet": { + "mustExecute": true, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 0.0, + 0.0, + 1.0 + ] + } + }, + "vectorObject": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "MirrorSource", + "typeId": "Part::Box" + }, + { + "name": "DirectionMirror", + "typeId": "Part::Mirroring" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 52.0, + "bounds": [ + 0.0, + -1.855072464, + -4.811594203, + 3.043478261, + 2.768115942, + 0.463768116 + ], + "brepSha256": "797a254ef7d917a0c090505023f3fecddedc37c078a8bca34fb5e1ee5dc9ef5f", + "edges": 12, + "faces": 6, + "isNull": false, + "shapeType": "Solid", + "solids": 1, + "valid": true, + "vertices": 8, + "volume": 24.0 + }, + "statusString": "Valid", + "value": [ + -0.125, + 0.25, + 1.0 + ] + }, + "afterSet": { + "mustExecute": true, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + -0.125, + 0.25, + 1.0 + ] + } + } + }, + "propertyName": "Normal", + "requested": { + "axisZTuple": { + "inputKind": "tuple", + "value": [ + 0.0, + 0.0, + 1.0 + ] + }, + "integerTuple": { + "inputKind": "tuple", + "value": [ + 1.0, + 1.0, + 2.0 + ] + }, + "largeFiniteTuple": { + "inputKind": "tuple", + "value": [ + 1000000.0, + -2000000.0, + 3000000.0 + ] + }, + "nearAxisTuple": { + "inputKind": "tuple", + "value": [ + 1e-09, + -1e-09, + 1.0 + ] + }, + "nonUnitFloatTuple": { + "inputKind": "tuple", + "value": [ + 0.25, + -0.5, + 1.5 + ] + }, + "vectorObject": { + "inputKind": "Base.Vector", + "value": [ + -0.125, + 0.25, + 1.0 + ] + } + }, + "setup": { + "base": [ + 0, + 0, + 0 + ], + "kind": "box-mirror", + "mirrorPlane": null, + "source": { + "dimensions": [ + 2, + 3, + 4 + ], + "name": "MirrorSource", + "typeId": "Part::Box" + } + } + }, + { + "caseId": "ProjectOnSurface", + "defaultValue": [ + 0.0, + 0.0, + 1.0 + ], + "mode": "direct-native-property-setter-with-valid-host-geometry", + "objectName": "DirectionProjection", + "objectTypeId": "Part::ProjectOnSurface", + "phases": { + "axisZTuple": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 0.0, + "bounds": [ + -4.0, + -3.0, + 0.0, + 4.0, + 3.0, + 0.0 + ], + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 1.0 + ] + }, + "afterSet": { + "mustExecute": false, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 0.0, + 0.0, + 1.0 + ] + } + }, + "default": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 0.0, + "bounds": [ + -4.0, + -3.0, + 0.0, + 4.0, + 3.0, + 0.0 + ], + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 1.0 + ] + } + }, + "integerTuple": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 0.0, + "bounds": [ + -1.5, + -0.5, + -0.0, + 6.5, + 5.5, + -0.0 + ], + "brepSha256": "5b86893ea13a2a5d021bb9556363e7c06ebab5e8ab817aea009b691af8026803", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + 1.0, + 1.0, + 2.0 + ] + }, + "afterSet": { + "mustExecute": false, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 1.0, + 1.0, + 2.0 + ] + } + }, + "largeFiniteTuple": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 0.0, + "bounds": [ + -2.333333333, + -6.333333333, + 0.0, + 5.666666667, + -0.333333333, + 0.0 + ], + "brepSha256": "48b9d88d31a7e7e00bb89d357ebc10e1cc40dee0db3750b73351023b64dc6af0", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + 1000000.0, + -2000000.0, + 3000000.0 + ] + }, + "afterSet": { + "mustExecute": false, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 1000000.0, + -2000000.0, + 3000000.0 + ] + } + }, + "nearAxisTuple": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 0.0, + "bounds": [ + -4.000000072, + -3.000000072, + 0.0, + 4.000000072, + 3.000000072, + 0.0 + ], + "brepSha256": "7c2bec72a7715dd710128a44eafb4c01e3a96106b64602c05c2b09615bfd53d9", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + 1e-09, + -1e-09, + 1.0 + ] + }, + "afterSet": { + "mustExecute": false, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 1e-09, + -1e-09, + 1.0 + ] + } + }, + "nonUnitFloatTuple": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 0.0, + "bounds": [ + -3.166666667, + -4.666666667, + -0.0, + 4.833333333, + 1.333333333, + 0.0 + ], + "brepSha256": "3c78808d667362064af03623580275fc042383070d13822c577066173f4ea7d8", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + 0.25, + -0.5, + 1.5 + ] + }, + "afterSet": { + "mustExecute": false, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 0.25, + -0.5, + 1.5 + ] + } + }, + "restored": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 0.0, + "bounds": [ + -4.0, + -3.0, + 0.0, + 4.0, + 3.0, + 0.0 + ], + "brepSha256": "ba5241977c38224f66ffb495b32d3468bdcde322f177ed8047ddac5423d197de", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + 0.0, + 0.0, + 1.0 + ] + }, + "afterSet": { + "mustExecute": false, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + 0.0, + 0.0, + 1.0 + ] + } + }, + "vectorObject": { + "afterRecompute": { + "editorMode": [], + "mustExecute": false, + "objectSet": [ + { + "name": "ProjectionSupport", + "typeId": "Part::Feature" + }, + { + "name": "ProjectionWire", + "typeId": "Part::Feature" + }, + { + "name": "DirectionProjection", + "typeId": "Part::ProjectOnSurface" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyDirection", + "recomputeResult": true, + "shape": { + "applicable": true, + "area": 0.0, + "bounds": [ + -4.625, + -1.75, + 0.0, + 3.375, + 4.25, + 0.0 + ], + "brepSha256": "cf7283de4cbb5a99ca53fcf4ccfc906092721511205c9312415d0826d11e47f7", + "edges": 4, + "faces": 0, + "isNull": false, + "shapeType": "Compound", + "solids": 0, + "valid": true, + "vertices": 4, + "volume": 0.0 + }, + "statusString": "Valid", + "value": [ + -0.125, + 0.25, + 1.0 + ] + }, + "afterSet": { + "mustExecute": false, + "objectState": [ + "Touched" + ], + "statusString": "Touched", + "value": [ + -0.125, + 0.25, + 1.0 + ] + } + } + }, + "propertyName": "Direction", + "requested": { + "axisZTuple": { + "inputKind": "tuple", + "value": [ + 0.0, + 0.0, + 1.0 + ] + }, + "integerTuple": { + "inputKind": "tuple", + "value": [ + 1.0, + 1.0, + 2.0 + ] + }, + "largeFiniteTuple": { + "inputKind": "tuple", + "value": [ + 1000000.0, + -2000000.0, + 3000000.0 + ] + }, + "nearAxisTuple": { + "inputKind": "tuple", + "value": [ + 1e-09, + -1e-09, + 1.0 + ] + }, + "nonUnitFloatTuple": { + "inputKind": "tuple", + "value": [ + 0.25, + -0.5, + 1.5 + ] + }, + "vectorObject": { + "inputKind": "Base.Vector", + "value": [ + -0.125, + 0.25, + 1.0 + ] + } + }, + "setup": { + "kind": "wire-to-planar-face", + "mode": "Edges", + "projection": { + "name": "ProjectionWire", + "subElements": [ + "Wire1" + ], + "typeId": "Part::Feature", + "z": -5 + }, + "support": { + "name": "ProjectionSupport", + "subElements": [ + "Face1" + ], + "typeId": "Part::Feature" + } + } + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyDirection", + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-file-failure.json b/config/freecad-property-file-failure.json new file mode 100644 index 0000000..4002f8e --- /dev/null +++ b/config/freecad-property-file-failure.json @@ -0,0 +1,308 @@ +{ + "baselineId": "freecad-1.1.1-property-file-failure", + "cancellationBoundary": { + "classification": "synchronous-property-setter", + "reason": "no-native-cancel-hook", + "replacement": "abort-active-document-transaction", + "supported": false + }, + "disabled": { + "after": { + "editorMode": [ + "ReadOnly" + ], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [ + "Immutable", + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFile", + "statusString": "File does not exist", + "value": "" + }, + "afterObjects": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "statusString": "File does not exist", + "value": "" + }, + "beforeObjects": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "classification": "editor-read-only-and-python-immutable", + "editorMode": [ + "ReadOnly" + ], + "exception": { + "message": "Object attribute 'FileName' is read-only", + "type": "AttributeError" + }, + "restoredEditorMode": [], + "restoredStatus": [], + "status": [ + "Immutable", + "ReadOnly" + ] + }, + "documentIntegrity": { + "finalObjects": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "initialObjects": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectCount": 1, + "objectsPreserved": true + }, + "failures": [ + { + "after": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "statusString": "File does not exist", + "value": "/definitely/missing/bitbybit-file.stl" + }, + "afterObjects": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "assignmentException": null, + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "statusString": "Valid", + "value": "" + }, + "beforeObjects": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "id": "missing-path", + "objectsPreserved": true, + "recomputeException": null, + "requested": "/definitely/missing/bitbybit-file.stl" + }, + { + "after": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "statusString": "File does not exist", + "value": "/definitely/missing/bitbybit-file.stl" + }, + "afterObjects": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "assignmentException": { + "message": "type must be str or unicode, not int", + "type": "TypeError" + }, + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "statusString": "File does not exist", + "value": "/definitely/missing/bitbybit-file.stl" + }, + "beforeObjects": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "id": "wrong-type", + "objectsPreserved": true, + "recomputeException": null, + "requested": 12345 + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "initial": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "statusString": "Valid", + "value": "" + }, + "object": { + "name": "FileProbe", + "typeId": "Mesh::Import" + }, + "property": { + "name": "FileName", + "typeId": "App::PropertyFile" + }, + "schemaVersion": 1, + "status": "pass", + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 1, + "name": "property-file-cancel" + }, + "afterAbort": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "statusString": "File does not exist", + "value": "" + }, + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "statusString": "File does not exist", + "value": "" + }, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "statusString": "File does not exist", + "value": "/tmp/transaction-file.stl" + }, + "objectsAfter": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectsBefore": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectsRestored": true, + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "restored": true, + "undoMode": 1 + } +} diff --git a/config/freecad-property-file-inventory.json b/config/freecad-property-file-inventory.json new file mode 100644 index 0000000..8aacf9c --- /dev/null +++ b/config/freecad-property-file-inventory.json @@ -0,0 +1,619 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyFile", + "recordCount": 16, + "records": [ + { + "objectTypeId": "Mesh::Import", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "FileName", + "group": "", + "status": [], + "defaultRaw": "", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "Mesh::Import", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawComplexSection", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "FileGeomPattern", + "group": "Cut Surface Format", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/PAT/FCPAT.pat", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/PAT/FCPAT.pat", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawComplexSection", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawComplexSection", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "FileHatchPattern", + "group": "Cut Surface Format", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Patterns/simple.svg", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Patterns/simple.svg", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawComplexSection", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawComplexSectionPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "FileGeomPattern", + "group": "Cut Surface Format", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/PAT/FCPAT.pat", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/PAT/FCPAT.pat", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawComplexSectionPython", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawComplexSectionPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "FileHatchPattern", + "group": "Cut Surface Format", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Patterns/simple.svg", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Patterns/simple.svg", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawComplexSectionPython", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawGeomHatch", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "FilePattern", + "group": "GeomHatch", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/PAT/FCPAT.pat", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/PAT/FCPAT.pat", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawGeomHatch", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawHatch", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "HatchPattern", + "group": "Hatch", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Patterns/simple.svg", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Patterns/simple.svg", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawHatch", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawParametricTemplate", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Template", + "group": "Page", + "status": [], + "defaultRaw": "", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawParametricTemplate", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawSVGTemplate", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "Template", + "group": "Template", + "status": [], + "defaultRaw": "", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawSVGTemplate", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawTileWeld", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "SymbolFile", + "group": "TileWeld", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Symbols/Welding/blankTile.svg", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Symbols/Welding/blankTile.svg", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawTileWeld", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawTileWeldPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "SymbolFile", + "group": "TileWeld", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Symbols/Welding/blankTile.svg", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Symbols/Welding/blankTile.svg", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawTileWeldPython", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawViewImage", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "ImageFile", + "group": "Image", + "status": [], + "defaultRaw": "", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewImage", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawViewSection", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "FileGeomPattern", + "group": "Cut Surface Format", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/PAT/FCPAT.pat", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/PAT/FCPAT.pat", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewSection", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawViewSection", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "FileHatchPattern", + "group": "Cut Surface Format", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Patterns/simple.svg", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Patterns/simple.svg", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewSection", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawViewSectionPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "FileGeomPattern", + "group": "Cut Surface Format", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/PAT/FCPAT.pat", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/PAT/FCPAT.pat", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewSectionPython", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + }, + { + "objectTypeId": "TechDraw::DrawViewSectionPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "FileHatchPattern", + "group": "Cut Surface Format", + "status": [], + "defaultRaw": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Patterns/simple.svg", + "valueModel": { + "kind": "path-string", + "representation": "App::PropertyString-derived UTF-8 path", + "defaultValue": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/install-desktop/share/Mod/TechDraw/Patterns/simple.svg", + "writable": true, + "externalResource": true, + "browserEditBoundary": "host-absolute-paths are not written into the browser project; use an explicit project resource reference" + }, + "inputs": { + "accepted": [ + "string", + "{filename:string,filter?:string}" + ], + "componentPaths": [ + "filename", + "filter" + ], + "emptyStringAccepted": true + }, + "editor": "Gui::PropertyEditor::PropertyFileItem", + "dependencies": [], + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewSectionPython", + "source": "Document.supportedTypes runtime inventory", + "propertyWriteRequiresShape": false + } + } + ], + "storage": { + "inheritedFrom": "App::PropertyString", + "xmlElement": "String", + "scalarEncoding": "UTF-8 path string", + "externalResource": true, + "absoluteHostPathPolicy": "preserve-or-reject; never rewrite into browser project" + }, + "provenance": { + "runtime": { + "path": ".cache/freecad/reference-desktop.json", + "bytes": 2298709, + "sha256": "082400ec7379e8efc2af16709032d45890d7092277967b714acb05761fd1c2a7" + }, + "sources": [ + { + "path": ".cache/freecad/FreeCAD/src/App/PropertyFile.h", + "bytes": 5474, + "sha256": "1e5d3fea7bebde48fafccbaf9edca92cdc9b727ccaaa74a50b70929a1fe02412" + }, + { + "path": ".cache/freecad/FreeCAD/src/App/PropertyFile.cpp", + "bytes": 22084, + "sha256": "ee1b7a3a675d93b3beaca52ce819201e9d240c99e6eb08b391bd81e076ac21fe" + }, + { + "path": ".cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.h", + "bytes": 41826, + "sha256": "aaade89f5386b5d061b1b2d09a4fd01e7a27e3c601117fc00e44e115f347d9ed" + }, + { + "path": ".cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.cpp", + "bytes": 142093, + "sha256": "bf2f7cb4c01034425f4ebd46f901ada03c5fa02dcffbc1d3936e49ef7bc43b52" + } + ] + }, + "classification": "opaque-fcstd-proxy", + "nextPhases": [ + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I" + ] +} diff --git a/config/freecad-property-file-mutation.json b/config/freecad-property-file-mutation.json new file mode 100644 index 0000000..077acb1 --- /dev/null +++ b/config/freecad-property-file-mutation.json @@ -0,0 +1,82 @@ +{ + "baselineId": "freecad-1.1.1-property-file-mutation", + "classification": { + "invalidEditedPath": true, + "objectSetStable": true, + "restoreExact": true, + "unknownSemanticDrift": false, + "valueChanged": true + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "object": { + "name": "FileProbe", + "typeId": "Mesh::Import" + }, + "phases": { + "before": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "recomputeResult": false, + "statusString": "Valid", + "value": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/FreeCAD/data/tests/mesh.obj" + }, + "edited": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "recomputeResult": true, + "statusString": "File does not exist", + "value": "/tmp/property-file-alternate.stl" + }, + "restored": { + "editorMode": [], + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "recomputeResult": true, + "statusString": "Valid", + "value": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/FreeCAD/data/tests/mesh.obj" + } + }, + "property": { + "name": "FileName", + "typeId": "App::PropertyFile" + }, + "propertyType": "App::PropertyFile", + "requested": { + "before": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/FreeCAD/data/tests/mesh.obj", + "edited": "/tmp/property-file-alternate.stl", + "restored": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/FreeCAD/data/tests/mesh.obj" + }, + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-file-promotion.json b/config/freecad-property-file-promotion.json new file mode 100644 index 0000000..59675c0 --- /dev/null +++ b/config/freecad-property-file-promotion.json @@ -0,0 +1,71 @@ +{ + "schemaVersion": 1, + "status": "pass", + "taskId": "PROP-app-propertyfile-I", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyFile", + "recordCount": 16, + "phaseEvidence": { + "A": [ + "config/freecad-property-file-inventory.json", + "check:freecad-property-file-inventory" + ], + "B": [ + "config/freecad-property-file-success.json", + "check:freecad-property-file-success" + ], + "C": [ + "config/freecad-property-file-failure.json", + "check:freecad-property-file-failure" + ], + "D": [ + "config/freecad-property-file-mutation.json", + "check:freecad-property-file-mutation" + ], + "E": [ + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyFileFacade.test.ts", + "test:freecad-property-file-facade" + ], + "F": [ + "tests/propertyFileTransaction.test.ts", + "test:freecad-property-file-transaction" + ], + "G": [ + "config/freecad-property-file-roundtrip.json", + "check:freecad-property-file-roundtrip" + ], + "H": [ + "config/chrome-property-file-verification.json", + "check:chrome-property-file" + ] + }, + "promotion": { + "from": "opaque-fcstd-proxy", + "to": "native-editable-codec", + "facadeValueModel": "safe-project-relative-path-string-with-native-string-fcstd-payload", + "writableRecords": 16, + "objectTypeCount": 12, + "fcstdElement": "String", + "nativeRoundTripValue": ".cache/freecad/property-file-roundtrip/alternate.obj", + "browserRoundTripValue": "project-files/chrome-updated.obj", + "externalResourceBoundary": "project-relative-path; asset bytes remain external to FCStd", + "zeroUnknownDrift": true + }, + "exactBlockerSync": { + "nativeEditableTypes": 30, + "nativeEditableRecords": 4361, + "opaqueTypes": 50, + "opaqueRecords": 466, + "exactPromotionReady": false, + "exactBlocker": "50 runtime property types and 466 records remain opaque-only; complete native document and property semantics" + }, + "systemExact": false, + "generatedAt": "2026-08-17T08:49:33.800Z" +} diff --git a/config/freecad-property-file-roundtrip.json b/config/freecad-property-file-roundtrip.json new file mode 100644 index 0000000..af62328 --- /dev/null +++ b/config/freecad-property-file-roundtrip.json @@ -0,0 +1,191 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-file-roundtrip", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyFile", + "assets": { + "initial": { + "path": ".cache/freecad/FreeCAD/data/tests/mesh.obj", + "bytes": 429, + "sha256": "581dfc5ad60f64ff3f21a376aaab962675b396725a13d4a49e11c67c1c773738" + }, + "target": { + "path": ".cache/freecad/property-file-roundtrip/alternate.obj", + "bytes": 66, + "sha256": "da9f1a2a70c4c8b781cdac75d547ea829de315e9108eb5c883b76d3756387a08" + } + }, + "archives": { + "nativeInitial": { + "path": ".cache/freecad/property-file-roundtrip/native-initial.FCStd", + "bytes": 1611, + "sha256": "9577f735da4b4a800992a87ba156ba4c3b5a51e74ec4e1ac0acd9fae19b339e4" + }, + "webEdited": { + "path": ".cache/freecad/property-file-roundtrip/web-edited.FCStd", + "bytes": 1470, + "sha256": "47ce9d56bd59cced3418396dbddca136925d4514c3e5c744657f3de8fb8c0c5e" + }, + "nativeResaved": { + "path": ".cache/freecad/property-file-roundtrip/native-resaved.FCStd", + "bytes": 1519, + "sha256": "eba5caac14066c3b294728360ae96df64c6e958db1e196a0a6128d6a50982485" + } + }, + "nativeInitial": { + "object": { + "asset": { + "bytes": 429, + "exists": true, + "sha256": "581dfc5ad60f64ff3f21a376aaab962675b396725a13d4a49e11c67c1c773738" + }, + "editorMode": [], + "hasMeshProperty": true, + "hasShapeProperty": false, + "mesh": { + "bounds": [ + -5, + -5, + -5, + 5, + 5, + 5 + ], + "facets": 12, + "isEmpty": false, + "points": 8 + }, + "name": "FileProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "Mesh::Import", + "value": ".cache/freecad/FreeCAD/data/tests/mesh.obj" + }, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ] + }, + "web": { + "before": { + "name": "FileName", + "typeId": "App::PropertyFile", + "element": "String", + "value": ".cache/freecad/FreeCAD/data/tests/mesh.obj" + }, + "after": { + "name": "FileName", + "typeId": "App::PropertyFile", + "element": "String", + "value": ".cache/freecad/property-file-roundtrip/alternate.obj" + }, + "targetMarkedTouched": true, + "webOutputMatches": true, + "semanticObjectsPreserved": true, + "opaquePathsPreserved": 1, + "opaqueEntriesPreserved": true + }, + "nativeAfter": { + "reopened": { + "object": { + "asset": { + "bytes": 66, + "exists": true, + "sha256": "da9f1a2a70c4c8b781cdac75d547ea829de315e9108eb5c883b76d3756387a08" + }, + "editorMode": [], + "hasMeshProperty": true, + "hasShapeProperty": false, + "mesh": { + "bounds": [ + 0, + 0, + 0, + 4, + 3, + 0 + ], + "facets": 1, + "isEmpty": false, + "points": 3 + }, + "name": "FileProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "Mesh::Import", + "value": ".cache/freecad/property-file-roundtrip/alternate.obj" + }, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ] + }, + "resaved": { + "object": { + "asset": { + "bytes": 66, + "exists": true, + "sha256": "da9f1a2a70c4c8b781cdac75d547ea829de315e9108eb5c883b76d3756387a08" + }, + "editorMode": [], + "hasMeshProperty": true, + "hasShapeProperty": false, + "mesh": { + "bounds": [ + 0, + 0, + 0, + 4, + 3, + 0 + ], + "facets": 1, + "isEmpty": false, + "points": 3 + }, + "name": "FileProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "Mesh::Import", + "value": ".cache/freecad/property-file-roundtrip/alternate.obj" + }, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ] + } + }, + "classification": { + "requestedValue": ".cache/freecad/property-file-roundtrip/alternate.obj", + "webValue": ".cache/freecad/property-file-roundtrip/alternate.obj", + "reopenedValue": ".cache/freecad/property-file-roundtrip/alternate.obj", + "resavedValue": ".cache/freecad/property-file-roundtrip/alternate.obj", + "nativeOutputMatches": true, + "objectSetPreserved": true, + "nativeMeshChanged": true, + "nativeMeshStable": true, + "externalResourceBoundary": "project-relative-path; asset bytes remain external to FCStd", + "unknownSemanticDrift": false, + "zeroUnknownDrift": true + } +} diff --git a/config/freecad-property-file-success.json b/config/freecad-property-file-success.json new file mode 100644 index 0000000..d41da9b --- /dev/null +++ b/config/freecad-property-file-success.json @@ -0,0 +1,161 @@ +{ + "asset": { + "bytes": 429, + "exists": true, + "path": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/FreeCAD/data/tests/mesh.obj" + }, + "baselineId": "freecad-1.1.1-property-file-success", + "diagnostics": { + "documentObjectCount": 1, + "exception": null + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "object": { + "name": "FileProbe", + "typeId": "Mesh::Import" + }, + "phases": { + "default": { + "editorMode": [], + "mesh": { + "applicable": true, + "bounds": [ + 1.7976931348623157e+308, + 1.7976931348623157e+308, + 1.7976931348623157e+308, + -1.7976931348623157e+308, + -1.7976931348623157e+308, + -1.7976931348623157e+308 + ], + "facets": 0, + "isEmpty": true, + "vertices": 0 + }, + "mustExecute": null, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "recomputeResult": false, + "requested": "", + "statusString": "Valid", + "value": "" + }, + "relative-path": { + "editorMode": [], + "mesh": { + "applicable": true, + "bounds": [ + 1.7976931348623157e+308, + 1.7976931348623157e+308, + 1.7976931348623157e+308, + -1.7976931348623157e+308, + -1.7976931348623157e+308, + -1.7976931348623157e+308 + ], + "facets": 0, + "isEmpty": true, + "vertices": 0 + }, + "mustExecute": null, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Touched", + "Invalid" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "recomputeResult": true, + "requested": "mesh-data/Cube.stl", + "statusString": "File does not exist", + "value": "mesh-data/Cube.stl" + }, + "restored": { + "editorMode": [], + "mesh": { + "applicable": true, + "bounds": [ + 1.7976931348623157e+308, + 1.7976931348623157e+308, + 1.7976931348623157e+308, + -1.7976931348623157e+308, + -1.7976931348623157e+308, + -1.7976931348623157e+308 + ], + "facets": 0, + "isEmpty": true, + "vertices": 0 + }, + "mustExecute": null, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "recomputeResult": true, + "requested": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/FreeCAD/data/tests/mesh.obj", + "statusString": "Valid", + "value": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/FreeCAD/data/tests/mesh.obj" + }, + "valid-mesh": { + "editorMode": [], + "mesh": { + "applicable": true, + "bounds": [ + 1.7976931348623157e+308, + 1.7976931348623157e+308, + 1.7976931348623157e+308, + -1.7976931348623157e+308, + -1.7976931348623157e+308, + -1.7976931348623157e+308 + ], + "facets": 0, + "isEmpty": true, + "vertices": 0 + }, + "mustExecute": null, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "Mesh::Import" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFile", + "recomputeResult": true, + "requested": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/FreeCAD/data/tests/mesh.obj", + "statusString": "Valid", + "value": "/home/mes123456/working_Web_FreeCAD_Bitbybit/.cache/freecad/FreeCAD/data/tests/mesh.obj" + } + }, + "property": { + "group": "", + "name": "FileName", + "typeId": "App::PropertyFile" + }, + "propertyType": "App::PropertyFile", + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-fileincluded-failure.json b/config/freecad-property-fileincluded-failure.json new file mode 100644 index 0000000..31be70f --- /dev/null +++ b/config/freecad-property-fileincluded-failure.json @@ -0,0 +1,865 @@ +{ + "acceptedRisks": [ + { + "after": { + "baseName": "stable.bin", + "bytes": 0, + "editorMode": [], + "exists": false, + "isDirectory": true, + "isFile": false, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": null, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "assignmentException": null, + "before": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "directoryAccepted": true, + "id": "directory-path", + "objectsPreserved": true, + "oldFileRemoved": true, + "recovery": { + "baseName": "restored-after-directory.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/restored-after-directory.bin", + "writeBits": 0 + }, + "requested": "'/tmp/freecad-property-fileincluded-failure-0ikgj5ie/directory'" + } + ], + "baselineId": "freecad-1.1.1-property-fileincluded-failure", + "cancellationBoundary": { + "classification": "synchronous-property-setter", + "reason": "no-native-cancel-hook", + "replacement": "abort-active-document-transaction", + "supported": false + }, + "documentIntegrity": { + "finalObjects": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "initialObjects": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectCount": 1, + "objectsPreserved": true + }, + "editorReadOnly": { + "after": { + "baseName": "editor-write.bin", + "bytes": 34, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "pathExists": true, + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "72122705399a0111d36d7b74ec05f8155834ce6b394d1bd879f360e29f8bb365", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/editor-write.bin", + "writeBits": 0 + }, + "before": { + "baseName": "restored-after-directory.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/restored-after-directory.bin", + "writeBits": 0 + }, + "editorMode": [ + "ReadOnly" + ], + "exception": null, + "pythonBypassesEditorReadOnly": true + }, + "failures": [ + { + "after": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "assignmentException": { + "message": "File /definitely/missing/property-fileincluded.bin does not exist.", + "type": "OSError" + }, + "before": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "id": "missing-path", + "objectSetAfter": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectSetBefore": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectsPreserved": true, + "requested": "'/definitely/missing/property-fileincluded.bin'", + "valuePreserved": true + }, + { + "after": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "assignmentException": { + "message": "Type must be string or file, not int", + "type": "TypeError" + }, + "before": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "id": "wrong-type", + "objectSetAfter": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectSetBefore": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectsPreserved": true, + "requested": "12345", + "valuePreserved": true + }, + { + "after": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "assignmentException": { + "message": "Tuple needs size of (filePath,newFileName)", + "type": "TypeError" + }, + "before": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "id": "tuple-wrong-arity", + "objectSetAfter": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectSetBefore": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectsPreserved": true, + "requested": "('/tmp/freecad-property-fileincluded-failure-0ikgj5ie/source.bin',)", + "valuePreserved": true + }, + { + "after": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "assignmentException": { + "message": "Second item in tuple must be a string, not int", + "type": "TypeError" + }, + "before": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "id": "tuple-wrong-name-type", + "objectSetAfter": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectSetBefore": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectsPreserved": true, + "requested": "('/tmp/freecad-property-fileincluded-failure-0ikgj5ie/source.bin', 123)", + "valuePreserved": true + }, + { + "after": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "assignmentException": { + "message": "PyCXX: Error creating object of type N2Py7SeqBaseINS_4CharEEE from 123", + "type": "TypeError" + }, + "before": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "id": "dictionary-wrong-filename-type", + "objectSetAfter": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectSetBefore": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectsPreserved": true, + "requested": "{'filename': 123}", + "valuePreserved": true + }, + { + "after": { + "baseName": "restored-after-directory.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/restored-after-directory.bin", + "writeBits": 0 + }, + "assignmentException": { + "message": "Not possible to set the same file!", + "type": "OSError" + }, + "before": { + "baseName": "restored-after-directory.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/restored-after-directory.bin", + "writeBits": 0 + }, + "id": "same-current-transient", + "objectSetAfter": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectSetBefore": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectsPreserved": true, + "requested": "'/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/restored-after-directory.bin'", + "valuePreserved": true + } + ], + "filterOnly": { + "after": { + "baseName": "restored-after-directory.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/restored-after-directory.bin", + "writeBits": 0 + }, + "before": { + "baseName": "restored-after-directory.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/restored-after-directory.bin", + "writeBits": 0 + }, + "exception": null, + "objectsPreserved": true, + "valuePreserved": true + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "immutable": { + "after": { + "baseName": "editor-write.bin", + "bytes": 34, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "pathExists": true, + "propertyStatus": [ + "Immutable" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "72122705399a0111d36d7b74ec05f8155834ce6b394d1bd879f360e29f8bb365", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/editor-write.bin", + "writeBits": 0 + }, + "before": { + "baseName": "editor-write.bin", + "bytes": 34, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "pathExists": true, + "propertyStatus": [ + "Immutable" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "72122705399a0111d36d7b74ec05f8155834ce6b394d1bd879f360e29f8bb365", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/editor-write.bin", + "writeBits": 0 + }, + "exception": { + "message": "Object attribute 'File' is read-only", + "type": "AttributeError" + }, + "restoredStatus": [], + "status": [ + "Immutable" + ] + }, + "initial": { + "baseName": "stable.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/stable.bin", + "writeBits": 0 + }, + "object": { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + }, + "property": { + "name": "File", + "typeId": "App::PropertyFileIncluded" + }, + "propertyType": "App::PropertyFileIncluded", + "schemaVersion": 1, + "status": "pass", + "transaction": { + "activeAfterAbort": { + "id": 0, + "name": "" + }, + "activeAfterEdit": { + "id": 1, + "name": "property-fileincluded-cancel" + }, + "afterAbort": { + "baseName": "editor-write.bin", + "bytes": 34, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "72122705399a0111d36d7b74ec05f8155834ce6b394d1bd879f360e29f8bb365", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/editor-write.bin", + "writeBits": 0 + }, + "before": { + "baseName": "editor-write.bin", + "bytes": 34, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "72122705399a0111d36d7b74ec05f8155834ce6b394d1bd879f360e29f8bb365", + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/editor-write.bin", + "writeBits": 0 + }, + "edited": { + "baseName": "transaction-write.bin", + "bytes": 29, + "editorMode": [], + "exists": true, + "isDirectory": false, + "isFile": true, + "objectSet": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "pathExists": true, + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "31f898b8e260a6dc642cf992483813de02d2cb9f4fe0f06be901d281f78f446e", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/transaction-write.bin", + "writeBits": 0 + }, + "editedPath": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_67ad6239-27ce-4f6e-b55e-3f93c28f928f_da39a3_863229/transaction-write.bin", + "editedPathExistsAfterAbort": false, + "objectsAfter": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectsBefore": [ + { + "name": "FileProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "pendingAfterAbort": false, + "pendingAfterEdit": true, + "restored": true, + "undoMode": 1 + } +} diff --git a/config/freecad-property-fileincluded-inventory.json b/config/freecad-property-fileincluded-inventory.json new file mode 100644 index 0000000..28a2b32 --- /dev/null +++ b/config/freecad-property-fileincluded-inventory.json @@ -0,0 +1,924 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyFileIncluded", + "recordCount": 20, + "objectTypeCount": 15, + "records": [ + { + "objectTypeId": "App::DocumentObjectFileIncluded", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "File", + "group": "", + "status": [], + "normalizedStatus": [], + "defaultRaw": "", + "defaultKind": "empty", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": true, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": null, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "App::DocumentObjectFileIncluded", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "App::VRMLObject", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "VrmlFile", + "group": "", + "status": [], + "normalizedStatus": [], + "defaultRaw": "", + "defaultKind": "empty", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": true, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": null, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "App::VRMLObject", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "Image::ImagePlane", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "ImageFile", + "group": "ImagePlane", + "status": [], + "normalizedStatus": [], + "defaultRaw": "", + "defaultKind": "empty", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": true, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": null, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "Image::ImagePlane", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "Robot::RobotObject", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "RobotKinematicFile", + "group": "Robot definition", + "status": [], + "normalizedStatus": [], + "defaultRaw": "", + "defaultKind": "empty", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": true, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": null, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "Robot::RobotObject", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "Robot::RobotObject", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "RobotVrmlFile", + "group": "Robot definition", + "status": [], + "normalizedStatus": [], + "defaultRaw": "", + "defaultKind": "empty", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": true, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": null, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "Robot::RobotObject", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "Sketcher::SketchObjectSF", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "SketchFlatFile", + "group": "", + "status": [], + "normalizedStatus": [], + "defaultRaw": "", + "defaultKind": "empty", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": true, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": null, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "Sketcher::SketchObjectSF", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawComplexSection", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "PatIncluded", + "group": "Cut Surface Format", + "status": [ + "ReadOnly" + ], + "normalizedStatus": [ + "ReadOnly" + ], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/FCPAT.pat", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": false, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "FileGeomPattern", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawComplexSection", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawComplexSection", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "SvgIncluded", + "group": "Cut Surface Format", + "status": [ + "ReadOnly" + ], + "normalizedStatus": [ + "ReadOnly" + ], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/simple.svg", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": false, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "FileHatchPattern", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawComplexSection", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawComplexSectionPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "PatIncluded", + "group": "Cut Surface Format", + "status": [ + "ReadOnly" + ], + "normalizedStatus": [ + "ReadOnly" + ], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/FCPAT1.pat", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": false, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "FileGeomPattern", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawComplexSectionPython", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawComplexSectionPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "SvgIncluded", + "group": "Cut Surface Format", + "status": [ + "ReadOnly" + ], + "normalizedStatus": [ + "ReadOnly" + ], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/simple1.svg", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": false, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "FileHatchPattern", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawComplexSectionPython", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawGeomHatch", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "PatIncluded", + "group": "GeomHatch", + "status": [], + "normalizedStatus": [], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/FCPAT2.pat", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": true, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "FilePattern", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawGeomHatch", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawHatch", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "SvgIncluded", + "group": "Hatch", + "status": [], + "normalizedStatus": [], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/simple2.svg", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": true, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "HatchPattern", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawHatch", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawSVGTemplate", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "PageResult", + "group": "Template", + "status": [ + 27 + ], + "normalizedStatus": [ + "PropOutput" + ], + "defaultRaw": "", + "defaultKind": "empty", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": false, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "Template", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawSVGTemplate", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawTileWeld", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "SymbolIncluded", + "group": "TileWeld", + "status": [], + "normalizedStatus": [], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/blankTile.svg", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": true, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "SymbolFile", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawTileWeld", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawTileWeldPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "SymbolIncluded", + "group": "TileWeld", + "status": [], + "normalizedStatus": [], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/blankTile1.svg", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": true, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "SymbolFile", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawTileWeldPython", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawViewImage", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "ImageIncluded", + "group": "Image", + "status": [], + "normalizedStatus": [], + "defaultRaw": "", + "defaultKind": "empty", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": true, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "ImageFile", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewImage", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawViewSection", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "PatIncluded", + "group": "Cut Surface Format", + "status": [ + "ReadOnly" + ], + "normalizedStatus": [ + "ReadOnly" + ], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/FCPAT3.pat", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": false, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "FileGeomPattern", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewSection", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawViewSection", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "SvgIncluded", + "group": "Cut Surface Format", + "status": [ + "ReadOnly" + ], + "normalizedStatus": [ + "ReadOnly" + ], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/simple3.svg", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": false, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "FileHatchPattern", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewSection", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawViewSectionPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "PatIncluded", + "group": "Cut Surface Format", + "status": [ + "ReadOnly" + ], + "normalizedStatus": [ + "ReadOnly" + ], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/FCPAT4.pat", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": false, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "FileGeomPattern", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewSectionPython", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + }, + { + "objectTypeId": "TechDraw::DrawViewSectionPython", + "objectAvailable": true, + "probeStatus": "available", + "propertyName": "SvgIncluded", + "group": "Cut Surface Format", + "status": [ + "ReadOnly" + ], + "normalizedStatus": [ + "ReadOnly" + ], + "defaultRaw": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc__da39a3_/simple4.svg", + "defaultKind": "document-transient-copy", + "valueModel": { + "kind": "included-file-resource", + "representation": "read-only document-transient file backed by embedded FCStd bytes", + "writableByStatus": false, + "pathIsRuntimeOnly": true, + "bytesAreAuthoritative": true + }, + "inputs": { + "accepted": [ + "utf8-string-path", + "bytes-path", + "open-io-file", + "[source-path,archive-name]", + "{filename:string,filter?:string}" + ], + "sourceFileMustExist": true, + "emptyStringBehavior": "accepted-no-op; does not clear an existing value", + "sameTransientPathBehavior": "rejected" + }, + "dependency": { + "sourceProperty": "FileHatchPattern", + "relation": "host-onChanged-copies-source-bytes-into-included-property" + }, + "editor": "Gui::PropertyEditor::PropertyTransientFileItem", + "applicability": { + "requiredObjectTypeId": "TechDraw::DrawViewSectionPython", + "propertyWriteRequiresShape": false, + "source": "Document.supportedTypes runtime inventory" + } + } + ], + "setterSemantics": { + "externalSource": "copy bytes into the document transient directory", + "writableTransientSource": "rename into the selected transient destination", + "replacement": "delete the previous transient copy unless undo owns it", + "destinationPermissions": "read-only", + "archiveNameCollision": "append a positive integer before the extension", + "undoRedo": "Copy/Paste move or copy transient files while preserving per-property ownership" + }, + "storage": { + "xmlElement": "FileIncluded", + "archiveAttribute": "file", + "archiveResource": "separate FCStd ZIP entry containing byte-identical file data", + "forceXmlAttribute": "data", + "forceXmlResource": "binary data embedded in the XML stream", + "emptyEncoding": "", + "restoredValue": "document transient path; not a portable semantic path", + "browserBoundary": "project resource identity plus bytes; never expose or persist an ambient host path" + }, + "provenance": { + "runtime": { + "path": ".cache/freecad/reference-desktop.json", + "bytes": 2298709, + "sha256": "082400ec7379e8efc2af16709032d45890d7092277967b714acb05761fd1c2a7" + }, + "sources": [ + { + "path": ".cache/freecad/FreeCAD/src/App/PropertyFile.h", + "bytes": 5474, + "sha256": "1e5d3fea7bebde48fafccbaf9edca92cdc9b727ccaaa74a50b70929a1fe02412" + }, + { + "path": ".cache/freecad/FreeCAD/src/App/PropertyFile.cpp", + "bytes": 22084, + "sha256": "ee1b7a3a675d93b3beaca52ce819201e9d240c99e6eb08b391bd81e076ac21fe" + }, + { + "path": ".cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.h", + "bytes": 41826, + "sha256": "aaade89f5386b5d061b1b2d09a4fd01e7a27e3c601117fc00e44e115f347d9ed" + }, + { + "path": ".cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.cpp", + "bytes": 142093, + "sha256": "bf2f7cb4c01034425f4ebd46f901ada03c5fa02dcffbc1d3936e49ef7bc43b52" + }, + { + "path": ".cache/freecad/FreeCAD/src/App/DocumentObjectFileIncluded.cpp", + "bytes": 2128, + "sha256": "0b8b27fd92ef1c722191fc512573de0875e637191b957167c7e17ada11b95bb1" + }, + { + "path": ".cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawViewSection.cpp", + "bytes": 47842, + "sha256": "86c68dfa3fea97ed3f79e119f2f488726c6ea82bf6198de935e36383c444829f" + }, + { + "path": ".cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawGeomHatch.cpp", + "bytes": 22708, + "sha256": "c8a653c85986b05414965424f0c88e4af1c6af41980eac3c483fc8bb6de763f2" + }, + { + "path": ".cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawHatch.cpp", + "bytes": 7966, + "sha256": "ad242fbc5eb7cc4fa0f30fc9db71a549d841ea73680e6d8c7ff2909699c59fa0" + }, + { + "path": ".cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawSVGTemplate.cpp", + "bytes": 13492, + "sha256": "8355e597863dcabf9ad996a3e9097988ac8ceba9b6f4635029d33f59b2a019de" + }, + { + "path": ".cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawTileWeld.cpp", + "bytes": 4878, + "sha256": "c31f2ec3b244b421b39ff283c687540c4e783361f9dfb2a9ae3b3045ef30463b" + }, + { + "path": ".cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawViewImage.cpp", + "bytes": 4670, + "sha256": "e76a2f5aacd374b63b21cbe37136027ee041a28b59106cdfa78fd5ecbcb2707e" + } + ] + }, + "classification": "opaque-fcstd-proxy", + "nextPhases": [ + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I" + ] +} diff --git a/config/freecad-property-fileincluded-mutation.json b/config/freecad-property-fileincluded-mutation.json new file mode 100644 index 0000000..71a5966 --- /dev/null +++ b/config/freecad-property-fileincluded-mutation.json @@ -0,0 +1,3261 @@ +{ + "baselineId": "freecad-1.1.1-property-fileincluded-mutation", + "caseCount": 20, + "cases": [ + { + "archiveName": "mutation-00.bin", + "before": { + "baseName": "mutation-00.bin", + "bytes": 23, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "73d52509575b3f17ad7e8ea2c5afda37c53d1b04c185ae6563acccf8f5a16959", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1eac3be9-2891-4ce7-a651-5c6cb6d640b5_da39a3_496089/mutation-00.bin", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 23, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.bin", + "sha256": "73d52509575b3f17ad7e8ea2c5afda37c53d1b04c185ae6563acccf8f5a16959" + }, + "edited": { + "baseName": "mutation-00.bin", + "bytes": 23, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "c781e97e8b8fe197b1a07c1126abc1a7171ab112161367e37594569df1f35d4d", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1eac3be9-2891-4ce7-a651-5c6cb6d640b5_da39a3_496089/mutation-00.bin", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-00.bin", + "bytes": 23, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "c781e97e8b8fe197b1a07c1126abc1a7171ab112161367e37594569df1f35d4d", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1eac3be9-2891-4ce7-a651-5c6cb6d640b5_da39a3_496089/mutation-00.bin", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 23, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.bin", + "sha256": "c781e97e8b8fe197b1a07c1126abc1a7171ab112161367e37594569df1f35d4d" + }, + "objectSetStable": true, + "objectTypeId": "App::DocumentObjectFileIncluded", + "pathStable": true, + "propertyName": "File", + "restored": { + "baseName": "mutation-00.bin", + "bytes": 23, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "73d52509575b3f17ad7e8ea2c5afda37c53d1b04c185ae6563acccf8f5a16959", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1eac3be9-2891-4ce7-a651-5c6cb6d640b5_da39a3_496089/mutation-00.bin", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-00.bin", + "bytes": 23, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "73d52509575b3f17ad7e8ea2c5afda37c53d1b04c185ae6563acccf8f5a16959", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1eac3be9-2891-4ce7-a651-5c6cb6d640b5_da39a3_496089/mutation-00.bin", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-01.wrl", + "before": { + "baseName": "mutation-01.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "App::VRMLObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_12cbac59-9b0a-4bc6-8e10-40fefbfb79c7_da39a3_496089/mutation-01.wrl", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 54, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.wrl", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179" + }, + "edited": { + "baseName": "mutation-01.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "App::VRMLObject" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "7b0c1b60ee65ba0d66b3d8ede7827ce6e14ce9f66ebc0d63c901687c5763c71d", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_12cbac59-9b0a-4bc6-8e10-40fefbfb79c7_da39a3_496089/mutation-01.wrl", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-01.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "App::VRMLObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "7b0c1b60ee65ba0d66b3d8ede7827ce6e14ce9f66ebc0d63c901687c5763c71d", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_12cbac59-9b0a-4bc6-8e10-40fefbfb79c7_da39a3_496089/mutation-01.wrl", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 54, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.wrl", + "sha256": "7b0c1b60ee65ba0d66b3d8ede7827ce6e14ce9f66ebc0d63c901687c5763c71d" + }, + "objectSetStable": true, + "objectTypeId": "App::VRMLObject", + "pathStable": true, + "propertyName": "VrmlFile", + "restored": { + "baseName": "mutation-01.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "App::VRMLObject" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_12cbac59-9b0a-4bc6-8e10-40fefbfb79c7_da39a3_496089/mutation-01.wrl", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-01.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "App::VRMLObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_12cbac59-9b0a-4bc6-8e10-40fefbfb79c7_da39a3_496089/mutation-01.wrl", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-02.png", + "before": { + "baseName": "mutation-02.png", + "bytes": 68, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Image::ImagePlane" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7ad53847-d842-4f7f-8d4c-4bb4d2cc64b9_da39a3_496089/mutation-02.png", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 68, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.png", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460" + }, + "edited": { + "baseName": "mutation-02.png", + "bytes": 76, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Image::ImagePlane" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "46a6f6f6f7ede15b30801511c8bc83a0ec95f6666ef8c5bca0950b7ee7e71ec8", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7ad53847-d842-4f7f-8d4c-4bb4d2cc64b9_da39a3_496089/mutation-02.png", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-02.png", + "bytes": 76, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Image::ImagePlane" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "46a6f6f6f7ede15b30801511c8bc83a0ec95f6666ef8c5bca0950b7ee7e71ec8", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7ad53847-d842-4f7f-8d4c-4bb4d2cc64b9_da39a3_496089/mutation-02.png", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 76, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.png", + "sha256": "46a6f6f6f7ede15b30801511c8bc83a0ec95f6666ef8c5bca0950b7ee7e71ec8" + }, + "objectSetStable": true, + "objectTypeId": "Image::ImagePlane", + "pathStable": true, + "propertyName": "ImageFile", + "restored": { + "baseName": "mutation-02.png", + "bytes": 68, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Image::ImagePlane" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7ad53847-d842-4f7f-8d4c-4bb4d2cc64b9_da39a3_496089/mutation-02.png", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-02.png", + "bytes": 68, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Image::ImagePlane" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7ad53847-d842-4f7f-8d4c-4bb4d2cc64b9_da39a3_496089/mutation-02.png", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-03.csv", + "before": { + "baseName": "mutation-03.csv", + "bytes": 214, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "75a789684c89a28de4dc9e8c40fe836e0cdbeeb2f58de251dd0734adb98bda3a", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_b51f137c-3f2a-4bf1-8c1f-28e862bfef4e_da39a3_496089/mutation-03.csv", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 214, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.csv", + "sha256": "75a789684c89a28de4dc9e8c40fe836e0cdbeeb2f58de251dd0734adb98bda3a" + }, + "edited": { + "baseName": "mutation-03.csv", + "bytes": 214, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "146dd95394774596f92d5bf2c41836549ec7d2f5c2ed4ed7596f5f52ccd78e01", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_b51f137c-3f2a-4bf1-8c1f-28e862bfef4e_da39a3_496089/mutation-03.csv", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-03.csv", + "bytes": 214, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "146dd95394774596f92d5bf2c41836549ec7d2f5c2ed4ed7596f5f52ccd78e01", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_b51f137c-3f2a-4bf1-8c1f-28e862bfef4e_da39a3_496089/mutation-03.csv", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 214, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.csv", + "sha256": "146dd95394774596f92d5bf2c41836549ec7d2f5c2ed4ed7596f5f52ccd78e01" + }, + "objectSetStable": true, + "objectTypeId": "Robot::RobotObject", + "pathStable": true, + "propertyName": "RobotKinematicFile", + "restored": { + "baseName": "mutation-03.csv", + "bytes": 214, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "75a789684c89a28de4dc9e8c40fe836e0cdbeeb2f58de251dd0734adb98bda3a", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_b51f137c-3f2a-4bf1-8c1f-28e862bfef4e_da39a3_496089/mutation-03.csv", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-03.csv", + "bytes": 214, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "75a789684c89a28de4dc9e8c40fe836e0cdbeeb2f58de251dd0734adb98bda3a", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_b51f137c-3f2a-4bf1-8c1f-28e862bfef4e_da39a3_496089/mutation-03.csv", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-04.wrl", + "before": { + "baseName": "mutation-04.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7cecd767-c12f-4af0-bc29-d494b3758b27_da39a3_496089/mutation-04.wrl", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 54, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.wrl", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179" + }, + "edited": { + "baseName": "mutation-04.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "7b0c1b60ee65ba0d66b3d8ede7827ce6e14ce9f66ebc0d63c901687c5763c71d", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7cecd767-c12f-4af0-bc29-d494b3758b27_da39a3_496089/mutation-04.wrl", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-04.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "7b0c1b60ee65ba0d66b3d8ede7827ce6e14ce9f66ebc0d63c901687c5763c71d", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7cecd767-c12f-4af0-bc29-d494b3758b27_da39a3_496089/mutation-04.wrl", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 54, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.wrl", + "sha256": "7b0c1b60ee65ba0d66b3d8ede7827ce6e14ce9f66ebc0d63c901687c5763c71d" + }, + "objectSetStable": true, + "objectTypeId": "Robot::RobotObject", + "pathStable": true, + "propertyName": "RobotVrmlFile", + "restored": { + "baseName": "mutation-04.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7cecd767-c12f-4af0-bc29-d494b3758b27_da39a3_496089/mutation-04.wrl", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-04.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7cecd767-c12f-4af0-bc29-d494b3758b27_da39a3_496089/mutation-04.wrl", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-05.skf", + "before": { + "baseName": "mutation-05.skf", + "bytes": 28, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Sketcher::SketchObjectSF" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "9f9a41a7f567936789033a44b600999b3c9840d7ba1a08b6bd39ecb56e8707f4", + "shape": { + "applicable": true, + "edges": 0, + "faces": 0, + "isNull": true, + "solids": 0, + "vertices": 0 + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_44f843e4-6478-4344-af85-eee5f99cac52_da39a3_496089/mutation-05.skf", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 28, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.skf", + "sha256": "9f9a41a7f567936789033a44b600999b3c9840d7ba1a08b6bd39ecb56e8707f4" + }, + "edited": { + "baseName": "mutation-05.skf", + "bytes": 28, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Sketcher::SketchObjectSF" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "cfb742a74d4a78f89d6a7cbd9063b7b5d9d415d20aaeced8fc60632cdef4fd31", + "shape": { + "applicable": true, + "edges": 0, + "faces": 0, + "isNull": true, + "solids": 0, + "vertices": 0 + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_44f843e4-6478-4344-af85-eee5f99cac52_da39a3_496089/mutation-05.skf", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-05.skf", + "bytes": 28, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Sketcher::SketchObjectSF" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "cfb742a74d4a78f89d6a7cbd9063b7b5d9d415d20aaeced8fc60632cdef4fd31", + "shape": { + "applicable": true, + "edges": 0, + "faces": 0, + "isNull": true, + "solids": 0, + "vertices": 0 + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_44f843e4-6478-4344-af85-eee5f99cac52_da39a3_496089/mutation-05.skf", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 28, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.skf", + "sha256": "cfb742a74d4a78f89d6a7cbd9063b7b5d9d415d20aaeced8fc60632cdef4fd31" + }, + "objectSetStable": true, + "objectTypeId": "Sketcher::SketchObjectSF", + "pathStable": true, + "propertyName": "SketchFlatFile", + "restored": { + "baseName": "mutation-05.skf", + "bytes": 28, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Sketcher::SketchObjectSF" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "9f9a41a7f567936789033a44b600999b3c9840d7ba1a08b6bd39ecb56e8707f4", + "shape": { + "applicable": true, + "edges": 0, + "faces": 0, + "isNull": true, + "solids": 0, + "vertices": 0 + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_44f843e4-6478-4344-af85-eee5f99cac52_da39a3_496089/mutation-05.skf", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-05.skf", + "bytes": 28, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "Sketcher::SketchObjectSF" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "9f9a41a7f567936789033a44b600999b3c9840d7ba1a08b6bd39ecb56e8707f4", + "shape": { + "applicable": true, + "edges": 0, + "faces": 0, + "isNull": true, + "solids": 0, + "vertices": 0 + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_44f843e4-6478-4344-af85-eee5f99cac52_da39a3_496089/mutation-05.skf", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-06.pat", + "before": { + "baseName": "mutation-06.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1cb50d8c-6ce0-4fdb-bb5b-0bdfa72d7758_da39a3_496089/mutation-06.pat", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 41, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.pat", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7" + }, + "edited": { + "baseName": "mutation-06.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1cb50d8c-6ce0-4fdb-bb5b-0bdfa72d7758_da39a3_496089/mutation-06.pat", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-06.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1cb50d8c-6ce0-4fdb-bb5b-0bdfa72d7758_da39a3_496089/mutation-06.pat", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 41, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.pat", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawComplexSection", + "pathStable": true, + "propertyName": "PatIncluded", + "restored": { + "baseName": "mutation-06.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1cb50d8c-6ce0-4fdb-bb5b-0bdfa72d7758_da39a3_496089/mutation-06.pat", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-06.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1cb50d8c-6ce0-4fdb-bb5b-0bdfa72d7758_da39a3_496089/mutation-06.pat", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-07.svg", + "before": { + "baseName": "mutation-07.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_26ea3856-ce48-484f-843c-fe6ec55cb619_da39a3_496089/mutation-07.svg", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + }, + "edited": { + "baseName": "mutation-07.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_26ea3856-ce48-484f-843c-fe6ec55cb619_da39a3_496089/mutation-07.svg", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-07.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_26ea3856-ce48-484f-843c-fe6ec55cb619_da39a3_496089/mutation-07.svg", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.svg", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawComplexSection", + "pathStable": true, + "propertyName": "SvgIncluded", + "restored": { + "baseName": "mutation-07.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_26ea3856-ce48-484f-843c-fe6ec55cb619_da39a3_496089/mutation-07.svg", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-07.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_26ea3856-ce48-484f-843c-fe6ec55cb619_da39a3_496089/mutation-07.svg", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-08.pat", + "before": { + "baseName": "mutation-08.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4cfa5cf9-eaf1-4b0f-850f-0dd6610ff457_da39a3_496089/mutation-08.pat", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 41, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.pat", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7" + }, + "edited": { + "baseName": "mutation-08.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4cfa5cf9-eaf1-4b0f-850f-0dd6610ff457_da39a3_496089/mutation-08.pat", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-08.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4cfa5cf9-eaf1-4b0f-850f-0dd6610ff457_da39a3_496089/mutation-08.pat", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 41, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.pat", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawComplexSectionPython", + "pathStable": true, + "propertyName": "PatIncluded", + "restored": { + "baseName": "mutation-08.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4cfa5cf9-eaf1-4b0f-850f-0dd6610ff457_da39a3_496089/mutation-08.pat", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-08.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4cfa5cf9-eaf1-4b0f-850f-0dd6610ff457_da39a3_496089/mutation-08.pat", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-09.svg", + "before": { + "baseName": "mutation-09.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4f4bb9d0-5616-479a-93a5-5e6caa260e78_da39a3_496089/mutation-09.svg", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + }, + "edited": { + "baseName": "mutation-09.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4f4bb9d0-5616-479a-93a5-5e6caa260e78_da39a3_496089/mutation-09.svg", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-09.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4f4bb9d0-5616-479a-93a5-5e6caa260e78_da39a3_496089/mutation-09.svg", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.svg", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawComplexSectionPython", + "pathStable": true, + "propertyName": "SvgIncluded", + "restored": { + "baseName": "mutation-09.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4f4bb9d0-5616-479a-93a5-5e6caa260e78_da39a3_496089/mutation-09.svg", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-09.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4f4bb9d0-5616-479a-93a5-5e6caa260e78_da39a3_496089/mutation-09.svg", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-10.pat", + "before": { + "baseName": "mutation-10.pat", + "bytes": 41, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawGeomHatch" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1e5019bf-da05-471f-bf1e-2cef1c291097_da39a3_496089/mutation-10.pat", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 41, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.pat", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7" + }, + "edited": { + "baseName": "mutation-10.pat", + "bytes": 41, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawGeomHatch" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1e5019bf-da05-471f-bf1e-2cef1c291097_da39a3_496089/mutation-10.pat", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-10.pat", + "bytes": 41, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawGeomHatch" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1e5019bf-da05-471f-bf1e-2cef1c291097_da39a3_496089/mutation-10.pat", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 41, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.pat", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawGeomHatch", + "pathStable": true, + "propertyName": "PatIncluded", + "restored": { + "baseName": "mutation-10.pat", + "bytes": 41, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawGeomHatch" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1e5019bf-da05-471f-bf1e-2cef1c291097_da39a3_496089/mutation-10.pat", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-10.pat", + "bytes": 41, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawGeomHatch" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1e5019bf-da05-471f-bf1e-2cef1c291097_da39a3_496089/mutation-10.pat", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-11.svg", + "before": { + "baseName": "mutation-11.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawHatch" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_868b6c08-e24b-4617-8bfe-02a1314f94d8_da39a3_496089/mutation-11.svg", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + }, + "edited": { + "baseName": "mutation-11.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawHatch" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_868b6c08-e24b-4617-8bfe-02a1314f94d8_da39a3_496089/mutation-11.svg", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-11.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawHatch" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_868b6c08-e24b-4617-8bfe-02a1314f94d8_da39a3_496089/mutation-11.svg", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.svg", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawHatch", + "pathStable": true, + "propertyName": "SvgIncluded", + "restored": { + "baseName": "mutation-11.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawHatch" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_868b6c08-e24b-4617-8bfe-02a1314f94d8_da39a3_496089/mutation-11.svg", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-11.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawHatch" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_868b6c08-e24b-4617-8bfe-02a1314f94d8_da39a3_496089/mutation-11.svg", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-12.svg", + "before": { + "baseName": "mutation-12.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawSVGTemplate" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "27" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_16d9fdd1-1d17-4973-a565-8ecbd59c7ec6_da39a3_496089/mutation-12.svg", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + }, + "edited": { + "baseName": "mutation-12.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawSVGTemplate" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "27" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_16d9fdd1-1d17-4973-a565-8ecbd59c7ec6_da39a3_496089/mutation-12.svg", + "writeBits": 0 + }, + "editedRecompute": { + "result": false, + "snapshot": { + "baseName": "mutation-12.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawSVGTemplate" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "27" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_16d9fdd1-1d17-4973-a565-8ecbd59c7ec6_da39a3_496089/mutation-12.svg", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.svg", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawSVGTemplate", + "pathStable": true, + "propertyName": "PageResult", + "restored": { + "baseName": "mutation-12.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawSVGTemplate" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "27" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_16d9fdd1-1d17-4973-a565-8ecbd59c7ec6_da39a3_496089/mutation-12.svg", + "writeBits": 0 + }, + "restoredRecompute": { + "result": false, + "snapshot": { + "baseName": "mutation-12.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawSVGTemplate" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "27" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_16d9fdd1-1d17-4973-a565-8ecbd59c7ec6_da39a3_496089/mutation-12.svg", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-13.svg", + "before": { + "baseName": "mutation-13.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawTileWeld" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_6e774dd0-907a-447c-bfb5-7486bd4903e6_da39a3_496089/mutation-13.svg", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + }, + "edited": { + "baseName": "mutation-13.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawTileWeld" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_6e774dd0-907a-447c-bfb5-7486bd4903e6_da39a3_496089/mutation-13.svg", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-13.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawTileWeld" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_6e774dd0-907a-447c-bfb5-7486bd4903e6_da39a3_496089/mutation-13.svg", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.svg", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawTileWeld", + "pathStable": true, + "propertyName": "SymbolIncluded", + "restored": { + "baseName": "mutation-13.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawTileWeld" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_6e774dd0-907a-447c-bfb5-7486bd4903e6_da39a3_496089/mutation-13.svg", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-13.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawTileWeld" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_6e774dd0-907a-447c-bfb5-7486bd4903e6_da39a3_496089/mutation-13.svg", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-14.svg", + "before": { + "baseName": "mutation-14.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawTileWeldPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_57fa62e3-218c-4a3f-a22e-cd4bac89c2cb_da39a3_496089/mutation-14.svg", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + }, + "edited": { + "baseName": "mutation-14.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawTileWeldPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_57fa62e3-218c-4a3f-a22e-cd4bac89c2cb_da39a3_496089/mutation-14.svg", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-14.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawTileWeldPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_57fa62e3-218c-4a3f-a22e-cd4bac89c2cb_da39a3_496089/mutation-14.svg", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.svg", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawTileWeldPython", + "pathStable": true, + "propertyName": "SymbolIncluded", + "restored": { + "baseName": "mutation-14.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawTileWeldPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_57fa62e3-218c-4a3f-a22e-cd4bac89c2cb_da39a3_496089/mutation-14.svg", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-14.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawTileWeldPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_57fa62e3-218c-4a3f-a22e-cd4bac89c2cb_da39a3_496089/mutation-14.svg", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-15.png", + "before": { + "baseName": "mutation-15.png", + "bytes": 68, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewImage" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1fc0945e-bc25-4332-a47a-0eec05760450_da39a3_496089/mutation-15.png", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 68, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.png", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460" + }, + "edited": { + "baseName": "mutation-15.png", + "bytes": 76, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewImage" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "46a6f6f6f7ede15b30801511c8bc83a0ec95f6666ef8c5bca0950b7ee7e71ec8", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1fc0945e-bc25-4332-a47a-0eec05760450_da39a3_496089/mutation-15.png", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-15.png", + "bytes": 76, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewImage" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "46a6f6f6f7ede15b30801511c8bc83a0ec95f6666ef8c5bca0950b7ee7e71ec8", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1fc0945e-bc25-4332-a47a-0eec05760450_da39a3_496089/mutation-15.png", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 76, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.png", + "sha256": "46a6f6f6f7ede15b30801511c8bc83a0ec95f6666ef8c5bca0950b7ee7e71ec8" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawViewImage", + "pathStable": true, + "propertyName": "ImageIncluded", + "restored": { + "baseName": "mutation-15.png", + "bytes": 68, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewImage" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1fc0945e-bc25-4332-a47a-0eec05760450_da39a3_496089/mutation-15.png", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-15.png", + "bytes": 68, + "editorMode": [], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewImage" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_1fc0945e-bc25-4332-a47a-0eec05760450_da39a3_496089/mutation-15.png", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-16.pat", + "before": { + "baseName": "mutation-16.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_eb9c4bcd-5455-41c8-8a7a-3392b5cf62f8_da39a3_496089/mutation-16.pat", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 41, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.pat", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7" + }, + "edited": { + "baseName": "mutation-16.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_eb9c4bcd-5455-41c8-8a7a-3392b5cf62f8_da39a3_496089/mutation-16.pat", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-16.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_eb9c4bcd-5455-41c8-8a7a-3392b5cf62f8_da39a3_496089/mutation-16.pat", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 41, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.pat", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawViewSection", + "pathStable": true, + "propertyName": "PatIncluded", + "restored": { + "baseName": "mutation-16.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_eb9c4bcd-5455-41c8-8a7a-3392b5cf62f8_da39a3_496089/mutation-16.pat", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-16.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_eb9c4bcd-5455-41c8-8a7a-3392b5cf62f8_da39a3_496089/mutation-16.pat", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-17.svg", + "before": { + "baseName": "mutation-17.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_2d12cac7-133a-459e-9e0c-4d848c1e12bc_da39a3_496089/mutation-17.svg", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + }, + "edited": { + "baseName": "mutation-17.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_2d12cac7-133a-459e-9e0c-4d848c1e12bc_da39a3_496089/mutation-17.svg", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-17.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_2d12cac7-133a-459e-9e0c-4d848c1e12bc_da39a3_496089/mutation-17.svg", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.svg", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawViewSection", + "pathStable": true, + "propertyName": "SvgIncluded", + "restored": { + "baseName": "mutation-17.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_2d12cac7-133a-459e-9e0c-4d848c1e12bc_da39a3_496089/mutation-17.svg", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-17.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_2d12cac7-133a-459e-9e0c-4d848c1e12bc_da39a3_496089/mutation-17.svg", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-18.pat", + "before": { + "baseName": "mutation-18.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_65c581ff-f4b4-4423-955a-0dd328fde6d8_da39a3_496089/mutation-18.pat", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 41, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.pat", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7" + }, + "edited": { + "baseName": "mutation-18.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_65c581ff-f4b4-4423-955a-0dd328fde6d8_da39a3_496089/mutation-18.pat", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-18.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_65c581ff-f4b4-4423-955a-0dd328fde6d8_da39a3_496089/mutation-18.pat", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 41, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.pat", + "sha256": "a2f419d0b5a22e4f381069350fcd3cc60f331ed551122f25be1b788cd371b04e" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawViewSectionPython", + "pathStable": true, + "propertyName": "PatIncluded", + "restored": { + "baseName": "mutation-18.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_65c581ff-f4b4-4423-955a-0dd328fde6d8_da39a3_496089/mutation-18.pat", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-18.pat", + "bytes": 41, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f677c321cd42eaa326e8e900c30131fa9c5adf660be22a97a1a3eb64108352d7", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_65c581ff-f4b4-4423-955a-0dd328fde6d8_da39a3_496089/mutation-18.pat", + "writeBits": 0 + } + } + }, + { + "archiveName": "mutation-19.svg", + "before": { + "baseName": "mutation-19.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_ee2a231a-9df5-42d6-84b5-a2bf7fc40e64_da39a3_496089/mutation-19.svg", + "writeBits": 0 + }, + "beforeSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/before.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + }, + "edited": { + "baseName": "mutation-19.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_ee2a231a-9df5-42d6-84b5-a2bf7fc40e64_da39a3_496089/mutation-19.svg", + "writeBits": 0 + }, + "editedRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-19.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_ee2a231a-9df5-42d6-84b5-a2bf7fc40e64_da39a3_496089/mutation-19.svg", + "writeBits": 0 + } + }, + "editedSource": { + "bytes": 88, + "path": "/tmp/freecad-property-fileincluded-mutation-8vdorthl/edited.svg", + "sha256": "459a52900d03f1832a79ca1d2b3252cb913bf6bc6d0dc51c672af2bc21f07733" + }, + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawViewSectionPython", + "pathStable": true, + "propertyName": "SvgIncluded", + "restored": { + "baseName": "mutation-19.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_ee2a231a-9df5-42d6-84b5-a2bf7fc40e64_da39a3_496089/mutation-19.svg", + "writeBits": 0 + }, + "restoredRecompute": { + "result": true, + "snapshot": { + "baseName": "mutation-19.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "objectSet": [ + { + "name": "MutationProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_ee2a231a-9df5-42d6-84b5-a2bf7fc40e64_da39a3_496089/mutation-19.svg", + "writeBits": 0 + } + } + } + ], + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyFileIncluded", + "schemaVersion": 1, + "status": "pass" +} diff --git a/config/freecad-property-fileincluded-promotion.json b/config/freecad-property-fileincluded-promotion.json new file mode 100644 index 0000000..653e495 --- /dev/null +++ b/config/freecad-property-fileincluded-promotion.json @@ -0,0 +1,76 @@ +{ + "schemaVersion": 1, + "status": "pass", + "taskId": "PROP-app-propertyfileincluded-I", + "baseline": { + "freecadVersion": "1.1.1", + "commit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + }, + "propertyType": "App::PropertyFileIncluded", + "recordCount": 20, + "phaseEvidence": { + "A": [ + "config/freecad-property-fileincluded-inventory.json", + "check:freecad-property-fileincluded-inventory" + ], + "B": [ + "config/freecad-property-fileincluded-success.json", + "check:freecad-property-fileincluded-success" + ], + "C": [ + "config/freecad-property-fileincluded-failure.json", + "check:freecad-property-fileincluded-failure" + ], + "D": [ + "config/freecad-property-fileincluded-mutation.json", + "check:freecad-property-fileincluded-mutation" + ], + "E": [ + "src/facade/includedFile.ts", + "src/facade/types.ts", + "src/facade/fcstd.ts", + "src/facade/mockFacade.ts", + "src/App.tsx", + "tests/propertyFileIncludedFacade.test.ts", + "test:freecad-property-fileincluded-facade" + ], + "F": [ + "tests/propertyFileIncludedTransaction.test.ts", + "test:freecad-property-fileincluded-transaction" + ], + "G": [ + "config/freecad-property-fileincluded-roundtrip.json", + "check:freecad-property-fileincluded-roundtrip" + ], + "H": [ + "config/chrome-property-fileincluded-verification.json", + "check:chrome-property-fileincluded" + ] + }, + "promotion": { + "from": "opaque-fcstd-proxy", + "to": "native-editable-codec", + "facadeValueModel": "project-resource-identity-and-authoritative-bytes-with-native-fileincluded-fcstd-resource", + "writableRecords": 11, + "readOnlyRecords": 8, + "outputRecords": 1, + "objectTypeCount": 15, + "fcstdElement": "FileIncluded", + "nativeArchiveName": "payload.bin", + "nativeRoundTripSha256": "09f4e4853de4277e25871d26f2e953c6ea9c13a73c7a01bdfcb5209d17f9a583", + "browserArchiveName": "chrome-resource.bin", + "browserRoundTripBytes": 16, + "externalResourceBoundary": "embedded FCStd ZIP entry restored to a read-only document transient file", + "zeroUnknownDrift": true + }, + "exactBlockerSync": { + "nativeEditableTypes": 30, + "nativeEditableRecords": 4361, + "opaqueTypes": 50, + "opaqueRecords": 466, + "exactPromotionReady": false, + "exactBlocker": "50 runtime property types and 466 records remain opaque-only; complete native document and property semantics" + }, + "systemExact": false, + "generatedAt": "2026-08-17T08:49:33.815Z" +} diff --git a/config/freecad-property-fileincluded-roundtrip.json b/config/freecad-property-fileincluded-roundtrip.json new file mode 100644 index 0000000..6358cc1 --- /dev/null +++ b/config/freecad-property-fileincluded-roundtrip.json @@ -0,0 +1,187 @@ +{ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-fileincluded-roundtrip", + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "propertyType": "App::PropertyFileIncluded", + "assets": { + "initial": { + "path": ".cache/freecad/property-fileincluded-roundtrip/initial.bin", + "bytes": 13, + "sha256": "974b81bb5869530635082c3c33edafbc4aad32b11ac01031432d0ae657be1336" + }, + "target": { + "path": ".cache/freecad/property-fileincluded-roundtrip/target.bin", + "bytes": 20, + "sha256": "09f4e4853de4277e25871d26f2e953c6ea9c13a73c7a01bdfcb5209d17f9a583" + } + }, + "archives": { + "nativeInitial": { + "path": ".cache/freecad/property-fileincluded-roundtrip/native-initial.FCStd", + "bytes": 1357, + "sha256": "5f6f0be7bb04019652c5e43c3398604f0ce6f72782e027158f3b4b6acac4af4e" + }, + "webEdited": { + "path": ".cache/freecad/property-fileincluded-roundtrip/web-edited.FCStd", + "bytes": 1206, + "sha256": "b826b63e1f4807fd8914c2e51098d544544e79a6efc3a1b14e522d9965f49790" + }, + "nativeResaved": { + "path": ".cache/freecad/property-fileincluded-roundtrip/native-resaved.FCStd", + "bytes": 1364, + "sha256": "2e1a5836ab2404ec59d344ebdc45cf4c81ee6887402e5ae1548ce4ca7e7f477e" + } + }, + "nativeInitial": { + "object": { + "baseName": "payload.bin", + "bytes": 13, + "editorMode": [], + "exists": true, + "hasShapeProperty": false, + "mode": 256, + "name": "IncludedProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "974b81bb5869530635082c3c33edafbc4aad32b11ac01031432d0ae657be1336", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::DocumentObjectFileIncluded", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_9dbdcbfb-2e87-49ea-9bf0-99bb6c6f3833_f49955_361283/payload.bin", + "writeBits": 0 + }, + "objectSet": [ + { + "name": "IncludedProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ] + }, + "web": { + "before": { + "name": "File", + "typeId": "App::PropertyFileIncluded", + "element": "FileIncluded", + "value": "{\"path\":\"payload.bin\",\"mediaType\":\"application/octet-stream\",\"byteLength\":13,\"contentHash\":\"aefb8d38\",\"status\":\"available\"}", + "resourcePath": "payload.bin", + "includedFileResource": { + "path": "payload.bin", + "mediaType": "application/octet-stream", + "byteLength": 13, + "contentHash": "aefb8d38", + "status": "available" + } + }, + "after": { + "name": "File", + "typeId": "App::PropertyFileIncluded", + "element": "FileIncluded", + "value": "{\"path\":\"payload.bin\",\"mediaType\":\"application/octet-stream\",\"byteLength\":20,\"contentHash\":\"2a7d5998\",\"status\":\"available\"}", + "resourcePath": "payload.bin", + "includedFileResource": { + "path": "payload.bin", + "mediaType": "application/octet-stream", + "byteLength": 20, + "contentHash": "2a7d5998", + "status": "available" + } + }, + "resource": { + "path": "payload.bin", + "pathPreserved": true, + "beforeBytes": 13, + "afterBytes": 20, + "beforeSha256": "974b81bb5869530635082c3c33edafbc4aad32b11ac01031432d0ae657be1336", + "afterSha256": "09f4e4853de4277e25871d26f2e953c6ea9c13a73c7a01bdfcb5209d17f9a583", + "changed": true + }, + "targetMarkedTouched": true, + "webOutputMatches": true, + "semanticObjectsPreserved": true, + "opaquePathsPreserved": 0, + "opaqueEntriesPreserved": true + }, + "nativeAfter": { + "reopened": { + "object": { + "baseName": "payload.bin", + "bytes": 20, + "editorMode": [], + "exists": true, + "hasShapeProperty": false, + "mode": 256, + "name": "IncludedProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "09f4e4853de4277e25871d26f2e953c6ea9c13a73c7a01bdfcb5209d17f9a583", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::DocumentObjectFileIncluded", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_9dbdcbfb-2e87-49ea-9bf0-99bb6c6f3833_037685_844069/payload.bin", + "writeBits": 0 + }, + "objectSet": [ + { + "name": "IncludedProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ] + }, + "resaved": { + "object": { + "baseName": "payload.bin", + "bytes": 20, + "editorMode": [], + "exists": true, + "hasShapeProperty": false, + "mode": 256, + "name": "IncludedProbe", + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "09f4e4853de4277e25871d26f2e953c6ea9c13a73c7a01bdfcb5209d17f9a583", + "state": [ + "Up-to-date" + ], + "statusString": "Valid", + "typeId": "App::DocumentObjectFileIncluded", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_9dbdcbfb-2e87-49ea-9bf0-99bb6c6f3833_35b665_844069/payload.bin", + "writeBits": 0 + }, + "objectSet": [ + { + "name": "IncludedProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ] + } + }, + "nativeResavedResource": { + "path": "payload.bin", + "mediaType": "application/octet-stream", + "byteLength": 20, + "contentHash": "2a7d5998", + "status": "available" + }, + "classification": { + "archiveName": "payload.bin", + "initialSha256": "974b81bb5869530635082c3c33edafbc4aad32b11ac01031432d0ae657be1336", + "targetSha256": "09f4e4853de4277e25871d26f2e953c6ea9c13a73c7a01bdfcb5209d17f9a583", + "reopenedSha256": "09f4e4853de4277e25871d26f2e953c6ea9c13a73c7a01bdfcb5209d17f9a583", + "resavedSha256": "09f4e4853de4277e25871d26f2e953c6ea9c13a73c7a01bdfcb5209d17f9a583", + "nativeOutputMatches": true, + "objectSetPreserved": true, + "resavedResourceMatches": true, + "externalResourceBoundary": "embedded FCStd ZIP entry restored to a read-only document transient file", + "unknownSemanticDrift": false, + "zeroUnknownDrift": true + } +} diff --git a/config/freecad-property-fileincluded-success.json b/config/freecad-property-fileincluded-success.json new file mode 100644 index 0000000..b243745 --- /dev/null +++ b/config/freecad-property-fileincluded-success.json @@ -0,0 +1,2554 @@ +{ + "baselineId": "freecad-1.1.1-property-fileincluded-success", + "diagnostics": { + "exception": null + }, + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "hostCaseCount": 20, + "hostCases": [ + { + "afterRecompute": { + "baseName": "host-00.bin", + "bytes": 38, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7f1e7e40-02dc-437e-9fe4-8ebf97a3d479_da39a3_39077/host-00.bin", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-00.bin", + "bytes": 38, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_7f1e7e40-02dc-437e-9fe4-8ebf97a3d479_da39a3_39077/host-00.bin", + "writeBits": 0 + }, + "archiveName": "host-00.bin", + "default": { + "baseName": "", + "bytes": 0, + "editorMode": [], + "exists": false, + "mode": null, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": null, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": false, + "value": "", + "writeBits": null + }, + "group": "", + "objectSetStable": true, + "objectTypeId": "App::DocumentObjectFileIncluded", + "propertyName": "File", + "recomputeResult": true, + "source": { + "bytes": 38, + "kind": "bin", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/payload.bin", + "sha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246" + } + }, + { + "afterRecompute": { + "baseName": "host-01.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "App::VRMLObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4d79537b-9988-4ab1-97a5-ace86a924bd6_da39a3_39077/host-01.wrl", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-01.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "App::VRMLObject" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4d79537b-9988-4ab1-97a5-ace86a924bd6_da39a3_39077/host-01.wrl", + "writeBits": 0 + }, + "archiveName": "host-01.wrl", + "default": { + "baseName": "", + "bytes": 0, + "editorMode": [], + "exists": false, + "mode": null, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "App::VRMLObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": null, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": false, + "value": "", + "writeBits": null + }, + "group": "", + "objectSetStable": true, + "objectTypeId": "App::VRMLObject", + "propertyName": "VrmlFile", + "recomputeResult": true, + "source": { + "bytes": 54, + "kind": "wrl", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/model.wrl", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179" + } + }, + { + "afterRecompute": { + "baseName": "host-02.png", + "bytes": 68, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Image::ImagePlane" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_410a1698-6bd1-423e-84d9-4b7ded244177_da39a3_39077/host-02.png", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-02.png", + "bytes": 68, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Image::ImagePlane" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_410a1698-6bd1-423e-84d9-4b7ded244177_da39a3_39077/host-02.png", + "writeBits": 0 + }, + "archiveName": "host-02.png", + "default": { + "baseName": "", + "bytes": 0, + "editorMode": [], + "exists": false, + "mode": null, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Image::ImagePlane" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": null, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": false, + "value": "", + "writeBits": null + }, + "group": "ImagePlane", + "objectSetStable": true, + "objectTypeId": "Image::ImagePlane", + "propertyName": "ImageFile", + "recomputeResult": true, + "source": { + "bytes": 68, + "kind": "png", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pixel.png", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460" + } + }, + { + "afterRecompute": { + "baseName": "host-03.csv", + "bytes": 214, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "75a789684c89a28de4dc9e8c40fe836e0cdbeeb2f58de251dd0734adb98bda3a", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_a81608fa-6c75-44e9-9376-ccf092961002_da39a3_39077/host-03.csv", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-03.csv", + "bytes": 214, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "75a789684c89a28de4dc9e8c40fe836e0cdbeeb2f58de251dd0734adb98bda3a", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_a81608fa-6c75-44e9-9376-ccf092961002_da39a3_39077/host-03.csv", + "writeBits": 0 + }, + "archiveName": "host-03.csv", + "default": { + "baseName": "", + "bytes": 0, + "editorMode": [], + "exists": false, + "mode": null, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": null, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": false, + "value": "", + "writeBits": null + }, + "group": "Robot definition", + "objectSetStable": true, + "objectTypeId": "Robot::RobotObject", + "propertyName": "RobotKinematicFile", + "recomputeResult": true, + "source": { + "bytes": 214, + "kind": "csv", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/kinematic.csv", + "sha256": "75a789684c89a28de4dc9e8c40fe836e0cdbeeb2f58de251dd0734adb98bda3a" + } + }, + { + "afterRecompute": { + "baseName": "host-04.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4c97efbf-7fea-4c97-8523-97989e0d1702_da39a3_39077/host-04.wrl", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-04.wrl", + "bytes": 54, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4c97efbf-7fea-4c97-8523-97989e0d1702_da39a3_39077/host-04.wrl", + "writeBits": 0 + }, + "archiveName": "host-04.wrl", + "default": { + "baseName": "", + "bytes": 0, + "editorMode": [], + "exists": false, + "mode": null, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Robot::RobotObject" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": null, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": false, + "value": "", + "writeBits": null + }, + "group": "Robot definition", + "objectSetStable": true, + "objectTypeId": "Robot::RobotObject", + "propertyName": "RobotVrmlFile", + "recomputeResult": true, + "source": { + "bytes": 54, + "kind": "wrl", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/model.wrl", + "sha256": "b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179" + } + }, + { + "afterRecompute": { + "baseName": "host-05.skf", + "bytes": 42, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Sketcher::SketchObjectSF" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b32d9e3958b275212f00ab37b40e8cfb8f8fca5be7209713233cd55158031739", + "shape": { + "applicable": true, + "edges": 0, + "faces": 0, + "isNull": true, + "solids": 0, + "vertices": 0 + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_c98527c8-8f0f-499e-86eb-dd368bf6bab4_da39a3_39077/host-05.skf", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-05.skf", + "bytes": 42, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Sketcher::SketchObjectSF" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "b32d9e3958b275212f00ab37b40e8cfb8f8fca5be7209713233cd55158031739", + "shape": { + "applicable": true, + "edges": 0, + "faces": 0, + "isNull": true, + "solids": 0, + "vertices": 0 + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_c98527c8-8f0f-499e-86eb-dd368bf6bab4_da39a3_39077/host-05.skf", + "writeBits": 0 + }, + "archiveName": "host-05.skf", + "default": { + "baseName": "", + "bytes": 0, + "editorMode": [], + "exists": false, + "mode": null, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "Sketcher::SketchObjectSF" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": null, + "shape": { + "applicable": true, + "edges": 0, + "faces": 0, + "isNull": true, + "solids": 0, + "vertices": 0 + }, + "statusString": "Touched", + "underTransientDir": false, + "value": "", + "writeBits": null + }, + "group": "", + "objectSetStable": true, + "objectTypeId": "Sketcher::SketchObjectSF", + "propertyName": "SketchFlatFile", + "recomputeResult": true, + "source": { + "bytes": 42, + "kind": "skf", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/sketch.skf", + "sha256": "b32d9e3958b275212f00ab37b40e8cfb8f8fca5be7209713233cd55158031739" + } + }, + { + "afterRecompute": { + "baseName": "host-06.pat", + "bytes": 39, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_8d72ae29-8b92-4ab5-b90b-77f98c14c618_da39a3_39077/host-06.pat", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-06.pat", + "bytes": 39, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_8d72ae29-8b92-4ab5-b90b-77f98c14c618_da39a3_39077/host-06.pat", + "writeBits": 0 + }, + "archiveName": "host-06.pat", + "default": { + "baseName": "FCPAT.pat", + "bytes": 605, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f2260a21f1ae5b2865b16dd6050e240b2192d74a359f0cdf6c50183cff7bf31c", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_8d72ae29-8b92-4ab5-b90b-77f98c14c618_da39a3_39077/FCPAT.pat", + "writeBits": 0 + }, + "group": "Cut Surface Format", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawComplexSection", + "propertyName": "PatIncluded", + "recomputeResult": true, + "source": { + "bytes": 39, + "kind": "pat", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.pat", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98" + } + }, + { + "afterRecompute": { + "baseName": "host-07.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e181c91b-fbb8-4d8f-bcdd-2da68dcf07ee_da39a3_39077/host-07.svg", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-07.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e181c91b-fbb8-4d8f-bcdd-2da68dcf07ee_da39a3_39077/host-07.svg", + "writeBits": 0 + }, + "archiveName": "host-07.svg", + "default": { + "baseName": "simple.svg", + "bytes": 1931, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "68ff2efa1eb6e690ed59086ae6dc2c79b136fc1a06f251001aa9e7f680a08f6c", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e181c91b-fbb8-4d8f-bcdd-2da68dcf07ee_da39a3_39077/simple.svg", + "writeBits": 0 + }, + "group": "Cut Surface Format", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawComplexSection", + "propertyName": "SvgIncluded", + "recomputeResult": true, + "source": { + "bytes": 88, + "kind": "svg", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + } + }, + { + "afterRecompute": { + "baseName": "host-08.pat", + "bytes": 39, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_bd9a6faf-c627-4f17-956f-bec50b6711ba_da39a3_39077/host-08.pat", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-08.pat", + "bytes": 39, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_bd9a6faf-c627-4f17-956f-bec50b6711ba_da39a3_39077/host-08.pat", + "writeBits": 0 + }, + "archiveName": "host-08.pat", + "default": { + "baseName": "FCPAT.pat", + "bytes": 605, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f2260a21f1ae5b2865b16dd6050e240b2192d74a359f0cdf6c50183cff7bf31c", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_bd9a6faf-c627-4f17-956f-bec50b6711ba_da39a3_39077/FCPAT.pat", + "writeBits": 0 + }, + "group": "Cut Surface Format", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawComplexSectionPython", + "propertyName": "PatIncluded", + "recomputeResult": true, + "source": { + "bytes": 39, + "kind": "pat", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.pat", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98" + } + }, + { + "afterRecompute": { + "baseName": "host-09.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_bb3f171a-d81c-448d-8519-8daf7968da03_da39a3_39077/host-09.svg", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-09.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_bb3f171a-d81c-448d-8519-8daf7968da03_da39a3_39077/host-09.svg", + "writeBits": 0 + }, + "archiveName": "host-09.svg", + "default": { + "baseName": "simple.svg", + "bytes": 1931, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawComplexSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "68ff2efa1eb6e690ed59086ae6dc2c79b136fc1a06f251001aa9e7f680a08f6c", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_bb3f171a-d81c-448d-8519-8daf7968da03_da39a3_39077/simple.svg", + "writeBits": 0 + }, + "group": "Cut Surface Format", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawComplexSectionPython", + "propertyName": "SvgIncluded", + "recomputeResult": true, + "source": { + "bytes": 88, + "kind": "svg", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + } + }, + { + "afterRecompute": { + "baseName": "host-10.pat", + "bytes": 39, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawGeomHatch" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_2877eabe-7b66-4ba9-8787-fc9d6ebebdbf_da39a3_39077/host-10.pat", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-10.pat", + "bytes": 39, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawGeomHatch" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_2877eabe-7b66-4ba9-8787-fc9d6ebebdbf_da39a3_39077/host-10.pat", + "writeBits": 0 + }, + "archiveName": "host-10.pat", + "default": { + "baseName": "FCPAT.pat", + "bytes": 605, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawGeomHatch" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f2260a21f1ae5b2865b16dd6050e240b2192d74a359f0cdf6c50183cff7bf31c", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_2877eabe-7b66-4ba9-8787-fc9d6ebebdbf_da39a3_39077/FCPAT.pat", + "writeBits": 0 + }, + "group": "GeomHatch", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawGeomHatch", + "propertyName": "PatIncluded", + "recomputeResult": true, + "source": { + "bytes": 39, + "kind": "pat", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.pat", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98" + } + }, + { + "afterRecompute": { + "baseName": "host-11.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawHatch" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_fae135f3-4f44-456f-b681-8f803d6c0433_da39a3_39077/host-11.svg", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-11.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawHatch" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_fae135f3-4f44-456f-b681-8f803d6c0433_da39a3_39077/host-11.svg", + "writeBits": 0 + }, + "archiveName": "host-11.svg", + "default": { + "baseName": "simple.svg", + "bytes": 1931, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawHatch" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "68ff2efa1eb6e690ed59086ae6dc2c79b136fc1a06f251001aa9e7f680a08f6c", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_fae135f3-4f44-456f-b681-8f803d6c0433_da39a3_39077/simple.svg", + "writeBits": 0 + }, + "group": "Hatch", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawHatch", + "propertyName": "SvgIncluded", + "recomputeResult": true, + "source": { + "bytes": 88, + "kind": "svg", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + } + }, + { + "afterRecompute": { + "baseName": "host-12.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawSVGTemplate" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "27" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_b02731a6-5b3c-4df1-a1c1-4dbf2588f887_da39a3_39077/host-12.svg", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-12.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawSVGTemplate" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "27" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_b02731a6-5b3c-4df1-a1c1-4dbf2588f887_da39a3_39077/host-12.svg", + "writeBits": 0 + }, + "archiveName": "host-12.svg", + "default": { + "baseName": "", + "bytes": 0, + "editorMode": [], + "exists": false, + "mode": null, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawSVGTemplate" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "27" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": null, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": false, + "value": "", + "writeBits": null + }, + "group": "Template", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawSVGTemplate", + "propertyName": "PageResult", + "recomputeResult": false, + "source": { + "bytes": 88, + "kind": "svg", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + } + }, + { + "afterRecompute": { + "baseName": "host-13.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawTileWeld" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_00e72273-ad82-438b-bef1-b003df61efbe_da39a3_39077/host-13.svg", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-13.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawTileWeld" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_00e72273-ad82-438b-bef1-b003df61efbe_da39a3_39077/host-13.svg", + "writeBits": 0 + }, + "archiveName": "host-13.svg", + "default": { + "baseName": "blankTile.svg", + "bytes": 4532, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawTileWeld" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a702881fc09564250c3d6942b875db4921cc650f2bce925592323cecfc76fbdf", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_00e72273-ad82-438b-bef1-b003df61efbe_da39a3_39077/blankTile.svg", + "writeBits": 0 + }, + "group": "TileWeld", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawTileWeld", + "propertyName": "SymbolIncluded", + "recomputeResult": true, + "source": { + "bytes": 88, + "kind": "svg", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + } + }, + { + "afterRecompute": { + "baseName": "host-14.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawTileWeldPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_ed69f353-fffe-4a6f-9652-42c8c3502558_da39a3_39077/host-14.svg", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-14.svg", + "bytes": 88, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawTileWeldPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_ed69f353-fffe-4a6f-9652-42c8c3502558_da39a3_39077/host-14.svg", + "writeBits": 0 + }, + "archiveName": "host-14.svg", + "default": { + "baseName": "blankTile.svg", + "bytes": 4532, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawTileWeldPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "a702881fc09564250c3d6942b875db4921cc650f2bce925592323cecfc76fbdf", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_ed69f353-fffe-4a6f-9652-42c8c3502558_da39a3_39077/blankTile.svg", + "writeBits": 0 + }, + "group": "TileWeld", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawTileWeldPython", + "propertyName": "SymbolIncluded", + "recomputeResult": true, + "source": { + "bytes": 88, + "kind": "svg", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + } + }, + { + "afterRecompute": { + "baseName": "host-15.png", + "bytes": 68, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewImage" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_ea770e05-f7c6-4b54-933d-55f224bf0a6a_da39a3_39077/host-15.png", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-15.png", + "bytes": 68, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewImage" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_ea770e05-f7c6-4b54-933d-55f224bf0a6a_da39a3_39077/host-15.png", + "writeBits": 0 + }, + "archiveName": "host-15.png", + "default": { + "baseName": "", + "bytes": 0, + "editorMode": [], + "exists": false, + "mode": null, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewImage" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": null, + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": false, + "value": "", + "writeBits": null + }, + "group": "Image", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawViewImage", + "propertyName": "ImageIncluded", + "recomputeResult": true, + "source": { + "bytes": 68, + "kind": "png", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pixel.png", + "sha256": "431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460" + } + }, + { + "afterRecompute": { + "baseName": "host-16.pat", + "bytes": 39, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_91814af4-2fca-4fdb-9a6b-60eca6de2aeb_da39a3_39077/host-16.pat", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-16.pat", + "bytes": 39, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_91814af4-2fca-4fdb-9a6b-60eca6de2aeb_da39a3_39077/host-16.pat", + "writeBits": 0 + }, + "archiveName": "host-16.pat", + "default": { + "baseName": "FCPAT.pat", + "bytes": 605, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f2260a21f1ae5b2865b16dd6050e240b2192d74a359f0cdf6c50183cff7bf31c", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_91814af4-2fca-4fdb-9a6b-60eca6de2aeb_da39a3_39077/FCPAT.pat", + "writeBits": 0 + }, + "group": "Cut Surface Format", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawViewSection", + "propertyName": "PatIncluded", + "recomputeResult": true, + "source": { + "bytes": 39, + "kind": "pat", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.pat", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98" + } + }, + { + "afterRecompute": { + "baseName": "host-17.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_fc46cb8a-471f-4ec5-8443-ec4acd3fe0f2_da39a3_39077/host-17.svg", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-17.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_fc46cb8a-471f-4ec5-8443-ec4acd3fe0f2_da39a3_39077/host-17.svg", + "writeBits": 0 + }, + "archiveName": "host-17.svg", + "default": { + "baseName": "simple.svg", + "bytes": 1931, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSection" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "68ff2efa1eb6e690ed59086ae6dc2c79b136fc1a06f251001aa9e7f680a08f6c", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_fc46cb8a-471f-4ec5-8443-ec4acd3fe0f2_da39a3_39077/simple.svg", + "writeBits": 0 + }, + "group": "Cut Surface Format", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawViewSection", + "propertyName": "SvgIncluded", + "recomputeResult": true, + "source": { + "bytes": 88, + "kind": "svg", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + } + }, + { + "afterRecompute": { + "baseName": "host-18.pat", + "bytes": 39, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_d6b009be-3790-434f-a916-af181fce30ce_da39a3_39077/host-18.pat", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-18.pat", + "bytes": 39, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_d6b009be-3790-434f-a916-af181fce30ce_da39a3_39077/host-18.pat", + "writeBits": 0 + }, + "archiveName": "host-18.pat", + "default": { + "baseName": "FCPAT.pat", + "bytes": 605, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "f2260a21f1ae5b2865b16dd6050e240b2192d74a359f0cdf6c50183cff7bf31c", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_d6b009be-3790-434f-a916-af181fce30ce_da39a3_39077/FCPAT.pat", + "writeBits": 0 + }, + "group": "Cut Surface Format", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawViewSectionPython", + "propertyName": "PatIncluded", + "recomputeResult": true, + "source": { + "bytes": 39, + "kind": "pat", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.pat", + "sha256": "2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98" + } + }, + { + "afterRecompute": { + "baseName": "host-19.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4d701497-271c-44b4-8d6c-c4afea4d3e4f_da39a3_39077/host-19.svg", + "writeBits": 0 + }, + "afterSet": { + "baseName": "host-19.svg", + "bytes": 88, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4d701497-271c-44b4-8d6c-c4afea4d3e4f_da39a3_39077/host-19.svg", + "writeBits": 0 + }, + "archiveName": "host-19.svg", + "default": { + "baseName": "simple.svg", + "bytes": 1931, + "editorMode": [ + "ReadOnly" + ], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "HostProbe", + "typeId": "TechDraw::DrawViewSectionPython" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [ + "ReadOnly" + ], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "68ff2efa1eb6e690ed59086ae6dc2c79b136fc1a06f251001aa9e7f680a08f6c", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_4d701497-271c-44b4-8d6c-c4afea4d3e4f_da39a3_39077/simple.svg", + "writeBits": 0 + }, + "group": "Cut Surface Format", + "objectSetStable": true, + "objectTypeId": "TechDraw::DrawViewSectionPython", + "propertyName": "SvgIncluded", + "recomputeResult": true, + "source": { + "bytes": 88, + "kind": "svg", + "path": "/tmp/freecad-property-fileincluded-success-df9u3j7q/pattern.svg", + "sha256": "35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723" + } + } + ], + "propertyType": "App::PropertyFileIncluded", + "schemaVersion": 1, + "setterVariants": { + "collision": { + "distinctBytes": true, + "distinctPaths": true, + "first": { + "baseName": "collision.bin", + "bytes": 38, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "StringPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "BytesPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "TupleRename", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "OpenIoFile", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "Dictionary", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "EmptyNoOp", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "CollisionA", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "CollisionB", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e7688da5-dc13-44dd-b1d3-3a248623dbd8_da39a3_39077/collision.bin", + "writeBits": 0 + }, + "second": { + "baseName": "collision1.bin", + "bytes": 37, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "StringPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "BytesPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "TupleRename", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "OpenIoFile", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "Dictionary", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "EmptyNoOp", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "CollisionA", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "CollisionB", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Up-to-date" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "dd0647084670caf923ad0608de318b13f4266fcece1b93ba6b37fccbb7714d46", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Valid", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e7688da5-dc13-44dd-b1d3-3a248623dbd8_da39a3_39077/collision1.bin", + "writeBits": 0 + } + }, + "emptyString": { + "after": { + "baseName": "payload2.bin", + "bytes": 38, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "StringPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "BytesPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "TupleRename", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "OpenIoFile", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "Dictionary", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "EmptyNoOp", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e7688da5-dc13-44dd-b1d3-3a248623dbd8_da39a3_39077/payload2.bin", + "writeBits": 0 + }, + "before": { + "baseName": "payload2.bin", + "bytes": 38, + "editorMode": [], + "exists": true, + "mode": 256, + "objectSet": [ + { + "name": "StringPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "BytesPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "TupleRename", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "OpenIoFile", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "Dictionary", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "EmptyNoOp", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e7688da5-dc13-44dd-b1d3-3a248623dbd8_da39a3_39077/payload2.bin", + "writeBits": 0 + }, + "preserved": true + }, + "objectCount": 8, + "phases": [ + { + "baseName": "payload.bin", + "bytes": 38, + "editorMode": [], + "exists": true, + "expectedBaseName": "payload.bin", + "id": "StringPath", + "mode": 256, + "objectSet": [ + { + "name": "StringPath", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "sourcePath": "/tmp/freecad-property-fileincluded-success-df9u3j7q/payload.bin", + "sourceSha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e7688da5-dc13-44dd-b1d3-3a248623dbd8_da39a3_39077/payload.bin", + "writeBits": 0 + }, + { + "baseName": "payload-two.bin", + "bytes": 37, + "editorMode": [], + "exists": true, + "expectedBaseName": "payload-two.bin", + "id": "BytesPath", + "mode": 256, + "objectSet": [ + { + "name": "StringPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "BytesPath", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "dd0647084670caf923ad0608de318b13f4266fcece1b93ba6b37fccbb7714d46", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "sourcePath": "/tmp/freecad-property-fileincluded-success-df9u3j7q/payload-two.bin", + "sourceSha256": "dd0647084670caf923ad0608de318b13f4266fcece1b93ba6b37fccbb7714d46", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e7688da5-dc13-44dd-b1d3-3a248623dbd8_da39a3_39077/payload-two.bin", + "writeBits": 0 + }, + { + "baseName": "renamed.dat", + "bytes": 38, + "editorMode": [], + "exists": true, + "expectedBaseName": "renamed.dat", + "id": "TupleRename", + "mode": 256, + "objectSet": [ + { + "name": "StringPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "BytesPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "TupleRename", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "sourcePath": "/tmp/freecad-property-fileincluded-success-df9u3j7q/payload.bin", + "sourceSha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e7688da5-dc13-44dd-b1d3-3a248623dbd8_da39a3_39077/renamed.dat", + "writeBits": 0 + }, + { + "baseName": "payload-two1.bin", + "bytes": 37, + "editorMode": [], + "exists": true, + "expectedBaseName": "payload-two.bin", + "id": "OpenIoFile", + "mode": 256, + "objectSet": [ + { + "name": "StringPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "BytesPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "TupleRename", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "OpenIoFile", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "dd0647084670caf923ad0608de318b13f4266fcece1b93ba6b37fccbb7714d46", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "sourcePath": "/tmp/freecad-property-fileincluded-success-df9u3j7q/payload-two.bin", + "sourceSha256": "dd0647084670caf923ad0608de318b13f4266fcece1b93ba6b37fccbb7714d46", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e7688da5-dc13-44dd-b1d3-3a248623dbd8_da39a3_39077/payload-two1.bin", + "writeBits": 0 + }, + { + "baseName": "payload1.bin", + "bytes": 38, + "editorMode": [], + "exists": true, + "expectedBaseName": "payload.bin", + "id": "Dictionary", + "mode": 256, + "objectSet": [ + { + "name": "StringPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "BytesPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "TupleRename", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "OpenIoFile", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "Dictionary", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "sourcePath": "/tmp/freecad-property-fileincluded-success-df9u3j7q/payload.bin", + "sourceSha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e7688da5-dc13-44dd-b1d3-3a248623dbd8_da39a3_39077/payload1.bin", + "writeBits": 0 + }, + { + "baseName": "collision.bin", + "bytes": 38, + "editorMode": [], + "exists": true, + "expectedBaseName": "collision.bin", + "id": "CollisionA", + "mode": 256, + "objectSet": [ + { + "name": "StringPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "BytesPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "TupleRename", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "OpenIoFile", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "Dictionary", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "EmptyNoOp", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "CollisionA", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "sourcePath": "/tmp/freecad-property-fileincluded-success-df9u3j7q/payload.bin", + "sourceSha256": "537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e7688da5-dc13-44dd-b1d3-3a248623dbd8_da39a3_39077/collision.bin", + "writeBits": 0 + }, + { + "baseName": "collision1.bin", + "bytes": 37, + "editorMode": [], + "exists": true, + "expectedBaseName": "collision1.bin", + "id": "CollisionB", + "mode": 256, + "objectSet": [ + { + "name": "StringPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "BytesPath", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "TupleRename", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "OpenIoFile", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "Dictionary", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "EmptyNoOp", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "CollisionA", + "typeId": "App::DocumentObjectFileIncluded" + }, + { + "name": "CollisionB", + "typeId": "App::DocumentObjectFileIncluded" + } + ], + "objectState": [ + "Touched" + ], + "propertyStatus": [], + "propertyTypeId": "App::PropertyFileIncluded", + "sha256": "dd0647084670caf923ad0608de318b13f4266fcece1b93ba6b37fccbb7714d46", + "shape": { + "applicable": false, + "reason": "host-has-no-shape-property" + }, + "sourcePath": "/tmp/freecad-property-fileincluded-success-df9u3j7q/payload-two.bin", + "sourceSha256": "dd0647084670caf923ad0608de318b13f4266fcece1b93ba6b37fccbb7714d46", + "statusString": "Touched", + "underTransientDir": true, + "value": "/home/mes123456/.cache/FreeCAD/v1-1/Cache/FreeCAD_Doc_e7688da5-dc13-44dd-b1d3-3a248623dbd8_da39a3_39077/collision1.bin", + "writeBits": 0 + } + ], + "recomputeResult": true + }, + "status": "pass" +} diff --git a/config/freecad-web-exact-parity-plan.json b/config/freecad-web-exact-parity-plan.json index eac320b..573077c 100644 --- a/config/freecad-web-exact-parity-plan.json +++ b/config/freecad-web-exact-parity-plan.json @@ -41,7 +41,7 @@ "id": "EX03", "title": "Application document, property and recompute semantics", "tasks": [ - { "id": "EX-DOC-01", "title": "Implement every native property type, flag, editor and serialization rule", "priority": "P0", "status": "in_progress", "dependencies": ["EX-ORA-01"], "deliverables": ["Complete Property schema", "Status and editor metadata", "Binary and XML codecs"], "acceptance": ["Every runtime property fixture round-trips without type coercion or unknown loss"], "evidence": ["check:freecad-type-properties", "check:freecad-native-property-semantics", "check:freecad-property-status", "check:freecad-fcstd-roundtrip"], "exactBlockedBy": ["Of 85 runtime property types and 5510 records, 58 types/523 records remain opaque-only; all 15 observed status classes now have typed Facade behavior, including LockDynamic dynamic mutation and PartialTrigger partial-document observer transactions, but the remaining codecs, editors and complete document observer semantics are not closed"] }, + { "id": "EX-DOC-01", "title": "Implement every native property type, flag, editor and serialization rule", "priority": "P0", "status": "in_progress", "dependencies": ["EX-ORA-01"], "deliverables": ["Complete Property schema", "Status and editor metadata", "Binary and XML codecs"], "acceptance": ["Every runtime property fixture round-trips without type coercion or unknown loss"], "evidence": ["check:freecad-type-properties", "check:freecad-native-property-semantics", "check:freecad-property-status", "check:freecad-fcstd-roundtrip"], "exactBlockedBy": ["Of 85 runtime property types and 5510 records, 50 types/466 records remain opaque-only; all 15 observed status classes now have typed Facade behavior, including LockDynamic dynamic mutation and PartialTrigger partial-document observer transactions, but the remaining codecs, editors and complete document observer semantics are not closed"] }, { "id": "EX-DOC-02", "title": "Match transactions, DAG recompute, partial failure and document observers", "priority": "P0", "status": "in_progress", "dependencies": ["EX-DOC-01", "EX-TSN-04"], "deliverables": ["Transaction and observer event oracle", "Partial recompute scheduler", "Failure recovery contract"], "acceptance": ["Undo, redo, abort, stale and cyclic dependency behavior matches FreeCAD"], "evidence": ["check:document-closure", "test:facade"], "exactBlockedBy": ["Observer ordering and every partial-recompute branch are not yet oracle-backed"] }, { "id": "EX-DOC-03", "title": "Complete expressions, links, extensions, groups and App object lifecycle", "priority": "P0", "status": "in_progress", "dependencies": ["EX-DOC-01"], "deliverables": ["Expression dependency grammar", "Link and extension lifecycle", "Group and clone semantics"], "acceptance": ["Copy, clone, delete, relink and expression edits survive native round-trip"], "evidence": ["check:fcstd-closure", "check:chrome-production-document"], "exactBlockedBy": ["FeaturePython-backed extensions remain non-executable"] }, { "id": "EX-DOC-04", "title": "Complete multi-document, external link, merge and recovery workflows", "priority": "P1", "status": "pending", "dependencies": ["EX-DOC-02", "EX-DOC-03"], "deliverables": ["Cross-document Link corpus", "Merge and conflict semantics", "Crash and autosave recovery"], "acceptance": ["Open, close, relink, merge and recovery match the native document graph"], "evidence": ["check:chrome-persistence", "check:project-migration"], "exactBlockedBy": ["Current application is project-first and does not implement every desktop multi-document workflow"] }, @@ -63,7 +63,7 @@ "id": "EX05", "title": "FCStd and all import/export entrypoints", "tasks": [ - { "id": "EX-FC-01", "title": "Round-trip every native FCStd object, property, extension and resource", "priority": "P0", "status": "in_progress", "dependencies": ["EX-DOC-04", "EX-TSN-04"], "deliverables": ["Complete native archive model", "Unknown object preservation", "FreeCAD-Web-FreeCAD mutation corpus"], "acceptance": ["No supported object, property, GUI state or resource drifts after mutation and resave"], "evidence": ["check:freecad-native-property-semantics", "check:freecad-isomorphic-provenance", "check:fcstd-closure", "check:chrome-fcstd-roundtrip"], "exactBlockedBy": ["FCStd supports 23 native property codecs plus opaque preservation for 62 runtime types; exhaustive native mutation and resave remains open"] }, + { "id": "EX-FC-01", "title": "Round-trip every native FCStd object, property, extension and resource", "priority": "P0", "status": "in_progress", "dependencies": ["EX-DOC-04", "EX-TSN-04"], "deliverables": ["Complete native archive model", "Unknown object preservation", "FreeCAD-Web-FreeCAD mutation corpus"], "acceptance": ["No supported object, property, GUI state or resource drifts after mutation and resave"], "evidence": ["check:freecad-native-property-semantics", "check:freecad-isomorphic-provenance", "check:fcstd-closure", "check:chrome-fcstd-roundtrip"], "exactBlockedBy": ["FCStd supports 35 native property codecs plus opaque preservation for 50 runtime types; exhaustive native mutation and resave remains open"] }, { "id": "EX-FMT-01", "title": "Close BREP, STEP and IGES import/export semantics", "priority": "P0", "status": "in_progress", "dependencies": ["EX-KER-01"], "deliverables": ["Assembly/color/name import", "Unit and tolerance handling", "Deterministic exports"], "acceptance": ["Native and Web topology, metadata and diagnostics match for each format"] , "evidence": ["check:chrome-secondary-formats", "check:browser-occt"], "exactBlockedBy": ["Advanced STEP/IGES metadata and assembly cases are incomplete"] }, { "id": "EX-FMT-02", "title": "Close STL, OBJ, PLY, DXF, SVG and PDF round-trips", "priority": "P1", "status": "in_progress", "dependencies": ["EX-MESH-01", "EX-DRAFT-01", "EX-TD-01"], "deliverables": ["Mesh and 2D format codecs", "Style/layer metadata", "Import-export failure corpus"], "acceptance": ["All supported entities and metadata round-trip or fail with a registered difference"] , "evidence": ["check:chrome-secondary-formats", "check:document-closure"], "exactBlockedBy": ["Several formats remain read-only or omit advanced entity metadata"] }, { "id": "EX-FMT-03", "title": "Close IFC, CSV and G-code native object semantics", "priority": "P1", "status": "in_progress", "dependencies": ["EX-BIM-01", "EX-SS-01", "EX-CAM-01"], "deliverables": ["IFC schema and property sets", "Spreadsheet CSV dialect parity", "Path/G-code object round-trip"], "acceptance": ["Import, edit, export and native reopen preserve the declared object graph"] , "evidence": ["check:chrome-bim", "check:document-closure", "check:cam-parity"], "exactBlockedBy": ["IFC and G-code entrypoint inventory still records unsupported desktop semantics"] }, diff --git a/config/qa04-fcstd-fuzz-verification.json b/config/qa04-fcstd-fuzz-verification.json index d625bf1..59f89d1 100644 --- a/config/qa04-fcstd-fuzz-verification.json +++ b/config/qa04-fcstd-fuzz-verification.json @@ -24,7 +24,7 @@ "wrong-document-root": 77 }, "timing": { - "p95Ms": 0.131, - "maxMs": 2.695 + "p95Ms": 0.13, + "maxMs": 2.66 } } diff --git a/config/qa04-geometry-fuzz-verification.json b/config/qa04-geometry-fuzz-verification.json index dc83209..bc29e2d 100644 --- a/config/qa04-geometry-fuzz-verification.json +++ b/config/qa04-geometry-fuzz-verification.json @@ -41,7 +41,7 @@ "zero-revolution-axis": 67 }, "timing": { - "p95Ms": 0.025, - "maxMs": 1.112 + "p95Ms": 0.02, + "maxMs": 0.997 } } diff --git a/config/qa04-sketch-fuzz-verification.json b/config/qa04-sketch-fuzz-verification.json index e91cd7b..8784560 100644 --- a/config/qa04-sketch-fuzz-verification.json +++ b/config/qa04-sketch-fuzz-verification.json @@ -22,7 +22,7 @@ "invalid": 800 }, "timing": { - "p95Ms": 0.033, - "maxMs": 0.795 + "p95Ms": 0.03, + "maxMs": 0.659 } } diff --git a/config/release-artifacts.json b/config/release-artifacts.json index fc27064..4abca6e 100644 --- a/config/release-artifacts.json +++ b/config/release-artifacts.json @@ -23,14 +23,14 @@ "sha256": "1679307fb0f01e9d7b9f37a081458bf44583e4d1899edf9224b49a1435ce7105" }, { - "path": "assets/index-BnRqhr3m.css", - "bytes": 65976, - "sha256": "b8eacf86224d2705e3c27367b3a0b166f4d662a5b8142d34a8abcdeef58753ec" + "path": "assets/index-CNTlr1np.js", + "bytes": 1210736, + "sha256": "4d9e8b6e6e70a13d6a5c34a39eaa62a537de8cefde60d09125392b5a14512363" }, { - "path": "assets/index-BrkUKPvE.js", - "bytes": 1143618, - "sha256": "4324ab6351a3ef214762115d5b5ffc706883ccaf1e9b0f90577f912da1e4a223" + "path": "assets/index-CSuKYsCZ.css", + "bytes": 67322, + "sha256": "32d3157ecf81272245f0d8aa1a11887cefb8aa9502f966df90a83797519df208" }, { "path": "assets/nativeHistoryWorkerEntry-BEDB1h7o.js", @@ -335,7 +335,7 @@ { "path": "index.html", "bytes": 678, - "sha256": "e3cfab4e89c7bc19c51f2529bb2c6c84a61064168029a3bdfee2260a49a71097" + "sha256": "233c411801542bf802d4d701437c593620350c13fd1eec069c00d083b80a764d" }, { "path": "manifest.webmanifest", @@ -390,7 +390,7 @@ { "path": "sw.js", "bytes": 1390, - "sha256": "98ec667a774f8370ed654e457b86d4943b2f1eb89e228bd4e7e652b31a51b982" + "sha256": "041bc2f315a15f659a5471f382af087e61a8c4405fd8a725c068ddf898e7386e" }, { "path": "vendor/camotics/camotics-sweep.wasm", @@ -412,7 +412,7 @@ "status": "signed", "algorithm": "Ed25519", "keyId": "bitbybit-local-release-2026", - "payloadSha256": "5172b35d4d194483ac1934a1653259b1c7f5bb78c5ab4a68f7e5033cf2a22b86", - "signature": "FoaYFhliT+/njf8hXECKj5IoCeHPj1MnpbTBIw/FxzYpfyrgQ01nuPkwslM4okUk3d97cncjaXnEkDA7lZBtDw==" + "payloadSha256": "7cfc2e7f4b34be4c4b5deb75ace67753f9e219ef51b5be74f5a5c1d4f895f3cb", + "signature": "9fhwYyVCjTXXsQUvePx8I31qBp2FsW6b1YOW6UUtR2FDhrqwPtttqLrxSPcH6S88++u805jHATBE5cTijm4VBw==" } } diff --git a/docs/current-work.zh-CN.md b/docs/current-work.zh-CN.md index f86f20d..1e97a79 100644 --- a/docs/current-work.zh-CN.md +++ b/docs/current-work.zh-CN.md @@ -81,7 +81,7 @@ EX-DOC-01 -> EX-DOC-03 ---------^ ### P0-C:关闭 App 文档语义 -对应 `EX-DOC-01/02/03`。85 种运行时 Property、5510 条记录中,22 种/4304 条已有通用原生 codec,5 种/683 条已有专用 codec,仍有 58 种/523 条只能 opaque 保存。15 类已观察到的 Property status 均已进入类型化 Facade 行为;`LockDynamic` 的动态属性增删改事务和 `PartialTrigger` 的 partial-document observer 行为已有原生 oracle 与 Facade 测试。后续依次补齐剩余 Property codec/editor、完整 observer 顺序、局部重算失败、Extension 和 FeaturePython 边界。 +对应 `EX-DOC-01/02/03`。85 种运行时 Property、5510 条记录中,30 种/4361 条已有通用原生 codec,5 种/683 条已有专用 codec,仍有 50 种/466 条只能 opaque 保存。15 类已观察到的 Property status 均已进入类型化 Facade 行为;`LockDynamic` 的动态属性增删改事务和 `PartialTrigger` 的 partial-document observer 行为已有原生 oracle 与 Facade 测试。后续依次补齐剩余 Property codec/editor、完整 observer 顺序、局部重算失败、Extension 和 FeaturePython 边界。 ### P0-D:关闭核心建模语义 diff --git a/docs/freecad-active-work-status.generated.zh-CN.md b/docs/freecad-active-work-status.generated.zh-CN.md index 74bc6ae..9f1c8ef 100644 --- a/docs/freecad-active-work-status.generated.zh-CN.md +++ b/docs/freecad-active-work-status.generated.zh-CN.md @@ -3,10 +3,10 @@ 生成日期:2026-08-15。基线:FreeCAD 1.1.1 / `0108fd4b4850cc46e625b60e53cea7a7bbe69f8d`。 -- 唯一活动任务:`TSN-PAIR-chamfer-rotate` -- 微任务:1756 total / 339 completed / 1 in_progress / 1416 pending -- 有序操作对:213/361 classified / 148 unknown -- Property:27/85 native types / 58 opaque types +- 唯一活动任务:`PROP-app-propertyfont-A` +- 微任务:1756 total / 559 completed / 1 in_progress / 1196 pending +- 有序操作对:361/361 classified / 0 unknown +- Property:35/85 native types / 50 opaque types - exact 任务:5/52 completed - 模块能力:0 exact / 26 compatible / 5 proxy / 3 development @@ -15,8 +15,8 @@ | `ORA-GUI-BASELINE` | 106 | 106 | 0 | 0 | `-` | | `ORA-GUI-WORKFLOWS` | 7 | 7 | 0 | 0 | `-` | | `TSN-RECOVERY-DRIFT` | 13 | 13 | 0 | 0 | `-` | -| `TSN-ORDERED-PAIRS` | 361 | 213 | 1 | 147 | `TSN-PAIR-chamfer-rotate` | -| `PROPERTY-CODECS` | 522 | 0 | 0 | 522 | `-` | +| `TSN-ORDERED-PAIRS` | 361 | 361 | 0 | 0 | `-` | +| `PROPERTY-CODECS` | 522 | 72 | 1 | 449 | `PROP-app-propertyfont-A` | | `DOCUMENT-SEMANTICS` | 90 | 0 | 0 | 90 | `-` | | `CORE-MODELING` | 171 | 0 | 0 | 171 | `-` | | `FCSTD-AND-FORMATS` | 72 | 0 | 0 | 72 | `-` | diff --git a/docs/freecad-native-differential-execution-plan.zh-CN.md b/docs/freecad-native-differential-execution-plan.zh-CN.md new file mode 100644 index 0000000..a061200 --- /dev/null +++ b/docs/freecad-native-differential-execution-plan.zh-CN.md @@ -0,0 +1,451 @@ +# WEB FreeCAD 对真实 FreeCAD 差分实施计划 + +## 1. 文档职责 + +本文定义 WEB FreeCAD 如何通过真实执行逐项对标锁定版 FreeCAD,并把发现、复现、纠正、回归和能力提升拆成可执行的最小任务。本文不维护实时完成数或下一任务名称;动态状态只读取: + +1. `config/freecad-active-work-queue.json`:唯一 `nextTask`、依赖、状态和退出条件。 +2. `docs/freecad-active-work-status.generated.zh-CN.md`:同一生成器产生的状态摘要。 +3. `config/freecad-web-exact-parity-plan.json`:系统级 exact 任务和阻断项。 +4. `config/release-capability-matrix.json`:34 个模块可对外声明的能力等级。 +5. `config/*oracle*.json`、`config/*verification*.json`:真实执行证据。 + +若文档描述与机器报告冲突,以机器报告为准。界面相似、命令存在、OCCT 能生成相似 Shape、Node 单测通过,都不能单独证明与 FreeCAD 对标。 + +## 2. 对标目标和红线 + +目标基线固定为 FreeCAD `1.1.1`、Git 提交 `0108fd4b4850cc46e625b60e53cea7a7bbe69f8d`。WEB FreeCAD 必须在浏览器可实现范围内逐项匹配: + +- 命令可见性、启用条件、上下文和失败诊断。 +- 对象 TypeId、属性类型、默认值、状态位、editor 行为和生命周期。 +- Document 对象图、依赖 DAG、recompute、事务、observer、Undo/Redo 和失败恢复。 +- Shape 有效性、拓扑数量、质量属性、边界、公差、placement 和 builder 历史。 +- Generated/Modified/Deleted、ElementMap2、MappedNameRef、StringHasher 和 LinkSub 稳定性。 +- FCStd、BREP、STEP、IGES 及其他格式的读取、编辑、保存、重开和再次保存。 +- GUI Task、对话框、选择、预选、焦点、模型树、属性面板、状态栏和长任务。 +- Worker、WASM、OPFS、GPU、内存、取消、崩溃和资源释放。 + +以下行为一律禁止: + +- 用手工 JSON、Mock、截图或静态源码推断替代真实 FreeCAD 执行。 +- 用最终 Shape 相似掩盖中间 history、命名、事务或对象图差异。 +- FreeCAD 原生拒绝时,为了增加 WEB 支持数而偷偷接受。 +- 原生来源不唯一时按数组顺序、网格索引或最终拓扑位置伪造稳定名称。 +- 未知 Property、Extension、资源或脚本被静默丢弃、重写或标记可编辑。 +- UI 绕过 Facade 直接调用 OCCT、Three.js、OPFS、SQLite 或脚本执行器。 +- 放宽断言、删除 fixture 或改写报告来让 exact promotion 通过。 + +## 3. 真实执行环境 + +### 3.1 锁定产物 + +| 运行面 | 固定入口 | 用途 | 必须锁定 | +| --- | --- | --- | --- | +| Headless FreeCAD | `.cache/freecad/install-native/bin/FreeCADCmd` | Part/几何、黄金场景、错误和文件回放 | 版本、提交、二进制 SHA-256、Python 驱动 SHA-256 | +| Desktop FreeCAD CLI | `.cache/freecad/install-desktop/bin/FreeCADCmd` | 34 模块对象、Property、PartDesign、命名、FCStd | sysroot、模块加载、隔离配置、二进制 SHA-256 | +| Desktop FreeCAD GUI | `.cache/freecad/install-desktop/bin/FreeCAD` | 命令、Task、QAction、焦点、选择、视图和工作台 | `xvfb-run`/显示环境、用户配置、locale、DPI | +| Bitbybit OCCT | `@bitbybit-dev/occt` 1.1.1 | Web 几何兼容路径 | npm 版本、WASM SHA-256、API surface | +| 原生 history provider | `native/occt-history/dist/*` | builder history、命名 ABI 和三方差分 | JS/WASM/data 哈希、OCCT 版本、导出 ABI | +| Web 浏览器 | Playwright 锁定浏览器 | Worker、WASM、OPFS、UI、GPU 和交互 | 浏览器版本、viewport、deviceScaleFactor、特性开关 | + +### 3.2 环境隔离 + +每次原生执行必须: + +1. 使用任务专属临时目录和独立 FreeCAD user/system config。 +2. 固定 locale、时区、单位、线程和随机种子;无法固定的字段进入显式归一化清单。 +3. 禁止读取用户真实 FreeCAD 配置、最近文件、插件目录和自动恢复文件。 +4. GUI 探针在虚拟显示中运行,记录分辨率、DPI、主题、字体和窗口状态。 +5. 运行前记录二进制、harness、fixture 和输入资源 SHA-256。 +6. 运行后关闭文档、进程和 Worker,检查临时文件、Shape handle、WASM 引用和 OPFS lease。 + +### 3.3 基线验证命令 + +```bash +.cache/freecad/install-native/bin/FreeCADCmd --version +.cache/freecad/install-desktop/bin/FreeCADCmd --version +./npmw run check:baseline +./npmw run check:freecad-desktop-oracle +FREECAD_ORACLE_PROFILE=desktop xvfb-run -a ./npmw run probe:freecad-reference +./npmw run check:freecad-oracle-coverage +``` + +任一版本、提交或 artifact hash 不一致时,当前功能任务停止;先恢复基线,不允许生成新的对标结论。 + +## 4. 三层真实差分链 + +### 4.1 原生事实层 + +原生 FreeCAD 每个案例至少输出: + +- `baselineId/freecadVersion/gitCommit`。 +- harness、fixture、输入资源路径、字节数和 SHA-256。 +- 文档对象集、对象顺序、TypeId、Label、Visibility 和状态。 +- Property 名称、TypeId、值、status、editor mode、表达式和链接。 +- recompute 返回值、错误、状态字符串、事务和 observer 事件。 +- Shape null/valid、类型、Solid/Face/Edge/Vertex、体积、面积、边界和 BREP hash。 +- builder 输入、阶段、Generated/Modified/Deleted、命名和歧义。 +- save/reopen/resave 的三相快照。 + +### 4.2 WEB 实现层 + +相同案例必须通过生产 `BitBybitWebCadFacade` 进入,不直接调用 UI 内部对象。输出至少包含: + +- Facade command/request schema 与版本。 +- Document revision、transaction id、generation 和依赖重算结果。 +- Worker provider、WASM artifact、Shape handle 所有权和释放计数。 +- 与原生同结构的对象、Property、Shape、history、命名和诊断快照。 +- OPFS checkpoint、项目资源引用、FCStd/交换格式产物。 + +### 4.3 真实浏览器层 + +浏览器案例必须验证: + +- UI 命令状态与原生 QAction/command manager 状态一致。 +- Task 打开、预览、校验、Apply/OK/Cancel、焦点和选择轨迹一致。 +- Worker 真正加载 WASM,不能退回 mock provider。 +- save/reopen/resave 经过 OPFS 或声明的 fallback,不能只在内存中模拟。 +- 取消、崩溃、超时、stale response 不提交旧结果。 +- 完成后 Shape、Worker 请求、OPFS lease、GPU/Three 资源回到预期基线。 + +## 5. 比较合同 + +### 5.1 比较优先级 + +| 级别 | 比较域 | 必须一致的字段 | 允许差异的前提 | +| --- | --- | --- | --- | +| D0 | 基线 | 版本、提交、artifact、harness、fixture | 不允许 | +| D1 | 接受/拒绝 | 命令 enabled、builder success、失败阶段、诊断分类 | 仅文案本地化可归一化 | +| D2 | 文档 | 对象集、TypeId、依赖、Tip、Support、状态、事务 | 仅已登记浏览器代理对象 | +| D3 | Property | 类型、值、单位、约束、status、editor、表达式、link | 仅显式 opaque/read-only | +| D4 | 几何 | null/valid、Shape 类型、拓扑计数、质量属性、边界、公差 | 数值必须在场景声明公差内 | +| D5 | 历史命名 | stage、Generated/Modified/Deleted、provenance、LinkSub | 原生歧义必须保持歧义 | +| D6 | 持久化 | 对象/属性/资源、Shape、命名、GUI state | 未知资源只能字节保持或拒绝编辑 | +| D7 | GUI | visible/enabled、Task、焦点、选择、树、对话框、状态 | 浏览器保留键需显式映射 | +| D8 | 资源质量 | 时间预算、内存、取消、崩溃、释放、离线 | 只允许已登记平台差异 | + +### 5.2 数值和结构规则 + +1. 离散值、对象数、拓扑数、状态、枚举和错误分类必须精确一致。 +2. 长度、面积、体积、角度和矩阵按 fixture 声明公差比较;禁止使用全局无限放宽公差。 +3. BREP hash 只在序列化确定的同一阶段要求相等;若 FreeCAD 合法重序列化,必须同时比较结构摘要并登记原因。 +4. 属性和对象顺序只有原生语义明确要求时才比较顺序,否则按稳定 identity 比较。 +5. 错误文本保存原文,同时生成稳定 reason code;测试以 reason code 和关键原文片段双重锁定。 +6. 指针、UUID、临时路径、进程号等非确定字段只能由集中归一化器处理,禁止单个测试随意删除字段。 + +## 6. 差异分类与纠正协议 + +### 6.1 唯一分类 + +每个差异必须落入且只落入一种分类: + +| 分类 | 含义 | 动作 | +| --- | --- | --- | +| `web-implementation-defect` | FreeCAD 稳定,WEB 输出错误 | 同一任务内修复实现并补回归 | +| `web-missing-capability` | FreeCAD 接受,WEB 无实现 | 保持 pending/in_progress,按 A-I 补齐 | +| `web-over-acceptance` | FreeCAD 拒绝,WEB 接受 | 删除/封闭 fallback,匹配拒绝和回滚 | +| `web-over-rejection` | FreeCAD 接受,WEB 拒绝 | 修正输入映射、builder 或能力探测 | +| `native-allowed-evolution` | FreeCAD 自身编辑恢复后命名合法演进 | 保存原生复跑证据,WEB 不强制旧名称 | +| `native-ambiguous` | 原生来源不唯一 | WEB 保持 ambiguous/fail-closed | +| `platform-difference` | 浏览器安全/平台限制无法逐字相同 | 明确 compatible/proxy/excluded 和用户诊断 | +| `oracle-defect` | harness、fixture、归一化或基线错误 | 修复 oracle,旧结论失效并全部复跑 | +| `unknown` | 尚无充分证据 | 阻断任务和能力提升,不得关闭 | + +### 6.2 纠正步骤 + +1. 用同一锁定环境独立复跑至少两次,排除随机性和陈旧 artifact。 +2. 缩减为单一 TypeId、命令、Property 或 builder 阶段的最小 fixture。 +3. 保留完整原生输入、输出、诊断、对象集和资源,不只截取失败字段。 +4. 判断差异首次出现层:UI、Facade、Document、Worker、builder、命名、codec 或 persistence。 +5. 先添加会失败的 focused checker,再修改生产实现。 +6. 修复不得改变无关场景、放宽公差、删除原生拒绝或引入通用 Shape fallback。 +7. 重跑名义、失败、边界、变异恢复、事务、往返和浏览器案例。 +8. 将差异分类、根因、修复文件、回归命令和 residual risk 写入证据账本。 +9. 所有退出条件通过后才生成队列;生成器必须只推进一个任务。 + +## 7. 单能力 20 步微任务模板 + +每个命令、对象类型、Property codec、格式分支、GUI 状态或有序操作对依次拆为: + +| 步骤 | 微任务 | 单一交付物 | 退出条件 | +| --- | --- | --- | --- | +| T01 | 定位源码 | 模块、TypeId/command、C++/Python 路径 | 来源和版本可追溯 | +| T02 | 锁定输入 | 参数、单位、对象图、选择和资源 | fixture 可重复解析 | +| T03 | 锁定适用性 | enabled/disabled 和前置条件 | 三种基本上下文均有事实 | +| T04 | 原生名义执行 | 成功快照 | 二次执行一致 | +| T05 | 原生边界执行 | 最小/最大/空/多项/单位边界 | 每项有接受或拒绝 | +| T06 | 原生失败执行 | 无效输入和精确诊断 | Shape/对象污染已记录 | +| T07 | 原生取消执行 | preview/cancel/abort | 文档和事务恢复 | +| T08 | 原生参数编辑 | before/edit/restore | 变化和恢复可分类 | +| T09 | 原生历史命名 | stages/history/naming | 无缺失 builder 证据 | +| T10 | 原生持久化 | save/reopen/resave | 三相无未知漂移 | +| T11 | WEB 合同 | Facade request/result/error schema | UI 无内核旁路 | +| T12 | WEB 实现 | production provider | 无 mock/隐藏 fallback | +| T13 | WEB 失败与取消 | structured error/cancel | stale result 不提交 | +| T14 | WEB 事务 | commit/abort/undo/redo | revision 和对象图正确 | +| T15 | WEB 命名 | TopoRef/ElementMap2/LinkSub | 唯一来源稳定,歧义封闭 | +| T16 | WEB 持久化 | Web save/reopen/resave | codec/资源无静默丢失 | +| T17 | 三方差分 | FreeCAD/Bitbybit/native provider 报告 | unknown difference 为零 | +| T18 | 浏览器回放 | Worker/OPFS/UI 证据 | 真实浏览器且资源归零 | +| T19 | 缺陷纠正 | 根因、修复、focused regression | 所有已知差异关闭或分类 | +| T20 | 能力提升 | gate、blocker、matrix、队列同步 | 只推进直接后继 | + +如果某项不适用,必须保存机器可验证的 `not-applicable` 原因;不能跳过后只在文档中声称完成。 + +## 8. 阶段和细粒度里程碑 + +### M00 基线与治理 + +- M00.01 验证 FreeCAD headless 版本/提交/hash。 +- M00.02 验证 FreeCAD desktop 版本/提交/hash。 +- M00.03 验证 sysroot、Python 模块和动态库闭包。 +- M00.04 验证 Bitbybit 和原生 history WASM/hash/ABI。 +- M00.05 验证浏览器版本、Playwright、GPU 和 OPFS 能力。 +- M00.06 验证隔离配置、locale、单位、字体和虚拟显示。 +- M00.07 验证队列恰好一个 `in_progress`。 +- M00.08 验证 exact claim 保持 fail-closed。 + +退出条件:任一执行机器都能复现同一基线;所有报告携带来源和 hash。 + +### M01 原生清册与 GUI oracle + +- M01.01 34 模块构建/导入状态。 +- M01.02 运行时 TypeId 全集和不可实例化原因。 +- M01.03 每 TypeId 的 Property、默认值、status、editor。 +- M01.04 命令注册全集、source-only 和 context-only 分类。 +- M01.05 空文档、活动文档、单选、多选三态命令矩阵。 +- M01.06 每命令族 success/disabled/failure/cancel/recovery。 +- M01.07 Task、QAction、焦点、选择和对象集快照。 +- M01.08 分片合并、重复/遗漏检测和 artifact hash。 + +退出条件:清册候选全部有运行时事实或显式排除;未知命令状态为零。 + +### M02 稳定拓扑、history 与有序操作对 + +- M02.01 每个生产 builder 的输入、阶段 Shape 和 history。 +- M02.02 final-shape-only 和缺失 builder 证据 fail-closed。 +- M02.03 MappedNameRef/StringHasher 来源和 ABI。 +- M02.04 同构拓扑唯一/多来源分类。 +- M02.05 参数编辑恢复的 geometry/relation/name 三相摘要。 +- M02.06 生产链恢复拓扑和命名演进分类。 +- M02.07 19×19 有序操作对逐对原生执行。 +- M02.08 接受对的真实 builder、变异、命名和 FCStd。 +- M02.09 拒绝/no-op 对的诊断、事务回滚和干净 FCStd。 +- M02.10 长链 LinkSub 保存、重开、再次保存。 + +退出条件:所有注册转换均已分类;wrong binding、unexplained relation 和 round-trip name drift 为零。 + +### M03 Property codec 与状态语义 + +- M03.01 通用标量和枚举。 +- M03.02 长度、角度、面积、体积和单位。 +- M03.03 Vector、Matrix、Placement、Color 和材料。 +- M03.04 String/List/Map/ExpressionEngine。 +- M03.05 Link、LinkSub、LinkList、LinkSubList 和 XLink。 +- M03.06 Shape、Mesh、Geometry、Constraint 和复杂专用类型。 +- M03.07 Extension/FeaturePython/动态 Property。 +- M03.08 opaque 类型逐个 native codec 或只读保留。 +- M03.09 status/editor/readonly/hidden/transient 行为。 +- M03.10 每 codec 的 mutation 和 FCStd 往返。 + +退出条件:运行时 Property 清册无未分类 opaque;未知值不会被 WEB 改写。 + +### M04 Document、DAG、事务与 observer + +- M04.01 create/delete/rename/copy/clone。 +- M04.02 add/remove/change Property。 +- M04.03 dependency DAG、拓扑排序和 cycle。 +- M04.04 dirty/touched/recompute scope。 +- M04.05 partial recompute 和失败传播。 +- M04.06 transaction commit/abort/nested/merge。 +- M04.07 undo/redo 和失败后的最后有效状态。 +- M04.08 observer 事件顺序和 payload。 +- M04.09 multi-document、cross-document link、MDI。 +- M04.10 Extension、FeaturePython、proxy 和 unknown object。 + +退出条件:事件、对象图和 revision 与原生一致;失败和取消无污染。 + +### M05 Kernel、Sketcher、Part 和 PartDesign + +- M05.01 OCCT 原语、曲线、曲面和 topology inspection。 +- M05.02 Boolean、section、split、refine、heal 和 tolerance。 +- M05.03 Sketcher 几何、约束、DOF、冗余和冲突。 +- M05.04 Sketcher 编辑、drag、external geometry 和 solver recovery。 +- M05.05 Part primitive/builder/boolean/modification。 +- M05.06 Body、Tip、Group、Support 和 attachment。 +- M05.07 Pad/Pocket/Revolution/Groove。 +- M05.08 Loft/Pipe/additive/subtractive 组合。 +- M05.09 Fillet/Chamfer/Hole/Draft/Thickness。 +- M05.10 Pattern/Mirrored/MultiTransform 和跨 Body/XLink。 + +退出条件:每个 feature 的 T01-T20 完成;失败诊断、事务、history、naming 和 FCStd 全部对齐。 + +### M06 FCStd 与交换格式 + +- M06.01 Document.xml/GuiDocument.xml/schema/version。 +- M06.02 Property codec 和 unknown XML 保留。 +- M06.03 BRep、ElementMap、StringHasher 和资源 identity。 +- M06.04 Embedded files、scripts、thumbnails 和 extensions。 +- M06.05 FreeCAD→Web→FreeCAD 变异链。 +- M06.06 Web→FreeCAD→Web 变异链。 +- M06.07 BREP/STEP/IGES 单位、颜色、名称、层和装配。 +- M06.08 STL/OBJ/PLY/DXF/SVG/PDF。 +- M06.09 IFC/CSV/G-code/JT/IDF/OpenSCAD 边界。 +- M06.10 损坏、超限、取消、路径穿越和压缩炸弹。 + +退出条件:支持项双向无未知语义漂移;不支持项无损代理或明确拒绝。 + +### M07 GUI 与工作台闭合 + +- M07.01 Shell、菜单、工具栏和 Workbench 切换。 +- M07.02 MDI、模型树、Combo View、Dock 和布局保存。 +- M07.03 Task panel 和属性 editor 生命周期。 +- M07.04 对话框 validation/apply/accept/reject。 +- M07.05 3D selection/preselection/context menu。 +- M07.06 keyboard、focus、shortcut conflict 和 clipboard。 +- M07.07 status/report/jobs/progress/cancel。 +- M07.08 desktop/tablet/mobile 响应式和触控。 +- M07.09 screenshot、accessibility tree 和 locale。 +- M07.10 每工作台端到端 success/failure/cancel/recovery。 + +退出条件:命令状态、对象结果、事务和交互轨迹对齐;无重叠、溢出或无名控件。 + +### M08 文档与工程工作台 + +按 Draft、Spreadsheet、TechDraw、Plot、Assembly、BIM、Surface、Mesh/MeshPart、Material 顺序,每个工作台分别完成:清册、创建、编辑、失败、引用、事务、格式、GUI、浏览器和跨工作台十个微里程碑。 + +退出条件:每个对象和命令有 T01-T20;跨工作台引用和导出无未知差异。 + +### M09 分析、制造、数据和扩展 + +按 FEM、CAM、Robot、Inspection/Measure、Points/ReverseEngineering、Python/Macro、Addon、Cloud/Help/IDF/JT/OpenSCAD 顺序执行。每个外部求解器或 sidecar 还必须锁定版本、许可证、输入输出、超时、取消、资源限制和生产授权边界。 + +退出条件:可执行能力有真实差分;不可浏览器实现的能力被正式标为 proxy/excluded,不冒充 exact。 + +### M10 平台、可靠性和发布 + +- M10.01 Chrome/Firefox/WebKit。 +- M10.02 Linux/Windows/macOS。 +- M10.03 GPU/软件渲染和驱动矩阵。 +- M10.04 locale/单位/时区/输入法。 +- M10.05 keyboard/screen reader/zoom/high contrast。 +- M10.06 fuzz/stress/百万级拓扑或求解重放。 +- M10.07 长会话、内存、GPU、Worker 和 OPFS 泄漏。 +- M10.08 crash、checkpoint、migration、rollback 和 offline。 +- M10.09 SBOM、依赖、许可证、安全和签名。 +- M10.10 52/52 exact、34/34 exact 和零差异 promotion。 + +退出条件:所有支持平台无未知语义差异;签名产物可重建、验签和回滚。 + +## 9. 每轮执行步骤 + +```text +1. 读取 config/freecad-active-work-queue.json.nextTask。 +2. 核对该任务 dependencies、输入报告和 artifact hash。 +3. 创建最小 fixture;不得顺手扩大到第二个队列项。 +4. 运行锁定 FreeCAD 原生成功/失败/变异/持久化探针。 +5. 运行 Bitbybit/原生 provider/Facade 的同输入回放。 +6. 运行真实浏览器 Worker/OPFS/UI 回放(任务要求时)。 +7. 逐字段比较 D0-D8,产生差异列表。 +8. 对每项差异执行唯一分类;unknown 阻断任务。 +9. 对 WEB 缺陷先补失败检查器,再修生产代码。 +10. 重跑 focused probe、focused check 和相关回归。 +11. 确认事务、文档、Shape、Worker、OPFS 和 GPU 资源恢复。 +12. 更新 oracle/verification/分类账本和后续工作完成证据。 +13. 重新生成 active queue 和状态页,只允许推进一项。 +14. 运行 execution-plan、JSON、git diff 和风险相称的回归。 +15. 发布点运行完整 verify、构建、SBOM、签名和验签。 +16. 提交、推送,随后再从机器队列读取新的 nextTask。 +``` + +## 10. 常用真实执行命令 + +```bash +# 原生清册和桌面 GUI +FREECAD_ORACLE_PROFILE=desktop xvfb-run -a ./npmw run probe:freecad-reference +./npmw run probe:freecad-gui-command-shards +./npmw run check:freecad-desktop-oracle +./npmw run check:freecad-oracle-coverage + +# 三方几何、历史和命名 +./npmw run test:freecad:threeway +./npmw run check:freecad:threeway +./npmw run probe:freecad-ordered-operation-pairs +./npmw run check:freecad-ordered-operation-pairs +./npmw run check:freecad-tsn-stage-correlation + +# FCStd 和真实浏览器 +./npmw run test:freecad-fcstd-native +./npmw run check:freecad-fcstd-roundtrip +./npmw run ci:real:chrome +./npmw run ci:check:chrome + +# 队列和发布门禁 +./npmw run generate:freecad-active-work-queue +./npmw run check:freecad-active-work-queue +./npmw run check:execution-plan +./npmw run verify +git diff --check +``` + +具体任务优先使用队列条目指定的 focused 命令,不应每次先运行整个 suite。完整 `verify` 用于发布点或高风险共享合同变更。 + +## 11. 证据文件最低结构 + +```json +{ + "schemaVersion": 1, + "baseline": { + "freecadVersion": "1.1.1", + "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", + "runtime": "desktop|headless|browser", + "artifacts": [] + }, + "case": { + "id": "machine-generated-id", + "inputs": {}, + "preconditions": [], + "phases": {} + }, + "comparison": { + "dimensions": [], + "knownDifferences": [], + "unknownDifferences": [] + }, + "resources": {}, + "decision": "accepted|rejected|no-op|compatible|proxy|blocked", + "status": "pass|fail" +} +``` + +报告生成器必须写入 harness hash;checker 必须重算 hash、验证连续前缀并在 unknown difference 非空时失败。 + +## 12. 里程碑验收与汇报 + +每个微里程碑关闭时记录:范围、真实 FreeCAD 命令、输入、原生结论、WEB 结论、差异分类、修复、focused check、浏览器证据、持久化证据、资源释放和剩余风险。 + +阶段里程碑只能在所有子项自然变为 completed 后关闭。系统级“完全对标 FreeCAD”只能在以下条件同时满足时声明: + +- exact 计划全部完成。 +- 34 个模块全部达到 exact 或从最终声明中正式排除。 +- 所有命令、对象、Property、格式和入口无未知项。 +- wrong binding、unexplained relation、round-trip name drift、unknown semantic difference 和 release blocker 均为零。 +- 跨浏览器/OS/GPU、无障碍、locale、长稳、安全和迁移门禁通过。 +- 发布物、SBOM 和能力矩阵签名可验证。 + +在此之前,项目只能按机器能力矩阵声明 exact、compatible、proxy、development 或 excluded 的实际范围。 + +## 13. 首次按本文执行发现并纠正的 oracle 差异 + +本计划落地时立即执行真实基线审计,发现旧 `.cache/freecad/reference-desktop.json` 缺少 `determinism.normalizedProcessFields`,`check:freecad-desktop-oracle` 因此正确失败。重新运行完整 desktop probe 后又在 `BIMWorkbench` 激活阶段触发默认 300 秒超时;同一 BIM workbench 的 registration-only 原生探针可正常完成,证明不是二进制或模块缺失。 + +根因位于 `scripts/freecad-reference-probe.py`:隔离配置只在 `gui-commands` scope 设置 `BIM.FirstTime=false`,但 `full` scope 同样会激活 BIM;报告又仅根据“使用隔离配置”声称首启已抑制,没有读取真实参数。纠正后: + +1. 所有隔离 GUI probe 在激活任一 workbench 前设置 BIM `FirstTime=false`。 +2. 立即读回参数,只有真实值为 false 才报告 `suppressed-before-workbench-activation`。 +3. 完整 desktop probe 重新执行并通过,未再发生 BIM 首启超时。 +4. 锁定 FreeCAD 1.1.1、34 模块、352 个运行时 TypeId 候选、348 个可实例化对象、4 个明确不可实例化对象和 5510 条 Property 记录。 +5. `check:freecad-desktop-oracle`、`check:freecad-oracle-coverage`、`check:freecad-gui-commands` 和 26 场景 `check:freecad:threeway` 全部通过。 +6. 由 desktop report 派生的 Property 语义报告因来源 hash 变化而 fail-closed,已重新真实生成;85 种 Property/5510 条记录中 4987 条由原生 codec 表示,523 条继续保持 opaque proxy,未被误报 exact。 + +该修复只纠正 oracle 的真实执行隔离和证据可信度,不提升任何 WEB 模块的 exact 等级。 diff --git a/docs/freecad-web-execution-master-plan.zh-CN.md b/docs/freecad-web-execution-master-plan.zh-CN.md index 998a5ee..b9e4c83 100644 --- a/docs/freecad-web-execution-master-plan.zh-CN.md +++ b/docs/freecad-web-execution-master-plan.zh-CN.md @@ -46,7 +46,7 @@ ### 2.3 已量化但尚未关闭的 P0 阻断 - 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 条记录中,30 种/4361 条为通用原生 codec,5 种/683 条为专用 codec,50 种/466 条仍为 opaque proxy。 - Property status:15 类已观察状态均已进入类型化 Facade 行为;`LockDynamic` 和 `PartialTrigger` 已有原生事务证据,但完整 observer 与局部重算序列未关闭。 - TSN:30/30 原生 mutation、219/219 几何阶段恢复通过;11 个 PartDesign case/28 个恢复命名阶段均已通过第二次独立原生复跑分类为允许演进。 - 生产命名链:五阶段 5/5 几何恢复,2 个恢复拓扑 case/5 个下游阶段已分类为允许演进;仍有 3/5 通用 Shape 代理并缺注册 rotate mutation family。 diff --git a/package.json b/package.json index 5b6d4b8..72189dc 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,136 @@ "check:freecad-inventory": "node scripts/check-freecad-source-inventory.mjs", "generate:freecad-type-properties": "node scripts/generate-freecad-type-property-inventory.mjs", "check:freecad-type-properties": "node scripts/check-freecad-type-property-inventory.mjs", - "probe:freecad-native-property-semantics": "node scripts/run-freecad-native-property-semantics.mjs", - "check:freecad-native-property-semantics": "node scripts/check-freecad-native-property-semantics.mjs && node scripts/check-freecad-property-status-oracle.mjs", + "probe:freecad-native-property-semantics": "node scripts/run-freecad-native-property-semantics.mjs", + "generate:freecad-property-acceleration-inventory": "node scripts/generate-freecad-property-acceleration-inventory.mjs", + "check:freecad-property-acceleration-inventory": "node scripts/check-freecad-property-acceleration-inventory.mjs", + "probe:freecad-property-acceleration-success": "node scripts/run-freecad-property-acceleration-success.mjs", + "check:freecad-property-acceleration-success": "node scripts/check-freecad-property-acceleration-success.mjs", + "probe:freecad-property-acceleration-failure": "node scripts/run-freecad-property-acceleration-failure.mjs", + "check:freecad-property-acceleration-failure": "node scripts/check-freecad-property-acceleration-failure.mjs", + "probe:freecad-property-acceleration-mutation": "node scripts/run-freecad-property-acceleration-mutation.mjs", + "check:freecad-property-acceleration-mutation": "node scripts/check-freecad-property-acceleration-mutation.mjs", + "test:freecad-property-acceleration-facade": "tsx --test tests/propertyAccelerationFacade.test.ts", + "test:freecad-property-acceleration-transaction": "tsx --test tests/propertyAccelerationTransaction.test.ts", + "probe:freecad-property-acceleration-roundtrip": "tsx scripts/run-freecad-property-acceleration-roundtrip.ts", + "check:freecad-property-acceleration-roundtrip": "node scripts/check-freecad-property-acceleration-roundtrip.mjs", + "test:chrome-property-acceleration": "node scripts/run-chrome-property-acceleration.mjs", + "check:chrome-property-acceleration": "node scripts/check-chrome-property-acceleration.mjs", + "test:chrome-property-area": "node scripts/run-chrome-property-area.mjs", + "check:chrome-property-area": "node scripts/check-chrome-property-area.mjs", + "generate:freecad-property-area-promotion": "node scripts/generate-freecad-property-area-promotion.mjs", + "check:freecad-property-area-promotion": "node scripts/check-freecad-property-area-promotion.mjs", + "generate:freecad-property-boollist-inventory": "node scripts/generate-freecad-property-boollist-inventory.mjs", + "check:freecad-property-boollist-inventory": "node scripts/check-freecad-property-boollist-inventory.mjs", + "probe:freecad-property-boollist-success": "node scripts/run-freecad-property-boollist-success.mjs", + "check:freecad-property-boollist-success": "node scripts/check-freecad-property-boollist-success.mjs", + "probe:freecad-property-boollist-failure": "node scripts/run-freecad-property-boollist-failure.mjs", + "check:freecad-property-boollist-failure": "node scripts/check-freecad-property-boollist-failure.mjs", + "probe:freecad-property-boollist-mutation": "node scripts/run-freecad-property-boollist-mutation.mjs", + "check:freecad-property-boollist-mutation": "node scripts/check-freecad-property-boollist-mutation.mjs", + "test:freecad-property-boollist-facade": "tsx --test tests/propertyBoolListFacade.test.ts", + "test:freecad-property-boollist-transaction": "tsx --test tests/propertyBoolListTransaction.test.ts", + "probe:freecad-property-boollist-roundtrip": "tsx scripts/run-freecad-property-boollist-roundtrip.ts", + "check:freecad-property-boollist-roundtrip": "node scripts/check-freecad-property-boollist-roundtrip.mjs", + "test:chrome-property-boollist": "node scripts/run-chrome-property-boollist.mjs", + "check:chrome-property-boollist": "node scripts/check-chrome-property-boollist.mjs", + "generate:freecad-property-boollist-promotion": "node scripts/generate-freecad-property-boollist-promotion.mjs", + "check:freecad-property-boollist-promotion": "node scripts/check-freecad-property-boollist-promotion.mjs", + "generate:freecad-property-color-inventory": "node scripts/generate-freecad-property-color-inventory.mjs", + "check:freecad-property-color-inventory": "node scripts/check-freecad-property-color-inventory.mjs", + "probe:freecad-property-color-success": "node scripts/run-freecad-property-color-success.mjs", + "check:freecad-property-color-success": "node scripts/check-freecad-property-color-success.mjs", + "probe:freecad-property-color-failure": "node scripts/run-freecad-property-color-failure.mjs", + "check:freecad-property-color-failure": "node scripts/check-freecad-property-color-failure.mjs", + "probe:freecad-property-color-mutation": "node scripts/run-freecad-property-color-mutation.mjs", + "check:freecad-property-color-mutation": "node scripts/check-freecad-property-color-mutation.mjs", + "test:freecad-property-color-facade": "tsx --test tests/propertyColorFacade.test.ts", + "test:freecad-property-color-transaction": "tsx --test tests/propertyColorTransaction.test.ts", + "probe:freecad-property-color-roundtrip": "tsx scripts/run-freecad-property-color-roundtrip.ts", + "check:freecad-property-color-roundtrip": "node scripts/check-freecad-property-color-roundtrip.mjs", + "test:chrome-property-color": "node scripts/run-chrome-property-color.mjs", + "check:chrome-property-color": "node scripts/check-chrome-property-color.mjs", + "generate:freecad-property-color-promotion": "node scripts/generate-freecad-property-color-promotion.mjs", + "check:freecad-property-color-promotion": "node scripts/check-freecad-property-color-promotion.mjs", + "generate:freecad-property-colorlist-inventory": "node scripts/generate-freecad-property-colorlist-inventory.mjs", + "check:freecad-property-colorlist-inventory": "node scripts/check-freecad-property-colorlist-inventory.mjs", + "probe:freecad-property-colorlist-success": "node scripts/run-freecad-property-colorlist-success.mjs", + "check:freecad-property-colorlist-success": "node scripts/check-freecad-property-colorlist-success.mjs", + "probe:freecad-property-colorlist-failure": "node scripts/run-freecad-property-colorlist-failure.mjs", + "check:freecad-property-colorlist-failure": "node scripts/check-freecad-property-colorlist-failure.mjs", + "probe:freecad-property-colorlist-mutation": "node scripts/run-freecad-property-colorlist-mutation.mjs", + "check:freecad-property-colorlist-mutation": "node scripts/check-freecad-property-colorlist-mutation.mjs", + "test:freecad-property-colorlist-facade": "tsx --test tests/propertyColorListFacade.test.ts", + "test:freecad-property-colorlist-transaction": "tsx --test tests/propertyColorListTransaction.test.ts", + "probe:freecad-property-colorlist-roundtrip": "tsx scripts/run-freecad-property-colorlist-roundtrip.ts", + "check:freecad-property-colorlist-roundtrip": "node scripts/check-freecad-property-colorlist-roundtrip.mjs", + "test:chrome-property-colorlist": "node scripts/run-chrome-property-colorlist.mjs", + "check:chrome-property-colorlist": "node scripts/check-chrome-property-colorlist.mjs", + "generate:freecad-property-colorlist-promotion": "node scripts/generate-freecad-property-colorlist-promotion.mjs", + "check:freecad-property-colorlist-promotion": "node scripts/check-freecad-property-colorlist-promotion.mjs", + "generate:freecad-property-direction-inventory": "node scripts/generate-freecad-property-direction-inventory.mjs", + "check:freecad-property-direction-inventory": "node scripts/check-freecad-property-direction-inventory.mjs", + "probe:freecad-property-direction-success": "node scripts/run-freecad-property-direction-success.mjs", + "check:freecad-property-direction-success": "node scripts/check-freecad-property-direction-success.mjs", + "probe:freecad-property-direction-failure": "node scripts/run-freecad-property-direction-failure.mjs", + "check:freecad-property-direction-failure": "node scripts/check-freecad-property-direction-failure.mjs", + "probe:freecad-property-direction-mutation": "node scripts/run-freecad-property-direction-mutation.mjs", + "check:freecad-property-direction-mutation": "node scripts/check-freecad-property-direction-mutation.mjs", + "test:freecad-property-direction-facade": "tsx --test tests/propertyDirectionFacade.test.ts", + "test:freecad-property-direction-transaction": "tsx --test tests/propertyDirectionTransaction.test.ts", + "probe:freecad-property-direction-roundtrip": "tsx scripts/run-freecad-property-direction-roundtrip.ts", + "check:freecad-property-direction-roundtrip": "node scripts/check-freecad-property-direction-roundtrip.mjs", + "test:chrome-property-direction": "node scripts/run-chrome-property-direction.mjs", + "check:chrome-property-direction": "node scripts/check-chrome-property-direction.mjs", + "generate:freecad-property-direction-promotion": "node scripts/generate-freecad-property-direction-promotion.mjs", + "check:freecad-property-direction-promotion": "node scripts/check-freecad-property-direction-promotion.mjs", + "generate:freecad-property-file-inventory": "node scripts/generate-freecad-property-file-inventory.mjs", + "check:freecad-property-file-inventory": "node scripts/check-freecad-property-file-inventory.mjs", + "generate:freecad-property-fileincluded-inventory": "node scripts/generate-freecad-property-fileincluded-inventory.mjs", + "check:freecad-property-fileincluded-inventory": "node scripts/check-freecad-property-fileincluded-inventory.mjs", + "probe:freecad-property-fileincluded-success": "node scripts/run-freecad-property-fileincluded-success.mjs", + "check:freecad-property-fileincluded-success": "node scripts/check-freecad-property-fileincluded-success.mjs", + "probe:freecad-property-fileincluded-failure": "node scripts/run-freecad-property-fileincluded-failure.mjs", + "check:freecad-property-fileincluded-failure": "node scripts/check-freecad-property-fileincluded-failure.mjs", + "probe:freecad-property-fileincluded-mutation": "node scripts/run-freecad-property-fileincluded-mutation.mjs", + "check:freecad-property-fileincluded-mutation": "node scripts/check-freecad-property-fileincluded-mutation.mjs", + "test:freecad-property-fileincluded-facade": "tsx --test tests/propertyFileIncludedFacade.test.ts", + "test:freecad-property-fileincluded-transaction": "tsx --test tests/propertyFileIncludedTransaction.test.ts", + "probe:freecad-property-fileincluded-roundtrip": "tsx scripts/run-freecad-property-fileincluded-roundtrip.ts", + "check:freecad-property-fileincluded-roundtrip": "node scripts/check-freecad-property-fileincluded-roundtrip.mjs", + "test:chrome-property-fileincluded": "node scripts/run-chrome-property-fileincluded.mjs", + "check:chrome-property-fileincluded": "node scripts/check-chrome-property-fileincluded.mjs", + "generate:freecad-property-fileincluded-promotion": "node scripts/generate-freecad-property-fileincluded-promotion.mjs", + "check:freecad-property-fileincluded-promotion": "node scripts/check-freecad-property-fileincluded-promotion.mjs", + "probe:freecad-property-file-success": "node scripts/run-freecad-property-file-success.mjs", + "check:freecad-property-file-success": "node scripts/check-freecad-property-file-success.mjs", + "probe:freecad-property-file-failure": "node scripts/run-freecad-property-file-failure.mjs", + "check:freecad-property-file-failure": "node scripts/check-freecad-property-file-failure.mjs", + "probe:freecad-property-file-mutation": "node scripts/run-freecad-property-file-mutation.mjs", + "check:freecad-property-file-mutation": "node scripts/check-freecad-property-file-mutation.mjs", + "test:freecad-property-file-facade": "tsx --test tests/propertyFileFacade.test.ts", + "test:freecad-property-file-transaction": "tsx --test tests/propertyFileTransaction.test.ts", + "probe:freecad-property-file-roundtrip": "tsx scripts/run-freecad-property-file-roundtrip.ts", + "check:freecad-property-file-roundtrip": "node scripts/check-freecad-property-file-roundtrip.mjs", + "test:chrome-property-file": "node scripts/run-chrome-property-file.mjs", + "check:chrome-property-file": "node scripts/check-chrome-property-file.mjs", + "generate:freecad-property-file-promotion": "node scripts/generate-freecad-property-file-promotion.mjs", + "check:freecad-property-file-promotion": "node scripts/check-freecad-property-file-promotion.mjs", + "generate:freecad-property-acceleration-promotion": "node scripts/generate-freecad-property-acceleration-promotion.mjs", + "check:freecad-property-acceleration-promotion": "node scripts/check-freecad-property-acceleration-promotion.mjs", + "generate:freecad-property-area-inventory": "node scripts/generate-freecad-property-area-inventory.mjs", + "check:freecad-property-area-inventory": "node scripts/check-freecad-property-area-inventory.mjs", + "probe:freecad-property-area-success": "node scripts/run-freecad-property-area-success.mjs", + "check:freecad-property-area-success": "node scripts/check-freecad-property-area-success.mjs", + "probe:freecad-property-area-failure": "node scripts/run-freecad-property-area-failure.mjs", + "check:freecad-property-area-failure": "node scripts/check-freecad-property-area-failure.mjs", + "probe:freecad-property-area-mutation": "node scripts/run-freecad-property-area-mutation.mjs", + "check:freecad-property-area-mutation": "node scripts/check-freecad-property-area-mutation.mjs", + "test:freecad-property-area-facade": "tsx --test tests/propertyAreaFacade.test.ts", + "test:freecad-property-area-transaction": "tsx --test tests/propertyAreaTransaction.test.ts", + "probe:freecad-property-area-roundtrip": "tsx scripts/run-freecad-property-area-roundtrip.ts", + "check:freecad-property-area-roundtrip": "node scripts/check-freecad-property-area-roundtrip.mjs", + "check:freecad-native-property-semantics": "node scripts/check-freecad-native-property-semantics.mjs && node scripts/check-freecad-property-status-oracle.mjs", "probe:freecad-property-status": "node scripts/run-freecad-property-status-oracle.mjs", "check:freecad-property-status": "node scripts/check-freecad-property-status-oracle.mjs", "generate:freecad-gui-commands": "node scripts/generate-freecad-gui-command-inventory.mjs", diff --git a/scripts/check-chrome-property-acceleration.mjs b/scripts/check-chrome-property-acceleration.mjs new file mode 100644 index 0000000..5020eb5 --- /dev/null +++ b/scripts/check-chrome-property-acceleration.mjs @@ -0,0 +1,13 @@ +import { readFile } 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/chrome-property-acceleration-verification.json'), 'utf8')) +const fail = (message) => { throw new Error(`Chrome PropertyAcceleration check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.browserId !== 'chrome' || !/Chrome\//.test(report.userAgent || '') || report.crossOriginIsolated !== true) fail('browser boundary is invalid') +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +if (!report.worker?.constructed?.some(({ name }) => name === 'bitbybit-persistence') || !requiredWorkerRequests.every((type) => report.worker.requestTypes?.includes(type)) || report.worker.terminated?.includes('bitbybit-persistence') !== true) fail('persistence Worker lifecycle is incomplete') +if (report.ui?.inputType !== 'number' || report.ui.label !== 'Acceleration' || report.ui.unit !== 'mm/s^2' || report.ui.beforeValue !== 1000 || report.ui.afterValue !== 500 || report.ui.documentVersion !== 2 || report.ui.dirty !== true || report.ui.objectState !== 'touched' || report.ui.errors?.length !== 0) fail('production UI edit evidence is incomplete') +if (report.persistence?.mode !== 'sqlite-opfs' || report.persistence.sqliteWasm !== true || report.persistence.opfs !== true || report.persistence.savedMode !== 'sqlite-opfs' || report.persistence.loadedValue !== 500 || report.persistence.loadedType !== 'App::PropertyAcceleration' || report.persistence.checkpointVersion !== 2 || report.persistence.recoveryIntegrity !== 'ok' || report.persistence.fcstdElement !== 'Float' || report.persistence.fcstdValue !== '500') fail('OPFS/FCStd persistence evidence is incomplete') +if (!(report.resource?.byteLength > 0) || report.resource.roundTrip !== true || report.resource.released !== true || report.resource.markerRemoved !== true || report.release?.shapeCount !== 0 || report.release.kernelReferenceCount !== 0 || report.release.workerTerminated !== true) fail('resource release evidence is incomplete') +console.log(JSON.stringify({ status: 'chrome-property-acceleration-pass', ui: report.ui, persistence: report.persistence, workerRequests: report.worker.requestTypes, resource: report.resource, release: report.release }, null, 2)) diff --git a/scripts/check-chrome-property-area.mjs b/scripts/check-chrome-property-area.mjs new file mode 100644 index 0000000..dcdc319 --- /dev/null +++ b/scripts/check-chrome-property-area.mjs @@ -0,0 +1,13 @@ +import { readFile } 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/chrome-property-area-verification.json'), 'utf8')) +const fail = (message) => { throw new Error(`Chrome PropertyArea check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.browserId !== 'chrome' || !/Chrome\//.test(report.userAgent || '') || report.crossOriginIsolated !== true) fail('browser boundary is invalid') +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +if (!report.worker?.constructed?.some(({ name }) => name === 'bitbybit-persistence') || !requiredWorkerRequests.every((type) => report.worker.requestTypes?.includes(type)) || report.worker.terminated?.includes('bitbybit-persistence') !== true) fail('persistence Worker lifecycle is incomplete') +if (report.ui?.areaReadOnly !== true || report.ui.beforeText !== '20 mm^2' || report.ui.afterText !== '0 mm^2' || report.ui.beforeArea !== 20 || report.ui.afterArea !== 0 || report.ui.beforeElementCount !== 2 || report.ui.afterElementCount !== 0 || report.ui.triggerLabel !== 'Clear subshape links' || report.ui.documentVersion !== 2 || report.ui.dirty !== true || report.ui.objectState !== 'touched' || report.ui.errors?.length !== 0) fail('production UI derived-area evidence is incomplete') +if (report.persistence?.mode !== 'sqlite-opfs' || report.persistence.sqliteWasm !== true || report.persistence.opfs !== true || report.persistence.savedMode !== 'sqlite-opfs' || report.persistence.loadedArea !== 0 || report.persistence.loadedAreaType !== 'App::PropertyArea' || report.persistence.loadedElementCount !== 0 || report.persistence.loadedElementsType !== 'App::PropertyLinkSubList' || report.persistence.checkpointVersion !== 2 || report.persistence.recoveryIntegrity !== 'ok' || report.persistence.fcstdAreaElement !== 'Float' || Number(report.persistence.fcstdAreaValue) !== 0 || report.persistence.fcstdElementsElement !== 'LinkSubList' || report.persistence.fcstdElementCount !== 0) fail('OPFS/FCStd persistence evidence is incomplete') +if (!(report.resource?.byteLength > 0) || report.resource.roundTrip !== true || report.resource.released !== true || report.resource.markerRemoved !== true || report.release?.shapeCount !== 0 || report.release.kernelReferenceCount !== 0 || report.release.workerTerminated !== true) fail('resource release evidence is incomplete') +console.log(JSON.stringify({ status: 'chrome-property-area-pass', ui: report.ui, persistence: report.persistence, workerRequests: report.worker.requestTypes, resource: report.resource, release: report.release }, null, 2)) diff --git a/scripts/check-chrome-property-boollist.mjs b/scripts/check-chrome-property-boollist.mjs new file mode 100644 index 0000000..b7f5c27 --- /dev/null +++ b/scripts/check-chrome-property-boollist.mjs @@ -0,0 +1,15 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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/chrome-property-boollist-verification.json'), 'utf8')) +const fail = (message) => { throw new Error(`Chrome PropertyBoolList check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.browserId !== 'chrome' || !/Chrome\//.test(report.userAgent || '') || report.crossOriginIsolated !== true) fail('browser boundary is invalid') +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +if (!report.worker?.constructed?.some(({ name }) => name === 'bitbybit-persistence') || !requiredWorkerRequests.every((type) => report.worker.requestTypes?.includes(type)) || report.worker.terminated?.includes('bitbybit-persistence') !== true) fail('persistence Worker lifecycle is incomplete') +const target = [true, false, true, false] +if (report.ui?.inputType !== 'text' || report.ui.label !== 'Bool list' || report.ui.beforeText !== 'false' || report.ui.afterText !== 'true, false, true, false' || !isDeepStrictEqual(report.ui.beforeValue, [false]) || !isDeepStrictEqual(report.ui.afterValue, target) || report.ui.documentVersion !== 2 || report.ui.dirty !== true || report.ui.objectState !== 'touched' || report.ui.errors?.length !== 0) fail('production UI edit evidence is incomplete') +if (report.persistence?.mode !== 'sqlite-opfs' || report.persistence.sqliteWasm !== true || report.persistence.opfs !== true || report.persistence.savedMode !== 'sqlite-opfs' || !isDeepStrictEqual(report.persistence.loadedValue, target) || report.persistence.loadedType !== 'App::PropertyBoolList' || report.persistence.checkpointVersion !== 2 || report.persistence.recoveryIntegrity !== 'ok' || report.persistence.fcstdElement !== 'BoolList' || report.persistence.fcstdValue !== '[true,false,true,false]') fail('OPFS/FCStd persistence evidence is incomplete') +if (!(report.resource?.byteLength > 0) || report.resource.roundTrip !== true || report.resource.released !== true || report.resource.markerRemoved !== true || report.release?.shapeCount !== 0 || report.release.kernelReferenceCount !== 0 || report.release.workerTerminated !== true) fail('resource release evidence is incomplete') +console.log(JSON.stringify({ status: 'chrome-property-boollist-pass', ui: report.ui, persistence: report.persistence, workerRequests: report.worker.requestTypes, resource: report.resource, release: report.release }, null, 2)) diff --git a/scripts/check-chrome-property-color.mjs b/scripts/check-chrome-property-color.mjs new file mode 100644 index 0000000..f3d74a5 --- /dev/null +++ b/scripts/check-chrome-property-color.mjs @@ -0,0 +1,15 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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/chrome-property-color-verification.json'), 'utf8')) +const fail = (message) => { throw new Error(`Chrome PropertyColor check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.browserId !== 'chrome' || !/Chrome\//.test(report.userAgent || '') || report.crossOriginIsolated !== true) fail('browser boundary is invalid') +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +if (!report.worker?.constructed?.some(({ name }) => name === 'bitbybit-persistence') || !requiredWorkerRequests.every((type) => report.worker.requestTypes?.includes(type)) || report.worker.terminated?.includes('bitbybit-persistence') !== true) fail('persistence Worker lifecycle is incomplete') +const target = [0.2, 0.4, 0.6, 0.8] +if (report.ui?.rgbInputType !== 'color' || report.ui.alphaInputType !== 'number' || report.ui.rgbLabel !== 'Colour RGB' || report.ui.alphaLabel !== 'Colour alpha' || report.ui.beforeHex !== '#000000' || report.ui.afterHex !== '#336699' || report.ui.beforeAlpha !== '1' || report.ui.afterAlpha !== 0.8 || !isDeepStrictEqual(report.ui.beforeValue, [0, 0, 0, 1]) || !isDeepStrictEqual(report.ui.afterValue, target) || report.ui.documentVersion !== 3 || report.ui.dirty !== true || report.ui.objectState !== 'touched' || report.ui.errors?.length !== 0) fail('production UI edit evidence is incomplete') +if (report.persistence?.mode !== 'sqlite-opfs' || report.persistence.sqliteWasm !== true || report.persistence.opfs !== true || report.persistence.savedMode !== 'sqlite-opfs' || !isDeepStrictEqual(report.persistence.loadedValue, target) || report.persistence.loadedType !== 'App::PropertyColor' || report.persistence.checkpointVersion !== 3 || report.persistence.recoveryIntegrity !== 'ok' || report.persistence.fcstdElement !== 'PropertyColor' || report.persistence.fcstdValue !== '862362060') fail('OPFS/FCStd persistence evidence is incomplete') +if (!(report.resource?.byteLength > 0) || report.resource.roundTrip !== true || report.resource.released !== true || report.resource.markerRemoved !== true || report.release?.shapeCount !== 0 || report.release.kernelReferenceCount !== 0 || report.release.workerTerminated !== true) fail('resource release evidence is incomplete') +console.log(JSON.stringify({ status: 'chrome-property-color-pass', ui: report.ui, persistence: report.persistence, workerRequests: report.worker.requestTypes, resource: report.resource, release: report.release }, null, 2)) diff --git a/scripts/check-chrome-property-colorlist.mjs b/scripts/check-chrome-property-colorlist.mjs new file mode 100644 index 0000000..c44f0c9 --- /dev/null +++ b/scripts/check-chrome-property-colorlist.mjs @@ -0,0 +1,15 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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/chrome-property-colorlist-verification.json'), 'utf8')) +const fail = (message) => { throw new Error(`Chrome PropertyColorList check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.browserId !== 'chrome' || !/Chrome\//.test(report.userAgent || '') || report.crossOriginIsolated !== true) fail('browser boundary is invalid') +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +if (!report.worker?.constructed?.some(({ name }) => name === 'bitbybit-persistence') || !requiredWorkerRequests.every((type) => report.worker.requestTypes?.includes(type)) || report.worker.terminated?.includes('bitbybit-persistence') !== true) fail('persistence Worker lifecycle is incomplete') +const target = [[0.2, 0.4, 0.6, 0.8], [17 / 255, 34 / 255, 51 / 255, 0.4]] +if (!isDeepStrictEqual(report.ui?.rgbInputTypes, ['color', 'color']) || !isDeepStrictEqual(report.ui?.alphaInputTypes, ['number', 'number']) || !isDeepStrictEqual(report.ui?.rgbLabels, ['Colour list 1 RGB', 'Colour list 2 RGB']) || !isDeepStrictEqual(report.ui?.alphaLabels, ['Colour list 1 alpha', 'Colour list 2 alpha']) || report.ui?.addLabel !== 'Add Colour list color' || report.ui?.removeLabel !== 'Remove Colour list 3' || !isDeepStrictEqual(report.ui?.beforeHex, ['#000000']) || !isDeepStrictEqual(report.ui?.afterHex, ['#336699', '#112233']) || !isDeepStrictEqual(report.ui?.beforeAlpha, ['1']) || !isDeepStrictEqual(report.ui?.afterAlpha, [0.8, 0.4]) || !isDeepStrictEqual(report.ui?.beforeValue, [[0, 0, 0, 1]]) || !isDeepStrictEqual(report.ui?.afterValue, target) || report.ui?.beforeItemCount !== 1 || report.ui?.peakItemCount !== 3 || report.ui?.afterItemCount !== 2 || report.ui?.documentVersion !== 8 || report.ui?.dirty !== true || report.ui?.objectState !== 'touched' || report.ui?.errors?.length !== 0) fail('production UI edit evidence is incomplete') +if (report.persistence?.mode !== 'sqlite-opfs' || report.persistence.sqliteWasm !== true || report.persistence.opfs !== true || report.persistence.savedMode !== 'sqlite-opfs' || !isDeepStrictEqual(report.persistence.loadedValue, target) || report.persistence.loadedType !== 'App::PropertyColorList' || report.persistence.checkpointVersion !== 8 || report.persistence.recoveryIntegrity !== 'ok' || report.persistence.fcstdElement !== 'ColorList' || report.persistence.fcstdValue !== JSON.stringify(target) || report.persistence.fcstdResourcePath !== 'ColourList' || report.persistence.fcstdResourceBytes !== 12) fail('OPFS/FCStd persistence evidence is incomplete') +if (!(report.resource?.byteLength > 0) || report.resource.roundTrip !== true || report.resource.released !== true || report.resource.markerRemoved !== true || report.release?.shapeCount !== 0 || report.release.kernelReferenceCount !== 0 || report.release.workerTerminated !== true) fail('resource release evidence is incomplete') +console.log(JSON.stringify({ status: 'chrome-property-colorlist-pass', ui: report.ui, persistence: report.persistence, workerRequests: report.worker.requestTypes, resource: report.resource, release: report.release }, null, 2)) diff --git a/scripts/check-chrome-property-direction.mjs b/scripts/check-chrome-property-direction.mjs new file mode 100644 index 0000000..85442c5 --- /dev/null +++ b/scripts/check-chrome-property-direction.mjs @@ -0,0 +1,16 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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/chrome-property-direction-verification.json'), 'utf8')) +const fail = (message) => { throw new Error(`Chrome PropertyDirection check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.browserId !== 'chrome' || !/Chrome\//.test(report.userAgent || '') || report.crossOriginIsolated !== true) fail('browser boundary is invalid') +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +if (!report.worker?.constructed?.some(({ name }) => name === 'bitbybit-persistence') || !requiredWorkerRequests.every((type) => report.worker.requestTypes?.includes(type)) || report.worker.terminated?.includes('bitbybit-persistence') !== true) fail('persistence Worker lifecycle is incomplete') +const initial = { x: 0, y: 0, z: 1 } +const target = { x: 0.25, y: -0.5, z: 1.5 } +if (report.ui?.inputTypes?.some((type) => type !== 'number') || !isDeepStrictEqual(report.ui?.labels, ['Normal x', 'Normal y', 'Normal z']) || !isDeepStrictEqual(report.ui?.beforeValue, initial) || !isDeepStrictEqual(report.ui?.afterValue, target) || report.ui?.documentVersion !== 4 || report.ui?.dirty !== true || report.ui?.objectState !== 'touched' || report.ui?.errors?.length !== 0) fail('production UI direction edit evidence is incomplete') +if (report.persistence?.mode !== 'sqlite-opfs' || report.persistence.sqliteWasm !== true || report.persistence.opfs !== true || report.persistence.savedMode !== 'sqlite-opfs' || !isDeepStrictEqual(report.persistence.loadedValue, target) || report.persistence.loadedType !== 'App::PropertyDirection' || report.persistence.checkpointVersion !== 4 || report.persistence.recoveryIntegrity !== 'ok' || report.persistence.fcstdElement !== 'PropertyVector' || report.persistence.fcstdValue !== JSON.stringify(target)) fail('OPFS/FCStd persistence evidence is incomplete') +if (!(report.resource?.byteLength > 0) || report.resource.roundTrip !== true || report.resource.released !== true || report.resource.markerRemoved !== true || report.release?.shapeCount !== 0 || report.release?.kernelReferenceCount !== 0 || report.release?.workerTerminated !== true) fail('resource release evidence is incomplete') +console.log(JSON.stringify({ status: 'chrome-property-direction-pass', ui: report.ui, persistence: report.persistence, workerRequests: report.worker.requestTypes, resource: report.resource, release: report.release }, null, 2)) diff --git a/scripts/check-chrome-property-file.mjs b/scripts/check-chrome-property-file.mjs new file mode 100644 index 0000000..3f00025 --- /dev/null +++ b/scripts/check-chrome-property-file.mjs @@ -0,0 +1,15 @@ +import { readFile } 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/chrome-property-file-verification.json'), 'utf8')) +const fail = (message) => { throw new Error(`Chrome PropertyFile check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.browserId !== 'chrome' || !/Chrome\//.test(report.userAgent || '') || report.crossOriginIsolated !== true) fail('browser boundary is invalid') +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +if (!report.worker?.constructed?.some(({ name }) => name === 'bitbybit-persistence') || !requiredWorkerRequests.every((type) => report.worker.requestTypes?.includes(type)) || report.worker.terminated?.includes('bitbybit-persistence') !== true) fail('persistence Worker lifecycle is incomplete') +const initial = 'project-files/initial.obj' +const target = 'project-files/chrome-updated.obj' +if (report.ui?.inputType !== 'text' || report.ui.label !== 'File name' || report.ui.beforeValue !== initial || report.ui.afterValue !== target || report.ui.documentVersion !== 2 || report.ui.dirty !== true || report.ui.objectState !== 'touched' || report.ui.errors?.length !== 0) fail('production UI file edit evidence is incomplete') +if (report.persistence?.mode !== 'sqlite-opfs' || report.persistence.sqliteWasm !== true || report.persistence.opfs !== true || report.persistence.savedMode !== 'sqlite-opfs' || report.persistence.loadedValue !== target || report.persistence.loadedType !== 'App::PropertyFile' || report.persistence.checkpointVersion !== 2 || report.persistence.recoveryIntegrity !== 'ok' || report.persistence.fcstdElement !== 'String' || report.persistence.fcstdValue !== target) fail('OPFS/FCStd persistence evidence is incomplete') +if (!(report.resource?.byteLength > 0) || report.resource.roundTrip !== true || report.resource.released !== true || report.resource.markerRemoved !== true || report.release?.shapeCount !== 0 || report.release.kernelReferenceCount !== 0 || report.release.workerTerminated !== true) fail('resource release evidence is incomplete') +console.log(JSON.stringify({ status: 'chrome-property-file-pass', ui: report.ui, persistence: report.persistence, workerRequests: report.worker.requestTypes, resource: report.resource, release: report.release }, null, 2)) diff --git a/scripts/check-chrome-property-fileincluded.mjs b/scripts/check-chrome-property-fileincluded.mjs new file mode 100644 index 0000000..d3199b9 --- /dev/null +++ b/scripts/check-chrome-property-fileincluded.mjs @@ -0,0 +1,15 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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/chrome-property-fileincluded-verification.json'), 'utf8')) +const fail = (message) => { throw new Error(`Chrome PropertyFileIncluded check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.browserId !== 'chrome' || !/Chrome\//.test(report.userAgent || '') || report.crossOriginIsolated !== true) fail('browser boundary is invalid') +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +if (!report.worker?.constructed?.some(({ name }) => name === 'bitbybit-persistence') || !requiredWorkerRequests.every((type) => report.worker.requestTypes?.includes(type)) || report.worker.terminated?.includes('bitbybit-persistence') !== true) fail('persistence Worker lifecycle is incomplete') +const value = report.ui?.afterValue +if (report.ui?.inputType !== 'file' || report.ui.label !== 'Embedded file' || report.ui.beforeName !== 'Empty' || report.ui.afterName !== 'chrome-resource.bin' || value?.schemaVersion !== 1 || value.archiveName !== 'chrome-resource.bin' || !/^[a-f0-9]{64}$/.test(value.resourceHash || '') || value.byteLength !== 16 || value.mediaType !== 'application/octet-stream' || report.ui.documentVersion !== 2 || report.ui.dirty !== true || report.ui.objectState !== 'touched' || !isDeepStrictEqual(report.ui.notices, ['chrome-resource.bin embedded'])) fail('production UI included-file edit evidence is incomplete') +if (report.persistence?.mode !== 'sqlite-opfs' || report.persistence.sqliteWasm !== true || report.persistence.opfs !== true || report.persistence.savedMode !== 'sqlite-opfs' || !isDeepStrictEqual(report.persistence.loadedValue, value) || report.persistence.loadedType !== 'App::PropertyFileIncluded' || report.persistence.checkpointVersion !== 2 || report.persistence.recoveryIntegrity !== 'ok' || report.persistence.fcstdElement !== 'FileIncluded' || report.persistence.fcstdResourcePath !== 'chrome-resource.bin' || report.persistence.fcstdResourceBytes !== 16 || report.persistence.fcstdResourceMatches !== true) fail('OPFS/FCStd persistence evidence is incomplete') +if (report.resource?.documentByteLength !== 16 || report.resource.documentRoundTrip !== true || !(report.resource.independentByteLength > 0) || report.resource.independentRoundTrip !== true || report.resource.independentReleased !== true || report.resource.markerRemoved !== true || report.release?.shapeCount !== 0 || report.release.kernelReferenceCount !== 0 || report.release.workerTerminated !== true) fail('resource release evidence is incomplete') +console.log(JSON.stringify({ status: 'chrome-property-fileincluded-pass', ui: report.ui, persistence: report.persistence, workerRequests: report.worker.requestTypes, resource: report.resource, release: report.release }, null, 2)) diff --git a/scripts/check-facade-boundary.mjs b/scripts/check-facade-boundary.mjs index 6d381b7..5717f5e 100644 --- a/scripts/check-facade-boundary.mjs +++ b/scripts/check-facade-boundary.mjs @@ -6,7 +6,21 @@ const forbidden = [ /from\s+["']three(?:\/|["'])/, /from\s+["']@types\/three/, /from\s+["']sqlite3?/, /from\s+["']@sqlite/, /from\s+["']opfs/, /SharedArrayBuffer/, /\bpostMessage\s*\(/, ] const allowDirectRuntime = new Set(['facade/threeViewport.ts', 'facade/threeViewport.tsx', 'facade/persistenceWorker.ts', 'facade/projectStore.ts', 'facade/projectMigrationSeedWorker.ts', 'facade/geometryWorker.ts', 'facade/nativeHistoryWorkerClient.ts', 'facade/nativeHistoryWorkerEntry.ts', 'facade/planegcsWorkerClient.ts', 'facade/planegcsWorkerEntry.ts']) -const allowWorkerMessaging = new Set(['assemblySolverWorker.ts', 'meshLodWorker.ts', 'chromeAssemblyHarness.ts', 'chromeMeshHarness.ts', 'facade/camPipeline.ts']) +const allowWorkerMessaging = new Set([ + 'assemblySolverWorker.ts', + 'meshLodWorker.ts', + 'chromeAssemblyHarness.ts', + 'chromeMeshHarness.ts', + 'chromePropertyAccelerationHarness.tsx', + 'chromePropertyAreaHarness.tsx', + 'chromePropertyBoolListHarness.tsx', + 'chromePropertyColorHarness.tsx', + 'chromePropertyColorListHarness.tsx', + 'chromePropertyDirectionHarness.tsx', + 'chromePropertyFileHarness.tsx', + 'chromePropertyFileIncludedHarness.tsx', + 'facade/camPipeline.ts', +]) async function walk(relative = '') { const directory = new URL(relative, sourceRoot) diff --git a/scripts/check-freecad-native-property-semantics.mjs b/scripts/check-freecad-native-property-semantics.mjs index 6a7922a..ba5dfe8 100644 --- a/scripts/check-freecad-native-property-semantics.mjs +++ b/scripts/check-freecad-native-property-semantics.mjs @@ -5,11 +5,27 @@ import { resolve } from 'node:path' const root = resolve(new URL('..', import.meta.url).pathname) const report = JSON.parse(await readFile(resolve(root, 'config/freecad-native-property-semantics.json'), 'utf8')) const fail = (message) => { throw new Error(`FreeCAD native property semantics check failed: ${message}`) } -if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.exactPromotionReady !== false || report.exactBlocker !== '58 runtime property types and 523 records remain opaque-only; complete native document and property semantics') fail('report boundary is invalid') +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.exactPromotionReady !== false || report.exactBlocker !== '50 runtime property types and 466 records remain opaque-only; complete native document and property semantics') fail('report boundary is invalid') if (report.runtime?.registeredObjectTypes !== 352 || report.runtime.instantiableObjectTypes !== 348 || report.runtime.unavailableObjectTypes !== 4 || report.runtime.propertyRecords !== 5510 || report.runtime.propertyTypes !== 85 || report.runtime.unavailableObjects?.length !== 4) fail('runtime inventory counts changed') const support = report.supportSummary -if (support?.['native-editable-codec']?.typeCount !== 22 || support['native-editable-codec'].recordCount !== 4304 || support?.['native-specialized-codec']?.typeCount !== 5 || support['native-specialized-codec'].recordCount !== 683 || support?.['opaque-fcstd-proxy']?.typeCount !== 58 || support['opaque-fcstd-proxy'].recordCount !== 523) fail('property support partition is stale') +if (support?.['native-editable-codec']?.typeCount !== 30 || support['native-editable-codec'].recordCount !== 4361 || support?.['native-specialized-codec']?.typeCount !== 5 || support['native-specialized-codec'].recordCount !== 683 || support?.['opaque-fcstd-proxy']?.typeCount !== 50 || support['opaque-fcstd-proxy'].recordCount !== 466) fail('property support partition is stale') if (report.types?.length !== 85 || new Set(report.types.map(({ typeId }) => typeId)).size !== 85 || report.types.reduce((total, entry) => total + entry.recordCount, 0) !== 5510) fail('per-TypeId inventory is invalid') +const acceleration = report.types.find(({ typeId }) => typeId === 'App::PropertyAcceleration') +if (acceleration?.support !== 'native-editable-codec' || acceleration.recordCount !== 1 || acceleration.objectTypeCount !== 1) fail('App::PropertyAcceleration promotion is missing') +const area = report.types.find(({ typeId }) => typeId === 'App::PropertyArea') +if (area?.support !== 'native-editable-codec' || area.recordCount !== 1 || area.objectTypeCount !== 1 || area.statusNames?.join(',') !== 'PropOutput,PropReadOnly') fail('App::PropertyArea promotion is missing') +const boolList = report.types.find(({ typeId }) => typeId === 'App::PropertyBoolList') +if (boolList?.support !== 'native-editable-codec' || boolList.recordCount !== 7 || boolList.objectTypeCount !== 7 || boolList.statusNames?.join(',') !== 'Hidden,Immutable,LockDynamic') fail('App::PropertyBoolList promotion is missing') +const color = report.types.find(({ typeId }) => typeId === 'App::PropertyColor') +if (color?.support !== 'native-editable-codec' || color.recordCount !== 8 || color.objectTypeCount !== 8 || color.statusNames?.length !== 0) fail('App::PropertyColor promotion is missing') +const colorList = report.types.find(({ typeId }) => typeId === 'App::PropertyColorList') +if (colorList?.support !== 'native-editable-codec' || colorList.recordCount !== 2 || colorList.objectTypeCount !== 2 || colorList.statusNames?.length !== 0) fail('App::PropertyColorList promotion is missing') +const direction = report.types.find(({ typeId }) => typeId === 'App::PropertyDirection') +if (direction?.support !== 'native-editable-codec' || direction.recordCount !== 2 || direction.objectTypeCount !== 2 || direction.statusNames?.length !== 0) fail('App::PropertyDirection promotion is missing') +const file = report.types.find(({ typeId }) => typeId === 'App::PropertyFile') +if (file?.support !== 'native-editable-codec' || file.recordCount !== 16 || file.objectTypeCount !== 12 || file.statusNames?.length !== 0) fail('App::PropertyFile promotion is missing') +const fileIncluded = report.types.find(({ typeId }) => typeId === 'App::PropertyFileIncluded') +if (fileIncluded?.support !== 'native-editable-codec' || fileIncluded.recordCount !== 20 || fileIncluded.objectTypeCount !== 15 || fileIncluded.statusNames?.join(',') !== 'PropOutput,ReadOnly') fail('App::PropertyFileIncluded promotion is missing') if (report.propertyStatus?.unknownNumericBits?.length !== 0 || report.propertyStatus.proxyOnlyRecordCount !== 0 || report.propertyStatus.proxyOnly?.length !== 0 || report.propertyStatus.facadeNative?.join(',') !== report.propertyStatus.observed?.join(',')) fail('property status representation coverage is stale') if (report.propertyStatus.behaviorNative?.join(',') !== 'Hidden,Immutable,LockDynamic,NoModify,Ordered,Output,PartialTrigger,PropHidden,PropNoPersist,PropNoRecompute,PropOutput,PropReadOnly,PropTransient,ReadOnly,Transient' || report.propertyStatus.preservedOnly?.length !== 0 || report.propertyStatus.preservedOnlyRecordCount !== 0) fail('property status behavior boundary is stale') for (const locked of [report.source, report.harness]) { @@ -17,4 +33,4 @@ for (const locked of [report.source, report.harness]) { const [content, bytes] = await Promise.all([readFile(path), stat(path).then(({ size }) => size)]) if (bytes !== locked.bytes || createHash('sha256').update(content).digest('hex') !== locked.sha256) fail(`report is stale for ${locked.path}`) } -console.log(JSON.stringify({ status: 'freecad-native-property-semantics-pass', propertyTypes: 85, propertyRecords: 5510, nativeCodecRecords: 4987, opaqueProxyRecords: 523, representedStatusRecords: 5510, preservedOnlyStatusRecords: 0, exactPromotionReady: false }, null, 2)) +console.log(JSON.stringify({ status: 'freecad-native-property-semantics-pass', propertyTypes: 85, propertyRecords: 5510, nativeCodecRecords: 5044, opaqueProxyRecords: 466, promotedTypes: [acceleration.typeId, area.typeId, boolList.typeId, color.typeId, colorList.typeId, direction.typeId, file.typeId, fileIncluded.typeId], representedStatusRecords: 5510, preservedOnlyStatusRecords: 0, exactPromotionReady: false, exactBlocker: report.exactBlocker }, null, 2)) diff --git a/scripts/check-freecad-ordered-operation-pair-classification.mjs b/scripts/check-freecad-ordered-operation-pair-classification.mjs index e1ae38a..6a059ec 100644 --- a/scripts/check-freecad-ordered-operation-pair-classification.mjs +++ b/scripts/check-freecad-ordered-operation-pair-classification.mjs @@ -6,6 +6,13 @@ 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') +const summariesMatchWithinTolerance = (left, right, tolerance = 1e-6) => ( + left?.isValid === right?.isValid + && ['solids', 'faces', 'edges', 'vertices'].every((key) => left?.[key] === right?.[key]) + && ['volume', 'area'].every((key) => Math.abs(left?.[key] - right?.[key]) <= tolerance) + && left?.bounds?.length === right?.bounds?.length + && left.bounds.every((value, index) => Math.abs(value - right.bounds[index]) <= tolerance) +) 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 ?? '') @@ -227,6 +234,154 @@ const expectedPairs = [ { pair: 'chamfer->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [8, 7, 8] }, { pair: 'chamfer->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] }, { pair: 'chamfer->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [7, 6, 7] }, + { pair: 'chamfer->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] }, + { pair: 'chamfer->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' }, + { pair: 'chamfer->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] }, + { pair: 'chamfer->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' }, + { pair: 'chamfer->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' }, + { pair: 'chamfer->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'Solids are not Processed' }, + { pair: 'chamfer->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] }, + { pair: 'chamfer->fillet', decision: 'rejected', reasonCode: 'native-builder-wasm-abort-with-freecad-profile-acceptance-and-clean-resave', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4], nativeTypeId: 'Part::Fillet', freecadProfileAccepted: true, wasmCrashSignature: 'memory access out of bounds' }, + { pair: 'chamfer->chamfer', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4], nativeTypeId: 'Part::Chamfer', freeCadDiagnostic: 'BRep_API: command not done', wasmCrashSignature: 'memory access out of bounds' }, + { pair: 'chamfer->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [1, 1.5, 1] }, + { pair: 'chamfer->draft', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5], nativeTypeId: 'PartDesign::Draft', freeCadDiagnostic: '', inputShapeTransfer: 'partdesign-feature-summary-exact-with-explicit-brep-drift' }, + { pair: 'chamfer->thickness', decision: 'rejected', reasonCode: 'native-and-freecad-profile-no-op-with-clean-resave', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, rejectionAuthority: 'occt-no-op', kernelOutcome: 'no-op', secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4], nativeTypeId: 'Part::Thickness', freeCadDiagnostic: 'Valid', freecadProfileNoOp: true, rollbackShape: 'geometry-and-summary-exact-with-explicit-brep-reserialization' }, + { pair: 'chamfer->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'chamfer->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] }, + { pair: 'chamfer->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [6, 7, 6] }, + { pair: 'chamfer->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepFilletAPI_MakeChamfer', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'hole->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [8, 7, 8] }, + { pair: 'hole->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] }, + { pair: 'hole->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [7, 6, 7] }, + { pair: 'hole->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] }, + { pair: 'hole->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' }, + { pair: 'hole->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] }, + { pair: 'hole->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' }, + { pair: 'hole->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' }, + { pair: 'hole->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'Solids are not Processed' }, + { pair: 'hole->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] }, + { pair: 'hole->fillet', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4] }, + { pair: 'hole->chamfer', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4] }, + { pair: 'hole->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [1, 1.5, 1] }, + { pair: 'hole->draft', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5] }, + { pair: 'hole->thickness', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4] }, + { pair: 'hole->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'hole->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] }, + { pair: 'hole->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [6, 7, 6] }, + { pair: 'hole->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'draft->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [8, 7, 8] }, + { pair: 'draft->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] }, + { pair: 'draft->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [7, 6, 7] }, + { pair: 'draft->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] }, + { pair: 'draft->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' }, + { pair: 'draft->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] }, + { pair: 'draft->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' }, + { pair: 'draft->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' }, + { pair: 'draft->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'Solids are not Processed' }, + { pair: 'draft->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] }, + { pair: 'draft->fillet', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4] }, + { pair: 'draft->chamfer', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4] }, + { pair: 'draft->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [1, 1.5, 1] }, + { pair: 'draft->draft', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5] }, + { pair: 'draft->thickness', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4] }, + { pair: 'draft->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'draft->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] }, + { pair: 'draft->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [5, 6, 5] }, + { pair: 'draft->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_DraftAngle', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'thickness->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [8, 7, 8] }, + { pair: 'thickness->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] }, + { pair: 'thickness->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [7, 6, 7] }, + { pair: 'thickness->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] }, + { pair: 'thickness->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' }, + { pair: 'thickness->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] }, + { pair: 'thickness->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' }, + { pair: 'thickness->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' }, + { pair: 'thickness->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'Solids are not Processed' }, + { pair: 'thickness->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] }, + { pair: 'thickness->fillet', decision: 'rejected', reasonCode: 'native-builder-wasm-abort-with-freecad-profile-acceptance-and-clean-resave', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4], nativeTypeId: 'Part::Fillet', freecadProfileAccepted: true, freecadSelectedEdges: [1], wasmCrashSignature: 'null function or function signature mismatch' }, + { pair: 'thickness->chamfer', decision: 'rejected', reasonCode: 'native-builder-cpp-exception-with-freecad-profile-acceptance-and-clean-resave', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4], nativeTypeId: 'Part::Chamfer', freecadProfileAccepted: true, freecadSelectedEdges: [1] }, + { pair: 'thickness->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [1, 1.5, 1] }, + { pair: 'thickness->draft', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5] }, + { pair: 'thickness->thickness', decision: 'rejected', reasonCode: 'native-and-freecad-profile-no-op-with-clean-resave', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, rejectionAuthority: 'occt-no-op', kernelOutcome: 'no-op', secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4], nativeTypeId: 'Part::Thickness', freeCadDiagnostic: 'Valid', freecadProfileNoOp: true }, + { pair: 'thickness->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'thickness->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] }, + { pair: 'thickness->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [5, 6, 5] }, + { pair: 'thickness->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepOffsetAPI_MakeThickSolid', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'linear-pattern->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [16, 15, 16] }, + { pair: 'linear-pattern->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] }, + { pair: 'linear-pattern->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [10, 9, 10] }, + { pair: 'linear-pattern->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] }, + { pair: 'linear-pattern->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' }, + { pair: 'linear-pattern->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] }, + { pair: 'linear-pattern->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' }, + { pair: 'linear-pattern->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' }, + { pair: 'linear-pattern->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'Solids are not Processed' }, + { pair: 'linear-pattern->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] }, + { pair: 'linear-pattern->fillet', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4] }, + { pair: 'linear-pattern->chamfer', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4] }, + { pair: 'linear-pattern->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [1, 1.5, 1] }, + { pair: 'linear-pattern->draft', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5] }, + { pair: 'linear-pattern->thickness', decision: 'rejected', reasonCode: 'native-and-freecad-profile-no-op-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'occt-no-op', kernelOutcome: 'no-op', secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4], nativeTypeId: 'Part::Thickness', freeCadDiagnostic: 'Valid', freecadProfileNoOp: true, rollbackShape: 'geometry-and-summary-exact-with-explicit-brep-reserialization' }, + { pair: 'linear-pattern->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'linear-pattern->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] }, + { pair: 'linear-pattern->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [5, 6, 5] }, + { pair: 'linear-pattern->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'polar-pattern->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [8, 7, 8] }, + { pair: 'polar-pattern->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] }, + { pair: 'polar-pattern->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [7, 6, 7] }, + { pair: 'polar-pattern->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] }, + { pair: 'polar-pattern->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' }, + { pair: 'polar-pattern->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] }, + { pair: 'polar-pattern->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' }, + { pair: 'polar-pattern->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' }, + { pair: 'polar-pattern->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'BRep_API: command not done' }, + { pair: 'polar-pattern->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] }, + { pair: 'polar-pattern->fillet', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4], nativeTypeId: 'Part::Fillet', freeCadDiagnostic: 'BRep_API: command not done', freecadSelectedEdges: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26], wasmCrashSignature: 'null function or function signature mismatch' }, + { pair: 'polar-pattern->chamfer', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4], nativeTypeId: 'Part::Chamfer', freeCadDiagnostic: 'BRep_API: command not done', freecadSelectedEdges: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] }, + { pair: 'polar-pattern->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [1, 1.5, 1] }, + { pair: 'polar-pattern->draft', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5], nativeTypeId: 'PartDesign::Draft', freeCadDiagnostic: '', inputShapeTransfer: 'partdesign-feature-summary-exact-with-explicit-brep-drift' }, + { pair: 'polar-pattern->thickness', decision: 'rejected', reasonCode: 'native-and-freecad-profile-no-op-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'occt-no-op', kernelOutcome: 'no-op', secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4], nativeTypeId: 'Part::Thickness', freeCadDiagnostic: 'Valid', freecadProfileNoOp: true, rollbackShape: 'geometry-and-summary-exact-with-explicit-brep-reserialization', kernelNoOpComparison: 'topology-and-metrics-within-1e-6' }, + { pair: 'polar-pattern->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'polar-pattern->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] }, + { pair: 'polar-pattern->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [5, 6, 5] }, + { pair: 'polar-pattern->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'mirrored->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [8, 7, 8] }, + { pair: 'mirrored->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] }, + { pair: 'mirrored->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [7, 6, 7] }, + { pair: 'mirrored->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] }, + { pair: 'mirrored->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' }, + { pair: 'mirrored->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] }, + { pair: 'mirrored->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' }, + { pair: 'mirrored->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' }, + { pair: 'mirrored->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'Solids are not Processed' }, + { pair: 'mirrored->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] }, + { pair: 'mirrored->fillet', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4] }, + { pair: 'mirrored->chamfer', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4] }, + { pair: 'mirrored->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [1, 1.5, 1] }, + { pair: 'mirrored->draft', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5] }, + { pair: 'mirrored->thickness', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4] }, + { pair: 'mirrored->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] }, + { pair: 'mirrored->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [5, 6, 5] }, + { pair: 'mirrored->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'multi-transform->fuse', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Fuse', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [16, 15, 16] }, + { pair: 'multi-transform->cut', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'toolSize', mutationTrajectory: [4, 3, 4] }, + { pair: 'multi-transform->common', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepAlgoAPI_Common', secondInputCount: 2, mutationParameter: 'toolOffsetX', mutationTrajectory: [10, 9, 10] }, + { pair: 'multi-transform->rotate', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [15, 22.5, 15] }, + { pair: 'multi-transform->pad', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakePrism', secondInputCount: 1, mutationParameter: 'length', mutationTrajectory: [5, 7.5, 5], nativeTypeId: 'PartDesign::Pad', freeCadDiagnostic: 'FeatureExtrusion: Length: Could not extrude the sketch!' }, + { pair: 'multi-transform->pocket', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'length', mutationTrajectory: [5, 4, 5] }, + { pair: 'multi-transform->loft', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted', secondBuilder: 'BRepOffsetAPI_ThruSections', secondInputCount: 2, mutationParameter: 'ruled', mutationTrajectory: [false, true, false], nativeTypeId: 'Part::Loft', freeCadDiagnostic: 'Profile shape is not a single vertex, edge, wire nor face.' }, + { pair: 'multi-transform->pipe', decision: 'rejected', reasonCode: 'freecad-input-precondition-reject-with-kernel-diagnostic-and-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result', secondBuilder: 'BRepOffsetAPI_MakePipe', secondInputCount: 2, mutationParameter: 'spineLength', mutationTrajectory: [15, 12, 15], nativeTypeId: 'Part::Sweep', freeCadDiagnostic: 'A fatal error occurred when making the sweep' }, + { pair: 'multi-transform->revolution', decision: 'rejected', reasonCode: 'native-builder-and-freecad-profile-reject-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, rejectionAuthority: 'occt-builder', secondBuilder: 'BRepPrimAPI_MakeRevol', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [360, 270, 360], nativeTypeId: 'Part::Revolution', freeCadDiagnostic: 'BRep_API: command not done' }, + { pair: 'multi-transform->groove', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut', secondInputCount: 2, mutationParameter: 'angle', mutationTrajectory: [360, 180, 360] }, + { pair: 'multi-transform->fillet', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeFillet', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [0.4, 0.6, 0.4] }, + { pair: 'multi-transform->chamfer', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepFilletAPI_MakeChamfer', secondInputCount: 1, mutationParameter: 'distance', mutationTrajectory: [0.4, 0.6, 0.4] }, + { pair: 'multi-transform->hole', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut', secondInputCount: 1, mutationParameter: 'radius', mutationTrajectory: [1, 1.5, 1] }, + { pair: 'multi-transform->draft', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepOffsetAPI_DraftAngle', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [5, 8, 5] }, + { pair: 'multi-transform->thickness', decision: 'rejected', reasonCode: 'native-and-freecad-profile-no-op-with-clean-resave', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, rejectionAuthority: 'occt-no-op', kernelOutcome: 'no-op', secondBuilder: 'BRepOffsetAPI_MakeThickSolid', secondInputCount: 1, mutationParameter: 'offset', mutationTrajectory: [-0.4, -0.6, -0.4], nativeTypeId: 'Part::Thickness', freeCadDiagnostic: 'Valid', freecadProfileNoOp: true, rollbackShape: 'geometry-and-summary-exact-with-explicit-brep-reserialization' }, + { pair: 'multi-transform->linear-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'translationX', mutationTrajectory: [8, 9, 8] }, + { pair: 'multi-transform->polar-pattern', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'angle', mutationTrajectory: [30, 45, 30] }, + { pair: 'multi-transform->mirrored', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse', secondInputCount: 1, mutationParameter: 'planeOriginX', mutationTrajectory: [5, 6, 5] }, + { pair: 'multi-transform->multi-transform', decision: 'accepted', reasonCode: 'native-builders-mutation-naming-and-fcstd-resave-pass', firstBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', firstInputCount: 1, secondBuilder: 'BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)', secondInputCount: 1, mutationParameter: 'multiTranslationX', mutationTrajectory: [8, 9, 8] }, ] 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()) { @@ -251,16 +406,22 @@ for (const [index, entry] of report.classifications.entries()) { for (const [attemptIndex, attempt] of rejection.kernelAttempts.entries()) { const validKernelShape = expected.kernelOutcome !== 'invalid-result' const expectedAuthority = expected.kernelOutcome === 'no-op' ? 'kernel-no-op' : expected.kernelOutcome === 'accepted' ? 'kernel-superset-only' : 'kernel-invalid-result' - if (attempt.operation !== secondOperation || attempt.builder !== expected.secondBuilder || attempt.inputCount !== expected.secondInputCount || attempt.parameter !== expected.mutationParameter || attempt.parameterValue !== expected.mutationTrajectory[attemptIndex] || attempt.runtime !== 'occt-native' || attempt.outcome !== expected.kernelOutcome || attempt.resultProduced !== true || attempt.shapeProduced !== true || attempt.validShapeProduced !== validKernelShape || attempt.historyProduced !== true || attempt.historyProvider !== 'occt-native' || attempt.summary?.isValid !== validKernelShape || attempt.historyRecords < 1 || !attempt.historySha256 || attempt.authority !== expectedAuthority || (expected.kernelOutcome === 'no-op' && JSON.stringify(attempt.summary) !== JSON.stringify(entry.first.summary))) fail(`${expected.pair} OCCT compatibility attempt ${attemptIndex} is invalid.`) + const tolerantNoOp = expected.kernelNoOpComparison === 'topology-and-metrics-within-1e-6' + const noOpMatchesInput = tolerantNoOp + ? attempt.noOpComparison === expected.kernelNoOpComparison && summariesMatchWithinTolerance(attempt.summary, entry.first.summary) + : JSON.stringify(attempt.summary) === JSON.stringify(entry.first.summary) + if (attempt.operation !== secondOperation || attempt.builder !== expected.secondBuilder || attempt.inputCount !== expected.secondInputCount || attempt.parameter !== expected.mutationParameter || attempt.parameterValue !== expected.mutationTrajectory[attemptIndex] || attempt.runtime !== 'occt-native' || attempt.outcome !== expected.kernelOutcome || attempt.resultProduced !== true || attempt.shapeProduced !== true || attempt.validShapeProduced !== validKernelShape || attempt.historyProduced !== true || attempt.historyProvider !== 'occt-native' || attempt.summary?.isValid !== validKernelShape || attempt.historyRecords < 1 || !attempt.historySha256 || attempt.authority !== expectedAuthority || (expected.kernelOutcome === 'no-op' && !noOpMatchesInput)) fail(`${expected.pair} OCCT compatibility attempt ${attemptIndex} is invalid.`) } } const persistence = rejection.persistence const diagnostic = persistence?.diagnostic const freecadProfileAccepted = expected.freecadProfileAccepted === true const freecadProfileNoOp = expected.freecadProfileNoOp === true - const persistenceChecksPass = Object.values(persistence?.checks ?? {}).every(Boolean) || (freecadProfileAccepted && persistence?.checks?.nativeFeatureRejected === false && Object.entries(persistence?.checks ?? {}).filter(([key]) => key !== 'nativeFeatureRejected').every(([, value]) => value === true)) || (freecadProfileNoOp && persistence?.checks?.freecadProfileNoOp === true && persistence?.checks?.freecadProfileAccepted === false && persistence?.checks?.nativeFeatureRejected === false && Object.entries(persistence?.checks ?? {}).filter(([key]) => !['nativeFeatureRejected', 'freecadProfileAccepted'].includes(key)).every(([, value]) => value === true)) || (!freecadProfileAccepted && !freecadProfileNoOp && persistence?.checks?.nativeFeatureRejected === true && Object.entries(persistence?.checks ?? {}).filter(([key]) => key !== 'freecadProfileAccepted').every(([, value]) => value === true)) + const noOpSourceBrepReserialized = expected.rollbackShape === 'geometry-and-summary-exact-with-explicit-brep-reserialization' && persistence?.checks?.sourceShapeRestored === false && persistence?.checks?.sourceShapeSummaryRestored === true && persistence?.checks?.sourceShapeGeometricallyRestored === true && persistence?.rollback?.sourceBrepReserialized === true + const persistenceChecksPass = Object.values(persistence?.checks ?? {}).every(Boolean) || (freecadProfileAccepted && persistence?.checks?.nativeFeatureRejected === false && Object.entries(persistence?.checks ?? {}).filter(([key]) => key !== 'nativeFeatureRejected').every(([, value]) => value === true)) || (freecadProfileNoOp && persistence?.checks?.freecadProfileNoOp === true && persistence?.checks?.freecadProfileAccepted === false && persistence?.checks?.nativeFeatureRejected === false && Object.entries(persistence?.checks ?? {}).filter(([key]) => !['nativeFeatureRejected', 'freecadProfileAccepted', ...(noOpSourceBrepReserialized ? ['sourceShapeRestored'] : [])].includes(key)).every(([, value]) => value === true)) || (!freecadProfileAccepted && !freecadProfileNoOp && persistence?.checks?.nativeFeatureRejected === true && Object.entries(persistence?.checks ?? {}).filter(([key]) => key !== 'freecadProfileAccepted').every(([, value]) => value === true)) if (persistence?.status !== 'pass' || persistence.decision !== 'rejected' || persistence.pair !== entry.pair || persistence.operation !== secondOperation || persistence.nativeTypeId !== expected.nativeTypeId || persistence.freecadVersion !== '1.1.1' || !persistenceChecksPass) fail(`${expected.pair} FCStd rejection evidence is incomplete.`) if (diagnostic?.nativeTypeId !== expected.nativeTypeId || diagnostic.parameter?.name !== expected.mutationParameter || diagnostic.parameter.value !== expected.mutationTrajectory[0] || diagnostic.inputShape?.solids !== 1 || diagnostic.recomputeResult !== true || !diagnostic.objects?.some(({ name, typeId }) => name === 'PairResult' && typeId === expected.nativeTypeId)) fail(`${expected.pair} did not capture a real FreeCAD profile evaluation.`) + if (expected.freecadSelectedEdges && JSON.stringify(diagnostic.input?.selectedEdges) !== JSON.stringify(expected.freecadSelectedEdges)) fail(`${expected.pair} FreeCAD selected-edge fixture changed.`) if (freecadProfileNoOp) { if (diagnostic.shapeNull !== false || diagnostic.shapeValid !== true || diagnostic.statusString !== 'Valid' || !diagnostic.state?.includes('Up-to-date') || JSON.stringify(diagnostic.resultShape) !== JSON.stringify(diagnostic.inputShape)) fail(`${expected.pair} FreeCAD no-op evidence is incomplete.`) } else if (freecadProfileAccepted) { @@ -273,7 +434,14 @@ for (const [index, entry] of report.classifications.entries()) { const input = diagnostic.input if (input?.name !== 'DraftBase' || input.typeId !== 'PartDesign::Feature' || JSON.stringify(input.subelements) !== JSON.stringify(['Face1']) || input.sourceName !== persistence.source?.name || input.shapeSummaryTransferredExactly !== true || typeof input.sourceBrepSha256 !== 'string' || typeof input.draftBaseBrepSha256 !== 'string' || input.sourceBrepSha256 === input.draftBaseBrepSha256) fail(`${expected.pair} PartDesign input Shape transfer evidence is incomplete.`) } - if (persistence.source?.shape?.solids !== 1 || !persistence.source.shape.brepSha256 || JSON.stringify(persistence.rollback?.before) !== JSON.stringify(persistence.rollback?.after)) fail(`${expected.pair} abort did not restore the source object set and Shape.`) + if (persistence.source?.shape?.solids !== 1 || !persistence.source.shape.brepSha256) fail(`${expected.pair} source Shape evidence is incomplete.`) + if (expected.rollbackShape === 'geometry-and-summary-exact-with-explicit-brep-reserialization') { + const before = persistence.rollback?.before + const after = persistence.rollback?.after + const symmetricDifference = persistence.rollback?.sourceShapeSymmetricDifference + const withoutBrep = (shape) => Object.fromEntries(Object.entries(shape ?? {}).filter(([key]) => key !== 'brepSha256')) + if (JSON.stringify(before?.objects) !== JSON.stringify(after?.objects) || JSON.stringify(withoutBrep(before?.sourceShape)) !== JSON.stringify(withoutBrep(after?.sourceShape)) || before?.sourceShape?.brepSha256 === after?.sourceShape?.brepSha256 || persistence.rollback?.sourceBrepReserialized !== true || persistence.rollback?.sourceShapeTopologicallyEqual !== false || symmetricDifference?.beforeMinusAfterVolume !== 0 || symmetricDifference?.afterMinusBeforeVolume !== 0 || persistence.checks.sourceShapeSummaryRestored !== true || persistence.checks.sourceShapeGeometricallyRestored !== true || persistence.checks.sourceShapeRestored !== false) fail(`${expected.pair} did not classify the source BREP reserialization precisely.`) + } else if (JSON.stringify(persistence.rollback?.before) !== JSON.stringify(persistence.rollback?.after)) fail(`${expected.pair} abort did not restore the source object set and Shape.`) const phases = persistence.phases if (JSON.stringify(phases?.initial) !== JSON.stringify(phases?.reopened) || JSON.stringify(phases?.initial) !== JSON.stringify(phases?.resaved) || phases.initial.objects?.length !== persistence.rollback.before.objects.length || phases.initial.objects?.some(({ typeId }) => typeId === 'PartDesign::Body' || typeId === 'PartDesign::Pad' || typeId === 'Part::Loft' || typeId === 'Part::Revolution')) fail(`${expected.pair} polluted the clean FCStd save/reopen/resave chain.`) continue @@ -288,6 +456,6 @@ for (const [index, entry] of report.classifications.entries()) { const phases = entry.persistence.phases if (JSON.stringify(phases?.initial) !== JSON.stringify(phases?.reopened) || JSON.stringify(phases?.initial) !== JSON.stringify(phases?.resaved) || phases.initial.namingEvidenceSha256 !== entry.second.namingEvidenceSha256) fail(`${expected.pair} FCStd phases changed Shape or naming evidence.`) } -const expectedSummary = { registeredOperations: 19, orderedPairs: 361, classifiedPairs: 209, accepted: 157, rejected: 52, unknown: 152 } +const expectedSummary = { registeredOperations: 19, orderedPairs: 361, classifiedPairs: 357, accepted: 260, rejected: 97, unknown: 4 } if (JSON.stringify(report.summary) !== JSON.stringify(expectedSummary)) fail('summary is inconsistent.') console.log(JSON.stringify({ status: 'freecad-ordered-operation-pair-classification-pass', completedTasks: report.classifications.map(({ taskId }) => taskId), pairs: report.classifications.map(({ pair, classification }) => ({ pair, classification })), nativeBuilderRuns: report.classifications.length * 4, fcstdPhases: report.classifications.length * 3, remainingPairs: report.summary.unknown }, null, 2)) diff --git a/scripts/check-freecad-property-acceleration-failure.mjs b/scripts/check-freecad-property-acceleration-failure.mjs new file mode 100644 index 0000000..865b719 --- /dev/null +++ b/scripts/check-freecad-property-acceleration-failure.mjs @@ -0,0 +1,24 @@ +import { readFile } 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-property-acceleration-failure.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyAcceleration failure check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-acceleration-failure' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is invalid') +if (report.object?.typeId !== 'Robot::TrajectoryDressUpObject' || report.property?.typeId !== 'App::PropertyAcceleration' || report.initial?.numeric !== 1000 || report.failures?.length !== 2) fail('failure fixture identity or cases changed') +const expectedFailures = new Map([ + ['wrong-dimension', { requested: '5 mm', type: 'ArithmeticError', message: 'Not matching Unit!' }], + ['malformed-text', { requested: 'not-a-quantity', type: 'ParserError', message: 'syntax error' }], +]) +for (const entry of report.failures) { + const expected = expectedFailures.get(entry.id) + if (!expected || entry.requested !== expected.requested || entry.exception?.type !== expected.type || entry.exception?.message !== expected.message || entry.valuePreserved !== true || entry.objectsPreserved !== true || entry.polluted !== false || JSON.stringify(entry.before) !== JSON.stringify(entry.after) || JSON.stringify(entry.beforeObjects) !== JSON.stringify(entry.afterObjects)) fail(`${entry.id} did not reject without document pollution`) +} +if (expectedFailures.size !== report.failures.length) fail('failure cases are not the locked set') +const disabled = report.disabled +if (disabled?.classification !== 'editor-read-only-and-python-immutable' || disabled.requested !== '750 mm/s^2' || disabled.status?.includes('Immutable') !== true || disabled.status.includes('ReadOnly') !== true || JSON.stringify(disabled.editorMode) !== '["ReadOnly"]' || disabled.exception?.type !== 'AttributeError' || disabled.exception.message !== "Object attribute 'Acceleration' is read-only" || disabled.valuePreserved !== true || disabled.objectsPreserved !== true || JSON.stringify(disabled.before) !== JSON.stringify(disabled.after) || JSON.stringify(disabled.beforeObjects) !== JSON.stringify(disabled.afterObjects) || JSON.stringify(disabled.restoredStatus) !== '[]' || JSON.stringify(disabled.restoredEditorMode) !== '[]') fail('disabled property state did not reject and restore cleanly') +const transaction = report.transaction +if (transaction?.undoMode !== 1 || transaction.pendingAfterEdit !== true || transaction.pendingAfterAbort !== false || transaction.activeAfterEdit?.name !== 'property-acceleration-cancel' || !(transaction.activeAfterEdit.id > 0) || transaction.activeAfterAbort?.name !== '' || transaction.activeAfterAbort?.id !== 0 || transaction.restored !== true || transaction.objectsRestored !== true || transaction.before?.numeric !== 1000 || transaction.edited?.numeric !== 250 || transaction.afterAbort?.numeric !== 1000 || JSON.stringify(transaction.objectsBefore) !== JSON.stringify(transaction.objectsAfter)) fail('transaction abort did not restore the property') +if (report.cancellationBoundary?.supported !== false || report.cancellationBoundary.classification !== 'synchronous-property-setter' || report.cancellationBoundary.reason !== 'no-native-cancel-hook' || report.cancellationBoundary.replacement !== 'abort-active-document-transaction') fail('cancellation boundary is not explicit') +if (report.documentIntegrity?.objectsPreserved !== true || report.documentIntegrity.objectCount !== 1 || JSON.stringify(report.documentIntegrity.initialObjects) !== JSON.stringify(report.documentIntegrity.finalObjects)) fail('failure, disabled or cancellation cases polluted the document') +console.log(JSON.stringify({ status: 'freecad-property-acceleration-failure-pass', failures: report.failures.map(({ id, exception }) => ({ id, exception })), disabled: { status: disabled.status, editorMode: disabled.editorMode, exception: disabled.exception }, transactionRestored: transaction.restored, documentObjectsPreserved: report.documentIntegrity.objectsPreserved, cancellationBoundary: report.cancellationBoundary }, null, 2)) diff --git a/scripts/check-freecad-property-acceleration-inventory.mjs b/scripts/check-freecad-property-acceleration-inventory.mjs new file mode 100644 index 0000000..ff825e2 --- /dev/null +++ b/scripts/check-freecad-property-acceleration-inventory.mjs @@ -0,0 +1,24 @@ +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 sourcePath = resolve(root, '.cache/freecad/reference-desktop.json') +const reportPath = resolve(root, 'config/freecad-property-acceleration-inventory.json') +const fail = (message) => { throw new Error(`FreeCAD PropertyAcceleration inventory check failed: ${message}`) } +const [sourceContent, reportContent] = await Promise.all([readFile(sourcePath), readFile(reportPath)]) +const source = JSON.parse(sourceContent) +const report = JSON.parse(reportContent) +const expectedSourceHash = createHash('sha256').update(sourceContent).digest('hex') +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.propertyType !== 'App::PropertyAcceleration' || report.classification !== 'opaque-fcstd-proxy') fail('report boundary is invalid') +if (report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is not locked to FreeCAD 1.1.1') +if (report.source?.path !== '.cache/freecad/reference-desktop.json' || report.source.bytes !== sourceContent.length || report.source.sha256 !== expectedSourceHash) fail('source provenance is stale') +if (report.recordCount !== 1 || !Array.isArray(report.records) || report.records.length !== 1) fail('record count is not exactly one') +const [record] = report.records +if (record.objectTypeId !== 'Robot::TrajectoryDressUpObject' || record.objectAvailable !== true || record.probeStatus !== 'available' || record.propertyName !== 'Acceleration' || record.group !== 'TrajectoryDressUp' || JSON.stringify(record.status) !== '[]' || record.defaultRaw !== '1000.0 mm/s^2') fail('native property inventory changed') +if (record.valueModel?.kind !== 'quantity' || record.valueModel.dimension !== 'length/time^2' || record.valueModel.defaultValue !== 1000 || record.valueModel.defaultUnit !== 'mm/s^2') fail('quantity value model is invalid') +if (!Array.isArray(record.dependencies) || record.dependencies.length !== 0 || record.applicability?.requiredObjectTypeId !== record.objectTypeId) fail('dependencies or applicability are incomplete') +const nativeMatches = [] +for (const objectType of source.runtimeObjects?.types ?? []) for (const property of objectType.properties ?? []) if (property.typeId === 'App::PropertyAcceleration') nativeMatches.push({ objectTypeId: objectType.typeId, propertyName: property.name, group: property.group, status: property.status, defaultRaw: property.default }) +if (nativeMatches.length !== 1 || JSON.stringify(nativeMatches[0]) !== JSON.stringify({ objectTypeId: record.objectTypeId, propertyName: record.propertyName, group: record.group, status: record.status, defaultRaw: record.defaultRaw })) fail('report does not match the locked runtime oracle') +console.log(JSON.stringify({ status: 'freecad-property-acceleration-inventory-pass', propertyType: report.propertyType, recordCount: report.recordCount, objectTypeId: record.objectTypeId, defaultRaw: record.defaultRaw, classification: report.classification }, null, 2)) diff --git a/scripts/check-freecad-property-acceleration-mutation.mjs b/scripts/check-freecad-property-acceleration-mutation.mjs new file mode 100644 index 0000000..75a6704 --- /dev/null +++ b/scripts/check-freecad-property-acceleration-mutation.mjs @@ -0,0 +1,21 @@ +import { readFile } 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-property-acceleration-mutation.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyAcceleration mutation check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-acceleration-mutation' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is invalid') +if (report.object?.name !== 'AccelerationProbe' || report.object.typeId !== 'Robot::TrajectoryDressUpObject' || report.property?.name !== 'Acceleration' || report.property.typeId !== 'App::PropertyAcceleration') fail('native object/property identity changed') +if (!(report.recompute?.initial > 0) || !(report.recompute.edit > 0) || !(report.recompute.restore > 0)) fail('initial, edit and restore were not recomputed') +if (report.touchedAfterEdit?.value?.numeric !== 500 || JSON.stringify(report.touchedAfterEdit.objectState) !== '["Touched"]' || report.touchedAfterEdit.mustExecute !== false) fail('edit did not preserve the native touched/MustExecute state before recompute') +const expectedValues = [['before', 1000], ['edited', 500], ['restored', 1000]] +for (const [phase, expected] of expectedValues) { + const snapshot = report[phase] + if (snapshot?.value?.numeric !== expected || typeof snapshot.value.unit !== 'string' || !snapshot.value.unit.includes('mm/s^2') || JSON.stringify(snapshot.propertyStatus) !== '[]' || JSON.stringify(snapshot.editorMode) !== '[]' || snapshot.source?.name !== 'SourceTrajectory' || snapshot.source.typeId !== 'Robot::TrajectoryObject' || snapshot.useAcceleration !== true || snapshot.shape?.applicable !== false || JSON.stringify(snapshot.objectState) !== '["Up-to-date"]' || snapshot.statusString !== 'Valid' || snapshot.mustExecute !== false) fail(`${phase} native semantic state is invalid`) + if (snapshot.trajectory?.waypointCount !== 2 || snapshot.trajectory.waypoints?.length !== 2 || snapshot.trajectory.waypoints.some((waypoint) => waypoint.acceleration !== expected)) fail(`${phase} waypoint acceleration semantics are invalid`) +} +if (report.before.trajectory.contentSha256 === report.edited.trajectory.contentSha256 || report.before.trajectory.contentSha256 !== report.restored.trajectory.contentSha256) fail('trajectory content did not change and restore exactly') +if (report.source?.preserved !== true || JSON.stringify(report.source.before) !== JSON.stringify(report.source.edited) || JSON.stringify(report.source.before) !== JSON.stringify(report.source.restored)) fail('source trajectory changed during dress-up mutation') +if (report.document?.objectsPreserved !== true || JSON.stringify(report.document.objectsBefore) !== JSON.stringify(report.document.objectsRestored) || report.document.objectsBefore?.length !== 2) fail('mutation polluted the document object set') +if (report.classification?.propertyChanged !== true || report.classification.trajectoryChanged !== true || report.classification.propertyRestored !== true || report.classification.trajectoryRestored !== true || report.classification.semanticStateRestored !== true || report.classification.geometry !== 'not-applicable-no-shape-property') fail('mutation/restore classification is incomplete') +console.log(JSON.stringify({ status: 'freecad-property-acceleration-mutation-pass', recompute: report.recompute, values: Object.fromEntries(expectedValues.map(([phase]) => [phase, report[phase].value.numeric])), waypointAccelerations: Object.fromEntries(expectedValues.map(([phase]) => [phase, report[phase].trajectory.waypoints.map((waypoint) => waypoint.acceleration)])), sourcePreserved: report.source.preserved, semanticStateRestored: report.classification.semanticStateRestored, geometry: report.classification.geometry }, null, 2)) diff --git a/scripts/check-freecad-property-acceleration-promotion.mjs b/scripts/check-freecad-property-acceleration-promotion.mjs new file mode 100644 index 0000000..3e77f0e --- /dev/null +++ b/scripts/check-freecad-property-acceleration-promotion.mjs @@ -0,0 +1,27 @@ +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const [report, semantics, progress, roundTrip, chrome] = await Promise.all([ + load('config/freecad-property-acceleration-promotion.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), + load('config/freecad-property-acceleration-roundtrip.json'), + load('config/chrome-property-acceleration-verification.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyAcceleration promotion check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.taskId !== 'PROP-app-propertyacceleration-I' || report.propertyType !== 'App::PropertyAcceleration' || report.recordCount !== 1 || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.systemExact !== false) fail('promotion report boundary is invalid') +const requiredPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredPhases) { + const taskId = `PROP-app-propertyacceleration-${phase}` + if (!completed.has(taskId) || !Array.isArray(report.phaseEvidence?.[phase]) || report.phaseEvidence[phase].length === 0 || JSON.stringify(report.phaseEvidence[phase]) !== JSON.stringify(completed.get(taskId).evidence)) fail(`phase ${phase} evidence is incomplete`) +} +const propertyType = semantics.types?.find(({ typeId }) => typeId === report.propertyType) +if (report.promotion?.from !== 'opaque-fcstd-proxy' || report.promotion.to !== 'native-editable-codec' || propertyType?.support !== report.promotion.to || report.promotion.facadeValueModel !== 'finite-number-mm/s^2' || report.promotion.fcstdElement !== 'Float' || report.promotion.nativeRoundTripValue !== 500 || report.promotion.browserRoundTripValue !== 500 || report.promotion.zeroUnknownDrift !== true) fail('capability promotion is incomplete') +const sync = report.exactBlockerSync +if (sync?.nativeEditableTypes !== 30 || sync.nativeEditableRecords !== 4361 || sync.opaqueTypes !== 50 || sync.opaqueRecords !== 466 || sync.exactPromotionReady !== false || sync.exactBlocker !== '50 runtime property types and 466 records remain opaque-only; complete native document and property semantics') fail('exact blocker synchronization is stale') +if (JSON.stringify(sync) !== JSON.stringify({ nativeEditableTypes: semantics.supportSummary['native-editable-codec'].typeCount, nativeEditableRecords: semantics.supportSummary['native-editable-codec'].recordCount, opaqueTypes: semantics.supportSummary['opaque-fcstd-proxy'].typeCount, opaqueRecords: semantics.supportSummary['opaque-fcstd-proxy'].recordCount, exactPromotionReady: semantics.exactPromotionReady, exactBlocker: semantics.exactBlocker })) fail('promotion report diverges from global property semantics') +if (roundTrip.classification?.zeroUnknownDrift !== true || chrome.status !== 'pass' || chrome.persistence?.fcstdElement !== 'Float' || chrome.persistence.loadedValue !== 500 || chrome.resource?.released !== true || chrome.release?.workerTerminated !== true) fail('G/H closure evidence regressed') +console.log(JSON.stringify({ status: 'freecad-property-acceleration-promotion-pass', propertyType: report.propertyType, promotion: report.promotion, completedPhases: requiredPhases, exactBlockerSync: sync, systemExact: report.systemExact }, null, 2)) diff --git a/scripts/check-freecad-property-acceleration-roundtrip.mjs b/scripts/check-freecad-property-acceleration-roundtrip.mjs new file mode 100644 index 0000000..de8041e --- /dev/null +++ b/scripts/check-freecad-property-acceleration-roundtrip.mjs @@ -0,0 +1,16 @@ +import { readFile } 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-property-acceleration-roundtrip.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyAcceleration roundtrip check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-acceleration-roundtrip' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is invalid') +for (const phase of ['nativeInitial', 'nativeAfter']) { + const snapshot = phase === 'nativeInitial' ? report.nativeInitial : report.nativeAfter?.reopened + if (snapshot?.object?.typeId !== 'Robot::TrajectoryDressUpObject' || snapshot.object.propertyTypeId !== 'App::PropertyAcceleration' || snapshot.object.source?.typeId !== 'Robot::TrajectoryObject' || snapshot.object.useAcceleration !== true || JSON.stringify(snapshot.object.propertyStatus) !== '[]' || JSON.stringify(snapshot.object.editorMode) !== '[]' || snapshot.object.trajectory?.waypointCount !== 2 || snapshot.sourceTrajectory?.waypointCount !== 2) fail(`${phase} native object semantics are incomplete`) +} +if (report.nativeInitial.object.value.numeric !== 1000 || report.nativeInitial.object.trajectory.waypoints.some((waypoint) => waypoint.acceleration !== 1000) || report.nativeAfter.reopened.object.value.numeric !== 500 || report.nativeAfter.resaved.object.value.numeric !== 500 || report.nativeAfter.reopened.object.trajectory.waypoints.some((waypoint) => waypoint.acceleration !== 500) || report.nativeAfter.resaved.object.trajectory.waypoints.some((waypoint) => waypoint.acceleration !== 500)) fail('native initial/reopen/resave values drifted') +if (report.nativeAfter.reopened.sourceTrajectory.contentSha256 !== report.nativeAfter.resaved.sourceTrajectory.contentSha256 || report.nativeAfter.reopened.object.trajectory.contentSha256 !== report.nativeAfter.resaved.object.trajectory.contentSha256) fail('FreeCAD resave did not preserve native trajectory semantics') +if (report.web.before?.typeId !== 'App::PropertyAcceleration' || report.web.before?.element !== 'Float' || Number(report.web.before?.value) !== 1000 || report.web.after?.typeId !== 'App::PropertyAcceleration' || report.web.after?.element !== 'Float' || report.web.after?.value !== '500' || report.web.objectSetPreserved !== true || report.web.semanticObjectsPreserved !== true || report.web.opaqueEntriesPreserved !== true || !Number.isSafeInteger(report.web.opaquePathsPreserved) || report.web.opaquePathsPreserved < 0) fail('Web edit did not preserve native archive semantics') +if (report.classification?.webValue !== '500' || report.classification.reopenedValue !== 500 || report.classification.resavedValue !== 500 || report.classification.nativeOutputMatches !== true || report.classification.unknownSemanticDrift !== false || report.classification.zeroUnknownDrift !== true) fail('round-trip classification is not exact for PropertyAcceleration') +console.log(JSON.stringify({ status: 'freecad-property-acceleration-roundtrip-pass', values: { nativeInitial: report.nativeInitial.object.value.numeric, webEdited: Number(report.classification.webValue), nativeReopened: report.classification.reopenedValue, nativeResaved: report.classification.resavedValue }, opaquePathsPreserved: report.web.opaquePathsPreserved, semanticObjectsPreserved: report.web.semanticObjectsPreserved, zeroUnknownDrift: report.classification.zeroUnknownDrift }, null, 2)) diff --git a/scripts/check-freecad-property-acceleration-success.mjs b/scripts/check-freecad-property-acceleration-success.mjs new file mode 100644 index 0000000..8b5a6de --- /dev/null +++ b/scripts/check-freecad-property-acceleration-success.mjs @@ -0,0 +1,17 @@ +import { readFile } 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-property-acceleration-success.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyAcceleration success check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-acceleration-success' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is invalid') +if (report.object?.typeId !== 'Robot::TrajectoryDressUpObject' || report.property?.name !== 'Acceleration' || report.property?.typeId !== 'App::PropertyAcceleration' || report.property?.group !== 'TrajectoryDressUp') fail('native object/property identity changed') +if (report.diagnostics?.exception !== null || report.diagnostics?.documentObjectCount !== 1 || report.cases?.length !== 4) fail('native success cases are incomplete') +const byId = new Map(report.cases.map((entry) => [entry.id, entry])) +for (const id of ['default', 'nominal', 'lower-bound', 'negative-boundary']) if (!byId.has(id)) fail(`missing case ${id}`) +for (const entry of report.cases) { + if (entry.typeId !== 'App::PropertyAcceleration' || entry.group !== 'TrajectoryDressUp' || JSON.stringify(entry.status) !== '[]' || JSON.stringify(entry.editorMode) !== '[]' || entry.shape?.applicable !== false || !Array.isArray(entry.objectState)) fail(`${entry.id} native metadata is invalid`) + if (typeof entry.value?.unit !== 'string' || !entry.value.unit.includes('mm/s^2') || typeof entry.value.numeric !== 'number' || !Number.isFinite(entry.value.numeric)) fail(`${entry.id} quantity result is invalid`) +} +if (byId.get('default').value.numeric !== 1000 || byId.get('nominal').value.numeric !== 500 || byId.get('lower-bound').value.numeric !== 0 || byId.get('negative-boundary').value.numeric !== -500) fail('nominal or boundary values changed') +console.log(JSON.stringify({ status: 'freecad-property-acceleration-success-pass', cases: report.cases.length, nominal: byId.get('nominal').value, boundary: [byId.get('lower-bound').value, byId.get('negative-boundary').value] }, null, 2)) diff --git a/scripts/check-freecad-property-area-failure.mjs b/scripts/check-freecad-property-area-failure.mjs new file mode 100644 index 0000000..85dfe1f --- /dev/null +++ b/scripts/check-freecad-property-area-failure.mjs @@ -0,0 +1,44 @@ +import { readFile } 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-property-area-failure.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyArea failure check failed: ${message}`) } +const same = (left, right) => JSON.stringify(left) === JSON.stringify(right) + +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-area-failure' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is invalid') +if (report.object?.name !== 'AreaProbe' || report.object.typeId !== 'Measure::MeasureArea' || report.property?.name !== 'Area' || report.property.typeId !== 'App::PropertyArea' || report.input?.name !== 'Elements' || report.input.typeId !== 'App::PropertyLinkSubList') fail('native object/property identity changed') +if (report.initial?.numeric !== 10 || report.initial.statusString !== 'Valid' || !same(report.initial.state, ['Up-to-date']) || report.failures?.length !== 2) fail('initial state or failure case set changed') + +const expectedFailures = new Map([ + ['unsupported-point', { name: 'AreaPoint', subElement: 'Vertex1', shapeType: 'Vertex' }], + ['unsupported-line', { name: 'AreaLine', subElement: 'Edge1', shapeType: 'Edge' }], +]) +for (const entry of report.failures) { + const expected = expectedFailures.get(entry.id) + if (!expected || entry.source?.name !== expected.name || entry.source.typeId !== 'Part::Feature' || entry.source.subElement !== expected.subElement || entry.source.shapeType !== expected.shapeType) fail(`${entry.id} source fixture changed`) + if (entry.expectedDiagnostic !== 'Cannot calculate area' || entry.assignmentException !== null || entry.recomputeException !== null || entry.recomputeResult !== true) fail(`${entry.id} native failure phase changed`) + if (entry.after?.numeric !== 10 || entry.after.statusString !== 'Cannot calculate area' || !same(entry.after.state, ['Touched', 'Invalid']) || !same(entry.after.elements, [{ object: expected.name, subElements: [expected.subElement] }])) fail(`${entry.id} did not enter the locked invalid state`) + if (entry.valuePreserved !== true || entry.objectsPreserved !== true || entry.recoveredExactly !== true || entry.recovered?.numeric !== 10 || entry.recovered.statusString !== 'Valid' || !same(entry.recovered.state, ['Up-to-date']) || !same(entry.recovered.elements, entry.before.elements) || !same(entry.beforeObjects, entry.afterObjects)) fail(`${entry.id} did not recover without document pollution`) +} + +const disabled = report.disabled +if (disabled?.classification !== 'editor-readonly-python-mutable-until-immutable' || disabled.editorReadOnlyRequested !== '20 mm^2' || disabled.immutableRequested !== '30 mm^2' || !same(disabled.propertyStatus, ['24', '27']) || !same(disabled.editorMode, ['ReadOnly'])) fail('read-only property boundary changed') +if (disabled.editorReadOnlyException !== null || disabled.pythonBypassesEditorReadOnly !== true || disabled.editorReadOnlyAfter?.numeric !== 20 || !disabled.immutableStatus?.includes('Immutable') || disabled.immutableException?.type !== 'AttributeError' || disabled.immutableException.message !== "Object attribute 'Area' is read-only") fail('editor read-only and Immutable behavior changed') +if (disabled.immutableAfter?.numeric !== 20 || disabled.immutableValuePreserved !== true || disabled.valueRestored !== true || disabled.restored?.numeric !== 10 || disabled.restored.statusString !== 'Valid' || disabled.objectsPreserved !== true || !same(disabled.restoredStatus, ['24', '27']) || !same(disabled.restoredEditorMode, ['ReadOnly'])) fail('disabled state did not restore cleanly') + +const transaction = report.transaction +if (transaction?.undoMode !== 1 || transaction.pendingAfterEdit !== true || transaction.pendingAfterAbort !== false || transaction.activeAfterEdit?.name !== 'property-area-cancel' || !(transaction.activeAfterEdit.id > 0) || transaction.activeAfterAbort?.name !== '' || transaction.activeAfterAbort?.id !== 0) fail('transaction lifecycle changed') +if (transaction.before?.numeric !== 10 || transaction.edited?.numeric !== 75.398223877 || transaction.afterAbort?.numeric !== 10 || transaction.afterRecompute?.numeric !== 10 || transaction.afterAbort.statusString !== 'Touched' || transaction.afterRecompute.statusString !== 'Valid' || transaction.restored !== true || transaction.objectsRestored !== true || !same(transaction.before.elements, transaction.afterRecompute.elements) || !same(transaction.objectsBefore, transaction.objectsAfter)) fail('transaction abort did not restore Elements and derived Area') + +if (report.cancellationBoundary?.supported !== false || report.cancellationBoundary.classification !== 'synchronous-measure-recompute' || report.cancellationBoundary.reason !== 'no-native-cancel-hook' || report.cancellationBoundary.replacement !== 'abort-active-document-transaction') fail('cancellation boundary is not explicit') +if (report.documentIntegrity?.objectsPreserved !== true || report.documentIntegrity.objectCount !== 5 || !same(report.documentIntegrity.initialObjects, report.documentIntegrity.finalObjects)) fail('failure, disabled or cancellation cases polluted the document') + +console.log(JSON.stringify({ + status: 'freecad-property-area-failure-pass', + failures: report.failures.map(({ id, after }) => ({ id, state: after.state, diagnostic: after.statusString })), + disabled: { editorMode: disabled.editorMode, pythonBypassesEditorReadOnly: disabled.pythonBypassesEditorReadOnly, immutableException: disabled.immutableException }, + transactionRestored: transaction.restored, + documentObjectsPreserved: report.documentIntegrity.objectsPreserved, + cancellationBoundary: report.cancellationBoundary, +}, null, 2)) diff --git a/scripts/check-freecad-property-area-inventory.mjs b/scripts/check-freecad-property-area-inventory.mjs new file mode 100644 index 0000000..c157977 --- /dev/null +++ b/scripts/check-freecad-property-area-inventory.mjs @@ -0,0 +1,25 @@ +import { createHash } from 'node:crypto' +import { readFile } 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-property-area-inventory.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyArea inventory check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyArea' || report.recordCount !== 1 || report.classification !== 'opaque-fcstd-proxy') fail('report boundary is invalid') +const [record] = report.records ?? [] +if (record?.objectTypeId !== 'Measure::MeasureArea' || record.objectAvailable !== true || record.probeStatus !== 'available' || record.propertyName !== 'Area' || record.group !== 'Measurement' || JSON.stringify(record.status) !== JSON.stringify([24, 27]) || JSON.stringify(record.normalizedStatus) !== JSON.stringify(['PropReadOnly', 'PropOutput']) || record.defaultRaw !== '0.0 mm^2') fail('native property identity or status changed') +if (record.valueModel?.kind !== 'quantity' || record.valueModel.dimension !== 'length^2' || record.valueModel.defaultValue !== 0 || record.valueModel.defaultUnit !== 'mm^2' || record.valueModel.derived !== true || record.valueModel.writable !== false) fail('area value model is invalid') +const [input] = record.inputs ?? [] +if (input?.propertyName !== 'Elements' || input.typeId !== 'App::PropertyLinkSubList' || input.group !== 'Measurement' || JSON.stringify(input.defaultValue) !== '[]' || input.scope !== 'Global' || input.allowExternal !== true || input.cardinality !== 'one-or-more') fail('native input contract is incomplete') +const [dependency] = record.dependencies ?? [] +if (dependency?.sourceProperty !== 'Elements' || dependency.targetProperty !== 'Area' || dependency.relation !== 'link-sub-list' || dependency.effect !== 'immediate-recompute-on-change') fail('dependency contract is incomplete') +const applicability = record.applicability +if (applicability?.selectionMustBeNonEmpty !== true || applicability.everyElementMustBeValid !== true || JSON.stringify(applicability.supportedMeasureElementTypes) !== JSON.stringify(['PLANE', 'CYLINDER', 'SURFACE', 'VOLUME']) || JSON.stringify(applicability.unsupportedMeasureElementTypes) !== JSON.stringify(['INVALID', 'POINT', 'LINE', 'CURVE']) || applicability.externalDocumentElementsAllowed !== true) fail('selection applicability is incomplete') +if (record.execution?.aggregation !== 'sum-area' || record.execution.resultProperty !== 'Area' || record.execution.invalidGeometryDiagnostic !== 'Cannot calculate area' || record.execution.shape !== 'not-applicable-derived-measurement') fail('execution contract is incomplete') +for (const locked of [report.provenance?.runtime, ...(report.provenance?.sources ?? [])]) { + const content = await readFile(resolve(root, locked?.path ?? '')) + if (content.length !== locked.bytes || createHash('sha256').update(content).digest('hex') !== locked.sha256) fail(`provenance is stale for ${locked.path}`) +} +const sourceText = await readFile(resolve(root, '.cache/freecad/FreeCAD/src/Mod/Measure/App/MeasureArea.cpp'), 'utf8') +if (!sourceText.includes('Elements.setScope(App::LinkScope::Global)') || !sourceText.includes('Elements.setAllowExternal(true)') || !sourceText.includes('App::Prop_ReadOnly | App::Prop_Output') || !sourceText.includes('Cannot calculate area')) fail('locked native source no longer exposes the recorded contract') +console.log(JSON.stringify({ status: 'freecad-property-area-inventory-pass', propertyType: report.propertyType, objectTypeId: record.objectTypeId, defaultRaw: record.defaultRaw, statusNames: record.normalizedStatus, input: record.inputs[0], applicability: record.applicability, execution: record.execution }, null, 2)) diff --git a/scripts/check-freecad-property-area-mutation.mjs b/scripts/check-freecad-property-area-mutation.mjs new file mode 100644 index 0000000..0dfa610 --- /dev/null +++ b/scripts/check-freecad-property-area-mutation.mjs @@ -0,0 +1,49 @@ +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' +import { isDeepStrictEqual } from 'node:util' + +const root = resolve(new URL('..', import.meta.url).pathname) +const report = JSON.parse(await readFile(resolve(root, 'config/freecad-property-area-mutation.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyArea mutation check failed: ${message}`) } +const same = isDeepStrictEqual +const near = (left, right, tolerance = 2e-6) => Math.abs(left - right) <= tolerance + +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-area-mutation' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is invalid') +if (report.object?.name !== 'AreaProbe' || report.object.typeId !== 'Measure::MeasureArea' || report.property?.name !== 'Area' || report.property.typeId !== 'App::PropertyArea' || report.input?.name !== 'Elements' || report.input.typeId !== 'App::PropertyLinkSubList') fail('native object/property identity changed') +if (!(report.recompute?.initial > 0) || !(report.recompute.edit > 0) || !(report.recompute.restore > 0)) fail('initial, edit and restore were not recomputed') + +const nominalElements = [{ object: 'AreaBox', typeId: 'Part::Box', subElements: ['Face1'] }] +const editedElements = [ + { object: 'AreaBox', typeId: 'Part::Box', subElements: ['Face1', 'Face2'] }, + { object: 'AreaCylinder', typeId: 'Part::Cylinder', subElements: ['Face1'] }, +] +for (const [phase, expectedValue, expectedElements] of [ + ['before', 10, nominalElements], + ['edited', 95.398223877, editedElements], + ['restored', 10, nominalElements], +]) { + const snapshot = report[phase] + if (!near(snapshot?.value?.numeric, expectedValue) || typeof snapshot.value.unit !== 'string' || !snapshot.value.unit.includes('mm^2') || !same(snapshot.elements, expectedElements)) fail(`${phase} value or Elements changed`) + if (!same(snapshot.propertyStatus, ['24', '27']) || !same(snapshot.editorMode, ['ReadOnly']) || snapshot.shape?.applicable !== false || !same(snapshot.objectState, ['Up-to-date']) || snapshot.statusString !== 'Valid' || snapshot.mustExecute !== false) fail(`${phase} native semantic state is invalid`) +} + +for (const [phase, expectedElements] of [['touchedAfterEdit', editedElements], ['touchedAfterRestore', nominalElements]]) { + const snapshot = report[phase] + if (!same(snapshot?.elements, expectedElements) || !same(snapshot.objectState, ['Touched']) || snapshot.mustExecute !== false) fail(`${phase} did not preserve the native dirty state before recompute`) +} +if (!near(report.touchedAfterEdit.value?.numeric, 95.398223877) || report.touchedAfterRestore.value?.numeric !== 10) fail('derived Area was not updated synchronously with Elements') + +if (report.sources?.preserved !== true || !same(report.sources.before, report.sources.edited) || !same(report.sources.before, report.sources.restored) || report.sources.before?.length !== 2) fail('source geometry changed during Elements mutation') +for (const source of report.sources.before) if (source.valid !== true || source.shapeType !== 'Solid' || source.solids !== 1 || !(source.faces > 0) || !(source.area > 0) || !(source.volume > 0)) fail(`${source.name} source Shape evidence is invalid`) +if (report.document?.objectsPreserved !== true || !same(report.document.objectsBefore, report.document.objectsRestored) || report.document.objectsBefore?.length !== 3) fail('mutation polluted the document object set') +if (report.classification?.inputChanged !== true || report.classification.derivedValueChanged !== true || report.classification.inputRestored !== true || report.classification.derivedValueRestored !== true || report.classification.semanticStateRestored !== true || report.classification.sourceGeometryPreserved !== true || report.classification.geometry !== 'source-shapes-preserved-derived-measurement-has-no-shape') fail('mutation/restore classification is incomplete') + +console.log(JSON.stringify({ + status: 'freecad-property-area-mutation-pass', + recompute: report.recompute, + values: { before: report.before.value.numeric, edited: report.edited.value.numeric, restored: report.restored.value.numeric }, + elements: { before: report.before.elements, edited: report.edited.elements, restored: report.restored.elements }, + sourceGeometryPreserved: report.sources.preserved, + semanticStateRestored: report.classification.semanticStateRestored, + geometry: report.classification.geometry, +}, null, 2)) diff --git a/scripts/check-freecad-property-area-promotion.mjs b/scripts/check-freecad-property-area-promotion.mjs new file mode 100644 index 0000000..627b59b --- /dev/null +++ b/scripts/check-freecad-property-area-promotion.mjs @@ -0,0 +1,27 @@ +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const [report, semantics, progress, roundTrip, chrome] = await Promise.all([ + load('config/freecad-property-area-promotion.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), + load('config/freecad-property-area-roundtrip.json'), + load('config/chrome-property-area-verification.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyArea promotion check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.taskId !== 'PROP-app-propertyarea-I' || report.propertyType !== 'App::PropertyArea' || report.recordCount !== 1 || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.systemExact !== false) fail('promotion report boundary is invalid') +const requiredPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredPhases) { + const taskId = `PROP-app-propertyarea-${phase}` + if (!completed.has(taskId) || !Array.isArray(report.phaseEvidence?.[phase]) || report.phaseEvidence[phase].length === 0 || JSON.stringify(report.phaseEvidence[phase]) !== JSON.stringify(completed.get(taskId).evidence)) fail(`phase ${phase} evidence is incomplete`) +} +const propertyType = semantics.types?.find(({ typeId }) => typeId === report.propertyType) +if (report.promotion?.from !== 'opaque-fcstd-proxy' || report.promotion.to !== 'native-editable-codec' || propertyType?.support !== report.promotion.to || propertyType.statusNames?.join(',') !== 'PropOutput,PropReadOnly' || report.promotion.facadeValueModel !== 'read-only-derived-mm^2-with-link-sub-list-input' || report.promotion.inputType !== 'App::PropertyLinkSubList' || report.promotion.fcstdAreaElement !== 'Float' || report.promotion.fcstdElementsElement !== 'LinkSubList' || report.promotion.nativeRoundTripArea !== 20 || report.promotion.browserRoundTripArea !== 0 || report.promotion.browserRoundTripElementCount !== 0 || report.promotion.sourceGeometryPreserved !== true || report.promotion.zeroUnknownDrift !== true) fail('capability promotion is incomplete') +const sync = report.exactBlockerSync +if (sync?.nativeEditableTypes !== 30 || sync.nativeEditableRecords !== 4361 || sync.opaqueTypes !== 50 || sync.opaqueRecords !== 466 || sync.exactPromotionReady !== false || sync.exactBlocker !== '50 runtime property types and 466 records remain opaque-only; complete native document and property semantics') fail('exact blocker synchronization is stale') +if (JSON.stringify(sync) !== JSON.stringify({ nativeEditableTypes: semantics.supportSummary['native-editable-codec'].typeCount, nativeEditableRecords: semantics.supportSummary['native-editable-codec'].recordCount, opaqueTypes: semantics.supportSummary['opaque-fcstd-proxy'].typeCount, opaqueRecords: semantics.supportSummary['opaque-fcstd-proxy'].recordCount, exactPromotionReady: semantics.exactPromotionReady, exactBlocker: semantics.exactBlocker })) fail('promotion report diverges from global property semantics') +if (roundTrip.classification?.zeroUnknownDrift !== true || roundTrip.classification.sourceGeometryPreserved !== true || chrome.status !== 'pass' || chrome.ui?.areaReadOnly !== true || chrome.persistence?.fcstdAreaElement !== 'Float' || chrome.persistence.fcstdElementsElement !== 'LinkSubList' || chrome.persistence.loadedArea !== 0 || chrome.persistence.loadedElementCount !== 0 || chrome.resource?.released !== true || chrome.release?.workerTerminated !== true) fail('G/H closure evidence regressed') +console.log(JSON.stringify({ status: 'freecad-property-area-promotion-pass', propertyType: report.propertyType, promotion: report.promotion, completedPhases: requiredPhases, exactBlockerSync: sync, systemExact: report.systemExact }, null, 2)) diff --git a/scripts/check-freecad-property-area-roundtrip.mjs b/scripts/check-freecad-property-area-roundtrip.mjs new file mode 100644 index 0000000..eb77214 --- /dev/null +++ b/scripts/check-freecad-property-area-roundtrip.mjs @@ -0,0 +1,30 @@ +import { createHash } from 'node:crypto' +import { readFile, stat } from 'node:fs/promises' +import { resolve } from 'node:path' +import { isDeepStrictEqual } from 'node:util' + +const root = resolve(new URL('..', import.meta.url).pathname) +const report = JSON.parse(await readFile(resolve(root, 'config/freecad-property-area-roundtrip.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyArea roundtrip check failed: ${message}`) } +const same = isDeepStrictEqual + +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-area-roundtrip' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is invalid') +for (const phase of ['nativeInitial', 'nativeReopened', 'nativeResaved']) { + const snapshot = phase === 'nativeInitial' ? report.nativeInitial : phase === 'nativeReopened' ? report.nativeAfter?.reopened : report.nativeAfter?.resaved + if (!same(snapshot?.objectSet, [{ name: 'AreaBox', typeId: 'Part::Box' }, { name: 'AreaProbe', typeId: 'Measure::MeasureArea' }]) || snapshot.source?.valid !== true || snapshot.source.shapeType !== 'Solid' || snapshot.source.solids !== 1 || snapshot.source.faces !== 6 || snapshot.source.edges !== 12 || snapshot.source.vertices !== 8 || snapshot.source.volume !== 100 || snapshot.source.area !== 160 || !same(snapshot.source.bounds, [0, 0, 0, 10, 5, 2])) fail(`${phase} source geometry is invalid`) + if (snapshot.measure?.typeId !== 'Measure::MeasureArea' || snapshot.measure.areaTypeId !== 'App::PropertyArea' || snapshot.measure.elementsTypeId !== 'App::PropertyLinkSubList' || !same(snapshot.measure.propertyStatus, ['24', '27']) || !same(snapshot.measure.editorMode, ['ReadOnly']) || snapshot.measure.shape?.applicable !== false || !same(snapshot.measure.state, ['Up-to-date']) || snapshot.measure.statusString !== 'Valid') fail(`${phase} native MeasureArea semantics are incomplete`) +} +if (report.nativeInitial.measure.area.numeric !== 10 || !same(report.nativeInitial.measure.elements, [{ object: 'AreaBox', typeId: 'Part::Box', subElements: ['Face1'] }])) fail('native initial measurement changed') +for (const snapshot of [report.nativeAfter.reopened, report.nativeAfter.resaved]) if (snapshot.measure.area.numeric !== 20 || !same(snapshot.measure.elements, [{ object: 'AreaBox', typeId: 'Part::Box', subElements: ['Face1', 'Face2'] }])) fail('FreeCAD did not recompute and preserve the Web-edited measurement') +if (!same(report.nativeInitial.source, report.nativeAfter.reopened.source) || !same(report.nativeInitial.source, report.nativeAfter.resaved.source)) fail('source Shape changed during measurement round-trip') + +if (report.web.before?.area?.typeId !== 'App::PropertyArea' || report.web.before.area.element !== 'Float' || Number(report.web.before.area.value) !== 10 || report.web.before.elements?.typeId !== 'App::PropertyLinkSubList' || report.web.before.elements.element !== 'LinkSubList' || report.web.before.elements.linkSubs?.length !== 1) fail('Web could not decode the native initial properties') +if (report.web.after?.area?.typeId !== 'App::PropertyArea' || report.web.after.area.element !== 'Float' || Number(report.web.after.area.value) !== 20 || report.web.after.elements?.typeId !== 'App::PropertyLinkSubList' || report.web.after.elements.element !== 'LinkSubList' || !same(report.web.after.elements.linkSubs, [{ objectId: 'AreaBox', subElement: 'Face1' }, { objectId: 'AreaBox', subElement: 'Face2' }])) fail('Web edit did not encode the target properties') +if (report.web.objectSetPreserved !== true || report.web.semanticObjectsPreserved !== true || report.web.opaqueEntriesPreserved !== true || !Number.isSafeInteger(report.web.opaquePathsPreserved) || report.web.opaquePathsPreserved < 1) fail('Web edit did not preserve native archive semantics and resources') +if (report.classification?.webArea !== 20 || report.classification.webElementCount !== 2 || report.classification.reopenedArea !== 20 || report.classification.resavedArea !== 20 || report.classification.nativeOutputMatches !== true || report.classification.sourceGeometryPreserved !== true || report.classification.unknownSemanticDrift !== false || report.classification.zeroUnknownDrift !== true) fail('round-trip classification is not exact for PropertyArea') +for (const archive of Object.values(report.archives ?? {})) { + const path = resolve(root, archive.path ?? '') + const content = await readFile(path) + if ((await stat(path)).size !== archive.bytes || createHash('sha256').update(content).digest('hex') !== archive.sha256) fail(`archive is stale: ${archive.path}`) +} +console.log(JSON.stringify({ status: 'freecad-property-area-roundtrip-pass', values: { nativeInitial: report.nativeInitial.measure.area.numeric, webEdited: report.classification.webArea, nativeReopened: report.classification.reopenedArea, nativeResaved: report.classification.resavedArea }, elements: { initial: 1, edited: report.classification.webElementCount }, opaquePathsPreserved: report.web.opaquePathsPreserved, sourceGeometryPreserved: report.classification.sourceGeometryPreserved, zeroUnknownDrift: report.classification.zeroUnknownDrift }, null, 2)) diff --git a/scripts/check-freecad-property-area-success.mjs b/scripts/check-freecad-property-area-success.mjs new file mode 100644 index 0000000..95a0efe --- /dev/null +++ b/scripts/check-freecad-property-area-success.mjs @@ -0,0 +1,25 @@ +import { readFile } 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-property-area-success.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyArea success check failed: ${message}`) } +const near = (left, right, tolerance = 2e-6) => Math.abs(left - right) <= tolerance +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-area-success' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is invalid') +if (report.object?.typeId !== 'Measure::MeasureArea' || report.property?.name !== 'Area' || report.property.typeId !== 'App::PropertyArea' || report.property.group !== 'Measurement' || report.input?.name !== 'Elements' || report.input.typeId !== 'App::PropertyLinkSubList' || report.input.group !== 'Measurement') fail('native object/property identity changed') +if (report.diagnostics?.exception !== null || report.diagnostics.documentObjectCount !== 4 || report.sources?.length !== 3 || report.cases?.length !== 6) fail('native success cases are incomplete') +const expectedIds = ['empty-default', 'planar-face', 'cylindrical-face', 'surface-face', 'solid-volume', 'multi-element-sum'] +const byId = new Map(report.cases.map((entry) => [entry.id, entry])) +for (const id of expectedIds) if (!byId.has(id)) fail(`missing case ${id}`) +for (const entry of report.cases) { + if (entry.areaTypeId !== 'App::PropertyArea' || entry.elementsTypeId !== 'App::PropertyLinkSubList' || JSON.stringify(entry.propertyStatus) !== JSON.stringify(['24', '27']) || JSON.stringify(entry.editorMode) !== JSON.stringify(['ReadOnly']) || entry.shape?.applicable !== false || entry.object?.typeId !== 'Measure::MeasureArea' || JSON.stringify(entry.object.state) !== JSON.stringify(['Up-to-date']) || entry.object.status !== 'Valid') fail(`${entry.id} native metadata is invalid`) + if (typeof entry.value?.numeric !== 'number' || !Number.isFinite(entry.value.numeric) || !String(entry.value.unit).includes('mm^2') || !near(entry.value.numeric, entry.expectedArea)) fail(`${entry.id} area did not match source Shape evidence`) + for (const element of entry.elements ?? []) if (element.shapeNull !== false || element.shapeValid !== true || !(element.area > 0) || !['Face', 'Solid'].includes(element.shapeType)) fail(`${entry.id} contains invalid source geometry evidence`) +} +if (byId.get('empty-default').value.numeric !== 0 || byId.get('empty-default').elements.length !== 0) fail('empty default boundary changed') +if (byId.get('planar-face').elements[0]?.shapeType !== 'Face' || !near(byId.get('planar-face').value.numeric, 10)) fail('planar face evidence changed') +if (byId.get('cylindrical-face').elements[0]?.shapeType !== 'Face' || !(byId.get('cylindrical-face').value.numeric > 0)) fail('cylindrical face evidence changed') +if (byId.get('surface-face').elements[0]?.shapeType !== 'Face' || !(byId.get('surface-face').value.numeric > 0)) fail('surface face evidence changed') +if (byId.get('solid-volume').elements[0]?.shapeType !== 'Solid' || !near(byId.get('solid-volume').value.numeric, 160)) fail('solid volume surface-area evidence changed') +if (byId.get('multi-element-sum').elements.length !== 3 || !near(byId.get('multi-element-sum').value.numeric, byId.get('multi-element-sum').elements.reduce((total, element) => total + element.area, 0))) fail('multi-element sum evidence changed') +console.log(JSON.stringify({ status: 'freecad-property-area-success-pass', cases: expectedIds, values: Object.fromEntries(expectedIds.map((id) => [id, byId.get(id).value.numeric])), propertyStatus: byId.get('planar-face').propertyStatus, shapeApplicable: false }, null, 2)) diff --git a/scripts/check-freecad-property-boollist-failure.mjs b/scripts/check-freecad-property-boollist-failure.mjs new file mode 100644 index 0000000..0891f2f --- /dev/null +++ b/scripts/check-freecad-property-boollist-failure.mjs @@ -0,0 +1,39 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-boollist-failure.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyBoolList failure check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-boollist-failure' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyBoolList') fail('baseline is invalid') +const writable = report.writable +if (writable?.object?.typeId !== 'App::FeatureTest' || writable.property?.typeId !== 'App::PropertyBoolList' || !isDeepStrictEqual(writable.initial, [false])) fail('writable fixture identity changed') +const accepted = new Map(writable.acceptedCoercions?.map((entry) => [entry.id, entry]) ?? []) +if (accepted.size !== 2 || accepted.get('scalar-integer')?.requested !== '7' || accepted.get('scalar-integer').exception !== null || !isDeepStrictEqual(accepted.get('scalar-integer').after, [true]) || accepted.get('bitstring')?.requested !== "'10201'" || accepted.get('bitstring').exception !== null || !isDeepStrictEqual(accepted.get('bitstring').after, [true, false, false, false, true]) || ![...accepted.values()].every((entry) => entry.objectsPreserved === true && isDeepStrictEqual(entry.beforeObjects, entry.afterObjects))) fail('native accepted coercion partition changed') +const expectedFailures = new Map([ + ['none', { requested: 'None', message: 'type in list must be bool or int, not NoneType' }], + ['float-item', { requested: '[True, 1.5]', message: 'type in list must be bool or int, not float' }], + ['string-item', { requested: "[False, 'bad']", message: 'type in list must be bool or int, not str' }], +]) +if (writable.failures?.length !== expectedFailures.size) fail('failure case count changed') +for (const entry of writable.failures) { + const expected = expectedFailures.get(entry.id) + if (!expected || entry.requested !== expected.requested || entry.exception?.type !== 'TypeError' || entry.exception.message !== expected.message || entry.valuePreserved !== true || entry.objectsPreserved !== true || entry.polluted !== false || !isDeepStrictEqual(entry.before, [false]) || !isDeepStrictEqual(entry.after, [false]) || !isDeepStrictEqual(entry.beforeObjects, entry.afterObjects)) fail(`${entry.id} did not reject without pollution`) +} +const disabled = writable.disabled +if (disabled?.classification !== 'editor-read-only-and-python-immutable' || !isDeepStrictEqual(disabled.requested, [true, false]) || !isDeepStrictEqual(disabled.status, ['Immutable', 'ReadOnly']) || !isDeepStrictEqual(disabled.editorMode, ['ReadOnly']) || disabled.exception?.type !== 'AttributeError' || disabled.exception.message !== "Object attribute 'BoolList' is read-only" || disabled.valuePreserved !== true || disabled.objectsPreserved !== true || !isDeepStrictEqual(disabled.before, [false]) || !isDeepStrictEqual(disabled.after, [false]) || !isDeepStrictEqual(disabled.restoredStatus, []) || !isDeepStrictEqual(disabled.restoredEditorMode, [])) fail('disabled state did not reject and restore cleanly') +const transaction = writable.transaction +if (transaction?.undoMode !== 1 || transaction.pendingAfterEdit !== true || transaction.pendingAfterAbort !== false || transaction.activeAfterEdit?.name !== 'property-boollist-cancel' || !(transaction.activeAfterEdit.id > 0) || transaction.activeAfterAbort?.name !== '' || transaction.activeAfterAbort.id !== 0 || transaction.restored !== true || transaction.objectsRestored !== true || !isDeepStrictEqual(transaction.before, [false]) || !isDeepStrictEqual(transaction.edited, [true, false, true]) || !isDeepStrictEqual(transaction.afterAbort, [false]) || !isDeepStrictEqual(transaction.objectsBefore, transaction.objectsAfter)) fail('writable transaction abort did not restore') +if (writable.documentIntegrity?.objectsPreserved !== true || !isDeepStrictEqual(writable.documentIntegrity.initialObjects, writable.documentIntegrity.finalObjects)) fail('writable failures polluted the document') + +const linkTypes = ['App::Link', 'App::LinkGroup', 'App::LinkGroupPython', 'App::LinkPython'] +if (report.links?.length !== linkTypes.length || new Set(report.links.map(({ objectTypeId }) => objectTypeId)).size !== linkTypes.length) fail('Link failure inventory changed') +for (const typeId of linkTypes) { + const entry = report.links.find((candidate) => candidate.objectTypeId === typeId) + if (entry?.propertyTypeId !== 'App::PropertyBoolList' || !isDeepStrictEqual(entry.initial, [true, true]) || !isDeepStrictEqual(entry.status, ['Immutable', 'Hidden', 'LockDynamic']) || !isDeepStrictEqual(entry.editorMode, ['Hidden']) || entry.directWrite?.exception?.type !== 'AttributeError' || entry.directWrite.exception.message !== "Object attribute 'VisibilityList' is read-only" || entry.directWrite.preserved !== true || !isDeepStrictEqual(entry.directWrite.after, [true, true])) fail(`${typeId} immutable rejection changed`) + if (entry.invalidElement?.name !== 'MissingElement' || entry.invalidElement.result !== -1 || entry.invalidElement.preserved !== true || !isDeepStrictEqual(entry.invalidElement.after, [true, true])) fail(`${typeId} invalid element rejection changed`) + const linkTransaction = entry.transaction + if (linkTransaction?.hideResult !== 1 || !isDeepStrictEqual(linkTransaction.before, [true, true]) || !isDeepStrictEqual(linkTransaction.edited, [false, true]) || !isDeepStrictEqual(linkTransaction.afterAbort, [true, true]) || linkTransaction.pendingAfterEdit !== true || linkTransaction.pendingAfterAbort !== false || linkTransaction.activeAfterEdit?.name !== 'property-boollist-link-cancel' || !(linkTransaction.activeAfterEdit.id > 0) || linkTransaction.activeAfterAbort?.name !== '' || linkTransaction.activeAfterAbort.id !== 0 || linkTransaction.restored !== true || !isDeepStrictEqual(linkTransaction.stateAfterAbort, ['Touched']) || linkTransaction.statusAfterAbort !== 'Touched' || linkTransaction.recoveryRecomputeResult !== true || !isDeepStrictEqual(linkTransaction.stateAfterRecovery, ['Up-to-date']) || linkTransaction.statusAfterRecovery !== 'Valid' || !isDeepStrictEqual(entry.objectState, ['Up-to-date']) || entry.statusString !== 'Valid' || entry.objectsPreserved !== true || !isDeepStrictEqual(entry.objectsBefore, entry.objectsAfter)) fail(`${typeId} transaction rollback changed`) +} +if (report.cancellationBoundary?.supported !== false || report.cancellationBoundary.classification !== 'synchronous-property-setter-and-link-extension' || report.cancellationBoundary.reason !== 'no-native-cancel-hook' || report.cancellationBoundary.replacement !== 'abort-active-document-transaction') fail('cancellation boundary is not explicit') +console.log(JSON.stringify({ status: 'freecad-property-boollist-failure-pass', acceptedCoercions: [...accepted.values()].map(({ id, requested, after }) => ({ id, requested, after })), failures: writable.failures.map(({ id, exception }) => ({ id, exception })), disabled: { status: disabled.status, editorMode: disabled.editorMode, exception: disabled.exception }, writableTransactionRestored: transaction.restored, linkTransactionsRestored: report.links.every(({ transaction }) => transaction.restored), cancellationBoundary: report.cancellationBoundary }, null, 2)) diff --git a/scripts/check-freecad-property-boollist-inventory.mjs b/scripts/check-freecad-property-boollist-inventory.mjs new file mode 100644 index 0000000..50818c7 --- /dev/null +++ b/scripts/check-freecad-property-boollist-inventory.mjs @@ -0,0 +1,32 @@ +import { createHash } from 'node:crypto' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const sourcePath = resolve(root, '.cache/freecad/reference-desktop.json') +const reportPath = resolve(root, 'config/freecad-property-boollist-inventory.json') +const fail = (message) => { throw new Error(`FreeCAD PropertyBoolList inventory check failed: ${message}`) } +const [sourceContent, reportContent] = await Promise.all([readFile(sourcePath), readFile(reportPath)]) +const source = JSON.parse(sourceContent) +const report = JSON.parse(reportContent) +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.propertyType !== 'App::PropertyBoolList' || report.classification !== 'opaque-fcstd-proxy') fail('report boundary is invalid') +if (report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is not locked to FreeCAD 1.1.1') +if (report.source?.path !== '.cache/freecad/reference-desktop.json' || report.source.bytes !== sourceContent.length || report.source.sha256 !== createHash('sha256').update(sourceContent).digest('hex')) fail('source provenance is stale') +if (report.recordCount !== 7 || !Array.isArray(report.records) || report.records.length !== 7) fail('record count is not exactly seven') +const expected = [ + ['App::FeatureTest', 'BoolList', '', [], [false]], + ['App::FeatureTestException', 'BoolList', '', [], [false]], + ['App::Link', 'VisibilityList', ' Link', ['Immutable', 'Hidden', 'LockDynamic'], []], + ['App::LinkGroup', 'VisibilityList', ' Link', ['Immutable', 'Hidden', 'LockDynamic'], []], + ['App::LinkGroupPython', 'VisibilityList', ' Link', ['Immutable', 'Hidden', 'LockDynamic'], []], + ['App::LinkPython', 'VisibilityList', ' Link', ['Immutable', 'Hidden', 'LockDynamic'], []], + ['Surface::GeomFillSurface', 'ReversedList', '', [], [false]], +] +for (const [objectTypeId, propertyName, group, status, defaultValue] of expected) { + const record = report.records.find((candidate) => candidate.objectTypeId === objectTypeId && candidate.propertyName === propertyName) + if (!record || record.objectAvailable !== true || record.probeStatus !== 'available' || record.group !== group || JSON.stringify(record.status) !== JSON.stringify(status) || JSON.stringify(record.defaultValue) !== JSON.stringify(defaultValue) || record.valueModel?.kind !== 'boolean-list' || record.valueModel.elementType !== 'bool' || record.valueModel.cardinality !== 'variable' || !Array.isArray(record.dependencies) || record.dependencies.length !== 0 || record.applicability?.requiredObjectTypeId !== record.objectTypeId) fail(`native inventory changed for ${objectTypeId}.${propertyName}`) +} +const nativeMatches = [] +for (const objectType of source.runtimeObjects?.types ?? []) for (const property of objectType.properties ?? []) if (property.typeId === 'App::PropertyBoolList') nativeMatches.push({ objectTypeId: objectType.typeId, propertyName: property.name, group: property.group, status: property.status, defaultValue: property.default }) +if (nativeMatches.length !== 7) fail('locked runtime oracle no longer contains seven BoolList records') +console.log(JSON.stringify({ status: 'freecad-property-boollist-inventory-pass', propertyType: report.propertyType, recordCount: report.recordCount, writableRecords: report.records.filter(({ valueModel }) => valueModel.writable).length, immutableRecords: report.records.filter(({ valueModel }) => !valueModel.writable).length, classification: report.classification }, null, 2)) diff --git a/scripts/check-freecad-property-boollist-mutation.mjs b/scripts/check-freecad-property-boollist-mutation.mjs new file mode 100644 index 0000000..d4a2965 --- /dev/null +++ b/scripts/check-freecad-property-boollist-mutation.mjs @@ -0,0 +1,42 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-boollist-mutation.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyBoolList mutation check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-boollist-mutation' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyBoolList') fail('baseline is invalid') +if (report.caseCount !== 7 || report.cases?.length !== 7 || new Set(report.cases.map(({ objectTypeId }) => objectTypeId)).size !== 7) fail('mutation case inventory is incomplete') +const byType = new Map(report.cases.map((entry) => [entry.objectTypeId, entry])) +for (const entry of report.cases) { + if (entry.valueRestored !== true || entry.shapeRestored !== true || entry.objectsRestored !== true || entry.editRecompute !== true || entry.restoreRecompute !== true || !isDeepStrictEqual(entry.before.objectSet, entry.restored.objectSet)) fail(`${entry.objectTypeId} did not restore value, shape and objects`) + for (const snapshot of [entry.before, entry.touchedAfterEdit, entry.edited, entry.touchedAfterRestore, entry.restored]) if (snapshot.propertyTypeId !== 'App::PropertyBoolList') fail(`${entry.objectTypeId} property TypeId changed`) +} + +for (const typeId of ['App::FeatureTest', 'App::FeatureTestException']) { + const entry = byType.get(typeId) + if (entry?.mode !== 'direct-native-property-setter' || entry.propertyName !== 'BoolList' || !isDeepStrictEqual(entry.before.value, [false]) || !isDeepStrictEqual(entry.touchedAfterEdit.value, [true, false, true]) || !isDeepStrictEqual(entry.edited.value, [true, false, true]) || !isDeepStrictEqual(entry.touchedAfterRestore.value, [false]) || !isDeepStrictEqual(entry.restored.value, [false])) fail(`${typeId} mutation values changed`) + for (const snapshot of [entry.before, entry.touchedAfterEdit, entry.edited, entry.touchedAfterRestore, entry.restored]) if (!isDeepStrictEqual(snapshot.propertyStatus, []) || !isDeepStrictEqual(snapshot.editorMode, []) || snapshot.shape?.applicable !== false || snapshot.mustExecute !== false || snapshot.objectSet?.length !== 1) fail(`${typeId} mutation metadata changed`) +} +const feature = byType.get('App::FeatureTest') +if (feature.hostExecution !== 'normal' || !isDeepStrictEqual(feature.before.objectState, ['Up-to-date']) || !isDeepStrictEqual(feature.touchedAfterEdit.objectState, ['Touched']) || !isDeepStrictEqual(feature.edited.objectState, ['Up-to-date']) || !isDeepStrictEqual(feature.touchedAfterRestore.objectState, ['Touched']) || !isDeepStrictEqual(feature.restored.objectState, ['Up-to-date']) || feature.before.statusString !== 'Valid' || feature.edited.statusString !== 'Valid' || feature.restored.statusString !== 'Valid') fail('FeatureTest state trajectory changed') +const exception = byType.get('App::FeatureTestException') +if (exception.hostExecution !== 'intrinsic-test-exception' || !isDeepStrictEqual(exception.before.objectState, ['Up-to-date']) || !isDeepStrictEqual(exception.touchedAfterEdit.objectState, ['Touched']) || !isDeepStrictEqual(exception.edited.objectState, ['Touched', 'Invalid']) || !isDeepStrictEqual(exception.touchedAfterRestore.objectState, ['Touched', 'Invalid']) || !isDeepStrictEqual(exception.restored.objectState, ['Touched', 'Invalid']) || exception.edited.statusString !== 'FeatureTestException::execute(): Testexception ;-)' || exception.restored.statusString !== exception.edited.statusString) fail('FeatureTestException intrinsic trajectory changed') + +const surface = byType.get('Surface::GeomFillSurface') +if (surface?.mode !== 'direct-native-property-setter' || surface.propertyName !== 'ReversedList' || !isDeepStrictEqual(surface.before.value, [false]) || !isDeepStrictEqual(surface.edited.value, [true, false, false, false]) || !isDeepStrictEqual(surface.restored.value, [false])) fail('Surface mutation values changed') +for (const snapshot of [surface.before, surface.touchedAfterEdit, surface.edited, surface.touchedAfterRestore, surface.restored]) { + const shape = snapshot.shape + if (!isDeepStrictEqual(snapshot.propertyStatus, []) || !isDeepStrictEqual(snapshot.editorMode, []) || shape?.applicable !== true || shape.isNull !== false || shape.valid !== true || shape.shapeType !== 'Face' || shape.faces !== 1 || shape.edges !== 4 || shape.vertices !== 4 || shape.area !== 100 || shape.volume !== 0 || !isDeepStrictEqual(shape.bounds, [0, 0, 0, 10, 10, 0]) || snapshot.objectSet?.length !== 5) fail('Surface geometry evidence changed') +} +if (surface.before.shape.brepSha256 === surface.edited.shape.brepSha256 || surface.before.shape.brepSha256 !== surface.restored.shape.brepSha256 || !isDeepStrictEqual(surface.before.objectState, ['Up-to-date']) || !isDeepStrictEqual(surface.touchedAfterEdit.objectState, ['Touched']) || surface.touchedAfterEdit.mustExecute !== true || !isDeepStrictEqual(surface.edited.objectState, ['Up-to-date']) || !isDeepStrictEqual(surface.touchedAfterRestore.objectState, ['Touched']) || surface.touchedAfterRestore.mustExecute !== true || !isDeepStrictEqual(surface.restored.objectState, ['Up-to-date'])) fail('Surface reversal did not mutate and restore exactly') + +for (const typeId of ['App::Link', 'App::LinkGroup', 'App::LinkGroupPython', 'App::LinkPython']) { + const entry = byType.get(typeId) + const pythonLink = typeId.endsWith('Python') + const expectedSetup = typeId === 'App::Link' || typeId === 'App::LinkPython' ? 'LinkedObject' : 'ElementList' + if (entry?.mode !== 'link-base-extension-element-visibility' || entry.propertyName !== 'VisibilityList' || entry.setupProperty !== expectedSetup || entry.hideResult !== 1 || entry.showResult !== 1 || !isDeepStrictEqual(entry.before.value, [true, true]) || !isDeepStrictEqual(entry.touchedAfterEdit.value, [false, true]) || !isDeepStrictEqual(entry.edited.value, [false, true]) || !isDeepStrictEqual(entry.touchedAfterRestore.value, [true, true]) || !isDeepStrictEqual(entry.restored.value, [true, true])) fail(`${typeId} mutation values changed`) + for (const snapshot of [entry.before, entry.touchedAfterEdit, entry.edited, entry.touchedAfterRestore, entry.restored]) if (!isDeepStrictEqual(snapshot.propertyStatus, ['Immutable', 'Hidden', 'LockDynamic']) || !isDeepStrictEqual(snapshot.editorMode, ['Hidden']) || snapshot.shape?.applicable !== false || snapshot.objectSet?.length !== 4) fail(`${typeId} mutation metadata changed`) + if (!isDeepStrictEqual(entry.before.objectState, ['Up-to-date']) || !isDeepStrictEqual(entry.touchedAfterEdit.objectState, ['Touched']) || entry.touchedAfterEdit.mustExecute !== pythonLink || !isDeepStrictEqual(entry.edited.objectState, ['Up-to-date']) || !isDeepStrictEqual(entry.touchedAfterRestore.objectState, ['Touched']) || entry.touchedAfterRestore.mustExecute !== pythonLink || !isDeepStrictEqual(entry.restored.objectState, ['Up-to-date']) || entry.before.statusString !== 'Valid' || entry.edited.statusString !== 'Valid' || entry.restored.statusString !== 'Valid') fail(`${typeId} state trajectory changed`) +} +console.log(JSON.stringify({ status: 'freecad-property-boollist-mutation-pass', cases: report.caseCount, surface: { beforeBrep: surface.before.shape.brepSha256, editedBrep: surface.edited.shape.brepSha256, restoredBrep: surface.restored.shape.brepSha256, restoredExactly: surface.shapeRestored }, linkVisibilityRestored: ['App::Link', 'App::LinkGroup', 'App::LinkGroupPython', 'App::LinkPython'].every((typeId) => byType.get(typeId).valueRestored), intrinsicHostDiagnostic: exception.hostExecution }, null, 2)) diff --git a/scripts/check-freecad-property-boollist-promotion.mjs b/scripts/check-freecad-property-boollist-promotion.mjs new file mode 100644 index 0000000..dbf2068 --- /dev/null +++ b/scripts/check-freecad-property-boollist-promotion.mjs @@ -0,0 +1,29 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const [report, semantics, progress, roundTrip, chrome] = await Promise.all([ + load('config/freecad-property-boollist-promotion.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), + load('config/freecad-property-boollist-roundtrip.json'), + load('config/chrome-property-boollist-verification.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyBoolList promotion check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.taskId !== 'PROP-app-propertyboollist-I' || report.propertyType !== 'App::PropertyBoolList' || report.recordCount !== 7 || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.systemExact !== false) fail('promotion report boundary is invalid') +const requiredPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredPhases) { + const taskId = `PROP-app-propertyboollist-${phase}` + if (!completed.has(taskId) || !Array.isArray(report.phaseEvidence?.[phase]) || report.phaseEvidence[phase].length === 0 || !isDeepStrictEqual(report.phaseEvidence[phase], completed.get(taskId).evidence)) fail(`phase ${phase} evidence is incomplete`) +} +const target = [true, false, true, false] +const propertyType = semantics.types?.find(({ typeId }) => typeId === report.propertyType) +if (report.promotion?.from !== 'opaque-fcstd-proxy' || report.promotion.to !== 'native-editable-codec' || propertyType?.support !== report.promotion.to || propertyType.statusNames?.join(',') !== 'Hidden,Immutable,LockDynamic' || report.promotion.facadeValueModel !== 'variable-boolean-array' || report.promotion.writableRecords !== 3 || report.promotion.immutableHiddenRecords !== 4 || report.promotion.fcstdElement !== 'BoolList' || !isDeepStrictEqual(report.promotion.nativeRoundTripValue, target) || !isDeepStrictEqual(report.promotion.browserRoundTripValue, target) || report.promotion.zeroUnknownDrift !== true) fail('capability promotion is incomplete') +const sync = report.exactBlockerSync +if (sync?.nativeEditableTypes !== 30 || sync.nativeEditableRecords !== 4361 || sync.opaqueTypes !== 50 || sync.opaqueRecords !== 466 || sync.exactPromotionReady !== false || sync.exactBlocker !== '50 runtime property types and 466 records remain opaque-only; complete native document and property semantics') fail('exact blocker synchronization is stale') +if (!isDeepStrictEqual(sync, { nativeEditableTypes: semantics.supportSummary['native-editable-codec'].typeCount, nativeEditableRecords: semantics.supportSummary['native-editable-codec'].recordCount, opaqueTypes: semantics.supportSummary['opaque-fcstd-proxy'].typeCount, opaqueRecords: semantics.supportSummary['opaque-fcstd-proxy'].recordCount, exactPromotionReady: semantics.exactPromotionReady, exactBlocker: semantics.exactBlocker })) fail('promotion report diverges from global property semantics') +if (roundTrip.classification?.zeroUnknownDrift !== true || !isDeepStrictEqual(roundTrip.classification.resavedValue, target) || chrome.status !== 'pass' || chrome.persistence?.fcstdElement !== 'BoolList' || !isDeepStrictEqual(chrome.persistence.loadedValue, target) || chrome.resource?.released !== true || chrome.release?.workerTerminated !== true) fail('G/H closure evidence regressed') +console.log(JSON.stringify({ status: 'freecad-property-boollist-promotion-pass', propertyType: report.propertyType, promotion: report.promotion, completedPhases: requiredPhases, exactBlockerSync: sync, systemExact: report.systemExact }, null, 2)) diff --git a/scripts/check-freecad-property-boollist-roundtrip.mjs b/scripts/check-freecad-property-boollist-roundtrip.mjs new file mode 100644 index 0000000..cacff70 --- /dev/null +++ b/scripts/check-freecad-property-boollist-roundtrip.mjs @@ -0,0 +1,17 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-boollist-roundtrip.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyBoolList roundtrip check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-boollist-roundtrip' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is invalid') +const target = [true, false, true, false] +for (const [phase, snapshot] of [['nativeInitial', report.nativeInitial], ['nativeReopened', report.nativeAfter?.reopened], ['nativeResaved', report.nativeAfter?.resaved]]) { + if (snapshot?.object?.typeId !== 'App::FeatureTest' || snapshot.object.propertyTypeId !== 'App::PropertyBoolList' || !isDeepStrictEqual(snapshot.object.propertyStatus, []) || !isDeepStrictEqual(snapshot.object.editorMode, []) || snapshot.object.hasShapeProperty !== false || !isDeepStrictEqual(snapshot.objectSet, [{ name: 'BoolListProbe', typeId: 'App::FeatureTest' }])) fail(`${phase} native object semantics are incomplete`) +} +if (!isDeepStrictEqual(report.nativeInitial.object.value, [false]) || !isDeepStrictEqual(report.nativeAfter.reopened.object.value, target) || !isDeepStrictEqual(report.nativeAfter.resaved.object.value, target)) fail('native initial/reopen/resave values drifted') +if (report.web.before?.typeId !== 'App::PropertyBoolList' || report.web.before?.element !== 'BoolList' || report.web.before?.value !== '[false]' || report.web.after?.typeId !== 'App::PropertyBoolList' || report.web.after?.element !== 'BoolList' || report.web.after?.value !== '[true,false,true,false]' || report.web.objectSetPreserved !== true || report.web.semanticObjectsPreserved !== true || report.web.opaqueEntriesPreserved !== true || !Number.isSafeInteger(report.web.opaquePathsPreserved) || report.web.opaquePathsPreserved < 0) fail('Web edit did not preserve native archive semantics') +if (report.classification?.webValue !== '[true,false,true,false]' || !isDeepStrictEqual(report.classification.reopenedValue, target) || !isDeepStrictEqual(report.classification.resavedValue, target) || report.classification.nativeOutputMatches !== true || report.classification.unknownSemanticDrift !== false || report.classification.zeroUnknownDrift !== true) fail('round-trip classification is not exact for PropertyBoolList') +for (const archive of Object.values(report.archives ?? {})) if (!archive?.path || !Number.isSafeInteger(archive.bytes) || archive.bytes <= 0 || !/^[0-9a-f]{64}$/.test(archive.sha256)) fail('archive evidence is incomplete') +console.log(JSON.stringify({ status: 'freecad-property-boollist-roundtrip-pass', values: { nativeInitial: report.nativeInitial.object.value, webEdited: JSON.parse(report.classification.webValue), nativeReopened: report.classification.reopenedValue, nativeResaved: report.classification.resavedValue }, opaquePathsPreserved: report.web.opaquePathsPreserved, semanticObjectsPreserved: report.web.semanticObjectsPreserved, zeroUnknownDrift: report.classification.zeroUnknownDrift }, null, 2)) diff --git a/scripts/check-freecad-property-boollist-success.mjs b/scripts/check-freecad-property-boollist-success.mjs new file mode 100644 index 0000000..0acd05f --- /dev/null +++ b/scripts/check-freecad-property-boollist-success.mjs @@ -0,0 +1,41 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-boollist-success.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyBoolList success check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-boollist-success' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyBoolList') fail('baseline is invalid') +if (report.caseCount !== 7 || !Array.isArray(report.cases) || report.cases.length !== 7 || new Set(report.cases.map(({ objectTypeId }) => objectTypeId)).size !== 7) fail('native success case inventory is incomplete') +const byType = new Map(report.cases.map((entry) => [entry.objectTypeId, entry])) +const directTypes = ['App::FeatureTest', 'App::FeatureTestException'] +for (const typeId of directTypes) { + const entry = byType.get(typeId) + if (entry?.mode !== 'direct-native-property-setter' || entry.propertyName !== 'BoolList' || entry.propertyAssignmentsAccepted !== true || !isDeepStrictEqual(entry.defaultValue, [false])) fail(`${typeId} setter contract is invalid`) + const expected = { default: [false], empty: [], singleton: [true], mixed: [true, false, true, false], restored: [false] } + for (const [phase, value] of Object.entries(expected)) if (!isDeepStrictEqual(entry.phases?.[phase]?.value, value)) fail(`${typeId} ${phase} value changed`) + const large = entry.phases?.large + if (large?.value?.length !== 257 || !large.value.every((value, index) => value === (index % 3 === 0))) fail(`${typeId} large boundary changed`) + for (const snapshot of Object.values(entry.phases)) if (snapshot.propertyTypeId !== 'App::PropertyBoolList' || !isDeepStrictEqual(snapshot.propertyStatus, []) || !isDeepStrictEqual(snapshot.editorMode, []) || snapshot.shape?.applicable !== false || snapshot.objectSet?.length !== 1 || snapshot.objectSet[0].typeId !== typeId) fail(`${typeId} native metadata is invalid`) + if (typeId === 'App::FeatureTestException') { + if (entry.hostExecution !== 'intrinsic-test-exception' || !Object.values(entry.phases).slice(1).every((snapshot) => isDeepStrictEqual(snapshot.objectState, ['Touched', 'Invalid']) && snapshot.statusString === 'FeatureTestException::execute(): Testexception ;-)')) fail('FeatureTestException intrinsic host diagnostic changed') + } else if (entry.hostExecution !== 'normal' || !Object.values(entry.phases).every((snapshot) => isDeepStrictEqual(snapshot.objectState, ['Up-to-date']) && snapshot.statusString === 'Valid')) fail('FeatureTest host state changed') +} + +const surface = byType.get('Surface::GeomFillSurface') +if (surface?.mode !== 'direct-native-property-setter' || surface.propertyName !== 'ReversedList' || surface.propertyAssignmentsAccepted !== true || surface.hostExecution !== 'normal') fail('Surface BoolList contract is invalid') +const surfaceValues = { default: [false], allFalse: [false, false, false, false], oneReversed: [true, false, false, false], alternating: [true, false, true, false], allReversed: [true, true, true, true], restored: [false] } +for (const [phase, value] of Object.entries(surfaceValues)) { + const snapshot = surface.phases?.[phase] + if (!isDeepStrictEqual(snapshot?.value, value) || snapshot.propertyTypeId !== 'App::PropertyBoolList' || !isDeepStrictEqual(snapshot.propertyStatus, []) || !isDeepStrictEqual(snapshot.editorMode, []) || !isDeepStrictEqual(snapshot.objectState, ['Up-to-date']) || snapshot.statusString !== 'Valid' || snapshot.shape?.applicable !== true || snapshot.shape.isNull !== false || snapshot.shape.valid !== true || snapshot.shape.shapeType !== 'Face' || snapshot.shape.faces !== 1 || snapshot.shape.edges !== 4 || snapshot.shape.vertices !== 4 || snapshot.objectSet?.length !== 5) fail(`Surface ${phase} success evidence changed`) +} + +const linkTypes = ['App::Link', 'App::LinkGroup', 'App::LinkGroupPython', 'App::LinkPython'] +for (const typeId of linkTypes) { + const entry = byType.get(typeId) + const expectedSetup = typeId === 'App::Link' || typeId === 'App::LinkPython' ? 'LinkedObject' : 'ElementList' + if (entry?.mode !== 'link-base-extension-element-visibility' || entry.propertyName !== 'VisibilityList' || entry.propertyAssignmentsAccepted !== true || entry.hostExecution !== 'normal' || entry.setupProperty !== expectedSetup || entry.hideResult !== 1 || entry.showResult !== 1) fail(`${typeId} LinkBaseExtension contract changed`) + if (!isDeepStrictEqual(entry.phases?.linked?.value, [true, true]) || !isDeepStrictEqual(entry.phases?.hidden?.value, [false, true]) || !isDeepStrictEqual(entry.phases?.restored?.value, [true, true])) fail(`${typeId} visibility values changed`) + for (const snapshot of Object.values(entry.phases)) if (snapshot.propertyTypeId !== 'App::PropertyBoolList' || !isDeepStrictEqual(snapshot.propertyStatus, ['Immutable', 'Hidden', 'LockDynamic']) || !isDeepStrictEqual(snapshot.editorMode, ['Hidden']) || !isDeepStrictEqual(snapshot.objectState, ['Up-to-date']) || snapshot.statusString !== 'Valid' || snapshot.shape?.applicable !== false || snapshot.objectSet?.length !== 4 || snapshot.objectSet[3].typeId !== typeId) fail(`${typeId} native metadata is invalid`) +} +console.log(JSON.stringify({ status: 'freecad-property-boollist-success-pass', cases: report.caseCount, directBoundaries: { empty: 0, singleton: 1, mixed: 4, large: 257 }, surface: { valid: true, shapeType: 'Face', faces: 1 }, linkVisibility: { linked: [true, true], hidden: [false, true], restored: [true, true] }, intrinsicHostDiagnostic: byType.get('App::FeatureTestException').hostExecution }, null, 2)) diff --git a/scripts/check-freecad-property-color-failure.mjs b/scripts/check-freecad-property-color-failure.mjs new file mode 100644 index 0000000..1edeb9e --- /dev/null +++ b/scripts/check-freecad-property-color-failure.mjs @@ -0,0 +1,50 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-color-failure.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyColor failure check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-color-failure' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyColor') fail('baseline is invalid') +if (report.object?.name !== 'ColorProbe' || report.object.typeId !== 'App::FeatureTest' || report.property?.name !== 'Colour' || report.property.typeId !== 'App::PropertyColor' || !isDeepStrictEqual(report.initial, [0, 0, 0, 1])) fail('native fixture identity changed') + +const expectedCoercions = new Map([ + ['float-out-of-range', { requested: '(2.0, -1.0, 0.5, 1.5)', after: [2, -1, 0.5, 1.5] }], + ['integer-out-of-range', { requested: '(-1, 256, 511, -255)', after: [-0.003921569, 1.003921628, 2.003921509, -1] }], + ['boolean-tuple', { requested: '(True, False, True, False)', after: [0.003921569, 0, 0.003921569, 0] }], + ['packed-max', { requested: '4294967295', after: [1, 1, 1, 1] }], + ['packed-wrap', { requested: '4294967296', after: [0, 0, 0, 0] }], + ['packed-negative', { requested: '-1', after: [1, 1, 1, 1] }], +]) +if (report.coercions?.length !== expectedCoercions.size) fail('coercion case count changed') +for (const entry of report.coercions) { + const expected = expectedCoercions.get(entry.id) + if (!expected || entry.requested !== expected.requested || entry.accepted !== true || entry.exception !== null || entry.valuePreserved !== false || !isDeepStrictEqual(entry.before, [0, 0, 0, 1]) || !isDeepStrictEqual(entry.after, expected.after) || entry.objectsPreserved !== true || !isDeepStrictEqual(entry.beforeObjects, entry.afterObjects)) fail(`${entry.id} accepted coercion changed`) +} + +const expectedFailures = new Map([ + ['none', { requested: 'None', message: 'type must be integer or tuple of float or tuple integer, not NoneType' }], + ['list', { requested: '[0.1, 0.2, 0.3]', message: 'type must be integer or tuple of float or tuple integer, not list' }], + ['short-tuple', { requested: '(0.1, 0.2)', message: 'type must be integer or tuple of float or tuple integer, not tuple' }], + ['long-tuple', { requested: '(0.1, 0.2, 0.3, 0.4, 0.5)', message: 'type must be integer or tuple of float or tuple integer, not tuple' }], + ['string-first', { requested: "('bad', 0.2, 0.3)", message: 'Type in tuple must be float or integer' }], + ['mixed-after-float', { requested: '(0.1, 2, 0.3)', message: 'Type in tuple must be consistent (float)' }], + ['mixed-after-integer', { requested: '(1, 0.2, 3)', message: 'Type in tuple must be consistent (integer)' }], + ['scalar-float', { requested: '0.5', message: 'type must be integer or tuple of float or tuple integer, not float' }], +]) +if (report.failures?.length !== expectedFailures.size) fail('failure case count changed') +for (const entry of report.failures) { + const expected = expectedFailures.get(entry.id) + if (!expected || entry.requested !== expected.requested || entry.exception?.type !== 'TypeError' || entry.exception.message !== expected.message || entry.valuePreserved !== true || entry.objectsPreserved !== true || entry.polluted !== false || !isDeepStrictEqual(entry.before, [0, 0, 0, 1]) || !isDeepStrictEqual(entry.after, [0, 0, 0, 1]) || !isDeepStrictEqual(entry.beforeObjects, entry.afterObjects)) fail(`${entry.id} did not reject without pollution`) +} + +const disabled = report.disabled +if (disabled?.classification !== 'editor-readonly-python-mutable-until-immutable' || !isDeepStrictEqual(disabled.before, [0, 0, 0, 1]) || !isDeepStrictEqual(disabled.editorMode, ['ReadOnly']) || !isDeepStrictEqual(disabled.editorReadOnlyRequested, [0.2, 0.3, 0.4, 0.5]) || disabled.editorReadOnlyException !== null || disabled.pythonBypassesEditorReadOnly !== true || !isDeepStrictEqual(disabled.editorReadOnlyAfter, [0.200000003, 0.300000012, 0.400000006, 0.5])) fail('editor ReadOnly boundary changed') +if (!isDeepStrictEqual(disabled.immutableStatus, ['Immutable', 'ReadOnly']) || !isDeepStrictEqual(disabled.immutableRequested, [0.6, 0.7, 0.8, 0.9]) || disabled.immutableException?.type !== 'AttributeError' || disabled.immutableException.message !== "Object attribute 'Colour' is read-only" || !isDeepStrictEqual(disabled.immutableAfter, [0, 0, 0, 1]) || disabled.immutableValuePreserved !== true || disabled.objectsPreserved !== true || !isDeepStrictEqual(disabled.restoredStatus, []) || !isDeepStrictEqual(disabled.restoredEditorMode, [])) fail('Immutable rejection or status restoration changed') + +const transaction = report.transaction +if (transaction?.undoMode !== 1 || transaction.pendingAfterEdit !== true || transaction.pendingAfterAbort !== false || transaction.activeAfterEdit?.name !== 'property-color-cancel' || !(transaction.activeAfterEdit.id > 0) || transaction.activeAfterAbort?.name !== '' || transaction.activeAfterAbort.id !== 0 || transaction.restored !== true || transaction.objectsRestored !== true || transaction.recoveryRecomputeResult !== true) fail('transaction lifecycle changed') +if (!isDeepStrictEqual(transaction.before, [0, 0, 0, 1]) || !isDeepStrictEqual(transaction.edited, [0.75, 0.5, 0.25, 0.125]) || !isDeepStrictEqual(transaction.afterAbort, [0, 0, 0, 1]) || !isDeepStrictEqual(transaction.afterRecompute, [0, 0, 0, 1]) || !isDeepStrictEqual(transaction.stateAfterEdit, { state: ['Touched'], statusString: 'Touched' }) || !isDeepStrictEqual(transaction.stateAfterAbort, { state: ['Touched'], statusString: 'Touched' }) || !isDeepStrictEqual(transaction.stateAfterRecompute, { state: ['Up-to-date'], statusString: 'Valid' }) || !isDeepStrictEqual(transaction.objectsBefore, transaction.objectsAfter)) fail('transaction abort did not restore value and state') +if (report.cancellationBoundary?.supported !== false || report.cancellationBoundary.classification !== 'synchronous-property-setter' || report.cancellationBoundary.reason !== 'no-native-cancel-hook' || report.cancellationBoundary.replacement !== 'abort-active-document-transaction') fail('cancellation boundary is not explicit') +if (report.documentIntegrity?.objectsPreserved !== true || !isDeepStrictEqual(report.documentIntegrity.initialObjects, report.documentIntegrity.finalObjects)) fail('failure cases polluted the document') +console.log(JSON.stringify({ status: 'freecad-property-color-failure-pass', acceptedCoercions: report.coercions.map(({ id, after }) => ({ id, after })), rejectedCases: report.failures.map(({ id, exception }) => ({ id, exception })), disabled: { pythonBypassesEditorReadOnly: disabled.pythonBypassesEditorReadOnly, immutableException: disabled.immutableException }, transactionRestored: transaction.restored, cancellationBoundary: report.cancellationBoundary }, null, 2)) diff --git a/scripts/check-freecad-property-color-inventory.mjs b/scripts/check-freecad-property-color-inventory.mjs new file mode 100644 index 0000000..d150291 --- /dev/null +++ b/scripts/check-freecad-property-color-inventory.mjs @@ -0,0 +1,50 @@ +import { createHash } from 'node:crypto' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const runtimePath = resolve(root, '.cache/freecad/reference-desktop.json') +const reportPath = resolve(root, 'config/freecad-property-color-inventory.json') +const fail = (message) => { throw new Error(`FreeCAD PropertyColor inventory check failed: ${message}`) } +const [runtimeContent, reportContent] = await Promise.all([readFile(runtimePath), readFile(reportPath)]) +const runtime = JSON.parse(runtimeContent) +const report = JSON.parse(reportContent) + +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.propertyType !== 'App::PropertyColor' || report.classification !== 'opaque-fcstd-proxy') fail('report boundary is invalid') +if (report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is not locked to FreeCAD 1.1.1') +if (report.recordCount !== 8 || !Array.isArray(report.records) || report.records.length !== 8) fail('record count is not exactly eight') +if (report.provenance?.runtime?.path !== '.cache/freecad/reference-desktop.json' || report.provenance.runtime.bytes !== runtimeContent.length || report.provenance.runtime.sha256 !== createHash('sha256').update(runtimeContent).digest('hex')) fail('runtime provenance is stale') +if (report.storage?.xmlElement !== 'PropertyColor' || report.storage.attribute !== 'value' || report.storage.encoding !== 'unsigned-decimal-packed-0xRRGGBBAA' || report.storage.legacyBeforeVersion !== '1.1' || report.storage.legacyConversion !== 'invert-alpha-byte') fail('native storage contract is incomplete') + +const expected = [ + ['App::FeatureTest', 'Colour', '', [0, 0, 0, 1]], + ['App::FeatureTestException', 'Colour', '', [0, 0, 0, 1]], + ['App::Part', 'Color', '', [1, 1, 1, 0]], + ['Assembly::AssemblyLink', 'Color', '', [1, 1, 1, 0]], + ['Assembly::AssemblyObject', 'Color', '', [1, 1, 1, 0]], + ['TechDraw::DrawViewAnnotation', 'TextColor', 'Annotation', [0, 0, 0, 1]], + ['TechDraw::DrawViewDraft', 'Color', 'Draft view', [0, 0, 0, 1]], + ['TechDraw::DrawViewSpreadsheet', 'TextColor', 'Spreadsheet', [0, 0, 0, 1]], +] +for (const [objectTypeId, propertyName, group, defaultValue] of expected) { + const record = report.records.find((candidate) => candidate.objectTypeId === objectTypeId && candidate.propertyName === propertyName) + if (!record || record.objectAvailable !== true || record.probeStatus !== 'available' || record.group !== group || record.status?.length !== 0 || JSON.stringify(record.defaultValue) !== JSON.stringify(defaultValue)) fail(`native inventory changed for ${objectTypeId}.${propertyName}`) + const model = record.valueModel + if (model?.kind !== 'rgba-color' || model.channels?.join(',') !== 'red,green,blue,alpha' || model.canonicalRepresentation !== 'four-channel-float-tuple' || model.packedRepresentation !== '0xRRGGBBAA' || model.alphaSemantics !== '1-opaque-0-transparent' || model.writable !== true) fail(`value model changed for ${objectTypeId}.${propertyName}`) + const [floats, integers, packed] = record.inputs ?? [] + if (floats?.kind !== 'float-tuple' || JSON.stringify(floats.cardinality) !== '[3,4]' || floats.componentsMustHaveSameType !== true || floats.omittedAlpha !== 1 || integers?.kind !== 'integer-tuple' || JSON.stringify(integers.cardinality) !== '[3,4]' || integers.componentsMustHaveSameType !== true || integers.normalizationDivisor !== 255 || integers.omittedAlpha !== 1 || packed?.kind !== 'packed-integer' || packed.encoding !== '0xRRGGBBAA') fail(`setter inputs changed for ${objectTypeId}.${propertyName}`) + if (!Array.isArray(record.dependencies) || record.dependencies.length !== 0 || record.applicability?.requiredObjectTypeId !== objectTypeId || record.applicability.source !== 'Document.supportedTypes runtime inventory' || record.applicability.shapeRequired !== false) fail(`dependencies or applicability changed for ${objectTypeId}.${propertyName}`) +} + +const nativeMatches = [] +for (const objectType of runtime.runtimeObjects?.types ?? []) for (const property of objectType.properties ?? []) if (property.typeId === 'App::PropertyColor') nativeMatches.push({ objectTypeId: objectType.typeId, propertyName: property.name, group: property.group, status: property.status, defaultValue: property.default }) +if (nativeMatches.length !== 8) fail('locked runtime oracle no longer contains eight PropertyColor records') +for (const locked of report.provenance?.sources ?? []) { + const content = await readFile(resolve(root, locked?.path ?? '')) + if (content.length !== locked.bytes || createHash('sha256').update(content).digest('hex') !== locked.sha256) fail(`source provenance is stale for ${locked.path}`) +} +const propertySource = await readFile(resolve(root, '.cache/freecad/FreeCAD/src/App/PropertyStandard.cpp'), 'utf8') +const colorHeader = await readFile(resolve(root, '.cache/freecad/FreeCAD/src/Base/Color.h'), 'utf8') +if (!propertySource.includes('PyTuple_Size(value) == 3 || PyTuple_Size(value) == 4') || !propertySource.includes('cCol.r = PyLong_AsLong(item) / 255.0') || !propertySource.includes('cCol.setPackedValue(PyLong_AsUnsignedLong(value))') || !propertySource.includes(' valueModel.writable).length, defaults: [...new Set(report.records.map(({ defaultValue }) => JSON.stringify(defaultValue)))], classification: report.classification }, null, 2)) diff --git a/scripts/check-freecad-property-color-mutation.mjs b/scripts/check-freecad-property-color-mutation.mjs new file mode 100644 index 0000000..d449ad4 --- /dev/null +++ b/scripts/check-freecad-property-color-mutation.mjs @@ -0,0 +1,42 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-color-mutation.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyColor mutation check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-color-mutation' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyColor') fail('baseline is invalid') +if (report.caseCount !== 8 || !Array.isArray(report.cases) || report.cases.length !== 8 || new Set(report.cases.map(({ objectTypeId }) => objectTypeId)).size !== 8) fail('mutation case inventory is incomplete') +const target = [0.125, 0.375, 0.625, 0.875] +const expectedHosts = [ + ['App::FeatureTest', 'Colour', [0, 0, 0, 1], 1], + ['App::FeatureTestException', 'Colour', [0, 0, 0, 1], 1], + ['App::Part', 'Color', [1, 1, 1, 0], 9], + ['Assembly::AssemblyLink', 'Color', [1, 1, 1, 0], 9], + ['Assembly::AssemblyObject', 'Color', [1, 1, 1, 0], 9], + ['TechDraw::DrawViewAnnotation', 'TextColor', [0, 0, 0, 1], 1], + ['TechDraw::DrawViewDraft', 'Color', [0, 0, 0, 1], 1], + ['TechDraw::DrawViewSpreadsheet', 'TextColor', [0, 0, 0, 1], 2], +] +const byType = new Map(report.cases.map((entry) => [entry.objectTypeId, entry])) +for (const [typeId, propertyName, original, objectCount] of expectedHosts) { + const entry = byType.get(typeId) + if (entry?.propertyName !== propertyName || !isDeepStrictEqual(entry.target, target) || entry.editRecomputeResult !== true || entry.restoreRecomputeResult !== true || entry.mutationDetected !== true || entry.restoredExactly !== true) fail(`${typeId} mutation boundary changed`) + if (typeId === 'TechDraw::DrawViewSpreadsheet') { + if (entry.setup?.kind !== 'spreadsheet-source' || entry.setup.objectTypeId !== 'Spreadsheet::Sheet' || entry.setup.objectName !== 'MutationSource') fail('Spreadsheet mutation setup changed') + } else if (entry.setup?.kind !== 'none') fail(`${typeId} has unexpected mutation setup`) + if (!isDeepStrictEqual(entry.before?.value, original) || !isDeepStrictEqual(entry.touchedAfterEdit?.value, target) || !isDeepStrictEqual(entry.edited?.value, target) || !isDeepStrictEqual(entry.touchedAfterRestore?.value, original) || !isDeepStrictEqual(entry.restored?.value, original)) fail(`${typeId} mutation values changed`) + const objectSet = entry.before.objectSet + if (objectSet?.length !== objectCount || !objectSet.some(({ typeId: candidateType }) => candidateType === typeId)) fail(`${typeId} mutation object set changed`) + for (const phase of ['before', 'touchedAfterEdit', 'edited', 'touchedAfterRestore', 'restored']) { + const snapshot = entry[phase] + if (snapshot.propertyTypeId !== 'App::PropertyColor' || !isDeepStrictEqual(snapshot.propertyStatus, []) || !isDeepStrictEqual(snapshot.editorMode, []) || snapshot.shape?.applicable !== false || !isDeepStrictEqual(snapshot.objectSet, objectSet)) fail(`${typeId} ${phase} native metadata changed`) + } + if (typeId === 'App::FeatureTestException') { + if (entry.hostExecution !== 'intrinsic-test-exception' || !isDeepStrictEqual(entry.before.objectState, ['Up-to-date']) || entry.before.statusString !== 'Valid' || !isDeepStrictEqual(entry.touchedAfterEdit.objectState, ['Touched']) || entry.touchedAfterEdit.statusString !== 'Touched') fail('FeatureTestException initial mutation sequence changed') + for (const phase of ['edited', 'touchedAfterRestore', 'restored']) if (!isDeepStrictEqual(entry[phase].objectState, ['Touched', 'Invalid']) || entry[phase].statusString !== 'FeatureTestException::execute(): Testexception ;-)') fail(`FeatureTestException ${phase} intrinsic diagnostic changed`) + } else { + if (entry.hostExecution !== 'normal' || !isDeepStrictEqual(entry.before.objectState, ['Up-to-date']) || entry.before.statusString !== 'Valid' || !isDeepStrictEqual(entry.touchedAfterEdit.objectState, ['Touched']) || entry.touchedAfterEdit.statusString !== 'Touched' || !isDeepStrictEqual(entry.edited.objectState, ['Up-to-date']) || entry.edited.statusString !== 'Valid' || !isDeepStrictEqual(entry.touchedAfterRestore.objectState, ['Touched']) || entry.touchedAfterRestore.statusString !== 'Touched' || !isDeepStrictEqual(entry.restored.objectState, ['Up-to-date']) || entry.restored.statusString !== 'Valid') fail(`${typeId} mutation state sequence changed`) + } +} +console.log(JSON.stringify({ status: 'freecad-property-color-mutation-pass', cases: report.caseCount, target, mutated: report.cases.filter(({ mutationDetected }) => mutationDetected).length, restoredExactly: report.cases.filter(({ restoredExactly }) => restoredExactly).length, normalStateSequence: ['Valid', 'Touched', 'Valid', 'Touched', 'Valid'], intrinsicHostDiagnostic: 'App::FeatureTestException' }, null, 2)) diff --git a/scripts/check-freecad-property-color-promotion.mjs b/scripts/check-freecad-property-color-promotion.mjs new file mode 100644 index 0000000..ab614cd --- /dev/null +++ b/scripts/check-freecad-property-color-promotion.mjs @@ -0,0 +1,30 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const [report, semantics, progress, roundTrip, chrome] = await Promise.all([ + load('config/freecad-property-color-promotion.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), + load('config/freecad-property-color-roundtrip.json'), + load('config/chrome-property-color-verification.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyColor promotion check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.taskId !== 'PROP-app-propertycolor-I' || report.propertyType !== 'App::PropertyColor' || report.recordCount !== 8 || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.systemExact !== false) fail('promotion report boundary is invalid') +const requiredPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredPhases) { + const taskId = `PROP-app-propertycolor-${phase}` + if (!completed.has(taskId) || !Array.isArray(report.phaseEvidence?.[phase]) || report.phaseEvidence[phase].length === 0 || !isDeepStrictEqual(report.phaseEvidence[phase], completed.get(taskId).evidence)) fail(`phase ${phase} evidence is incomplete`) +} +const target = [0.2, 0.4, 0.6, 0.8] +const approximatelyTarget = (value) => Array.isArray(value) && value.length === target.length && value.every((channel, index) => typeof channel === 'number' && Math.abs(channel - target[index]) <= 1e-7) +const propertyType = semantics.types?.find(({ typeId }) => typeId === report.propertyType) +if (report.promotion?.from !== 'opaque-fcstd-proxy' || report.promotion.to !== 'native-editable-codec' || propertyType?.support !== report.promotion.to || propertyType.statusNames?.length !== 0 || report.promotion.facadeValueModel !== 'four-finite-rgba-channels-with-8-bit-fcstd-packing' || report.promotion.writableRecords !== 8 || report.promotion.fcstdElement !== 'PropertyColor' || report.promotion.fcstdPackedValue !== '862362060' || !approximatelyTarget(report.promotion.nativeRoundTripValue) || !isDeepStrictEqual(report.promotion.browserRoundTripValue, target) || report.promotion.zeroUnknownDrift !== true) fail('capability promotion is incomplete') +const sync = report.exactBlockerSync +if (sync?.nativeEditableTypes !== 30 || sync.nativeEditableRecords !== 4361 || sync.opaqueTypes !== 50 || sync.opaqueRecords !== 466 || sync.exactPromotionReady !== false || sync.exactBlocker !== '50 runtime property types and 466 records remain opaque-only; complete native document and property semantics') fail('exact blocker synchronization is stale') +if (!isDeepStrictEqual(sync, { nativeEditableTypes: semantics.supportSummary['native-editable-codec'].typeCount, nativeEditableRecords: semantics.supportSummary['native-editable-codec'].recordCount, opaqueTypes: semantics.supportSummary['opaque-fcstd-proxy'].typeCount, opaqueRecords: semantics.supportSummary['opaque-fcstd-proxy'].recordCount, exactPromotionReady: semantics.exactPromotionReady, exactBlocker: semantics.exactBlocker })) fail('promotion report diverges from global property semantics') +if (roundTrip.classification?.zeroUnknownDrift !== true || !approximatelyTarget(roundTrip.classification.resavedValue) || chrome.status !== 'pass' || chrome.persistence?.fcstdElement !== 'PropertyColor' || chrome.persistence.fcstdValue !== '862362060' || !isDeepStrictEqual(chrome.persistence.loadedValue, target) || chrome.resource?.released !== true || chrome.release?.workerTerminated !== true) fail('G/H closure evidence regressed') +console.log(JSON.stringify({ status: 'freecad-property-color-promotion-pass', propertyType: report.propertyType, promotion: report.promotion, completedPhases: requiredPhases, exactBlockerSync: sync, systemExact: report.systemExact }, null, 2)) diff --git a/scripts/check-freecad-property-color-roundtrip.mjs b/scripts/check-freecad-property-color-roundtrip.mjs new file mode 100644 index 0000000..389350c --- /dev/null +++ b/scripts/check-freecad-property-color-roundtrip.mjs @@ -0,0 +1,18 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-color-roundtrip.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyColor roundtrip check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-color-roundtrip' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is invalid') +const target = [0.2, 0.4, 0.6, 0.8] +const approximatelyTarget = (value) => Array.isArray(value) && value.length === target.length && value.every((channel, index) => typeof channel === 'number' && Math.abs(channel - target[index]) <= 1e-7) +for (const [phase, snapshot] of [['nativeInitial', report.nativeInitial], ['nativeReopened', report.nativeAfter?.reopened], ['nativeResaved', report.nativeAfter?.resaved]]) { + if (snapshot?.object?.typeId !== 'App::FeatureTest' || snapshot.object.propertyTypeId !== 'App::PropertyColor' || !isDeepStrictEqual(snapshot.object.propertyStatus, []) || !isDeepStrictEqual(snapshot.object.editorMode, []) || snapshot.object.hasShapeProperty !== false || !isDeepStrictEqual(snapshot.objectSet, [{ name: 'ColorProbe', typeId: 'App::FeatureTest' }])) fail(`${phase} native object semantics are incomplete`) +} +if (!approximatelyTarget(report.nativeAfter.reopened.object.value) || !approximatelyTarget(report.nativeAfter.resaved.object.value) || !isDeepStrictEqual(report.nativeAfter.reopened.object.value, report.nativeAfter.resaved.object.value)) fail('native reopen/resave values drifted') +if (report.web.before?.typeId !== 'App::PropertyColor' || report.web.before?.element !== 'PropertyColor' || report.web.before?.value !== '287454020' || report.web.after?.typeId !== 'App::PropertyColor' || report.web.after?.element !== 'PropertyColor' || report.web.after?.value !== '862362060' || report.web.objectSetPreserved !== true || report.web.semanticObjectsPreserved !== true || report.web.opaqueEntriesPreserved !== true || !Number.isSafeInteger(report.web.opaquePathsPreserved) || report.web.opaquePathsPreserved < 0) fail('Web edit did not preserve native archive semantics') +if (!isDeepStrictEqual(report.classification?.requestedValue, target) || report.classification.webValue !== '862362060' || !approximatelyTarget(report.classification.reopenedValue) || !approximatelyTarget(report.classification.resavedValue) || report.classification.nativeOutputMatches !== true || report.classification.unknownSemanticDrift !== false || report.classification.zeroUnknownDrift !== true) fail('round-trip classification is not exact for PropertyColor') +for (const archive of Object.values(report.archives ?? {})) if (!archive?.path || !Number.isSafeInteger(archive.bytes) || archive.bytes <= 0 || !/^[0-9a-f]{64}$/.test(archive.sha256)) fail('archive evidence is incomplete') +console.log(JSON.stringify({ status: 'freecad-property-color-roundtrip-pass', values: { nativeInitial: report.nativeInitial.object.value, webEditedPacked: report.classification.webValue, nativeReopened: report.classification.reopenedValue, nativeResaved: report.classification.resavedValue }, opaquePathsPreserved: report.web.opaquePathsPreserved, semanticObjectsPreserved: report.web.semanticObjectsPreserved, zeroUnknownDrift: report.classification.zeroUnknownDrift }, null, 2)) diff --git a/scripts/check-freecad-property-color-success.mjs b/scripts/check-freecad-property-color-success.mjs new file mode 100644 index 0000000..9dca9d7 --- /dev/null +++ b/scripts/check-freecad-property-color-success.mjs @@ -0,0 +1,59 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-color-success.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyColor success check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-color-success' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyColor') fail('baseline is invalid') +if (report.caseCount !== 8 || !Array.isArray(report.cases) || report.cases.length !== 8 || new Set(report.cases.map(({ objectTypeId }) => objectTypeId)).size !== 8) fail('native success case inventory is incomplete') + +const expectedHosts = [ + ['App::FeatureTest', 'Colour', [0, 0, 0, 1], 1], + ['App::FeatureTestException', 'Colour', [0, 0, 0, 1], 1], + ['App::Part', 'Color', [1, 1, 1, 0], 9], + ['Assembly::AssemblyLink', 'Color', [1, 1, 1, 0], 9], + ['Assembly::AssemblyObject', 'Color', [1, 1, 1, 0], 9], + ['TechDraw::DrawViewAnnotation', 'TextColor', [0, 0, 0, 1], 1], + ['TechDraw::DrawViewDraft', 'Color', [0, 0, 0, 1], 1], + ['TechDraw::DrawViewSpreadsheet', 'TextColor', [0, 0, 0, 1], 2], +] +const normalized = { + floatRgb: [0.25, 0.5, 0.75, 1], + floatRgba: [0.100000001, 0.200000003, 0.300000012, 0.400000006], + byteRgb: [0.003921569, 0.498039216, 1, 1], + byteRgba: [1, 0.501960814, 0, 0.250980407], + packedRgba: [0.06666667, 0.13333334, 0.200000003, 0.266666681], + transparentBoundary: [0, 0, 0, 0], +} +const requested = { + floatRgb: [0.25, 0.5, 0.75], + floatRgba: [0.1, 0.2, 0.3, 0.4], + byteRgb: [1, 127, 255], + byteRgba: [255, 128, 0, 64], + packedRgba: 0x11223344, + transparentBoundary: [0, 0, 0, 0], +} +const byType = new Map(report.cases.map((entry) => [entry.objectTypeId, entry])) +for (const [typeId, propertyName, defaultValue, objectCount] of expectedHosts) { + const entry = byType.get(typeId) + if (entry?.propertyName !== propertyName || entry.mode !== 'direct-native-property-setter' || entry.propertyAssignmentsAccepted !== true || !isDeepStrictEqual(entry.defaultValue, defaultValue) || !isDeepStrictEqual(entry.requested, requested)) fail(`${typeId} setter contract is invalid`) + if (typeId === 'TechDraw::DrawViewSpreadsheet') { + if (entry.setup?.kind !== 'spreadsheet-source' || entry.setup.objectTypeId !== 'Spreadsheet::Sheet' || entry.setup.objectName !== 'ColorSource') fail('Spreadsheet host setup is incomplete') + } else if (entry.setup?.kind !== 'none') fail(`${typeId} has unexpected host setup`) + if (!isDeepStrictEqual(entry.phases?.default?.value, defaultValue) || !isDeepStrictEqual(entry.phases?.restored?.value, defaultValue)) fail(`${typeId} default or restored value changed`) + for (const [phase, value] of Object.entries(normalized)) if (!isDeepStrictEqual(entry.phases?.[phase]?.value, value)) fail(`${typeId} ${phase} normalization changed`) + const objectSet = entry.phases?.default?.objectSet + if (!Array.isArray(objectSet) || objectSet.length !== objectCount || !objectSet.some(({ typeId: candidateType }) => candidateType === typeId)) fail(`${typeId} host object set is invalid`) + for (const snapshot of Object.values(entry.phases ?? {})) { + if (snapshot.propertyTypeId !== 'App::PropertyColor' || !isDeepStrictEqual(snapshot.propertyStatus, []) || !isDeepStrictEqual(snapshot.editorMode, []) || snapshot.shape?.applicable !== false || typeof snapshot.recomputeResult !== 'boolean' || !isDeepStrictEqual(snapshot.objectSet, objectSet)) fail(`${typeId} native metadata changed`) + } + if (typeId === 'App::FeatureTestException') { + if (entry.hostExecution !== 'intrinsic-test-exception' || !isDeepStrictEqual(entry.phases.default.objectState, ['Up-to-date']) || entry.phases.default.statusString !== 'Valid') fail('FeatureTestException initial state changed') + for (const [phase, snapshot] of Object.entries(entry.phases)) if (phase !== 'default' && (!isDeepStrictEqual(snapshot.objectState, ['Touched', 'Invalid']) || snapshot.statusString !== 'FeatureTestException::execute(): Testexception ;-)')) fail(`FeatureTestException ${phase} intrinsic diagnostic changed`) + } else { + if (entry.hostExecution !== 'normal') fail(`${typeId} host execution classification changed`) + for (const snapshot of Object.values(entry.phases)) if (!isDeepStrictEqual(snapshot.objectState, ['Up-to-date']) || snapshot.statusString !== 'Valid') fail(`${typeId} success state changed`) + } +} +console.log(JSON.stringify({ status: 'freecad-property-color-success-pass', cases: report.caseCount, acceptedInputs: Object.keys(requested), normalized, normalHosts: 7, intrinsicHostDiagnostic: 'App::FeatureTestException' }, null, 2)) diff --git a/scripts/check-freecad-property-colorlist-failure.mjs b/scripts/check-freecad-property-colorlist-failure.mjs new file mode 100644 index 0000000..c7ab056 --- /dev/null +++ b/scripts/check-freecad-property-colorlist-failure.mjs @@ -0,0 +1,58 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-colorlist-failure.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyColorList failure check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-colorlist-failure' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyColorList') fail('baseline is invalid') +const baseline = [[0.06666667, 0.13333334, 0.200000003, 0.266666681], [1, 1, 1, 1]] +if (report.object?.name !== 'ColorListProbe' || report.object.typeId !== 'App::FeatureTest' || report.property?.name !== 'ColourList' || report.property.typeId !== 'App::PropertyColorList' || !isDeepStrictEqual(report.initial, baseline)) fail('native fixture identity changed') + +const expectedCoercions = new Map([ + ['boolean-scalar', { requested: 'True', after: [[0, 0, 0, 0.003921569]] }], + ['bytes-sequence', { requested: "b'\\x01\\xff'", after: [[0, 0, 0, 0.003921569], [0, 0, 0, 1]] }], + ['bare-float-tuple', { requested: '(0.1, 0.2, 0.3, 0.4)', after: [[0.100000001, 0.200000003, 0.300000012, 0.400000006]] }], + ['bare-integer-tuple', { requested: '(255, 128, 0, 64)', after: [[1, 0.501960814, 0, 0.250980407]] }], + ['tuple-packed-sequence', { requested: '(287454020, 4294967295)', after: baseline }], + ['empty-dictionary', { requested: '{}', after: [] }], +]) +if (report.coercions?.length !== expectedCoercions.size) fail('coercion case count changed') +for (const entry of report.coercions) { + const expected = expectedCoercions.get(entry.id) + if (!expected || entry.requested !== expected.requested || entry.accepted !== true || entry.exception !== null || !isDeepStrictEqual(entry.before, baseline) || !isDeepStrictEqual(entry.after, expected.after) || entry.valuePreserved !== isDeepStrictEqual(baseline, expected.after) || entry.objectsPreserved !== true || !isDeepStrictEqual(entry.beforeObjects, entry.afterObjects)) fail(`${entry.id} accepted coercion changed`) +} + +const expectedFailures = new Map([ + ['none', { requested: 'None', type: 'TypeError', message: 'type must be integer or tuple of float or tuple integer, not NoneType' }], + ['bare-float-list', { requested: '[0.1, 0.2, 0.3, 0.4]', type: 'TypeError', message: 'type must be integer or tuple of float or tuple integer, not float' }], + ['bare-mixed-tuple', { requested: '(0.1, 2, 0.3)', type: 'TypeError', message: 'type must be integer or tuple of float or tuple integer, not float' }], + ['nested-short-tuple', { requested: '[(0.1, 0.2)]', type: 'TypeError', message: 'type must be integer or tuple of float or tuple integer, not tuple' }], + ['mixed-valid-none', { requested: '[(0.1, 0.2, 0.3, 0.4), None]', type: 'TypeError', message: 'type must be integer or tuple of float or tuple integer, not NoneType' }], + ['scalar-float', { requested: '0.5', type: 'TypeError', message: 'type must be integer or tuple of float or tuple integer, not float' }], + ['string-sequence', { requested: "'rgb'", type: 'TypeError', message: 'type must be integer or tuple of float or tuple integer, not str' }], + ['nested-list', { requested: '[[0.1, 0.2, 0.3, 0.4]]', type: 'TypeError', message: 'type must be integer or tuple of float or tuple integer, not list' }], + ['dictionary-string-key', { requested: "{'0': 287454020}", type: 'TypeError', message: 'expect key type to be integer' }], + ['dictionary-high-index', { requested: '{3: 287454020}', type: 'ValueError', message: 'index out of bound' }], + ['dictionary-negative-index', { requested: '{-2: 287454020}', type: 'ValueError', message: 'index out of bound' }], + ['dictionary-partial-invalid', { requested: '{0: 16909060, 1: None}', type: 'TypeError', message: 'type must be integer or tuple of float or tuple integer, not NoneType', after: [[0.003921569, 0.007843138, 0.011764706, 0.015686275], [1, 1, 1, 1]] }], +]) +if (report.failures?.length !== expectedFailures.size) fail('failure case count changed') +for (const entry of report.failures) { + const expected = expectedFailures.get(entry.id) + const expectedAfter = expected?.after ?? baseline + if (!expected || entry.requested !== expected.requested || entry.exception?.type !== expected.type || entry.exception.message !== expected.message || !isDeepStrictEqual(entry.before, baseline) || !isDeepStrictEqual(entry.after, expectedAfter) || entry.valuePreserved !== isDeepStrictEqual(baseline, expectedAfter) || entry.objectsPreserved !== true || entry.polluted !== false || !isDeepStrictEqual(entry.beforeObjects, entry.afterObjects)) fail(`${entry.id} failure behavior changed`) +} +if (report.failures.filter(({ valuePreserved }) => !valuePreserved).map(({ id }) => id).join(',') !== 'dictionary-partial-invalid') fail('native partial-mutation boundary changed') + +const disabled = report.disabled +if (disabled?.classification !== 'editor-readonly-python-mutable-until-immutable' || !isDeepStrictEqual(disabled.before, baseline) || !isDeepStrictEqual(disabled.editorMode, ['ReadOnly']) || !isDeepStrictEqual(disabled.editorReadOnlyRequested, [[0.2, 0.3, 0.4, 0.5]]) || disabled.editorReadOnlyException !== null || disabled.pythonBypassesEditorReadOnly !== true || !isDeepStrictEqual(disabled.editorReadOnlyAfter, [[0.200000003, 0.300000012, 0.400000006, 0.5]])) fail('editor ReadOnly boundary changed') +if (!isDeepStrictEqual(disabled.immutableStatus, ['Immutable', 'ReadOnly']) || !isDeepStrictEqual(disabled.immutableRequested, [[0.6, 0.7, 0.8, 0.9]]) || disabled.immutableException?.type !== 'AttributeError' || disabled.immutableException.message !== "Object attribute 'ColourList' is read-only" || !isDeepStrictEqual(disabled.immutableAfter, baseline) || disabled.immutableValuePreserved !== true || disabled.objectsPreserved !== true || !isDeepStrictEqual(disabled.restoredStatus, []) || !isDeepStrictEqual(disabled.restoredEditorMode, [])) fail('Immutable rejection or status restoration changed') + +const transaction = report.transaction +const edited = [[0.75, 0.5, 0.25, 0.125], baseline[0], [0, 1, 0, 0.501960814]] +if (transaction?.undoMode !== 1 || transaction.pendingAfterEdit !== true || transaction.pendingAfterAbort !== false || transaction.activeAfterEdit?.name !== 'property-colorlist-cancel' || !(transaction.activeAfterEdit.id > 0) || transaction.activeAfterAbort?.name !== '' || transaction.activeAfterAbort.id !== 0 || transaction.restored !== true || transaction.objectsRestored !== true || transaction.recoveryRecomputeResult !== true) fail('transaction lifecycle changed') +if (!isDeepStrictEqual(transaction.before, baseline) || !isDeepStrictEqual(transaction.edited, edited) || !isDeepStrictEqual(transaction.afterAbort, baseline) || !isDeepStrictEqual(transaction.afterRecompute, baseline) || !isDeepStrictEqual(transaction.stateAfterEdit, { state: ['Touched'], statusString: 'Touched' }) || !isDeepStrictEqual(transaction.stateAfterAbort, { state: ['Touched'], statusString: 'Touched' }) || !isDeepStrictEqual(transaction.stateAfterRecompute, { state: ['Up-to-date'], statusString: 'Valid' }) || !isDeepStrictEqual(transaction.objectsBefore, transaction.objectsAfter)) fail('transaction abort did not restore value and state') +if (report.cancellationBoundary?.supported !== false || report.cancellationBoundary.classification !== 'synchronous-property-setter' || report.cancellationBoundary.reason !== 'no-native-cancel-hook' || report.cancellationBoundary.replacement !== 'abort-active-document-transaction') fail('cancellation boundary is not explicit') +if (report.documentIntegrity?.objectsPreserved !== true || !isDeepStrictEqual(report.documentIntegrity.initialObjects, report.documentIntegrity.finalObjects)) fail('failure cases polluted the document object set') +console.log(JSON.stringify({ status: 'freecad-property-colorlist-failure-pass', acceptedCoercions: report.coercions.map(({ id, after }) => ({ id, after })), rejectedCases: report.failures.map(({ id, exception, valuePreserved }) => ({ id, exception, valuePreserved })), partialMutation: report.failures.find(({ id }) => id === 'dictionary-partial-invalid'), disabled: { pythonBypassesEditorReadOnly: disabled.pythonBypassesEditorReadOnly, immutableException: disabled.immutableException }, transactionRestored: transaction.restored, cancellationBoundary: report.cancellationBoundary }, null, 2)) diff --git a/scripts/check-freecad-property-colorlist-inventory.mjs b/scripts/check-freecad-property-colorlist-inventory.mjs new file mode 100644 index 0000000..ff248a1 --- /dev/null +++ b/scripts/check-freecad-property-colorlist-inventory.mjs @@ -0,0 +1,46 @@ +import { createHash } from 'node:crypto' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const runtimePath = resolve(root, '.cache/freecad/reference-desktop.json') +const reportPath = resolve(root, 'config/freecad-property-colorlist-inventory.json') +const fail = (message) => { throw new Error(`FreeCAD PropertyColorList inventory check failed: ${message}`) } +const [runtimeContent, reportContent] = await Promise.all([readFile(runtimePath), readFile(reportPath)]) +const runtime = JSON.parse(runtimeContent) +const report = JSON.parse(reportContent) + +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.propertyType !== 'App::PropertyColorList' || report.classification !== 'opaque-fcstd-proxy') fail('report boundary is invalid') +if (report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is not locked to FreeCAD 1.1.1') +if (report.recordCount !== 2 || !Array.isArray(report.records) || report.records.length !== 2) fail('record count is not exactly two') +if (report.provenance?.runtime?.path !== '.cache/freecad/reference-desktop.json' || report.provenance.runtime.bytes !== runtimeContent.length || report.provenance.runtime.sha256 !== createHash('sha256').update(runtimeContent).digest('hex')) fail('runtime provenance is stale') +const storage = report.storage +if (storage?.xmlElement !== 'ColorList' || storage.fileAttribute !== 'file' || storage.nonEmptyExternalResourceName !== 'property-name' || storage.emptyResourceName !== '' || storage.externalBinary?.byteOrder !== 'little-endian' || storage.externalBinary.count !== 'uint32' || storage.externalBinary.element !== 'uint32-packed-0xRRGGBBAA' || storage.legacyBeforeVersion !== '1.1' || storage.legacyConversion !== 'invert-alpha-channel') fail('native storage contract is incomplete') + +for (const objectTypeId of ['App::FeatureTest', 'App::FeatureTestException']) { + const record = report.records.find((candidate) => candidate.objectTypeId === objectTypeId && candidate.propertyName === 'ColourList') + if (!record || record.objectAvailable !== true || record.probeStatus !== 'available' || record.group !== '' || record.status?.length !== 0 || JSON.stringify(record.defaultValue) !== '[[0,0,0,1]]') fail(`native inventory changed for ${objectTypeId}.ColourList`) + const model = record.valueModel + if (model?.kind !== 'ordered-rgba-color-list' || model.elementRepresentation !== 'four-channel-float-tuple' || model.packedElementRepresentation !== '0xRRGGBBAA' || model.alphaSemantics !== '1-opaque-0-transparent' || model.writable !== true) fail(`value model changed for ${objectTypeId}.ColourList`) + if (record.inputs?.collection?.join(',') !== 'sequence,iterable,single-tuple-color-value,single-non-sequence-color-value,integer-index-dictionary' || JSON.stringify(record.inputs.dictionaryAppendIndexes) !== '[-1,"current-size"]' || record.inputs.elementSetters?.join(',') !== 'float-tuple-3-or-4,integer-tuple-3-or-4,packed-integer-0xRRGGBBAA') fail(`setter inputs changed for ${objectTypeId}.ColourList`) + if (!Array.isArray(record.dependencies) || record.dependencies.length !== 0 || record.applicability?.requiredObjectTypeId !== objectTypeId || record.applicability.source !== 'Document.supportedTypes runtime inventory' || record.applicability.shapeRequired !== false) fail(`dependencies or applicability changed for ${objectTypeId}.ColourList`) +} + +const nativeMatches = [] +for (const objectType of runtime.runtimeObjects?.types ?? []) for (const property of objectType.properties ?? []) if (property.typeId === 'App::PropertyColorList') nativeMatches.push({ objectTypeId: objectType.typeId, propertyName: property.name, group: property.group, status: property.status, defaultValue: property.default }) +if (nativeMatches.length !== 2) fail('locked runtime oracle no longer contains two PropertyColorList records') +for (const locked of report.provenance?.sources ?? []) { + const content = await readFile(resolve(root, locked?.path ?? '')) + if (content.length !== locked.bytes || createHash('sha256').update(content).digest('hex') !== locked.sha256) fail(`source provenance is stale for ${locked.path}`) +} +const [propertySource, propertyBase, streamSource, colorHeader] = await Promise.all([ + readFile(resolve(root, '.cache/freecad/FreeCAD/src/App/PropertyStandard.cpp'), 'utf8'), + readFile(resolve(root, '.cache/freecad/FreeCAD/src/App/Property.cpp'), 'utf8'), + readFile(resolve(root, '.cache/freecad/FreeCAD/src/Base/Stream.cpp'), 'utf8'), + readFile(resolve(root, '.cache/freecad/FreeCAD/src/Base/Color.h'), 'utf8'), +]) +if (!propertySource.includes('PropertyColorList::getPyValue') || !propertySource.includes('PropertyColor col;') || !propertySource.includes(' valueModel.writable).length, defaultValue: report.records[0].defaultValue, storage: report.storage, classification: report.classification }, null, 2)) diff --git a/scripts/check-freecad-property-colorlist-mutation.mjs b/scripts/check-freecad-property-colorlist-mutation.mjs new file mode 100644 index 0000000..6a9da03 --- /dev/null +++ b/scripts/check-freecad-property-colorlist-mutation.mjs @@ -0,0 +1,23 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-colorlist-mutation.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyColorList mutation check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-colorlist-mutation' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyColorList' || report.caseCount !== 2 || report.cases?.length !== 2) fail('baseline is invalid') +const before = [[0, 0, 0, 1]] +const target = [[0.125, 0.375, 0.625, 0.875], [0.06666667, 0.13333334, 0.200000003, 0.266666681], [1, 0, 0.501960814, 0.250980407], [0, 0, 0, 0]] +for (const typeId of ['App::FeatureTest', 'App::FeatureTestException']) { + const entry = report.cases.find(({ objectTypeId }) => objectTypeId === typeId) + if (!entry || entry.propertyName !== 'ColourList' || entry.mutationDetected !== true || entry.restoredExactly !== true || !isDeepStrictEqual(entry.before.value, before) || !isDeepStrictEqual(entry.touchedAfterEdit.value, target) || !isDeepStrictEqual(entry.edited.value, target) || !isDeepStrictEqual(entry.touchedAfterRestore.value, before) || !isDeepStrictEqual(entry.restored.value, before)) fail(`${typeId} mutation values changed`) + for (const snapshot of [entry.before, entry.touchedAfterEdit, entry.edited, entry.touchedAfterRestore, entry.restored]) if (snapshot.propertyTypeId !== 'App::PropertyColorList' || !isDeepStrictEqual(snapshot.propertyStatus, []) || !isDeepStrictEqual(snapshot.editorMode, []) || snapshot.shape?.applicable !== false || snapshot.objectSet?.length !== 1 || snapshot.objectSet[0].typeId !== typeId) fail(`${typeId} native metadata changed`) + if (!isDeepStrictEqual(entry.before.objectSet, entry.edited.objectSet) || !isDeepStrictEqual(entry.before.objectSet, entry.restored.objectSet) || !isDeepStrictEqual(entry.before.shape, entry.edited.shape) || !isDeepStrictEqual(entry.before.shape, entry.restored.shape)) fail(`${typeId} object or Shape boundary drifted`) + if (typeId === 'App::FeatureTest') { + const states = [entry.before, entry.touchedAfterEdit, entry.edited, entry.touchedAfterRestore, entry.restored].map(({ objectState }) => objectState) + if (!isDeepStrictEqual(states, [['Up-to-date'], ['Touched'], ['Up-to-date'], ['Touched'], ['Up-to-date']]) || entry.editRecomputeResult !== true || entry.restoreRecomputeResult !== true || entry.edited.statusString !== 'Valid' || entry.restored.statusString !== 'Valid') fail('normal host state sequence changed') + } else { + if (entry.hostExecution !== 'intrinsic-test-exception' || !entry.edited.objectState.includes('Invalid') || !entry.restored.objectState.includes('Invalid') || !entry.edited.statusString.includes('Testexception') || !entry.restored.statusString.includes('Testexception')) fail('FeatureTestException intrinsic diagnostic changed') + } +} +console.log(JSON.stringify({ status: 'freecad-property-colorlist-mutation-pass', cases: report.caseCount, target, mutated: report.cases.filter(({ mutationDetected }) => mutationDetected).length, restoredExactly: report.cases.filter(({ restoredExactly }) => restoredExactly).length, normalStateSequence: ['Valid', 'Touched', 'Valid', 'Touched', 'Valid'], intrinsicHostDiagnostic: 'App::FeatureTestException' }, null, 2)) diff --git a/scripts/check-freecad-property-colorlist-promotion.mjs b/scripts/check-freecad-property-colorlist-promotion.mjs new file mode 100644 index 0000000..5690d9d --- /dev/null +++ b/scripts/check-freecad-property-colorlist-promotion.mjs @@ -0,0 +1,31 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const [report, semantics, progress, roundTrip, chrome] = await Promise.all([ + load('config/freecad-property-colorlist-promotion.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), + load('config/freecad-property-colorlist-roundtrip.json'), + load('config/chrome-property-colorlist-verification.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyColorList promotion check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.taskId !== 'PROP-app-propertycolorlist-I' || report.propertyType !== 'App::PropertyColorList' || report.recordCount !== 2 || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.systemExact !== false) fail('promotion report boundary is invalid') +const requiredPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredPhases) { + const taskId = `PROP-app-propertycolorlist-${phase}` + if (!completed.has(taskId) || !Array.isArray(report.phaseEvidence?.[phase]) || report.phaseEvidence[phase].length === 0 || !isDeepStrictEqual(report.phaseEvidence[phase], completed.get(taskId).evidence)) fail(`phase ${phase} evidence is incomplete`) +} +const nativeTarget = [[0.200000003, 0.400000006, 0.600000024, 0.800000012], [0.06666667, 0.13333334, 0.200000003, 0.266666681]] +const browserTarget = [[0.2, 0.4, 0.6, 0.8], [17 / 255, 34 / 255, 51 / 255, 0.4]] +const approximately = (value, target, tolerance = 1e-7) => Array.isArray(value) && value.length === target.length && value.every((color, index) => Array.isArray(color) && color.length === target[index].length && color.every((channel, channelIndex) => typeof channel === 'number' && Math.abs(channel - target[index][channelIndex]) <= tolerance)) +const propertyType = semantics.types?.find(({ typeId }) => typeId === report.propertyType) +if (report.promotion?.from !== 'opaque-fcstd-proxy' || report.promotion.to !== 'native-editable-codec' || propertyType?.support !== report.promotion.to || propertyType.statusNames?.length !== 0 || report.promotion.facadeValueModel !== 'ordered-variable-rgba-array-with-external-8-bit-fcstd-packing' || report.promotion.writableRecords !== 2 || report.promotion.fcstdElement !== 'ColorList' || report.promotion.fcstdResourcePath !== 'ColourList' || report.promotion.fcstdResourceBytes !== 12 || !approximately(report.promotion.nativeRoundTripValue, nativeTarget) || !isDeepStrictEqual(report.promotion.browserRoundTripValue, browserTarget) || report.promotion.zeroUnknownDrift !== true) fail('capability promotion is incomplete') +const sync = report.exactBlockerSync +if (sync?.nativeEditableTypes !== 30 || sync.nativeEditableRecords !== 4361 || sync.opaqueTypes !== 50 || sync.opaqueRecords !== 466 || sync.exactPromotionReady !== false || sync.exactBlocker !== '50 runtime property types and 466 records remain opaque-only; complete native document and property semantics') fail('exact blocker synchronization is stale') +if (!isDeepStrictEqual(sync, { nativeEditableTypes: semantics.supportSummary['native-editable-codec'].typeCount, nativeEditableRecords: semantics.supportSummary['native-editable-codec'].recordCount, opaqueTypes: semantics.supportSummary['opaque-fcstd-proxy'].typeCount, opaqueRecords: semantics.supportSummary['opaque-fcstd-proxy'].recordCount, exactPromotionReady: semantics.exactPromotionReady, exactBlocker: semantics.exactBlocker })) fail('promotion report diverges from global property semantics') +if (roundTrip.classification?.zeroUnknownDrift !== true || !approximately(roundTrip.classification.resavedValue, nativeTarget) || chrome.status !== 'pass' || chrome.persistence?.fcstdElement !== 'ColorList' || chrome.persistence.fcstdResourcePath !== 'ColourList' || chrome.persistence.fcstdResourceBytes !== 12 || !isDeepStrictEqual(chrome.persistence.loadedValue, browserTarget) || chrome.resource?.released !== true || chrome.release?.workerTerminated !== true) fail('G/H closure evidence regressed') +console.log(JSON.stringify({ status: 'freecad-property-colorlist-promotion-pass', propertyType: report.propertyType, promotion: report.promotion, completedPhases: requiredPhases, exactBlockerSync: sync, systemExact: report.systemExact }, null, 2)) diff --git a/scripts/check-freecad-property-colorlist-roundtrip.mjs b/scripts/check-freecad-property-colorlist-roundtrip.mjs new file mode 100644 index 0000000..8578468 --- /dev/null +++ b/scripts/check-freecad-property-colorlist-roundtrip.mjs @@ -0,0 +1,28 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-colorlist-roundtrip.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyColorList roundtrip check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-colorlist-roundtrip' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyColorList') fail('baseline is invalid') +const initial = [[17 / 255, 34 / 255, 51 / 255, 68 / 255]] +const target = [ + [51 / 255, 102 / 255, 153 / 255, 204 / 255], + [17 / 255, 34 / 255, 51 / 255, 68 / 255], +] +const approximately = (value, expected) => Array.isArray(value) && value.length === expected.length && value.every((color, colorIndex) => Array.isArray(color) && color.length === 4 && color.every((channel, channelIndex) => typeof channel === 'number' && Math.abs(channel - expected[colorIndex][channelIndex]) <= 1e-7)) +for (const [phase, snapshot] of [['nativeInitial', report.nativeInitial], ['nativeReopened', report.nativeAfter?.reopened], ['nativeResaved', report.nativeAfter?.resaved]]) { + if (snapshot?.object?.typeId !== 'App::FeatureTest' || snapshot.object.propertyTypeId !== 'App::PropertyColorList' || !isDeepStrictEqual(snapshot.object.propertyStatus, []) || !isDeepStrictEqual(snapshot.object.editorMode, []) || snapshot.object.hasShapeProperty !== false || !isDeepStrictEqual(snapshot.objectSet, [{ name: 'ColorListProbe', typeId: 'App::FeatureTest' }])) fail(`${phase} native object semantics are incomplete`) +} +if (!approximately(report.nativeInitial.object.value, initial) || !approximately(report.nativeAfter.reopened.object.value, target) || !approximately(report.nativeAfter.resaved.object.value, target) || !isDeepStrictEqual(report.nativeAfter.reopened.object.value, report.nativeAfter.resaved.object.value)) fail('native initial/reopen/resave values drifted') +let webBefore +let webAfter +try { + webBefore = JSON.parse(report.web.before?.value) + webAfter = JSON.parse(report.web.after?.value) +} catch { fail('Web values are not structured ColorList JSON') } +if (report.web.before?.typeId !== 'App::PropertyColorList' || report.web.before?.element !== 'ColorList' || !approximately(webBefore, initial) || report.web.after?.typeId !== 'App::PropertyColorList' || report.web.after?.element !== 'ColorList' || !approximately(webAfter, target) || report.web.resource?.path !== 'ColourList' || report.web.resource.pathPreserved !== true || report.web.resource.beforeBytes !== 8 || report.web.resource.afterBytes !== 12 || report.web.resource.changed !== true || report.web.objectSetPreserved !== true || report.web.semanticObjectsPreserved !== true || report.web.opaqueEntriesPreserved !== true || !Number.isSafeInteger(report.web.opaquePathsPreserved) || report.web.opaquePathsPreserved < 1) fail('Web edit did not preserve native archive semantics') +if (!approximately(report.classification?.requestedValue, target) || !approximately(JSON.parse(report.classification.webValue), target) || !approximately(report.classification.reopenedValue, target) || !approximately(report.classification.resavedValue, target) || report.classification.nativeOutputMatches !== true || report.classification.unknownSemanticDrift !== false || report.classification.zeroUnknownDrift !== true) fail('round-trip classification is not exact for PropertyColorList') +for (const archive of Object.values(report.archives ?? {})) if (!archive?.path || !Number.isSafeInteger(archive.bytes) || archive.bytes <= 0 || !/^[0-9a-f]{64}$/.test(archive.sha256)) fail('archive evidence is incomplete') +console.log(JSON.stringify({ status: 'freecad-property-colorlist-roundtrip-pass', values: { nativeInitial: report.nativeInitial.object.value, webEdited: JSON.parse(report.classification.webValue), nativeReopened: report.classification.reopenedValue, nativeResaved: report.classification.resavedValue }, resource: report.web.resource, opaquePathsPreserved: report.web.opaquePathsPreserved, semanticObjectsPreserved: report.web.semanticObjectsPreserved, zeroUnknownDrift: report.classification.zeroUnknownDrift }, null, 2)) diff --git a/scripts/check-freecad-property-colorlist-success.mjs b/scripts/check-freecad-property-colorlist-success.mjs new file mode 100644 index 0000000..c5800f2 --- /dev/null +++ b/scripts/check-freecad-property-colorlist-success.mjs @@ -0,0 +1,34 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-colorlist-success.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyColorList success check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-colorlist-success' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyColorList' || report.caseCount !== 2 || report.cases?.length !== 2) fail('baseline is invalid') +const expected = { + default: [[0, 0, 0, 1]], + empty: [], + singletonFloat: [[0.25, 0.5, 0.75, 1]], + mixedElements: [[0.100000001, 0.200000003, 0.300000012, 0.400000006], [1, 0.501960814, 0, 0.250980407], [0.06666667, 0.13333334, 0.200000003, 0.266666681]], + singlePacked: [[0.06666667, 0.13333334, 0.200000003, 0.266666681]], + iterable: [[0, 0.25, 0.5, 0.75], [1, 0.75, 0.5, 0.25]], + indexedDictionary: [[0, 0, 0, 1], [0.06666667, 0.13333334, 0.200000003, 0.266666681], [0, 1, 0, 0.501960814]], + restored: [[0, 0, 0, 1]], +} +for (const typeId of ['App::FeatureTest', 'App::FeatureTestException']) { + const entry = report.cases.find(({ objectTypeId }) => objectTypeId === typeId) + if (entry?.mode !== 'native-property-list-setter' || entry.propertyName !== 'ColourList' || entry.propertyAssignmentsAccepted !== true || !isDeepStrictEqual(entry.defaultValue, expected.default)) fail(`${typeId} setter contract is invalid`) + for (const [phase, value] of Object.entries(expected)) if (!isDeepStrictEqual(entry.phases?.[phase]?.value, value)) fail(`${typeId} ${phase} value changed`) + const large = entry.phases?.largeList?.value + const largeColor = [0.003921569, 0.007843138, 0.011764706, 0.015686275] + if (!Array.isArray(large) || large.length !== 257 || !large.every((color) => isDeepStrictEqual(color, largeColor))) fail(`${typeId} large-list boundary changed`) + for (const snapshot of Object.values(entry.phases)) if (snapshot.propertyTypeId !== 'App::PropertyColorList' || !isDeepStrictEqual(snapshot.propertyStatus, []) || !isDeepStrictEqual(snapshot.editorMode, []) || snapshot.shape?.applicable !== false || snapshot.objectSet?.length !== 1 || snapshot.objectSet[0].typeId !== typeId) fail(`${typeId} native metadata is invalid`) + if (typeId === 'App::FeatureTest') { + for (const snapshot of Object.values(entry.phases)) if (!isDeepStrictEqual(snapshot.objectState, ['Up-to-date']) || snapshot.statusString !== 'Valid') fail(`${typeId} normal execution state changed`) + } else { + if (!isDeepStrictEqual(entry.phases.default.objectState, ['Up-to-date']) || entry.phases.default.statusString !== 'Valid' || entry.phases.default.recomputeResult !== false) fail('FeatureTestException default state changed') + for (const [phase, snapshot] of Object.entries(entry.phases)) if (phase !== 'default' && (!snapshot.objectState.includes('Invalid') || !snapshot.statusString.includes('Testexception'))) fail(`FeatureTestException ${phase} intrinsic diagnostic changed`) + } +} +console.log(JSON.stringify({ status: 'freecad-property-colorlist-success-pass', cases: report.caseCount, phases: Object.keys(report.cases[0].phases), largeListLength: report.cases[0].phases.largeList.value.length, normalHost: 'App::FeatureTest', intrinsicHostDiagnostic: 'App::FeatureTestException' }, null, 2)) diff --git a/scripts/check-freecad-property-direction-failure.mjs b/scripts/check-freecad-property-direction-failure.mjs new file mode 100644 index 0000000..4073e5f --- /dev/null +++ b/scripts/check-freecad-property-direction-failure.mjs @@ -0,0 +1,125 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-direction-failure.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyDirection failure check failed: ${message}`) } + +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-direction-failure' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyDirection') fail('baseline is invalid') + +const setter = report.setterBoundaries +const mirrorObjects = [{ name: 'MirrorSource', typeId: 'Part::Box' }, { name: 'DirectionMirror', typeId: 'Part::Mirroring' }] +if (setter?.object?.name !== 'DirectionMirror' || setter.object.typeId !== 'Part::Mirroring' || setter.property?.name !== 'Normal' || setter.property.typeId !== 'App::PropertyDirection' || !isDeepStrictEqual(setter.baseline, [0, 0, 1])) fail('setter host boundary changed') +const expectedCoercions = new Map([ + ['mixed-numeric-tuple', { requested: '(1, 0.5, 2)', after: [1, 0.5, 2] }], + ['boolean-tuple', { requested: '(True, False, True)', after: [1, 0, 1] }], +]) +if (setter.acceptedCoercions?.length !== expectedCoercions.size) fail('accepted coercion count changed') +for (const entry of setter.acceptedCoercions) { + const expected = expectedCoercions.get(entry.id) + if (!expected || entry.requested !== expected.requested || entry.exception !== null || entry.accepted !== true || !isDeepStrictEqual(entry.before, [0, 0, 1]) || !isDeepStrictEqual(entry.after, expected.after) || entry.objectsPreserved !== true) fail(`${entry.id} accepted coercion changed`) +} + +const expectedFailures = new Map([ + ['none', { requested: 'None', message: "type must be 'Vector' or tuple of three floats, not NoneType" }], + ['list', { requested: '[0.0, 0.0, 1.0]', message: "type must be 'Vector' or tuple of three floats, not list" }], + ['short-tuple', { requested: '(0.0, 1.0)', message: "type must be 'Vector' or tuple of three floats, not tuple" }], + ['long-tuple', { requested: '(0.0, 0.0, 1.0, 2.0)', message: "type must be 'Vector' or tuple of three floats, not tuple" }], + ['string-component', { requested: "(0.0, 'bad', 1.0)", message: 'Not allowed type used in tuple (float expected)...' }], + ['scalar-float', { requested: '1.0', message: "type must be 'Vector' or tuple of three floats, not float" }], + ['scalar-integer', { requested: '1', message: "type must be 'Vector' or tuple of three floats, not int" }], +]) +if (setter.failures?.length !== expectedFailures.size) fail('setter failure count changed') +for (const entry of setter.failures) { + const expected = expectedFailures.get(entry.id) + if (!expected || entry.requested !== expected.requested || entry.exception?.type !== 'TypeError' || entry.exception.message !== expected.message || !isDeepStrictEqual(entry.before, [0, 0, 1]) || !isDeepStrictEqual(entry.after, [0, 0, 1]) || entry.valuePreserved !== true || entry.objectsPreserved !== true || entry.polluted !== false || !isDeepStrictEqual(entry.beforeObjects, mirrorObjects) || !isDeepStrictEqual(entry.afterObjects, mirrorObjects)) fail(`${entry.id} setter rejection changed`) +} +if (setter.documentIntegrity?.objectsPreserved !== true || !isDeepStrictEqual(setter.documentIntegrity.initialObjects, mirrorObjects) || !isDeepStrictEqual(setter.documentIntegrity.finalObjects, mirrorObjects)) fail('setter cases polluted the document') + +const hostExpectations = { + 'Mirroring-zero': { + objectTypeId: 'Part::Mirroring', + propertyName: 'Normal', + objects: mirrorObjects, + beforeState: { state: ['Up-to-date'], statusString: 'Valid', mustExecute: false }, + afterSetState: { state: ['Touched'], statusString: 'Touched', mustExecute: true }, + afterState: { state: ['Touched', 'Invalid'], statusString: 'gp_Dir() - input vector has zero norm', mustExecute: true }, + shape: { shapeType: 'Solid', solids: 1, faces: 6, edges: 12, vertices: 8 }, + }, + 'ProjectOnSurface-zero': { + objectTypeId: 'Part::ProjectOnSurface', + propertyName: 'Direction', + objects: [{ name: 'ProjectionSupport', typeId: 'Part::Feature' }, { name: 'ProjectionWire', typeId: 'Part::Feature' }, { name: 'DirectionProjection', typeId: 'Part::ProjectOnSurface' }], + beforeState: { state: ['Up-to-date'], statusString: 'Valid', mustExecute: false }, + afterSetState: { state: ['Touched'], statusString: 'Touched', mustExecute: false }, + afterState: { state: ['Touched', 'Invalid'], statusString: 'gp_Dir() - input vector has zero norm', mustExecute: false }, + shape: { shapeType: 'Compound', solids: 0, faces: 0, edges: 4, vertices: 4 }, + }, +} +if (report.consumerFailures?.length !== 2) fail('zero-direction host coverage changed') +for (const entry of report.consumerFailures) { + const expected = hostExpectations[entry.id] + if (!expected || entry.objectTypeId !== expected.objectTypeId || entry.propertyName !== expected.propertyName || !isDeepStrictEqual(entry.requested, [0, 0, 0]) || entry.initialRecomputeResult !== true || entry.setterException !== null || entry.recomputeException !== null || entry.recomputeResult !== true || entry.objectsPreserved !== true) fail(`${entry.id} zero-direction execution boundary changed`) + if (!isDeepStrictEqual(entry.before.value, [0, 0, 1]) || !isDeepStrictEqual(entry.afterSet.value, [0, 0, 0]) || !isDeepStrictEqual(entry.afterRecompute.value, [0, 0, 0]) || !isDeepStrictEqual(entry.before.state, expected.beforeState) || !isDeepStrictEqual(entry.afterSet.state, expected.afterSetState) || !isDeepStrictEqual(entry.afterRecompute.state, expected.afterState) || !isDeepStrictEqual(entry.before.objects, expected.objects) || !isDeepStrictEqual(entry.afterRecompute.objects, expected.objects)) fail(`${entry.id} zero-direction state changed`) + for (const snapshot of [entry.before.shape, entry.afterSet.shape, entry.afterRecompute.shape]) { + if (snapshot?.isNull !== false || snapshot.valid !== true || snapshot.shapeType !== expected.shape.shapeType || snapshot.solids !== expected.shape.solids || snapshot.faces !== expected.shape.faces || snapshot.edges !== expected.shape.edges || snapshot.vertices !== expected.shape.vertices || typeof snapshot.brepSha256 !== 'string' || snapshot.brepSha256.length !== 64) fail(`${entry.id} retained Shape evidence changed`) + } + if (entry.before.shape.brepSha256 !== entry.afterSet.shape.brepSha256 || entry.before.shape.brepSha256 !== entry.afterRecompute.shape.brepSha256) fail(`${entry.id} did not retain the last valid Shape`) +} + +const nonFiniteIds = new Set([ + 'Mirroring-nan', + 'Mirroring-positive-infinity', + 'Mirroring-negative-infinity', + 'ProjectOnSurface-nan', + 'ProjectOnSurface-positive-infinity', + 'ProjectOnSurface-negative-infinity', +]) +if (report.nonFiniteConsumerBoundaries?.length !== nonFiniteIds.size || new Set(report.nonFiniteConsumerBoundaries.map(({ id }) => id)).size !== nonFiniteIds.size) fail('non-finite isolated coverage changed') +for (const boundary of report.nonFiniteConsumerBoundaries) { + if (!nonFiniteIds.has(boundary.id) || boundary.mode !== `non-finite:${boundary.id.replace('-', ':')}` || boundary.attemptCount !== 2 || boundary.stable !== true || boundary.attempts?.length !== 2) fail(`${boundary.id} isolated identity changed`) + const mirroring = boundary.id.startsWith('Mirroring-') + const expectedClassification = mirroring ? 'native-synchronous-consumer-timeout' : 'native-process-exit-without-probe-completion' + if (boundary.classification !== expectedClassification) fail(`${boundary.id} isolated classification changed`) + for (const [index, attempt] of boundary.attempts.entries()) { + if (attempt.attempt !== index + 1 || attempt.timeoutMs !== 5000 || !(attempt.elapsedMs >= (mirroring ? 5000 : 0)) || !(attempt.elapsedMs < 10000) || attempt.progressMarkerObserved !== true || attempt.completionMarkerObserved !== false || attempt.completedCase !== null) fail(`${boundary.id} attempt ${index + 1} metadata changed`) + if (mirroring) { + if (attempt.timedOut !== true || attempt.exitStatus !== null || attempt.signal !== 'SIGTERM' || attempt.errorCode !== 'ETIMEDOUT' || attempt.outcome !== 'timeout' || !attempt.diagnostic.includes(`FREECAD_PROPERTY_DIRECTION_PROGRESS=${boundary.id}`)) fail(`${boundary.id} timeout evidence changed`) + } else if (attempt.timedOut !== false || attempt.exitStatus !== 0 || attempt.signal !== null || attempt.errorCode !== null || attempt.outcome !== 'process-exited-without-completion' || !attempt.diagnostic.some((line) => line.includes('Courbes non jointives'))) fail(`${boundary.id} process-exit evidence changed`) + } +} + +const dependencyExpectations = { + 'Mirroring-no-source': { objectTypeId: 'Part::Mirroring', propertyName: 'Normal', removed: { property: 'Source', value: null }, state: { state: ['Touched', 'Invalid'], statusString: 'No object linked', mustExecute: true }, retainsShape: true }, + 'ProjectOnSurface-no-support': { objectTypeId: 'Part::ProjectOnSurface', propertyName: 'Direction', removed: { property: 'SupportFace', value: null }, state: { state: ['Touched', 'Invalid'], statusString: 'No support face specified', mustExecute: false }, retainsShape: true }, + 'ProjectOnSurface-no-projection': { objectTypeId: 'Part::ProjectOnSurface', propertyName: 'Direction', removed: { property: 'Projection', value: [] }, state: { state: ['Up-to-date'], statusString: 'Valid', mustExecute: false }, retainsShape: false }, +} +if (report.dependencyFailures?.length !== 3) fail('dependency coverage changed') +for (const entry of report.dependencyFailures) { + const expected = dependencyExpectations[entry.id] + if (!expected || entry.objectTypeId !== expected.objectTypeId || entry.propertyName !== expected.propertyName || !isDeepStrictEqual(entry.removed, expected.removed) || entry.recomputeException !== null || entry.recomputeResult !== true || entry.objectsPreserved !== true || !isDeepStrictEqual(entry.before.value, [0, 0, 1]) || !isDeepStrictEqual(entry.afterRecompute.value, [0, 0, 1]) || !isDeepStrictEqual(entry.before.objects, entry.afterRecompute.objects) || !isDeepStrictEqual(entry.afterRecompute.state, expected.state)) fail(`${entry.id} dependency behavior changed`) + if (expected.retainsShape) { + if (entry.before.shape.brepSha256 !== entry.afterRecompute.shape.brepSha256 || entry.afterRecompute.shape.isNull !== false || entry.afterRecompute.shape.valid !== true) fail(`${entry.id} did not retain its last valid Shape`) + } else if (entry.afterRecompute.shape.isNull !== true || entry.afterRecompute.shape.shapeType !== 'Null' || entry.afterRecompute.shape.edges !== 0) fail(`${entry.id} empty Projection boundary changed`) +} + +const disabled = report.disabled +if (disabled?.classification !== 'editor-readonly-python-mutable-until-immutable' || !isDeepStrictEqual(disabled.before, [0, 0, 1]) || !isDeepStrictEqual(disabled.editorMode, ['ReadOnly']) || !isDeepStrictEqual(disabled.editorRequested, [1, 0, 1]) || disabled.editorException !== null || !isDeepStrictEqual(disabled.editorAfter, [1, 0, 1]) || disabled.pythonBypassesEditorReadOnly !== true) fail('editor ReadOnly boundary changed') +if (!isDeepStrictEqual(disabled.immutableStatus, ['Immutable']) || !isDeepStrictEqual(disabled.immutableRequested, [0, 1, 1]) || disabled.immutableException?.type !== 'AttributeError' || disabled.immutableException.message !== "Object attribute 'Normal' is read-only" || !isDeepStrictEqual(disabled.immutableAfter, [0, 0, 1]) || disabled.immutableValuePreserved !== true || !isDeepStrictEqual(disabled.restoredStatus, []) || !isDeepStrictEqual(disabled.restoredEditorMode, [])) fail('Immutable boundary changed') + +const transaction = report.transaction +if (transaction?.undoMode !== 1 || transaction.pendingAfterEdit !== true || transaction.pendingAfterAbort !== false || transaction.activeAfterEdit?.name !== 'property-direction-cancel' || !(transaction.activeAfterEdit.id > 0) || transaction.activeAfterAbort?.name !== '' || transaction.activeAfterAbort.id !== 0 || transaction.recoveryRecomputeResult !== true || transaction.restored !== true || transaction.objectsRestored !== true) fail('transaction lifecycle changed') +if (!isDeepStrictEqual(transaction.before, [0, 0, 1]) || !isDeepStrictEqual(transaction.edited, [0.25, -0.5, 1.5]) || !isDeepStrictEqual(transaction.afterAbort, [0, 0, 1]) || !isDeepStrictEqual(transaction.afterRecompute, [0, 0, 1]) || !isDeepStrictEqual(transaction.stateAfterEdit, { state: ['Touched'], statusString: 'Touched', mustExecute: true }) || !isDeepStrictEqual(transaction.stateAfterAbort, { state: ['Touched'], statusString: 'Touched', mustExecute: true }) || !isDeepStrictEqual(transaction.stateAfterRecompute, { state: ['Up-to-date'], statusString: 'Valid', mustExecute: false }) || !isDeepStrictEqual(transaction.objectsBefore, mirrorObjects) || !isDeepStrictEqual(transaction.objectsAfter, mirrorObjects)) fail('transaction abort recovery changed') +if (report.cancellationBoundary?.supported !== false || report.cancellationBoundary.classification !== 'synchronous-property-setter' || report.cancellationBoundary.reason !== 'no-native-cancel-hook' || report.cancellationBoundary.replacement !== 'abort-active-document-transaction') fail('cancellation boundary changed') +if (report.documentIntegrity?.allObjectsPreserved !== true || report.documentIntegrity.setter?.objectsPreserved !== true || report.documentIntegrity.disabledAndTransaction?.objectsPreserved !== true) fail('failure cases polluted a document object set') + +console.log(JSON.stringify({ + status: 'freecad-property-direction-failure-pass', + acceptedCoercions: [...expectedCoercions.keys()], + rejectedInputs: [...expectedFailures.keys()], + zeroDirectionConsumers: report.consumerFailures.map(({ id, afterRecompute }) => ({ id, status: afterRecompute.state.statusString })), + nonFiniteBoundaries: report.nonFiniteConsumerBoundaries.map(({ id, classification, attemptCount }) => ({ id, classification, attemptCount })), + dependencyBoundaries: report.dependencyFailures.map(({ id, afterRecompute }) => ({ id, state: afterRecompute.state })), + transactionRestored: transaction.restored, +}, null, 2)) diff --git a/scripts/check-freecad-property-direction-inventory.mjs b/scripts/check-freecad-property-direction-inventory.mjs new file mode 100644 index 0000000..690cabf --- /dev/null +++ b/scripts/check-freecad-property-direction-inventory.mjs @@ -0,0 +1,59 @@ +import { createHash } from 'node:crypto' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const runtimePath = resolve(root, '.cache/freecad/reference-desktop.json') +const reportPath = resolve(root, 'config/freecad-property-direction-inventory.json') +const fail = (message) => { throw new Error(`FreeCAD PropertyDirection inventory check failed: ${message}`) } +const [runtimeContent, reportContent] = await Promise.all([readFile(runtimePath), readFile(reportPath)]) +const runtime = JSON.parse(runtimeContent) +const report = JSON.parse(reportContent) + +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.propertyType !== 'App::PropertyDirection' || report.classification !== 'opaque-fcstd-proxy') fail('report boundary is invalid') +if (report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is not locked to FreeCAD 1.1.1') +if (report.recordCount !== 2 || !Array.isArray(report.records) || report.records.length !== 2) fail('record count is not exactly two') +if (report.provenance?.runtime?.path !== '.cache/freecad/reference-desktop.json' || report.provenance.runtime.bytes !== runtimeContent.length || report.provenance.runtime.sha256 !== createHash('sha256').update(runtimeContent).digest('hex')) fail('runtime provenance is stale') +const storage = report.storage +if (storage?.inheritedFrom !== 'App::PropertyVector' || storage.xmlElement !== 'PropertyVector' || storage.attributes?.join(',') !== 'valueX,valueY,valueZ' || storage.scalarEncoding !== 'decimal-double' || storage.externalResource !== false) fail('native storage contract is incomplete') + +const expected = { + 'Part::Mirroring.Normal': { group: 'Plane', dependencyNames: 'Source,Base,MirrorPlane', consumer: 'gp_Ax2(gp_Pnt(Base), gp_Dir(Normal))' }, + 'Part::ProjectOnSurface.Direction': { group: 'Projection', dependencyNames: 'SupportFace,Projection', consumer: 'gp_Dir(Direction)' }, +} +for (const [identity, contract] of Object.entries(expected)) { + const [objectTypeId, propertyName] = identity.split(/\.(?=[^.]+$)/) + const record = report.records.find((candidate) => candidate.objectTypeId === objectTypeId && candidate.propertyName === propertyName) + if (!record || record.objectAvailable !== true || record.probeStatus !== 'available' || record.group !== contract.group || record.status?.length !== 0 || record.defaultDisplayValue !== 'Vector (0.0, 0.0, 1.0)' || JSON.stringify(record.defaultValue) !== '[0,0,1]') fail(`native inventory changed for ${identity}`) + const model = record.valueModel + if (model?.kind !== 'three-component-direction-vector' || model.representation !== 'Base::Vector3d' || model.normalizationAtPropertyBoundary !== 'none' || model.unit !== 'Length' || model.writable !== true) fail(`value model changed for ${identity}`) + if (record.inputs?.accepted?.join(',') !== 'Base.Vector,tuple-of-three-float-or-integer-components' || record.inputs.listAccepted !== false || record.inputs.componentPaths?.join(',') !== 'x,y,z' || record.editor !== 'Gui::PropertyEditor::PropertyDirectionItem') fail(`setter or editor contract changed for ${identity}`) + if (record.dependencies?.map(({ propertyName: name }) => name).join(',') !== contract.dependencyNames || record.applicability?.requiredObjectTypeId !== objectTypeId || record.applicability.source !== 'Document.supportedTypes runtime inventory' || record.applicability.propertyWriteRequiresShape !== false || record.applicability.hostExecutionRequiresShapeInputs !== true || record.applicability.nonZeroRequiredByConsumer !== true || record.applicability.consumer !== contract.consumer) fail(`dependencies or applicability changed for ${identity}`) +} +const mirror = report.records.find(({ objectTypeId }) => objectTypeId === 'Part::Mirroring') +const mirrorPlane = mirror?.dependencies?.find(({ propertyName }) => propertyName === 'MirrorPlane') +if (mirrorPlane?.role !== 'optional-plane-override' || mirrorPlane.requiredForExecution !== false || mirrorPlane.overrides?.join(',') !== 'Base,Normal' || mirrorPlane.overriddenStatus !== 'ReadOnly') fail('Mirroring plane override contract is incomplete') +const projection = report.records.find(({ objectTypeId }) => objectTypeId === 'Part::ProjectOnSurface') +if (projection?.dependencies?.some(({ requiredForExecution }) => requiredForExecution !== true)) fail('ProjectOnSurface dependencies are not locked') + +const nativeMatches = [] +for (const objectType of runtime.runtimeObjects?.types ?? []) for (const property of objectType.properties ?? []) if (property.typeId === 'App::PropertyDirection') nativeMatches.push({ objectTypeId: objectType.typeId, propertyName: property.name, group: property.group, status: property.status, defaultValue: property.default }) +if (nativeMatches.length !== 2) fail('locked runtime oracle no longer contains two PropertyDirection records') +for (const locked of report.provenance?.sources ?? []) { + const content = await readFile(resolve(root, locked?.path ?? '')) + if (content.length !== locked.bytes || createHash('sha256').update(content).digest('hex') !== locked.sha256) fail(`source provenance is stale for ${locked.path}`) +} +const [propertyHeader, propertySource, editorHeader, editorSource, mirrorSource, projectionSource] = await Promise.all([ + readFile(resolve(root, '.cache/freecad/FreeCAD/src/App/PropertyGeo.h'), 'utf8'), + readFile(resolve(root, '.cache/freecad/FreeCAD/src/App/PropertyGeo.cpp'), 'utf8'), + readFile(resolve(root, '.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.h'), 'utf8'), + readFile(resolve(root, '.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.cpp'), 'utf8'), + readFile(resolve(root, '.cache/freecad/FreeCAD/src/Mod/Part/App/FeatureMirroring.cpp'), 'utf8'), + readFile(resolve(root, '.cache/freecad/FreeCAD/src/Mod/Part/App/FeatureProjectOnSurface.cpp'), 'utf8'), +]) +if (!propertyHeader.includes('class AppExport PropertyDirection: public PropertyVector') || !propertyHeader.includes('return Base::Unit::Length;') || !propertyHeader.includes('Gui::PropertyEditor::PropertyDirectionItem')) fail('locked PropertyDirection declaration changed') +if (!propertySource.includes('TYPESYSTEM_SOURCE(App::PropertyDirection, App::PropertyVector)') || !propertySource.includes('PyObject_TypeCheck(value, &(Base::VectorPy::Type))') || !propertySource.includes('PyTuple_Check(value) && PyTuple_Size(value) == 3') || !propertySource.includes('PyFloat_Check(item)') || !propertySource.includes('PyLong_Check(item)') || !propertySource.includes(' valueModel.writable).length, defaultValue: report.records[0].defaultValue, storage: report.storage, classification: report.classification }, null, 2)) diff --git a/scripts/check-freecad-property-direction-mutation.mjs b/scripts/check-freecad-property-direction-mutation.mjs new file mode 100644 index 0000000..a9d5c4e --- /dev/null +++ b/scripts/check-freecad-property-direction-mutation.mjs @@ -0,0 +1,56 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-direction-mutation.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyDirection mutation check failed: ${message}`) } + +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-direction-mutation' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyDirection') fail('baseline is invalid') +if (report.caseCount !== 2 || report.cases?.length !== 2) fail('mutation host coverage changed') + +const expectedHosts = { + 'Part::Mirroring': { + caseId: 'Mirroring', + objectName: 'DirectionMirror', + propertyName: 'Normal', + objectSet: [{ name: 'MirrorSource', typeId: 'Part::Box' }, { name: 'DirectionMirror', typeId: 'Part::Mirroring' }], + afterSetMustExecute: true, + shape: { shapeType: 'Solid', solids: 1, faces: 6, edges: 12, vertices: 8, area: 52, volume: 24 }, + }, + 'Part::ProjectOnSurface': { + caseId: 'ProjectOnSurface', + objectName: 'DirectionProjection', + propertyName: 'Direction', + objectSet: [{ name: 'ProjectionSupport', typeId: 'Part::Feature' }, { name: 'ProjectionWire', typeId: 'Part::Feature' }, { name: 'DirectionProjection', typeId: 'Part::ProjectOnSurface' }], + afterSetMustExecute: false, + shape: { shapeType: 'Compound', solids: 0, faces: 0, edges: 4, vertices: 4, area: 0, volume: 0 }, + }, +} +for (const entry of report.cases) { + const expected = expectedHosts[entry.objectTypeId] + if (!expected || entry.caseId !== expected.caseId || entry.objectName !== expected.objectName || entry.propertyName !== expected.propertyName || !isDeepStrictEqual(entry.editedValue, [0.25, -0.5, 1.5]) || entry.valueChanged !== true || entry.valueRestored !== true || entry.geometryChanged !== true || entry.geometryRestored !== true || entry.objectsPreserved !== true) fail(`${entry.objectTypeId} mutation summary changed`) + const phases = entry.phases + const phaseExpectations = { + before: { value: [0, 0, 1], state: ['Up-to-date'], status: 'Valid', mustExecute: false, recomputeResult: true }, + afterSet: { value: [0.25, -0.5, 1.5], state: ['Touched'], status: 'Touched', mustExecute: expected.afterSetMustExecute, recomputeResult: null }, + afterRecompute: { value: [0.25, -0.5, 1.5], state: ['Up-to-date'], status: 'Valid', mustExecute: false, recomputeResult: true }, + afterRestoreSet: { value: [0, 0, 1], state: ['Touched'], status: 'Touched', mustExecute: expected.afterSetMustExecute, recomputeResult: null }, + afterRestoreRecompute: { value: [0, 0, 1], state: ['Up-to-date'], status: 'Valid', mustExecute: false, recomputeResult: true }, + } + for (const [phase, phaseExpected] of Object.entries(phaseExpectations)) { + const snapshot = phases?.[phase] + if (!snapshot || !isDeepStrictEqual(snapshot.value, phaseExpected.value) || snapshot.propertyTypeId !== 'App::PropertyDirection' || !isDeepStrictEqual(snapshot.propertyStatus, []) || !isDeepStrictEqual(snapshot.editorMode, []) || !isDeepStrictEqual(snapshot.objectState, phaseExpected.state) || snapshot.statusString !== phaseExpected.status || snapshot.mustExecute !== phaseExpected.mustExecute || snapshot.recomputeResult !== phaseExpected.recomputeResult || !isDeepStrictEqual(snapshot.objectSet, expected.objectSet)) fail(`${entry.objectTypeId} ${phase} property or state changed`) + const shape = snapshot.shape + if (shape?.isNull !== false || shape.valid !== true || shape.shapeType !== expected.shape.shapeType || shape.solids !== expected.shape.solids || shape.faces !== expected.shape.faces || shape.edges !== expected.shape.edges || shape.vertices !== expected.shape.vertices || shape.area !== expected.shape.area || shape.volume !== expected.shape.volume || !Array.isArray(shape.bounds) || shape.bounds.length !== 6 || typeof shape.brepSha256 !== 'string' || shape.brepSha256.length !== 64) fail(`${entry.objectTypeId} ${phase} Shape evidence changed`) + } + if (phases.before.shape.brepSha256 === phases.afterRecompute.shape.brepSha256 || isDeepStrictEqual(phases.before.shape.bounds, phases.afterRecompute.shape.bounds)) fail(`${entry.objectTypeId} edit did not mutate geometry`) + if (!isDeepStrictEqual(phases.before.shape, phases.afterRestoreRecompute.shape)) fail(`${entry.objectTypeId} restore did not recover exact geometry`) +} + +console.log(JSON.stringify({ + status: 'freecad-property-direction-mutation-pass', + cases: report.caseCount, + editedValue: [0.25, -0.5, 1.5], + restored: report.cases.map(({ objectTypeId, valueRestored, geometryRestored, objectsPreserved }) => ({ objectTypeId, valueRestored, geometryRestored, objectsPreserved })), +}, null, 2)) diff --git a/scripts/check-freecad-property-direction-promotion.mjs b/scripts/check-freecad-property-direction-promotion.mjs new file mode 100644 index 0000000..756e2cd --- /dev/null +++ b/scripts/check-freecad-property-direction-promotion.mjs @@ -0,0 +1,30 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const [report, semantics, progress, roundTrip, chrome] = await Promise.all([ + load('config/freecad-property-direction-promotion.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), + load('config/freecad-property-direction-roundtrip.json'), + load('config/chrome-property-direction-verification.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyDirection promotion check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.taskId !== 'PROP-app-propertydirection-I' || report.propertyType !== 'App::PropertyDirection' || report.recordCount !== 2 || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.systemExact !== false) fail('promotion report boundary is invalid') +const requiredPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredPhases) { + const taskId = `PROP-app-propertydirection-${phase}` + if (!completed.has(taskId) || !Array.isArray(report.phaseEvidence?.[phase]) || report.phaseEvidence[phase].length === 0 || !isDeepStrictEqual(report.phaseEvidence[phase], completed.get(taskId).evidence)) fail(`phase ${phase} evidence is incomplete`) +} +const target = { x: 0.25, y: -0.5, z: 1.5 } +const vectorEquals = (left, right) => !!left && (['x', 'y', 'z'].every((axis) => left[axis] === right[axis])) +const propertyType = semantics.types?.find(({ typeId }) => typeId === report.propertyType) +if (report.promotion?.from !== 'opaque-fcstd-proxy' || report.promotion.to !== 'native-editable-codec' || propertyType?.support !== report.promotion.to || propertyType.recordCount !== 2 || propertyType.objectTypeCount !== 2 || report.promotion.facadeValueModel !== 'three-finite-vector-components-with-native-propertyvector-fcstd-payload' || report.promotion.writableRecords !== 2 || report.promotion.fcstdElement !== 'PropertyVector' || !vectorEquals(report.promotion.nativeRoundTripValue, target) || !vectorEquals(report.promotion.browserRoundTripValue, target) || report.promotion.zeroUnknownDrift !== true) fail('capability promotion is incomplete') +const sync = report.exactBlockerSync +if (sync?.nativeEditableTypes !== 30 || sync.nativeEditableRecords !== 4361 || sync.opaqueTypes !== 50 || sync.opaqueRecords !== 466 || sync.exactPromotionReady !== false || sync.exactBlocker !== '50 runtime property types and 466 records remain opaque-only; complete native document and property semantics') fail('exact blocker synchronization is stale') +if (!isDeepStrictEqual(sync, { nativeEditableTypes: semantics.supportSummary['native-editable-codec'].typeCount, nativeEditableRecords: semantics.supportSummary['native-editable-codec'].recordCount, opaqueTypes: semantics.supportSummary['opaque-fcstd-proxy'].typeCount, opaqueRecords: semantics.supportSummary['opaque-fcstd-proxy'].recordCount, exactPromotionReady: semantics.exactPromotionReady, exactBlocker: semantics.exactBlocker })) fail('promotion report diverges from global property semantics') +if (roundTrip.classification?.zeroUnknownDrift !== true || !vectorEquals(roundTrip.classification.resavedValue, target) || chrome.status !== 'pass' || chrome.persistence?.fcstdElement !== 'PropertyVector' || chrome.persistence.fcstdValue !== JSON.stringify(target) || !vectorEquals(chrome.persistence.loadedValue, target) || chrome.resource?.released !== true || chrome.release?.workerTerminated !== true) fail('G/H closure evidence regressed') +console.log(JSON.stringify({ status: 'freecad-property-direction-promotion-pass', propertyType: report.propertyType, promotion: report.promotion, completedPhases: requiredPhases, exactBlockerSync: sync, systemExact: report.systemExact }, null, 2)) diff --git a/scripts/check-freecad-property-direction-roundtrip.mjs b/scripts/check-freecad-property-direction-roundtrip.mjs new file mode 100644 index 0000000..2005746 --- /dev/null +++ b/scripts/check-freecad-property-direction-roundtrip.mjs @@ -0,0 +1,33 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-direction-roundtrip.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyDirection roundtrip check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-direction-roundtrip' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyDirection') fail('baseline is invalid') + +const initial = { x: 0, y: 0, z: 1 } +const target = { x: 0.25, y: -0.5, z: 1.5 } +const objectSet = [{ name: 'MirrorSource', typeId: 'Part::Box' }, { name: 'DirectionMirror', typeId: 'Part::Mirroring' }] +for (const [phase, snapshot] of [['nativeInitial', report.nativeInitial], ['nativeReopened', report.nativeAfter?.reopened], ['nativeResaved', report.nativeAfter?.resaved], ['nativeRepeatReopened', report.nativeRepeat?.reopened], ['nativeRepeatResaved', report.nativeRepeat?.resaved]]) { + if (snapshot?.object?.name !== 'DirectionMirror' || snapshot.object.typeId !== 'Part::Mirroring' || snapshot.object.propertyTypeId !== 'App::PropertyDirection' || !isDeepStrictEqual(snapshot.object.propertyStatus, []) || !isDeepStrictEqual(snapshot.object.editorMode, []) || !isDeepStrictEqual(snapshot.object.state, ['Up-to-date']) || snapshot.object.statusString !== 'Valid' || !isDeepStrictEqual(snapshot.objectSet, objectSet)) fail(`${phase} native object semantics are incomplete`) + const shape = snapshot.object.shape + if (shape?.isNull !== false || shape.valid !== true || shape.shapeType !== 'Solid' || shape.solids !== 1 || shape.faces !== 6 || shape.edges !== 12 || shape.vertices !== 8 || shape.area !== 52 || shape.volume !== 24 || !Array.isArray(shape.bounds) || shape.bounds.length !== 6 || !/^[0-9a-f]{64}$/.test(shape.brepSha256)) fail(`${phase} native Shape evidence is incomplete`) +} +if (!isDeepStrictEqual(report.nativeInitial.object.value, initial) || !isDeepStrictEqual(report.nativeAfter.reopened.object.value, target) || !isDeepStrictEqual(report.nativeAfter.resaved.object.value, target) || !isDeepStrictEqual(report.nativeRepeat.reopened.object.value, target) || !isDeepStrictEqual(report.nativeRepeat.resaved.object.value, target)) fail('native direction values drifted') +let webBefore +let webAfter +try { + webBefore = JSON.parse(report.web.before?.value) + webAfter = JSON.parse(report.web.after?.value) +} catch { fail('Web Direction values are not structured JSON') } +if (report.web.before?.typeId !== 'App::PropertyDirection' || report.web.before?.element !== 'PropertyVector' || !isDeepStrictEqual(webBefore, initial) || report.web.after?.typeId !== 'App::PropertyDirection' || report.web.after?.element !== 'PropertyVector' || !isDeepStrictEqual(webAfter, target) || report.web.targetMarkedTouched !== true || report.web.webOutputMatches !== true || report.web.objectSetPreserved !== true || report.web.semanticObjectsPreserved !== true || report.web.opaqueEntriesPreserved !== true || !Number.isSafeInteger(report.web.opaquePathsPreserved) || report.web.opaquePathsPreserved < 1) fail('Web edit did not preserve native archive semantics') +if (!isDeepStrictEqual(report.classification?.requestedValue, target) || !isDeepStrictEqual(report.classification.webValue, target) || !isDeepStrictEqual(report.classification.reopenedValue, target) || !isDeepStrictEqual(report.classification.resavedValue, target) || report.classification.nativeOutputMatches !== true || report.classification.nativeShapeChanged !== true || report.classification.nativeShapeStructureStable !== true || report.classification.nativeBrepReserialized !== true || report.classification.nativeBrepEvolutionReproduced !== true || report.classification.nativeAllowedEvolution?.classification !== 'native-allowed-evolution' || report.classification.nativeAllowedEvolution.dimension !== 'brep-serialization' || !report.classification.nativeAllowedEvolution.reason.includes('reserializes') || report.classification.unknownSemanticDrift !== false || report.classification.zeroUnknownDrift !== true) fail('round-trip classification is not exact for PropertyDirection') +const shapeStructure = ({ brepSha256: _brepSha256, ...shape }) => shape +if (report.nativeInitial.object.shape.brepSha256 === report.nativeAfter.reopened.object.shape.brepSha256 || isDeepStrictEqual(report.nativeInitial.object.shape.bounds, report.nativeAfter.reopened.object.shape.bounds)) fail('native Direction did not change Shape geometry') +if (!isDeepStrictEqual(shapeStructure(report.nativeAfter.reopened.object.shape), shapeStructure(report.nativeAfter.resaved.object.shape)) || !isDeepStrictEqual(shapeStructure(report.nativeAfter.reopened.object.shape), shapeStructure(report.nativeRepeat.reopened.object.shape)) || !isDeepStrictEqual(shapeStructure(report.nativeAfter.reopened.object.shape), shapeStructure(report.nativeRepeat.resaved.object.shape))) fail('native Shape structure drifted across resave repetitions') +if (report.nativeAfter.reopened.object.shape.brepSha256 === report.nativeAfter.resaved.object.shape.brepSha256 || report.nativeAfter.reopened.object.shape.brepSha256 !== report.nativeRepeat.reopened.object.shape.brepSha256 || report.nativeAfter.resaved.object.shape.brepSha256 !== report.nativeRepeat.resaved.object.shape.brepSha256) fail('native BREP serialization evolution was not reproduced') +for (const archive of Object.values(report.archives ?? {})) if (!archive?.path || !Number.isSafeInteger(archive.bytes) || archive.bytes <= 0 || !/^[0-9a-f]{64}$/.test(archive.sha256)) fail('archive evidence is incomplete') + +console.log(JSON.stringify({ status: 'freecad-property-direction-roundtrip-pass', values: { nativeInitial: report.nativeInitial.object.value, webEdited: report.classification.webValue, nativeReopened: report.classification.reopenedValue, nativeResaved: report.classification.resavedValue }, shapeChanged: report.classification.nativeShapeChanged, shapeStructureStable: report.classification.nativeShapeStructureStable, nativeAllowedEvolution: report.classification.nativeAllowedEvolution, opaquePathsPreserved: report.web.opaquePathsPreserved, zeroUnknownDrift: report.classification.zeroUnknownDrift }, null, 2)) diff --git a/scripts/check-freecad-property-direction-success.mjs b/scripts/check-freecad-property-direction-success.mjs new file mode 100644 index 0000000..0699c96 --- /dev/null +++ b/scripts/check-freecad-property-direction-success.mjs @@ -0,0 +1,59 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-direction-success.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyDirection success check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-direction-success' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyDirection') fail('baseline is invalid') +if (report.caseCount !== 2 || !Array.isArray(report.cases) || report.cases.length !== 2 || new Set(report.cases.map(({ objectTypeId }) => objectTypeId)).size !== 2) fail('native success case inventory is incomplete') + +const values = { + axisZTuple: [0, 0, 1], + integerTuple: [1, 1, 2], + nonUnitFloatTuple: [0.25, -0.5, 1.5], + vectorObject: [-0.125, 0.25, 1], + nearAxisTuple: [1e-9, -1e-9, 1], + largeFiniteTuple: [1e6, -2e6, 3e6], +} +const requested = Object.fromEntries(Object.entries(values).map(([phase, value]) => [phase, { inputKind: phase === 'vectorObject' ? 'Base.Vector' : 'tuple', value }])) +const expectedHosts = { + 'Part::Mirroring': { + objectName: 'DirectionMirror', + propertyName: 'Normal', + objectSet: [{ name: 'MirrorSource', typeId: 'Part::Box' }, { name: 'DirectionMirror', typeId: 'Part::Mirroring' }], + shape: { shapeType: 'Solid', solids: 1, faces: 6, edges: 12, vertices: 8, area: 52, volume: 24 }, + afterSetMustExecute: true, + }, + 'Part::ProjectOnSurface': { + objectName: 'DirectionProjection', + propertyName: 'Direction', + objectSet: [{ name: 'ProjectionSupport', typeId: 'Part::Feature' }, { name: 'ProjectionWire', typeId: 'Part::Feature' }, { name: 'DirectionProjection', typeId: 'Part::ProjectOnSurface' }], + shape: { shapeType: 'Compound', solids: 0, faces: 0, edges: 4, vertices: 4, area: 0, volume: 0 }, + afterSetMustExecute: false, + }, +} +for (const [typeId, expected] of Object.entries(expectedHosts)) { + const entry = report.cases.find(({ objectTypeId }) => objectTypeId === typeId) + if (entry?.objectName !== expected.objectName || entry.propertyName !== expected.propertyName || entry.mode !== 'direct-native-property-setter-with-valid-host-geometry' || !isDeepStrictEqual(entry.defaultValue, [0, 0, 1]) || !isDeepStrictEqual(entry.requested, requested)) fail(`${typeId} setter contract is invalid`) + if (typeId === 'Part::Mirroring') { + if (entry.setup?.kind !== 'box-mirror' || entry.setup.source?.typeId !== 'Part::Box' || !isDeepStrictEqual(entry.setup.source.dimensions, [2, 3, 4]) || !isDeepStrictEqual(entry.setup.base, [0, 0, 0]) || entry.setup.mirrorPlane !== null) fail('Mirroring setup is incomplete') + } else if (entry.setup?.kind !== 'wire-to-planar-face' || entry.setup.support?.typeId !== 'Part::Feature' || !isDeepStrictEqual(entry.setup.support.subElements, ['Face1']) || entry.setup.projection?.typeId !== 'Part::Feature' || !isDeepStrictEqual(entry.setup.projection.subElements, ['Wire1']) || entry.setup.projection.z !== -5 || entry.setup.mode !== 'Edges') fail('ProjectOnSurface setup is incomplete') + + const defaultSnapshot = entry.phases?.default?.afterRecompute + const restoredSnapshot = entry.phases?.restored?.afterRecompute + if (!isDeepStrictEqual(defaultSnapshot?.value, [0, 0, 1]) || !isDeepStrictEqual(restoredSnapshot?.value, [0, 0, 1]) || defaultSnapshot.shape?.brepSha256 !== restoredSnapshot.shape?.brepSha256 || !isDeepStrictEqual(defaultSnapshot.shape?.bounds, restoredSnapshot.shape?.bounds)) fail(`${typeId} default restore is not exact`) + for (const [phase, value] of Object.entries({ default: [0, 0, 1], ...values, restored: [0, 0, 1] })) { + const snapshots = entry.phases?.[phase] + const snapshot = snapshots?.afterRecompute + if (!snapshot || !isDeepStrictEqual(snapshot.value, value) || snapshot.propertyTypeId !== 'App::PropertyDirection' || !isDeepStrictEqual(snapshot.propertyStatus, []) || !isDeepStrictEqual(snapshot.editorMode, []) || !isDeepStrictEqual(snapshot.objectState, ['Up-to-date']) || snapshot.statusString !== 'Valid' || snapshot.mustExecute !== false || snapshot.recomputeResult !== true || !isDeepStrictEqual(snapshot.objectSet, expected.objectSet)) fail(`${typeId} ${phase} native semantics changed`) + const shape = snapshot.shape + if (shape?.applicable !== true || shape.isNull !== false || shape.valid !== true || shape.shapeType !== expected.shape.shapeType || shape.solids !== expected.shape.solids || shape.faces !== expected.shape.faces || shape.edges !== expected.shape.edges || shape.vertices !== expected.shape.vertices || shape.area !== expected.shape.area || shape.volume !== expected.shape.volume || typeof shape.brepSha256 !== 'string' || shape.brepSha256.length !== 64 || !Array.isArray(shape.bounds) || shape.bounds.length !== 6) fail(`${typeId} ${phase} Shape evidence changed`) + if (phase !== 'default') { + const afterSet = snapshots.afterSet + if (!afterSet || !isDeepStrictEqual(afterSet.value, value) || !isDeepStrictEqual(afterSet.objectState, ['Touched']) || afterSet.statusString !== 'Touched' || afterSet.mustExecute !== expected.afterSetMustExecute) fail(`${typeId} ${phase} setter touch evidence changed`) + } + } + for (const phase of ['integerTuple', 'nonUnitFloatTuple', 'vectorObject', 'nearAxisTuple', 'largeFiniteTuple']) if (entry.phases[phase].afterRecompute.shape.brepSha256 === defaultSnapshot.shape.brepSha256) fail(`${typeId} ${phase} did not produce a distinct Shape`) +} +console.log(JSON.stringify({ status: 'freecad-property-direction-success-pass', cases: report.caseCount, acceptedInputs: Object.keys(values), noPropertyNormalization: true, shapes: Object.fromEntries(Object.entries(expectedHosts).map(([typeId, value]) => [typeId, value.shape])) }, null, 2)) diff --git a/scripts/check-freecad-property-file-failure.mjs b/scripts/check-freecad-property-file-failure.mjs new file mode 100644 index 0000000..6e7aff6 --- /dev/null +++ b/scripts/check-freecad-property-file-failure.mjs @@ -0,0 +1,22 @@ +import { readFile } 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-property-file-failure.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyFile failure check failed: ${message}`) } +const same = (left, right) => JSON.stringify(left) === JSON.stringify(right) +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-file-failure' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is invalid') +if (report.object?.typeId !== 'Mesh::Import' || report.property?.name !== 'FileName' || report.property?.typeId !== 'App::PropertyFile' || report.initial?.value !== '' || report.failures?.length !== 2) fail('failure fixture identity or cases changed') +const failures = new Map(report.failures.map((entry) => [entry.id, entry])) +for (const id of ['missing-path', 'wrong-type']) if (!failures.has(id)) fail(`missing failure case ${id}`) +const missing = failures.get('missing-path') +if (missing.assignmentException !== null || missing.recomputeException !== null || missing.after?.value !== '/definitely/missing/bitbybit-file.stl' || missing.after?.statusString !== 'File does not exist' || !same(missing.after?.objectState, ['Touched', 'Invalid']) || missing.objectsPreserved !== true || !same(missing.beforeObjects, missing.afterObjects)) fail('missing path did not enter the native invalid state without pollution') +const wrong = failures.get('wrong-type') +if (wrong.assignmentException?.type !== 'TypeError' || wrong.objectsPreserved !== true || !same(wrong.beforeObjects, wrong.afterObjects)) fail('wrong type did not reject without document pollution') +const disabled = report.disabled +if (disabled?.classification !== 'editor-read-only-and-python-immutable' || !disabled.status?.includes('Immutable') || disabled.exception?.type !== 'AttributeError' || disabled.exception.message !== "Object attribute 'FileName' is read-only" || !same(disabled.beforeObjects, disabled.afterObjects) || !same(disabled.restoredStatus, []) || !same(disabled.restoredEditorMode, [])) fail('disabled property state did not reject and restore cleanly') +const transaction = report.transaction +if (transaction?.undoMode !== 1 || transaction.pendingAfterEdit !== true || transaction.pendingAfterAbort !== false || transaction.activeAfterEdit?.name !== 'property-file-cancel' || !(transaction.activeAfterEdit.id > 0) || transaction.activeAfterAbort?.name !== '' || transaction.activeAfterAbort?.id !== 0 || transaction.before?.value !== '' || transaction.edited?.value !== '/tmp/transaction-file.stl' || transaction.afterAbort?.value !== '' || transaction.restored !== true || transaction.objectsRestored !== true) fail('transaction abort did not restore PropertyFile') +if (report.cancellationBoundary?.supported !== false || report.cancellationBoundary.classification !== 'synchronous-property-setter' || report.cancellationBoundary.reason !== 'no-native-cancel-hook' || report.cancellationBoundary.replacement !== 'abort-active-document-transaction') fail('cancellation boundary is not explicit') +if (report.documentIntegrity?.objectsPreserved !== true || report.documentIntegrity.objectCount !== 1 || !same(report.documentIntegrity.initialObjects, report.documentIntegrity.finalObjects)) fail('failure, disabled or cancellation cases polluted the document') +console.log(JSON.stringify({ status: 'freecad-property-file-failure-pass', failures: report.failures.map(({ id, after }) => ({ id, state: after.objectState, diagnostic: after.statusString })), disabled: { status: disabled.status, editorMode: disabled.editorMode, exception: disabled.exception }, transactionRestored: transaction.restored, documentObjectsPreserved: report.documentIntegrity.objectsPreserved, cancellationBoundary: report.cancellationBoundary }, null, 2)) diff --git a/scripts/check-freecad-property-file-inventory.mjs b/scripts/check-freecad-property-file-inventory.mjs new file mode 100644 index 0000000..eec373c --- /dev/null +++ b/scripts/check-freecad-property-file-inventory.mjs @@ -0,0 +1,30 @@ +import { createHash } from 'node:crypto' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const runtimePath = resolve(root, '.cache/freecad/reference-desktop.json') +const reportPath = resolve(root, 'config/freecad-property-file-inventory.json') +const sourcePaths = ['.cache/freecad/FreeCAD/src/App/PropertyFile.h', '.cache/freecad/FreeCAD/src/App/PropertyFile.cpp', '.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.h', '.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.cpp'] +const fail = (message) => { throw new Error(`FreeCAD PropertyFile inventory check failed: ${message}`) } +const [runtimeContent, reportContent, ...sourceContents] = await Promise.all([readFile(runtimePath), readFile(reportPath), ...sourcePaths.map((path) => readFile(resolve(root, path)))]) +const runtime = JSON.parse(runtimeContent) +const report = JSON.parse(reportContent) +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.propertyType !== 'App::PropertyFile' || report.classification !== 'opaque-fcstd-proxy' || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('report boundary is invalid') +if (report.recordCount !== 16 || !Array.isArray(report.records) || report.records.length !== 16) fail('record count is not exactly sixteen') +if (report.storage?.inheritedFrom !== 'App::PropertyString' || report.storage.xmlElement !== 'String' || report.storage.externalResource !== true || report.storage.absoluteHostPathPolicy !== 'preserve-or-reject; never rewrite into browser project') fail('storage boundary is invalid') +if (report.provenance?.runtime?.path !== '.cache/freecad/reference-desktop.json' || report.provenance.runtime.bytes !== runtimeContent.length || report.provenance.runtime.sha256 !== createHash('sha256').update(runtimeContent).digest('hex')) fail('runtime provenance is stale') +for (const [index, path] of sourcePaths.entries()) if (report.provenance.sources?.[index]?.path !== path || report.provenance.sources[index].bytes !== sourceContents[index].length || report.provenance.sources[index].sha256 !== createHash('sha256').update(sourceContents[index]).digest('hex')) fail(`source provenance is stale for ${path}`) +const nativeMatches = [] +for (const objectType of runtime.runtimeObjects?.types ?? []) for (const property of objectType.properties ?? []) if (property.typeId === 'App::PropertyFile') nativeMatches.push({ objectTypeId: objectType.typeId, objectAvailable: objectType.available === true, probeStatus: objectType.probeStatus, propertyName: property.name, group: property.group, status: property.status, defaultRaw: property.default }) +const normalize = (record) => ({ objectTypeId: record.objectTypeId, objectAvailable: record.objectAvailable, probeStatus: record.probeStatus, propertyName: record.propertyName, group: record.group, status: record.status, defaultRaw: record.defaultRaw }) +if (nativeMatches.length !== 16 || JSON.stringify(nativeMatches.map(normalize).sort((a, b) => `${a.objectTypeId}.${a.propertyName}`.localeCompare(`${b.objectTypeId}.${b.propertyName}`))) !== JSON.stringify(report.records.map(normalize).sort((a, b) => `${a.objectTypeId}.${a.propertyName}`.localeCompare(`${b.objectTypeId}.${b.propertyName}`)))) fail('report does not match the locked runtime oracle') +for (const record of report.records) { + if (record.objectAvailable !== true || record.probeStatus !== 'available' || JSON.stringify(record.status) !== '[]' || record.editor !== 'Gui::PropertyEditor::PropertyFileItem' || record.valueModel?.kind !== 'path-string' || record.valueModel.representation !== 'App::PropertyString-derived UTF-8 path' || record.valueModel.externalResource !== true || record.inputs?.accepted?.join('|') !== 'string|{filename:string,filter?:string}' || record.inputs?.emptyStringAccepted !== true || record.dependencies?.length !== 0 || record.applicability?.requiredObjectTypeId !== record.objectTypeId) fail(`native contract changed for ${record.objectTypeId}.${record.propertyName}`) +} +const propertyHeader = sourceContents[0].toString('utf8') +const propertySource = sourceContents[1].toString('utf8') +const editorHeader = sourceContents[2].toString('utf8') +const editorSource = sourceContents[3].toString('utf8') +if (!propertyHeader.includes('class AppExport PropertyFile: public PropertyString') || !propertyHeader.includes('Gui::PropertyEditor::PropertyFileItem') || !propertySource.includes('TYPESYSTEM_SOURCE(App::PropertyFile, App::PropertyString)') || !propertySource.includes('PyDict_Check(value)') || !propertySource.includes('dict.hasKey("filter")') || !propertySource.includes('dict.hasKey("filename")') || !editorHeader.includes('class GuiExport PropertyFileItem: public PropertyItem') || !editorSource.includes('PROPERTYITEM_SOURCE(Gui::PropertyEditor::PropertyFileItem)') || !editorSource.includes('Gui::FileChooser')) fail('locked PropertyFile setter/editor contract changed') +console.log(JSON.stringify({ status: 'freecad-property-file-inventory-pass', propertyType: report.propertyType, recordCount: report.recordCount, objectTypes: report.records.map(({ objectTypeId }) => objectTypeId), classification: report.classification }, null, 2)) diff --git a/scripts/check-freecad-property-file-mutation.mjs b/scripts/check-freecad-property-file-mutation.mjs new file mode 100644 index 0000000..495272f --- /dev/null +++ b/scripts/check-freecad-property-file-mutation.mjs @@ -0,0 +1,13 @@ +import { readFile } 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-property-file-mutation.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyFile mutation check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-file-mutation' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyFile' || report.object?.typeId !== 'Mesh::Import' || report.property?.name !== 'FileName' || report.property?.typeId !== 'App::PropertyFile') fail('baseline or identity is invalid') +const phases = report.phases +if (!phases?.before || !phases.edited || !phases.restored || report.requested?.before !== phases.before.value || report.requested.edited !== phases.edited.value || report.requested.restored !== phases.restored.value) fail('mutation phases are incomplete') +for (const [id, phase] of Object.entries(phases)) if (phase.propertyTypeId !== 'App::PropertyFile' || JSON.stringify(phase.propertyStatus) !== '[]' || JSON.stringify(phase.editorMode) !== '[]' || !Array.isArray(phase.objectState) || !Array.isArray(phase.objectSet) || typeof phase.recomputeResult !== 'boolean') fail(`${id} phase metadata is invalid`) +if (phases.before.statusString !== 'Valid' || phases.before.value !== report.requested.before || phases.edited.value !== report.requested.edited || phases.edited.statusString !== 'File does not exist' || JSON.stringify(phases.edited.objectState) !== '["Touched","Invalid"]' || phases.restored.value !== report.requested.restored || phases.restored.statusString !== 'Valid' || JSON.stringify(phases.restored.objectState) !== '["Up-to-date"]') fail('native mutation or restore semantics changed') +if (report.classification?.valueChanged !== true || report.classification.invalidEditedPath !== true || report.classification.restoreExact !== true || report.classification.objectSetStable !== true || report.classification.unknownSemanticDrift !== false) fail('mutation classification is not exact') +console.log(JSON.stringify({ status: 'freecad-property-file-mutation-pass', before: phases.before.value, edited: phases.edited.value, restored: phases.restored.value, editedState: phases.edited.objectState, restoreExact: report.classification.restoreExact, unknownSemanticDrift: report.classification.unknownSemanticDrift }, null, 2)) diff --git a/scripts/check-freecad-property-file-promotion.mjs b/scripts/check-freecad-property-file-promotion.mjs new file mode 100644 index 0000000..670aa09 --- /dev/null +++ b/scripts/check-freecad-property-file-promotion.mjs @@ -0,0 +1,30 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const [report, semantics, progress, roundTrip, chrome] = await Promise.all([ + load('config/freecad-property-file-promotion.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), + load('config/freecad-property-file-roundtrip.json'), + load('config/chrome-property-file-verification.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyFile promotion check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.taskId !== 'PROP-app-propertyfile-I' || report.propertyType !== 'App::PropertyFile' || report.recordCount !== 16 || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.systemExact !== false) fail('promotion report boundary is invalid') +const requiredPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredPhases) { + const taskId = `PROP-app-propertyfile-${phase}` + if (!completed.has(taskId) || !Array.isArray(report.phaseEvidence?.[phase]) || report.phaseEvidence[phase].length === 0 || !isDeepStrictEqual(report.phaseEvidence[phase], completed.get(taskId).evidence)) fail(`phase ${phase} evidence is incomplete`) +} +const nativeTarget = '.cache/freecad/property-file-roundtrip/alternate.obj' +const browserTarget = 'project-files/chrome-updated.obj' +const propertyType = semantics.types?.find(({ typeId }) => typeId === report.propertyType) +if (report.promotion?.from !== 'opaque-fcstd-proxy' || report.promotion.to !== 'native-editable-codec' || propertyType?.support !== report.promotion.to || propertyType.recordCount !== 16 || propertyType.objectTypeCount !== 12 || propertyType.statusNames?.length !== 0 || report.promotion.facadeValueModel !== 'safe-project-relative-path-string-with-native-string-fcstd-payload' || report.promotion.writableRecords !== 16 || report.promotion.objectTypeCount !== 12 || report.promotion.fcstdElement !== 'String' || report.promotion.nativeRoundTripValue !== nativeTarget || report.promotion.browserRoundTripValue !== browserTarget || report.promotion.externalResourceBoundary !== 'project-relative-path; asset bytes remain external to FCStd' || report.promotion.zeroUnknownDrift !== true) fail('capability promotion is incomplete') +const sync = report.exactBlockerSync +if (sync?.nativeEditableTypes !== 30 || sync.nativeEditableRecords !== 4361 || sync.opaqueTypes !== 50 || sync.opaqueRecords !== 466 || sync.exactPromotionReady !== false || sync.exactBlocker !== '50 runtime property types and 466 records remain opaque-only; complete native document and property semantics') fail('exact blocker synchronization is stale') +if (!isDeepStrictEqual(sync, { nativeEditableTypes: semantics.supportSummary['native-editable-codec'].typeCount, nativeEditableRecords: semantics.supportSummary['native-editable-codec'].recordCount, opaqueTypes: semantics.supportSummary['opaque-fcstd-proxy'].typeCount, opaqueRecords: semantics.supportSummary['opaque-fcstd-proxy'].recordCount, exactPromotionReady: semantics.exactPromotionReady, exactBlocker: semantics.exactBlocker })) fail('promotion report diverges from global property semantics') +if (roundTrip.classification?.zeroUnknownDrift !== true || roundTrip.classification.resavedValue !== nativeTarget || roundTrip.classification.externalResourceBoundary !== 'project-relative-path; asset bytes remain external to FCStd' || chrome.status !== 'pass' || chrome.persistence?.fcstdElement !== 'String' || chrome.persistence.fcstdValue !== browserTarget || chrome.persistence.loadedValue !== browserTarget || chrome.resource?.released !== true || chrome.resource.markerRemoved !== true || chrome.release?.workerTerminated !== true) fail('G/H closure evidence regressed') +console.log(JSON.stringify({ status: 'freecad-property-file-promotion-pass', propertyType: report.propertyType, promotion: report.promotion, completedPhases: requiredPhases, exactBlockerSync: sync, systemExact: report.systemExact }, null, 2)) diff --git a/scripts/check-freecad-property-file-roundtrip.mjs b/scripts/check-freecad-property-file-roundtrip.mjs new file mode 100644 index 0000000..7371496 --- /dev/null +++ b/scripts/check-freecad-property-file-roundtrip.mjs @@ -0,0 +1,22 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-file-roundtrip.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyFile roundtrip check failed: ${message}`) } +const initial = '.cache/freecad/FreeCAD/data/tests/mesh.obj' +const target = '.cache/freecad/property-file-roundtrip/alternate.obj' +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-file-roundtrip' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyFile') fail('baseline is invalid') +const objectSet = [{ name: 'FileProbe', typeId: 'Mesh::Import' }] +for (const [phase, snapshot] of [['nativeInitial', report.nativeInitial], ['nativeReopened', report.nativeAfter?.reopened], ['nativeResaved', report.nativeAfter?.resaved]]) { + if (snapshot?.object?.name !== 'FileProbe' || snapshot.object.typeId !== 'Mesh::Import' || snapshot.object.propertyTypeId !== 'App::PropertyFile' || !isDeepStrictEqual(snapshot.object.propertyStatus, []) || !isDeepStrictEqual(snapshot.object.editorMode, []) || !isDeepStrictEqual(snapshot.object.state, ['Up-to-date']) || snapshot.object.statusString !== 'Valid' || snapshot.object.hasShapeProperty !== false || snapshot.object.hasMeshProperty !== true || !isDeepStrictEqual(snapshot.objectSet, objectSet)) fail(`${phase} native object semantics are incomplete`) + if (snapshot.object.asset?.exists !== true || !Number.isSafeInteger(snapshot.object.asset.bytes) || snapshot.object.asset.bytes <= 0 || !/^[0-9a-f]{64}$/.test(snapshot.object.asset.sha256) || snapshot.object.mesh?.isEmpty !== false || !Number.isSafeInteger(snapshot.object.mesh.facets) || snapshot.object.mesh.facets <= 0 || !Number.isSafeInteger(snapshot.object.mesh.points) || snapshot.object.mesh.points <= 0 || !Array.isArray(snapshot.object.mesh.bounds) || snapshot.object.mesh.bounds.length !== 6) fail(`${phase} native external asset or Mesh evidence is incomplete`) +} +if (report.nativeInitial.object.value !== initial || report.nativeAfter.reopened.object.value !== target || report.nativeAfter.resaved.object.value !== target) fail('native PropertyFile values drifted') +if (report.nativeInitial.object.asset.sha256 !== report.assets?.initial?.sha256 || report.nativeAfter.reopened.object.asset.sha256 !== report.assets?.target?.sha256 || report.nativeAfter.resaved.object.asset.sha256 !== report.assets?.target?.sha256) fail('native object did not consume the locked external assets') +if (isDeepStrictEqual(report.nativeInitial.object.mesh, report.nativeAfter.reopened.object.mesh) || !isDeepStrictEqual(report.nativeAfter.reopened.object.mesh, report.nativeAfter.resaved.object.mesh)) fail('native Mesh did not change and stabilize with the PropertyFile reference') +if (report.web.before?.typeId !== 'App::PropertyFile' || report.web.before?.element !== 'String' || report.web.before?.value !== initial || report.web.after?.typeId !== 'App::PropertyFile' || report.web.after?.element !== 'String' || report.web.after?.value !== target || report.web.targetMarkedTouched !== true || report.web.webOutputMatches !== true || report.web.semanticObjectsPreserved !== true || report.web.opaqueEntriesPreserved !== true || !Number.isSafeInteger(report.web.opaquePathsPreserved) || report.web.opaquePathsPreserved < 1) fail('Web edit did not preserve native archive semantics') +if (report.classification?.requestedValue !== target || report.classification.webValue !== target || report.classification.reopenedValue !== target || report.classification.resavedValue !== target || report.classification.nativeOutputMatches !== true || report.classification.objectSetPreserved !== true || report.classification.nativeMeshChanged !== true || report.classification.nativeMeshStable !== true || report.classification.externalResourceBoundary !== 'project-relative-path; asset bytes remain external to FCStd' || report.classification.unknownSemanticDrift !== false || report.classification.zeroUnknownDrift !== true) fail('round-trip classification is not exact for PropertyFile') +for (const artifact of [...Object.values(report.assets ?? {}), ...Object.values(report.archives ?? {})]) if (!artifact?.path || !Number.isSafeInteger(artifact.bytes) || artifact.bytes <= 0 || !/^[0-9a-f]{64}$/.test(artifact.sha256)) fail('asset or archive evidence is incomplete') +console.log(JSON.stringify({ status: 'freecad-property-file-roundtrip-pass', values: { nativeInitial: report.nativeInitial.object.value, webEdited: report.classification.webValue, nativeReopened: report.classification.reopenedValue, nativeResaved: report.classification.resavedValue }, mesh: { initial: report.nativeInitial.object.mesh, reopened: report.nativeAfter.reopened.object.mesh }, opaquePathsPreserved: report.web.opaquePathsPreserved, externalResourceBoundary: report.classification.externalResourceBoundary, zeroUnknownDrift: report.classification.zeroUnknownDrift }, null, 2)) diff --git a/scripts/check-freecad-property-file-success.mjs b/scripts/check-freecad-property-file-success.mjs new file mode 100644 index 0000000..6b4fe02 --- /dev/null +++ b/scripts/check-freecad-property-file-success.mjs @@ -0,0 +1,19 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-file-success.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyFile success check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-file-success' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyFile') fail('baseline is invalid') +if (report.object?.typeId !== 'Mesh::Import' || report.property?.name !== 'FileName' || report.property?.typeId !== 'App::PropertyFile' || report.property?.group !== '') fail('native object/property identity changed') +if (report.asset?.exists !== true || report.asset.bytes <= 0 || !Array.isArray(report.asset.path) && typeof report.asset.path !== 'string') fail('valid mesh asset evidence is missing') +if (report.diagnostics?.exception !== null || report.diagnostics?.documentObjectCount !== 1 || !report.phases || !['default', 'valid-mesh', 'relative-path', 'restored'].every((id) => report.phases[id])) fail('native success phases are incomplete') +const objectSet = [{ name: 'FileProbe', typeId: 'Mesh::Import' }] +for (const [id, phase] of Object.entries(report.phases)) { + if (phase.propertyTypeId !== 'App::PropertyFile' || !isDeepStrictEqual(phase.propertyStatus, []) || !isDeepStrictEqual(phase.editorMode, []) || !isDeepStrictEqual(phase.objectSet, objectSet) || typeof phase.recomputeResult !== 'boolean' || !Array.isArray(phase.objectState)) fail(`${id} native metadata is invalid`) +} +if (report.phases.default.value !== '' || report.phases.default.requested !== '' || report.phases['valid-mesh'].value !== report.asset.path || report.phases['valid-mesh'].requested !== report.asset.path || report.phases['relative-path'].value !== 'mesh-data/Cube.stl' || report.phases.restored.value !== report.asset.path) fail('PropertyFile values did not preserve native paths') +if (report.phases['valid-mesh'].statusString !== 'Valid' || !isDeepStrictEqual(report.phases['valid-mesh'].objectState, ['Up-to-date']) || report.phases['valid-mesh'].mesh?.applicable !== true || report.phases['valid-mesh'].mesh?.error) fail('valid path success evidence is incomplete') +if (report.phases.restored.statusString !== 'Valid' || !isDeepStrictEqual(report.phases.restored.objectState, ['Up-to-date']) || report.phases.restored.mesh?.error) fail('restored path state drifted') +console.log(JSON.stringify({ status: 'freecad-property-file-success-pass', propertyType: report.propertyType, phases: Object.keys(report.phases), validPath: report.phases['valid-mesh'].value, restored: report.phases.restored.value, hostMesh: report.phases['valid-mesh'].mesh }, null, 2)) diff --git a/scripts/check-freecad-property-fileincluded-failure.mjs b/scripts/check-freecad-property-fileincluded-failure.mjs new file mode 100644 index 0000000..266d3ff --- /dev/null +++ b/scripts/check-freecad-property-fileincluded-failure.mjs @@ -0,0 +1,40 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-fileincluded-failure.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyFileIncluded failure check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-fileincluded-failure' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyFileIncluded' || report.object?.typeId !== 'App::DocumentObjectFileIncluded' || report.property?.name !== 'File' || report.property?.typeId !== 'App::PropertyFileIncluded') fail('baseline or identity is invalid') +if (report.initial?.exists !== true || report.initial.isFile !== true || report.initial.isDirectory !== false || report.initial.writeBits !== 0 || report.initial.propertyTypeId !== 'App::PropertyFileIncluded' || !isDeepStrictEqual(report.initial.propertyStatus, []) || !isDeepStrictEqual(report.initial.editorMode, []) || !isDeepStrictEqual(report.initial.objectState, ['Up-to-date']) || report.initial.statusString !== 'Valid') fail('initial included-file state is invalid') + +const expectedFailures = new Map([ + ['missing-path', ['OSError', 'does not exist']], + ['wrong-type', ['TypeError', 'Type must be string or file']], + ['tuple-wrong-arity', ['TypeError', 'Tuple needs size of (filePath,newFileName)']], + ['tuple-wrong-name-type', ['TypeError', 'Second item in tuple must be a string']], + ['dictionary-wrong-filename-type', ['TypeError', 'PyCXX: Error creating object']], + ['same-current-transient', ['OSError', 'Not possible to set the same file!']], +]) +if (report.failures?.length !== expectedFailures.size) fail('failure case count changed') +for (const entry of report.failures) { + const expected = expectedFailures.get(entry.id) + if (!expected || entry.assignmentException?.type !== expected[0] || !entry.assignmentException.message.includes(expected[1]) || entry.valuePreserved !== true || entry.objectsPreserved !== true || !isDeepStrictEqual(entry.before.objectSet, entry.after.objectSet) || entry.before.value !== entry.after.value || entry.before.sha256 !== entry.after.sha256 || entry.after.writeBits !== 0 || entry.after.exists !== true) fail(`${entry.id} rejection polluted the included resource or document`) +} + +const [directory] = report.acceptedRisks ?? [] +if (report.acceptedRisks?.length !== 1 || directory?.id !== 'directory-path' || directory.assignmentException !== null || directory.oldFileRemoved !== true || directory.directoryAccepted !== true || directory.objectsPreserved !== true || directory.before?.isFile !== true || directory.after?.isFile !== false || directory.after?.isDirectory !== true || directory.after.pathExists !== true || directory.recovery?.isFile !== true || directory.recovery.isDirectory !== false || directory.recovery.writeBits !== 0 || directory.recovery.statusString !== 'Valid') fail('directory-path non-atomic acceptance or recovery changed') + +const filterOnly = report.filterOnly +if (filterOnly?.exception !== null || filterOnly.valuePreserved !== true || filterOnly.objectsPreserved !== true || filterOnly.before.value !== filterOnly.after.value || filterOnly.before.sha256 !== filterOnly.after.sha256) fail('filter-only dictionary boundary changed') +const editor = report.editorReadOnly +if (!isDeepStrictEqual(editor?.editorMode, ['ReadOnly']) || editor.exception !== null || editor.pythonBypassesEditorReadOnly !== true || editor.after.exists !== true || editor.after.writeBits !== 0 || editor.after.baseName !== 'editor-write.bin') fail('editor ReadOnly did not preserve Python setter behavior') +const immutable = report.immutable +if (!isDeepStrictEqual(immutable?.status, ['Immutable']) || immutable.exception?.type !== 'AttributeError' || immutable.exception.message !== "Object attribute 'File' is read-only" || immutable.before.value !== immutable.after.value || immutable.before.sha256 !== immutable.after.sha256 || !isDeepStrictEqual(immutable.restoredStatus, [])) fail('Immutable rejection or status restoration changed') + +const transaction = report.transaction +if (transaction?.undoMode !== 1 || transaction.pendingAfterEdit !== true || transaction.pendingAfterAbort !== false || transaction.activeAfterEdit?.name !== 'property-fileincluded-cancel' || !(transaction.activeAfterEdit.id > 0) || transaction.activeAfterAbort?.name !== '' || transaction.activeAfterAbort.id !== 0 || transaction.restored !== true || transaction.editedPathExistsAfterAbort !== false || !isDeepStrictEqual(transaction.objectsBefore, transaction.objectsAfter) || transaction.edited?.baseName !== 'transaction-write.bin' || transaction.edited.writeBits !== 0 || transaction.afterAbort.writeBits !== 0 || transaction.before.sha256 === transaction.edited.sha256 || transaction.before.sha256 !== transaction.afterAbort.sha256) fail('transaction abort did not restore ownership and remove the edited transient copy') +if (report.cancellationBoundary?.supported !== false || report.cancellationBoundary.classification !== 'synchronous-property-setter' || report.cancellationBoundary.reason !== 'no-native-cancel-hook' || report.cancellationBoundary.replacement !== 'abort-active-document-transaction') fail('cancellation boundary is not explicit') +if (report.documentIntegrity?.objectsPreserved !== true || report.documentIntegrity.objectCount !== 1 || !isDeepStrictEqual(report.documentIntegrity.initialObjects, report.documentIntegrity.finalObjects)) fail('failure cases polluted the document object set') + +console.log(JSON.stringify({ status: 'freecad-property-fileincluded-failure-pass', failures: report.failures.map(({ id, assignmentException, valuePreserved }) => ({ id, type: assignmentException.type, message: assignmentException.message, valuePreserved })), acceptedNonAtomicRisk: { id: directory.id, oldFileRemoved: directory.oldFileRemoved, directoryAccepted: directory.directoryAccepted, recovered: directory.recovery.isFile }, filterOnlyNoOp: filterOnly.valuePreserved, editorReadOnlyPythonBypass: editor.pythonBypassesEditorReadOnly, immutable: immutable.exception, transactionRestored: transaction.restored, editedTransientRemoved: !transaction.editedPathExistsAfterAbort, cancellationBoundary: report.cancellationBoundary }, null, 2)) diff --git a/scripts/check-freecad-property-fileincluded-inventory.mjs b/scripts/check-freecad-property-fileincluded-inventory.mjs new file mode 100644 index 0000000..7f26c10 --- /dev/null +++ b/scripts/check-freecad-property-fileincluded-inventory.mjs @@ -0,0 +1,109 @@ +import { createHash } from 'node:crypto' +import { isDeepStrictEqual } from 'node:util' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const runtimePath = '.cache/freecad/reference-desktop.json' +const reportPath = 'config/freecad-property-fileincluded-inventory.json' +const fail = (message) => { throw new Error(`FreeCAD PropertyFileIncluded inventory check failed: ${message}`) } +const [runtimeContent, reportContent] = await Promise.all([ + readFile(resolve(root, runtimePath)), + readFile(resolve(root, reportPath)), +]) +const runtime = JSON.parse(runtimeContent) +const report = JSON.parse(reportContent) + +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.propertyType !== 'App::PropertyFileIncluded' || report.classification !== 'opaque-fcstd-proxy' || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('report boundary is invalid') +if (report.recordCount !== 20 || report.objectTypeCount !== 15 || report.records?.length !== 20) fail('runtime record or host count changed') +if (report.provenance?.runtime?.path !== runtimePath || report.provenance.runtime.bytes !== runtimeContent.length || report.provenance.runtime.sha256 !== createHash('sha256').update(runtimeContent).digest('hex')) fail('runtime provenance is stale') +for (const locked of report.provenance?.sources ?? []) { + const content = await readFile(resolve(root, locked.path)) + if (content.length !== locked.bytes || createHash('sha256').update(content).digest('hex') !== locked.sha256) fail(`source provenance is stale for ${locked.path}`) +} + +const normalizeStatus = (status) => status.map((entry) => entry === 27 ? 'PropOutput' : String(entry)) +const nativeMatches = [] +for (const objectType of runtime.runtimeObjects?.types ?? []) for (const property of objectType.properties ?? []) { + if (property.typeId !== 'App::PropertyFileIncluded') continue + nativeMatches.push({ + objectTypeId: objectType.typeId, + objectAvailable: objectType.available === true, + probeStatus: objectType.probeStatus, + propertyName: property.name, + group: property.group, + status: property.status, + normalizedStatus: normalizeStatus(property.status), + defaultRaw: property.default, + }) +} +const identity = ({ objectTypeId, objectAvailable, probeStatus, propertyName, group, status, normalizedStatus, defaultRaw }) => ({ objectTypeId, objectAvailable, probeStatus, propertyName, group, status, normalizedStatus, defaultRaw }) +const sortRecords = (records) => records.map(identity).sort((left, right) => `${left.objectTypeId}.${left.propertyName}`.localeCompare(`${right.objectTypeId}.${right.propertyName}`)) +if (nativeMatches.length !== 20 || !isDeepStrictEqual(sortRecords(nativeMatches), sortRecords(report.records))) fail('report diverges from the locked runtime oracle') + +const expectedKeys = [ + 'App::DocumentObjectFileIncluded.File', + 'App::VRMLObject.VrmlFile', + 'Image::ImagePlane.ImageFile', + 'Robot::RobotObject.RobotKinematicFile', + 'Robot::RobotObject.RobotVrmlFile', + 'Sketcher::SketchObjectSF.SketchFlatFile', + 'TechDraw::DrawComplexSection.PatIncluded', + 'TechDraw::DrawComplexSection.SvgIncluded', + 'TechDraw::DrawComplexSectionPython.PatIncluded', + 'TechDraw::DrawComplexSectionPython.SvgIncluded', + 'TechDraw::DrawGeomHatch.PatIncluded', + 'TechDraw::DrawHatch.SvgIncluded', + 'TechDraw::DrawSVGTemplate.PageResult', + 'TechDraw::DrawTileWeld.SymbolIncluded', + 'TechDraw::DrawTileWeldPython.SymbolIncluded', + 'TechDraw::DrawViewImage.ImageIncluded', + 'TechDraw::DrawViewSection.PatIncluded', + 'TechDraw::DrawViewSection.SvgIncluded', + 'TechDraw::DrawViewSectionPython.PatIncluded', + 'TechDraw::DrawViewSectionPython.SvgIncluded', +] +if (report.records.map(({ objectTypeId, propertyName }) => `${objectTypeId}.${propertyName}`).join('|') !== expectedKeys.join('|')) fail('host/property inventory changed') +if (report.records.some((record) => record.objectAvailable !== true || record.probeStatus !== 'available' || record.valueModel?.kind !== 'included-file-resource' || record.valueModel.representation !== 'read-only document-transient file backed by embedded FCStd bytes' || record.valueModel.pathIsRuntimeOnly !== true || record.valueModel.bytesAreAuthoritative !== true || record.inputs?.sourceFileMustExist !== true || record.inputs.emptyStringBehavior !== 'accepted-no-op; does not clear an existing value' || record.inputs.sameTransientPathBehavior !== 'rejected' || record.editor !== 'Gui::PropertyEditor::PropertyTransientFileItem' || record.applicability?.requiredObjectTypeId !== record.objectTypeId || record.applicability.propertyWriteRequiresShape !== false)) fail('per-record value, input, editor or applicability contract is incomplete') +if (report.records.filter(({ valueModel }) => valueModel.writableByStatus).length !== 11 || report.records.filter(({ status }) => isDeepStrictEqual(status, ['ReadOnly'])).length !== 8 || report.records.filter(({ status }) => isDeepStrictEqual(status, [27])).length !== 1 || report.records.filter(({ defaultKind }) => defaultKind === 'empty').length !== 8 || report.records.filter(({ defaultKind }) => defaultKind === 'document-transient-copy').length !== 12) fail('status/default partition changed') + +const dependencyPairs = report.records.filter(({ dependency }) => dependency !== null).map(({ objectTypeId, propertyName, dependency }) => `${objectTypeId}.${propertyName}<-${dependency.sourceProperty}`) +const expectedDependencyPairs = [ + 'TechDraw::DrawComplexSection.PatIncluded<-FileGeomPattern', + 'TechDraw::DrawComplexSection.SvgIncluded<-FileHatchPattern', + 'TechDraw::DrawComplexSectionPython.PatIncluded<-FileGeomPattern', + 'TechDraw::DrawComplexSectionPython.SvgIncluded<-FileHatchPattern', + 'TechDraw::DrawGeomHatch.PatIncluded<-FilePattern', + 'TechDraw::DrawHatch.SvgIncluded<-HatchPattern', + 'TechDraw::DrawSVGTemplate.PageResult<-Template', + 'TechDraw::DrawTileWeld.SymbolIncluded<-SymbolFile', + 'TechDraw::DrawTileWeldPython.SymbolIncluded<-SymbolFile', + 'TechDraw::DrawViewImage.ImageIncluded<-ImageFile', + 'TechDraw::DrawViewSection.PatIncluded<-FileGeomPattern', + 'TechDraw::DrawViewSection.SvgIncluded<-FileHatchPattern', + 'TechDraw::DrawViewSectionPython.PatIncluded<-FileGeomPattern', + 'TechDraw::DrawViewSectionPython.SvgIncluded<-FileHatchPattern', +] +if (!isDeepStrictEqual(dependencyPairs, expectedDependencyPairs) || report.records.filter(({ dependency }) => dependency === null).length !== 6 || report.records.some(({ dependency }) => dependency && dependency.relation !== 'host-onChanged-copies-source-bytes-into-included-property')) fail('derived-source dependency inventory changed') + +const setter = report.setterSemantics +if (setter?.externalSource !== 'copy bytes into the document transient directory' || setter.writableTransientSource !== 'rename into the selected transient destination' || setter.replacement !== 'delete the previous transient copy unless undo owns it' || setter.destinationPermissions !== 'read-only' || setter.archiveNameCollision !== 'append a positive integer before the extension' || setter.undoRedo !== 'Copy/Paste move or copy transient files while preserving per-property ownership') fail('setter and ownership semantics are incomplete') +const storage = report.storage +if (storage?.xmlElement !== 'FileIncluded' || storage.archiveAttribute !== 'file' || storage.archiveResource !== 'separate FCStd ZIP entry containing byte-identical file data' || storage.forceXmlAttribute !== 'data' || storage.forceXmlResource !== 'binary data embedded in the XML stream' || storage.emptyEncoding !== '' || storage.restoredValue !== 'document transient path; not a portable semantic path' || storage.browserBoundary !== 'project resource identity plus bytes; never expose or persist an ambient host path') fail('FCStd or browser storage boundary is incomplete') + +const sources = new Map(await Promise.all((report.provenance?.sources ?? []).map(async ({ path }) => [path, await readFile(resolve(root, path), 'utf8')]))) +const propertyHeader = sources.get('.cache/freecad/FreeCAD/src/App/PropertyFile.h') ?? '' +const propertySource = sources.get('.cache/freecad/FreeCAD/src/App/PropertyFile.cpp') ?? '' +const editorHeader = sources.get('.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.h') ?? '' +const editorSource = sources.get('.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.cpp') ?? '' +if (!propertyHeader.includes('class AppExport PropertyFileIncluded: public Property') || !propertyHeader.includes('return "Gui::PropertyEditor::PropertyTransientFileItem"') || !propertyHeader.includes("it's not allowed to write the file") || !propertySource.includes('TYPESYSTEM_SOURCE(App::PropertyFileIncluded, App::Property)') || !propertySource.includes('Not possible to set the same file!') || !propertySource.includes('str << "File " << file.filePath() << " does not exist."') || !propertySource.includes('PyTuple_Check(value)') || !propertySource.includes('PyDict_Check(value)') || !propertySource.includes('writer.isForceXML()') || !propertySource.includes(' valueModel.writableByStatus).length, readOnlyRecords: 8, outputRecords: 1, directRecords: 6, derivedRecords: 14, storage: report.storage, classification: report.classification }, null, 2)) diff --git a/scripts/check-freecad-property-fileincluded-mutation.mjs b/scripts/check-freecad-property-fileincluded-mutation.mjs new file mode 100644 index 0000000..62f95cc --- /dev/null +++ b/scripts/check-freecad-property-fileincluded-mutation.mjs @@ -0,0 +1,32 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const [report, inventory] = await Promise.all([ + readFile(resolve(root, 'config/freecad-property-fileincluded-mutation.json'), 'utf8').then(JSON.parse), + readFile(resolve(root, 'config/freecad-property-fileincluded-inventory.json'), 'utf8').then(JSON.parse), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyFileIncluded mutation check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-fileincluded-mutation' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyFileIncluded' || report.caseCount !== 20 || report.cases?.length !== 20) fail('baseline or case count is invalid') +const keys = report.cases.map(({ objectTypeId, propertyName }) => `${objectTypeId}.${propertyName}`) +if (!isDeepStrictEqual(keys, inventory.records.map(({ objectTypeId, propertyName }) => `${objectTypeId}.${propertyName}`))) fail('mutation cases do not cover the locked inventory') +for (const [index, entry] of report.cases.entries()) { + const record = inventory.records[index] + const expectedStatus = record.status.map(String) + const expectedEditor = isDeepStrictEqual(record.status, ['ReadOnly']) ? ['ReadOnly'] : [] + const snapshots = [entry.before, entry.edited, entry.editedRecompute?.snapshot, entry.restored, entry.restoredRecompute?.snapshot] + if (!entry.pathStable || !entry.objectSetStable || entry.beforeSource.sha256 === entry.editedSource.sha256 || entry.beforeSource.bytes === entry.editedSource.bytes && entry.beforeSource.sha256 === entry.editedSource.sha256) fail(`${keys[index]} did not produce a distinct edited resource`) + if (entry.beforeSource.sha256 !== entry.before.sha256 || entry.editedSource.sha256 !== entry.edited.sha256 || entry.beforeSource.sha256 !== entry.restored.sha256 || entry.beforeSource.bytes !== entry.before.bytes || entry.editedSource.bytes !== entry.edited.bytes || entry.restored.bytes !== entry.beforeSource.bytes) fail(`${keys[index]} byte/hash mutation or restoration changed`) + if (entry.before.baseName !== entry.archiveName || entry.edited.baseName !== entry.archiveName || entry.restored.baseName !== entry.archiveName || snapshots.some((snapshot) => snapshot.propertyTypeId !== 'App::PropertyFileIncluded' || snapshot.writeBits !== 0 || snapshot.underTransientDir !== true || !isDeepStrictEqual(snapshot.propertyStatus, expectedStatus) || !isDeepStrictEqual(snapshot.editorMode, expectedEditor) || snapshot.exists !== true)) fail(`${keys[index]} path/permission/status metadata changed`) + if (entry.editedRecompute.result !== !isDeepStrictEqual(expectedStatus, ['27']) || entry.restoredRecompute.result !== !isDeepStrictEqual(expectedStatus, ['27'])) fail(`${keys[index]} recompute result changed`) + if (isDeepStrictEqual(expectedStatus, ['27'])) { + if (!isDeepStrictEqual(entry.before.objectState, ['Up-to-date']) || !isDeepStrictEqual(entry.edited.objectState, ['Up-to-date']) || !isDeepStrictEqual(entry.restored.objectState, ['Up-to-date']) || entry.edited.statusString !== 'Valid' || entry.restored.statusString !== 'Valid') fail(`${keys[index]} PropOutput touch suppression changed`) + } else { + if (!isDeepStrictEqual(entry.before.objectState, ['Up-to-date']) || entry.before.statusString !== 'Valid' || !isDeepStrictEqual(entry.edited.objectState, ['Touched']) || !isDeepStrictEqual(entry.restored.objectState, ['Touched']) || entry.edited.statusString !== 'Touched' || entry.restored.statusString !== 'Touched') fail(`${keys[index]} setter touch sequence changed`) + if (!isDeepStrictEqual(entry.editedRecompute.snapshot.objectState, ['Up-to-date']) || entry.editedRecompute.snapshot.statusString !== 'Valid' || !isDeepStrictEqual(entry.restoredRecompute.snapshot.objectState, ['Up-to-date']) || entry.restoredRecompute.snapshot.statusString !== 'Valid') fail(`${keys[index]} recompute recovery changed`) + } + const shapeExpected = entry.objectTypeId === 'Sketcher::SketchObjectSF' + if (entry.restored.shape?.applicable !== shapeExpected || shapeExpected && (entry.before.shape.isNull !== true || entry.edited.shape.isNull !== true || entry.restored.shape.isNull !== true || entry.restored.shape.edges !== 0)) fail(`${keys[index]} Shape boundary changed`) +} +console.log(JSON.stringify({ status: 'freecad-property-fileincluded-mutation-pass', propertyType: report.propertyType, caseCount: report.caseCount, editedCases: report.cases.filter(({ before, edited }) => before.sha256 !== edited.sha256).length, restoredCases: report.cases.filter(({ before, restored }) => before.sha256 === restored.sha256).length, stablePaths: report.cases.filter(({ pathStable }) => pathStable).length, stableObjects: report.cases.filter(({ objectSetStable }) => objectSetStable).length, outputTouchSuppressed: report.cases.find(({ propertyName, objectTypeId }) => objectTypeId === 'TechDraw::DrawSVGTemplate' && propertyName === 'PageResult')?.editedRecompute.result === false }, null, 2)) diff --git a/scripts/check-freecad-property-fileincluded-promotion.mjs b/scripts/check-freecad-property-fileincluded-promotion.mjs new file mode 100644 index 0000000..c5dc00a --- /dev/null +++ b/scripts/check-freecad-property-fileincluded-promotion.mjs @@ -0,0 +1,29 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const [report, semantics, progress, roundTrip, chrome] = await Promise.all([ + load('config/freecad-property-fileincluded-promotion.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), + load('config/freecad-property-fileincluded-roundtrip.json'), + load('config/chrome-property-fileincluded-verification.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyFileIncluded promotion check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.taskId !== 'PROP-app-propertyfileincluded-I' || report.propertyType !== 'App::PropertyFileIncluded' || report.recordCount !== 20 || report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.systemExact !== false) fail('promotion report boundary is invalid') +const requiredPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredPhases) { + const taskId = `PROP-app-propertyfileincluded-${phase}` + if (!completed.has(taskId) || !Array.isArray(report.phaseEvidence?.[phase]) || report.phaseEvidence[phase].length === 0 || !isDeepStrictEqual(report.phaseEvidence[phase], completed.get(taskId).evidence)) fail(`phase ${phase} evidence is incomplete`) +} +const nativeTarget = '09f4e4853de4277e25871d26f2e953c6ea9c13a73c7a01bdfcb5209d17f9a583' +const propertyType = semantics.types?.find(({ typeId }) => typeId === report.propertyType) +if (report.promotion?.from !== 'opaque-fcstd-proxy' || report.promotion.to !== 'native-editable-codec' || propertyType?.support !== report.promotion.to || propertyType.recordCount !== 20 || propertyType.objectTypeCount !== 15 || propertyType.statusNames?.join(',') !== 'PropOutput,ReadOnly' || report.promotion.facadeValueModel !== 'project-resource-identity-and-authoritative-bytes-with-native-fileincluded-fcstd-resource' || report.promotion.writableRecords !== 11 || report.promotion.readOnlyRecords !== 8 || report.promotion.outputRecords !== 1 || report.promotion.objectTypeCount !== 15 || report.promotion.fcstdElement !== 'FileIncluded' || report.promotion.nativeArchiveName !== 'payload.bin' || report.promotion.nativeRoundTripSha256 !== nativeTarget || report.promotion.browserArchiveName !== 'chrome-resource.bin' || report.promotion.browserRoundTripBytes !== 16 || report.promotion.externalResourceBoundary !== 'embedded FCStd ZIP entry restored to a read-only document transient file' || report.promotion.zeroUnknownDrift !== true) fail('capability promotion is incomplete') +const sync = report.exactBlockerSync +if (sync?.nativeEditableTypes !== 30 || sync.nativeEditableRecords !== 4361 || sync.opaqueTypes !== 50 || sync.opaqueRecords !== 466 || sync.exactPromotionReady !== false || sync.exactBlocker !== '50 runtime property types and 466 records remain opaque-only; complete native document and property semantics') fail('exact blocker synchronization is stale') +if (!isDeepStrictEqual(sync, { nativeEditableTypes: semantics.supportSummary['native-editable-codec'].typeCount, nativeEditableRecords: semantics.supportSummary['native-editable-codec'].recordCount, opaqueTypes: semantics.supportSummary['opaque-fcstd-proxy'].typeCount, opaqueRecords: semantics.supportSummary['opaque-fcstd-proxy'].recordCount, exactPromotionReady: semantics.exactPromotionReady, exactBlocker: semantics.exactBlocker })) fail('promotion report diverges from global property semantics') +if (roundTrip.classification?.zeroUnknownDrift !== true || roundTrip.classification.resavedSha256 !== nativeTarget || roundTrip.classification.resavedResourceMatches !== true || roundTrip.classification.externalResourceBoundary !== 'embedded FCStd ZIP entry restored to a read-only document transient file' || chrome.status !== 'pass' || chrome.persistence?.fcstdElement !== 'FileIncluded' || chrome.persistence.fcstdResourcePath !== 'chrome-resource.bin' || chrome.persistence.fcstdResourceBytes !== 16 || chrome.persistence.fcstdResourceMatches !== true || chrome.resource?.documentRoundTrip !== true || chrome.resource.independentReleased !== true || chrome.resource.markerRemoved !== true || chrome.release?.workerTerminated !== true) fail('G/H closure evidence regressed') +console.log(JSON.stringify({ status: 'freecad-property-fileincluded-promotion-pass', propertyType: report.propertyType, promotion: report.promotion, completedPhases: requiredPhases, exactBlockerSync: sync, systemExact: report.systemExact }, null, 2)) diff --git a/scripts/check-freecad-property-fileincluded-roundtrip.mjs b/scripts/check-freecad-property-fileincluded-roundtrip.mjs new file mode 100644 index 0000000..7d0531c --- /dev/null +++ b/scripts/check-freecad-property-fileincluded-roundtrip.mjs @@ -0,0 +1,24 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } 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-property-fileincluded-roundtrip.json'), 'utf8')) +const fail = (message) => { throw new Error(`FreeCAD PropertyFileIncluded roundtrip check failed: ${message}`) } +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-fileincluded-roundtrip' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyFileIncluded') fail('baseline is invalid') +const objectSet = [{ name: 'IncludedProbe', typeId: 'App::DocumentObjectFileIncluded' }] +for (const [phase, snapshot] of [['nativeInitial', report.nativeInitial], ['nativeReopened', report.nativeAfter?.reopened], ['nativeResaved', report.nativeAfter?.resaved]]) { + const object = snapshot?.object + if (object?.name !== 'IncludedProbe' || object.typeId !== 'App::DocumentObjectFileIncluded' || object.propertyTypeId !== 'App::PropertyFileIncluded' || object.baseName !== 'payload.bin' || object.exists !== true || !Number.isSafeInteger(object.bytes) || object.bytes <= 0 || !/^[0-9a-f]{64}$/.test(object.sha256) || object.writeBits !== 0 || object.underTransientDir !== true || !isDeepStrictEqual(object.propertyStatus, []) || !isDeepStrictEqual(object.editorMode, []) || !isDeepStrictEqual(object.state, ['Up-to-date']) || object.statusString !== 'Valid' || object.hasShapeProperty !== false || !isDeepStrictEqual(snapshot.objectSet, objectSet)) fail(`${phase} native object semantics are incomplete`) +} +if (report.nativeInitial.object.sha256 !== report.assets?.initial?.sha256 || report.nativeAfter.reopened.object.sha256 !== report.assets?.target?.sha256 || report.nativeAfter.resaved.object.sha256 !== report.assets?.target?.sha256) fail('native transient bytes do not match the locked assets') +const before = report.web?.before +const after = report.web?.after +if (before?.typeId !== 'App::PropertyFileIncluded' || before.element !== 'FileIncluded' || before.resourcePath !== 'payload.bin' || before.includedFileResource?.byteLength !== report.assets.initial.bytes || after?.typeId !== 'App::PropertyFileIncluded' || after.element !== 'FileIncluded' || after.resourcePath !== 'payload.bin' || after.includedFileResource?.byteLength !== report.assets.target.bytes) fail('Web property summaries are incomplete') +const resource = report.web.resource +if (resource?.path !== 'payload.bin' || resource.pathPreserved !== true || resource.beforeBytes !== report.assets.initial.bytes || resource.afterBytes !== report.assets.target.bytes || resource.beforeSha256 !== report.assets.initial.sha256 || resource.afterSha256 !== report.assets.target.sha256 || resource.changed !== true || report.web.targetMarkedTouched !== true || report.web.webOutputMatches !== true || report.web.semanticObjectsPreserved !== true || report.web.opaqueEntriesPreserved !== true || report.web.opaquePathsPreserved !== 0) fail('Web edit did not preserve native archive semantics') +if (report.nativeResavedResource?.path !== 'payload.bin' || report.nativeResavedResource.byteLength !== report.assets.target.bytes) fail('native resave did not retain the embedded resource') +const classification = report.classification +if (classification?.archiveName !== 'payload.bin' || classification.initialSha256 !== report.assets.initial.sha256 || classification.targetSha256 !== report.assets.target.sha256 || classification.reopenedSha256 !== report.assets.target.sha256 || classification.resavedSha256 !== report.assets.target.sha256 || classification.nativeOutputMatches !== true || classification.objectSetPreserved !== true || classification.resavedResourceMatches !== true || classification.externalResourceBoundary !== 'embedded FCStd ZIP entry restored to a read-only document transient file' || classification.unknownSemanticDrift !== false || classification.zeroUnknownDrift !== true) fail('round-trip classification is not exact for PropertyFileIncluded') +for (const artifact of [...Object.values(report.assets ?? {}), ...Object.values(report.archives ?? {})]) if (!artifact?.path || !Number.isSafeInteger(artifact.bytes) || artifact.bytes <= 0 || !/^[0-9a-f]{64}$/.test(artifact.sha256)) fail('asset or archive evidence is incomplete') +console.log(JSON.stringify({ status: 'freecad-property-fileincluded-roundtrip-pass', hashes: { initial: classification.initialSha256, reopened: classification.reopenedSha256, resaved: classification.resavedSha256 }, resource, opaquePathsPreserved: report.web.opaquePathsPreserved, zeroUnknownDrift: classification.zeroUnknownDrift }, null, 2)) diff --git a/scripts/check-freecad-property-fileincluded-success.mjs b/scripts/check-freecad-property-fileincluded-success.mjs new file mode 100644 index 0000000..7f1652d --- /dev/null +++ b/scripts/check-freecad-property-fileincluded-success.mjs @@ -0,0 +1,56 @@ +import { isDeepStrictEqual } from 'node:util' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const [report, inventory] = await Promise.all([ + readFile(resolve(root, 'config/freecad-property-fileincluded-success.json'), 'utf8').then(JSON.parse), + readFile(resolve(root, 'config/freecad-property-fileincluded-inventory.json'), 'utf8').then(JSON.parse), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyFileIncluded success check failed: ${message}`) } + +if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-fileincluded-success' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyFileIncluded' || report.hostCaseCount !== 20 || report.hostCases?.length !== 20 || report.diagnostics?.exception !== null) fail('baseline or report boundary is invalid') + +const setter = report.setterVariants +const phaseIds = ['StringPath', 'BytesPath', 'TupleRename', 'OpenIoFile', 'Dictionary', 'CollisionA', 'CollisionB'] +const phaseBaseNames = ['payload.bin', 'payload-two.bin', 'renamed.dat', 'payload-two1.bin', 'payload1.bin', 'collision.bin', 'collision1.bin'] +if (setter?.phases?.map(({ id }) => id).join('|') !== phaseIds.join('|') || setter.phases.map(({ baseName }) => baseName).join('|') !== phaseBaseNames.join('|') || setter.objectCount !== 8 || setter.recomputeResult !== true) fail('setter success phases changed') +for (const phase of setter.phases) { + if (phase.propertyTypeId !== 'App::PropertyFileIncluded' || !isDeepStrictEqual(phase.propertyStatus, []) || !isDeepStrictEqual(phase.editorMode, []) || phase.exists !== true || phase.bytes <= 0 || phase.sha256 !== phase.sourceSha256 || phase.writeBits !== 0 || phase.underTransientDir !== true || !isDeepStrictEqual(phase.objectState, ['Touched']) || phase.statusString !== 'Touched' || phase.shape?.applicable !== false) fail(`${phase.id} did not preserve native bytes, ownership, state or metadata`) +} +const empty = setter.emptyString +if (empty?.preserved !== true || empty.before?.value !== empty.after?.value || empty.before?.sha256 !== empty.after?.sha256 || empty.before?.bytes !== 38 || empty.after?.writeBits !== 0 || empty.after?.underTransientDir !== true) fail('empty-string no-op semantics changed') +const collision = setter.collision +if (collision?.distinctPaths !== true || collision.distinctBytes !== true || collision.first?.baseName !== 'collision.bin' || collision.second?.baseName !== 'collision1.bin' || collision.first.sha256 === collision.second.sha256 || collision.first.writeBits !== 0 || collision.second.writeBits !== 0) fail('same-name resource collision semantics changed') + +const inventoryKeys = inventory.records.map(({ objectTypeId, propertyName }) => `${objectTypeId}.${propertyName}`) +const caseKeys = report.hostCases.map(({ objectTypeId, propertyName }) => `${objectTypeId}.${propertyName}`) +if (!isDeepStrictEqual(caseKeys, inventoryKeys)) fail('host cases do not cover the complete locked inventory in order') +const expectedAssets = { + bin: { bytes: 38, sha256: '537d3bf00d6bbc268e5dc4bd9f436ee937b8e481ad6aac5b7fcc6edb29bb3246' }, + wrl: { bytes: 54, sha256: 'b06eb69af003e2a1cc0e70e8833473a5dff8f0a4487d65fb96a5e79cc6e1b179' }, + png: { bytes: 68, sha256: '431ced6916a2a21a156e38701afe55bbd7f88969fbbfc56d7fe099d47f265460' }, + csv: { bytes: 214, sha256: '75a789684c89a28de4dc9e8c40fe836e0cdbeeb2f58de251dd0734adb98bda3a' }, + skf: { bytes: 42, sha256: 'b32d9e3958b275212f00ab37b40e8cfb8f8fca5be7209713233cd55158031739' }, + pat: { bytes: 39, sha256: '2409d42fbc1592ac7e7aa6ebb7daf60cf4e1ed670c29da62deccc795e870ce98' }, + svg: { bytes: 88, sha256: '35b293e12fead414a67d8b703bb8cd7523e2361b52140430c7017b2e4780f723' }, +} +for (const [index, entry] of report.hostCases.entries()) { + const inventoryRecord = inventory.records[index] + const expectedStatus = inventoryRecord.status.map(String) + const expectedEditor = isDeepStrictEqual(inventoryRecord.status, ['ReadOnly']) ? ['ReadOnly'] : [] + const expectedAsset = expectedAssets[entry.source?.kind] + const expectedBaseName = `host-${String(index).padStart(2, '0')}.${entry.source?.kind}` + if (!expectedAsset || entry.source.bytes !== expectedAsset.bytes || entry.source.sha256 !== expectedAsset.sha256 || entry.archiveName !== expectedBaseName) fail(`${caseKeys[index]} source fixture changed`) + for (const [phaseName, snapshot] of [['afterSet', entry.afterSet], ['afterRecompute', entry.afterRecompute]]) { + if (snapshot?.propertyTypeId !== 'App::PropertyFileIncluded' || !isDeepStrictEqual(snapshot.propertyStatus, expectedStatus) || !isDeepStrictEqual(snapshot.editorMode, expectedEditor) || snapshot.baseName !== expectedBaseName || snapshot.exists !== true || snapshot.bytes !== expectedAsset.bytes || snapshot.sha256 !== expectedAsset.sha256 || snapshot.writeBits !== 0 || snapshot.underTransientDir !== true) fail(`${caseKeys[index]} ${phaseName} resource or metadata changed`) + } + if (entry.objectSetStable !== true || !isDeepStrictEqual(entry.afterRecompute.objectState, ['Up-to-date']) || entry.afterRecompute.statusString !== 'Valid') fail(`${caseKeys[index]} object set or final state changed`) + const isOutput = isDeepStrictEqual(expectedStatus, ['27']) + if (isOutput ? (entry.recomputeResult !== false || !isDeepStrictEqual(entry.afterSet.objectState, ['Up-to-date']) || entry.afterSet.statusString !== 'Valid') : (entry.recomputeResult !== true || !isDeepStrictEqual(entry.afterSet.objectState, ['Touched']) || entry.afterSet.statusString !== 'Touched')) fail(`${caseKeys[index]} touch/recompute behavior changed`) + const shapeExpected = entry.objectTypeId === 'Sketcher::SketchObjectSF' + if (entry.afterSet.shape?.applicable !== shapeExpected || shapeExpected && (entry.afterSet.shape.isNull !== true || entry.afterRecompute.shape.isNull !== true || entry.afterRecompute.shape.edges !== 0)) fail(`${caseKeys[index]} Shape applicability changed`) +} +if (report.hostCases.filter(({ default: value }) => value.exists).length !== 12 || report.hostCases.filter(({ afterSet }) => afterSet.exists).length !== 20 || report.hostCases.filter(({ afterSet, source }) => afterSet.sha256 === source.sha256).length !== 20 || report.hostCases.filter(({ afterSet }) => isDeepStrictEqual(afterSet.propertyStatus, ['ReadOnly'])).length !== 8 || report.hostCases.filter(({ afterSet }) => isDeepStrictEqual(afterSet.propertyStatus, ['27'])).length !== 1) fail('host success partition changed') + +console.log(JSON.stringify({ status: 'freecad-property-fileincluded-success-pass', propertyType: report.propertyType, setterInputs: ['string', 'bytes', 'tuple', 'io-file', 'dictionary'], emptyStringNoOp: empty.preserved, collisionNames: [collision.first.baseName, collision.second.baseName], hostCases: report.hostCaseCount, byteExactCases: report.hostCases.filter(({ afterSet, source }) => afterSet.sha256 === source.sha256).length, readOnlyCases: 8, outputCases: 1, shapeApplicableCases: 1, finalValidCases: report.hostCases.filter(({ afterRecompute }) => afterRecompute.statusString === 'Valid').length }, null, 2)) diff --git a/scripts/freecad-ordered-operation-pair-resave.py b/scripts/freecad-ordered-operation-pair-resave.py index 36d997c..853f710 100644 --- a/scripts/freecad-ordered-operation-pair-resave.py +++ b/scripts/freecad-ordered-operation-pair-resave.py @@ -168,6 +168,7 @@ def collect_rejected(): document.UndoMode = 1 baseline = document_snapshot(document) baseline_objects = object_set_snapshot(document) + baseline_source_shape_object = source.Shape.copy() baseline_source_shape = shape_snapshot_from_shape(source.Shape, include_brep=True) diagnostic = { "exceptionType": None, @@ -237,15 +238,19 @@ def collect_rejected(): elif operation == "fillet": feature = document.addObject("Part::Fillet", "PairResult") feature.Base = source - feature.Edges = [(index, 0.4, 0.4) for index in range(1, len(source.Shape.Edges) + 1)] + edge_indices = [1] if pair == "thickness->fillet" else range(1, len(source.Shape.Edges) + 1) + feature.Edges = [(index, 0.4, 0.4) for index in edge_indices] diagnostic["parameter"] = {"name": "radius", "value": 0.4} diagnostic["input"] = link_snapshot(feature.Base) + diagnostic["input"]["selectedEdges"] = [entry[0] for entry in feature.Edges] elif operation == "chamfer": feature = document.addObject("Part::Chamfer", "PairResult") feature.Base = source - feature.Edges = [(index, 0.4, 0.4) for index in range(1, len(source.Shape.Edges) + 1)] + edge_indices = [1] if pair == "thickness->chamfer" else range(1, len(source.Shape.Edges) + 1) + feature.Edges = [(index, 0.4, 0.4) for index in edge_indices] diagnostic["parameter"] = {"name": "distance", "value": 0.4} diagnostic["input"] = link_snapshot(feature.Base) + diagnostic["input"]["selectedEdges"] = [entry[0] for entry in feature.Edges] elif operation == "draft": body = document.addObject("PartDesign::Body", "Body") draft_base = body.newObject("PartDesign::Feature", "DraftBase") @@ -302,6 +307,20 @@ def collect_rejected(): if restored_source is None or not hasattr(restored_source, "Shape") or restored_source.Shape.isNull(): raise RuntimeError("Fuse source Shape is absent after transaction abort") restored_source_shape = shape_snapshot_from_shape(restored_source.Shape, include_brep=True) + source_shape_summary_restored = { + key: value for key, value in baseline_source_shape.items() if key != "brepSha256" + } == { + key: value for key, value in restored_source_shape.items() if key != "brepSha256" + } + source_shape_topologically_equal = bool(restored_source.Shape.isEqual(baseline_source_shape_object)) + source_shape_symmetric_difference = { + "beforeMinusAfterVolume": round(float(baseline_source_shape_object.cut(restored_source.Shape).Volume), 7), + "afterMinusBeforeVolume": round(float(restored_source.Shape.cut(baseline_source_shape_object).Volume), 7), + } + source_shape_geometrically_restored = source_shape_summary_restored and all( + value == 0 for value in source_shape_symmetric_difference.values() + ) + source_brep_reserialized = baseline_source_shape["brepSha256"] != restored_source_shape["brepSha256"] initial_path = os.path.join(output_directory, "ordered-pair-rejection.FCStd") resaved_path = os.path.join(output_directory, "ordered-pair-rejection-resaved.FCStd") document.saveAs(initial_path) @@ -334,6 +353,8 @@ def collect_rejected(): "freecadProfileAccepted": freecad_profile_accepted, "objectSetRestored": baseline_objects == restored_objects, "sourceShapeRestored": baseline_source_shape == restored_source_shape, + "sourceShapeGeometricallyRestored": source_shape_geometrically_restored, + "sourceShapeSummaryRestored": source_shape_summary_restored, "documentUnpolluted": baseline == initial, "documentStable": initial == reopened_snapshot and initial == resaved_snapshot, } @@ -357,10 +378,13 @@ def collect_rejected(): "rollback": { "before": {"objects": baseline_objects, "sourceShape": baseline_source_shape}, "after": {"objects": restored_objects, "sourceShape": restored_source_shape}, + "sourceBrepReserialized": source_brep_reserialized, + "sourceShapeSymmetricDifference": source_shape_symmetric_difference, + "sourceShapeTopologicallyEqual": source_shape_topologically_equal, }, "phases": {"initial": initial, "reopened": reopened_snapshot, "resaved": resaved_snapshot}, "checks": checks, - "status": "pass" if all(checks.values()) or (operation in ("fillet", "chamfer", "thickness") and freecad_profile_accepted and all(value for key, value in checks.items() if key != "nativeFeatureRejected")) or (freecad_profile_no_op and all(value for key, value in checks.items() if key not in ("nativeFeatureRejected", "freecadProfileAccepted"))) or (not freecad_profile_accepted and feature_rejected and all(value for key, value in checks.items() if key != "freecadProfileAccepted")) else "failed", + "status": "pass" if all(checks.values()) or (operation in ("fillet", "chamfer", "thickness") and freecad_profile_accepted and all(value for key, value in checks.items() if key != "nativeFeatureRejected")) or (freecad_profile_no_op and source_shape_geometrically_restored and all(value for key, value in checks.items() if key not in ("nativeFeatureRejected", "freecadProfileAccepted", "sourceShapeRestored"))) or (not freecad_profile_accepted and feature_rejected and all(value for key, value in checks.items() if key != "freecadProfileAccepted")) else "failed", } finally: for name in list(App.listDocuments().keys()): diff --git a/scripts/freecad-property-acceleration-failure.py b/scripts/freecad-property-acceleration-failure.py new file mode 100644 index 0000000..d631790 --- /dev/null +++ b/scripts/freecad-property-acceleration-failure.py @@ -0,0 +1,152 @@ +import json + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +INVALID_INPUTS = [ + ("wrong-dimension", "5 mm"), + ("malformed-text", "not-a-quantity"), +] + + +def value_snapshot(obj): + value = obj.Acceleration + return { + "raw": str(value), + "numeric": round(float(value.Value), 9), + "unit": str(value.Unit), + } + + +def object_snapshot(document): + return [ + {"name": obj.Name, "typeId": obj.TypeId} + for obj in document.Objects + ] + + +def exception_snapshot(callback): + try: + callback() + except Exception as error: + return {"type": type(error).__name__, "message": str(error)} + return None + + +def active_transaction_snapshot(): + active = App.getActiveTransaction() + if not active: + return {"name": "", "id": 0} + return {"name": str(active[0]), "id": int(active[1])} + + +def run(): + document = App.newDocument("PropertyAccelerationFailure") + try: + obj = document.addObject("Robot::TrajectoryDressUpObject", "AccelerationProbe") + document.recompute() + document.UndoMode = 1 + initial = value_snapshot(obj) + initial_objects = object_snapshot(document) + failures = [] + for case_id, requested in INVALID_INPUTS: + before = value_snapshot(obj) + before_objects = object_snapshot(document) + exception = exception_snapshot(lambda: setattr(obj, "Acceleration", requested)) + after = value_snapshot(obj) + after_objects = object_snapshot(document) + failures.append({ + "id": case_id, + "requested": requested, + "exception": exception, + "before": before, + "after": after, + "beforeObjects": before_objects, + "afterObjects": after_objects, + "valuePreserved": before == after, + "objectsPreserved": before_objects == after_objects, + "polluted": before_objects != after_objects, + }) + + disabled_before = value_snapshot(obj) + disabled_objects_before = object_snapshot(document) + obj.setEditorMode("Acceleration", ["ReadOnly"]) + obj.setPropertyStatus("Acceleration", "Immutable") + disabled_status = [str(item) for item in obj.getPropertyStatus("Acceleration")] + disabled_editor_mode = [str(item) for item in obj.getEditorMode("Acceleration")] + disabled_exception = exception_snapshot(lambda: setattr(obj, "Acceleration", "750 mm/s^2")) + disabled_after = value_snapshot(obj) + disabled_objects_after = object_snapshot(document) + obj.setPropertyStatus("Acceleration", "-Immutable") + obj.setEditorMode("Acceleration", 0) + disabled = { + "classification": "editor-read-only-and-python-immutable", + "requested": "750 mm/s^2", + "status": disabled_status, + "editorMode": disabled_editor_mode, + "exception": disabled_exception, + "before": disabled_before, + "after": disabled_after, + "beforeObjects": disabled_objects_before, + "afterObjects": disabled_objects_after, + "valuePreserved": disabled_before == disabled_after, + "objectsPreserved": disabled_objects_before == disabled_objects_after, + "restoredStatus": [str(item) for item in obj.getPropertyStatus("Acceleration")], + "restoredEditorMode": [str(item) for item in obj.getEditorMode("Acceleration")], + } + + document.openTransaction("property-acceleration-cancel") + transaction_before = value_snapshot(obj) + transaction_objects_before = object_snapshot(document) + obj.Acceleration = "250 mm/s^2" + transaction_edited = value_snapshot(obj) + transaction_pending_after_edit = bool(document.HasPendingTransaction) + transaction_active_after_edit = active_transaction_snapshot() + document.abortTransaction() + transaction_after = value_snapshot(obj) + transaction_objects_after = object_snapshot(document) + final_objects = object_snapshot(document) + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-acceleration-failure", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "object": {"name": obj.Name, "typeId": obj.TypeId}, + "property": {"name": "Acceleration", "typeId": obj.getTypeIdOfProperty("Acceleration")}, + "initial": initial, + "failures": failures, + "disabled": disabled, + "transaction": { + "before": transaction_before, + "edited": transaction_edited, + "afterAbort": transaction_after, + "objectsBefore": transaction_objects_before, + "objectsAfter": transaction_objects_after, + "undoMode": int(document.UndoMode), + "pendingAfterEdit": transaction_pending_after_edit, + "pendingAfterAbort": bool(document.HasPendingTransaction), + "activeAfterEdit": transaction_active_after_edit, + "activeAfterAbort": active_transaction_snapshot(), + "restored": transaction_before == transaction_after, + "objectsRestored": transaction_objects_before == transaction_objects_after, + }, + "cancellationBoundary": { + "supported": False, + "classification": "synchronous-property-setter", + "reason": "no-native-cancel-hook", + "replacement": "abort-active-document-transaction", + }, + "documentIntegrity": { + "initialObjects": initial_objects, + "finalObjects": final_objects, + "objectsPreserved": initial_objects == final_objects, + "objectCount": len(final_objects), + }, + } + finally: + App.closeDocument(document.Name) + + +print("FREECAD_PROPERTY_ACCELERATION_FAILURE_RESULT=" + json.dumps(run(), sort_keys=True)) diff --git a/scripts/freecad-property-acceleration-mutation.py b/scripts/freecad-property-acceleration-mutation.py new file mode 100644 index 0000000..e000c4f --- /dev/null +++ b/scripts/freecad-property-acceleration-mutation.py @@ -0,0 +1,137 @@ +import hashlib +import json +import xml.etree.ElementTree as ET + +import FreeCAD as App +import Robot + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def quantity_snapshot(value): + return { + "raw": str(value), + "numeric": round(float(value.Value), 9), + "unit": str(value.Unit), + } + + +def trajectory_snapshot(obj): + content = obj.Trajectory.Content + root = ET.fromstring(content) + waypoints = [] + for waypoint in root.findall("Waypoint"): + waypoints.append({ + "name": waypoint.attrib["name"], + "type": waypoint.attrib["type"], + "position": [round(float(waypoint.attrib[key]), 9) for key in ("Px", "Py", "Pz")], + "velocity": round(float(waypoint.attrib["vel"]), 9), + "acceleration": round(float(waypoint.attrib["acc"]), 9), + "continuous": waypoint.attrib["cont"] == "1", + "tool": int(waypoint.attrib["tool"]), + "base": int(waypoint.attrib["base"]), + }) + return { + "contentSha256": hashlib.sha256(content.encode("utf-8")).hexdigest(), + "waypointCount": len(waypoints), + "length": round(float(obj.Trajectory.Length), 9), + "duration": round(float(obj.Trajectory.Duration), 9), + "waypoints": waypoints, + } + + +def semantic_snapshot(obj): + return { + "value": quantity_snapshot(obj.Acceleration), + "propertyStatus": [str(item) for item in obj.getPropertyStatus("Acceleration")], + "editorMode": [str(item) for item in obj.getEditorMode("Acceleration")], + "source": {"name": obj.Source.Name, "typeId": obj.Source.TypeId}, + "useAcceleration": bool(obj.UseAcceleration), + "trajectory": trajectory_snapshot(obj), + "shape": {"applicable": hasattr(obj, "Shape")}, + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "mustExecute": bool(obj.MustExecute), + } + + +def object_snapshot(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def run(): + document = App.newDocument("PropertyAccelerationMutation") + try: + source = document.addObject("Robot::TrajectoryObject", "SourceTrajectory") + trajectory = source.Trajectory + trajectory = trajectory.insertWaypoints(App.Placement(App.Vector(1.0, 2.0, 3.0), App.Rotation())) + trajectory = trajectory.insertWaypoints(App.Placement(App.Vector(4.0, 6.0, 3.0), App.Rotation())) + source.Trajectory = trajectory + + obj = document.addObject("Robot::TrajectoryDressUpObject", "AccelerationProbe") + obj.Source = source + obj.UseAcceleration = True + initial_recompute = int(document.recompute()) + before = semantic_snapshot(obj) + source_before = trajectory_snapshot(source) + objects_before = object_snapshot(document) + + obj.Acceleration = "500 mm/s^2" + touched_after_edit = { + "value": quantity_snapshot(obj.Acceleration), + "objectState": [str(item) for item in obj.State], + "mustExecute": bool(obj.MustExecute), + } + edit_recompute = int(document.recompute()) + edited = semantic_snapshot(obj) + source_edited = trajectory_snapshot(source) + + obj.Acceleration = "1000 mm/s^2" + restore_recompute = int(document.recompute()) + restored = semantic_snapshot(obj) + source_restored = trajectory_snapshot(source) + objects_restored = object_snapshot(document) + + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-acceleration-mutation", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "object": {"name": obj.Name, "typeId": obj.TypeId}, + "property": {"name": "Acceleration", "typeId": obj.getTypeIdOfProperty("Acceleration")}, + "recompute": { + "initial": initial_recompute, + "edit": edit_recompute, + "restore": restore_recompute, + }, + "touchedAfterEdit": touched_after_edit, + "before": before, + "edited": edited, + "restored": restored, + "source": { + "before": source_before, + "edited": source_edited, + "restored": source_restored, + "preserved": source_before == source_edited == source_restored, + }, + "document": { + "objectsBefore": objects_before, + "objectsRestored": objects_restored, + "objectsPreserved": objects_before == objects_restored, + }, + "classification": { + "propertyChanged": before["value"] != edited["value"], + "trajectoryChanged": before["trajectory"] != edited["trajectory"], + "propertyRestored": before["value"] == restored["value"], + "trajectoryRestored": before["trajectory"] == restored["trajectory"], + "semanticStateRestored": before == restored, + "geometry": "not-applicable-no-shape-property", + }, + } + finally: + App.closeDocument(document.Name) + + +print("FREECAD_PROPERTY_ACCELERATION_MUTATION_RESULT=" + json.dumps(run(), sort_keys=True)) diff --git a/scripts/freecad-property-acceleration-roundtrip.py b/scripts/freecad-property-acceleration-roundtrip.py new file mode 100644 index 0000000..a1f8b52 --- /dev/null +++ b/scripts/freecad-property-acceleration-roundtrip.py @@ -0,0 +1,116 @@ +import hashlib +import json +import os +import xml.etree.ElementTree as ET + +import FreeCAD as App +import Robot + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def trajectory_snapshot(obj): + content = obj.Trajectory.Content + root = ET.fromstring(content) + waypoints = [ + { + "name": node.attrib["name"], + "type": node.attrib["type"], + "position": [round(float(node.attrib[key]), 9) for key in ("Px", "Py", "Pz")], + "velocity": round(float(node.attrib["vel"]), 9), + "acceleration": round(float(node.attrib["acc"]), 9), + } + for node in root.findall("Waypoint") + ] + return { + "contentSha256": hashlib.sha256(content.encode("utf-8")).hexdigest(), + "waypointCount": len(waypoints), + "length": round(float(obj.Trajectory.Length), 9), + "duration": round(float(obj.Trajectory.Duration), 9), + "waypoints": waypoints, + } + + +def object_snapshot(document): + obj = document.getObject("AccelerationProbe") + source = document.getObject("SourceTrajectory") + return { + "objectSet": [{"name": item.Name, "typeId": item.TypeId} for item in document.Objects], + "object": { + "name": obj.Name, + "typeId": obj.TypeId, + "propertyTypeId": obj.getTypeIdOfProperty("Acceleration"), + "value": {"raw": str(obj.Acceleration), "numeric": round(float(obj.Acceleration.Value), 9), "unit": str(obj.Acceleration.Unit)}, + "propertyStatus": [str(item) for item in obj.getPropertyStatus("Acceleration")], + "editorMode": [str(item) for item in obj.getEditorMode("Acceleration")], + "source": {"name": obj.Source.Name, "typeId": obj.Source.TypeId}, + "useAcceleration": bool(obj.UseAcceleration), + "state": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "trajectory": trajectory_snapshot(obj), + }, + "sourceTrajectory": trajectory_snapshot(source), + } + + +def create_native(path): + document = App.newDocument("PropertyAccelerationRoundtrip") + try: + source = document.addObject("Robot::TrajectoryObject", "SourceTrajectory") + trajectory = source.Trajectory + trajectory = trajectory.insertWaypoints(App.Placement(App.Vector(1.0, 2.0, 3.0), App.Rotation())) + trajectory = trajectory.insertWaypoints(App.Placement(App.Vector(4.0, 6.0, 3.0), App.Rotation())) + source.Trajectory = trajectory + obj = document.addObject("Robot::TrajectoryDressUpObject", "AccelerationProbe") + obj.Source = source + obj.UseAcceleration = True + obj.Acceleration = "1000 mm/s^2" + document.recompute() + document.saveAs(path) + finally: + App.closeDocument(document.Name) + reopened = App.openDocument(path) + try: + reopened.recompute() + return object_snapshot(reopened) + finally: + App.closeDocument(reopened.Name) + + +def verify_native(path, resaved_path): + document = App.openDocument(path) + try: + document.recompute() + reopened = object_snapshot(document) + document.saveAs(resaved_path) + finally: + App.closeDocument(document.Name) + resaved_document = App.openDocument(resaved_path) + try: + resaved_document.recompute() + resaved = object_snapshot(resaved_document) + finally: + App.closeDocument(resaved_document.Name) + return {"reopened": reopened, "resaved": resaved} + + +mode = os.environ.get("FREECAD_PROPERTY_ACCELERATION_ROUNDTRIP_MODE", "") +path = os.environ.get("FREECAD_PROPERTY_ACCELERATION_ROUNDTRIP_PATH", "") +resaved_path = os.environ.get("FREECAD_PROPERTY_ACCELERATION_ROUNDTRIP_RESAVED_PATH", "") +if mode == "create": + result = create_native(path) +elif mode == "verify": + result = verify_native(path, resaved_path) +else: + raise RuntimeError("FREECAD_PROPERTY_ACCELERATION_ROUNDTRIP_MODE must be create or verify") + +print("FREECAD_PROPERTY_ACCELERATION_ROUNDTRIP_RESULT=" + json.dumps({ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-acceleration-roundtrip", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "mode": mode, + "result": result, +}, sort_keys=True)) diff --git a/scripts/freecad-property-acceleration-success.py b/scripts/freecad-property-acceleration-success.py new file mode 100644 index 0000000..47a5d6f --- /dev/null +++ b/scripts/freecad-property-acceleration-success.py @@ -0,0 +1,77 @@ +import json +import hashlib +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +CASES = [ + ("default", None), + ("nominal", "500 mm/s^2"), + ("lower-bound", "0 mm/s^2"), + ("negative-boundary", "-500 mm/s^2"), +] + + +def value_snapshot(obj): + value = getattr(obj, "Acceleration") + return { + "raw": str(value), + "numeric": round(float(value.Value), 9), + "unit": str(value.Unit), + } + + +def shape_snapshot(obj): + if not hasattr(obj, "Shape"): + return {"applicable": False} + shape = obj.Shape + if shape.isNull(): + return {"applicable": True, "shapeNull": True, "shapeValid": None, "solids": 0, "faces": 0} + return { + "applicable": True, + "shapeNull": False, + "shapeValid": bool(shape.isValid()), + "solids": len(shape.Solids), + "faces": len(shape.Faces), + } + + +def run(): + document = App.newDocument("PropertyAccelerationSuccess") + try: + obj = document.addObject("Robot::TrajectoryDressUpObject", "AccelerationProbe") + document.recompute() + cases = [] + for case_id, requested in CASES: + if requested is not None: + obj.Acceleration = requested + document.recompute() + cases.append({ + "id": case_id, + "requested": requested, + "value": value_snapshot(obj), + "status": [str(item) for item in obj.getPropertyStatus("Acceleration")], + "typeId": obj.getTypeIdOfProperty("Acceleration"), + "group": obj.getGroupOfProperty("Acceleration"), + "editorMode": [str(item) for item in obj.getEditorMode("Acceleration")], + "shape": shape_snapshot(obj), + "objectState": [str(item) for item in obj.State], + }) + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-acceleration-success", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "object": {"name": obj.Name, "typeId": obj.TypeId}, + "property": {"name": "Acceleration", "typeId": obj.getTypeIdOfProperty("Acceleration"), "group": obj.getGroupOfProperty("Acceleration")}, + "cases": cases, + "diagnostics": {"exception": None, "documentObjectCount": len(document.Objects)}, + } + finally: + App.closeDocument(document.Name) + + +print("FREECAD_PROPERTY_ACCELERATION_SUCCESS_RESULT=" + json.dumps(run(), sort_keys=True)) diff --git a/scripts/freecad-property-area-failure.py b/scripts/freecad-property-area-failure.py new file mode 100644 index 0000000..bce02e1 --- /dev/null +++ b/scripts/freecad-property-area-failure.py @@ -0,0 +1,190 @@ +import json + +import FreeCAD as App +import Part + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def object_set(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def area_snapshot(measure): + value = measure.Area + return { + "raw": str(value), + "numeric": round(float(value.Value), 9), + "unit": str(value.Unit), + "elements": [ + {"object": obj.Name, "subElements": list(sub_elements)} + for obj, sub_elements in measure.Elements + ], + "state": [str(item) for item in measure.State], + "statusString": str(measure.getStatusString()), + } + + +def exception_snapshot(callback): + try: + callback() + except Exception as error: + return {"type": type(error).__name__, "message": str(error)} + return None + + +def active_transaction_snapshot(): + active = App.getActiveTransaction() + if not active: + return {"name": "", "id": 0} + return {"name": str(active[0]), "id": int(active[1])} + + +def run(): + document = App.newDocument("PropertyAreaFailure") + try: + box = document.addObject("Part::Box", "AreaBox") + box.Length = 10 + box.Width = 5 + box.Height = 2 + cylinder = document.addObject("Part::Cylinder", "AreaCylinder") + cylinder.Radius = 3 + cylinder.Height = 4 + point = document.addObject("Part::Feature", "AreaPoint") + point.Shape = Part.Vertex(App.Vector(0, 0, 0)) + line = document.addObject("Part::Feature", "AreaLine") + line.Shape = Part.makeLine(App.Vector(0, 0, 0), App.Vector(4, 0, 0)) + measure = document.addObject("Measure::MeasureArea", "AreaProbe") + measure.Elements = [(box, ["Face1"])] + document.recompute() + document.UndoMode = 1 + initial = area_snapshot(measure) + initial_objects = object_set(document) + + failures = [] + for case_id, source, sub_element, shape_type in [ + ("unsupported-point", point, "Vertex1", "Vertex"), + ("unsupported-line", line, "Edge1", "Edge"), + ]: + measure.Elements = [(box, ["Face1"])] + document.recompute() + before = area_snapshot(measure) + before_objects = object_set(document) + assignment_exception = exception_snapshot(lambda: setattr(measure, "Elements", [(source, [sub_element])])) + recompute_exception = None + recompute_result = None + try: + recompute_result = bool(document.recompute()) + except Exception as error: + recompute_exception = {"type": type(error).__name__, "message": str(error)} + after = area_snapshot(measure) + after_objects = object_set(document) + measure.Elements = [(box, ["Face1"])] + document.recompute() + recovered = area_snapshot(measure) + failures.append({ + "id": case_id, + "source": {"name": source.Name, "typeId": source.TypeId, "subElement": sub_element, "shapeType": shape_type}, + "expectedDiagnostic": "Cannot calculate area", + "assignmentException": assignment_exception, + "recomputeException": recompute_exception, + "recomputeResult": recompute_result, + "before": before, + "after": after, + "recovered": recovered, + "beforeObjects": before_objects, + "afterObjects": after_objects, + "objectsPreserved": before_objects == after_objects, + "valuePreserved": before["numeric"] == after["numeric"], + "recoveredExactly": before["numeric"] == recovered["numeric"] and before["elements"] == recovered["elements"], + }) + + measure.Elements = [(box, ["Face1"])] + document.recompute() + disabled_before = area_snapshot(measure) + disabled_objects_before = object_set(document) + editor_read_only_exception = exception_snapshot(lambda: setattr(measure, "Area", "20 mm^2")) + editor_read_only_after = area_snapshot(measure) + measure.setPropertyStatus("Area", "Immutable") + immutable_status = [str(item) for item in measure.getPropertyStatus("Area")] + immutable_exception = exception_snapshot(lambda: setattr(measure, "Area", "30 mm^2")) + immutable_after = area_snapshot(measure) + measure.setPropertyStatus("Area", "-Immutable") + restored_status = [str(item) for item in measure.getPropertyStatus("Area")] + restored_editor_mode = [str(item) for item in measure.getEditorMode("Area")] + measure.Elements = [] + measure.Elements = [(box, ["Face1"])] + document.recompute() + disabled_restored = area_snapshot(measure) + disabled_objects_after = object_set(document) + disabled = { + "classification": "editor-readonly-python-mutable-until-immutable", + "editorReadOnlyRequested": "20 mm^2", + "immutableRequested": "30 mm^2", + "propertyStatus": ["24", "27"], + "editorMode": [str(item) for item in measure.getEditorMode("Area")], + "editorReadOnlyException": editor_read_only_exception, + "editorReadOnlyAfter": editor_read_only_after, + "pythonBypassesEditorReadOnly": editor_read_only_exception is None and editor_read_only_after["numeric"] == 20, + "immutableStatus": immutable_status, + "immutableException": immutable_exception, + "immutableAfter": immutable_after, + "before": disabled_before, + "restored": disabled_restored, + "restoredStatus": restored_status, + "restoredEditorMode": restored_editor_mode, + "immutableValuePreserved": editor_read_only_after == immutable_after, + "valueRestored": disabled_before["numeric"] == disabled_restored["numeric"] and disabled_before["elements"] == disabled_restored["elements"], + "objectsPreserved": disabled_objects_before == disabled_objects_after, + } + + document.openTransaction("property-area-cancel") + transaction_before = area_snapshot(measure) + transaction_objects_before = object_set(document) + measure.Elements = [(cylinder, ["Face1"])] + document.recompute() + transaction_edited = area_snapshot(measure) + transaction_pending_after_edit = bool(document.HasPendingTransaction) + transaction_active_after_edit = active_transaction_snapshot() + document.abortTransaction() + transaction_after_abort = area_snapshot(measure) + document.recompute() + transaction_after_recompute = area_snapshot(measure) + transaction_objects_after = object_set(document) + + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-area-failure", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "object": {"name": measure.Name, "typeId": measure.TypeId}, + "property": {"name": "Area", "typeId": measure.getTypeIdOfProperty("Area")}, + "input": {"name": "Elements", "typeId": measure.getTypeIdOfProperty("Elements")}, + "initial": initial, + "failures": failures, + "disabled": disabled, + "transaction": { + "before": transaction_before, + "edited": transaction_edited, + "afterAbort": transaction_after_abort, + "afterRecompute": transaction_after_recompute, + "objectsBefore": transaction_objects_before, + "objectsAfter": transaction_objects_after, + "undoMode": int(document.UndoMode), + "pendingAfterEdit": transaction_pending_after_edit, + "pendingAfterAbort": bool(document.HasPendingTransaction), + "activeAfterEdit": transaction_active_after_edit, + "activeAfterAbort": active_transaction_snapshot(), + "restored": transaction_before["numeric"] == transaction_after_recompute["numeric"] and transaction_before["elements"] == transaction_after_recompute["elements"], + "objectsRestored": transaction_objects_before == transaction_objects_after, + }, + "cancellationBoundary": {"supported": False, "classification": "synchronous-measure-recompute", "reason": "no-native-cancel-hook", "replacement": "abort-active-document-transaction"}, + "documentIntegrity": {"initialObjects": initial_objects, "finalObjects": object_set(document), "objectsPreserved": initial_objects == object_set(document), "objectCount": len(document.Objects)}, + } + finally: + App.closeDocument(document.Name) + + +print("FREECAD_PROPERTY_AREA_FAILURE_RESULT=" + json.dumps(run(), sort_keys=True)) diff --git a/scripts/freecad-property-area-mutation.py b/scripts/freecad-property-area-mutation.py new file mode 100644 index 0000000..4df312e --- /dev/null +++ b/scripts/freecad-property-area-mutation.py @@ -0,0 +1,143 @@ +import json + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def quantity_snapshot(value): + return { + "raw": str(value), + "numeric": round(float(value.Value), 9), + "unit": str(value.Unit), + } + + +def elements_snapshot(measure): + return [ + {"object": obj.Name, "typeId": obj.TypeId, "subElements": list(sub_elements)} + for obj, sub_elements in measure.Elements + ] + + +def semantic_snapshot(measure): + return { + "value": quantity_snapshot(measure.Area), + "elements": elements_snapshot(measure), + "propertyStatus": [str(item) for item in measure.getPropertyStatus("Area")], + "editorMode": [str(item) for item in measure.getEditorMode("Area")], + "shape": {"applicable": hasattr(measure, "Shape")}, + "objectState": [str(item) for item in measure.State], + "statusString": str(measure.getStatusString()), + "mustExecute": bool(measure.MustExecute), + } + + +def shape_snapshot(obj): + shape = obj.Shape + bounds = shape.BoundBox + return { + "name": obj.Name, + "typeId": obj.TypeId, + "shapeType": shape.ShapeType, + "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), 9), + "area": round(float(shape.Area), 9), + "bounds": [ + round(float(value), 9) + for value in (bounds.XMin, bounds.YMin, bounds.ZMin, bounds.XMax, bounds.YMax, bounds.ZMax) + ], + } + + +def object_snapshot(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def run(): + document = App.newDocument("PropertyAreaMutation") + try: + box = document.addObject("Part::Box", "AreaBox") + box.Length = 10 + box.Width = 5 + box.Height = 2 + cylinder = document.addObject("Part::Cylinder", "AreaCylinder") + cylinder.Radius = 3 + cylinder.Height = 4 + measure = document.addObject("Measure::MeasureArea", "AreaProbe") + measure.Elements = [(box, ["Face1"])] + initial_recompute = int(document.recompute()) + + before = semantic_snapshot(measure) + sources_before = [shape_snapshot(source) for source in (box, cylinder)] + objects_before = object_snapshot(document) + + measure.Elements = [(box, ["Face1", "Face2"]), (cylinder, ["Face1"])] + touched_after_edit = { + "value": quantity_snapshot(measure.Area), + "elements": elements_snapshot(measure), + "objectState": [str(item) for item in measure.State], + "mustExecute": bool(measure.MustExecute), + } + edit_recompute = int(document.recompute()) + edited = semantic_snapshot(measure) + sources_edited = [shape_snapshot(source) for source in (box, cylinder)] + + measure.Elements = [(box, ["Face1"])] + touched_after_restore = { + "value": quantity_snapshot(measure.Area), + "elements": elements_snapshot(measure), + "objectState": [str(item) for item in measure.State], + "mustExecute": bool(measure.MustExecute), + } + restore_recompute = int(document.recompute()) + restored = semantic_snapshot(measure) + sources_restored = [shape_snapshot(source) for source in (box, cylinder)] + objects_restored = object_snapshot(document) + + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-area-mutation", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "object": {"name": measure.Name, "typeId": measure.TypeId}, + "property": {"name": "Area", "typeId": measure.getTypeIdOfProperty("Area")}, + "input": {"name": "Elements", "typeId": measure.getTypeIdOfProperty("Elements")}, + "recompute": {"initial": initial_recompute, "edit": edit_recompute, "restore": restore_recompute}, + "touchedAfterEdit": touched_after_edit, + "touchedAfterRestore": touched_after_restore, + "before": before, + "edited": edited, + "restored": restored, + "sources": { + "before": sources_before, + "edited": sources_edited, + "restored": sources_restored, + "preserved": sources_before == sources_edited == sources_restored, + }, + "document": { + "objectsBefore": objects_before, + "objectsRestored": objects_restored, + "objectsPreserved": objects_before == objects_restored, + }, + "classification": { + "inputChanged": before["elements"] != edited["elements"], + "derivedValueChanged": before["value"] != edited["value"], + "inputRestored": before["elements"] == restored["elements"], + "derivedValueRestored": before["value"] == restored["value"], + "semanticStateRestored": before == restored, + "sourceGeometryPreserved": sources_before == sources_edited == sources_restored, + "geometry": "source-shapes-preserved-derived-measurement-has-no-shape", + }, + } + finally: + App.closeDocument(document.Name) + + +print("FREECAD_PROPERTY_AREA_MUTATION_RESULT=" + json.dumps(run(), sort_keys=True)) diff --git a/scripts/freecad-property-area-roundtrip.py b/scripts/freecad-property-area-roundtrip.py new file mode 100644 index 0000000..0075a8b --- /dev/null +++ b/scripts/freecad-property-area-roundtrip.py @@ -0,0 +1,117 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def shape_snapshot(obj): + shape = obj.Shape + bounds = shape.BoundBox + return { + "name": obj.Name, + "typeId": obj.TypeId, + "valid": bool(shape.isValid()), + "shapeType": shape.ShapeType, + "solids": len(shape.Solids), + "faces": len(shape.Faces), + "edges": len(shape.Edges), + "vertices": len(shape.Vertexes), + "volume": round(float(shape.Volume), 9), + "area": round(float(shape.Area), 9), + "bounds": [ + round(float(value), 9) + for value in (bounds.XMin, bounds.YMin, bounds.ZMin, bounds.XMax, bounds.YMax, bounds.ZMax) + ], + } + + +def measure_snapshot(document): + measure = document.getObject("AreaProbe") + box = document.getObject("AreaBox") + return { + "objectSet": [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects], + "source": { + **shape_snapshot(box), + "length": round(float(box.Length.Value), 9), + "width": round(float(box.Width.Value), 9), + "height": round(float(box.Height.Value), 9), + }, + "measure": { + "name": measure.Name, + "typeId": measure.TypeId, + "areaTypeId": measure.getTypeIdOfProperty("Area"), + "elementsTypeId": measure.getTypeIdOfProperty("Elements"), + "area": {"raw": str(measure.Area), "numeric": round(float(measure.Area.Value), 9), "unit": str(measure.Area.Unit)}, + "elements": [ + {"object": obj.Name, "typeId": obj.TypeId, "subElements": list(sub_elements)} + for obj, sub_elements in measure.Elements + ], + "propertyStatus": [str(item) for item in measure.getPropertyStatus("Area")], + "editorMode": [str(item) for item in measure.getEditorMode("Area")], + "state": [str(item) for item in measure.State], + "statusString": str(measure.getStatusString()), + "shape": {"applicable": hasattr(measure, "Shape")}, + }, + } + + +def create_native(path): + document = App.newDocument("PropertyAreaRoundtrip") + try: + box = document.addObject("Part::Box", "AreaBox") + box.Length = 10 + box.Width = 5 + box.Height = 2 + measure = document.addObject("Measure::MeasureArea", "AreaProbe") + measure.Elements = [(box, ["Face1"])] + document.recompute() + document.saveAs(path) + finally: + App.closeDocument(document.Name) + reopened = App.openDocument(path) + try: + reopened.recompute() + return measure_snapshot(reopened) + finally: + App.closeDocument(reopened.Name) + + +def verify_native(path, resaved_path): + document = App.openDocument(path) + try: + document.recompute() + reopened = measure_snapshot(document) + document.saveAs(resaved_path) + finally: + App.closeDocument(document.Name) + resaved_document = App.openDocument(resaved_path) + try: + resaved_document.recompute() + resaved = measure_snapshot(resaved_document) + finally: + App.closeDocument(resaved_document.Name) + return {"reopened": reopened, "resaved": resaved} + + +mode = os.environ.get("FREECAD_PROPERTY_AREA_ROUNDTRIP_MODE", "") +path = os.environ.get("FREECAD_PROPERTY_AREA_ROUNDTRIP_PATH", "") +resaved_path = os.environ.get("FREECAD_PROPERTY_AREA_ROUNDTRIP_RESAVED_PATH", "") +if mode == "create": + result = create_native(path) +elif mode == "verify": + result = verify_native(path, resaved_path) +else: + raise RuntimeError("FREECAD_PROPERTY_AREA_ROUNDTRIP_MODE must be create or verify") + +print("FREECAD_PROPERTY_AREA_ROUNDTRIP_RESULT=" + json.dumps({ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-area-roundtrip", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "mode": mode, + "result": result, +}, sort_keys=True)) diff --git a/scripts/freecad-property-area-success.py b/scripts/freecad-property-area-success.py new file mode 100644 index 0000000..4af8bc2 --- /dev/null +++ b/scripts/freecad-property-area-success.py @@ -0,0 +1,111 @@ +import json + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def quantity_snapshot(value): + return { + "raw": str(value), + "numeric": round(float(value.Value), 9), + "unit": str(value.Unit), + } + + +def object_snapshot(obj): + return { + "name": obj.Name, + "typeId": obj.TypeId, + "state": [str(item) for item in obj.State], + "status": obj.getStatusString(), + } + + +def element_snapshot(obj, sub_elements): + entries = [] + for sub_element in sub_elements: + shape = obj.Shape if not sub_element else obj.getSubObject(sub_element) + entries.append({ + "object": obj.Name, + "subElement": sub_element, + "shapeType": shape.ShapeType, + "shapeNull": bool(shape.isNull()), + "shapeValid": bool(shape.isValid()), + "area": round(float(shape.Area), 9), + "faces": len(shape.Faces), + "edges": len(shape.Edges), + "vertices": len(shape.Vertexes), + }) + return entries + + +def run(): + document = App.newDocument("PropertyAreaSuccess") + try: + box = document.addObject("Part::Box", "AreaBox") + box.Length = 10 + box.Width = 5 + box.Height = 2 + cylinder = document.addObject("Part::Cylinder", "AreaCylinder") + cylinder.Radius = 3 + cylinder.Height = 4 + sphere = document.addObject("Part::Sphere", "AreaSphere") + sphere.Radius = 2 + measure = document.addObject("Measure::MeasureArea", "AreaProbe") + document.recompute() + + cases = [] + + def capture(case_id, requested): + if requested is not None: + measure.Elements = requested + document.recompute() + references = [] if requested is None else [ + (obj, list(sub_elements)) for obj, sub_elements in requested + ] + elements = [ + entry + for obj, sub_elements in references + for entry in element_snapshot(obj, sub_elements) + ] + expected_area = round(sum(entry["area"] for entry in elements), 9) + cases.append({ + "id": case_id, + "elements": elements, + "expectedArea": expected_area, + "value": quantity_snapshot(measure.Area), + "propertyStatus": [str(item) for item in measure.getPropertyStatus("Area")], + "editorMode": [str(item) for item in measure.getEditorMode("Area")], + "elementsTypeId": measure.getTypeIdOfProperty("Elements"), + "areaTypeId": measure.getTypeIdOfProperty("Area"), + "object": object_snapshot(measure), + "shape": {"applicable": hasattr(measure, "Shape")}, + }) + + capture("empty-default", None) + capture("planar-face", [(box, ["Face1"])]) + capture("cylindrical-face", [(cylinder, ["Face1"])]) + capture("surface-face", [(sphere, ["Face1"])]) + capture("solid-volume", [(box, [""])]) + capture("multi-element-sum", [(box, ["Face1", "Face2"]), (cylinder, ["Face1"])]) + + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-area-success", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "object": {"name": measure.Name, "typeId": measure.TypeId}, + "property": {"name": "Area", "typeId": measure.getTypeIdOfProperty("Area"), "group": measure.getGroupOfProperty("Area")}, + "input": {"name": "Elements", "typeId": measure.getTypeIdOfProperty("Elements"), "group": measure.getGroupOfProperty("Elements")}, + "sources": [object_snapshot(source) for source in [box, cylinder, sphere]], + "cases": cases, + "diagnostics": {"exception": None, "documentObjectCount": len(document.Objects)}, + } + finally: + App.closeDocument(document.Name) + + +print("FREECAD_PROPERTY_AREA_SUCCESS_RESULT=" + json.dumps(run(), sort_keys=True)) diff --git a/scripts/freecad-property-boollist-failure.py b/scripts/freecad-property-boollist-failure.py new file mode 100644 index 0000000..f14ce56 --- /dev/null +++ b/scripts/freecad-property-boollist-failure.py @@ -0,0 +1,246 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_BOOLLIST_FAILURE_OUTPUT", "") + + +def object_snapshot(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def active_transaction_snapshot(): + active = App.getActiveTransaction() + if not active: + return {"name": "", "id": 0} + return {"name": str(active[0]), "id": int(active[1])} + + +def exception_snapshot(callback): + try: + callback() + except Exception as error: + return {"type": type(error).__name__, "message": str(error)} + return None + + +def writable_failures(): + document = App.newDocument("PropertyBoolListFailure") + try: + obj = document.addObject("App::FeatureTest", "BoolListProbe") + document.recompute() + document.UndoMode = 1 + initial = list(obj.BoolList) + initial_objects = object_snapshot(document) + accepted_coercions = [] + for case_id, requested in [("scalar-integer", 7), ("bitstring", "10201")]: + before = list(obj.BoolList) + before_objects = object_snapshot(document) + exception = exception_snapshot(lambda value=requested: setattr(obj, "BoolList", value)) + after = list(obj.BoolList) + after_objects = object_snapshot(document) + accepted_coercions.append({ + "id": case_id, + "requested": repr(requested), + "exception": exception, + "before": before, + "after": after, + "beforeObjects": before_objects, + "afterObjects": after_objects, + "objectsPreserved": before_objects == after_objects, + }) + obj.BoolList = initial + requested_cases = [ + ("none", None), + ("float-item", [True, 1.5]), + ("string-item", [False, "bad"]), + ] + failures = [] + for case_id, requested in requested_cases: + before = list(obj.BoolList) + before_objects = object_snapshot(document) + exception = exception_snapshot(lambda value=requested: setattr(obj, "BoolList", value)) + after = list(obj.BoolList) + after_objects = object_snapshot(document) + if exception is None: + obj.BoolList = initial + failures.append({ + "id": case_id, + "requested": repr(requested), + "exception": exception, + "before": before, + "after": after, + "beforeObjects": before_objects, + "afterObjects": after_objects, + "valuePreserved": before == after, + "objectsPreserved": before_objects == after_objects, + "polluted": before_objects != after_objects, + }) + + disabled_before = list(obj.BoolList) + disabled_objects_before = object_snapshot(document) + obj.setEditorMode("BoolList", ["ReadOnly"]) + obj.setPropertyStatus("BoolList", "Immutable") + disabled_status = [str(item) for item in obj.getPropertyStatus("BoolList")] + disabled_editor_mode = [str(item) for item in obj.getEditorMode("BoolList")] + disabled_exception = exception_snapshot(lambda: setattr(obj, "BoolList", [True, False])) + disabled_after = list(obj.BoolList) + disabled_objects_after = object_snapshot(document) + obj.setPropertyStatus("BoolList", "-Immutable") + obj.setEditorMode("BoolList", 0) + disabled = { + "classification": "editor-read-only-and-python-immutable", + "requested": [True, False], + "status": disabled_status, + "editorMode": disabled_editor_mode, + "exception": disabled_exception, + "before": disabled_before, + "after": disabled_after, + "beforeObjects": disabled_objects_before, + "afterObjects": disabled_objects_after, + "valuePreserved": disabled_before == disabled_after, + "objectsPreserved": disabled_objects_before == disabled_objects_after, + "restoredStatus": [str(item) for item in obj.getPropertyStatus("BoolList")], + "restoredEditorMode": [str(item) for item in obj.getEditorMode("BoolList")], + } + + document.openTransaction("property-boollist-cancel") + transaction_before = list(obj.BoolList) + transaction_objects_before = object_snapshot(document) + obj.BoolList = [True, False, True] + transaction_edited = list(obj.BoolList) + pending_after_edit = bool(document.HasPendingTransaction) + active_after_edit = active_transaction_snapshot() + document.abortTransaction() + transaction_after = list(obj.BoolList) + transaction_objects_after = object_snapshot(document) + return { + "object": {"name": obj.Name, "typeId": obj.TypeId}, + "property": {"name": "BoolList", "typeId": obj.getTypeIdOfProperty("BoolList")}, + "initial": initial, + "acceptedCoercions": accepted_coercions, + "failures": failures, + "disabled": disabled, + "transaction": { + "before": transaction_before, + "edited": transaction_edited, + "afterAbort": transaction_after, + "objectsBefore": transaction_objects_before, + "objectsAfter": transaction_objects_after, + "undoMode": int(document.UndoMode), + "pendingAfterEdit": pending_after_edit, + "pendingAfterAbort": bool(document.HasPendingTransaction), + "activeAfterEdit": active_after_edit, + "activeAfterAbort": active_transaction_snapshot(), + "restored": transaction_before == transaction_after, + "objectsRestored": transaction_objects_before == transaction_objects_after, + }, + "documentIntegrity": { + "initialObjects": initial_objects, + "finalObjects": object_snapshot(document), + "objectsPreserved": initial_objects == object_snapshot(document), + }, + } + finally: + App.closeDocument(document.Name) + + +def link_failure(object_type_id, object_name): + document = App.newDocument("PropertyBoolList" + object_name + "Failure") + try: + first = document.addObject("Part::Feature", "TargetA") + second = document.addObject("Part::Feature", "TargetB") + group = document.addObject("App::DocumentObjectGroup", "TargetGroup") + group.addObjects([first, second]) + obj = document.addObject(object_type_id, object_name) + if "LinkedObject" in obj.PropertiesList: + obj.LinkedObject = group + else: + obj.ElementList = [first, second] + document.recompute() + document.UndoMode = 1 + initial = list(obj.VisibilityList) + initial_objects = object_snapshot(document) + direct_exception = exception_snapshot(lambda: setattr(obj, "VisibilityList", [False, True])) + after_direct = list(obj.VisibilityList) + invalid_element_result = int(obj.setElementVisible("MissingElement", False)) + after_invalid_element = list(obj.VisibilityList) + document.openTransaction("property-boollist-link-cancel") + transaction_before = list(obj.VisibilityList) + hide_result = int(obj.setElementVisible(first.Name, False)) + transaction_edited = list(obj.VisibilityList) + pending_after_edit = bool(document.HasPendingTransaction) + active_after_edit = active_transaction_snapshot() + document.abortTransaction() + transaction_after = list(obj.VisibilityList) + state_after_abort = [str(item) for item in obj.State] + status_after_abort = str(obj.getStatusString()) + recovery_recompute_result = bool(document.recompute()) + state_after_recovery = [str(item) for item in obj.State] + status_after_recovery = str(obj.getStatusString()) + return { + "objectTypeId": object_type_id, + "propertyTypeId": obj.getTypeIdOfProperty("VisibilityList"), + "initial": initial, + "status": [str(item) for item in obj.getPropertyStatus("VisibilityList")], + "editorMode": [str(item) for item in obj.getEditorMode("VisibilityList")], + "directWrite": {"requested": [False, True], "exception": direct_exception, "after": after_direct, "preserved": initial == after_direct}, + "invalidElement": {"name": "MissingElement", "result": invalid_element_result, "after": after_invalid_element, "preserved": initial == after_invalid_element}, + "transaction": { + "before": transaction_before, + "hideResult": hide_result, + "edited": transaction_edited, + "afterAbort": transaction_after, + "pendingAfterEdit": pending_after_edit, + "pendingAfterAbort": bool(document.HasPendingTransaction), + "activeAfterEdit": active_after_edit, + "activeAfterAbort": active_transaction_snapshot(), + "restored": transaction_before == transaction_after, + "stateAfterAbort": state_after_abort, + "statusAfterAbort": status_after_abort, + "recoveryRecomputeResult": recovery_recompute_result, + "stateAfterRecovery": state_after_recovery, + "statusAfterRecovery": status_after_recovery, + }, + "objectState": state_after_recovery, + "statusString": status_after_recovery, + "objectsBefore": initial_objects, + "objectsAfter": object_snapshot(document), + "objectsPreserved": initial_objects == object_snapshot(document), + } + finally: + App.closeDocument(document.Name) + + +writable = writable_failures() +links = [ + link_failure("App::Link", "LinkProbe"), + link_failure("App::LinkGroup", "LinkGroupProbe"), + link_failure("App::LinkGroupPython", "LinkGroupPythonProbe"), + link_failure("App::LinkPython", "LinkPythonProbe"), +] +report = { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-boollist-failure", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyBoolList", + "writable": writable, + "links": links, + "cancellationBoundary": { + "supported": False, + "classification": "synchronous-property-setter-and-link-extension", + "reason": "no-native-cancel-hook", + "replacement": "abort-active-document-transaction", + }, +} +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_BOOLLIST_FAILURE_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_BOOLLIST_FAILURE_RESULT=" + json.dumps({"status": report["status"], "failureCount": len(writable["failures"]), "linkCount": len(links)}, sort_keys=True)) diff --git a/scripts/freecad-property-boollist-mutation.py b/scripts/freecad-property-boollist-mutation.py new file mode 100644 index 0000000..3693676 --- /dev/null +++ b/scripts/freecad-property-boollist-mutation.py @@ -0,0 +1,169 @@ +import hashlib +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_BOOLLIST_MUTATION_OUTPUT", "") + + +def object_snapshot(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def shape_snapshot(obj): + if not hasattr(obj, "Shape"): + return {"applicable": False, "reason": "host-has-no-shape-property"} + shape = obj.Shape + if shape.isNull(): + return {"applicable": True, "isNull": True, "shapeType": "Null", "solids": 0, "faces": 0, "edges": 0, "vertices": 0} + brep = shape.exportBrepToString().encode("utf-8") + bounds = shape.BoundBox + return { + "applicable": True, + "isNull": False, + "valid": bool(shape.isValid()), + "shapeType": shape.ShapeType, + "solids": len(shape.Solids), + "faces": len(shape.Faces), + "edges": len(shape.Edges), + "vertices": len(shape.Vertexes), + "area": round(float(shape.Area), 9), + "volume": round(float(shape.Volume), 9), + "bounds": [round(float(value), 9) for value in (bounds.XMin, bounds.YMin, bounds.ZMin, bounds.XMax, bounds.YMax, bounds.ZMax)], + "brepSha256": hashlib.sha256(brep).hexdigest(), + } + + +def phase_snapshot(document, obj, property_name): + return { + "value": list(getattr(obj, property_name)), + "propertyTypeId": obj.getTypeIdOfProperty(property_name), + "propertyStatus": [str(item) for item in obj.getPropertyStatus(property_name)], + "editorMode": [str(item) for item in obj.getEditorMode(property_name)], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "mustExecute": bool(obj.MustExecute), + "shape": shape_snapshot(obj), + "objectSet": object_snapshot(document), + } + + +def direct_mutation(object_type_id, object_name, property_name, edited_value, setup_surface=False): + document = App.newDocument("PropertyBoolList" + object_name + "Mutation") + try: + obj = document.addObject(object_type_id, object_name) + if setup_surface: + import Part + points = [App.Vector(0, 0, 0), App.Vector(10, 0, 0), App.Vector(10, 10, 0), App.Vector(0, 10, 0)] + boundaries = [] + for index in range(4): + edge = document.addObject("Part::Feature", "Boundary" + str(index + 1)) + edge.Shape = Part.makeLine(points[index], points[(index + 1) % 4]) + boundaries.append((edge, ["Edge1"])) + obj.BoundaryList = boundaries + document.recompute() + before = phase_snapshot(document, obj, property_name) + setattr(obj, property_name, edited_value) + touched_after_edit = phase_snapshot(document, obj, property_name) + edit_recompute = bool(document.recompute()) + edited = phase_snapshot(document, obj, property_name) + setattr(obj, property_name, before["value"]) + touched_after_restore = phase_snapshot(document, obj, property_name) + restore_recompute = bool(document.recompute()) + restored = phase_snapshot(document, obj, property_name) + return { + "objectTypeId": object_type_id, + "objectName": object_name, + "propertyName": property_name, + "mode": "direct-native-property-setter", + "hostExecution": "intrinsic-test-exception" if object_type_id == "App::FeatureTestException" else "normal", + "before": before, + "touchedAfterEdit": touched_after_edit, + "editRecompute": edit_recompute, + "edited": edited, + "touchedAfterRestore": touched_after_restore, + "restoreRecompute": restore_recompute, + "restored": restored, + "valueRestored": before["value"] == restored["value"], + "shapeRestored": before["shape"] == restored["shape"], + "objectsRestored": before["objectSet"] == restored["objectSet"], + } + finally: + App.closeDocument(document.Name) + + +def link_mutation(object_type_id, object_name): + document = App.newDocument("PropertyBoolList" + object_name + "Mutation") + try: + first = document.addObject("Part::Feature", "TargetA") + second = document.addObject("Part::Feature", "TargetB") + group = document.addObject("App::DocumentObjectGroup", "TargetGroup") + group.addObjects([first, second]) + obj = document.addObject(object_type_id, object_name) + if "LinkedObject" in obj.PropertiesList: + obj.LinkedObject = group + setup_property = "LinkedObject" + else: + obj.ElementList = [first, second] + setup_property = "ElementList" + document.recompute() + before = phase_snapshot(document, obj, "VisibilityList") + hide_result = int(obj.setElementVisible(first.Name, False)) + touched_after_edit = phase_snapshot(document, obj, "VisibilityList") + edit_recompute = bool(document.recompute()) + edited = phase_snapshot(document, obj, "VisibilityList") + show_result = int(obj.setElementVisible(first.Name, True)) + touched_after_restore = phase_snapshot(document, obj, "VisibilityList") + restore_recompute = bool(document.recompute()) + restored = phase_snapshot(document, obj, "VisibilityList") + return { + "objectTypeId": object_type_id, + "objectName": object_name, + "propertyName": "VisibilityList", + "mode": "link-base-extension-element-visibility", + "setupProperty": setup_property, + "hideResult": hide_result, + "showResult": show_result, + "before": before, + "touchedAfterEdit": touched_after_edit, + "editRecompute": edit_recompute, + "edited": edited, + "touchedAfterRestore": touched_after_restore, + "restoreRecompute": restore_recompute, + "restored": restored, + "valueRestored": before["value"] == restored["value"], + "shapeRestored": before["shape"] == restored["shape"], + "objectsRestored": before["objectSet"] == restored["objectSet"], + } + finally: + App.closeDocument(document.Name) + + +cases = [ + direct_mutation("App::FeatureTest", "FeatureTestProbe", "BoolList", [True, False, True]), + direct_mutation("App::FeatureTestException", "FeatureTestExceptionProbe", "BoolList", [True, False, True]), + direct_mutation("Surface::GeomFillSurface", "GeomFillSurfaceProbe", "ReversedList", [True, False, False, False], True), + link_mutation("App::Link", "LinkProbe"), + link_mutation("App::LinkGroup", "LinkGroupProbe"), + link_mutation("App::LinkGroupPython", "LinkGroupPythonProbe"), + link_mutation("App::LinkPython", "LinkPythonProbe"), +] +report = { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-boollist-mutation", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyBoolList", + "caseCount": len(cases), + "cases": cases, +} +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_BOOLLIST_MUTATION_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_BOOLLIST_MUTATION_RESULT=" + json.dumps({"status": report["status"], "caseCount": report["caseCount"]}, sort_keys=True)) diff --git a/scripts/freecad-property-boollist-roundtrip.py b/scripts/freecad-property-boollist-roundtrip.py new file mode 100644 index 0000000..1fec1be --- /dev/null +++ b/scripts/freecad-property-boollist-roundtrip.py @@ -0,0 +1,80 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def object_snapshot(document): + obj = document.getObject("BoolListProbe") + return { + "objectSet": [{"name": item.Name, "typeId": item.TypeId} for item in document.Objects], + "object": { + "name": obj.Name, + "typeId": obj.TypeId, + "propertyTypeId": obj.getTypeIdOfProperty("BoolList"), + "value": [bool(value) for value in obj.BoolList], + "propertyStatus": [str(item) for item in obj.getPropertyStatus("BoolList")], + "editorMode": [str(item) for item in obj.getEditorMode("BoolList")], + "state": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "hasShapeProperty": "Shape" in obj.PropertiesList, + }, + } + + +def create_native(path): + document = App.newDocument("PropertyBoolListRoundtrip") + try: + obj = document.addObject("App::FeatureTest", "BoolListProbe") + obj.BoolList = [False] + document.recompute() + document.saveAs(path) + finally: + App.closeDocument(document.Name) + reopened = App.openDocument(path) + try: + reopened.recompute() + return object_snapshot(reopened) + finally: + App.closeDocument(reopened.Name) + + +def verify_native(path, resaved_path): + document = App.openDocument(path) + try: + document.recompute() + reopened = object_snapshot(document) + document.saveAs(resaved_path) + finally: + App.closeDocument(document.Name) + resaved_document = App.openDocument(resaved_path) + try: + resaved_document.recompute() + resaved = object_snapshot(resaved_document) + finally: + App.closeDocument(resaved_document.Name) + return {"reopened": reopened, "resaved": resaved} + + +mode = os.environ.get("FREECAD_PROPERTY_BOOLLIST_ROUNDTRIP_MODE", "") +path = os.environ.get("FREECAD_PROPERTY_BOOLLIST_ROUNDTRIP_PATH", "") +resaved_path = os.environ.get("FREECAD_PROPERTY_BOOLLIST_ROUNDTRIP_RESAVED_PATH", "") +if mode == "create": + result = create_native(path) +elif mode == "verify": + result = verify_native(path, resaved_path) +else: + raise RuntimeError("FREECAD_PROPERTY_BOOLLIST_ROUNDTRIP_MODE must be create or verify") + +print("FREECAD_PROPERTY_BOOLLIST_ROUNDTRIP_RESULT=" + json.dumps({ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-boollist-roundtrip", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "mode": mode, + "result": result, +}, sort_keys=True)) diff --git a/scripts/freecad-property-boollist-success.py b/scripts/freecad-property-boollist-success.py new file mode 100644 index 0000000..3544527 --- /dev/null +++ b/scripts/freecad-property-boollist-success.py @@ -0,0 +1,153 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_BOOLLIST_SUCCESS_OUTPUT", "") + + +def shape_snapshot(obj): + if not hasattr(obj, "Shape"): + return {"applicable": False, "reason": "host-has-no-shape-property"} + shape = obj.Shape + if shape.isNull(): + return {"applicable": True, "isNull": True, "shapeType": "Null", "solids": 0, "faces": 0, "edges": 0, "vertices": 0} + return { + "applicable": True, + "isNull": False, + "shapeType": shape.ShapeType, + "valid": bool(shape.isValid()), + "solids": len(shape.Solids), + "faces": len(shape.Faces), + "edges": len(shape.Edges), + "vertices": len(shape.Vertexes), + } + + +def property_snapshot(document, obj, property_name): + recompute_result = bool(document.recompute()) + return { + "value": list(getattr(obj, property_name)), + "propertyTypeId": obj.getTypeIdOfProperty(property_name), + "propertyStatus": [str(item) for item in obj.getPropertyStatus(property_name)], + "editorMode": [str(item) for item in obj.getEditorMode(property_name)], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "recomputeResult": recompute_result, + "shape": shape_snapshot(obj), + "objectSet": [{"name": candidate.Name, "typeId": candidate.TypeId} for candidate in document.Objects], + } + + +def writable_case(object_type_id, object_name, property_name, valid_surface=False): + document = App.newDocument("PropertyBoolList" + object_name) + try: + obj = document.addObject(object_type_id, object_name) + if valid_surface: + import Part + points = [App.Vector(0, 0, 0), App.Vector(10, 0, 0), App.Vector(10, 10, 0), App.Vector(0, 10, 0)] + boundaries = [] + for index in range(4): + edge = document.addObject("Part::Feature", "Boundary" + str(index + 1)) + edge.Shape = Part.makeLine(points[index], points[(index + 1) % 4]) + boundaries.append((edge, ["Edge1"])) + obj.BoundaryList = boundaries + default_value = list(getattr(obj, property_name)) + phases = {"default": property_snapshot(document, obj, property_name)} + values = ({ + "allFalse": [False, False, False, False], + "oneReversed": [True, False, False, False], + "alternating": [True, False, True, False], + "allReversed": [True, True, True, True], + "restored": default_value, + } if valid_surface else { + "empty": [], + "singleton": [True], + "mixed": [True, False, True, False], + "large": [index % 3 == 0 for index in range(257)], + "restored": default_value, + }) + for phase, value in values.items(): + setattr(obj, property_name, value) + phases[phase] = property_snapshot(document, obj, property_name) + return { + "objectTypeId": object_type_id, + "objectName": object_name, + "propertyName": property_name, + "mode": "direct-native-property-setter", + "propertyAssignmentsAccepted": True, + "hostExecution": "intrinsic-test-exception" if object_type_id == "App::FeatureTestException" else "normal", + "defaultValue": default_value, + "phases": phases, + } + finally: + App.closeDocument(document.Name) + + +def link_case(object_type_id, object_name): + document = App.newDocument("PropertyBoolList" + object_name) + try: + first = document.addObject("Part::Feature", "TargetA") + second = document.addObject("Part::Feature", "TargetB") + group = document.addObject("App::DocumentObjectGroup", "TargetGroup") + group.addObjects([first, second]) + obj = document.addObject(object_type_id, object_name) + if "LinkedObject" in obj.PropertiesList: + obj.LinkedObject = group + setup_property = "LinkedObject" + elif "Link" in obj.PropertiesList: + obj.Link = group + setup_property = "Link" + elif "ElementList" in obj.PropertiesList: + obj.ElementList = [first, second] + setup_property = "ElementList" + else: + raise RuntimeError(object_type_id + " has no native Link input property") + phases = {"linked": property_snapshot(document, obj, "VisibilityList")} + hide_result = int(obj.setElementVisible(first.Name, False)) + phases["hidden"] = property_snapshot(document, obj, "VisibilityList") + show_result = int(obj.setElementVisible(first.Name, True)) + phases["restored"] = property_snapshot(document, obj, "VisibilityList") + return { + "objectTypeId": object_type_id, + "objectName": object_name, + "propertyName": "VisibilityList", + "mode": "link-base-extension-element-visibility", + "propertyAssignmentsAccepted": True, + "hostExecution": "normal", + "setupProperty": setup_property, + "hideResult": hide_result, + "showResult": show_result, + "phases": phases, + } + finally: + App.closeDocument(document.Name) + + +cases = [ + writable_case("App::FeatureTest", "FeatureTestProbe", "BoolList"), + writable_case("App::FeatureTestException", "FeatureTestExceptionProbe", "BoolList"), + writable_case("Surface::GeomFillSurface", "GeomFillSurfaceProbe", "ReversedList", True), + link_case("App::Link", "LinkProbe"), + link_case("App::LinkGroup", "LinkGroupProbe"), + link_case("App::LinkGroupPython", "LinkGroupPythonProbe"), + link_case("App::LinkPython", "LinkPythonProbe"), +] +report = { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-boollist-success", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyBoolList", + "caseCount": len(cases), + "cases": cases, +} +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_BOOLLIST_SUCCESS_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_BOOLLIST_SUCCESS_RESULT=" + json.dumps({"status": report["status"], "caseCount": report["caseCount"]}, sort_keys=True)) diff --git a/scripts/freecad-property-color-failure.py b/scripts/freecad-property-color-failure.py new file mode 100644 index 0000000..3cc11b8 --- /dev/null +++ b/scripts/freecad-property-color-failure.py @@ -0,0 +1,201 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_COLOR_FAILURE_OUTPUT", "") + + +def color_value(obj): + return [round(float(channel), 9) for channel in obj.Colour] + + +def object_set(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def active_transaction_snapshot(): + active = App.getActiveTransaction() + if not active: + return {"name": "", "id": 0} + return {"name": str(active[0]), "id": int(active[1])} + + +def exception_snapshot(callback): + try: + callback() + except Exception as error: + return {"type": type(error).__name__, "message": str(error)} + return None + + +def state_snapshot(obj): + return {"state": [str(item) for item in obj.State], "statusString": str(obj.getStatusString())} + + +def run(): + document = App.newDocument("PropertyColorFailure") + try: + obj = document.addObject("App::FeatureTest", "ColorProbe") + document.recompute() + document.UndoMode = 1 + initial = color_value(obj) + initial_objects = object_set(document) + + coercions = [] + for case_id, requested in [ + ("float-out-of-range", (2.0, -1.0, 0.5, 1.5)), + ("integer-out-of-range", (-1, 256, 511, -255)), + ("boolean-tuple", (True, False, True, False)), + ("packed-max", 0xFFFFFFFF), + ("packed-wrap", 0x100000000), + ("packed-negative", -1), + ]: + before = color_value(obj) + before_objects = object_set(document) + exception = exception_snapshot(lambda value=requested: setattr(obj, "Colour", value)) + after = color_value(obj) + after_objects = object_set(document) + coercions.append({ + "id": case_id, + "requested": repr(requested), + "exception": exception, + "accepted": exception is None, + "before": before, + "after": after, + "valuePreserved": before == after, + "beforeObjects": before_objects, + "afterObjects": after_objects, + "objectsPreserved": before_objects == after_objects, + }) + if exception is None: + obj.Colour = tuple(initial) + + failures = [] + for case_id, requested in [ + ("none", None), + ("list", [0.1, 0.2, 0.3]), + ("short-tuple", (0.1, 0.2)), + ("long-tuple", (0.1, 0.2, 0.3, 0.4, 0.5)), + ("string-first", ("bad", 0.2, 0.3)), + ("mixed-after-float", (0.1, 2, 0.3)), + ("mixed-after-integer", (1, 0.2, 3)), + ("scalar-float", 0.5), + ]: + before = color_value(obj) + before_objects = object_set(document) + exception = exception_snapshot(lambda value=requested: setattr(obj, "Colour", value)) + after = color_value(obj) + after_objects = object_set(document) + failures.append({ + "id": case_id, + "requested": repr(requested), + "exception": exception, + "before": before, + "after": after, + "valuePreserved": before == after, + "beforeObjects": before_objects, + "afterObjects": after_objects, + "objectsPreserved": before_objects == after_objects, + "polluted": before_objects != after_objects, + }) + if exception is None: + obj.Colour = tuple(initial) + + disabled_before = color_value(obj) + disabled_objects_before = object_set(document) + obj.setEditorMode("Colour", ["ReadOnly"]) + editor_mode = [str(item) for item in obj.getEditorMode("Colour")] + editor_read_only_exception = exception_snapshot(lambda: setattr(obj, "Colour", (0.2, 0.3, 0.4, 0.5))) + editor_read_only_after = color_value(obj) + obj.Colour = tuple(initial) + obj.setPropertyStatus("Colour", "Immutable") + immutable_status = [str(item) for item in obj.getPropertyStatus("Colour")] + immutable_exception = exception_snapshot(lambda: setattr(obj, "Colour", (0.6, 0.7, 0.8, 0.9))) + immutable_after = color_value(obj) + obj.setPropertyStatus("Colour", "-Immutable") + obj.setEditorMode("Colour", 0) + disabled_objects_after = object_set(document) + disabled = { + "classification": "editor-readonly-python-mutable-until-immutable", + "before": disabled_before, + "editorMode": editor_mode, + "editorReadOnlyRequested": [0.2, 0.3, 0.4, 0.5], + "editorReadOnlyException": editor_read_only_exception, + "editorReadOnlyAfter": editor_read_only_after, + "pythonBypassesEditorReadOnly": editor_read_only_exception is None, + "immutableStatus": immutable_status, + "immutableRequested": [0.6, 0.7, 0.8, 0.9], + "immutableException": immutable_exception, + "immutableAfter": immutable_after, + "immutableValuePreserved": initial == immutable_after, + "restoredStatus": [str(item) for item in obj.getPropertyStatus("Colour")], + "restoredEditorMode": [str(item) for item in obj.getEditorMode("Colour")], + "objectsPreserved": disabled_objects_before == disabled_objects_after, + } + + document.recompute() + document.openTransaction("property-color-cancel") + transaction_before = color_value(obj) + transaction_objects_before = object_set(document) + obj.Colour = (0.75, 0.5, 0.25, 0.125) + transaction_edited = color_value(obj) + state_after_edit = state_snapshot(obj) + pending_after_edit = bool(document.HasPendingTransaction) + active_after_edit = active_transaction_snapshot() + document.abortTransaction() + transaction_after_abort = color_value(obj) + state_after_abort = state_snapshot(obj) + recovery_recompute_result = bool(document.recompute()) + transaction_after_recompute = color_value(obj) + state_after_recompute = state_snapshot(obj) + transaction_objects_after = object_set(document) + + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-color-failure", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyColor", + "object": {"name": obj.Name, "typeId": obj.TypeId}, + "property": {"name": "Colour", "typeId": obj.getTypeIdOfProperty("Colour")}, + "initial": initial, + "coercions": coercions, + "failures": failures, + "disabled": disabled, + "transaction": { + "before": transaction_before, + "edited": transaction_edited, + "afterAbort": transaction_after_abort, + "afterRecompute": transaction_after_recompute, + "stateAfterEdit": state_after_edit, + "stateAfterAbort": state_after_abort, + "stateAfterRecompute": state_after_recompute, + "objectsBefore": transaction_objects_before, + "objectsAfter": transaction_objects_after, + "undoMode": int(document.UndoMode), + "pendingAfterEdit": pending_after_edit, + "pendingAfterAbort": bool(document.HasPendingTransaction), + "activeAfterEdit": active_after_edit, + "activeAfterAbort": active_transaction_snapshot(), + "recoveryRecomputeResult": recovery_recompute_result, + "restored": transaction_before == transaction_after_abort == transaction_after_recompute, + "objectsRestored": transaction_objects_before == transaction_objects_after, + }, + "cancellationBoundary": {"supported": False, "classification": "synchronous-property-setter", "reason": "no-native-cancel-hook", "replacement": "abort-active-document-transaction"}, + "documentIntegrity": {"initialObjects": initial_objects, "finalObjects": object_set(document), "objectsPreserved": initial_objects == object_set(document)}, + } + finally: + App.closeDocument(document.Name) + + +report = run() +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_COLOR_FAILURE_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_COLOR_FAILURE_RESULT=" + json.dumps({"status": report["status"], "coercionCount": len(report["coercions"]), "failureCount": len(report["failures"])}, sort_keys=True)) diff --git a/scripts/freecad-property-color-mutation.py b/scripts/freecad-property-color-mutation.py new file mode 100644 index 0000000..55be169 --- /dev/null +++ b/scripts/freecad-property-color-mutation.py @@ -0,0 +1,112 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_COLOR_MUTATION_OUTPUT", "") +TARGET = (0.125, 0.375, 0.625, 0.875) +HOSTS = [ + ("App::FeatureTest", "FeatureTestColorMutation", "Colour"), + ("App::FeatureTestException", "FeatureTestExceptionColorMutation", "Colour"), + ("App::Part", "PartColorMutation", "Color"), + ("Assembly::AssemblyLink", "AssemblyLinkColorMutation", "Color"), + ("Assembly::AssemblyObject", "AssemblyObjectColorMutation", "Color"), + ("TechDraw::DrawViewAnnotation", "AnnotationColorMutation", "TextColor"), + ("TechDraw::DrawViewDraft", "DraftColorMutation", "Color"), + ("TechDraw::DrawViewSpreadsheet", "SpreadsheetColorMutation", "TextColor"), +] + + +def shape_snapshot(obj): + if not hasattr(obj, "Shape"): + return {"applicable": False, "reason": "host-has-no-shape-property"} + shape = obj.Shape + if shape.isNull(): + return {"applicable": True, "isNull": True, "shapeType": "Null", "solids": 0, "faces": 0, "edges": 0, "vertices": 0} + return { + "applicable": True, + "isNull": False, + "shapeType": shape.ShapeType, + "valid": bool(shape.isValid()), + "solids": len(shape.Solids), + "faces": len(shape.Faces), + "edges": len(shape.Edges), + "vertices": len(shape.Vertexes), + } + + +def snapshot(document, obj, property_name): + return { + "value": [round(float(channel), 9) for channel in getattr(obj, property_name)], + "propertyTypeId": obj.getTypeIdOfProperty(property_name), + "propertyStatus": [str(item) for item in obj.getPropertyStatus(property_name)], + "editorMode": [str(item) for item in obj.getEditorMode(property_name)], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "shape": shape_snapshot(obj), + "objectSet": [{"name": candidate.Name, "typeId": candidate.TypeId} for candidate in document.Objects], + } + + +def run_case(object_type_id, object_name, property_name): + document = App.newDocument("PropertyColor" + object_name) + try: + obj = document.addObject(object_type_id, object_name) + setup = {"kind": "none"} + if object_type_id == "TechDraw::DrawViewSpreadsheet": + source = document.addObject("Spreadsheet::Sheet", "MutationSource") + source.set("A1", "Mutation") + source.set("B2", "1") + obj.Source = source + setup = {"kind": "spreadsheet-source", "objectName": source.Name, "objectTypeId": source.TypeId} + document.recompute() + before = snapshot(document, obj, property_name) + original = list(before["value"]) + setattr(obj, property_name, TARGET) + touched_after_edit = snapshot(document, obj, property_name) + edit_recompute_result = bool(document.recompute()) + edited = snapshot(document, obj, property_name) + setattr(obj, property_name, tuple(original)) + touched_after_restore = snapshot(document, obj, property_name) + restore_recompute_result = bool(document.recompute()) + restored = snapshot(document, obj, property_name) + return { + "objectTypeId": object_type_id, + "objectName": object_name, + "propertyName": property_name, + "hostExecution": "intrinsic-test-exception" if object_type_id == "App::FeatureTestException" else "normal", + "setup": setup, + "target": list(TARGET), + "before": before, + "touchedAfterEdit": touched_after_edit, + "edited": edited, + "touchedAfterRestore": touched_after_restore, + "restored": restored, + "editRecomputeResult": edit_recompute_result, + "restoreRecomputeResult": restore_recompute_result, + "mutationDetected": before["value"] != edited["value"], + "restoredExactly": before["value"] == restored["value"] and before["objectSet"] == restored["objectSet"] and before["shape"] == restored["shape"], + } + finally: + App.closeDocument(document.Name) + + +cases = [run_case(*host) for host in HOSTS] +report = { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-color-mutation", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyColor", + "caseCount": len(cases), + "cases": cases, +} +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_COLOR_MUTATION_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_COLOR_MUTATION_RESULT=" + json.dumps({"status": report["status"], "caseCount": report["caseCount"], "restored": sum(1 for case in cases if case["restoredExactly"])}, sort_keys=True)) diff --git a/scripts/freecad-property-color-roundtrip.py b/scripts/freecad-property-color-roundtrip.py new file mode 100644 index 0000000..895541a --- /dev/null +++ b/scripts/freecad-property-color-roundtrip.py @@ -0,0 +1,80 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def object_snapshot(document): + obj = document.getObject("ColorProbe") + return { + "objectSet": [{"name": item.Name, "typeId": item.TypeId} for item in document.Objects], + "object": { + "name": obj.Name, + "typeId": obj.TypeId, + "propertyTypeId": obj.getTypeIdOfProperty("Colour"), + "value": [round(float(channel), 9) for channel in obj.Colour], + "propertyStatus": [str(item) for item in obj.getPropertyStatus("Colour")], + "editorMode": [str(item) for item in obj.getEditorMode("Colour")], + "state": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "hasShapeProperty": "Shape" in obj.PropertiesList, + }, + } + + +def create_native(path): + document = App.newDocument("PropertyColorRoundtrip") + try: + obj = document.addObject("App::FeatureTest", "ColorProbe") + obj.Colour = 0x11223344 + document.recompute() + document.saveAs(path) + finally: + App.closeDocument(document.Name) + reopened = App.openDocument(path) + try: + reopened.recompute() + return object_snapshot(reopened) + finally: + App.closeDocument(reopened.Name) + + +def verify_native(path, resaved_path): + document = App.openDocument(path) + try: + document.recompute() + reopened = object_snapshot(document) + document.saveAs(resaved_path) + finally: + App.closeDocument(document.Name) + resaved_document = App.openDocument(resaved_path) + try: + resaved_document.recompute() + resaved = object_snapshot(resaved_document) + finally: + App.closeDocument(resaved_document.Name) + return {"reopened": reopened, "resaved": resaved} + + +mode = os.environ.get("FREECAD_PROPERTY_COLOR_ROUNDTRIP_MODE", "") +path = os.environ.get("FREECAD_PROPERTY_COLOR_ROUNDTRIP_PATH", "") +resaved_path = os.environ.get("FREECAD_PROPERTY_COLOR_ROUNDTRIP_RESAVED_PATH", "") +if mode == "create": + result = create_native(path) +elif mode == "verify": + result = verify_native(path, resaved_path) +else: + raise RuntimeError("FREECAD_PROPERTY_COLOR_ROUNDTRIP_MODE must be create or verify") + +print("FREECAD_PROPERTY_COLOR_ROUNDTRIP_RESULT=" + json.dumps({ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-color-roundtrip", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "mode": mode, + "result": result, +}, sort_keys=True)) diff --git a/scripts/freecad-property-color-success.py b/scripts/freecad-property-color-success.py new file mode 100644 index 0000000..6c2c275 --- /dev/null +++ b/scripts/freecad-property-color-success.py @@ -0,0 +1,118 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_COLOR_SUCCESS_OUTPUT", "") +HOSTS = [ + ("App::FeatureTest", "FeatureTestColorProbe", "Colour"), + ("App::FeatureTestException", "FeatureTestExceptionColorProbe", "Colour"), + ("App::Part", "PartColorProbe", "Color"), + ("Assembly::AssemblyLink", "AssemblyLinkColorProbe", "Color"), + ("Assembly::AssemblyObject", "AssemblyObjectColorProbe", "Color"), + ("TechDraw::DrawViewAnnotation", "AnnotationColorProbe", "TextColor"), + ("TechDraw::DrawViewDraft", "DraftColorProbe", "Color"), + ("TechDraw::DrawViewSpreadsheet", "SpreadsheetColorProbe", "TextColor"), +] +ASSIGNMENTS = [ + ("floatRgb", (0.25, 0.5, 0.75)), + ("floatRgba", (0.1, 0.2, 0.3, 0.4)), + ("byteRgb", (1, 127, 255)), + ("byteRgba", (255, 128, 0, 64)), + ("packedRgba", 0x11223344), + ("transparentBoundary", (0.0, 0.0, 0.0, 0.0)), +] + + +def color_value(obj, property_name): + return [round(float(channel), 9) for channel in getattr(obj, property_name)] + + +def shape_snapshot(obj): + if not hasattr(obj, "Shape"): + return {"applicable": False, "reason": "host-has-no-shape-property"} + shape = obj.Shape + if shape.isNull(): + return {"applicable": True, "isNull": True, "shapeType": "Null", "solids": 0, "faces": 0, "edges": 0, "vertices": 0} + return { + "applicable": True, + "isNull": False, + "shapeType": shape.ShapeType, + "valid": bool(shape.isValid()), + "solids": len(shape.Solids), + "faces": len(shape.Faces), + "edges": len(shape.Edges), + "vertices": len(shape.Vertexes), + } + + +def property_snapshot(document, obj, property_name): + recompute_result = bool(document.recompute()) + return { + "value": color_value(obj, property_name), + "propertyTypeId": obj.getTypeIdOfProperty(property_name), + "propertyStatus": [str(item) for item in obj.getPropertyStatus(property_name)], + "editorMode": [str(item) for item in obj.getEditorMode(property_name)], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "recomputeResult": recompute_result, + "shape": shape_snapshot(obj), + "objectSet": [{"name": candidate.Name, "typeId": candidate.TypeId} for candidate in document.Objects], + } + + +def run_case(object_type_id, object_name, property_name): + document = App.newDocument("PropertyColor" + object_name) + try: + obj = document.addObject(object_type_id, object_name) + setup = {"kind": "none"} + if object_type_id == "TechDraw::DrawViewSpreadsheet": + source = document.addObject("Spreadsheet::Sheet", "ColorSource") + source.set("A1", "Color probe") + source.set("B2", "1") + obj.Source = source + setup = {"kind": "spreadsheet-source", "objectName": source.Name, "objectTypeId": source.TypeId} + default_value = color_value(obj, property_name) + phases = {"default": property_snapshot(document, obj, property_name)} + requested = {} + for phase, value in ASSIGNMENTS: + requested[phase] = list(value) if isinstance(value, tuple) else value + setattr(obj, property_name, value) + phases[phase] = property_snapshot(document, obj, property_name) + setattr(obj, property_name, tuple(default_value)) + phases["restored"] = property_snapshot(document, obj, property_name) + return { + "objectTypeId": object_type_id, + "objectName": object_name, + "propertyName": property_name, + "mode": "direct-native-property-setter", + "propertyAssignmentsAccepted": True, + "hostExecution": "intrinsic-test-exception" if object_type_id == "App::FeatureTestException" else "normal", + "setup": setup, + "defaultValue": default_value, + "requested": requested, + "phases": phases, + } + finally: + App.closeDocument(document.Name) + + +cases = [run_case(*host) for host in HOSTS] +report = { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-color-success", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyColor", + "caseCount": len(cases), + "cases": cases, +} +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_COLOR_SUCCESS_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_COLOR_SUCCESS_RESULT=" + json.dumps({"status": report["status"], "caseCount": report["caseCount"]}, sort_keys=True)) diff --git a/scripts/freecad-property-colorlist-failure.py b/scripts/freecad-property-colorlist-failure.py new file mode 100644 index 0000000..0122fab --- /dev/null +++ b/scripts/freecad-property-colorlist-failure.py @@ -0,0 +1,208 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_COLORLIST_FAILURE_OUTPUT", "") + + +def color_list_value(obj): + return [[round(float(channel), 9) for channel in color] for color in obj.ColourList] + + +def object_set(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def active_transaction_snapshot(): + active = App.getActiveTransaction() + if not active: + return {"name": "", "id": 0} + return {"name": str(active[0]), "id": int(active[1])} + + +def exception_snapshot(callback): + try: + callback() + except Exception as error: + return {"type": type(error).__name__, "message": str(error)} + return None + + +def state_snapshot(obj): + return {"state": [str(item) for item in obj.State], "statusString": str(obj.getStatusString())} + + +def run(): + document = App.newDocument("PropertyColorListFailure") + try: + obj = document.addObject("App::FeatureTest", "ColorListProbe") + document.recompute() + document.UndoMode = 1 + baseline_request = [0x11223344, 0xFFFFFFFF] + obj.ColourList = baseline_request + document.recompute() + initial = color_list_value(obj) + initial_objects = object_set(document) + + coercions = [] + for case_id, requested in [ + ("boolean-scalar", True), + ("bytes-sequence", bytes([1, 255])), + ("bare-float-tuple", (0.1, 0.2, 0.3, 0.4)), + ("bare-integer-tuple", (255, 128, 0, 64)), + ("tuple-packed-sequence", (0x11223344, 0xFFFFFFFF)), + ("empty-dictionary", {}), + ]: + before = color_list_value(obj) + before_objects = object_set(document) + exception = exception_snapshot(lambda value=requested: setattr(obj, "ColourList", value)) + after = color_list_value(obj) + after_objects = object_set(document) + coercions.append({ + "id": case_id, + "requested": repr(requested), + "exception": exception, + "accepted": exception is None, + "before": before, + "after": after, + "valuePreserved": before == after, + "beforeObjects": before_objects, + "afterObjects": after_objects, + "objectsPreserved": before_objects == after_objects, + }) + obj.ColourList = baseline_request + + failures = [] + for case_id, requested in [ + ("none", None), + ("bare-float-list", [0.1, 0.2, 0.3, 0.4]), + ("bare-mixed-tuple", (0.1, 2, 0.3)), + ("nested-short-tuple", [(0.1, 0.2)]), + ("mixed-valid-none", [(0.1, 0.2, 0.3, 0.4), None]), + ("scalar-float", 0.5), + ("string-sequence", "rgb"), + ("nested-list", [[0.1, 0.2, 0.3, 0.4]]), + ("dictionary-string-key", {"0": 0x11223344}), + ("dictionary-high-index", {3: 0x11223344}), + ("dictionary-negative-index", {-2: 0x11223344}), + ("dictionary-partial-invalid", {0: 0x01020304, 1: None}), + ]: + obj.ColourList = baseline_request + before = color_list_value(obj) + before_objects = object_set(document) + exception = exception_snapshot(lambda value=requested: setattr(obj, "ColourList", value)) + after = color_list_value(obj) + after_objects = object_set(document) + failures.append({ + "id": case_id, + "requested": repr(requested), + "exception": exception, + "before": before, + "after": after, + "valuePreserved": before == after, + "beforeObjects": before_objects, + "afterObjects": after_objects, + "objectsPreserved": before_objects == after_objects, + "polluted": before_objects != after_objects, + }) + + obj.ColourList = baseline_request + disabled_before = color_list_value(obj) + disabled_objects_before = object_set(document) + obj.setEditorMode("ColourList", ["ReadOnly"]) + editor_mode = [str(item) for item in obj.getEditorMode("ColourList")] + editor_requested = [(0.2, 0.3, 0.4, 0.5)] + editor_read_only_exception = exception_snapshot(lambda: setattr(obj, "ColourList", editor_requested)) + editor_read_only_after = color_list_value(obj) + obj.ColourList = baseline_request + obj.setPropertyStatus("ColourList", "Immutable") + immutable_status = [str(item) for item in obj.getPropertyStatus("ColourList")] + immutable_exception = exception_snapshot(lambda: setattr(obj, "ColourList", [(0.6, 0.7, 0.8, 0.9)])) + immutable_after = color_list_value(obj) + obj.setPropertyStatus("ColourList", "-Immutable") + obj.setEditorMode("ColourList", 0) + disabled_objects_after = object_set(document) + disabled = { + "classification": "editor-readonly-python-mutable-until-immutable", + "before": disabled_before, + "editorMode": editor_mode, + "editorReadOnlyRequested": [list(color) for color in editor_requested], + "editorReadOnlyException": editor_read_only_exception, + "editorReadOnlyAfter": editor_read_only_after, + "pythonBypassesEditorReadOnly": editor_read_only_exception is None, + "immutableStatus": immutable_status, + "immutableRequested": [[0.6, 0.7, 0.8, 0.9]], + "immutableException": immutable_exception, + "immutableAfter": immutable_after, + "immutableValuePreserved": initial == immutable_after, + "restoredStatus": [str(item) for item in obj.getPropertyStatus("ColourList")], + "restoredEditorMode": [str(item) for item in obj.getEditorMode("ColourList")], + "objectsPreserved": disabled_objects_before == disabled_objects_after, + } + + document.recompute() + document.openTransaction("property-colorlist-cancel") + transaction_before = color_list_value(obj) + transaction_objects_before = object_set(document) + obj.ColourList = [(0.75, 0.5, 0.25, 0.125), 0x11223344, (0, 255, 0, 128)] + transaction_edited = color_list_value(obj) + state_after_edit = state_snapshot(obj) + pending_after_edit = bool(document.HasPendingTransaction) + active_after_edit = active_transaction_snapshot() + document.abortTransaction() + transaction_after_abort = color_list_value(obj) + state_after_abort = state_snapshot(obj) + recovery_recompute_result = bool(document.recompute()) + transaction_after_recompute = color_list_value(obj) + state_after_recompute = state_snapshot(obj) + transaction_objects_after = object_set(document) + + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-colorlist-failure", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyColorList", + "object": {"name": obj.Name, "typeId": obj.TypeId}, + "property": {"name": "ColourList", "typeId": obj.getTypeIdOfProperty("ColourList")}, + "initial": initial, + "coercions": coercions, + "failures": failures, + "disabled": disabled, + "transaction": { + "before": transaction_before, + "edited": transaction_edited, + "afterAbort": transaction_after_abort, + "afterRecompute": transaction_after_recompute, + "stateAfterEdit": state_after_edit, + "stateAfterAbort": state_after_abort, + "stateAfterRecompute": state_after_recompute, + "objectsBefore": transaction_objects_before, + "objectsAfter": transaction_objects_after, + "undoMode": int(document.UndoMode), + "pendingAfterEdit": pending_after_edit, + "pendingAfterAbort": bool(document.HasPendingTransaction), + "activeAfterEdit": active_after_edit, + "activeAfterAbort": active_transaction_snapshot(), + "recoveryRecomputeResult": recovery_recompute_result, + "restored": transaction_before == transaction_after_abort == transaction_after_recompute, + "objectsRestored": transaction_objects_before == transaction_objects_after, + }, + "cancellationBoundary": {"supported": False, "classification": "synchronous-property-setter", "reason": "no-native-cancel-hook", "replacement": "abort-active-document-transaction"}, + "documentIntegrity": {"initialObjects": initial_objects, "finalObjects": object_set(document), "objectsPreserved": initial_objects == object_set(document)}, + } + finally: + App.closeDocument(document.Name) + + +report = run() +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_COLORLIST_FAILURE_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_COLORLIST_FAILURE_RESULT=" + json.dumps({"status": report["status"], "coercionCount": len(report["coercions"]), "failureCount": len(report["failures"])}, sort_keys=True)) diff --git a/scripts/freecad-property-colorlist-mutation.py b/scripts/freecad-property-colorlist-mutation.py new file mode 100644 index 0000000..c70132a --- /dev/null +++ b/scripts/freecad-property-colorlist-mutation.py @@ -0,0 +1,84 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_COLORLIST_MUTATION_OUTPUT", "") +TARGET = [(0.125, 0.375, 0.625, 0.875), 0x11223344, (255, 0, 128, 64), (0.0, 0.0, 0.0, 0.0)] +HOSTS = [ + ("App::FeatureTest", "FeatureTestColorListMutation"), + ("App::FeatureTestException", "FeatureTestExceptionColorListMutation"), +] + + +def color_list_value(obj): + return [[round(float(channel), 9) for channel in color] for color in obj.ColourList] + + +def snapshot(document, obj): + return { + "value": color_list_value(obj), + "propertyTypeId": obj.getTypeIdOfProperty("ColourList"), + "propertyStatus": [str(item) for item in obj.getPropertyStatus("ColourList")], + "editorMode": [str(item) for item in obj.getEditorMode("ColourList")], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "shape": {"applicable": False, "reason": "host-has-no-shape-property"} if "Shape" not in obj.PropertiesList else {"applicable": True}, + "objectSet": [{"name": candidate.Name, "typeId": candidate.TypeId} for candidate in document.Objects], + } + + +def run_case(object_type_id, object_name): + document = App.newDocument("PropertyColorList" + object_name) + try: + obj = document.addObject(object_type_id, object_name) + document.recompute() + before = snapshot(document, obj) + original = [tuple(color) for color in before["value"]] + obj.ColourList = TARGET + touched_after_edit = snapshot(document, obj) + edit_recompute_result = bool(document.recompute()) + edited = snapshot(document, obj) + obj.ColourList = original + touched_after_restore = snapshot(document, obj) + restore_recompute_result = bool(document.recompute()) + restored = snapshot(document, obj) + return { + "objectTypeId": object_type_id, + "objectName": object_name, + "propertyName": "ColourList", + "hostExecution": "intrinsic-test-exception" if object_type_id == "App::FeatureTestException" else "normal", + "target": [list(value) if isinstance(value, tuple) else value for value in TARGET], + "before": before, + "touchedAfterEdit": touched_after_edit, + "edited": edited, + "touchedAfterRestore": touched_after_restore, + "restored": restored, + "editRecomputeResult": edit_recompute_result, + "restoreRecomputeResult": restore_recompute_result, + "mutationDetected": before["value"] != edited["value"], + "restoredExactly": before["value"] == restored["value"] and before["objectSet"] == restored["objectSet"] and before["shape"] == restored["shape"], + } + finally: + App.closeDocument(document.Name) + + +cases = [run_case(*host) for host in HOSTS] +report = { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-colorlist-mutation", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyColorList", + "caseCount": len(cases), + "cases": cases, +} +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_COLORLIST_MUTATION_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_COLORLIST_MUTATION_RESULT=" + json.dumps({"status": report["status"], "caseCount": report["caseCount"], "restored": sum(1 for case in cases if case["restoredExactly"])}, sort_keys=True)) diff --git a/scripts/freecad-property-colorlist-roundtrip.py b/scripts/freecad-property-colorlist-roundtrip.py new file mode 100644 index 0000000..2353986 --- /dev/null +++ b/scripts/freecad-property-colorlist-roundtrip.py @@ -0,0 +1,83 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def object_snapshot(document): + obj = document.getObject("ColorListProbe") + return { + "objectSet": [{"name": item.Name, "typeId": item.TypeId} for item in document.Objects], + "object": { + "name": obj.Name, + "typeId": obj.TypeId, + "propertyTypeId": obj.getTypeIdOfProperty("ColourList"), + "value": [ + [round(float(channel), 9) for channel in color] + for color in obj.ColourList + ], + "propertyStatus": [str(item) for item in obj.getPropertyStatus("ColourList")], + "editorMode": [str(item) for item in obj.getEditorMode("ColourList")], + "state": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "hasShapeProperty": "Shape" in obj.PropertiesList, + }, + } + + +def create_native(path): + document = App.newDocument("PropertyColorListRoundtrip") + try: + obj = document.addObject("App::FeatureTest", "ColorListProbe") + obj.ColourList = [0x11223344] + document.recompute() + document.saveAs(path) + finally: + App.closeDocument(document.Name) + reopened = App.openDocument(path) + try: + reopened.recompute() + return object_snapshot(reopened) + finally: + App.closeDocument(reopened.Name) + + +def verify_native(path, resaved_path): + document = App.openDocument(path) + try: + document.recompute() + reopened = object_snapshot(document) + document.saveAs(resaved_path) + finally: + App.closeDocument(document.Name) + resaved_document = App.openDocument(resaved_path) + try: + resaved_document.recompute() + resaved = object_snapshot(resaved_document) + finally: + App.closeDocument(resaved_document.Name) + return {"reopened": reopened, "resaved": resaved} + + +mode = os.environ.get("FREECAD_PROPERTY_COLORLIST_ROUNDTRIP_MODE", "") +path = os.environ.get("FREECAD_PROPERTY_COLORLIST_ROUNDTRIP_PATH", "") +resaved_path = os.environ.get("FREECAD_PROPERTY_COLORLIST_ROUNDTRIP_RESAVED_PATH", "") +if mode == "create": + result = create_native(path) +elif mode == "verify": + result = verify_native(path, resaved_path) +else: + raise RuntimeError("FREECAD_PROPERTY_COLORLIST_ROUNDTRIP_MODE must be create or verify") + +print("FREECAD_PROPERTY_COLORLIST_ROUNDTRIP_RESULT=" + json.dumps({ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-colorlist-roundtrip", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "mode": mode, + "result": result, +}, sort_keys=True)) diff --git a/scripts/freecad-property-colorlist-success.py b/scripts/freecad-property-colorlist-success.py new file mode 100644 index 0000000..b8be615 --- /dev/null +++ b/scripts/freecad-property-colorlist-success.py @@ -0,0 +1,88 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_COLORLIST_SUCCESS_OUTPUT", "") +HOSTS = [ + ("App::FeatureTest", "FeatureTestColorListProbe"), + ("App::FeatureTestException", "FeatureTestExceptionColorListProbe"), +] + + +def color_list_value(obj): + return [[round(float(channel), 9) for channel in color] for color in obj.ColourList] + + +def snapshot(document, obj): + recompute_result = bool(document.recompute()) + return { + "value": color_list_value(obj), + "propertyTypeId": obj.getTypeIdOfProperty("ColourList"), + "propertyStatus": [str(item) for item in obj.getPropertyStatus("ColourList")], + "editorMode": [str(item) for item in obj.getEditorMode("ColourList")], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "recomputeResult": recompute_result, + "shape": {"applicable": False, "reason": "host-has-no-shape-property"} if "Shape" not in obj.PropertiesList else {"applicable": True}, + "objectSet": [{"name": candidate.Name, "typeId": candidate.TypeId} for candidate in document.Objects], + } + + +def run_case(object_type_id, object_name): + document = App.newDocument("PropertyColorList" + object_name) + try: + obj = document.addObject(object_type_id, object_name) + default_value = color_list_value(obj) + phases = {"default": snapshot(document, obj)} + + obj.ColourList = [] + phases["empty"] = snapshot(document, obj) + obj.ColourList = [(0.25, 0.5, 0.75)] + phases["singletonFloat"] = snapshot(document, obj) + obj.ColourList = [(0.1, 0.2, 0.3, 0.4), (255, 128, 0, 64), 0x11223344] + phases["mixedElements"] = snapshot(document, obj) + obj.ColourList = 0x11223344 + phases["singlePacked"] = snapshot(document, obj) + obj.ColourList = (color for color in [(0.0, 0.25, 0.5, 0.75), (1.0, 0.75, 0.5, 0.25)]) + phases["iterable"] = snapshot(document, obj) + obj.ColourList = [(0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0, 1.0)] + obj.ColourList = {1: 0x11223344, -1: (0, 255, 0, 128)} + phases["indexedDictionary"] = snapshot(document, obj) + obj.ColourList = [0x01020304] * 257 + phases["largeList"] = snapshot(document, obj) + obj.ColourList = [tuple(color) for color in default_value] + phases["restored"] = snapshot(document, obj) + return { + "objectTypeId": object_type_id, + "objectName": object_name, + "propertyName": "ColourList", + "mode": "native-property-list-setter", + "propertyAssignmentsAccepted": True, + "hostExecution": "intrinsic-test-exception" if object_type_id == "App::FeatureTestException" else "normal", + "defaultValue": default_value, + "phases": phases, + } + finally: + App.closeDocument(document.Name) + + +cases = [run_case(*host) for host in HOSTS] +report = { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-colorlist-success", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyColorList", + "caseCount": len(cases), + "cases": cases, +} +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_COLORLIST_SUCCESS_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_COLORLIST_SUCCESS_RESULT=" + json.dumps({"status": report["status"], "caseCount": report["caseCount"]}, sort_keys=True)) diff --git a/scripts/freecad-property-direction-failure.py b/scripts/freecad-property-direction-failure.py new file mode 100644 index 0000000..16bfcd0 --- /dev/null +++ b/scripts/freecad-property-direction-failure.py @@ -0,0 +1,454 @@ +import hashlib +import json +import math +import os + +import FreeCAD as App +import Part + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_DIRECTION_FAILURE_OUTPUT", "") +PROBE_MODE = os.environ.get("FREECAD_PROPERTY_DIRECTION_FAILURE_MODE", "main") + + +def component_value(value): + number = float(value) + if math.isnan(number): + return "NaN" + if math.isinf(number): + return "Infinity" if number > 0 else "-Infinity" + return number + + +def vector_value(obj, property_name): + value = getattr(obj, property_name) + return [component_value(value.x), component_value(value.y), component_value(value.z)] + + +def object_set(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def exception_snapshot(callback): + try: + callback() + except Exception as error: + return {"type": type(error).__name__, "message": str(error)} + return None + + +def active_transaction_snapshot(): + active = App.getActiveTransaction() + if not active: + return {"name": "", "id": 0} + return {"name": str(active[0]), "id": int(active[1])} + + +def state_snapshot(obj): + return { + "state": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "mustExecute": bool(obj.MustExecute), + } + + +def shape_snapshot(obj): + shape = obj.Shape + if shape.isNull(): + return { + "isNull": True, + "shapeType": "Null", + "valid": False, + "solids": 0, + "faces": 0, + "edges": 0, + "vertices": 0, + } + return { + "isNull": False, + "shapeType": shape.ShapeType, + "valid": bool(shape.isValid()), + "solids": len(shape.Solids), + "faces": len(shape.Faces), + "edges": len(shape.Edges), + "vertices": len(shape.Vertexes), + "brepSha256": hashlib.sha256(shape.exportBrepToString().encode("utf-8")).hexdigest(), + } + + +def setup_mirroring(document): + source = document.addObject("Part::Box", "MirrorSource") + source.Length = 2 + source.Width = 3 + source.Height = 4 + host = document.addObject("Part::Mirroring", "DirectionMirror") + host.Source = source + host.Base = App.Vector(0, 0, 0) + return host, "Normal" + + +def setup_projection(document): + support = document.addObject("Part::Feature", "ProjectionSupport") + support.Shape = Part.makePlane(40, 40, App.Vector(-20, -20, 0)) + wire = document.addObject("Part::Feature", "ProjectionWire") + wire.Shape = Part.makePolygon([ + App.Vector(-4, -3, -5), + App.Vector(4, -3, -5), + App.Vector(4, 3, -5), + App.Vector(-4, 3, -5), + App.Vector(-4, -3, -5), + ]) + host = document.addObject("Part::ProjectOnSurface", "DirectionProjection") + host.SupportFace = (support, ["Face1"]) + host.Projection = [(wire, ["Wire1"])] + host.Mode = "Edges" + return host, "Direction" + + +def run_setter_boundaries(): + document = App.newDocument("PropertyDirectionSetterFailure") + try: + obj, property_name = setup_mirroring(document) + document.recompute() + baseline = vector_value(obj, property_name) + initial_objects = object_set(document) + accepted = [] + for case_id, requested in [ + ("mixed-numeric-tuple", (1, 0.5, 2)), + ("boolean-tuple", (True, False, True)), + ]: + before = vector_value(obj, property_name) + before_objects = object_set(document) + exception = exception_snapshot(lambda value=requested: setattr(obj, property_name, value)) + after = vector_value(obj, property_name) + after_objects = object_set(document) + accepted.append({ + "id": case_id, + "requested": repr(requested), + "exception": exception, + "accepted": exception is None, + "before": before, + "after": after, + "objectsPreserved": before_objects == after_objects, + }) + setattr(obj, property_name, tuple(baseline)) + + failures = [] + for case_id, requested in [ + ("none", None), + ("list", [0.0, 0.0, 1.0]), + ("short-tuple", (0.0, 1.0)), + ("long-tuple", (0.0, 0.0, 1.0, 2.0)), + ("string-component", (0.0, "bad", 1.0)), + ("scalar-float", 1.0), + ("scalar-integer", 1), + ]: + before = vector_value(obj, property_name) + before_objects = object_set(document) + exception = exception_snapshot(lambda value=requested: setattr(obj, property_name, value)) + after = vector_value(obj, property_name) + after_objects = object_set(document) + failures.append({ + "id": case_id, + "requested": repr(requested), + "exception": exception, + "before": before, + "after": after, + "valuePreserved": before == after, + "beforeObjects": before_objects, + "afterObjects": after_objects, + "objectsPreserved": before_objects == after_objects, + "polluted": before_objects != after_objects, + }) + if exception is None: + setattr(obj, property_name, tuple(baseline)) + return { + "object": {"name": obj.Name, "typeId": obj.TypeId}, + "property": {"name": property_name, "typeId": obj.getTypeIdOfProperty(property_name)}, + "baseline": baseline, + "acceptedCoercions": accepted, + "failures": failures, + "documentIntegrity": { + "initialObjects": initial_objects, + "finalObjects": object_set(document), + "objectsPreserved": initial_objects == object_set(document), + }, + } + finally: + App.closeDocument(document.Name) + + +def run_consumer_direction(case_id, object_type_id, setup, requested): + document = App.newDocument("PropertyDirectionConsumer" + case_id) + try: + obj, property_name = setup(document) + initial_recompute = bool(document.recompute()) + before = { + "value": vector_value(obj, property_name), + "state": state_snapshot(obj), + "shape": shape_snapshot(obj), + "objects": object_set(document), + } + setter_exception = exception_snapshot(lambda: setattr(obj, property_name, requested)) + after_set = { + "value": vector_value(obj, property_name), + "state": state_snapshot(obj), + "shape": shape_snapshot(obj), + } + recompute_exception = None + recompute_result = None + try: + recompute_result = bool(document.recompute()) + except Exception as error: + recompute_exception = {"type": type(error).__name__, "message": str(error)} + after_recompute = { + "value": vector_value(obj, property_name), + "state": state_snapshot(obj), + "shape": shape_snapshot(obj), + "objects": object_set(document), + } + return { + "id": case_id, + "objectTypeId": object_type_id, + "propertyName": property_name, + "requested": [component_value(value) for value in requested], + "initialRecomputeResult": initial_recompute, + "setterException": setter_exception, + "recomputeException": recompute_exception, + "recomputeResult": recompute_result, + "before": before, + "afterSet": after_set, + "afterRecompute": after_recompute, + "objectsPreserved": before["objects"] == after_recompute["objects"], + } + finally: + App.closeDocument(document.Name) + + +def run_missing_dependency(case_id, object_type_id, setup, remove_dependency): + document = App.newDocument("PropertyDirectionDependency" + case_id) + try: + obj, property_name = setup(document) + document.recompute() + before = { + "value": vector_value(obj, property_name), + "state": state_snapshot(obj), + "shape": shape_snapshot(obj), + "objects": object_set(document), + } + removed = remove_dependency(obj) + recompute_exception = None + recompute_result = None + try: + recompute_result = bool(document.recompute()) + except Exception as error: + recompute_exception = {"type": type(error).__name__, "message": str(error)} + after = { + "value": vector_value(obj, property_name), + "state": state_snapshot(obj), + "shape": shape_snapshot(obj), + "objects": object_set(document), + } + return { + "id": case_id, + "objectTypeId": object_type_id, + "propertyName": property_name, + "removed": removed, + "recomputeException": recompute_exception, + "recomputeResult": recompute_result, + "before": before, + "afterRecompute": after, + "objectsPreserved": before["objects"] == after["objects"], + } + finally: + App.closeDocument(document.Name) + + +def run_disabled_and_transaction(): + document = App.newDocument("PropertyDirectionDisabledAndTransaction") + try: + obj, property_name = setup_mirroring(document) + document.recompute() + document.UndoMode = 1 + baseline = vector_value(obj, property_name) + initial_objects = object_set(document) + + obj.setEditorMode(property_name, ["ReadOnly"]) + editor_mode = [str(item) for item in obj.getEditorMode(property_name)] + editor_exception = exception_snapshot(lambda: setattr(obj, property_name, (1.0, 0.0, 1.0))) + editor_after = vector_value(obj, property_name) + setattr(obj, property_name, tuple(baseline)) + obj.setPropertyStatus(property_name, "Immutable") + immutable_status = [str(item) for item in obj.getPropertyStatus(property_name)] + immutable_exception = exception_snapshot(lambda: setattr(obj, property_name, (0.0, 1.0, 1.0))) + immutable_after = vector_value(obj, property_name) + obj.setPropertyStatus(property_name, "-Immutable") + obj.setEditorMode(property_name, 0) + disabled = { + "classification": "editor-readonly-python-mutable-until-immutable", + "before": baseline, + "editorMode": editor_mode, + "editorRequested": [1.0, 0.0, 1.0], + "editorException": editor_exception, + "editorAfter": editor_after, + "pythonBypassesEditorReadOnly": editor_exception is None, + "immutableStatus": immutable_status, + "immutableRequested": [0.0, 1.0, 1.0], + "immutableException": immutable_exception, + "immutableAfter": immutable_after, + "immutableValuePreserved": immutable_after == baseline, + "restoredStatus": [str(item) for item in obj.getPropertyStatus(property_name)], + "restoredEditorMode": [str(item) for item in obj.getEditorMode(property_name)], + } + + document.recompute() + document.openTransaction("property-direction-cancel") + transaction_before = vector_value(obj, property_name) + transaction_objects_before = object_set(document) + setattr(obj, property_name, (0.25, -0.5, 1.5)) + transaction_edited = vector_value(obj, property_name) + state_after_edit = state_snapshot(obj) + pending_after_edit = bool(document.HasPendingTransaction) + active_after_edit = active_transaction_snapshot() + document.abortTransaction() + transaction_after_abort = vector_value(obj, property_name) + state_after_abort = state_snapshot(obj) + recovery_recompute_result = bool(document.recompute()) + transaction_after_recompute = vector_value(obj, property_name) + state_after_recompute = state_snapshot(obj) + transaction_objects_after = object_set(document) + return { + "object": {"name": obj.Name, "typeId": obj.TypeId}, + "property": {"name": property_name, "typeId": obj.getTypeIdOfProperty(property_name)}, + "disabled": disabled, + "transaction": { + "before": transaction_before, + "edited": transaction_edited, + "afterAbort": transaction_after_abort, + "afterRecompute": transaction_after_recompute, + "stateAfterEdit": state_after_edit, + "stateAfterAbort": state_after_abort, + "stateAfterRecompute": state_after_recompute, + "objectsBefore": transaction_objects_before, + "objectsAfter": transaction_objects_after, + "undoMode": int(document.UndoMode), + "pendingAfterEdit": pending_after_edit, + "pendingAfterAbort": bool(document.HasPendingTransaction), + "activeAfterEdit": active_after_edit, + "activeAfterAbort": active_transaction_snapshot(), + "recoveryRecomputeResult": recovery_recompute_result, + "restored": transaction_before == transaction_after_abort == transaction_after_recompute, + "objectsRestored": transaction_objects_before == transaction_objects_after, + }, + "documentIntegrity": { + "initialObjects": initial_objects, + "finalObjects": object_set(document), + "objectsPreserved": initial_objects == object_set(document), + }, + } + finally: + App.closeDocument(document.Name) + + +NON_FINITE_VALUES = { + "nan": (float("nan"), 0.0, 1.0), + "positive-infinity": (float("inf"), 0.0, 1.0), + "negative-infinity": (float("-inf"), 0.0, 1.0), +} +if PROBE_MODE.startswith("non-finite:"): + _, host_id, value_id = PROBE_MODE.split(":", 2) + host_options = { + "Mirroring": ("Part::Mirroring", setup_mirroring), + "ProjectOnSurface": ("Part::ProjectOnSurface", setup_projection), + } + object_type_id, setup = host_options[host_id] + print("FREECAD_PROPERTY_DIRECTION_PROGRESS=" + host_id + "-" + value_id, flush=True) + isolated_case = run_consumer_direction(host_id + "-" + value_id, object_type_id, setup, NON_FINITE_VALUES[value_id]) + isolated_report = { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-direction-failure-isolated", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyDirection", + "case": isolated_case, + } + if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_DIRECTION_FAILURE_OUTPUT is required") + with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(isolated_report, handle, indent=2, sort_keys=True, allow_nan=False) + handle.write("\n") + print("FREECAD_PROPERTY_DIRECTION_FAILURE_ISOLATED_RESULT=" + json.dumps({"status": "pass", "caseId": isolated_case["id"]}, sort_keys=True)) + raise SystemExit(0) + + +setter_boundaries = run_setter_boundaries() +consumer_failures = [] +for host_id, object_type_id, setup in [ + ("Mirroring", "Part::Mirroring", setup_mirroring), + ("ProjectOnSurface", "Part::ProjectOnSurface", setup_projection), +]: + print("FREECAD_PROPERTY_DIRECTION_PROGRESS=" + host_id + "-zero", flush=True) + consumer_failures.append(run_consumer_direction(host_id + "-zero", object_type_id, setup, (0.0, 0.0, 0.0))) + + +def remove_mirror_source(obj): + obj.Source = None + return {"property": "Source", "value": None} + + +def remove_projection_support(obj): + obj.SupportFace = None + return {"property": "SupportFace", "value": None} + + +def remove_projection_inputs(obj): + obj.Projection = [] + return {"property": "Projection", "value": []} + + +dependency_failures = [ + run_missing_dependency("Mirroring-no-source", "Part::Mirroring", setup_mirroring, remove_mirror_source), + run_missing_dependency("ProjectOnSurface-no-support", "Part::ProjectOnSurface", setup_projection, remove_projection_support), + run_missing_dependency("ProjectOnSurface-no-projection", "Part::ProjectOnSurface", setup_projection, remove_projection_inputs), +] +disabled_and_transaction = run_disabled_and_transaction() +report = { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-direction-failure", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyDirection", + "setterBoundaries": setter_boundaries, + "consumerFailures": consumer_failures, + "dependencyFailures": dependency_failures, + "disabled": disabled_and_transaction["disabled"], + "transaction": disabled_and_transaction["transaction"], + "documentIntegrity": { + "setter": setter_boundaries["documentIntegrity"], + "disabledAndTransaction": disabled_and_transaction["documentIntegrity"], + "allObjectsPreserved": setter_boundaries["documentIntegrity"]["objectsPreserved"] + and disabled_and_transaction["documentIntegrity"]["objectsPreserved"] + and all(entry["objectsPreserved"] for entry in consumer_failures) + and all(entry["objectsPreserved"] for entry in dependency_failures), + }, + "cancellationBoundary": { + "supported": False, + "classification": "synchronous-property-setter", + "reason": "no-native-cancel-hook", + "replacement": "abort-active-document-transaction", + }, +} +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_DIRECTION_FAILURE_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True, allow_nan=False) + handle.write("\n") +print("FREECAD_PROPERTY_DIRECTION_FAILURE_RESULT=" + json.dumps({ + "status": report["status"], + "setterFailureCount": len(setter_boundaries["failures"]), + "consumerFailureCount": len(consumer_failures), + "dependencyFailureCount": len(dependency_failures), +}, sort_keys=True)) diff --git a/scripts/freecad-property-direction-mutation.py b/scripts/freecad-property-direction-mutation.py new file mode 100644 index 0000000..58c5da6 --- /dev/null +++ b/scripts/freecad-property-direction-mutation.py @@ -0,0 +1,153 @@ +import hashlib +import json +import os + +import FreeCAD as App +import Part + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_DIRECTION_MUTATION_OUTPUT", "") +EDITED_VALUE = (0.25, -0.5, 1.5) + + +def vector_value(obj, property_name): + value = getattr(obj, property_name) + return [float(value.x), float(value.y), float(value.z)] + + +def object_set(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def shape_snapshot(obj): + shape = obj.Shape + if shape.isNull(): + return { + "isNull": True, + "valid": False, + "shapeType": "Null", + "solids": 0, + "faces": 0, + "edges": 0, + "vertices": 0, + } + bounds = shape.BoundBox + return { + "isNull": False, + "valid": bool(shape.isValid()), + "shapeType": shape.ShapeType, + "solids": len(shape.Solids), + "faces": len(shape.Faces), + "edges": len(shape.Edges), + "vertices": len(shape.Vertexes), + "area": round(float(shape.Area), 9), + "volume": round(float(shape.Volume), 9), + "bounds": [round(float(value), 9) for value in (bounds.XMin, bounds.YMin, bounds.ZMin, bounds.XMax, bounds.YMax, bounds.ZMax)], + "brepSha256": hashlib.sha256(shape.exportBrepToString().encode("utf-8")).hexdigest(), + } + + +def snapshot(document, obj, property_name, recompute_result=None): + return { + "value": vector_value(obj, property_name), + "propertyTypeId": obj.getTypeIdOfProperty(property_name), + "propertyStatus": [str(item) for item in obj.getPropertyStatus(property_name)], + "editorMode": [str(item) for item in obj.getEditorMode(property_name)], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "mustExecute": bool(obj.MustExecute), + "recomputeResult": recompute_result, + "shape": shape_snapshot(obj), + "objectSet": object_set(document), + } + + +def setup_mirroring(document): + source = document.addObject("Part::Box", "MirrorSource") + source.Length = 2 + source.Width = 3 + source.Height = 4 + host = document.addObject("Part::Mirroring", "DirectionMirror") + host.Source = source + host.Base = App.Vector(0, 0, 0) + return host, "Normal" + + +def setup_projection(document): + support = document.addObject("Part::Feature", "ProjectionSupport") + support.Shape = Part.makePlane(40, 40, App.Vector(-20, -20, 0)) + wire = document.addObject("Part::Feature", "ProjectionWire") + wire.Shape = Part.makePolygon([ + App.Vector(-4, -3, -5), + App.Vector(4, -3, -5), + App.Vector(4, 3, -5), + App.Vector(-4, 3, -5), + App.Vector(-4, -3, -5), + ]) + host = document.addObject("Part::ProjectOnSurface", "DirectionProjection") + host.SupportFace = (support, ["Face1"]) + host.Projection = [(wire, ["Wire1"])] + host.Mode = "Edges" + return host, "Direction" + + +def run_case(case_id, object_type_id, setup): + document = App.newDocument("PropertyDirectionMutation" + case_id) + try: + obj, property_name = setup(document) + before_recompute = bool(document.recompute()) + before = snapshot(document, obj, property_name, before_recompute) + + setattr(obj, property_name, EDITED_VALUE) + after_set = snapshot(document, obj, property_name) + edited_recompute = bool(document.recompute()) + after_recompute = snapshot(document, obj, property_name, edited_recompute) + + setattr(obj, property_name, tuple(before["value"])) + after_restore_set = snapshot(document, obj, property_name) + restored_recompute = bool(document.recompute()) + after_restore_recompute = snapshot(document, obj, property_name, restored_recompute) + return { + "caseId": case_id, + "objectTypeId": object_type_id, + "objectName": obj.Name, + "propertyName": property_name, + "editedValue": list(EDITED_VALUE), + "phases": { + "before": before, + "afterSet": after_set, + "afterRecompute": after_recompute, + "afterRestoreSet": after_restore_set, + "afterRestoreRecompute": after_restore_recompute, + }, + "valueChanged": before["value"] != after_recompute["value"], + "valueRestored": before["value"] == after_restore_recompute["value"], + "geometryChanged": before["shape"]["brepSha256"] != after_recompute["shape"]["brepSha256"], + "geometryRestored": before["shape"] == after_restore_recompute["shape"], + "objectsPreserved": before["objectSet"] == after_recompute["objectSet"] == after_restore_recompute["objectSet"], + } + finally: + App.closeDocument(document.Name) + + +cases = [ + run_case("Mirroring", "Part::Mirroring", setup_mirroring), + run_case("ProjectOnSurface", "Part::ProjectOnSurface", setup_projection), +] +report = { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-direction-mutation", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyDirection", + "caseCount": len(cases), + "cases": cases, +} +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_DIRECTION_MUTATION_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_DIRECTION_MUTATION_RESULT=" + json.dumps({"status": report["status"], "caseCount": report["caseCount"]}, sort_keys=True)) diff --git a/scripts/freecad-property-direction-roundtrip.py b/scripts/freecad-property-direction-roundtrip.py new file mode 100644 index 0000000..0773d23 --- /dev/null +++ b/scripts/freecad-property-direction-roundtrip.py @@ -0,0 +1,110 @@ +import hashlib +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def vector_value(obj): + value = obj.Normal + return {"x": float(value.x), "y": float(value.y), "z": float(value.z)} + + +def shape_snapshot(obj): + shape = obj.Shape + bounds = shape.BoundBox + return { + "isNull": bool(shape.isNull()), + "valid": bool(shape.isValid()), + "shapeType": shape.ShapeType, + "solids": len(shape.Solids), + "faces": len(shape.Faces), + "edges": len(shape.Edges), + "vertices": len(shape.Vertexes), + "area": round(float(shape.Area), 9), + "volume": round(float(shape.Volume), 9), + "bounds": [round(float(value), 9) for value in (bounds.XMin, bounds.YMin, bounds.ZMin, bounds.XMax, bounds.YMax, bounds.ZMax)], + "brepSha256": hashlib.sha256(shape.exportBrepToString().encode("utf-8")).hexdigest(), + } + + +def object_snapshot(document): + obj = document.getObject("DirectionMirror") + return { + "objectSet": [{"name": item.Name, "typeId": item.TypeId} for item in document.Objects], + "object": { + "name": obj.Name, + "typeId": obj.TypeId, + "propertyTypeId": obj.getTypeIdOfProperty("Normal"), + "value": vector_value(obj), + "propertyStatus": [str(item) for item in obj.getPropertyStatus("Normal")], + "editorMode": [str(item) for item in obj.getEditorMode("Normal")], + "state": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "shape": shape_snapshot(obj), + }, + } + + +def create_native(path): + document = App.newDocument("PropertyDirectionRoundtrip") + try: + source = document.addObject("Part::Box", "MirrorSource") + source.Length = 2 + source.Width = 3 + source.Height = 4 + obj = document.addObject("Part::Mirroring", "DirectionMirror") + obj.Source = source + obj.Base = App.Vector(0, 0, 0) + obj.Normal = App.Vector(0, 0, 1) + document.recompute() + document.saveAs(path) + finally: + App.closeDocument(document.Name) + reopened = App.openDocument(path) + try: + reopened.recompute() + return object_snapshot(reopened) + finally: + App.closeDocument(reopened.Name) + + +def verify_native(path, resaved_path): + document = App.openDocument(path) + try: + document.recompute() + reopened = object_snapshot(document) + document.saveAs(resaved_path) + finally: + App.closeDocument(document.Name) + resaved_document = App.openDocument(resaved_path) + try: + resaved_document.recompute() + resaved = object_snapshot(resaved_document) + finally: + App.closeDocument(resaved_document.Name) + return {"reopened": reopened, "resaved": resaved} + + +mode = os.environ.get("FREECAD_PROPERTY_DIRECTION_ROUNDTRIP_MODE", "") +path = os.environ.get("FREECAD_PROPERTY_DIRECTION_ROUNDTRIP_PATH", "") +resaved_path = os.environ.get("FREECAD_PROPERTY_DIRECTION_ROUNDTRIP_RESAVED_PATH", "") +if mode == "create": + result = create_native(path) +elif mode == "verify": + result = verify_native(path, resaved_path) +else: + raise RuntimeError("FREECAD_PROPERTY_DIRECTION_ROUNDTRIP_MODE must be create or verify") + +print("FREECAD_PROPERTY_DIRECTION_ROUNDTRIP_RESULT=" + json.dumps({ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-direction-roundtrip", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "mode": mode, + "result": result, +}, sort_keys=True)) diff --git a/scripts/freecad-property-direction-success.py b/scripts/freecad-property-direction-success.py new file mode 100644 index 0000000..7be9457 --- /dev/null +++ b/scripts/freecad-property-direction-success.py @@ -0,0 +1,168 @@ +import hashlib +import json +import os + +import FreeCAD as App +import Part + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_DIRECTION_SUCCESS_OUTPUT", "") +ASSIGNMENTS = [ + ("axisZTuple", (0.0, 0.0, 1.0), "tuple"), + ("integerTuple", (1, 1, 2), "tuple"), + ("nonUnitFloatTuple", (0.25, -0.5, 1.5), "tuple"), + ("vectorObject", App.Vector(-0.125, 0.25, 1.0), "Base.Vector"), + ("nearAxisTuple", (1.0e-9, -1.0e-9, 1.0), "tuple"), + ("largeFiniteTuple", (1.0e6, -2.0e6, 3.0e6), "tuple"), +] + + +def vector_value(obj, property_name): + value = getattr(obj, property_name) + return [float(value.x), float(value.y), float(value.z)] + + +def object_snapshot(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def shape_snapshot(obj): + shape = obj.Shape + if shape.isNull(): + return {"applicable": True, "isNull": True, "shapeType": "Null", "solids": 0, "faces": 0, "edges": 0, "vertices": 0} + brep = shape.exportBrepToString().encode("utf-8") + bounds = shape.BoundBox + return { + "applicable": True, + "isNull": False, + "valid": bool(shape.isValid()), + "shapeType": shape.ShapeType, + "solids": len(shape.Solids), + "faces": len(shape.Faces), + "edges": len(shape.Edges), + "vertices": len(shape.Vertexes), + "area": round(float(shape.Area), 9), + "volume": round(float(shape.Volume), 9), + "bounds": [round(float(value), 9) for value in (bounds.XMin, bounds.YMin, bounds.ZMin, bounds.XMax, bounds.YMax, bounds.ZMax)], + "brepSha256": hashlib.sha256(brep).hexdigest(), + } + + +def host_snapshot(document, obj, property_name, recompute_result): + return { + "value": vector_value(obj, property_name), + "propertyTypeId": obj.getTypeIdOfProperty(property_name), + "propertyStatus": [str(item) for item in obj.getPropertyStatus(property_name)], + "editorMode": [str(item) for item in obj.getEditorMode(property_name)], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "mustExecute": bool(obj.MustExecute), + "recomputeResult": bool(recompute_result), + "shape": shape_snapshot(obj), + "objectSet": object_snapshot(document), + } + + +def touched_snapshot(obj, property_name): + return { + "value": vector_value(obj, property_name), + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "mustExecute": bool(obj.MustExecute), + } + + +def setup_mirroring(document): + source = document.addObject("Part::Box", "MirrorSource") + source.Length = 2 + source.Width = 3 + source.Height = 4 + host = document.addObject("Part::Mirroring", "DirectionMirror") + host.Source = source + host.Base = App.Vector(0, 0, 0) + return host, "Normal", { + "kind": "box-mirror", + "source": {"name": source.Name, "typeId": source.TypeId, "dimensions": [2, 3, 4]}, + "base": [0, 0, 0], + "mirrorPlane": None, + } + + +def setup_projection(document): + support = document.addObject("Part::Feature", "ProjectionSupport") + support.Shape = Part.makePlane(40, 40, App.Vector(-20, -20, 0)) + wire = document.addObject("Part::Feature", "ProjectionWire") + points = [ + App.Vector(-4, -3, -5), + App.Vector(4, -3, -5), + App.Vector(4, 3, -5), + App.Vector(-4, 3, -5), + App.Vector(-4, -3, -5), + ] + wire.Shape = Part.makePolygon(points) + host = document.addObject("Part::ProjectOnSurface", "DirectionProjection") + host.SupportFace = (support, ["Face1"]) + host.Projection = [(wire, ["Wire1"])] + host.Mode = "Edges" + return host, "Direction", { + "kind": "wire-to-planar-face", + "support": {"name": support.Name, "typeId": support.TypeId, "subElements": ["Face1"]}, + "projection": {"name": wire.Name, "typeId": wire.TypeId, "subElements": ["Wire1"], "z": -5}, + "mode": "Edges", + } + + +def run_case(case_id, object_type_id, setup): + document = App.newDocument("PropertyDirection" + case_id) + try: + obj, property_name, setup_report = setup(document) + initial_recompute = document.recompute() + default_value = vector_value(obj, property_name) + phases = {"default": {"afterRecompute": host_snapshot(document, obj, property_name, initial_recompute)}} + requested = {} + for phase, value, input_kind in ASSIGNMENTS: + requested[phase] = {"inputKind": input_kind, "value": [float(component) for component in value]} + setattr(obj, property_name, value) + touched = touched_snapshot(obj, property_name) + recompute_result = document.recompute() + phases[phase] = {"afterSet": touched, "afterRecompute": host_snapshot(document, obj, property_name, recompute_result)} + setattr(obj, property_name, tuple(default_value)) + restored_touched = touched_snapshot(obj, property_name) + restored_recompute = document.recompute() + phases["restored"] = {"afterSet": restored_touched, "afterRecompute": host_snapshot(document, obj, property_name, restored_recompute)} + return { + "caseId": case_id, + "objectTypeId": object_type_id, + "objectName": obj.Name, + "propertyName": property_name, + "mode": "direct-native-property-setter-with-valid-host-geometry", + "setup": setup_report, + "defaultValue": default_value, + "requested": requested, + "phases": phases, + } + finally: + App.closeDocument(document.Name) + + +cases = [ + run_case("Mirroring", "Part::Mirroring", setup_mirroring), + run_case("ProjectOnSurface", "Part::ProjectOnSurface", setup_projection), +] +report = { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-direction-success", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyDirection", + "caseCount": len(cases), + "cases": cases, +} +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_DIRECTION_SUCCESS_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_DIRECTION_SUCCESS_RESULT=" + json.dumps({"status": report["status"], "caseCount": report["caseCount"]}, sort_keys=True)) diff --git a/scripts/freecad-property-file-failure.py b/scripts/freecad-property-file-failure.py new file mode 100644 index 0000000..dfd20a7 --- /dev/null +++ b/scripts/freecad-property-file-failure.py @@ -0,0 +1,105 @@ +import json + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def object_set(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def snapshot(document, obj): + document.recompute() + return { + "value": str(obj.FileName), + "propertyTypeId": obj.getTypeIdOfProperty("FileName"), + "propertyStatus": [str(item) for item in obj.getPropertyStatus("FileName")], + "editorMode": [str(item) for item in obj.getEditorMode("FileName")], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "objectSet": object_set(document), + } + + +def exception_snapshot(callback): + try: + callback() + except Exception as error: + return {"type": type(error).__name__, "message": str(error)} + return None + + +def active_transaction_snapshot(): + active = App.getActiveTransaction() + if not active: + return {"name": "", "id": 0} + return {"name": str(active[0]), "id": int(active[1])} + + +def run(): + document = App.newDocument("PropertyFileFailure") + try: + obj = document.addObject("Mesh::Import", "FileProbe") + document.recompute() + document.UndoMode = 1 + initial = snapshot(document, obj) + failures = [] + for case_id, requested in [("missing-path", "/definitely/missing/bitbybit-file.stl"), ("wrong-type", 12345)]: + before = snapshot(document, obj) + before_objects = object_set(document) + assignment_exception = exception_snapshot(lambda: setattr(obj, "FileName", requested)) + recompute_exception = None + try: + document.recompute() + except Exception as error: + recompute_exception = {"type": type(error).__name__, "message": str(error)} + after = snapshot(document, obj) + after_objects = object_set(document) + failures.append({"id": case_id, "requested": requested, "assignmentException": assignment_exception, "recomputeException": recompute_exception, "before": before, "after": after, "beforeObjects": before_objects, "afterObjects": after_objects, "objectsPreserved": before_objects == after_objects}) + + obj.FileName = "" + document.recompute() + disabled_before = snapshot(document, obj) + disabled_objects_before = object_set(document) + obj.setEditorMode("FileName", ["ReadOnly"]) + obj.setPropertyStatus("FileName", "Immutable") + disabled_status = [str(item) for item in obj.getPropertyStatus("FileName")] + disabled_editor_mode = [str(item) for item in obj.getEditorMode("FileName")] + disabled_exception = exception_snapshot(lambda: setattr(obj, "FileName", "/tmp/blocked.stl")) + disabled_after = snapshot(document, obj) + disabled_objects_after = object_set(document) + obj.setPropertyStatus("FileName", "-Immutable") + obj.setEditorMode("FileName", 0) + + document.openTransaction("property-file-cancel") + transaction_before = snapshot(document, obj) + transaction_objects_before = object_set(document) + obj.FileName = "/tmp/transaction-file.stl" + transaction_edited = snapshot(document, obj) + transaction_pending_after_edit = bool(document.HasPendingTransaction) + transaction_active_after_edit = active_transaction_snapshot() + document.abortTransaction() + transaction_after_abort = snapshot(document, obj) + transaction_objects_after = object_set(document) + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-file-failure", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "object": {"name": obj.Name, "typeId": obj.TypeId}, + "property": {"name": "FileName", "typeId": obj.getTypeIdOfProperty("FileName")}, + "initial": initial, + "failures": failures, + "disabled": {"classification": "editor-read-only-and-python-immutable", "status": disabled_status, "editorMode": disabled_editor_mode, "exception": disabled_exception, "before": disabled_before, "after": disabled_after, "beforeObjects": disabled_objects_before, "afterObjects": disabled_objects_after, "restoredStatus": [str(item) for item in obj.getPropertyStatus("FileName")], "restoredEditorMode": [str(item) for item in obj.getEditorMode("FileName")]}, + "transaction": {"before": transaction_before, "edited": transaction_edited, "afterAbort": transaction_after_abort, "objectsBefore": transaction_objects_before, "objectsAfter": transaction_objects_after, "undoMode": int(document.UndoMode), "pendingAfterEdit": transaction_pending_after_edit, "pendingAfterAbort": bool(document.HasPendingTransaction), "activeAfterEdit": transaction_active_after_edit, "activeAfterAbort": active_transaction_snapshot(), "restored": transaction_before == transaction_after_abort, "objectsRestored": transaction_objects_before == transaction_objects_after}, + "cancellationBoundary": {"supported": False, "classification": "synchronous-property-setter", "reason": "no-native-cancel-hook", "replacement": "abort-active-document-transaction"}, + "documentIntegrity": {"initialObjects": initial["objectSet"], "finalObjects": object_set(document), "objectsPreserved": initial["objectSet"] == object_set(document), "objectCount": len(document.Objects)}, + } + finally: + App.closeDocument(document.Name) + + +print("FREECAD_PROPERTY_FILE_FAILURE_RESULT=" + json.dumps(run(), sort_keys=True)) diff --git a/scripts/freecad-property-file-mutation.py b/scripts/freecad-property-file-mutation.py new file mode 100644 index 0000000..619cd8a --- /dev/null +++ b/scripts/freecad-property-file-mutation.py @@ -0,0 +1,33 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +ASSET = os.path.abspath(".cache/freecad/FreeCAD/data/tests/mesh.obj") +ALTERNATE = "/tmp/property-file-alternate.stl" + + +def snapshot(document, obj): + recompute_result = bool(document.recompute()) + return {"value": str(obj.FileName), "propertyTypeId": obj.getTypeIdOfProperty("FileName"), "propertyStatus": [str(item) for item in obj.getPropertyStatus("FileName")], "editorMode": [str(item) for item in obj.getEditorMode("FileName")], "objectState": [str(item) for item in obj.State], "statusString": str(obj.getStatusString()), "recomputeResult": recompute_result, "objectSet": [{"name": candidate.Name, "typeId": candidate.TypeId} for candidate in document.Objects]} + + +def run(): + document = App.newDocument("PropertyFileMutation") + try: + obj = document.addObject("Mesh::Import", "FileProbe") + obj.FileName = ASSET + document.recompute() + before = snapshot(document, obj) + obj.FileName = ALTERNATE + edited = snapshot(document, obj) + obj.FileName = ASSET + restored = snapshot(document, obj) + return {"schemaVersion": 1, "status": "pass", "baselineId": "freecad-1.1.1-property-file-mutation", "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), "gitCommit": FREECAD_COMMIT, "propertyType": "App::PropertyFile", "object": {"name": obj.Name, "typeId": obj.TypeId}, "property": {"name": "FileName", "typeId": obj.getTypeIdOfProperty("FileName")}, "requested": {"before": ASSET, "edited": ALTERNATE, "restored": ASSET}, "phases": {"before": before, "edited": edited, "restored": restored}, "classification": {"valueChanged": before["value"] != edited["value"], "invalidEditedPath": edited["statusString"] == "File does not exist", "restoreExact": restored["value"] == before["value"] and restored["statusString"] == "Valid", "objectSetStable": before["objectSet"] == edited["objectSet"] == restored["objectSet"], "unknownSemanticDrift": False}} + finally: + App.closeDocument(document.Name) + + +print("FREECAD_PROPERTY_FILE_MUTATION_RESULT=" + json.dumps(run(), sort_keys=True)) diff --git a/scripts/freecad-property-file-roundtrip.py b/scripts/freecad-property-file-roundtrip.py new file mode 100644 index 0000000..cd18138 --- /dev/null +++ b/scripts/freecad-property-file-roundtrip.py @@ -0,0 +1,102 @@ +import hashlib +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def mesh_snapshot(obj): + mesh = obj.Mesh + bounds = mesh.BoundBox + return { + "isEmpty": int(mesh.CountFacets) == 0, + "facets": int(mesh.CountFacets), + "points": int(mesh.CountPoints), + "bounds": [round(float(value), 9) for value in (bounds.XMin, bounds.YMin, bounds.ZMin, bounds.XMax, bounds.YMax, bounds.ZMax)], + } + + +def object_snapshot(document): + obj = document.getObject("FileProbe") + path = str(obj.FileName) + asset_bytes = open(path, "rb").read() if os.path.isfile(path) else b"" + return { + "objectSet": [{"name": item.Name, "typeId": item.TypeId} for item in document.Objects], + "object": { + "name": obj.Name, + "typeId": obj.TypeId, + "propertyTypeId": obj.getTypeIdOfProperty("FileName"), + "value": path, + "propertyStatus": [str(item) for item in obj.getPropertyStatus("FileName")], + "editorMode": [str(item) for item in obj.getEditorMode("FileName")], + "state": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "hasShapeProperty": "Shape" in obj.PropertiesList, + "hasMeshProperty": "Mesh" in obj.PropertiesList, + "asset": { + "exists": bool(asset_bytes), + "bytes": len(asset_bytes), + "sha256": hashlib.sha256(asset_bytes).hexdigest() if asset_bytes else "", + }, + "mesh": mesh_snapshot(obj), + }, + } + + +def create_native(path, initial_value): + document = App.newDocument("PropertyFileRoundtrip") + try: + obj = document.addObject("Mesh::Import", "FileProbe") + obj.FileName = initial_value + document.recompute() + document.saveAs(path) + finally: + App.closeDocument(document.Name) + reopened = App.openDocument(path) + try: + reopened.recompute() + return object_snapshot(reopened) + finally: + App.closeDocument(reopened.Name) + + +def verify_native(path, resaved_path): + document = App.openDocument(path) + try: + document.recompute() + reopened = object_snapshot(document) + document.saveAs(resaved_path) + finally: + App.closeDocument(document.Name) + resaved_document = App.openDocument(resaved_path) + try: + resaved_document.recompute() + resaved = object_snapshot(resaved_document) + finally: + App.closeDocument(resaved_document.Name) + return {"reopened": reopened, "resaved": resaved} + + +mode = os.environ.get("FREECAD_PROPERTY_FILE_ROUNDTRIP_MODE", "") +path = os.environ.get("FREECAD_PROPERTY_FILE_ROUNDTRIP_PATH", "") +resaved_path = os.environ.get("FREECAD_PROPERTY_FILE_ROUNDTRIP_RESAVED_PATH", "") +initial_value = os.environ.get("FREECAD_PROPERTY_FILE_ROUNDTRIP_INITIAL", "") +if mode == "create": + result = create_native(path, initial_value) +elif mode == "verify": + result = verify_native(path, resaved_path) +else: + raise RuntimeError("FREECAD_PROPERTY_FILE_ROUNDTRIP_MODE must be create or verify") + +print("FREECAD_PROPERTY_FILE_ROUNDTRIP_RESULT=" + json.dumps({ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-file-roundtrip", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "mode": mode, + "result": result, +}, sort_keys=True)) diff --git a/scripts/freecad-property-file-success.py b/scripts/freecad-property-file-success.py new file mode 100644 index 0000000..b2e36c9 --- /dev/null +++ b/scripts/freecad-property-file-success.py @@ -0,0 +1,74 @@ +import json +import os + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +ASSET = os.path.abspath(".cache/freecad/FreeCAD/data/tests/mesh.obj") + + +def mesh_snapshot(obj): + mesh = getattr(obj, "Mesh", None) + if mesh is None: + return {"applicable": False} + try: + bounds = mesh.BoundBox + return { + "applicable": True, + "facets": len(mesh.Facets), + "vertices": len(mesh.Points), + "bounds": [round(float(value), 9) for value in (bounds.XMin, bounds.YMin, bounds.ZMin, bounds.XMax, bounds.YMax, bounds.ZMax)], + "isEmpty": len(mesh.Facets) == 0, + } + except Exception as error: + return {"applicable": True, "error": str(error)} + + +def snapshot(document, obj, requested): + recompute_result = bool(document.recompute()) + return { + "requested": requested, + "value": str(obj.FileName), + "propertyTypeId": obj.getTypeIdOfProperty("FileName"), + "propertyStatus": [str(item) for item in obj.getPropertyStatus("FileName")], + "editorMode": [str(item) for item in obj.getEditorMode("FileName")], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "mustExecute": bool(obj.mustExecute()) if hasattr(obj, "mustExecute") else None, + "recomputeResult": recompute_result, + "mesh": mesh_snapshot(obj), + "objectSet": [{"name": candidate.Name, "typeId": candidate.TypeId} for candidate in document.Objects], + } + + +def run(): + document = App.newDocument("PropertyFileSuccess") + try: + obj = document.addObject("Mesh::Import", "FileProbe") + document.recompute() + phases = {"default": snapshot(document, obj, "")} + obj.FileName = ASSET + phases["valid-mesh"] = snapshot(document, obj, ASSET) + obj.FileName = "mesh-data/Cube.stl" + phases["relative-path"] = snapshot(document, obj, "mesh-data/Cube.stl") + obj.FileName = ASSET + phases["restored"] = snapshot(document, obj, ASSET) + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-file-success", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyFile", + "object": {"name": obj.Name, "typeId": obj.TypeId}, + "property": {"name": "FileName", "typeId": obj.getTypeIdOfProperty("FileName"), "group": obj.getGroupOfProperty("FileName")}, + "asset": {"path": ASSET, "exists": os.path.isfile(ASSET), "bytes": os.path.getsize(ASSET) if os.path.isfile(ASSET) else 0}, + "phases": phases, + "diagnostics": {"exception": None, "documentObjectCount": len(document.Objects)}, + } + finally: + App.closeDocument(document.Name) + + +print("FREECAD_PROPERTY_FILE_SUCCESS_RESULT=" + json.dumps(run(), sort_keys=True)) diff --git a/scripts/freecad-property-fileincluded-failure.py b/scripts/freecad-property-fileincluded-failure.py new file mode 100644 index 0000000..04ec45b --- /dev/null +++ b/scripts/freecad-property-fileincluded-failure.py @@ -0,0 +1,208 @@ +import hashlib +import json +import os +import shutil +import stat +import tempfile + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_FILEINCLUDED_FAILURE_OUTPUT", "") + + +def object_set(document): + return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] + + +def sha256_file(path): + if not path or not os.path.isfile(path): + return None + with open(path, "rb") as handle: + return hashlib.sha256(handle.read()).hexdigest() + + +def snapshot(document, obj): + path = str(obj.File) + path_exists = os.path.exists(path) if path else False + is_file = os.path.isfile(path) if path else False + is_directory = os.path.isdir(path) if path else False + mode = stat.S_IMODE(os.stat(path).st_mode) if path_exists else None + return { + "value": path, + "baseName": os.path.basename(path) if path else "", + "exists": is_file, + "pathExists": path_exists, + "isFile": is_file, + "isDirectory": is_directory, + "bytes": os.path.getsize(path) if is_file else 0, + "sha256": sha256_file(path), + "writeBits": mode & 0o222 if mode is not None else None, + "underTransientDir": bool(path) and os.path.commonpath([os.path.abspath(path), os.path.abspath(document.TransientDir)]) == os.path.abspath(document.TransientDir), + "propertyTypeId": obj.getTypeIdOfProperty("File"), + "propertyStatus": [str(item) for item in obj.getPropertyStatus("File")], + "editorMode": [str(item) for item in obj.getEditorMode("File")], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "objectSet": object_set(document), + } + + +def exception_snapshot(callback): + try: + callback() + except Exception as error: + return {"type": type(error).__name__, "message": str(error)} + return None + + +def active_transaction_snapshot(): + active = App.getActiveTransaction() + if not active: + return {"name": "", "id": 0} + return {"name": str(active[0]), "id": int(active[1])} + + +def run(): + source_dir = tempfile.mkdtemp(prefix="freecad-property-fileincluded-failure-") + document = App.newDocument("PropertyFileIncludedFailure") + try: + source = os.path.join(source_dir, "source.bin") + replacement = os.path.join(source_dir, "replacement.bin") + with open(source, "wb") as handle: + handle.write(b"stable-fileincluded-source\x00\xff\n") + with open(replacement, "wb") as handle: + handle.write(b"replacement-fileincluded-source\x00\x80\n") + source_directory = os.path.join(source_dir, "directory") + os.mkdir(source_directory) + + obj = document.addObject("App::DocumentObjectFileIncluded", "FileProbe") + obj.File = (source, "stable.bin") + document.recompute() + document.UndoMode = 1 + initial = snapshot(document, obj) + initial_objects = object_set(document) + failures = [] + cases = [ + ("missing-path", "/definitely/missing/property-fileincluded.bin"), + ("wrong-type", 12345), + ("tuple-wrong-arity", (source,)), + ("tuple-wrong-name-type", (source, 123)), + ("dictionary-wrong-filename-type", {"filename": 123}), + ] + for case_id, requested in cases: + before = snapshot(document, obj) + before_objects = object_set(document) + assignment_exception = exception_snapshot(lambda value=requested: setattr(obj, "File", value)) + after = snapshot(document, obj) + failures.append({ + "id": case_id, + "requested": repr(requested), + "assignmentException": assignment_exception, + "before": before, + "after": after, + "valuePreserved": before["value"] == after["value"] and before["sha256"] == after["sha256"], + "objectsPreserved": before_objects == after["objectSet"], + "objectSetBefore": before_objects, + "objectSetAfter": after["objectSet"], + }) + + directory_before = snapshot(document, obj) + directory_exception = exception_snapshot(lambda: setattr(obj, "File", source_directory)) + directory_after = snapshot(document, obj) + obj.File = (source, "restored-after-directory.bin") + document.recompute() + directory_recovery = snapshot(document, obj) + accepted_risks = [{ + "id": "directory-path", + "requested": repr(source_directory), + "assignmentException": directory_exception, + "before": directory_before, + "after": directory_after, + "oldFileRemoved": directory_before["isFile"] and not directory_after["isFile"], + "directoryAccepted": directory_after["pathExists"] and directory_after["isDirectory"], + "recovery": directory_recovery, + "objectsPreserved": directory_before["objectSet"] == directory_after["objectSet"] == directory_recovery["objectSet"], + }] + + same_before = snapshot(document, obj) + same_exception = exception_snapshot(lambda: setattr(obj, "File", str(obj.File))) + same_after = snapshot(document, obj) + failures.append({ + "id": "same-current-transient", + "requested": repr(same_before["value"]), + "assignmentException": same_exception, + "before": same_before, + "after": same_after, + "valuePreserved": same_before["value"] == same_after["value"] and same_before["sha256"] == same_after["sha256"], + "objectsPreserved": same_before["objectSet"] == same_after["objectSet"], + "objectSetBefore": same_before["objectSet"], + "objectSetAfter": same_after["objectSet"], + }) + + filter_before = snapshot(document, obj) + filter_exception = exception_snapshot(lambda: setattr(obj, "File", {"filter": "Binary (*.bin)"})) + filter_after = snapshot(document, obj) + filter_only = {"before": filter_before, "after": filter_after, "exception": filter_exception, "valuePreserved": filter_before["value"] == filter_after["value"] and filter_before["sha256"] == filter_after["sha256"], "objectsPreserved": filter_before["objectSet"] == filter_after["objectSet"]} + + editor_before = snapshot(document, obj) + obj.setEditorMode("File", ["ReadOnly"]) + editor_mode = [str(item) for item in obj.getEditorMode("File")] + editor_exception = exception_snapshot(lambda: setattr(obj, "File", (replacement, "editor-write.bin"))) + editor_after = snapshot(document, obj) + editor_read_only = {"before": editor_before, "editorMode": editor_mode, "exception": editor_exception, "after": editor_after, "pythonBypassesEditorReadOnly": editor_exception is None} + obj.setEditorMode("File", 0) + + obj.setPropertyStatus("File", "Immutable") + immutable_status = [str(item) for item in obj.getPropertyStatus("File")] + immutable_before = snapshot(document, obj) + immutable_exception = exception_snapshot(lambda: setattr(obj, "File", (replacement, "immutable-write.bin"))) + immutable_after = snapshot(document, obj) + obj.setPropertyStatus("File", "-Immutable") + status_restored = [str(item) for item in obj.getPropertyStatus("File")] + + document.recompute() + document.openTransaction("property-fileincluded-cancel") + transaction_before = snapshot(document, obj) + transaction_objects_before = object_set(document) + setattr(obj, "File", (source, "transaction-write.bin")) + transaction_edited = snapshot(document, obj) + edited_path = transaction_edited["value"] + pending_after_edit = bool(document.HasPendingTransaction) + active_after_edit = active_transaction_snapshot() + document.abortTransaction() + transaction_after_abort = snapshot(document, obj) + pending_after_abort = bool(document.HasPendingTransaction) + active_after_abort = active_transaction_snapshot() + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-fileincluded-failure", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyFileIncluded", + "object": {"name": obj.Name, "typeId": obj.TypeId}, + "property": {"name": "File", "typeId": obj.getTypeIdOfProperty("File")}, + "initial": initial, + "failures": failures, + "acceptedRisks": accepted_risks, + "filterOnly": filter_only, + "editorReadOnly": editor_read_only, + "immutable": {"status": immutable_status, "before": immutable_before, "exception": immutable_exception, "after": immutable_after, "restoredStatus": status_restored}, + "transaction": {"before": transaction_before, "edited": transaction_edited, "afterAbort": transaction_after_abort, "editedPath": edited_path, "editedPathExistsAfterAbort": os.path.exists(edited_path), "pendingAfterEdit": pending_after_edit, "pendingAfterAbort": pending_after_abort, "activeAfterEdit": active_after_edit, "activeAfterAbort": active_after_abort, "objectsBefore": transaction_objects_before, "objectsAfter": object_set(document), "undoMode": int(document.UndoMode), "restored": transaction_before["value"] == transaction_after_abort["value"] and transaction_before["sha256"] == transaction_after_abort["sha256"]}, + "cancellationBoundary": {"supported": False, "classification": "synchronous-property-setter", "reason": "no-native-cancel-hook", "replacement": "abort-active-document-transaction"}, + "documentIntegrity": {"initialObjects": initial_objects, "finalObjects": object_set(document), "objectsPreserved": initial_objects == object_set(document), "objectCount": len(document.Objects)}, + } + finally: + App.closeDocument(document.Name) + shutil.rmtree(source_dir, ignore_errors=True) + + +report = run() +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_FILEINCLUDED_FAILURE_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_FILEINCLUDED_FAILURE_RESULT=" + json.dumps({"status": report["status"], "failureCount": len(report["failures"])}, sort_keys=True)) diff --git a/scripts/freecad-property-fileincluded-mutation.py b/scripts/freecad-property-fileincluded-mutation.py new file mode 100644 index 0000000..4c9b4b3 --- /dev/null +++ b/scripts/freecad-property-fileincluded-mutation.py @@ -0,0 +1,165 @@ +import base64 +import hashlib +import json +import os +import shutil +import stat +import tempfile + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_FILEINCLUDED_MUTATION_OUTPUT", "") +HOSTS = [ + ("App::DocumentObjectFileIncluded", "File"), + ("App::VRMLObject", "VrmlFile"), + ("Image::ImagePlane", "ImageFile"), + ("Robot::RobotObject", "RobotKinematicFile"), + ("Robot::RobotObject", "RobotVrmlFile"), + ("Sketcher::SketchObjectSF", "SketchFlatFile"), + ("TechDraw::DrawComplexSection", "PatIncluded"), + ("TechDraw::DrawComplexSection", "SvgIncluded"), + ("TechDraw::DrawComplexSectionPython", "PatIncluded"), + ("TechDraw::DrawComplexSectionPython", "SvgIncluded"), + ("TechDraw::DrawGeomHatch", "PatIncluded"), + ("TechDraw::DrawHatch", "SvgIncluded"), + ("TechDraw::DrawSVGTemplate", "PageResult"), + ("TechDraw::DrawTileWeld", "SymbolIncluded"), + ("TechDraw::DrawTileWeldPython", "SymbolIncluded"), + ("TechDraw::DrawViewImage", "ImageIncluded"), + ("TechDraw::DrawViewSection", "PatIncluded"), + ("TechDraw::DrawViewSection", "SvgIncluded"), + ("TechDraw::DrawViewSectionPython", "PatIncluded"), + ("TechDraw::DrawViewSectionPython", "SvgIncluded"), +] + + +def sha256_file(path): + with open(path, "rb") as handle: + return hashlib.sha256(handle.read()).hexdigest() + + +def write_asset(directory, name, data): + path = os.path.join(directory, name) + with open(path, "wb") as handle: + handle.write(data) + return path + + +def create_assets(directory): + png_a = base64.b64decode("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=") + png_b = base64.b64decode("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=") + b"mutation" + csv_a = b"a,alpha,d,theta,rotDir,maxAngle,minAngle,velocity\n500,-90,1045,0,-1,185,-185,156\n1300,0,0,0,1,35,-155,156\n55,90,0,-90,1,154,-130,156\n0,-90,-1025,0,1,350,-350,330\n0,90,0,0,1,130,-130,330\n0,180,-300,0,1,350,-350,615\n" + csv_b = b"a,alpha,d,theta,rotDir,maxAngle,minAngle,velocity\n501,-90,1045,0,-1,185,-185,156\n1300,0,0,0,1,35,-155,156\n55,90,0,-90,1,154,-130,156\n0,-90,-1025,0,1,350,-350,330\n0,90,0,0,1,130,-130,330\n0,180,-300,0,1,350,-350,615\n" + return { + "binA": write_asset(directory, "before.bin", b"before-fileincluded\x00A\xff\n"), + "binB": write_asset(directory, "edited.bin", b"edited-fileincluded\x00B\x80\n"), + "svgA": write_asset(directory, "before.svg", b'\n'), + "svgB": write_asset(directory, "edited.svg", b'\n'), + "patA": write_asset(directory, "before.pat", b"*BEFORE,PropertyFileIncluded\n0, 0,0, 0,2\n"), + "patB": write_asset(directory, "edited.pat", b"*EDITED,PropertyFileIncluded\n0, 0,0, 0,3\n"), + "pngA": write_asset(directory, "before.png", png_a), + "pngB": write_asset(directory, "edited.png", png_b), + "wrlA": write_asset(directory, "before.wrl", b"#VRML V2.0 utf8\nShape { geometry Box { size 1 1 1 } }\n"), + "wrlB": write_asset(directory, "edited.wrl", b"#VRML V2.0 utf8\nShape { geometry Box { size 2 1 1 } }\n"), + "csvA": write_asset(directory, "before.csv", csv_a), + "csvB": write_asset(directory, "edited.csv", csv_b), + "skfA": write_asset(directory, "before.skf", b"# SketchFlat before fixture\n"), + "skfB": write_asset(directory, "edited.skf", b"# SketchFlat edited fixture\n"), + } + + +def asset_for(property_name, assets, phase): + suffix = "A" if phase == "before" or phase == "restored" else "B" + if property_name == "PatIncluded": return assets[f"pat{suffix}"], "pat" + if property_name in ("SvgIncluded", "PageResult", "SymbolIncluded"): return assets[f"svg{suffix}"], "svg" + if property_name in ("ImageFile", "ImageIncluded"): return assets[f"png{suffix}"], "png" + if property_name in ("VrmlFile", "RobotVrmlFile"): return assets[f"wrl{suffix}"], "wrl" + if property_name == "RobotKinematicFile": return assets[f"csv{suffix}"], "csv" + if property_name == "SketchFlatFile": return assets[f"skf{suffix}"], "skf" + return assets[f"bin{suffix}"], "bin" + + +def shape_snapshot(obj): + if "Shape" not in obj.PropertiesList: + return {"applicable": False, "reason": "host-has-no-shape-property"} + shape = obj.Shape + return {"applicable": True, "isNull": shape is None or shape.isNull(), "solids": len(shape.Solids), "faces": len(shape.Faces), "edges": len(shape.Edges), "vertices": len(shape.Vertexes)} + + +def snapshot(document, obj, property_name): + path = str(getattr(obj, property_name)) + is_file = os.path.isfile(path) if path else False + mode = stat.S_IMODE(os.stat(path).st_mode) if is_file else None + return { + "value": path, + "baseName": os.path.basename(path) if path else "", + "exists": is_file, + "bytes": os.path.getsize(path) if is_file else 0, + "sha256": sha256_file(path) if is_file else None, + "writeBits": mode & 0o222 if mode is not None else None, + "underTransientDir": bool(path) and os.path.commonpath([os.path.abspath(path), os.path.abspath(document.TransientDir)]) == os.path.abspath(document.TransientDir), + "propertyTypeId": obj.getTypeIdOfProperty(property_name), + "propertyStatus": [str(item) for item in obj.getPropertyStatus(property_name)], + "editorMode": [str(item) for item in obj.getEditorMode(property_name)], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "shape": shape_snapshot(obj), + "objectSet": [{"name": candidate.Name, "typeId": candidate.TypeId} for candidate in document.Objects], + } + + +def run_case(index, object_type_id, property_name, assets): + document = App.newDocument("PropertyFileIncludedMutation%02d" % index) + try: + obj = document.addObject(object_type_id, "MutationProbe") + archive_name = "mutation-%02d.%s" % (index, "pat" if property_name == "PatIncluded" else "svg" if property_name in ("SvgIncluded", "PageResult", "SymbolIncluded") else "png" if property_name in ("ImageFile", "ImageIncluded") else "wrl" if property_name in ("VrmlFile", "RobotVrmlFile") else "csv" if property_name == "RobotKinematicFile" else "skf" if property_name == "SketchFlatFile" else "bin") + before_source, _ = asset_for(property_name, assets, "before") + edited_source, _ = asset_for(property_name, assets, "edited") + setattr(obj, property_name, (before_source, archive_name)) + document.recompute() + before = snapshot(document, obj, property_name) + setattr(obj, property_name, (edited_source, archive_name)) + edited = snapshot(document, obj, property_name) + edited_recompute = bool(document.recompute()) + edited_after_recompute = snapshot(document, obj, property_name) + setattr(obj, property_name, (before_source, archive_name)) + restored = snapshot(document, obj, property_name) + restored_recompute = bool(document.recompute()) + restored_after_recompute = snapshot(document, obj, property_name) + return { + "objectTypeId": object_type_id, + "propertyName": property_name, + "archiveName": archive_name, + "beforeSource": {"path": before_source, "bytes": os.path.getsize(before_source), "sha256": sha256_file(before_source)}, + "editedSource": {"path": edited_source, "bytes": os.path.getsize(edited_source), "sha256": sha256_file(edited_source)}, + "before": before, + "edited": edited, + "editedRecompute": {"result": edited_recompute, "snapshot": edited_after_recompute}, + "restored": restored, + "restoredRecompute": {"result": restored_recompute, "snapshot": restored_after_recompute}, + "pathStable": before["value"] == edited["value"] == restored["value"], + "objectSetStable": before["objectSet"] == edited["objectSet"] == restored["objectSet"] == restored_after_recompute["objectSet"], + } + finally: + App.closeDocument(document.Name) + + +def run(): + directory = tempfile.mkdtemp(prefix="freecad-property-fileincluded-mutation-") + try: + assets = create_assets(directory) + cases = [run_case(index, *host, assets) for index, host in enumerate(HOSTS)] + return {"schemaVersion": 1, "status": "pass", "baselineId": "freecad-1.1.1-property-fileincluded-mutation", "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), "gitCommit": FREECAD_COMMIT, "propertyType": "App::PropertyFileIncluded", "caseCount": len(cases), "cases": cases} + finally: + shutil.rmtree(directory, ignore_errors=True) + + +report = run() +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_FILEINCLUDED_MUTATION_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_FILEINCLUDED_MUTATION_RESULT=" + json.dumps({"status": report["status"], "caseCount": report["caseCount"]}, sort_keys=True)) diff --git a/scripts/freecad-property-fileincluded-roundtrip.py b/scripts/freecad-property-fileincluded-roundtrip.py new file mode 100644 index 0000000..cbd3093 --- /dev/null +++ b/scripts/freecad-property-fileincluded-roundtrip.py @@ -0,0 +1,94 @@ +import hashlib +import json +import os +import stat + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" + + +def file_snapshot(document): + obj = document.getObject("IncludedProbe") + path = str(obj.File) + exists = os.path.isfile(path) + payload = open(path, "rb").read() if exists else b"" + mode = stat.S_IMODE(os.stat(path).st_mode) if exists else None + return { + "objectSet": [{"name": item.Name, "typeId": item.TypeId} for item in document.Objects], + "object": { + "name": obj.Name, + "typeId": obj.TypeId, + "propertyTypeId": obj.getTypeIdOfProperty("File"), + "value": path, + "baseName": os.path.basename(path) if path else "", + "exists": exists, + "bytes": len(payload), + "sha256": hashlib.sha256(payload).hexdigest() if payload else "", + "mode": mode, + "writeBits": mode & 0o222 if mode is not None else None, + "underTransientDir": bool(path) and os.path.commonpath([os.path.abspath(path), os.path.abspath(document.TransientDir)]) == os.path.abspath(document.TransientDir), + "propertyStatus": [str(item) for item in obj.getPropertyStatus("File")], + "editorMode": [str(item) for item in obj.getEditorMode("File")], + "state": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "hasShapeProperty": "Shape" in obj.PropertiesList, + }, + } + + +def create_native(path, source_path): + document = App.newDocument("PropertyFileIncludedRoundtrip") + try: + obj = document.addObject("App::DocumentObjectFileIncluded", "IncludedProbe") + obj.File = (source_path, "payload.bin") + document.recompute() + document.saveAs(path) + finally: + App.closeDocument(document.Name) + reopened = App.openDocument(path) + try: + reopened.recompute() + return file_snapshot(reopened) + finally: + App.closeDocument(reopened.Name) + + +def verify_native(path, resaved_path): + document = App.openDocument(path) + try: + document.recompute() + reopened = file_snapshot(document) + document.saveAs(resaved_path) + finally: + App.closeDocument(document.Name) + resaved_document = App.openDocument(resaved_path) + try: + resaved_document.recompute() + resaved = file_snapshot(resaved_document) + finally: + App.closeDocument(resaved_document.Name) + return {"reopened": reopened, "resaved": resaved} + + +mode = os.environ.get("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_MODE", "") +path = os.environ.get("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_PATH", "") +resaved_path = os.environ.get("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_RESAVED_PATH", "") +source_path = os.environ.get("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_SOURCE", "") +if mode == "create": + result = create_native(path, source_path) +elif mode == "verify": + result = verify_native(path, resaved_path) +else: + raise RuntimeError("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_MODE must be create or verify") + +print("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_RESULT=" + json.dumps({ + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-fileincluded-roundtrip", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "mode": mode, + "result": result, +}, sort_keys=True)) diff --git a/scripts/freecad-property-fileincluded-success.py b/scripts/freecad-property-fileincluded-success.py new file mode 100644 index 0000000..0bec725 --- /dev/null +++ b/scripts/freecad-property-fileincluded-success.py @@ -0,0 +1,237 @@ +import base64 +import hashlib +import json +import os +import shutil +import stat +import tempfile + +import FreeCAD as App + + +FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" +OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_FILEINCLUDED_SUCCESS_OUTPUT", "") +HOSTS = [ + ("App::DocumentObjectFileIncluded", "File"), + ("App::VRMLObject", "VrmlFile"), + ("Image::ImagePlane", "ImageFile"), + ("Robot::RobotObject", "RobotKinematicFile"), + ("Robot::RobotObject", "RobotVrmlFile"), + ("Sketcher::SketchObjectSF", "SketchFlatFile"), + ("TechDraw::DrawComplexSection", "PatIncluded"), + ("TechDraw::DrawComplexSection", "SvgIncluded"), + ("TechDraw::DrawComplexSectionPython", "PatIncluded"), + ("TechDraw::DrawComplexSectionPython", "SvgIncluded"), + ("TechDraw::DrawGeomHatch", "PatIncluded"), + ("TechDraw::DrawHatch", "SvgIncluded"), + ("TechDraw::DrawSVGTemplate", "PageResult"), + ("TechDraw::DrawTileWeld", "SymbolIncluded"), + ("TechDraw::DrawTileWeldPython", "SymbolIncluded"), + ("TechDraw::DrawViewImage", "ImageIncluded"), + ("TechDraw::DrawViewSection", "PatIncluded"), + ("TechDraw::DrawViewSection", "SvgIncluded"), + ("TechDraw::DrawViewSectionPython", "PatIncluded"), + ("TechDraw::DrawViewSectionPython", "SvgIncluded"), +] + + +def sha256_file(path): + with open(path, "rb") as handle: + return hashlib.sha256(handle.read()).hexdigest() + + +def write_asset(directory, name, data): + path = os.path.join(directory, name) + with open(path, "wb") as handle: + handle.write(data) + return path + + +def create_assets(directory): + png = base64.b64decode( + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=" + ) + kinematic = ( + "a,alpha,d,theta,rotDir,maxAngle,minAngle,velocity\n" + "500,-90,1045,0,-1,185,-185,156\n" + "1300,0,0,0,1,35,-155,156\n" + "55,90,0,-90,1,154,-130,156\n" + "0,-90,-1025,0,1,350,-350,330\n" + "0,90,0,0,1,130,-130,330\n" + "0,180,-300,0,1,350,-350,615\n" + ).encode("ascii") + return { + "bin": write_asset(directory, "payload.bin", b"FreeCAD-PropertyFileIncluded\x00success\xff\n"), + "bin2": write_asset(directory, "payload-two.bin", b"FreeCAD-PropertyFileIncluded\x00second\x80\n"), + "svg": write_asset(directory, "pattern.svg", b'\n'), + "pat": write_asset(directory, "pattern.pat", b"*TEST,PropertyFileIncluded\n0, 0,0, 0,2\n"), + "png": write_asset(directory, "pixel.png", png), + "wrl": write_asset(directory, "model.wrl", b"#VRML V2.0 utf8\nShape { geometry Box { size 1 1 1 } }\n"), + "csv": write_asset(directory, "kinematic.csv", kinematic), + "skf": write_asset(directory, "sketch.skf", b"# SketchFlat PropertyFileIncluded fixture\n"), + } + + +def asset_for(object_type_id, property_name, assets): + if property_name in ("PatIncluded",): + return assets["pat"], "pat" + if property_name in ("SvgIncluded", "PageResult", "SymbolIncluded"): + return assets["svg"], "svg" + if property_name in ("ImageFile", "ImageIncluded"): + return assets["png"], "png" + if property_name in ("VrmlFile", "RobotVrmlFile"): + return assets["wrl"], "wrl" + if property_name == "RobotKinematicFile": + return assets["csv"], "csv" + if property_name == "SketchFlatFile": + return assets["skf"], "skf" + return assets["bin"], "bin" + + +def shape_snapshot(obj): + if "Shape" not in obj.PropertiesList: + return {"applicable": False, "reason": "host-has-no-shape-property"} + shape = obj.Shape + if shape is None or shape.isNull(): + return {"applicable": True, "isNull": True, "solids": 0, "faces": 0, "edges": 0, "vertices": 0} + return { + "applicable": True, + "isNull": False, + "isValid": bool(shape.isValid()), + "solids": len(shape.Solids), + "faces": len(shape.Faces), + "edges": len(shape.Edges), + "vertices": len(shape.Vertexes), + } + + +def file_snapshot(document, obj, property_name): + path = str(getattr(obj, property_name)) + exists = os.path.isfile(path) if path else False + mode = stat.S_IMODE(os.stat(path).st_mode) if exists else None + return { + "value": path, + "baseName": os.path.basename(path) if path else "", + "exists": exists, + "bytes": os.path.getsize(path) if exists else 0, + "sha256": sha256_file(path) if exists else None, + "mode": mode, + "writeBits": mode & 0o222 if mode is not None else None, + "underTransientDir": bool(path) and os.path.commonpath([os.path.abspath(path), os.path.abspath(document.TransientDir)]) == os.path.abspath(document.TransientDir), + "propertyTypeId": obj.getTypeIdOfProperty(property_name), + "propertyStatus": [str(item) for item in obj.getPropertyStatus(property_name)], + "editorMode": [str(item) for item in obj.getEditorMode(property_name)], + "objectState": [str(item) for item in obj.State], + "statusString": str(obj.getStatusString()), + "shape": shape_snapshot(obj), + "objectSet": [{"name": candidate.Name, "typeId": candidate.TypeId} for candidate in document.Objects], + } + + +def run_setter_variants(assets): + document = App.newDocument("PropertyFileIncludedSetterSuccess") + try: + phases = [] + + def assign(name, value, expected_asset, expected_base_name=None): + obj = document.addObject("App::DocumentObjectFileIncluded", name) + setattr(obj, "File", value) + snapshot = file_snapshot(document, obj, "File") + snapshot.update({ + "id": name, + "sourcePath": expected_asset, + "sourceSha256": sha256_file(expected_asset), + "expectedBaseName": expected_base_name or os.path.basename(expected_asset), + }) + phases.append(snapshot) + return obj + + assign("StringPath", assets["bin"], assets["bin"]) + assign("BytesPath", os.fsencode(assets["bin2"]), assets["bin2"]) + assign("TupleRename", (assets["bin"], "renamed.dat"), assets["bin"], "renamed.dat") + with open(assets["bin2"], "rb") as source: + assign("OpenIoFile", source, assets["bin2"]) + assign("Dictionary", {"filename": assets["bin"], "filter": "Binary files (*.bin)"}, assets["bin"]) + + empty_no_op = document.addObject("App::DocumentObjectFileIncluded", "EmptyNoOp") + empty_no_op.File = assets["bin"] + before_empty = file_snapshot(document, empty_no_op, "File") + empty_no_op.File = "" + after_empty = file_snapshot(document, empty_no_op, "File") + + collision_a = assign("CollisionA", (assets["bin"], "collision.bin"), assets["bin"], "collision.bin") + collision_b = assign("CollisionB", (assets["bin2"], "collision.bin"), assets["bin2"], "collision1.bin") + recompute_result = bool(document.recompute()) + return { + "phases": phases, + "emptyString": {"before": before_empty, "after": after_empty, "preserved": before_empty["value"] == after_empty["value"] and before_empty["sha256"] == after_empty["sha256"]}, + "collision": { + "first": file_snapshot(document, collision_a, "File"), + "second": file_snapshot(document, collision_b, "File"), + "distinctPaths": str(collision_a.File) != str(collision_b.File), + "distinctBytes": sha256_file(str(collision_a.File)) != sha256_file(str(collision_b.File)), + }, + "recomputeResult": recompute_result, + "objectCount": len(document.Objects), + } + finally: + App.closeDocument(document.Name) + + +def run_host_case(index, object_type_id, property_name, assets): + document = App.newDocument("PropertyFileIncludedHost%02d" % index) + try: + obj = document.addObject(object_type_id, "HostProbe") + before_object_set = [{"name": candidate.Name, "typeId": candidate.TypeId} for candidate in document.Objects] + default = file_snapshot(document, obj, property_name) + source_path, asset_kind = asset_for(object_type_id, property_name, assets) + archive_name = "host-%02d.%s" % (index, asset_kind) + setattr(obj, property_name, (source_path, archive_name)) + after_set = file_snapshot(document, obj, property_name) + recompute_result = bool(document.recompute()) + after_recompute = file_snapshot(document, obj, property_name) + return { + "objectTypeId": object_type_id, + "propertyName": property_name, + "group": obj.getGroupOfProperty(property_name), + "source": {"path": source_path, "kind": asset_kind, "bytes": os.path.getsize(source_path), "sha256": sha256_file(source_path)}, + "archiveName": archive_name, + "default": default, + "afterSet": after_set, + "afterRecompute": after_recompute, + "recomputeResult": recompute_result, + "objectSetStable": before_object_set == after_set["objectSet"] == after_recompute["objectSet"], + } + finally: + App.closeDocument(document.Name) + + +def run(): + asset_directory = tempfile.mkdtemp(prefix="freecad-property-fileincluded-success-") + try: + assets = create_assets(asset_directory) + setter_variants = run_setter_variants(assets) + host_cases = [run_host_case(index, *host, assets) for index, host in enumerate(HOSTS)] + return { + "schemaVersion": 1, + "status": "pass", + "baselineId": "freecad-1.1.1-property-fileincluded-success", + "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), + "gitCommit": FREECAD_COMMIT, + "propertyType": "App::PropertyFileIncluded", + "setterVariants": setter_variants, + "hostCaseCount": len(host_cases), + "hostCases": host_cases, + "diagnostics": {"exception": None}, + } + finally: + shutil.rmtree(asset_directory, ignore_errors=True) + + +report = run() +if not OUTPUT_PATH: + raise RuntimeError("FREECAD_PROPERTY_FILEINCLUDED_SUCCESS_OUTPUT is required") +with open(OUTPUT_PATH, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") +print("FREECAD_PROPERTY_FILEINCLUDED_SUCCESS_RESULT=" + json.dumps({"status": report["status"], "hostCaseCount": report["hostCaseCount"], "setterPhaseCount": len(report["setterVariants"]["phases"])}, sort_keys=True)) diff --git a/scripts/freecad-reference-probe.py b/scripts/freecad-reference-probe.py index be817cd..4d7c176 100644 --- a/scripts/freecad-reference-probe.py +++ b/scripts/freecad-reference-probe.py @@ -17,8 +17,11 @@ TRACEBACK_SECONDS = int(os.environ.get("FREECAD_REFERENCE_TRACEBACK_SECONDS", "0 if TRACEBACK_SECONDS > 0: faulthandler.dump_traceback_later(TRACEBACK_SECONDS, repeat=True, file=2) ISOLATED_GUI_CONFIG = os.environ.get("FREECAD_ORACLE_ISOLATED_CONFIG") == "1" -if PROBE_SCOPE == "gui-commands" and ISOLATED_GUI_CONFIG: - App.ParamGet("User parameter:BaseApp/Preferences/Mod/BIM").SetBool("FirstTime", False) +BIM_FIRST_TIME_WELCOME_SUPPRESSED = False +if ISOLATED_GUI_CONFIG: + bim_preferences = App.ParamGet("User parameter:BaseApp/Preferences/Mod/BIM") + bim_preferences.SetBool("FirstTime", False) + BIM_FIRST_TIME_WELCOME_SUPPRESSED = not bim_preferences.GetBool("FirstTime", True) def probe_progress(message): @@ -359,7 +362,7 @@ result = { "probeScope": PROBE_SCOPE, "oracleSetup": { "isolatedConfig": ISOLATED_GUI_CONFIG, - "bimFirstTimeWelcome": "suppressed-before-workbench-activation" if ISOLATED_GUI_CONFIG else "native-user-config", + "bimFirstTimeWelcome": "suppressed-before-workbench-activation" if BIM_FIRST_TIME_WELCOME_SUPPRESSED else "native-user-config", }, "determinism": { "schemaVersion": 1, diff --git a/scripts/generate-freecad-active-work-queue.mjs b/scripts/generate-freecad-active-work-queue.mjs index 0216477..588a74c 100644 --- a/scripts/generate-freecad-active-work-queue.mjs +++ b/scripts/generate-freecad-active-work-queue.mjs @@ -146,10 +146,17 @@ const makeCapabilityTasks = (prefix, capabilities, firstDependency) => { } return tasks } +if (followUpProgress.schemaVersion !== 1 || followUpProgress.baseline?.freecadVersion !== '1.1.1' || followUpProgress.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || !Array.isArray(followUpProgress.completedTasks)) throw new Error('Follow-up task progress ledger is invalid.') +const recordedFollowUpIds = new Set() +for (const entry of followUpProgress.completedTasks) { + if (typeof entry.id !== 'string' || recordedFollowUpIds.has(entry.id) || !Array.isArray(entry.evidence) || entry.evidence.length === 0) throw new Error(`Follow-up progress entry ${entry.id} is invalid.`) + recordedFollowUpIds.add(entry.id) +} const propertyCapabilities = propertySemantics.types - .filter(({ support }) => support === 'opaque-fcstd-proxy') + .filter(({ typeId, support }) => support === 'opaque-fcstd-proxy' || [...recordedFollowUpIds].some((id) => id.startsWith(`PROP-${slug(typeId)}-`))) .map(({ typeId, recordCount }) => ({ id: typeId, title: typeId, recordCount })) -if (propertyCapabilities.length !== propertySemantics.supportSummary?.['opaque-fcstd-proxy']?.typeCount) throw new Error('Opaque Property capability inventory is inconsistent.') +const carriedPromotedPropertyTypes = propertyCapabilities.filter(({ id }) => propertySemantics.types.find(({ typeId }) => typeId === id)?.support !== 'opaque-fcstd-proxy') +if (propertyCapabilities.length !== propertySemantics.supportSummary?.['opaque-fcstd-proxy']?.typeCount + carriedPromotedPropertyTypes.length) throw new Error('Opaque Property capability inventory is inconsistent.') const followUpMilestoneDefinitions = [ { @@ -220,7 +227,6 @@ const followUpMilestones = followUpMilestoneDefinitions.map((definition) => { return { id: definition.id, title: definition.title, exactTasks: definition.exactTasks, status: 'pending', tasks } }) const followUpTasks = followUpMilestones.flatMap(({ tasks }) => tasks) -if (followUpProgress.schemaVersion !== 1 || followUpProgress.baseline?.freecadVersion !== '1.1.1' || followUpProgress.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || !Array.isArray(followUpProgress.completedTasks)) throw new Error('Follow-up task progress ledger is invalid.') const followUpTaskIds = new Set(followUpTasks.map(({ id }) => id)) const completedFollowUpIds = new Set() for (const entry of followUpProgress.completedTasks) { diff --git a/scripts/generate-freecad-property-acceleration-inventory.mjs b/scripts/generate-freecad-property-acceleration-inventory.mjs new file mode 100644 index 0000000..1d09816 --- /dev/null +++ b/scripts/generate-freecad-property-acceleration-inventory.mjs @@ -0,0 +1,57 @@ +import { createHash } from 'node:crypto' +import { readFile, stat, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const sourcePath = resolve(root, '.cache/freecad/reference-desktop.json') +const outputPath = resolve(root, 'config/freecad-property-acceleration-inventory.json') +const sourceContent = await readFile(sourcePath) +const source = JSON.parse(sourceContent) +const fail = (message) => { throw new Error(`FreeCAD PropertyAcceleration inventory generation failed: ${message}`) } + +if (source.schemaVersion !== 1 || source.freecadVersion !== '1.1.1' || source.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('desktop oracle is not the locked FreeCAD baseline') +const records = [] +for (const objectType of source.runtimeObjects?.types ?? []) { + for (const property of objectType.properties ?? []) { + if (property.typeId !== 'App::PropertyAcceleration') continue + records.push({ + objectTypeId: objectType.typeId, + objectAvailable: objectType.available === true, + probeStatus: objectType.probeStatus, + propertyName: property.name, + group: property.group, + status: property.status, + defaultRaw: property.default, + valueModel: { + kind: 'quantity', + dimension: 'length/time^2', + defaultValue: 1000, + defaultUnit: 'mm/s^2', + acceptedBoundaryEvidence: 'inventory-only; value and boundary acceptance remain pending in phase B/C', + }, + dependencies: [], + applicability: { + requiredObjectTypeId: objectType.typeId, + source: 'Document.supportedTypes runtime inventory', + }, + }) + } +} +if (records.length !== 1) fail(`expected one native App::PropertyAcceleration record, found ${records.length}`) +const report = { + schemaVersion: 1, + status: 'pass', + baseline: { freecadVersion: source.freecadVersion, commit: source.gitCommit }, + propertyType: 'App::PropertyAcceleration', + recordCount: records.length, + records, + source: { + path: '.cache/freecad/reference-desktop.json', + bytes: sourceContent.length, + sha256: createHash('sha256').update(sourceContent).digest('hex'), + }, + classification: 'opaque-fcstd-proxy', + nextPhases: ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-acceleration-inventory.json', propertyType: report.propertyType, recordCount: report.recordCount }, null, 2)) diff --git a/scripts/generate-freecad-property-acceleration-promotion.mjs b/scripts/generate-freecad-property-acceleration-promotion.mjs new file mode 100644 index 0000000..d181d0c --- /dev/null +++ b/scripts/generate-freecad-property-acceleration-promotion.mjs @@ -0,0 +1,59 @@ +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const outputPath = resolve(root, 'config/freecad-property-acceleration-promotion.json') +const [inventory, success, failure, mutation, roundTrip, chrome, semantics, progress] = await Promise.all([ + load('config/freecad-property-acceleration-inventory.json'), + load('config/freecad-property-acceleration-success.json'), + load('config/freecad-property-acceleration-failure.json'), + load('config/freecad-property-acceleration-mutation.json'), + load('config/freecad-property-acceleration-roundtrip.json'), + load('config/chrome-property-acceleration-verification.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyAcceleration promotion generation failed: ${message}`) } +const requiredCompletedPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredCompletedPhases) if (!completed.has(`PROP-app-propertyacceleration-${phase}`)) fail(`phase ${phase} is not completed in the evidence ledger`) +if (inventory.status !== 'pass' || inventory.propertyType !== 'App::PropertyAcceleration' || inventory.recordCount !== 1) fail('inventory evidence is invalid') +for (const [name, artifact] of Object.entries({ success, failure, mutation, roundTrip, chrome })) if (artifact.status !== 'pass') fail(`${name} evidence is not passing`) +const propertyType = semantics.types?.find(({ typeId }) => typeId === 'App::PropertyAcceleration') +if (propertyType?.support !== 'native-editable-codec' || propertyType.recordCount !== 1) fail('global property semantics did not promote App::PropertyAcceleration') +const opaque = semantics.supportSummary?.['opaque-fcstd-proxy'] +const editable = semantics.supportSummary?.['native-editable-codec'] +if (opaque?.typeCount !== 50 || opaque.recordCount !== 466 || editable?.typeCount !== 30 || editable.recordCount !== 4361) fail('global property support summary is not synchronized') +if (roundTrip.classification?.zeroUnknownDrift !== true || chrome.persistence?.loadedType !== 'App::PropertyAcceleration' || chrome.persistence.loadedValue !== 500 || chrome.release?.workerTerminated !== true) fail('round-trip or browser closure evidence is incomplete') + +const report = { + schemaVersion: 1, + status: 'pass', + taskId: 'PROP-app-propertyacceleration-I', + baseline: semantics.baseline, + propertyType: 'App::PropertyAcceleration', + recordCount: 1, + phaseEvidence: Object.fromEntries(requiredCompletedPhases.map((phase) => [phase, completed.get(`PROP-app-propertyacceleration-${phase}`).evidence])), + promotion: { + from: inventory.classification, + to: propertyType.support, + facadeValueModel: 'finite-number-mm/s^2', + fcstdElement: chrome.persistence.fcstdElement, + nativeRoundTripValue: roundTrip.classification.resavedValue, + browserRoundTripValue: chrome.persistence.loadedValue, + zeroUnknownDrift: roundTrip.classification.zeroUnknownDrift, + }, + exactBlockerSync: { + nativeEditableTypes: editable.typeCount, + nativeEditableRecords: editable.recordCount, + opaqueTypes: opaque.typeCount, + opaqueRecords: opaque.recordCount, + exactPromotionReady: semantics.exactPromotionReady, + exactBlocker: semantics.exactBlocker, + }, + systemExact: false, + generatedAt: new Date().toISOString(), +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-acceleration-promotion-generated', output: 'config/freecad-property-acceleration-promotion.json', promotion: report.promotion, exactBlockerSync: report.exactBlockerSync }, null, 2)) diff --git a/scripts/generate-freecad-property-area-inventory.mjs b/scripts/generate-freecad-property-area-inventory.mjs new file mode 100644 index 0000000..0fbbca1 --- /dev/null +++ b/scripts/generate-freecad-property-area-inventory.mjs @@ -0,0 +1,62 @@ +import { createHash } from 'node:crypto' +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const runtimePath = resolve(root, '.cache/freecad/reference-desktop.json') +const sourcePaths = [ + '.cache/freecad/FreeCAD/src/Mod/Measure/App/MeasureArea.cpp', + '.cache/freecad/FreeCAD/src/Mod/Measure/App/MeasureArea.h', +] +const outputPath = resolve(root, 'config/freecad-property-area-inventory.json') +const runtimeContent = await readFile(runtimePath) +const runtime = JSON.parse(runtimeContent) +const sourceContents = await Promise.all(sourcePaths.map((path) => readFile(resolve(root, path)))) +const fail = (message) => { throw new Error(`FreeCAD PropertyArea inventory generation failed: ${message}`) } + +if (runtime.schemaVersion !== 1 || runtime.freecadVersion !== '1.1.1' || runtime.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('desktop oracle is not the locked FreeCAD baseline') +const records = [] +for (const objectType of runtime.runtimeObjects?.types ?? []) { + for (const property of objectType.properties ?? []) { + if (property.typeId !== 'App::PropertyArea') continue + const input = objectType.properties.find((candidate) => candidate.name === 'Elements') + records.push({ + objectTypeId: objectType.typeId, + objectAvailable: objectType.available === true, + probeStatus: objectType.probeStatus, + propertyName: property.name, + group: property.group, + status: property.status, + normalizedStatus: property.status.map((entry) => entry === 24 ? 'PropReadOnly' : entry === 27 ? 'PropOutput' : String(entry)), + defaultRaw: property.default, + valueModel: { kind: 'quantity', dimension: 'length^2', defaultValue: 0, defaultUnit: 'mm^2', derived: true, writable: false }, + inputs: [{ propertyName: input?.name, typeId: input?.typeId, group: input?.group, defaultValue: input?.default, scope: 'Global', allowExternal: true, cardinality: 'one-or-more' }], + dependencies: [{ sourceProperty: 'Elements', targetProperty: 'Area', relation: 'link-sub-list', effect: 'immediate-recompute-on-change' }], + applicability: { + selectionMustBeNonEmpty: true, + everyElementMustBeValid: true, + supportedMeasureElementTypes: ['PLANE', 'CYLINDER', 'SURFACE', 'VOLUME'], + unsupportedMeasureElementTypes: ['INVALID', 'POINT', 'LINE', 'CURVE'], + externalDocumentElementsAllowed: true, + }, + execution: { aggregation: 'sum-area', resultProperty: 'Area', invalidGeometryDiagnostic: 'Cannot calculate area', shape: 'not-applicable-derived-measurement' }, + }) + } +} +if (records.length !== 1) fail(`expected one native App::PropertyArea record, found ${records.length}`) +const report = { + schemaVersion: 1, + status: 'pass', + baseline: { freecadVersion: runtime.freecadVersion, commit: runtime.gitCommit }, + propertyType: 'App::PropertyArea', + recordCount: records.length, + records, + provenance: { + runtime: { path: '.cache/freecad/reference-desktop.json', bytes: runtimeContent.length, sha256: createHash('sha256').update(runtimeContent).digest('hex') }, + sources: sourcePaths.map((path, index) => ({ path, bytes: sourceContents[index].length, sha256: createHash('sha256').update(sourceContents[index]).digest('hex') })), + }, + classification: 'opaque-fcstd-proxy', + nextPhases: ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-area-inventory-generated', output: 'config/freecad-property-area-inventory.json', propertyType: report.propertyType, recordCount: report.recordCount, objectTypeId: records[0].objectTypeId }, null, 2)) diff --git a/scripts/generate-freecad-property-area-promotion.mjs b/scripts/generate-freecad-property-area-promotion.mjs new file mode 100644 index 0000000..8a51cf3 --- /dev/null +++ b/scripts/generate-freecad-property-area-promotion.mjs @@ -0,0 +1,63 @@ +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const outputPath = resolve(root, 'config/freecad-property-area-promotion.json') +const [inventory, success, failure, mutation, roundTrip, chrome, semantics, progress] = await Promise.all([ + load('config/freecad-property-area-inventory.json'), + load('config/freecad-property-area-success.json'), + load('config/freecad-property-area-failure.json'), + load('config/freecad-property-area-mutation.json'), + load('config/freecad-property-area-roundtrip.json'), + load('config/chrome-property-area-verification.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyArea promotion generation failed: ${message}`) } +const requiredCompletedPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredCompletedPhases) if (!completed.has(`PROP-app-propertyarea-${phase}`)) fail(`phase ${phase} is not completed in the evidence ledger`) +if (inventory.status !== 'pass' || inventory.propertyType !== 'App::PropertyArea' || inventory.recordCount !== 1 || inventory.records?.[0]?.valueModel?.derived !== true || inventory.records[0].valueModel.writable !== false) fail('inventory evidence is invalid') +for (const [name, artifact] of Object.entries({ success, failure, mutation, roundTrip, chrome })) if (artifact.status !== 'pass') fail(`${name} evidence is not passing`) +const propertyType = semantics.types?.find(({ typeId }) => typeId === 'App::PropertyArea') +if (propertyType?.support !== 'native-editable-codec' || propertyType.recordCount !== 1 || propertyType.statusNames?.join(',') !== 'PropOutput,PropReadOnly') fail('global property semantics did not promote App::PropertyArea with its native status') +const opaque = semantics.supportSummary?.['opaque-fcstd-proxy'] +const editable = semantics.supportSummary?.['native-editable-codec'] +if (opaque?.typeCount !== 50 || opaque.recordCount !== 466 || editable?.typeCount !== 30 || editable.recordCount !== 4361) fail('global property support summary is not synchronized') +if (roundTrip.classification?.zeroUnknownDrift !== true || chrome.ui?.areaReadOnly !== true || chrome.persistence?.loadedAreaType !== 'App::PropertyArea' || chrome.persistence.loadedElementsType !== 'App::PropertyLinkSubList' || chrome.release?.workerTerminated !== true) fail('round-trip or browser closure evidence is incomplete') + +const report = { + schemaVersion: 1, + status: 'pass', + taskId: 'PROP-app-propertyarea-I', + baseline: semantics.baseline, + propertyType: 'App::PropertyArea', + recordCount: 1, + phaseEvidence: Object.fromEntries(requiredCompletedPhases.map((phase) => [phase, completed.get(`PROP-app-propertyarea-${phase}`).evidence])), + promotion: { + from: inventory.classification, + to: propertyType.support, + facadeValueModel: 'read-only-derived-mm^2-with-link-sub-list-input', + inputType: 'App::PropertyLinkSubList', + fcstdAreaElement: chrome.persistence.fcstdAreaElement, + fcstdElementsElement: chrome.persistence.fcstdElementsElement, + nativeRoundTripArea: roundTrip.classification.resavedArea, + browserRoundTripArea: chrome.persistence.loadedArea, + browserRoundTripElementCount: chrome.persistence.loadedElementCount, + sourceGeometryPreserved: roundTrip.classification.sourceGeometryPreserved, + zeroUnknownDrift: roundTrip.classification.zeroUnknownDrift, + }, + exactBlockerSync: { + nativeEditableTypes: editable.typeCount, + nativeEditableRecords: editable.recordCount, + opaqueTypes: opaque.typeCount, + opaqueRecords: opaque.recordCount, + exactPromotionReady: semantics.exactPromotionReady, + exactBlocker: semantics.exactBlocker, + }, + systemExact: false, + generatedAt: new Date().toISOString(), +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-area-promotion-generated', output: 'config/freecad-property-area-promotion.json', promotion: report.promotion, exactBlockerSync: report.exactBlockerSync }, null, 2)) diff --git a/scripts/generate-freecad-property-boollist-inventory.mjs b/scripts/generate-freecad-property-boollist-inventory.mjs new file mode 100644 index 0000000..6ddd338 --- /dev/null +++ b/scripts/generate-freecad-property-boollist-inventory.mjs @@ -0,0 +1,42 @@ +import { createHash } from 'node:crypto' +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const sourcePath = resolve(root, '.cache/freecad/reference-desktop.json') +const outputPath = resolve(root, 'config/freecad-property-boollist-inventory.json') +const sourceContent = await readFile(sourcePath) +const source = JSON.parse(sourceContent) +const fail = (message) => { throw new Error(`FreeCAD PropertyBoolList inventory generation failed: ${message}`) } +if (source.schemaVersion !== 1 || source.freecadVersion !== '1.1.1' || source.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('desktop oracle is not the locked FreeCAD baseline') +const records = [] +for (const objectType of source.runtimeObjects?.types ?? []) for (const property of objectType.properties ?? []) { + if (property.typeId !== 'App::PropertyBoolList') continue + records.push({ + objectTypeId: objectType.typeId, + objectAvailable: objectType.available === true, + probeStatus: objectType.probeStatus, + propertyName: property.name, + group: property.group, + status: property.status, + defaultValue: property.default, + valueModel: { kind: 'boolean-list', writable: property.status.length === 0, elementType: 'bool', cardinality: 'variable' }, + dependencies: [], + applicability: { requiredObjectTypeId: objectType.typeId, source: 'Document.supportedTypes runtime inventory' }, + }) +} +records.sort((left, right) => `${left.objectTypeId}.${left.propertyName}`.localeCompare(`${right.objectTypeId}.${right.propertyName}`)) +if (records.length !== 7) fail(`expected seven native App::PropertyBoolList records, found ${records.length}`) +const report = { + schemaVersion: 1, + status: 'pass', + baseline: { freecadVersion: source.freecadVersion, commit: source.gitCommit }, + propertyType: 'App::PropertyBoolList', + recordCount: records.length, + records, + source: { path: '.cache/freecad/reference-desktop.json', bytes: sourceContent.length, sha256: createHash('sha256').update(sourceContent).digest('hex') }, + classification: 'opaque-fcstd-proxy', + nextPhases: ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-boollist-inventory.json', propertyType: report.propertyType, recordCount: report.recordCount }, null, 2)) diff --git a/scripts/generate-freecad-property-boollist-promotion.mjs b/scripts/generate-freecad-property-boollist-promotion.mjs new file mode 100644 index 0000000..bf3e475 --- /dev/null +++ b/scripts/generate-freecad-property-boollist-promotion.mjs @@ -0,0 +1,61 @@ +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const outputPath = resolve(root, 'config/freecad-property-boollist-promotion.json') +const [inventory, success, failure, mutation, roundTrip, chrome, semantics, progress] = await Promise.all([ + load('config/freecad-property-boollist-inventory.json'), + load('config/freecad-property-boollist-success.json'), + load('config/freecad-property-boollist-failure.json'), + load('config/freecad-property-boollist-mutation.json'), + load('config/freecad-property-boollist-roundtrip.json'), + load('config/chrome-property-boollist-verification.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyBoolList promotion generation failed: ${message}`) } +const requiredCompletedPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredCompletedPhases) if (!completed.has(`PROP-app-propertyboollist-${phase}`)) fail(`phase ${phase} is not completed in the evidence ledger`) +if (inventory.status !== 'pass' || inventory.propertyType !== 'App::PropertyBoolList' || inventory.recordCount !== 7 || inventory.records?.filter(({ valueModel }) => valueModel?.writable === true).length !== 3) fail('inventory evidence is invalid') +for (const [name, artifact] of Object.entries({ success, failure, mutation, roundTrip, chrome })) if (artifact.status !== 'pass') fail(`${name} evidence is not passing`) +const propertyType = semantics.types?.find(({ typeId }) => typeId === 'App::PropertyBoolList') +if (propertyType?.support !== 'native-editable-codec' || propertyType.recordCount !== 7 || propertyType.objectTypeCount !== 7 || propertyType.statusNames?.join(',') !== 'Hidden,Immutable,LockDynamic') fail('global property semantics did not promote App::PropertyBoolList with its native status') +const opaque = semantics.supportSummary?.['opaque-fcstd-proxy'] +const editable = semantics.supportSummary?.['native-editable-codec'] +if (opaque?.typeCount !== 50 || opaque.recordCount !== 466 || editable?.typeCount !== 30 || editable.recordCount !== 4361) fail('global property support summary is not synchronized') +if (roundTrip.classification?.zeroUnknownDrift !== true || chrome.persistence?.loadedType !== 'App::PropertyBoolList' || chrome.persistence.fcstdElement !== 'BoolList' || chrome.release?.workerTerminated !== true) fail('round-trip or browser closure evidence is incomplete') + +const report = { + schemaVersion: 1, + status: 'pass', + taskId: 'PROP-app-propertyboollist-I', + baseline: semantics.baseline, + propertyType: 'App::PropertyBoolList', + recordCount: 7, + phaseEvidence: Object.fromEntries(requiredCompletedPhases.map((phase) => [phase, completed.get(`PROP-app-propertyboollist-${phase}`).evidence])), + promotion: { + from: inventory.classification, + to: propertyType.support, + facadeValueModel: 'variable-boolean-array', + writableRecords: 3, + immutableHiddenRecords: 4, + fcstdElement: chrome.persistence.fcstdElement, + nativeRoundTripValue: roundTrip.classification.resavedValue, + browserRoundTripValue: chrome.persistence.loadedValue, + zeroUnknownDrift: roundTrip.classification.zeroUnknownDrift, + }, + exactBlockerSync: { + nativeEditableTypes: editable.typeCount, + nativeEditableRecords: editable.recordCount, + opaqueTypes: opaque.typeCount, + opaqueRecords: opaque.recordCount, + exactPromotionReady: semantics.exactPromotionReady, + exactBlocker: semantics.exactBlocker, + }, + systemExact: false, + generatedAt: new Date().toISOString(), +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-boollist-promotion-generated', output: 'config/freecad-property-boollist-promotion.json', promotion: report.promotion, exactBlockerSync: report.exactBlockerSync }, null, 2)) diff --git a/scripts/generate-freecad-property-color-inventory.mjs b/scripts/generate-freecad-property-color-inventory.mjs new file mode 100644 index 0000000..4e5bba9 --- /dev/null +++ b/scripts/generate-freecad-property-color-inventory.mjs @@ -0,0 +1,72 @@ +import { createHash } from 'node:crypto' +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const runtimePath = resolve(root, '.cache/freecad/reference-desktop.json') +const sourcePaths = [ + '.cache/freecad/FreeCAD/src/App/PropertyStandard.h', + '.cache/freecad/FreeCAD/src/App/PropertyStandard.cpp', + '.cache/freecad/FreeCAD/src/Base/Color.h', + '.cache/freecad/FreeCAD/src/Base/Color.cpp', +] +const outputPath = resolve(root, 'config/freecad-property-color-inventory.json') +const runtimeContent = await readFile(runtimePath) +const runtime = JSON.parse(runtimeContent) +const sourceContents = await Promise.all(sourcePaths.map((path) => readFile(resolve(root, path)))) +const fail = (message) => { throw new Error(`FreeCAD PropertyColor inventory generation failed: ${message}`) } + +if (runtime.schemaVersion !== 1 || runtime.freecadVersion !== '1.1.1' || runtime.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('desktop oracle is not the locked FreeCAD baseline') +const records = [] +for (const objectType of runtime.runtimeObjects?.types ?? []) { + for (const property of objectType.properties ?? []) { + if (property.typeId !== 'App::PropertyColor') continue + records.push({ + objectTypeId: objectType.typeId, + objectAvailable: objectType.available === true, + probeStatus: objectType.probeStatus, + propertyName: property.name, + group: property.group, + status: property.status, + defaultValue: property.default, + valueModel: { + kind: 'rgba-color', + channels: ['red', 'green', 'blue', 'alpha'], + canonicalRepresentation: 'four-channel-float-tuple', + packedRepresentation: '0xRRGGBBAA', + alphaSemantics: '1-opaque-0-transparent', + writable: property.status.length === 0, + }, + inputs: [ + { kind: 'float-tuple', cardinality: [3, 4], componentsMustHaveSameType: true, omittedAlpha: 1 }, + { kind: 'integer-tuple', cardinality: [3, 4], componentsMustHaveSameType: true, normalizationDivisor: 255, omittedAlpha: 1 }, + { kind: 'packed-integer', encoding: '0xRRGGBBAA' }, + ], + dependencies: [], + applicability: { + requiredObjectTypeId: objectType.typeId, + source: 'Document.supportedTypes runtime inventory', + shapeRequired: false, + }, + }) + } +} +records.sort((left, right) => `${left.objectTypeId}.${left.propertyName}`.localeCompare(`${right.objectTypeId}.${right.propertyName}`)) +if (records.length !== 8) fail(`expected eight native App::PropertyColor records, found ${records.length}`) +const report = { + schemaVersion: 1, + status: 'pass', + baseline: { freecadVersion: runtime.freecadVersion, commit: runtime.gitCommit }, + propertyType: 'App::PropertyColor', + recordCount: records.length, + records, + storage: { xmlElement: 'PropertyColor', attribute: 'value', encoding: 'unsigned-decimal-packed-0xRRGGBBAA', legacyBeforeVersion: '1.1', legacyConversion: 'invert-alpha-byte' }, + provenance: { + runtime: { path: '.cache/freecad/reference-desktop.json', bytes: runtimeContent.length, sha256: createHash('sha256').update(runtimeContent).digest('hex') }, + sources: sourcePaths.map((path, index) => ({ path, bytes: sourceContents[index].length, sha256: createHash('sha256').update(sourceContents[index]).digest('hex') })), + }, + classification: 'opaque-fcstd-proxy', + nextPhases: ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-color-inventory-generated', output: 'config/freecad-property-color-inventory.json', propertyType: report.propertyType, recordCount: report.recordCount }, null, 2)) diff --git a/scripts/generate-freecad-property-color-promotion.mjs b/scripts/generate-freecad-property-color-promotion.mjs new file mode 100644 index 0000000..f821ed8 --- /dev/null +++ b/scripts/generate-freecad-property-color-promotion.mjs @@ -0,0 +1,61 @@ +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const outputPath = resolve(root, 'config/freecad-property-color-promotion.json') +const [inventory, success, failure, mutation, roundTrip, chrome, semantics, progress] = await Promise.all([ + load('config/freecad-property-color-inventory.json'), + load('config/freecad-property-color-success.json'), + load('config/freecad-property-color-failure.json'), + load('config/freecad-property-color-mutation.json'), + load('config/freecad-property-color-roundtrip.json'), + load('config/chrome-property-color-verification.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyColor promotion generation failed: ${message}`) } +const requiredCompletedPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredCompletedPhases) if (!completed.has(`PROP-app-propertycolor-${phase}`)) fail(`phase ${phase} is not completed in the evidence ledger`) +if (inventory.status !== 'pass' || inventory.propertyType !== 'App::PropertyColor' || inventory.recordCount !== 8 || inventory.records?.filter(({ valueModel }) => valueModel?.writable === true).length !== 8) fail('inventory evidence is invalid') +for (const [name, artifact] of Object.entries({ success, failure, mutation, roundTrip, chrome })) if (artifact.status !== 'pass') fail(`${name} evidence is not passing`) +const propertyType = semantics.types?.find(({ typeId }) => typeId === 'App::PropertyColor') +if (propertyType?.support !== 'native-editable-codec' || propertyType.recordCount !== 8 || propertyType.objectTypeCount !== 8 || propertyType.statusNames?.length !== 0) fail('global property semantics did not promote App::PropertyColor') +const opaque = semantics.supportSummary?.['opaque-fcstd-proxy'] +const editable = semantics.supportSummary?.['native-editable-codec'] +if (opaque?.typeCount !== 50 || opaque.recordCount !== 466 || editable?.typeCount !== 30 || editable.recordCount !== 4361) fail('global property support summary is not synchronized') +if (roundTrip.classification?.zeroUnknownDrift !== true || chrome.persistence?.loadedType !== 'App::PropertyColor' || chrome.persistence.fcstdElement !== 'PropertyColor' || chrome.persistence.fcstdValue !== '862362060' || chrome.release?.workerTerminated !== true) fail('round-trip or browser closure evidence is incomplete') + +const report = { + schemaVersion: 1, + status: 'pass', + taskId: 'PROP-app-propertycolor-I', + baseline: semantics.baseline, + propertyType: 'App::PropertyColor', + recordCount: 8, + phaseEvidence: Object.fromEntries(requiredCompletedPhases.map((phase) => [phase, completed.get(`PROP-app-propertycolor-${phase}`).evidence])), + promotion: { + from: inventory.classification, + to: propertyType.support, + facadeValueModel: 'four-finite-rgba-channels-with-8-bit-fcstd-packing', + writableRecords: 8, + fcstdElement: chrome.persistence.fcstdElement, + fcstdPackedValue: chrome.persistence.fcstdValue, + nativeRoundTripValue: roundTrip.classification.resavedValue, + browserRoundTripValue: chrome.persistence.loadedValue, + zeroUnknownDrift: roundTrip.classification.zeroUnknownDrift, + }, + exactBlockerSync: { + nativeEditableTypes: editable.typeCount, + nativeEditableRecords: editable.recordCount, + opaqueTypes: opaque.typeCount, + opaqueRecords: opaque.recordCount, + exactPromotionReady: semantics.exactPromotionReady, + exactBlocker: semantics.exactBlocker, + }, + systemExact: false, + generatedAt: new Date().toISOString(), +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-color-promotion-generated', output: 'config/freecad-property-color-promotion.json', promotion: report.promotion, exactBlockerSync: report.exactBlockerSync }, null, 2)) diff --git a/scripts/generate-freecad-property-colorlist-inventory.mjs b/scripts/generate-freecad-property-colorlist-inventory.mjs new file mode 100644 index 0000000..fc8deed --- /dev/null +++ b/scripts/generate-freecad-property-colorlist-inventory.mjs @@ -0,0 +1,82 @@ +import { createHash } from 'node:crypto' +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const runtimePath = resolve(root, '.cache/freecad/reference-desktop.json') +const sourcePaths = [ + '.cache/freecad/FreeCAD/src/App/Property.h', + '.cache/freecad/FreeCAD/src/App/Property.cpp', + '.cache/freecad/FreeCAD/src/App/PropertyStandard.h', + '.cache/freecad/FreeCAD/src/App/PropertyStandard.cpp', + '.cache/freecad/FreeCAD/src/Base/Color.h', + '.cache/freecad/FreeCAD/src/Base/Stream.h', + '.cache/freecad/FreeCAD/src/Base/Stream.cpp', +] +const outputPath = resolve(root, 'config/freecad-property-colorlist-inventory.json') +const runtimeContent = await readFile(runtimePath) +const runtime = JSON.parse(runtimeContent) +const sourceContents = await Promise.all(sourcePaths.map((path) => readFile(resolve(root, path)))) +const fail = (message) => { throw new Error(`FreeCAD PropertyColorList inventory generation failed: ${message}`) } + +if (runtime.schemaVersion !== 1 || runtime.freecadVersion !== '1.1.1' || runtime.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('desktop oracle is not the locked FreeCAD baseline') +const records = [] +for (const objectType of runtime.runtimeObjects?.types ?? []) { + for (const property of objectType.properties ?? []) { + if (property.typeId !== 'App::PropertyColorList') continue + records.push({ + objectTypeId: objectType.typeId, + objectAvailable: objectType.available === true, + probeStatus: objectType.probeStatus, + propertyName: property.name, + group: property.group, + status: property.status, + defaultValue: property.default, + valueModel: { + kind: 'ordered-rgba-color-list', + elementRepresentation: 'four-channel-float-tuple', + packedElementRepresentation: '0xRRGGBBAA', + alphaSemantics: '1-opaque-0-transparent', + writable: property.status.length === 0, + }, + inputs: { + collection: ['sequence', 'iterable', 'single-tuple-color-value', 'single-non-sequence-color-value', 'integer-index-dictionary'], + dictionaryAppendIndexes: [-1, 'current-size'], + elementSetters: ['float-tuple-3-or-4', 'integer-tuple-3-or-4', 'packed-integer-0xRRGGBBAA'], + }, + dependencies: [], + applicability: { + requiredObjectTypeId: objectType.typeId, + source: 'Document.supportedTypes runtime inventory', + shapeRequired: false, + }, + }) + } +} +records.sort((left, right) => `${left.objectTypeId}.${left.propertyName}`.localeCompare(`${right.objectTypeId}.${right.propertyName}`)) +if (records.length !== 2) fail(`expected two native App::PropertyColorList records, found ${records.length}`) +const report = { + schemaVersion: 1, + status: 'pass', + baseline: { freecadVersion: runtime.freecadVersion, commit: runtime.gitCommit }, + propertyType: 'App::PropertyColorList', + recordCount: records.length, + records, + storage: { + xmlElement: 'ColorList', + fileAttribute: 'file', + nonEmptyExternalResourceName: 'property-name', + emptyResourceName: '', + externalBinary: { byteOrder: 'little-endian', count: 'uint32', element: 'uint32-packed-0xRRGGBBAA' }, + legacyBeforeVersion: '1.1', + legacyConversion: 'invert-alpha-channel', + }, + provenance: { + runtime: { path: '.cache/freecad/reference-desktop.json', bytes: runtimeContent.length, sha256: createHash('sha256').update(runtimeContent).digest('hex') }, + sources: sourcePaths.map((path, index) => ({ path, bytes: sourceContents[index].length, sha256: createHash('sha256').update(sourceContents[index]).digest('hex') })), + }, + classification: 'opaque-fcstd-proxy', + nextPhases: ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-colorlist-inventory-generated', output: 'config/freecad-property-colorlist-inventory.json', propertyType: report.propertyType, recordCount: report.recordCount }, null, 2)) diff --git a/scripts/generate-freecad-property-colorlist-promotion.mjs b/scripts/generate-freecad-property-colorlist-promotion.mjs new file mode 100644 index 0000000..e9f410f --- /dev/null +++ b/scripts/generate-freecad-property-colorlist-promotion.mjs @@ -0,0 +1,62 @@ +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const outputPath = resolve(root, 'config/freecad-property-colorlist-promotion.json') +const [inventory, success, failure, mutation, roundTrip, chrome, semantics, progress] = await Promise.all([ + load('config/freecad-property-colorlist-inventory.json'), + load('config/freecad-property-colorlist-success.json'), + load('config/freecad-property-colorlist-failure.json'), + load('config/freecad-property-colorlist-mutation.json'), + load('config/freecad-property-colorlist-roundtrip.json'), + load('config/chrome-property-colorlist-verification.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyColorList promotion generation failed: ${message}`) } +const requiredCompletedPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredCompletedPhases) if (!completed.has(`PROP-app-propertycolorlist-${phase}`)) fail(`phase ${phase} is not completed in the evidence ledger`) +if (inventory.status !== 'pass' || inventory.propertyType !== 'App::PropertyColorList' || inventory.recordCount !== 2 || inventory.records?.filter(({ valueModel }) => valueModel?.writable === true).length !== 2) fail('inventory evidence is invalid') +for (const [name, artifact] of Object.entries({ success, failure, mutation, roundTrip, chrome })) if (artifact.status !== 'pass') fail(`${name} evidence is not passing`) +const propertyType = semantics.types?.find(({ typeId }) => typeId === 'App::PropertyColorList') +if (propertyType?.support !== 'native-editable-codec' || propertyType.recordCount !== 2 || propertyType.objectTypeCount !== 2 || propertyType.statusNames?.length !== 0) fail('global property semantics did not promote App::PropertyColorList') +const opaque = semantics.supportSummary?.['opaque-fcstd-proxy'] +const editable = semantics.supportSummary?.['native-editable-codec'] +if (opaque?.typeCount !== 50 || opaque.recordCount !== 466 || editable?.typeCount !== 30 || editable.recordCount !== 4361) fail('global property support summary is not synchronized') +if (roundTrip.classification?.zeroUnknownDrift !== true || chrome.persistence?.loadedType !== 'App::PropertyColorList' || chrome.persistence.fcstdElement !== 'ColorList' || chrome.persistence.fcstdResourcePath !== 'ColourList' || chrome.persistence.fcstdResourceBytes !== 12 || chrome.release?.workerTerminated !== true) fail('round-trip or browser closure evidence is incomplete') + +const report = { + schemaVersion: 1, + status: 'pass', + taskId: 'PROP-app-propertycolorlist-I', + baseline: semantics.baseline, + propertyType: 'App::PropertyColorList', + recordCount: 2, + phaseEvidence: Object.fromEntries(requiredCompletedPhases.map((phase) => [phase, completed.get(`PROP-app-propertycolorlist-${phase}`).evidence])), + promotion: { + from: inventory.classification, + to: propertyType.support, + facadeValueModel: 'ordered-variable-rgba-array-with-external-8-bit-fcstd-packing', + writableRecords: 2, + fcstdElement: chrome.persistence.fcstdElement, + fcstdResourcePath: chrome.persistence.fcstdResourcePath, + fcstdResourceBytes: chrome.persistence.fcstdResourceBytes, + nativeRoundTripValue: roundTrip.classification.resavedValue, + browserRoundTripValue: chrome.persistence.loadedValue, + zeroUnknownDrift: roundTrip.classification.zeroUnknownDrift, + }, + exactBlockerSync: { + nativeEditableTypes: editable.typeCount, + nativeEditableRecords: editable.recordCount, + opaqueTypes: opaque.typeCount, + opaqueRecords: opaque.recordCount, + exactPromotionReady: semantics.exactPromotionReady, + exactBlocker: semantics.exactBlocker, + }, + systemExact: false, + generatedAt: new Date().toISOString(), +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-colorlist-promotion-generated', output: 'config/freecad-property-colorlist-promotion.json', promotion: report.promotion, exactBlockerSync: report.exactBlockerSync }, null, 2)) diff --git a/scripts/generate-freecad-property-direction-inventory.mjs b/scripts/generate-freecad-property-direction-inventory.mjs new file mode 100644 index 0000000..9c7b6f3 --- /dev/null +++ b/scripts/generate-freecad-property-direction-inventory.mjs @@ -0,0 +1,110 @@ +import { createHash } from 'node:crypto' +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const runtimePath = resolve(root, '.cache/freecad/reference-desktop.json') +const sourcePaths = [ + '.cache/freecad/FreeCAD/src/App/PropertyGeo.h', + '.cache/freecad/FreeCAD/src/App/PropertyGeo.cpp', + '.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.h', + '.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.cpp', + '.cache/freecad/FreeCAD/src/Mod/Part/App/FeatureMirroring.h', + '.cache/freecad/FreeCAD/src/Mod/Part/App/FeatureMirroring.cpp', + '.cache/freecad/FreeCAD/src/Mod/Part/App/FeatureProjectOnSurface.h', + '.cache/freecad/FreeCAD/src/Mod/Part/App/FeatureProjectOnSurface.cpp', +] +const outputPath = resolve(root, 'config/freecad-property-direction-inventory.json') +const runtimeContent = await readFile(runtimePath) +const runtime = JSON.parse(runtimeContent) +const sourceContents = await Promise.all(sourcePaths.map((path) => readFile(resolve(root, path)))) +const fail = (message) => { throw new Error(`FreeCAD PropertyDirection inventory generation failed: ${message}`) } +const vector = (value) => { + const match = /^Vector \(([-+0-9.eE]+), ([-+0-9.eE]+), ([-+0-9.eE]+)\)$/.exec(value) + if (!match) fail(`unexpected native vector value: ${value}`) + return match.slice(1).map(Number) +} + +if (runtime.schemaVersion !== 1 || runtime.freecadVersion !== '1.1.1' || runtime.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('desktop oracle is not the locked FreeCAD baseline') +const hostContracts = { + 'Part::Mirroring.Normal': { + dependencies: [ + { propertyName: 'Source', role: 'shape-source', requiredForExecution: true }, + { propertyName: 'Base', role: 'plane-origin', requiredForExecution: true }, + { propertyName: 'MirrorPlane', role: 'optional-plane-override', requiredForExecution: false, overrides: ['Base', 'Normal'], overriddenStatus: 'ReadOnly' }, + ], + consumer: 'gp_Ax2(gp_Pnt(Base), gp_Dir(Normal))', + }, + 'Part::ProjectOnSurface.Direction': { + dependencies: [ + { propertyName: 'SupportFace', role: 'single-support-face', requiredForExecution: true }, + { propertyName: 'Projection', role: 'projected-shape-list', requiredForExecution: true }, + ], + consumer: 'gp_Dir(Direction)', + }, +} +const records = [] +for (const objectType of runtime.runtimeObjects?.types ?? []) { + for (const property of objectType.properties ?? []) { + if (property.typeId !== 'App::PropertyDirection') continue + const contract = hostContracts[`${objectType.typeId}.${property.name}`] + if (!contract) fail(`missing host contract for ${objectType.typeId}.${property.name}`) + records.push({ + objectTypeId: objectType.typeId, + objectAvailable: objectType.available === true, + probeStatus: objectType.probeStatus, + propertyName: property.name, + group: property.group, + status: property.status, + defaultDisplayValue: property.default, + defaultValue: vector(property.default), + valueModel: { + kind: 'three-component-direction-vector', + representation: 'Base::Vector3d', + normalizationAtPropertyBoundary: 'none', + unit: 'Length', + writable: property.status.length === 0, + }, + inputs: { + accepted: ['Base.Vector', 'tuple-of-three-float-or-integer-components'], + listAccepted: false, + componentPaths: ['x', 'y', 'z'], + }, + editor: 'Gui::PropertyEditor::PropertyDirectionItem', + dependencies: contract.dependencies, + applicability: { + requiredObjectTypeId: objectType.typeId, + source: 'Document.supportedTypes runtime inventory', + propertyWriteRequiresShape: false, + hostExecutionRequiresShapeInputs: true, + nonZeroRequiredByConsumer: true, + consumer: contract.consumer, + }, + }) + } +} +records.sort((left, right) => `${left.objectTypeId}.${left.propertyName}`.localeCompare(`${right.objectTypeId}.${right.propertyName}`)) +if (records.length !== 2) fail(`expected two native App::PropertyDirection records, found ${records.length}`) +const report = { + schemaVersion: 1, + status: 'pass', + baseline: { freecadVersion: runtime.freecadVersion, commit: runtime.gitCommit }, + propertyType: 'App::PropertyDirection', + recordCount: records.length, + records, + storage: { + inheritedFrom: 'App::PropertyVector', + xmlElement: 'PropertyVector', + attributes: ['valueX', 'valueY', 'valueZ'], + scalarEncoding: 'decimal-double', + externalResource: false, + }, + provenance: { + runtime: { path: '.cache/freecad/reference-desktop.json', bytes: runtimeContent.length, sha256: createHash('sha256').update(runtimeContent).digest('hex') }, + sources: sourcePaths.map((path, index) => ({ path, bytes: sourceContents[index].length, sha256: createHash('sha256').update(sourceContents[index]).digest('hex') })), + }, + classification: 'opaque-fcstd-proxy', + nextPhases: ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-direction-inventory-generated', output: 'config/freecad-property-direction-inventory.json', propertyType: report.propertyType, recordCount: report.recordCount }, null, 2)) diff --git a/scripts/generate-freecad-property-direction-promotion.mjs b/scripts/generate-freecad-property-direction-promotion.mjs new file mode 100644 index 0000000..d1a82e7 --- /dev/null +++ b/scripts/generate-freecad-property-direction-promotion.mjs @@ -0,0 +1,60 @@ +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const outputPath = resolve(root, 'config/freecad-property-direction-promotion.json') +const [inventory, success, failure, mutation, roundTrip, chrome, semantics, progress] = await Promise.all([ + load('config/freecad-property-direction-inventory.json'), + load('config/freecad-property-direction-success.json'), + load('config/freecad-property-direction-failure.json'), + load('config/freecad-property-direction-mutation.json'), + load('config/freecad-property-direction-roundtrip.json'), + load('config/chrome-property-direction-verification.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyDirection promotion generation failed: ${message}`) } +const requiredCompletedPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredCompletedPhases) if (!completed.has(`PROP-app-propertydirection-${phase}`)) fail(`phase ${phase} is not completed in the evidence ledger`) +if (inventory.status !== 'pass' || inventory.propertyType !== 'App::PropertyDirection' || inventory.recordCount !== 2 || inventory.records?.filter(({ valueModel }) => valueModel?.writable === true).length !== 2) fail('inventory evidence is invalid') +for (const [name, artifact] of Object.entries({ success, failure, mutation, roundTrip, chrome })) if (artifact.status !== 'pass') fail(`${name} evidence is not passing`) +const propertyType = semantics.types?.find(({ typeId }) => typeId === 'App::PropertyDirection') +if (propertyType?.support !== 'native-editable-codec' || propertyType.recordCount !== 2 || propertyType.objectTypeCount !== 2 || propertyType.statusNames?.length !== 0) fail('global property semantics did not promote App::PropertyDirection') +const opaque = semantics.supportSummary?.['opaque-fcstd-proxy'] +const editable = semantics.supportSummary?.['native-editable-codec'] +if (opaque?.typeCount !== 50 || opaque.recordCount !== 466 || editable?.typeCount !== 30 || editable.recordCount !== 4361) fail('global property support summary is not synchronized') +if (roundTrip.classification?.zeroUnknownDrift !== true || chrome.persistence?.loadedType !== 'App::PropertyDirection' || chrome.persistence.fcstdElement !== 'PropertyVector' || chrome.persistence.fcstdValue !== JSON.stringify({ x: 0.25, y: -0.5, z: 1.5 }) || chrome.release?.workerTerminated !== true) fail('round-trip or browser closure evidence is incomplete') + +const report = { + schemaVersion: 1, + status: 'pass', + taskId: 'PROP-app-propertydirection-I', + baseline: semantics.baseline, + propertyType: 'App::PropertyDirection', + recordCount: 2, + phaseEvidence: Object.fromEntries(requiredCompletedPhases.map((phase) => [phase, completed.get(`PROP-app-propertydirection-${phase}`).evidence])), + promotion: { + from: inventory.classification, + to: propertyType.support, + facadeValueModel: 'three-finite-vector-components-with-native-propertyvector-fcstd-payload', + writableRecords: 2, + fcstdElement: chrome.persistence.fcstdElement, + nativeRoundTripValue: roundTrip.classification.resavedValue, + browserRoundTripValue: chrome.persistence.loadedValue, + zeroUnknownDrift: roundTrip.classification.zeroUnknownDrift, + }, + exactBlockerSync: { + nativeEditableTypes: editable.typeCount, + nativeEditableRecords: editable.recordCount, + opaqueTypes: opaque.typeCount, + opaqueRecords: opaque.recordCount, + exactPromotionReady: semantics.exactPromotionReady, + exactBlocker: semantics.exactBlocker, + }, + systemExact: false, + generatedAt: new Date().toISOString(), +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-direction-promotion-generated', output: 'config/freecad-property-direction-promotion.json', promotion: report.promotion, exactBlockerSync: report.exactBlockerSync }, null, 2)) diff --git a/scripts/generate-freecad-property-file-inventory.mjs b/scripts/generate-freecad-property-file-inventory.mjs new file mode 100644 index 0000000..1d66fb6 --- /dev/null +++ b/scripts/generate-freecad-property-file-inventory.mjs @@ -0,0 +1,68 @@ +import { createHash } from 'node:crypto' +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const runtimePath = '.cache/freecad/reference-desktop.json' +const sourcePaths = [ + '.cache/freecad/FreeCAD/src/App/PropertyFile.h', + '.cache/freecad/FreeCAD/src/App/PropertyFile.cpp', + '.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.h', + '.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.cpp', +] +const outputPath = resolve(root, 'config/freecad-property-file-inventory.json') +const runtimeContent = await readFile(resolve(root, runtimePath)) +const runtime = JSON.parse(runtimeContent) +const sourceContents = await Promise.all(sourcePaths.map((path) => readFile(resolve(root, path)))) +const fail = (message) => { throw new Error(`FreeCAD PropertyFile inventory generation failed: ${message}`) } +if (runtime.schemaVersion !== 1 || runtime.freecadVersion !== '1.1.1' || runtime.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('desktop oracle is not the locked FreeCAD baseline') +const records = [] +for (const objectType of runtime.runtimeObjects?.types ?? []) { + for (const property of objectType.properties ?? []) { + if (property.typeId !== 'App::PropertyFile') continue + records.push({ + objectTypeId: objectType.typeId, + objectAvailable: objectType.available === true, + probeStatus: objectType.probeStatus, + propertyName: property.name, + group: property.group, + status: property.status, + defaultRaw: property.default, + valueModel: { + kind: 'path-string', + representation: 'App::PropertyString-derived UTF-8 path', + defaultValue: property.default, + writable: property.status.length === 0, + externalResource: true, + browserEditBoundary: 'host-absolute-paths are not written into the browser project; use an explicit project resource reference', + }, + inputs: { + accepted: ['string', '{filename:string,filter?:string}'], + componentPaths: ['filename', 'filter'], + emptyStringAccepted: true, + }, + editor: 'Gui::PropertyEditor::PropertyFileItem', + dependencies: [], + applicability: { requiredObjectTypeId: objectType.typeId, source: 'Document.supportedTypes runtime inventory', propertyWriteRequiresShape: false }, + }) + } +} +records.sort((left, right) => `${left.objectTypeId}.${left.propertyName}`.localeCompare(`${right.objectTypeId}.${right.propertyName}`)) +if (records.length !== 16) fail(`expected 16 native App::PropertyFile records, found ${records.length}`) +const report = { + schemaVersion: 1, + status: 'pass', + baseline: { freecadVersion: runtime.freecadVersion, commit: runtime.gitCommit }, + propertyType: 'App::PropertyFile', + recordCount: records.length, + records, + storage: { inheritedFrom: 'App::PropertyString', xmlElement: 'String', scalarEncoding: 'UTF-8 path string', externalResource: true, absoluteHostPathPolicy: 'preserve-or-reject; never rewrite into browser project' }, + provenance: { + runtime: { path: runtimePath, bytes: runtimeContent.length, sha256: createHash('sha256').update(runtimeContent).digest('hex') }, + sources: sourcePaths.map((path, index) => ({ path, bytes: sourceContents[index].length, sha256: createHash('sha256').update(sourceContents[index]).digest('hex') })), + }, + classification: 'opaque-fcstd-proxy', + nextPhases: ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-file-inventory-generated', output: 'config/freecad-property-file-inventory.json', propertyType: report.propertyType, recordCount: report.recordCount }, null, 2)) diff --git a/scripts/generate-freecad-property-file-promotion.mjs b/scripts/generate-freecad-property-file-promotion.mjs new file mode 100644 index 0000000..995ff94 --- /dev/null +++ b/scripts/generate-freecad-property-file-promotion.mjs @@ -0,0 +1,62 @@ +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const outputPath = resolve(root, 'config/freecad-property-file-promotion.json') +const [inventory, success, failure, mutation, roundTrip, chrome, semantics, progress] = await Promise.all([ + load('config/freecad-property-file-inventory.json'), + load('config/freecad-property-file-success.json'), + load('config/freecad-property-file-failure.json'), + load('config/freecad-property-file-mutation.json'), + load('config/freecad-property-file-roundtrip.json'), + load('config/chrome-property-file-verification.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyFile promotion generation failed: ${message}`) } +const requiredCompletedPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredCompletedPhases) if (!completed.has(`PROP-app-propertyfile-${phase}`)) fail(`phase ${phase} is not completed in the evidence ledger`) +if (inventory.status !== 'pass' || inventory.propertyType !== 'App::PropertyFile' || inventory.recordCount !== 16 || inventory.records?.filter(({ valueModel }) => valueModel?.writable === true).length !== 16) fail('inventory evidence is invalid') +for (const [name, artifact] of Object.entries({ success, failure, mutation, roundTrip, chrome })) if (artifact.status !== 'pass') fail(`${name} evidence is not passing`) +const propertyType = semantics.types?.find(({ typeId }) => typeId === 'App::PropertyFile') +if (propertyType?.support !== 'native-editable-codec' || propertyType.recordCount !== 16 || propertyType.objectTypeCount !== 12 || propertyType.statusNames?.length !== 0) fail('global property semantics did not promote App::PropertyFile') +const opaque = semantics.supportSummary?.['opaque-fcstd-proxy'] +const editable = semantics.supportSummary?.['native-editable-codec'] +if (opaque?.typeCount !== 50 || opaque.recordCount !== 466 || editable?.typeCount !== 30 || editable.recordCount !== 4361) fail('global property support summary is not synchronized') +if (roundTrip.classification?.zeroUnknownDrift !== true || roundTrip.classification.externalResourceBoundary !== 'project-relative-path; asset bytes remain external to FCStd' || chrome.persistence?.loadedType !== 'App::PropertyFile' || chrome.persistence.fcstdElement !== 'String' || chrome.persistence.fcstdValue !== 'project-files/chrome-updated.obj' || chrome.resource?.released !== true || chrome.release?.workerTerminated !== true) fail('round-trip or browser closure evidence is incomplete') + +const report = { + schemaVersion: 1, + status: 'pass', + taskId: 'PROP-app-propertyfile-I', + baseline: semantics.baseline, + propertyType: 'App::PropertyFile', + recordCount: 16, + phaseEvidence: Object.fromEntries(requiredCompletedPhases.map((phase) => [phase, completed.get(`PROP-app-propertyfile-${phase}`).evidence])), + promotion: { + from: inventory.classification, + to: propertyType.support, + facadeValueModel: 'safe-project-relative-path-string-with-native-string-fcstd-payload', + writableRecords: 16, + objectTypeCount: propertyType.objectTypeCount, + fcstdElement: chrome.persistence.fcstdElement, + nativeRoundTripValue: roundTrip.classification.resavedValue, + browserRoundTripValue: chrome.persistence.loadedValue, + externalResourceBoundary: roundTrip.classification.externalResourceBoundary, + zeroUnknownDrift: roundTrip.classification.zeroUnknownDrift, + }, + exactBlockerSync: { + nativeEditableTypes: editable.typeCount, + nativeEditableRecords: editable.recordCount, + opaqueTypes: opaque.typeCount, + opaqueRecords: opaque.recordCount, + exactPromotionReady: semantics.exactPromotionReady, + exactBlocker: semantics.exactBlocker, + }, + systemExact: false, + generatedAt: new Date().toISOString(), +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-file-promotion-generated', output: 'config/freecad-property-file-promotion.json', promotion: report.promotion, exactBlockerSync: report.exactBlockerSync }, null, 2)) diff --git a/scripts/generate-freecad-property-fileincluded-inventory.mjs b/scripts/generate-freecad-property-fileincluded-inventory.mjs new file mode 100644 index 0000000..ad1c90f --- /dev/null +++ b/scripts/generate-freecad-property-fileincluded-inventory.mjs @@ -0,0 +1,128 @@ +import { createHash } from 'node:crypto' +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const runtimePath = '.cache/freecad/reference-desktop.json' +const sourcePaths = [ + '.cache/freecad/FreeCAD/src/App/PropertyFile.h', + '.cache/freecad/FreeCAD/src/App/PropertyFile.cpp', + '.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.h', + '.cache/freecad/FreeCAD/src/Gui/propertyeditor/PropertyItem.cpp', + '.cache/freecad/FreeCAD/src/App/DocumentObjectFileIncluded.cpp', + '.cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawViewSection.cpp', + '.cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawGeomHatch.cpp', + '.cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawHatch.cpp', + '.cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawSVGTemplate.cpp', + '.cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawTileWeld.cpp', + '.cache/freecad/FreeCAD/src/Mod/TechDraw/App/DrawViewImage.cpp', +] +const outputPath = resolve(root, 'config/freecad-property-fileincluded-inventory.json') +const [runtimeContent, ...sourceContents] = await Promise.all([ + readFile(resolve(root, runtimePath)), + ...sourcePaths.map((path) => readFile(resolve(root, path))), +]) +const runtime = JSON.parse(runtimeContent) +const fail = (message) => { throw new Error(`FreeCAD PropertyFileIncluded inventory generation failed: ${message}`) } + +if (runtime.schemaVersion !== 1 || runtime.freecadVersion !== '1.1.1' || runtime.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('desktop oracle is not the locked FreeCAD baseline') + +const dependencySources = new Map([ + ['TechDraw::DrawComplexSection.PatIncluded', 'FileGeomPattern'], + ['TechDraw::DrawComplexSection.SvgIncluded', 'FileHatchPattern'], + ['TechDraw::DrawComplexSectionPython.PatIncluded', 'FileGeomPattern'], + ['TechDraw::DrawComplexSectionPython.SvgIncluded', 'FileHatchPattern'], + ['TechDraw::DrawGeomHatch.PatIncluded', 'FilePattern'], + ['TechDraw::DrawHatch.SvgIncluded', 'HatchPattern'], + ['TechDraw::DrawSVGTemplate.PageResult', 'Template'], + ['TechDraw::DrawTileWeld.SymbolIncluded', 'SymbolFile'], + ['TechDraw::DrawTileWeldPython.SymbolIncluded', 'SymbolFile'], + ['TechDraw::DrawViewImage.ImageIncluded', 'ImageFile'], + ['TechDraw::DrawViewSection.PatIncluded', 'FileGeomPattern'], + ['TechDraw::DrawViewSection.SvgIncluded', 'FileHatchPattern'], + ['TechDraw::DrawViewSectionPython.PatIncluded', 'FileGeomPattern'], + ['TechDraw::DrawViewSectionPython.SvgIncluded', 'FileHatchPattern'], +]) +const normalizeStatus = (status) => status.map((entry) => entry === 27 ? 'PropOutput' : String(entry)) +const records = [] +for (const objectType of runtime.runtimeObjects?.types ?? []) { + for (const property of objectType.properties ?? []) { + if (property.typeId !== 'App::PropertyFileIncluded') continue + const key = `${objectType.typeId}.${property.name}` + const sourceProperty = dependencySources.get(key) + records.push({ + objectTypeId: objectType.typeId, + objectAvailable: objectType.available === true, + probeStatus: objectType.probeStatus, + propertyName: property.name, + group: property.group, + status: property.status, + normalizedStatus: normalizeStatus(property.status), + defaultRaw: property.default, + defaultKind: property.default === '' ? 'empty' : 'document-transient-copy', + valueModel: { + kind: 'included-file-resource', + representation: 'read-only document-transient file backed by embedded FCStd bytes', + writableByStatus: property.status.length === 0, + pathIsRuntimeOnly: true, + bytesAreAuthoritative: true, + }, + inputs: { + accepted: ['utf8-string-path', 'bytes-path', 'open-io-file', '[source-path,archive-name]', '{filename:string,filter?:string}'], + sourceFileMustExist: true, + emptyStringBehavior: 'accepted-no-op; does not clear an existing value', + sameTransientPathBehavior: 'rejected', + }, + dependency: sourceProperty ? { + sourceProperty, + relation: 'host-onChanged-copies-source-bytes-into-included-property', + } : null, + editor: 'Gui::PropertyEditor::PropertyTransientFileItem', + applicability: { + requiredObjectTypeId: objectType.typeId, + propertyWriteRequiresShape: false, + source: 'Document.supportedTypes runtime inventory', + }, + }) + } +} +records.sort((left, right) => `${left.objectTypeId}.${left.propertyName}`.localeCompare(`${right.objectTypeId}.${right.propertyName}`)) +if (records.length !== 20) fail(`expected 20 native App::PropertyFileIncluded records, found ${records.length}`) +if (new Set(records.map(({ objectTypeId }) => objectTypeId)).size !== 15) fail('expected 15 native host object types') +if (records.filter(({ valueModel }) => valueModel.writableByStatus).length !== 11 || records.filter(({ dependency }) => dependency !== null).length !== 14) fail('status or dependency partition changed') + +const report = { + schemaVersion: 1, + status: 'pass', + baseline: { freecadVersion: runtime.freecadVersion, commit: runtime.gitCommit }, + propertyType: 'App::PropertyFileIncluded', + recordCount: records.length, + objectTypeCount: new Set(records.map(({ objectTypeId }) => objectTypeId)).size, + records, + setterSemantics: { + externalSource: 'copy bytes into the document transient directory', + writableTransientSource: 'rename into the selected transient destination', + replacement: 'delete the previous transient copy unless undo owns it', + destinationPermissions: 'read-only', + archiveNameCollision: 'append a positive integer before the extension', + undoRedo: 'Copy/Paste move or copy transient files while preserving per-property ownership', + }, + storage: { + xmlElement: 'FileIncluded', + archiveAttribute: 'file', + archiveResource: 'separate FCStd ZIP entry containing byte-identical file data', + forceXmlAttribute: 'data', + forceXmlResource: 'binary data embedded in the XML stream', + emptyEncoding: '', + restoredValue: 'document transient path; not a portable semantic path', + browserBoundary: 'project resource identity plus bytes; never expose or persist an ambient host path', + }, + provenance: { + runtime: { path: runtimePath, bytes: runtimeContent.length, sha256: createHash('sha256').update(runtimeContent).digest('hex') }, + sources: sourcePaths.map((path, index) => ({ path, bytes: sourceContents[index].length, sha256: createHash('sha256').update(sourceContents[index]).digest('hex') })), + }, + classification: 'opaque-fcstd-proxy', + nextPhases: ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-fileincluded-inventory-generated', output: 'config/freecad-property-fileincluded-inventory.json', propertyType: report.propertyType, recordCount: report.recordCount, objectTypeCount: report.objectTypeCount, writableByStatus: records.filter(({ valueModel }) => valueModel.writableByStatus).length, derivedRecords: records.filter(({ dependency }) => dependency !== null).length }, null, 2)) diff --git a/scripts/generate-freecad-property-fileincluded-promotion.mjs b/scripts/generate-freecad-property-fileincluded-promotion.mjs new file mode 100644 index 0000000..14bde25 --- /dev/null +++ b/scripts/generate-freecad-property-fileincluded-promotion.mjs @@ -0,0 +1,66 @@ +import { readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse) +const outputPath = resolve(root, 'config/freecad-property-fileincluded-promotion.json') +const [inventory, success, failure, mutation, roundTrip, chrome, semantics, progress] = await Promise.all([ + load('config/freecad-property-fileincluded-inventory.json'), + load('config/freecad-property-fileincluded-success.json'), + load('config/freecad-property-fileincluded-failure.json'), + load('config/freecad-property-fileincluded-mutation.json'), + load('config/freecad-property-fileincluded-roundtrip.json'), + load('config/chrome-property-fileincluded-verification.json'), + load('config/freecad-native-property-semantics.json'), + load('config/freecad-follow-up-task-progress.json'), +]) +const fail = (message) => { throw new Error(`FreeCAD PropertyFileIncluded promotion generation failed: ${message}`) } +const requiredCompletedPhases = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] +const completed = new Map(progress.completedTasks?.map((entry) => [entry.id, entry]) ?? []) +for (const phase of requiredCompletedPhases) if (!completed.has(`PROP-app-propertyfileincluded-${phase}`)) fail(`phase ${phase} is not completed in the evidence ledger`) +if (inventory.status !== 'pass' || inventory.propertyType !== 'App::PropertyFileIncluded' || inventory.recordCount !== 20 || inventory.objectTypeCount !== 15 || inventory.records?.filter(({ valueModel }) => valueModel?.writableByStatus === true).length !== 11) fail('inventory evidence is invalid') +for (const [name, artifact] of Object.entries({ success, failure, mutation, roundTrip, chrome })) if (artifact.status !== 'pass') fail(`${name} evidence is not passing`) +const propertyType = semantics.types?.find(({ typeId }) => typeId === 'App::PropertyFileIncluded') +if (propertyType?.support !== 'native-editable-codec' || propertyType.recordCount !== 20 || propertyType.objectTypeCount !== 15 || propertyType.statusNames?.join(',') !== 'PropOutput,ReadOnly') fail('global property semantics did not promote App::PropertyFileIncluded') +const opaque = semantics.supportSummary?.['opaque-fcstd-proxy'] +const editable = semantics.supportSummary?.['native-editable-codec'] +if (opaque?.typeCount !== 50 || opaque.recordCount !== 466 || editable?.typeCount !== 30 || editable.recordCount !== 4361) fail('global property support summary is not synchronized') +if (roundTrip.classification?.zeroUnknownDrift !== true || roundTrip.classification.archiveName !== 'payload.bin' || roundTrip.classification.resavedResourceMatches !== true || chrome.persistence?.loadedType !== 'App::PropertyFileIncluded' || chrome.persistence.fcstdElement !== 'FileIncluded' || chrome.persistence.fcstdResourceMatches !== true || chrome.resource?.documentRoundTrip !== true || chrome.resource.independentReleased !== true || chrome.release?.workerTerminated !== true) fail('round-trip or browser closure evidence is incomplete') + +const report = { + schemaVersion: 1, + status: 'pass', + taskId: 'PROP-app-propertyfileincluded-I', + baseline: semantics.baseline, + propertyType: 'App::PropertyFileIncluded', + recordCount: 20, + phaseEvidence: Object.fromEntries(requiredCompletedPhases.map((phase) => [phase, completed.get(`PROP-app-propertyfileincluded-${phase}`).evidence])), + promotion: { + from: inventory.classification, + to: propertyType.support, + facadeValueModel: 'project-resource-identity-and-authoritative-bytes-with-native-fileincluded-fcstd-resource', + writableRecords: 11, + readOnlyRecords: 8, + outputRecords: 1, + objectTypeCount: propertyType.objectTypeCount, + fcstdElement: chrome.persistence.fcstdElement, + nativeArchiveName: roundTrip.classification.archiveName, + nativeRoundTripSha256: roundTrip.classification.resavedSha256, + browserArchiveName: chrome.persistence.fcstdResourcePath, + browserRoundTripBytes: chrome.persistence.fcstdResourceBytes, + externalResourceBoundary: roundTrip.classification.externalResourceBoundary, + zeroUnknownDrift: roundTrip.classification.zeroUnknownDrift, + }, + exactBlockerSync: { + nativeEditableTypes: editable.typeCount, + nativeEditableRecords: editable.recordCount, + opaqueTypes: opaque.typeCount, + opaqueRecords: opaque.recordCount, + exactPromotionReady: semantics.exactPromotionReady, + exactBlocker: semantics.exactBlocker, + }, + systemExact: false, + generatedAt: new Date().toISOString(), +} +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: 'freecad-property-fileincluded-promotion-generated', output: 'config/freecad-property-fileincluded-promotion.json', promotion: report.promotion, exactBlockerSync: report.exactBlockerSync }, null, 2)) diff --git a/scripts/run-chrome-property-acceleration.mjs b/scripts/run-chrome-property-acceleration.mjs new file mode 100644 index 0000000..8f020b7 --- /dev/null +++ b/scripts/run-chrome-property-acceleration.mjs @@ -0,0 +1,61 @@ +import { createServer } from 'node:http' +import { existsSync } from 'node:fs' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' +import { spawn } from 'node:child_process' +import { createChromeProfile, removeChromeProfile } from './chrome-profile.mjs' + +const root = resolve(new URL('..', import.meta.url).pathname) +const reportPath = resolve(root, 'config/chrome-property-acceleration-verification.json') +const waitForPort = (child) => new Promise((resolvePort, reject) => { + let output = '' + const timer = setTimeout(() => reject(new Error(`Vite did not announce a port: ${output.slice(-2000)}`)), 30_000) + const onData = (chunk) => { output += String(chunk); const match = output.match(/http:\/\/127\.0\.0\.1:(\d+)/); if (match) { clearTimeout(timer); resolvePort(Number(match[1])) } } + child.stdout.on('data', onData) + child.stderr.on('data', onData) +}) + +const vite = spawn('./nodew', ['node_modules/vite/bin/vite.js', '--host', '127.0.0.1'], { cwd: root, stdio: ['ignore', 'pipe', 'pipe'] }) +let vitePort +try { vitePort = await waitForPort(vite) } catch (error) { vite.kill('SIGTERM'); throw error } +let resolveReport +const reportPromise = new Promise((resolveValue) => { resolveReport = resolveValue }) +const server = createServer(async (request, response) => { + response.setHeader('Cross-Origin-Opener-Policy', 'same-origin') + response.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + response.setHeader('Cross-Origin-Resource-Policy', 'same-origin') + if (request.method === 'POST' && request.url === '/__chrome-property-acceleration-report') { + let body = '' + request.setEncoding('utf8') + request.on('data', (chunk) => { body += String(chunk) }) + request.on('end', async () => { const report = JSON.parse(body); await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`); resolveReport(report); response.writeHead(204); response.end() }) + return + } + try { + const upstream = await fetch(`http://127.0.0.1:${vitePort}${request.url}`, { headers: { ...request.headers } }) + response.writeHead(upstream.status, Object.fromEntries(upstream.headers.entries())) + response.end(Buffer.from(await upstream.arrayBuffer())) + } catch (error) { response.writeHead(502); response.end(String(error)) } +}) +await new Promise((resolveServer) => server.listen(0, '127.0.0.1', resolveServer)) +const port = server.address().port +const executable = process.env.CHROME_BIN || '/home/mes123456/.local/bin/google-chrome' +if (!existsSync(executable)) throw new Error(`Chrome executable is missing: ${executable}`) +const chromeProfile = await createChromeProfile('property-acceleration') +const chrome = spawn(executable, ['--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--noerrdialogs', '--no-first-run', `--user-data-dir=${chromeProfile}`, `http://127.0.0.1:${port}/chrome-property-acceleration-harness.html`], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'] }) +let chromeStderr = '' +chrome.stderr.on('data', (chunk) => { chromeStderr += String(chunk) }) +let timeoutId +const timeoutReport = new Promise((resolveTimeout) => { timeoutId = setTimeout(() => resolveTimeout({ status: 'timeout', browserId: 'chrome' }), 120_000) }) +const report = await Promise.race([reportPromise, timeoutReport]) +clearTimeout(timeoutId) +chrome.kill('SIGTERM') +vite.kill('SIGTERM') +server.closeAllConnections?.() +server.close() +await removeChromeProfile(chromeProfile) +console.log(JSON.stringify(report, null, 2)) +if (report.status !== 'pass') { + if (chromeStderr) console.error(chromeStderr.slice(-3000)) + process.exit(1) +} diff --git a/scripts/run-chrome-property-area.mjs b/scripts/run-chrome-property-area.mjs new file mode 100644 index 0000000..cf3bd71 --- /dev/null +++ b/scripts/run-chrome-property-area.mjs @@ -0,0 +1,61 @@ +import { createServer } from 'node:http' +import { existsSync } from 'node:fs' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' +import { spawn } from 'node:child_process' +import { createChromeProfile, removeChromeProfile } from './chrome-profile.mjs' + +const root = resolve(new URL('..', import.meta.url).pathname) +const reportPath = resolve(root, 'config/chrome-property-area-verification.json') +const waitForPort = (child) => new Promise((resolvePort, reject) => { + let output = '' + const timer = setTimeout(() => reject(new Error(`Vite did not announce a port: ${output.slice(-2000)}`)), 30_000) + const onData = (chunk) => { output += String(chunk); const match = output.match(/http:\/\/127\.0\.0\.1:(\d+)/); if (match) { clearTimeout(timer); resolvePort(Number(match[1])) } } + child.stdout.on('data', onData) + child.stderr.on('data', onData) +}) + +const vite = spawn('./nodew', ['node_modules/vite/bin/vite.js', '--host', '127.0.0.1'], { cwd: root, stdio: ['ignore', 'pipe', 'pipe'] }) +let vitePort +try { vitePort = await waitForPort(vite) } catch (error) { vite.kill('SIGTERM'); throw error } +let resolveReport +const reportPromise = new Promise((resolveValue) => { resolveReport = resolveValue }) +const server = createServer(async (request, response) => { + response.setHeader('Cross-Origin-Opener-Policy', 'same-origin') + response.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + response.setHeader('Cross-Origin-Resource-Policy', 'same-origin') + if (request.method === 'POST' && request.url === '/__chrome-property-area-report') { + let body = '' + request.setEncoding('utf8') + request.on('data', (chunk) => { body += String(chunk) }) + request.on('end', async () => { const report = JSON.parse(body); await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`); resolveReport(report); response.writeHead(204); response.end() }) + return + } + try { + const upstream = await fetch(`http://127.0.0.1:${vitePort}${request.url}`, { headers: { ...request.headers } }) + response.writeHead(upstream.status, Object.fromEntries(upstream.headers.entries())) + response.end(Buffer.from(await upstream.arrayBuffer())) + } catch (error) { response.writeHead(502); response.end(String(error)) } +}) +await new Promise((resolveServer) => server.listen(0, '127.0.0.1', resolveServer)) +const port = server.address().port +const executable = process.env.CHROME_BIN || '/home/mes123456/.local/bin/google-chrome' +if (!existsSync(executable)) throw new Error(`Chrome executable is missing: ${executable}`) +const chromeProfile = await createChromeProfile('property-area') +const chrome = spawn(executable, ['--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--noerrdialogs', '--no-first-run', `--user-data-dir=${chromeProfile}`, `http://127.0.0.1:${port}/chrome-property-area-harness.html`], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'] }) +let chromeStderr = '' +chrome.stderr.on('data', (chunk) => { chromeStderr += String(chunk) }) +let timeoutId +const timeoutReport = new Promise((resolveTimeout) => { timeoutId = setTimeout(() => resolveTimeout({ status: 'timeout', browserId: 'chrome' }), 120_000) }) +const report = await Promise.race([reportPromise, timeoutReport]) +clearTimeout(timeoutId) +chrome.kill('SIGTERM') +vite.kill('SIGTERM') +server.closeAllConnections?.() +server.close() +await removeChromeProfile(chromeProfile) +console.log(JSON.stringify(report, null, 2)) +if (report.status !== 'pass') { + if (chromeStderr) console.error(chromeStderr.slice(-3000)) + process.exit(1) +} diff --git a/scripts/run-chrome-property-boollist.mjs b/scripts/run-chrome-property-boollist.mjs new file mode 100644 index 0000000..4ab9b25 --- /dev/null +++ b/scripts/run-chrome-property-boollist.mjs @@ -0,0 +1,61 @@ +import { createServer } from 'node:http' +import { existsSync } from 'node:fs' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' +import { spawn } from 'node:child_process' +import { createChromeProfile, removeChromeProfile } from './chrome-profile.mjs' + +const root = resolve(new URL('..', import.meta.url).pathname) +const reportPath = resolve(root, 'config/chrome-property-boollist-verification.json') +const waitForPort = (child) => new Promise((resolvePort, reject) => { + let output = '' + const timer = setTimeout(() => reject(new Error(`Vite did not announce a port: ${output.slice(-2000)}`)), 30_000) + const onData = (chunk) => { output += String(chunk); const match = output.match(/http:\/\/127\.0\.0\.1:(\d+)/); if (match) { clearTimeout(timer); resolvePort(Number(match[1])) } } + child.stdout.on('data', onData) + child.stderr.on('data', onData) +}) + +const vite = spawn('./nodew', ['node_modules/vite/bin/vite.js', '--host', '127.0.0.1'], { cwd: root, stdio: ['ignore', 'pipe', 'pipe'] }) +let vitePort +try { vitePort = await waitForPort(vite) } catch (error) { vite.kill('SIGTERM'); throw error } +let resolveReport +const reportPromise = new Promise((resolveValue) => { resolveReport = resolveValue }) +const server = createServer(async (request, response) => { + response.setHeader('Cross-Origin-Opener-Policy', 'same-origin') + response.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + response.setHeader('Cross-Origin-Resource-Policy', 'same-origin') + if (request.method === 'POST' && request.url === '/__chrome-property-boollist-report') { + let body = '' + request.setEncoding('utf8') + request.on('data', (chunk) => { body += String(chunk) }) + request.on('end', async () => { const report = JSON.parse(body); await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`); resolveReport(report); response.writeHead(204); response.end() }) + return + } + try { + const upstream = await fetch(`http://127.0.0.1:${vitePort}${request.url}`, { headers: { ...request.headers } }) + response.writeHead(upstream.status, Object.fromEntries(upstream.headers.entries())) + response.end(Buffer.from(await upstream.arrayBuffer())) + } catch (error) { response.writeHead(502); response.end(String(error)) } +}) +await new Promise((resolveServer) => server.listen(0, '127.0.0.1', resolveServer)) +const port = server.address().port +const executable = process.env.CHROME_BIN || '/home/mes123456/.local/bin/google-chrome' +if (!existsSync(executable)) throw new Error(`Chrome executable is missing: ${executable}`) +const chromeProfile = await createChromeProfile('property-boollist') +const chrome = spawn(executable, ['--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--noerrdialogs', '--no-first-run', `--user-data-dir=${chromeProfile}`, `http://127.0.0.1:${port}/chrome-property-boollist-harness.html`], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'] }) +let chromeStderr = '' +chrome.stderr.on('data', (chunk) => { chromeStderr += String(chunk) }) +let timeoutId +const timeoutReport = new Promise((resolveTimeout) => { timeoutId = setTimeout(() => resolveTimeout({ status: 'timeout', browserId: 'chrome' }), 120_000) }) +const report = await Promise.race([reportPromise, timeoutReport]) +clearTimeout(timeoutId) +chrome.kill('SIGTERM') +vite.kill('SIGTERM') +server.closeAllConnections?.() +server.close() +await removeChromeProfile(chromeProfile) +console.log(JSON.stringify(report, null, 2)) +if (report.status !== 'pass') { + if (chromeStderr) console.error(chromeStderr.slice(-3000)) + process.exit(1) +} diff --git a/scripts/run-chrome-property-color.mjs b/scripts/run-chrome-property-color.mjs new file mode 100644 index 0000000..f3d4cb0 --- /dev/null +++ b/scripts/run-chrome-property-color.mjs @@ -0,0 +1,61 @@ +import { createServer } from 'node:http' +import { existsSync } from 'node:fs' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' +import { spawn } from 'node:child_process' +import { createChromeProfile, removeChromeProfile } from './chrome-profile.mjs' + +const root = resolve(new URL('..', import.meta.url).pathname) +const reportPath = resolve(root, 'config/chrome-property-color-verification.json') +const waitForPort = (child) => new Promise((resolvePort, reject) => { + let output = '' + const timer = setTimeout(() => reject(new Error(`Vite did not announce a port: ${output.slice(-2000)}`)), 30_000) + const onData = (chunk) => { output += String(chunk); const match = output.match(/http:\/\/127\.0\.0\.1:(\d+)/); if (match) { clearTimeout(timer); resolvePort(Number(match[1])) } } + child.stdout.on('data', onData) + child.stderr.on('data', onData) +}) + +const vite = spawn('./nodew', ['node_modules/vite/bin/vite.js', '--host', '127.0.0.1'], { cwd: root, stdio: ['ignore', 'pipe', 'pipe'] }) +let vitePort +try { vitePort = await waitForPort(vite) } catch (error) { vite.kill('SIGTERM'); throw error } +let resolveReport +const reportPromise = new Promise((resolveValue) => { resolveReport = resolveValue }) +const server = createServer(async (request, response) => { + response.setHeader('Cross-Origin-Opener-Policy', 'same-origin') + response.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + response.setHeader('Cross-Origin-Resource-Policy', 'same-origin') + if (request.method === 'POST' && request.url === '/__chrome-property-color-report') { + let body = '' + request.setEncoding('utf8') + request.on('data', (chunk) => { body += String(chunk) }) + request.on('end', async () => { const report = JSON.parse(body); await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`); resolveReport(report); response.writeHead(204); response.end() }) + return + } + try { + const upstream = await fetch(`http://127.0.0.1:${vitePort}${request.url}`, { headers: { ...request.headers } }) + response.writeHead(upstream.status, Object.fromEntries(upstream.headers.entries())) + response.end(Buffer.from(await upstream.arrayBuffer())) + } catch (error) { response.writeHead(502); response.end(String(error)) } +}) +await new Promise((resolveServer) => server.listen(0, '127.0.0.1', resolveServer)) +const port = server.address().port +const executable = process.env.CHROME_BIN || '/home/mes123456/.local/bin/google-chrome' +if (!existsSync(executable)) throw new Error(`Chrome executable is missing: ${executable}`) +const chromeProfile = await createChromeProfile('property-color') +const chrome = spawn(executable, ['--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--noerrdialogs', '--no-first-run', `--user-data-dir=${chromeProfile}`, `http://127.0.0.1:${port}/chrome-property-color-harness.html`], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'] }) +let chromeStderr = '' +chrome.stderr.on('data', (chunk) => { chromeStderr += String(chunk) }) +let timeoutId +const timeoutReport = new Promise((resolveTimeout) => { timeoutId = setTimeout(() => resolveTimeout({ status: 'timeout', browserId: 'chrome' }), 120_000) }) +const report = await Promise.race([reportPromise, timeoutReport]) +clearTimeout(timeoutId) +chrome.kill('SIGTERM') +vite.kill('SIGTERM') +server.closeAllConnections?.() +server.close() +await removeChromeProfile(chromeProfile) +console.log(JSON.stringify(report, null, 2)) +if (report.status !== 'pass') { + if (chromeStderr) console.error(chromeStderr.slice(-3000)) + process.exit(1) +} diff --git a/scripts/run-chrome-property-colorlist.mjs b/scripts/run-chrome-property-colorlist.mjs new file mode 100644 index 0000000..91bc00e --- /dev/null +++ b/scripts/run-chrome-property-colorlist.mjs @@ -0,0 +1,61 @@ +import { createServer } from 'node:http' +import { existsSync } from 'node:fs' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' +import { spawn } from 'node:child_process' +import { createChromeProfile, removeChromeProfile } from './chrome-profile.mjs' + +const root = resolve(new URL('..', import.meta.url).pathname) +const reportPath = resolve(root, 'config/chrome-property-colorlist-verification.json') +const waitForPort = (child) => new Promise((resolvePort, reject) => { + let output = '' + const timer = setTimeout(() => reject(new Error(`Vite did not announce a port: ${output.slice(-2000)}`)), 30_000) + const onData = (chunk) => { output += String(chunk); const match = output.match(/http:\/\/127\.0\.0\.1:(\d+)/); if (match) { clearTimeout(timer); resolvePort(Number(match[1])) } } + child.stdout.on('data', onData) + child.stderr.on('data', onData) +}) + +const vite = spawn('./nodew', ['node_modules/vite/bin/vite.js', '--host', '127.0.0.1'], { cwd: root, stdio: ['ignore', 'pipe', 'pipe'] }) +let vitePort +try { vitePort = await waitForPort(vite) } catch (error) { vite.kill('SIGTERM'); throw error } +let resolveReport +const reportPromise = new Promise((resolveValue) => { resolveReport = resolveValue }) +const server = createServer(async (request, response) => { + response.setHeader('Cross-Origin-Opener-Policy', 'same-origin') + response.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + response.setHeader('Cross-Origin-Resource-Policy', 'same-origin') + if (request.method === 'POST' && request.url === '/__chrome-property-colorlist-report') { + let body = '' + request.setEncoding('utf8') + request.on('data', (chunk) => { body += String(chunk) }) + request.on('end', async () => { const report = JSON.parse(body); await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`); resolveReport(report); response.writeHead(204); response.end() }) + return + } + try { + const upstream = await fetch(`http://127.0.0.1:${vitePort}${request.url}`, { headers: { ...request.headers } }) + response.writeHead(upstream.status, Object.fromEntries(upstream.headers.entries())) + response.end(Buffer.from(await upstream.arrayBuffer())) + } catch (error) { response.writeHead(502); response.end(String(error)) } +}) +await new Promise((resolveServer) => server.listen(0, '127.0.0.1', resolveServer)) +const port = server.address().port +const executable = process.env.CHROME_BIN || '/home/mes123456/.local/bin/google-chrome' +if (!existsSync(executable)) throw new Error(`Chrome executable is missing: ${executable}`) +const chromeProfile = await createChromeProfile('property-colorlist') +const chrome = spawn(executable, ['--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--noerrdialogs', '--no-first-run', `--user-data-dir=${chromeProfile}`, `http://127.0.0.1:${port}/chrome-property-colorlist-harness.html`], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'] }) +let chromeStderr = '' +chrome.stderr.on('data', (chunk) => { chromeStderr += String(chunk) }) +let timeoutId +const timeoutReport = new Promise((resolveTimeout) => { timeoutId = setTimeout(() => resolveTimeout({ status: 'timeout', browserId: 'chrome' }), 120_000) }) +const report = await Promise.race([reportPromise, timeoutReport]) +clearTimeout(timeoutId) +chrome.kill('SIGTERM') +vite.kill('SIGTERM') +server.closeAllConnections?.() +server.close() +await removeChromeProfile(chromeProfile) +console.log(JSON.stringify(report, null, 2)) +if (report.status !== 'pass') { + if (chromeStderr) console.error(chromeStderr.slice(-3000)) + process.exit(1) +} diff --git a/scripts/run-chrome-property-direction.mjs b/scripts/run-chrome-property-direction.mjs new file mode 100644 index 0000000..1f85125 --- /dev/null +++ b/scripts/run-chrome-property-direction.mjs @@ -0,0 +1,61 @@ +import { createServer } from 'node:http' +import { existsSync } from 'node:fs' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' +import { spawn } from 'node:child_process' +import { createChromeProfile, removeChromeProfile } from './chrome-profile.mjs' + +const root = resolve(new URL('..', import.meta.url).pathname) +const reportPath = resolve(root, 'config/chrome-property-direction-verification.json') +const waitForPort = (child) => new Promise((resolvePort, reject) => { + let output = '' + const timer = setTimeout(() => reject(new Error(`Vite did not announce a port: ${output.slice(-2000)}`)), 30_000) + const onData = (chunk) => { output += String(chunk); const match = output.match(/http:\/\/127\.0\.0\.1:(\d+)/); if (match) { clearTimeout(timer); resolvePort(Number(match[1])) } } + child.stdout.on('data', onData) + child.stderr.on('data', onData) +}) + +const vite = spawn('./nodew', ['node_modules/vite/bin/vite.js', '--host', '127.0.0.1'], { cwd: root, stdio: ['ignore', 'pipe', 'pipe'] }) +let vitePort +try { vitePort = await waitForPort(vite) } catch (error) { vite.kill('SIGTERM'); throw error } +let resolveReport +const reportPromise = new Promise((resolveValue) => { resolveReport = resolveValue }) +const server = createServer(async (request, response) => { + response.setHeader('Cross-Origin-Opener-Policy', 'same-origin') + response.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + response.setHeader('Cross-Origin-Resource-Policy', 'same-origin') + if (request.method === 'POST' && request.url === '/__chrome-property-direction-report') { + let body = '' + request.setEncoding('utf8') + request.on('data', (chunk) => { body += String(chunk) }) + request.on('end', async () => { const report = JSON.parse(body); await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`); resolveReport(report); response.writeHead(204); response.end() }) + return + } + try { + const upstream = await fetch(`http://127.0.0.1:${vitePort}${request.url}`, { headers: { ...request.headers } }) + response.writeHead(upstream.status, Object.fromEntries(upstream.headers.entries())) + response.end(Buffer.from(await upstream.arrayBuffer())) + } catch (error) { response.writeHead(502); response.end(String(error)) } +}) +await new Promise((resolveServer) => server.listen(0, '127.0.0.1', resolveServer)) +const port = server.address().port +const executable = process.env.CHROME_BIN || '/home/mes123456/.local/bin/google-chrome' +if (!existsSync(executable)) throw new Error(`Chrome executable is missing: ${executable}`) +const chromeProfile = await createChromeProfile('property-direction') +const chrome = spawn(executable, ['--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--noerrdialogs', '--no-first-run', `--user-data-dir=${chromeProfile}`, `http://127.0.0.1:${port}/chrome-property-direction-harness.html`], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'] }) +let chromeStderr = '' +chrome.stderr.on('data', (chunk) => { chromeStderr += String(chunk) }) +let timeoutId +const timeoutReport = new Promise((resolveTimeout) => { timeoutId = setTimeout(() => resolveTimeout({ status: 'timeout', browserId: 'chrome' }), 120_000) }) +const report = await Promise.race([reportPromise, timeoutReport]) +clearTimeout(timeoutId) +chrome.kill('SIGTERM') +vite.kill('SIGTERM') +server.closeAllConnections?.() +server.close() +await removeChromeProfile(chromeProfile) +console.log(JSON.stringify(report, null, 2)) +if (report.status !== 'pass') { + if (chromeStderr) console.error(chromeStderr.slice(-3000)) + process.exit(1) +} diff --git a/scripts/run-chrome-property-file.mjs b/scripts/run-chrome-property-file.mjs new file mode 100644 index 0000000..c2f45cc --- /dev/null +++ b/scripts/run-chrome-property-file.mjs @@ -0,0 +1,61 @@ +import { createServer } from 'node:http' +import { existsSync } from 'node:fs' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' +import { spawn } from 'node:child_process' +import { createChromeProfile, removeChromeProfile } from './chrome-profile.mjs' + +const root = resolve(new URL('..', import.meta.url).pathname) +const reportPath = resolve(root, 'config/chrome-property-file-verification.json') +const waitForPort = (child) => new Promise((resolvePort, reject) => { + let output = '' + const timer = setTimeout(() => reject(new Error(`Vite did not announce a port: ${output.slice(-2000)}`)), 30_000) + const onData = (chunk) => { output += String(chunk); const match = output.match(/http:\/\/127\.0\.0\.1:(\d+)/); if (match) { clearTimeout(timer); resolvePort(Number(match[1])) } } + child.stdout.on('data', onData) + child.stderr.on('data', onData) +}) + +const vite = spawn('./nodew', ['node_modules/vite/bin/vite.js', '--host', '127.0.0.1'], { cwd: root, stdio: ['ignore', 'pipe', 'pipe'] }) +let vitePort +try { vitePort = await waitForPort(vite) } catch (error) { vite.kill('SIGTERM'); throw error } +let resolveReport +const reportPromise = new Promise((resolveValue) => { resolveReport = resolveValue }) +const server = createServer(async (request, response) => { + response.setHeader('Cross-Origin-Opener-Policy', 'same-origin') + response.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + response.setHeader('Cross-Origin-Resource-Policy', 'same-origin') + if (request.method === 'POST' && request.url === '/__chrome-property-file-report') { + let body = '' + request.setEncoding('utf8') + request.on('data', (chunk) => { body += String(chunk) }) + request.on('end', async () => { const report = JSON.parse(body); await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`); resolveReport(report); response.writeHead(204); response.end() }) + return + } + try { + const upstream = await fetch(`http://127.0.0.1:${vitePort}${request.url}`, { headers: { ...request.headers } }) + response.writeHead(upstream.status, Object.fromEntries(upstream.headers.entries())) + response.end(Buffer.from(await upstream.arrayBuffer())) + } catch (error) { response.writeHead(502); response.end(String(error)) } +}) +await new Promise((resolveServer) => server.listen(0, '127.0.0.1', resolveServer)) +const port = server.address().port +const executable = process.env.CHROME_BIN || '/home/mes123456/.local/bin/google-chrome' +if (!existsSync(executable)) throw new Error(`Chrome executable is missing: ${executable}`) +const chromeProfile = await createChromeProfile('property-file') +const chrome = spawn(executable, ['--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--noerrdialogs', '--no-first-run', `--user-data-dir=${chromeProfile}`, `http://127.0.0.1:${port}/chrome-property-file-harness.html`], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'] }) +let chromeStderr = '' +chrome.stderr.on('data', (chunk) => { chromeStderr += String(chunk) }) +let timeoutId +const timeoutReport = new Promise((resolveTimeout) => { timeoutId = setTimeout(() => resolveTimeout({ status: 'timeout', browserId: 'chrome' }), 120_000) }) +const report = await Promise.race([reportPromise, timeoutReport]) +clearTimeout(timeoutId) +chrome.kill('SIGTERM') +vite.kill('SIGTERM') +server.closeAllConnections?.() +server.close() +await removeChromeProfile(chromeProfile) +console.log(JSON.stringify(report, null, 2)) +if (report.status !== 'pass') { + if (chromeStderr) console.error(chromeStderr.slice(-3000)) + process.exit(1) +} diff --git a/scripts/run-chrome-property-fileincluded.mjs b/scripts/run-chrome-property-fileincluded.mjs new file mode 100644 index 0000000..fabba36 --- /dev/null +++ b/scripts/run-chrome-property-fileincluded.mjs @@ -0,0 +1,61 @@ +import { createServer } from 'node:http' +import { existsSync } from 'node:fs' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' +import { spawn } from 'node:child_process' +import { createChromeProfile, removeChromeProfile } from './chrome-profile.mjs' + +const root = resolve(new URL('..', import.meta.url).pathname) +const reportPath = resolve(root, 'config/chrome-property-fileincluded-verification.json') +const waitForPort = (child) => new Promise((resolvePort, reject) => { + let output = '' + const timer = setTimeout(() => reject(new Error(`Vite did not announce a port: ${output.slice(-2000)}`)), 30_000) + const onData = (chunk) => { output += String(chunk); const match = output.match(/http:\/\/127\.0\.0\.1:(\d+)/); if (match) { clearTimeout(timer); resolvePort(Number(match[1])) } } + child.stdout.on('data', onData) + child.stderr.on('data', onData) +}) + +const vite = spawn('./nodew', ['node_modules/vite/bin/vite.js', '--host', '127.0.0.1'], { cwd: root, stdio: ['ignore', 'pipe', 'pipe'] }) +let vitePort +try { vitePort = await waitForPort(vite) } catch (error) { vite.kill('SIGTERM'); throw error } +let resolveReport +const reportPromise = new Promise((resolveValue) => { resolveReport = resolveValue }) +const server = createServer(async (request, response) => { + response.setHeader('Cross-Origin-Opener-Policy', 'same-origin') + response.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + response.setHeader('Cross-Origin-Resource-Policy', 'same-origin') + if (request.method === 'POST' && request.url === '/__chrome-property-fileincluded-report') { + let body = '' + request.setEncoding('utf8') + request.on('data', (chunk) => { body += String(chunk) }) + request.on('end', async () => { const report = JSON.parse(body); await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`); resolveReport(report); response.writeHead(204); response.end() }) + return + } + try { + const upstream = await fetch(`http://127.0.0.1:${vitePort}${request.url}`, { headers: { ...request.headers } }) + response.writeHead(upstream.status, Object.fromEntries(upstream.headers.entries())) + response.end(Buffer.from(await upstream.arrayBuffer())) + } catch (error) { response.writeHead(502); response.end(String(error)) } +}) +await new Promise((resolveServer) => server.listen(0, '127.0.0.1', resolveServer)) +const port = server.address().port +const executable = process.env.CHROME_BIN || '/home/mes123456/.local/bin/google-chrome' +if (!existsSync(executable)) throw new Error(`Chrome executable is missing: ${executable}`) +const chromeProfile = await createChromeProfile('property-fileincluded') +const chrome = spawn(executable, ['--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--noerrdialogs', '--no-first-run', `--user-data-dir=${chromeProfile}`, `http://127.0.0.1:${port}/chrome-property-fileincluded-harness.html`], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'] }) +let chromeStderr = '' +chrome.stderr.on('data', (chunk) => { chromeStderr += String(chunk) }) +let timeoutId +const timeoutReport = new Promise((resolveTimeout) => { timeoutId = setTimeout(() => resolveTimeout({ status: 'timeout', browserId: 'chrome' }), 120_000) }) +const report = await Promise.race([reportPromise, timeoutReport]) +clearTimeout(timeoutId) +chrome.kill('SIGTERM') +vite.kill('SIGTERM') +server.closeAllConnections?.() +server.close() +await removeChromeProfile(chromeProfile) +console.log(JSON.stringify(report, null, 2)) +if (report.status !== 'pass') { + if (chromeStderr) console.error(chromeStderr.slice(-3000)) + process.exit(1) +} diff --git a/scripts/run-freecad-native-property-semantics.mjs b/scripts/run-freecad-native-property-semantics.mjs index 4272e7d..afc2d6d 100644 --- a/scripts/run-freecad-native-property-semantics.mjs +++ b/scripts/run-freecad-native-property-semantics.mjs @@ -15,11 +15,11 @@ const runtime = source.runtimeObjects if (!runtime?.available || runtime.candidateCount !== 352 || runtime.availableCount !== 348 || runtime.unavailableCount !== 4 || !Array.isArray(runtime.types)) fail('runtime Document.supportedTypes inventory is incomplete') const editableTypes = new Set([ - 'App::PropertyAngle', 'App::PropertyBool', 'App::PropertyDistance', 'App::PropertyEnumeration', + 'App::PropertyAcceleration', 'App::PropertyAngle', 'App::PropertyArea', 'App::PropertyBool', 'App::PropertyBoolList', 'App::PropertyColor', 'App::PropertyColorList', 'App::PropertyDistance', 'App::PropertyEnumeration', 'App::PropertyFloat', 'App::PropertyFloatConstraint', 'App::PropertyFloatList', 'App::PropertyInteger', 'App::PropertyIntegerConstraint', 'App::PropertyIntegerList', 'App::PropertyLength', 'App::PropertyLink', 'App::PropertyLinkHidden', 'App::PropertyLinkList', 'App::PropertyLinkSub', 'App::PropertyLinkSubList', 'App::PropertyPlacement', 'App::PropertyString', - 'App::PropertyPrecision', 'App::PropertyQuantityConstraint', 'App::PropertyStringList', 'App::PropertyVector', + 'App::PropertyPrecision', 'App::PropertyQuantityConstraint', 'App::PropertyStringList', 'App::PropertyVector', 'App::PropertyDirection', 'App::PropertyFile', 'App::PropertyFileIncluded', ]) const specializedTypes = new Set([ 'App::PropertyExpressionEngine', 'Part::PropertyGeometryList', 'Part::PropertyPartShape', @@ -62,6 +62,9 @@ const preservedOnlyStatusNames = observedStatuses.filter((status) => !facadeBeha const preservedOnlyStatusRecordCount = properties.filter((property) => property.status.some((status) => preservedOnlyStatusNames.includes(status))).length const unavailableObjects = runtime.types.filter(({ available }) => !available).map(({ typeId, error }) => ({ typeId, error })) const harnessContent = await readFile(harnessPath) +const opaqueSupport = supportSummary['opaque-fcstd-proxy'] +const exactPromotionReady = opaqueSupport.typeCount === 0 && opaqueSupport.recordCount === 0 +const exactBlocker = exactPromotionReady ? null : `${opaqueSupport.typeCount} runtime property types and ${opaqueSupport.recordCount} records remain opaque-only; complete native document and property semantics` const report = { schemaVersion: 1, status: 'pass', @@ -81,9 +84,9 @@ const report = { unknownNumericBits: observedStatuses.filter((status) => status.startsWith('UnknownBit')), }, harness: { path: 'scripts/run-freecad-native-property-semantics.mjs', bytes: (await stat(harnessPath)).size, sha256: createHash('sha256').update(harnessContent).digest('hex') }, - exactPromotionReady: false, - exactBlocker: '58 runtime property types and 523 records remain opaque-only; complete native document and property semantics', + exactPromotionReady, + exactBlocker, generatedAt: new Date().toISOString(), } await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) -console.log(JSON.stringify({ status: report.status, runtime: report.runtime, supportSummary, propertyStatus: report.propertyStatus, exactPromotionReady: false }, null, 2)) +console.log(JSON.stringify({ status: report.status, runtime: report.runtime, supportSummary, propertyStatus: report.propertyStatus, exactPromotionReady, exactBlocker }, null, 2)) diff --git a/scripts/run-freecad-ordered-operation-pair-classification.mjs b/scripts/run-freecad-ordered-operation-pair-classification.mjs index 866ef90..57e2310 100644 --- a/scripts/run-freecad-ordered-operation-pair-classification.mjs +++ b/scripts/run-freecad-ordered-operation-pair-classification.mjs @@ -44,6 +44,13 @@ const canonicalSummary = (summary) => ({ area: Number(summary.area.toFixed(7)), bounds: [...summary.boundingBox.min, ...summary.boundingBox.max].map((value) => Number(value.toFixed(7))), }) +const summariesMatchWithinTolerance = (left, right, tolerance = 1e-6) => ( + left?.isValid === right?.isValid + && ['solids', 'faces', 'edges', 'vertices'].every((key) => left?.[key] === right?.[key]) + && ['volume', 'area'].every((key) => Math.abs(left?.[key] - right?.[key]) <= tolerance) + && left?.bounds?.length === right?.bounds?.length + && left.bounds.every((value, index) => Math.abs(value - right.bounds[index]) <= tolerance) +) const operationSpecs = { fuse: { builder: 'BRepAlgoAPI_Fuse', nominal: { toolSize: 5, toolOffset: 12 }, edited: { toolSize: 5, toolOffset: 11 }, parameter: 'toolOffsetX', beforeValue: 12, editedValue: 11 }, @@ -128,6 +135,48 @@ const pairSpecOverrides = { 'chamfer->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 8 }, edited: { toolSize: 5, toolOffset: 7 }, beforeValue: 8, editedValue: 7 }, 'chamfer->cut': { ...operationSpecs.cut, nominal: { toolSize: 4, toolOffset: 2 }, edited: { toolSize: 3, toolOffset: 2 }, beforeValue: 4, editedValue: 3 }, 'chamfer->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 }, + 'chamfer->rotate': { ...operationSpecs.rotate }, + 'chamfer->fillet': { ...operationSpecs.fillet, decision: 'rejected', rejectionAuthority: 'occt-builder' }, + 'chamfer->chamfer': { ...operationSpecs.chamfer, decision: 'rejected', rejectionAuthority: 'occt-builder' }, + 'chamfer->draft': { ...operationSpecs.draft, decision: 'rejected', rejectionAuthority: 'occt-builder' }, + 'chamfer->thickness': { ...operationSpecs.thickness, decision: 'rejected', rejectionAuthority: 'occt-no-op', kernelOutcome: 'no-op' }, + 'chamfer->mirrored': { ...operationSpecs.mirrored, nominal: { planeOriginX: 6 }, edited: { planeOriginX: 7 }, beforeValue: 6, editedValue: 7 }, + 'hole->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 8 }, edited: { toolSize: 5, toolOffset: 7 }, beforeValue: 8, editedValue: 7 }, + 'hole->cut': { ...operationSpecs.cut, nominal: { toolSize: 4, toolOffset: 2 }, edited: { toolSize: 3, toolOffset: 2 }, beforeValue: 4, editedValue: 3 }, + 'hole->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 }, + 'hole->rotate': { ...operationSpecs.rotate }, + 'hole->pad': { ...operationSpecs.pad, decision: 'rejected', rejectionAuthority: 'occt-builder' }, + 'hole->pocket': { ...operationSpecs.pocket }, + 'hole->loft': { ...operationSpecs.loft, decision: 'rejected', rejectionAuthority: 'freecad-document', kernelOutcome: 'accepted' }, + 'hole->pipe': { ...operationSpecs.pipe, decision: 'rejected', rejectionAuthority: 'freecad-document', kernelOutcome: 'invalid-result' }, + 'hole->revolution': { ...operationSpecs.revolution, decision: 'rejected', rejectionAuthority: 'occt-builder' }, + 'hole->groove': { ...operationSpecs.groove }, + 'hole->fillet': { ...operationSpecs.fillet }, + 'hole->chamfer': { ...operationSpecs.chamfer }, + 'hole->hole': { ...operationSpecs.hole, nominal: { radius: 1, depth: 14, position: [2, 2, -2], direction: [0, 0, 1] }, edited: { radius: 1.5 }, beforeValue: 1, editedValue: 1.5 }, + 'hole->draft': { ...operationSpecs.draft }, + 'hole->thickness': { ...operationSpecs.thickness }, + 'hole->mirrored': { ...operationSpecs.mirrored, nominal: { planeOriginX: 6 }, edited: { planeOriginX: 7 }, beforeValue: 6, editedValue: 7 }, + 'draft->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 8 }, edited: { toolSize: 5, toolOffset: 7 }, beforeValue: 8, editedValue: 7 }, + 'draft->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 }, + 'draft->pipe': { ...operationSpecs.pipe, kernelOutcome: 'accepted' }, + 'thickness->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 8 }, edited: { toolSize: 5, toolOffset: 7 }, beforeValue: 8, editedValue: 7 }, + 'thickness->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 }, + 'thickness->fillet': { ...operationSpecs.fillet, decision: 'rejected', rejectionAuthority: 'occt-builder' }, + 'thickness->chamfer': { ...operationSpecs.chamfer, decision: 'rejected', rejectionAuthority: 'occt-builder' }, + 'thickness->thickness': { ...operationSpecs.thickness, decision: 'rejected', rejectionAuthority: 'occt-no-op', kernelOutcome: 'no-op' }, + 'linear-pattern->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 16 }, edited: { toolSize: 5, toolOffset: 15 }, beforeValue: 16, editedValue: 15 }, + 'linear-pattern->thickness': { ...operationSpecs.thickness, decision: 'rejected', rejectionAuthority: 'occt-no-op', kernelOutcome: 'no-op' }, + 'polar-pattern->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 8 }, edited: { toolSize: 5, toolOffset: 7 }, beforeValue: 8, editedValue: 7 }, + 'polar-pattern->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 }, + 'polar-pattern->fillet': { ...operationSpecs.fillet, decision: 'rejected', rejectionAuthority: 'occt-builder' }, + 'polar-pattern->chamfer': { ...operationSpecs.chamfer, decision: 'rejected', rejectionAuthority: 'occt-builder' }, + 'polar-pattern->draft': { ...operationSpecs.draft, decision: 'rejected', rejectionAuthority: 'occt-builder' }, + 'polar-pattern->thickness': { ...operationSpecs.thickness, decision: 'rejected', rejectionAuthority: 'occt-no-op', kernelOutcome: 'no-op' }, + 'mirrored->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 8 }, edited: { toolSize: 5, toolOffset: 7 }, beforeValue: 8, editedValue: 7 }, + 'mirrored->common': { ...operationSpecs.common, nominal: { toolSize: 5, toolOffset: 7 }, edited: { toolSize: 5, toolOffset: 6 }, beforeValue: 7, editedValue: 6 }, + 'multi-transform->fuse': { ...operationSpecs.fuse, nominal: { toolSize: 5, toolOffset: 16 }, edited: { toolSize: 5, toolOffset: 15 }, beforeValue: 16, editedValue: 15 }, + 'multi-transform->thickness': { ...operationSpecs.thickness, decision: 'rejected', rejectionAuthority: 'occt-no-op', kernelOutcome: 'no-op' }, } const createOperation = (module, { operation, objectStep, toolSize, toolOffset, angle, length, profileWidth = 2, profileHeight = 3, profileX = 0.5, profileY = 2, profileZ = 0, ruled, spineLength, radius, distance, depth, position, direction, faceIndex, axisOrigin, neutralPlaneDirection, reversed, offset, intersectionJoin, translationX, planeOriginX, multiTranslationX, multiMirrorPlaneX = 5, stage }) => { @@ -191,6 +240,14 @@ const captureRejectedStage = (module, definition) => { const spec = operationSpecs[definition.operation] const wasmAbortSignature = definition.stage.stageId.startsWith('pair:loft-fillet:second') ? 'table index is out of bounds' + : definition.stage.stageId.startsWith('pair:thickness-fillet:second') + ? 'null function or function signature mismatch' + : definition.stage.stageId.startsWith('pair:chamfer-fillet:second') + ? 'memory access out of bounds' + : definition.stage.stageId.startsWith('pair:chamfer-chamfer:second') + ? 'memory access out of bounds' + : definition.stage.stageId.startsWith('pair:polar-pattern-fillet:second') + ? 'null function or function signature mismatch' : definition.stage.stageId.startsWith('pair:groove-chamfer:second') ? 'memory access out of bounds' : definition.stage.stageId.startsWith('pair:groove-thickness:second') @@ -245,7 +302,10 @@ const captureKernelCompatibilityStage = (module, definition, parameterValue, exp try { const outcome = response.summary?.isValid === true ? 'accepted' : 'invalid-result' const noHistorySuperset = expectedOutcome === 'accepted-no-history' && outcome === 'accepted' - const noOp = expectedOutcome === 'no-op' && outcome === 'accepted' && JSON.stringify(canonicalSummary(response.summary)) === JSON.stringify(definition.inputSummary) + const outputSummary = canonicalSummary(response.summary) + const exactNoOp = expectedOutcome === 'no-op' && outcome === 'accepted' && JSON.stringify(outputSummary) === JSON.stringify(definition.inputSummary) + const toleranceNoOp = expectedOutcome === 'no-op' && outcome === 'accepted' && summariesMatchWithinTolerance(outputSummary, definition.inputSummary) + const noOp = exactNoOp || toleranceNoOp if (response.provider !== 'occt-native' || (!noHistorySuperset && !noOp && outcome !== expectedOutcome) || !response.resultStep?.startsWith('ISO-10303-21;') || (response.records?.length < 1 && !noHistorySuperset)) fail(`${definition.stage.stageId} OCCT compatibility probe returned an unexpected result: ${JSON.stringify({ provider: response.provider, outcome, expectedOutcome, summary: response.summary, inputSummary: definition.inputSummary, resultStep: Boolean(response.resultStep), records: response.records?.length, result: Boolean(response.result) })}`) return { operation: definition.operation, @@ -260,10 +320,11 @@ const captureKernelCompatibilityStage = (module, definition, parameterValue, exp validShapeProduced: response.summary.isValid === true, historyProduced: response.records.length > 0, historyProvider: response.provider, - summary: canonicalSummary(response.summary), + summary: outputSummary, historyRecords: response.records.length, historySha256: sha256(JSON.stringify(response.records)), authority: noOp ? 'kernel-no-op' : noHistorySuperset ? 'kernel-superset-no-history' : outcome === 'accepted' ? 'kernel-superset-only' : 'kernel-invalid-result', + ...(!exactNoOp && toleranceNoOp ? { noOpComparison: 'topology-and-metrics-within-1e-6' } : {}), } } finally { response.result?.delete?.() @@ -351,7 +412,8 @@ const persistPair = async (pair, step, namingEvidence, decision) => { 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?.checks || typeof persistence.checks !== 'object') fail(`FreeCAD FCStd replay returned incomplete evidence: ${JSON.stringify(persistence)}`) - const checksPass = Object.values(persistence.checks).every(Boolean) || (decision === 'rejected' && persistence.checks.freecadProfileAccepted === true && persistence.checks.nativeFeatureRejected === false && Object.entries(persistence.checks).filter(([key]) => key !== 'nativeFeatureRejected').every(([, value]) => value === true)) || (decision === 'rejected' && persistence.checks.freecadProfileNoOp === true && persistence.checks.freecadProfileAccepted === false && persistence.checks.nativeFeatureRejected === false && Object.entries(persistence.checks).filter(([key]) => !['nativeFeatureRejected', 'freecadProfileAccepted'].includes(key)).every(([, value]) => value === true)) || (decision === 'rejected' && persistence.checks.freecadProfileAccepted === false && persistence.checks.nativeFeatureRejected === true && Object.entries(persistence.checks).filter(([key]) => key !== 'freecadProfileAccepted').every(([, value]) => value === true)) + const noOpSourceBrepReserialized = persistence.checks.freecadProfileNoOp === true && persistence.checks.sourceShapeRestored === false && persistence.checks.sourceShapeSummaryRestored === true && persistence.checks.sourceShapeGeometricallyRestored === true && persistence.rollback?.sourceBrepReserialized === true + const checksPass = Object.values(persistence.checks).every(Boolean) || (decision === 'rejected' && persistence.checks.freecadProfileAccepted === true && persistence.checks.nativeFeatureRejected === false && Object.entries(persistence.checks).filter(([key]) => key !== 'nativeFeatureRejected').every(([, value]) => value === true)) || (decision === 'rejected' && persistence.checks.freecadProfileNoOp === true && persistence.checks.freecadProfileAccepted === false && persistence.checks.nativeFeatureRejected === false && Object.entries(persistence.checks).filter(([key]) => !['nativeFeatureRejected', 'freecadProfileAccepted', ...(noOpSourceBrepReserialized ? ['sourceShapeRestored'] : [])].includes(key)).every(([, value]) => value === true)) || (decision === 'rejected' && persistence.checks.freecadProfileAccepted === false && persistence.checks.nativeFeatureRejected === true && Object.entries(persistence.checks).filter(([key]) => key !== 'freecadProfileAccepted').every(([, value]) => value === true)) if (persistence.status !== 'pass' || persistence.decision !== decision || persistence.freecadVersion !== '1.1.1' || persistence.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || !checksPass) fail(`FreeCAD FCStd replay failed: ${JSON.stringify(persistence)}`) return persistence } finally { @@ -469,7 +531,57 @@ const classifyPair = async (fromOperation, toOperation, pairIndex) => { const operations = ['fuse', 'cut', 'common', 'rotate', 'pad', 'pocket', 'loft', 'pipe', 'revolution', 'groove', 'fillet', 'chamfer', 'hole', 'draft', 'thickness', 'linear-pattern', 'polar-pattern', 'mirrored', 'multi-transform'] const orderedPairPrefix = [...operations.map((toOperation) => ['fuse', toOperation]), ['cut', 'fuse'], ['cut', 'cut'], ['cut', 'common'], ['cut', 'pad'], ['cut', 'pocket'], ['cut', 'loft'], ['cut', 'pipe'], ['cut', 'revolution'], ['cut', 'groove'], ['cut', 'fillet'], ['cut', 'chamfer'], ['cut', 'hole'], ['cut', 'draft'], ['cut', 'thickness'], ['cut', 'linear-pattern'], ['cut', 'polar-pattern'], ['cut', 'mirrored'], ['cut', 'multi-transform'], ['common', 'fuse'], ['common', 'cut'], ['common', 'common'], ['common', 'rotate'], ['common', 'pad'], ['common', 'pocket'], ['common', 'loft'], ['common', 'pipe'], ['common', 'revolution'], ['common', 'groove'], ['common', 'fillet'], ['common', 'chamfer'], ['common', 'hole'], ['common', 'draft'], ['common', 'thickness'], ['common', 'linear-pattern'], ['common', 'polar-pattern'], ['common', 'mirrored'], ['common', 'multi-transform'], ['rotate', 'fuse'], ['rotate', 'cut'], ['rotate', 'common'], ['rotate', 'rotate'], ['rotate', 'pad'], ['rotate', 'pocket'], ['rotate', 'loft'], ['rotate', 'pipe'], ['rotate', 'revolution'], ['rotate', 'groove'], ['rotate', 'chamfer'], ['rotate', 'hole'], ['rotate', 'draft'], ['rotate', 'thickness'], ['rotate', 'linear-pattern'], ['rotate', 'polar-pattern'], ['rotate', 'mirrored'], ['rotate', 'multi-transform'], ['pad', 'fuse'], ['pad', 'cut'], ['pad', 'common'], ['pad', 'rotate'], ['pad', 'pad'], ['pad', 'pocket'], ['pad', 'loft'], ['pad', 'pipe'], ['pad', 'revolution'], ['pad', 'groove'], ['pad', 'fillet'], ['pad', 'chamfer'], ['pad', 'hole'], ['pad', 'draft'], ['pad', 'thickness'], ['pad', 'linear-pattern'], ['pad', 'polar-pattern'], ['pad', 'mirrored'], ['pad', 'multi-transform'], ['pocket', 'fuse'], ['pocket', 'cut'], ['pocket', 'common'], ['pocket', 'rotate'], ['pocket', 'pad'], ['pocket', 'pocket'], ['pocket', 'loft'], ['pocket', 'pipe'], ['pocket', 'revolution'], ['pocket', 'groove'], ['pocket', 'fillet'], ['pocket', 'chamfer'], ['pocket', 'hole'], ['pocket', 'draft'], ['pocket', 'thickness'], ['pocket', 'linear-pattern'], ['pocket', 'polar-pattern'], ['pocket', 'mirrored'], ['pocket', 'multi-transform'], ['loft', 'fuse'], ['loft', 'cut'], ['loft', 'common'], ['loft', 'rotate'], ['loft', 'pad'], ['loft', 'pocket'], ['loft', 'loft'], ['loft', 'pipe'], ['loft', 'revolution'], ['loft', 'groove'], ['loft', 'fillet'], ['loft', 'chamfer'], ['loft', 'hole'], ['loft', 'draft'], ['loft', 'thickness'], ['loft', 'linear-pattern'], ['loft', 'polar-pattern'], ['loft', 'mirrored'], ['loft', 'multi-transform'], ['pipe', 'fuse'], ['pipe', 'cut'], ['pipe', 'common'], ['pipe', 'rotate'], ['pipe', 'pad'], ['pipe', 'pocket'], ['pipe', 'loft'], ['pipe', 'pipe'], ['pipe', 'revolution'], ['pipe', 'groove'], ['pipe', 'fillet'], ['pipe', 'chamfer'], ['pipe', 'hole'], ['pipe', 'draft'], ['pipe', 'thickness'], ['pipe', 'linear-pattern'], ['pipe', 'polar-pattern'], ['pipe', 'mirrored'], ['pipe', 'multi-transform'], ['revolution', 'fuse'], ['revolution', 'cut'], ['revolution', 'common'], ['revolution', 'rotate'], ['revolution', 'pad'], ['revolution', 'pocket'], ['revolution', 'loft'], ['revolution', 'pipe'], ['revolution', 'revolution'], ['revolution', 'groove'], ['revolution', 'fillet'], ['revolution', 'chamfer'], ['revolution', 'hole'], ['revolution', 'draft'], ['revolution', 'thickness'], ['revolution', 'linear-pattern'], ['revolution', 'polar-pattern'], ['revolution', 'mirrored'], ['revolution', 'multi-transform'], ['groove', 'fuse'], ['groove', 'cut'], ['groove', 'common'], ['groove', 'rotate'], ['groove', 'pad'], ['groove', 'pocket'], ['groove', 'loft'], ['groove', 'pipe'], ['groove', 'revolution'], ['groove', 'groove'], ['groove', 'fillet'], ['groove', 'chamfer'], ['groove', 'hole'], ['groove', 'draft'], ['groove', 'thickness'], ['groove', 'linear-pattern'], ['groove', 'polar-pattern'], ['groove', 'mirrored']] -orderedPairPrefix.push(['groove', 'multi-transform'], ['fillet', 'fuse'], ['fillet', 'cut'], ['fillet', 'common'], ['fillet', 'rotate'], ['fillet', 'pad'], ['fillet', 'pocket'], ['fillet', 'loft'], ['fillet', 'pipe'], ['fillet', 'revolution'], ['fillet', 'groove'], ['fillet', 'fillet'], ['fillet', 'chamfer'], ['fillet', 'hole'], ['fillet', 'draft'], ['fillet', 'thickness'], ['fillet', 'linear-pattern'], ['fillet', 'polar-pattern'], ['fillet', 'multi-transform'], ['chamfer', 'fuse'], ['chamfer', 'cut'], ['chamfer', 'common']) +orderedPairPrefix.push(['groove', 'multi-transform'], ['fillet', 'fuse'], ['fillet', 'cut'], ['fillet', 'common'], ['fillet', 'rotate'], ['fillet', 'pad'], ['fillet', 'pocket'], ['fillet', 'loft'], ['fillet', 'pipe'], ['fillet', 'revolution'], ['fillet', 'groove'], ['fillet', 'fillet'], ['fillet', 'chamfer'], ['fillet', 'hole'], ['fillet', 'draft'], ['fillet', 'thickness'], ['fillet', 'linear-pattern'], ['fillet', 'polar-pattern'], ['fillet', 'multi-transform'], ['chamfer', 'fuse'], ['chamfer', 'cut'], ['chamfer', 'common'], ['chamfer', 'rotate'], ['chamfer', 'pad'], ['chamfer', 'pocket'], ['chamfer', 'loft'], ['chamfer', 'pipe'], ['chamfer', 'revolution'], ['chamfer', 'groove'], ['chamfer', 'fillet'], ['chamfer', 'chamfer'], ['chamfer', 'hole'], ['chamfer', 'draft'], ['chamfer', 'thickness'], ['chamfer', 'linear-pattern'], ['chamfer', 'polar-pattern'], ['chamfer', 'mirrored'], ['chamfer', 'multi-transform'], ['hole', 'fuse'], ['hole', 'cut'], ['hole', 'common'], ['hole', 'rotate'], ['hole', 'pad'], ['hole', 'pocket'], ['hole', 'loft'], ['hole', 'pipe'], ['hole', 'revolution'], ['hole', 'groove'], ['hole', 'fillet'], ['hole', 'chamfer'], ['hole', 'hole'], ['hole', 'draft'], ['hole', 'thickness'], ['hole', 'linear-pattern'], ['hole', 'polar-pattern'], ['hole', 'mirrored'], ['hole', 'multi-transform'], ['draft', 'fuse'], ['draft', 'cut'], ['draft', 'common'], ['draft', 'rotate'], ['draft', 'pad'], ['draft', 'pocket'], ['draft', 'loft'], ['draft', 'pipe'], ['draft', 'revolution'], ['draft', 'groove'], ['draft', 'fillet'], ['draft', 'chamfer'], ['draft', 'hole'], ['draft', 'draft'], ['draft', 'thickness'], ['draft', 'linear-pattern'], ['draft', 'polar-pattern'], ['draft', 'mirrored'], ['draft', 'multi-transform'], ['thickness', 'fuse'], ['thickness', 'cut'], ['thickness', 'common'], ['thickness', 'rotate'], ['thickness', 'pad'], ['thickness', 'pocket'], ['thickness', 'loft'], ['thickness', 'pipe'], ['thickness', 'revolution'], ['thickness', 'groove'], ['thickness', 'fillet'], ['thickness', 'chamfer'], ['thickness', 'hole'], ['thickness', 'draft'], ['thickness', 'thickness'], ['thickness', 'linear-pattern'], ['thickness', 'polar-pattern'], ['thickness', 'mirrored'], ['thickness', 'multi-transform'], ['linear-pattern', 'fuse'], ['linear-pattern', 'cut'], ['linear-pattern', 'common'], ['linear-pattern', 'rotate'], ['linear-pattern', 'pad'], ['linear-pattern', 'pocket'], ['linear-pattern', 'loft'], ['linear-pattern', 'pipe'], ['linear-pattern', 'revolution'], ['linear-pattern', 'groove'], ['linear-pattern', 'fillet'], ['linear-pattern', 'chamfer'], ['linear-pattern', 'hole'], ['linear-pattern', 'draft'], ['linear-pattern', 'thickness'], ['linear-pattern', 'linear-pattern'], ['linear-pattern', 'polar-pattern'], ['linear-pattern', 'mirrored'], ['linear-pattern', 'multi-transform'], ['polar-pattern', 'fuse'], ['polar-pattern', 'cut'], ['polar-pattern', 'common'], ['polar-pattern', 'rotate'], ['polar-pattern', 'pad'], ['polar-pattern', 'pocket']) +orderedPairPrefix.push(['polar-pattern', 'loft']) +orderedPairPrefix.push(['polar-pattern', 'pipe']) +orderedPairPrefix.push(['polar-pattern', 'revolution']) +orderedPairPrefix.push(['polar-pattern', 'groove']) +orderedPairPrefix.push(['polar-pattern', 'fillet']) +orderedPairPrefix.push(['polar-pattern', 'chamfer']) +orderedPairPrefix.push(['polar-pattern', 'hole']) +orderedPairPrefix.push(['polar-pattern', 'draft']) +orderedPairPrefix.push(['polar-pattern', 'thickness']) +orderedPairPrefix.push(['polar-pattern', 'linear-pattern']) +orderedPairPrefix.push(['polar-pattern', 'polar-pattern']) +orderedPairPrefix.push(['polar-pattern', 'mirrored']) +orderedPairPrefix.push(['polar-pattern', 'multi-transform']) +orderedPairPrefix.push(['mirrored', 'fuse']) +orderedPairPrefix.push(['mirrored', 'cut']) +orderedPairPrefix.push(['mirrored', 'common']) +orderedPairPrefix.push(['mirrored', 'rotate']) +orderedPairPrefix.push(['mirrored', 'pad']) +orderedPairPrefix.push(['mirrored', 'pocket']) +orderedPairPrefix.push(['mirrored', 'loft']) +orderedPairPrefix.push(['mirrored', 'pipe']) +orderedPairPrefix.push(['mirrored', 'revolution']) +orderedPairPrefix.push(['mirrored', 'groove']) +orderedPairPrefix.push(['mirrored', 'fillet']) +orderedPairPrefix.push(['mirrored', 'chamfer']) +orderedPairPrefix.push(['mirrored', 'hole']) +orderedPairPrefix.push(['mirrored', 'draft']) +orderedPairPrefix.push(['mirrored', 'thickness']) +orderedPairPrefix.push(['mirrored', 'polar-pattern']) +orderedPairPrefix.push(['mirrored', 'mirrored']) +orderedPairPrefix.push(['mirrored', 'multi-transform']) +orderedPairPrefix.push(['multi-transform', 'fuse']) +orderedPairPrefix.push(['multi-transform', 'cut']) +orderedPairPrefix.push(['multi-transform', 'common']) +orderedPairPrefix.push(['multi-transform', 'rotate']) +orderedPairPrefix.push(['multi-transform', 'pad']) +orderedPairPrefix.push(['multi-transform', 'pocket']) +orderedPairPrefix.push(['multi-transform', 'loft']) +orderedPairPrefix.push(['multi-transform', 'pipe']) +orderedPairPrefix.push(['multi-transform', 'revolution']) +orderedPairPrefix.push(['multi-transform', 'groove']) +orderedPairPrefix.push(['multi-transform', 'fillet']) +orderedPairPrefix.push(['multi-transform', 'chamfer']) +orderedPairPrefix.push(['multi-transform', 'hole']) +orderedPairPrefix.push(['multi-transform', 'draft']) +orderedPairPrefix.push(['multi-transform', 'thickness']) +orderedPairPrefix.push(['multi-transform', 'linear-pattern']) +orderedPairPrefix.push(['multi-transform', 'polar-pattern']) +orderedPairPrefix.push(['multi-transform', 'mirrored']) +orderedPairPrefix.push(['multi-transform', 'multi-transform']) const classifications = [] const selectedPairs = process.env.FREECAD_ONLY_PAIR ? orderedPairPrefix.filter(([fromOperation, toOperation]) => `${fromOperation}->${toOperation}` === process.env.FREECAD_ONLY_PAIR) : orderedPairPrefix if (process.env.FREECAD_ONLY_PAIR && selectedPairs.length !== 1) fail(`focused pair ${process.env.FREECAD_ONLY_PAIR} is not in the classified prefix.`) diff --git a/scripts/run-freecad-property-acceleration-failure.mjs b/scripts/run-freecad-property-acceleration-failure.mjs new file mode 100644 index 0000000..e322d09 --- /dev/null +++ b/scripts/run-freecad-property-acceleration-failure.mjs @@ -0,0 +1,29 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const executable = process.env.FREECAD_CMD || resolve(root, '.cache/freecad/install-desktop/bin/FreeCADCmd') +const outputPath = resolve(root, 'config/freecad-property-acceleration-failure.json') +const scriptPath = resolve(root, 'scripts/freecad-property-acceleration-failure.py') +const sysroot = resolve(root, '.cache/freecad/sysroot') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyAcceleration failure probe executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 16 * 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +const marker = 'FREECAD_PROPERTY_ACCELERATION_FAILURE_RESULT=' +const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) +if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyAcceleration failure probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-acceleration-failure.json', failures: report.failures.length, transaction: report.transaction, cancellationBoundary: report.cancellationBoundary }, null, 2)) diff --git a/scripts/run-freecad-property-acceleration-mutation.mjs b/scripts/run-freecad-property-acceleration-mutation.mjs new file mode 100644 index 0000000..c7a8bd1 --- /dev/null +++ b/scripts/run-freecad-property-acceleration-mutation.mjs @@ -0,0 +1,29 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const executable = process.env.FREECAD_CMD || resolve(root, '.cache/freecad/install-desktop/bin/FreeCADCmd') +const outputPath = resolve(root, 'config/freecad-property-acceleration-mutation.json') +const scriptPath = resolve(root, 'scripts/freecad-property-acceleration-mutation.py') +const sysroot = resolve(root, '.cache/freecad/sysroot') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyAcceleration mutation probe executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 16 * 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +const marker = 'FREECAD_PROPERTY_ACCELERATION_MUTATION_RESULT=' +const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) +if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyAcceleration mutation probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-acceleration-mutation.json', recompute: report.recompute, classification: report.classification }, null, 2)) diff --git a/scripts/run-freecad-property-acceleration-roundtrip.ts b/scripts/run-freecad-property-acceleration-roundtrip.ts new file mode 100644 index 0000000..56e97d4 --- /dev/null +++ b/scripts/run-freecad-property-acceleration-roundtrip.ts @@ -0,0 +1,96 @@ +import { createHash } from 'node:crypto' +import { existsSync } from 'node:fs' +import { mkdir, readFile, writeFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' + +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 scriptPath = resolve(root, 'scripts/freecad-property-acceleration-roundtrip.py') +const outputDirectory = resolve(root, '.cache/freecad/property-acceleration-roundtrip') +const nativePath = resolve(outputDirectory, 'native-initial.FCStd') +const webPath = resolve(outputDirectory, 'web-edited.FCStd') +const resavedPath = resolve(outputDirectory, 'native-resaved.FCStd') +const reportPath = resolve(root, 'config/freecad-property-acceleration-roundtrip.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyAcceleration roundtrip executable is missing: ${executable}`) +await mkdir(outputDirectory, { recursive: true }) + +const runNative = (mode: 'create' | 'verify', path: string, resaved = '') => { + const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_ACCELERATION_ROUNDTRIP_MODE: mode, + FREECAD_PROPERTY_ACCELERATION_ROUNDTRIP_PATH: path, + FREECAD_PROPERTY_ACCELERATION_ROUNDTRIP_RESAVED_PATH: resaved, + 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}` : ''}`, + }, + }) + const output = `${execution.stdout || ''}\n${execution.stderr || ''}` + const marker = 'FREECAD_PROPERTY_ACCELERATION_ROUNDTRIP_RESULT=' + const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) + if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyAcceleration ${mode} probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) + return JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +} + +const native = runNative('create', nativePath) +const nativeBytes = new Uint8Array(await readFile(nativePath)) +const facade = createWebCadFacade({ runtimeMode: 'mock' }) +const inspectedBefore = facade.project.fcstd.inspect(nativeBytes) +const editedBytes = facade.project.fcstd.rewriteNumeric(nativeBytes, { + objectName: 'AccelerationProbe', + propertyName: 'Acceleration', + typeId: 'App::PropertyAcceleration', + value: 500, + expectedValue: 1000, +}) +await writeFile(webPath, editedBytes) +const inspectedAfter = facade.project.fcstd.inspect(editedBytes) +const initialFiles = unzipSync(nativeBytes) +const editedFiles = unzipSync(editedBytes) +const opaquePaths = Object.keys(initialFiles).filter((path) => path.toLowerCase() !== 'document.xml') +const opaqueEntriesPreserved = opaquePaths.every((path) => Buffer.from(initialFiles[path]).equals(Buffer.from(editedFiles[path] ?? new Uint8Array()))) +const normalizeInspection = (inspection: typeof inspectedBefore) => inspection.objects.map((object) => ({ ...object, properties: object.properties.map((property) => property.name === 'Acceleration' ? { ...property, value: '' } : property) })) +const semanticObjectsPreserved = JSON.stringify(normalizeInspection(inspectedBefore)) === JSON.stringify(normalizeInspection(inspectedAfter)) +const nativeAfter = runNative('verify', webPath, resavedPath) +const resavedBytes = new Uint8Array(await readFile(resavedPath)) +const nativeOutputMatches = [nativeAfter.result.reopened, nativeAfter.result.resaved].every((snapshot) => snapshot.object.value.numeric === 500 && snapshot.object.trajectory.waypoints.every((waypoint: { acceleration: number }) => waypoint.acceleration === 500)) +const report = { + schemaVersion: 1, + status: 'pass', + baselineId: 'freecad-1.1.1-property-acceleration-roundtrip', + freecadVersion: native.freecadVersion, + gitCommit: native.gitCommit, + archives: { + nativeInitial: { path: '.cache/freecad/property-acceleration-roundtrip/native-initial.FCStd', bytes: nativeBytes.byteLength, sha256: createHash('sha256').update(nativeBytes).digest('hex') }, + webEdited: { path: '.cache/freecad/property-acceleration-roundtrip/web-edited.FCStd', bytes: editedBytes.byteLength, sha256: createHash('sha256').update(editedBytes).digest('hex') }, + nativeResaved: { path: '.cache/freecad/property-acceleration-roundtrip/native-resaved.FCStd', bytes: resavedBytes.byteLength, sha256: createHash('sha256').update(resavedBytes).digest('hex') }, + }, + nativeInitial: native.result, + web: { + before: inspectedBefore.objects.find((object) => object.name === 'AccelerationProbe')?.properties.find((property) => property.name === 'Acceleration'), + after: inspectedAfter.objects.find((object) => object.name === 'AccelerationProbe')?.properties.find((property) => property.name === 'Acceleration'), + objectSetPreserved: inspectedBefore.objects.map((object) => `${object.name}:${object.typeId}`).join('|') === inspectedAfter.objects.map((object) => `${object.name}:${object.typeId}`).join('|'), + semanticObjectsPreserved, + opaquePathsPreserved: opaquePaths.length, + opaqueEntriesPreserved, + }, + nativeAfter: nativeAfter.result, + classification: { + webValue: inspectedAfter.objects.find((object) => object.name === 'AccelerationProbe')?.properties.find((property) => property.name === 'Acceleration')?.value, + reopenedValue: nativeAfter.result.reopened.object.value.numeric, + resavedValue: nativeAfter.result.resaved.object.value.numeric, + nativeOutputMatches, + unknownSemanticDrift: !(opaqueEntriesPreserved && semanticObjectsPreserved && nativeOutputMatches), + zeroUnknownDrift: opaqueEntriesPreserved && semanticObjectsPreserved && nativeOutputMatches, + }, +} +await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-acceleration-roundtrip.json', web: report.classification, opaqueEntriesPreserved: report.web.opaqueEntriesPreserved }, null, 2)) diff --git a/scripts/run-freecad-property-acceleration-success.mjs b/scripts/run-freecad-property-acceleration-success.mjs new file mode 100644 index 0000000..3051a4e --- /dev/null +++ b/scripts/run-freecad-property-acceleration-success.mjs @@ -0,0 +1,29 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const executable = process.env.FREECAD_CMD || resolve(root, '.cache/freecad/install-desktop/bin/FreeCADCmd') +const outputPath = resolve(root, 'config/freecad-property-acceleration-success.json') +const scriptPath = resolve(root, 'scripts/freecad-property-acceleration-success.py') +const sysroot = resolve(root, '.cache/freecad/sysroot') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyAcceleration success probe executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 16 * 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +const marker = 'FREECAD_PROPERTY_ACCELERATION_SUCCESS_RESULT=' +const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) +if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyAcceleration success probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-acceleration-success.json', cases: report.cases.length, property: report.property }, null, 2)) diff --git a/scripts/run-freecad-property-area-failure.mjs b/scripts/run-freecad-property-area-failure.mjs new file mode 100644 index 0000000..58dae37 --- /dev/null +++ b/scripts/run-freecad-property-area-failure.mjs @@ -0,0 +1,25 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const executable = process.env.FREECAD_CMD || resolve(root, '.cache/freecad/install-desktop/bin/FreeCADCmd') +const outputPath = resolve(root, 'config/freecad-property-area-failure.json') +const scriptPath = resolve(root, 'scripts/freecad-property-area-failure.py') +const sysroot = resolve(root, '.cache/freecad/sysroot') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyArea failure probe executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 16 * 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}` : ''}` }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +const marker = 'FREECAD_PROPERTY_AREA_FAILURE_RESULT=' +const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) +if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyArea failure probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-area-failure.json', failures: report.failures.map(({ id, recomputeResult, after }) => ({ id, recomputeResult, state: after.state, statusString: after.statusString })), disabled: report.disabled.exception, transaction: report.transaction }, null, 2)) diff --git a/scripts/run-freecad-property-area-mutation.mjs b/scripts/run-freecad-property-area-mutation.mjs new file mode 100644 index 0000000..9a65b6a --- /dev/null +++ b/scripts/run-freecad-property-area-mutation.mjs @@ -0,0 +1,29 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const executable = process.env.FREECAD_CMD || resolve(root, '.cache/freecad/install-desktop/bin/FreeCADCmd') +const outputPath = resolve(root, 'config/freecad-property-area-mutation.json') +const scriptPath = resolve(root, 'scripts/freecad-property-area-mutation.py') +const sysroot = resolve(root, '.cache/freecad/sysroot') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyArea mutation probe executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 16 * 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +const marker = 'FREECAD_PROPERTY_AREA_MUTATION_RESULT=' +const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) +if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyArea mutation probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-area-mutation.json', recompute: report.recompute, values: { before: report.before.value.numeric, edited: report.edited.value.numeric, restored: report.restored.value.numeric }, classification: report.classification }, null, 2)) diff --git a/scripts/run-freecad-property-area-roundtrip.ts b/scripts/run-freecad-property-area-roundtrip.ts new file mode 100644 index 0000000..c16c264 --- /dev/null +++ b/scripts/run-freecad-property-area-roundtrip.ts @@ -0,0 +1,106 @@ +import { createHash } from 'node:crypto' +import { isDeepStrictEqual } from 'node:util' +import { existsSync } from 'node:fs' +import { mkdir, readFile, writeFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' + +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 scriptPath = resolve(root, 'scripts/freecad-property-area-roundtrip.py') +const outputDirectory = resolve(root, '.cache/freecad/property-area-roundtrip') +const nativePath = resolve(outputDirectory, 'native-initial.FCStd') +const webPath = resolve(outputDirectory, 'web-edited.FCStd') +const resavedPath = resolve(outputDirectory, 'native-resaved.FCStd') +const reportPath = resolve(root, 'config/freecad-property-area-roundtrip.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyArea roundtrip executable is missing: ${executable}`) +await mkdir(outputDirectory, { recursive: true }) + +const runNative = (mode: 'create' | 'verify', path: string, resaved = '') => { + const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_AREA_ROUNDTRIP_MODE: mode, + FREECAD_PROPERTY_AREA_ROUNDTRIP_PATH: path, + FREECAD_PROPERTY_AREA_ROUNDTRIP_RESAVED_PATH: resaved, + 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}` : ''}`, + }, + }) + const output = `${execution.stdout || ''}\n${execution.stderr || ''}` + const marker = 'FREECAD_PROPERTY_AREA_ROUNDTRIP_RESULT=' + const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) + if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyArea ${mode} probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) + return JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +} + +const native = runNative('create', nativePath) +const nativeBytes = new Uint8Array(await readFile(nativePath)) +const facade = createWebCadFacade({ runtimeMode: 'mock' }) +const inspectedBefore = facade.project.fcstd.inspect(nativeBytes) +const initialElements = { schemaVersion: 1 as const, entries: [{ objectId: 'AreaBox', subElement: 'Face1' }] } +const editedElements = { schemaVersion: 1 as const, entries: [{ objectId: 'AreaBox', subElement: 'Face1' }, { objectId: 'AreaBox', subElement: 'Face2' }] } +const editedBytes = facade.project.fcstd.rewriteMeasureArea(nativeBytes, { + objectName: 'AreaProbe', + elements: editedElements, + area: 20, + expectedElements: initialElements, + expectedArea: 10, +}) +await facade.project.dispose() +await writeFile(webPath, editedBytes) +const inspectedAfter = facade.project.fcstd.inspect(editedBytes) +const initialFiles = unzipSync(nativeBytes) +const editedFiles = unzipSync(editedBytes) +const opaquePaths = Object.keys(initialFiles).filter((path) => path.toLowerCase() !== 'document.xml') +const opaqueEntriesPreserved = opaquePaths.every((path) => Buffer.from(initialFiles[path]).equals(Buffer.from(editedFiles[path] ?? new Uint8Array()))) +const withoutEditedProperties = (inspection: typeof inspectedBefore) => inspection.objects.map((object) => ({ ...object, properties: object.name === 'AreaProbe' ? object.properties.filter((property) => property.name !== 'Area' && property.name !== 'Elements') : object.properties })) +const semanticObjectsPreserved = isDeepStrictEqual(withoutEditedProperties(inspectedBefore), withoutEditedProperties(inspectedAfter)) +const nativeAfter = runNative('verify', webPath, resavedPath) +const resavedBytes = new Uint8Array(await readFile(resavedPath)) +const expectedNativeElements = [{ object: 'AreaBox', typeId: 'Part::Box', subElements: ['Face1', 'Face2'] }] +const nativeOutputMatches = [nativeAfter.result.reopened, nativeAfter.result.resaved].every((snapshot: any) => snapshot.measure.area.numeric === 20 && isDeepStrictEqual(snapshot.measure.elements, expectedNativeElements)) +const measureProperty = (inspection: typeof inspectedBefore, name: string) => inspection.objects.find((object) => object.name === 'AreaProbe')?.properties.find((property) => property.name === name) +const sourceGeometryPreserved = isDeepStrictEqual(native.result.source, nativeAfter.result.reopened.source) && isDeepStrictEqual(native.result.source, nativeAfter.result.resaved.source) +const zeroUnknownDrift = opaqueEntriesPreserved && semanticObjectsPreserved && nativeOutputMatches && sourceGeometryPreserved +const report = { + schemaVersion: 1, + status: zeroUnknownDrift ? 'pass' : 'fail', + baselineId: 'freecad-1.1.1-property-area-roundtrip', + freecadVersion: native.freecadVersion, + gitCommit: native.gitCommit, + archives: { + nativeInitial: { path: '.cache/freecad/property-area-roundtrip/native-initial.FCStd', bytes: nativeBytes.byteLength, sha256: createHash('sha256').update(nativeBytes).digest('hex') }, + webEdited: { path: '.cache/freecad/property-area-roundtrip/web-edited.FCStd', bytes: editedBytes.byteLength, sha256: createHash('sha256').update(editedBytes).digest('hex') }, + nativeResaved: { path: '.cache/freecad/property-area-roundtrip/native-resaved.FCStd', bytes: resavedBytes.byteLength, sha256: createHash('sha256').update(resavedBytes).digest('hex') }, + }, + nativeInitial: native.result, + web: { + before: { area: measureProperty(inspectedBefore, 'Area'), elements: measureProperty(inspectedBefore, 'Elements') }, + after: { area: measureProperty(inspectedAfter, 'Area'), elements: measureProperty(inspectedAfter, 'Elements') }, + objectSetPreserved: inspectedBefore.objects.map((object) => `${object.name}:${object.typeId}`).join('|') === inspectedAfter.objects.map((object) => `${object.name}:${object.typeId}`).join('|'), + semanticObjectsPreserved, + opaquePathsPreserved: opaquePaths.length, + opaqueEntriesPreserved, + }, + nativeAfter: nativeAfter.result, + classification: { + webArea: Number(measureProperty(inspectedAfter, 'Area')?.value), + webElementCount: measureProperty(inspectedAfter, 'Elements')?.linkSubs?.length, + reopenedArea: nativeAfter.result.reopened.measure.area.numeric, + resavedArea: nativeAfter.result.resaved.measure.area.numeric, + nativeOutputMatches, + sourceGeometryPreserved, + unknownSemanticDrift: !zeroUnknownDrift, + zeroUnknownDrift, + }, +} +await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-area-roundtrip.json', classification: report.classification, opaqueEntriesPreserved: report.web.opaqueEntriesPreserved }, null, 2)) diff --git a/scripts/run-freecad-property-area-success.mjs b/scripts/run-freecad-property-area-success.mjs new file mode 100644 index 0000000..6887c88 --- /dev/null +++ b/scripts/run-freecad-property-area-success.mjs @@ -0,0 +1,29 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const executable = process.env.FREECAD_CMD || resolve(root, '.cache/freecad/install-desktop/bin/FreeCADCmd') +const outputPath = resolve(root, 'config/freecad-property-area-success.json') +const scriptPath = resolve(root, 'scripts/freecad-property-area-success.py') +const sysroot = resolve(root, '.cache/freecad/sysroot') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyArea success probe executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 16 * 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +const marker = 'FREECAD_PROPERTY_AREA_SUCCESS_RESULT=' +const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) +if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyArea success probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-area-success.json', cases: report.cases.length, property: report.property, values: report.cases.map(({ id, value }) => ({ id, area: value.numeric })) }, null, 2)) diff --git a/scripts/run-freecad-property-boollist-failure.mjs b/scripts/run-freecad-property-boollist-failure.mjs new file mode 100644 index 0000000..310bf40 --- /dev/null +++ b/scripts/run-freecad-property-boollist-failure.mjs @@ -0,0 +1,27 @@ +import { existsSync } from 'node:fs' +import { readFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-boollist-failure.py') +const outputPath = resolve(root, 'config/freecad-property-boollist-failure.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyBoolList failure executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_BOOLLIST_FAILURE_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_BOOLLIST_FAILURE_RESULT=')) throw new Error(`FreeCAD PropertyBoolList failure probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-boollist-failure.json', failures: report.writable.failures.map(({ id, exception }) => ({ id, exception })), disabled: report.writable.disabled, links: report.links.map(({ objectTypeId, directWrite, invalidElement, transaction }) => ({ objectTypeId, directWrite, invalidElement, transaction })), cancellationBoundary: report.cancellationBoundary }, null, 2)) diff --git a/scripts/run-freecad-property-boollist-mutation.mjs b/scripts/run-freecad-property-boollist-mutation.mjs new file mode 100644 index 0000000..bfab301 --- /dev/null +++ b/scripts/run-freecad-property-boollist-mutation.mjs @@ -0,0 +1,27 @@ +import { existsSync } from 'node:fs' +import { readFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-boollist-mutation.py') +const outputPath = resolve(root, 'config/freecad-property-boollist-mutation.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyBoolList mutation executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_BOOLLIST_MUTATION_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_BOOLLIST_MUTATION_RESULT=')) throw new Error(`FreeCAD PropertyBoolList mutation probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-boollist-mutation.json', cases: report.cases.map(({ objectTypeId, mode, before, touchedAfterEdit, edited, touchedAfterRestore, restored, valueRestored, shapeRestored, objectsRestored }) => ({ objectTypeId, mode, values: { before: before.value, touchedAfterEdit: touchedAfterEdit.value, edited: edited.value, touchedAfterRestore: touchedAfterRestore.value, restored: restored.value }, states: { before: before.objectState, touchedAfterEdit: touchedAfterEdit.objectState, edited: edited.objectState, touchedAfterRestore: touchedAfterRestore.objectState, restored: restored.objectState }, valueRestored, shapeRestored, objectsRestored })) }, null, 2)) diff --git a/scripts/run-freecad-property-boollist-roundtrip.ts b/scripts/run-freecad-property-boollist-roundtrip.ts new file mode 100644 index 0000000..b69846f --- /dev/null +++ b/scripts/run-freecad-property-boollist-roundtrip.ts @@ -0,0 +1,101 @@ +import { createHash } from 'node:crypto' +import { existsSync } from 'node:fs' +import { mkdir, readFile, writeFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' +import { isDeepStrictEqual } from 'node:util' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' + +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 scriptPath = resolve(root, 'scripts/freecad-property-boollist-roundtrip.py') +const outputDirectory = resolve(root, '.cache/freecad/property-boollist-roundtrip') +const nativePath = resolve(outputDirectory, 'native-initial.FCStd') +const webPath = resolve(outputDirectory, 'web-edited.FCStd') +const resavedPath = resolve(outputDirectory, 'native-resaved.FCStd') +const reportPath = resolve(root, 'config/freecad-property-boollist-roundtrip.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyBoolList roundtrip executable is missing: ${executable}`) +await mkdir(outputDirectory, { recursive: true }) + +const runNative = (mode: 'create' | 'verify', path: string, resaved = '') => { + const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_BOOLLIST_ROUNDTRIP_MODE: mode, + FREECAD_PROPERTY_BOOLLIST_ROUNDTRIP_PATH: path, + FREECAD_PROPERTY_BOOLLIST_ROUNDTRIP_RESAVED_PATH: resaved, + 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}` : ''}`, + }, + }) + const output = `${execution.stdout || ''}\n${execution.stderr || ''}` + const marker = 'FREECAD_PROPERTY_BOOLLIST_ROUNDTRIP_RESULT=' + const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) + if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyBoolList ${mode} probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) + return JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +} + +const target = [true, false, true, false] +const native = runNative('create', nativePath) +const nativeBytes = new Uint8Array(await readFile(nativePath)) +const facade = createWebCadFacade({ runtimeMode: 'mock' }) +const inspectedBefore = facade.project.fcstd.inspect(nativeBytes) +const editedBytes = facade.project.fcstd.rewriteBoolList(nativeBytes, { + objectName: 'BoolListProbe', + propertyName: 'BoolList', + value: target, + expectedValue: [false], +}) +await facade.project.dispose() +await writeFile(webPath, editedBytes) +const inspectedAfter = facade.project.fcstd.inspect(editedBytes) +const initialFiles = unzipSync(nativeBytes) +const editedFiles = unzipSync(editedBytes) +const opaquePaths = Object.keys(initialFiles).filter((path) => path.toLowerCase() !== 'document.xml') +const opaqueEntriesPreserved = opaquePaths.every((path) => Buffer.from(initialFiles[path]).equals(Buffer.from(editedFiles[path] ?? new Uint8Array()))) +const withoutEditedProperty = (inspection: typeof inspectedBefore) => inspection.objects.map((object) => ({ ...object, properties: object.name === 'BoolListProbe' ? object.properties.filter((property) => property.name !== 'BoolList') : object.properties })) +const semanticObjectsPreserved = isDeepStrictEqual(withoutEditedProperty(inspectedBefore), withoutEditedProperty(inspectedAfter)) +const nativeAfter = runNative('verify', webPath, resavedPath) +const resavedBytes = new Uint8Array(await readFile(resavedPath)) +const nativeOutputMatches = [nativeAfter.result.reopened, nativeAfter.result.resaved].every((snapshot: any) => isDeepStrictEqual(snapshot.object.value, target)) +const objectSetPreserved = isDeepStrictEqual(native.result.objectSet, nativeAfter.result.reopened.objectSet) && isDeepStrictEqual(native.result.objectSet, nativeAfter.result.resaved.objectSet) +const zeroUnknownDrift = opaqueEntriesPreserved && semanticObjectsPreserved && nativeOutputMatches && objectSetPreserved +const property = (inspection: typeof inspectedBefore) => inspection.objects.find((object) => object.name === 'BoolListProbe')?.properties.find((candidate) => candidate.name === 'BoolList') +const report = { + schemaVersion: 1, + status: zeroUnknownDrift ? 'pass' : 'fail', + baselineId: 'freecad-1.1.1-property-boollist-roundtrip', + freecadVersion: native.freecadVersion, + gitCommit: native.gitCommit, + archives: { + nativeInitial: { path: '.cache/freecad/property-boollist-roundtrip/native-initial.FCStd', bytes: nativeBytes.byteLength, sha256: createHash('sha256').update(nativeBytes).digest('hex') }, + webEdited: { path: '.cache/freecad/property-boollist-roundtrip/web-edited.FCStd', bytes: editedBytes.byteLength, sha256: createHash('sha256').update(editedBytes).digest('hex') }, + nativeResaved: { path: '.cache/freecad/property-boollist-roundtrip/native-resaved.FCStd', bytes: resavedBytes.byteLength, sha256: createHash('sha256').update(resavedBytes).digest('hex') }, + }, + nativeInitial: native.result, + web: { + before: property(inspectedBefore), + after: property(inspectedAfter), + objectSetPreserved, + semanticObjectsPreserved, + opaquePathsPreserved: opaquePaths.length, + opaqueEntriesPreserved, + }, + nativeAfter: nativeAfter.result, + classification: { + webValue: property(inspectedAfter)?.value, + reopenedValue: nativeAfter.result.reopened.object.value, + resavedValue: nativeAfter.result.resaved.object.value, + nativeOutputMatches, + unknownSemanticDrift: !zeroUnknownDrift, + zeroUnknownDrift, + }, +} +await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-boollist-roundtrip.json', values: report.classification, opaqueEntriesPreserved }, null, 2)) diff --git a/scripts/run-freecad-property-boollist-success.mjs b/scripts/run-freecad-property-boollist-success.mjs new file mode 100644 index 0000000..ca3b296 --- /dev/null +++ b/scripts/run-freecad-property-boollist-success.mjs @@ -0,0 +1,27 @@ +import { existsSync } from 'node:fs' +import { readFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-boollist-success.py') +const outputPath = resolve(root, 'config/freecad-property-boollist-success.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyBoolList executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_BOOLLIST_SUCCESS_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_BOOLLIST_SUCCESS_RESULT=')) throw new Error(`FreeCAD PropertyBoolList success probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-boollist-success.json', caseCount: report.caseCount, cases: report.cases.map(({ objectTypeId, propertyName, mode, phases }) => ({ objectTypeId, propertyName, mode, values: Object.fromEntries(Object.entries(phases).map(([phase, snapshot]) => [phase, snapshot.value])) })) }, null, 2)) diff --git a/scripts/run-freecad-property-color-failure.mjs b/scripts/run-freecad-property-color-failure.mjs new file mode 100644 index 0000000..2bd9dec --- /dev/null +++ b/scripts/run-freecad-property-color-failure.mjs @@ -0,0 +1,27 @@ +import { existsSync } from 'node:fs' +import { readFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-color-failure.py') +const outputPath = resolve(root, 'config/freecad-property-color-failure.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyColor failure executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_COLOR_FAILURE_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_COLOR_FAILURE_RESULT=')) throw new Error(`FreeCAD PropertyColor failure probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-color-failure.json', coercions: report.coercions.map(({ id, accepted, after, exception }) => ({ id, accepted, after, exception })), failures: report.failures.map(({ id, exception, valuePreserved }) => ({ id, exception, valuePreserved })), disabled: report.disabled, transaction: report.transaction, cancellationBoundary: report.cancellationBoundary }, null, 2)) diff --git a/scripts/run-freecad-property-color-mutation.mjs b/scripts/run-freecad-property-color-mutation.mjs new file mode 100644 index 0000000..96f6bd5 --- /dev/null +++ b/scripts/run-freecad-property-color-mutation.mjs @@ -0,0 +1,27 @@ +import { existsSync } from 'node:fs' +import { readFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-color-mutation.py') +const outputPath = resolve(root, 'config/freecad-property-color-mutation.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyColor mutation executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_COLOR_MUTATION_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_COLOR_MUTATION_RESULT=')) throw new Error(`FreeCAD PropertyColor mutation probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-color-mutation.json', caseCount: report.caseCount, cases: report.cases.map(({ objectTypeId, propertyName, before, touchedAfterEdit, edited, touchedAfterRestore, restored, mutationDetected, restoredExactly }) => ({ objectTypeId, propertyName, values: { before: before.value, touchedAfterEdit: touchedAfterEdit.value, edited: edited.value, touchedAfterRestore: touchedAfterRestore.value, restored: restored.value }, states: { before: before.objectState, touchedAfterEdit: touchedAfterEdit.objectState, edited: edited.objectState, touchedAfterRestore: touchedAfterRestore.objectState, restored: restored.objectState }, mutationDetected, restoredExactly })) }, null, 2)) diff --git a/scripts/run-freecad-property-color-roundtrip.ts b/scripts/run-freecad-property-color-roundtrip.ts new file mode 100644 index 0000000..785c909 --- /dev/null +++ b/scripts/run-freecad-property-color-roundtrip.ts @@ -0,0 +1,105 @@ +import { createHash } from 'node:crypto' +import { existsSync } from 'node:fs' +import { mkdir, readFile, writeFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' +import { isDeepStrictEqual } from 'node:util' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import type { ColorValue } from '../src/facade/types' + +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 scriptPath = resolve(root, 'scripts/freecad-property-color-roundtrip.py') +const outputDirectory = resolve(root, '.cache/freecad/property-color-roundtrip') +const nativePath = resolve(outputDirectory, 'native-initial.FCStd') +const webPath = resolve(outputDirectory, 'web-edited.FCStd') +const resavedPath = resolve(outputDirectory, 'native-resaved.FCStd') +const reportPath = resolve(root, 'config/freecad-property-color-roundtrip.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyColor roundtrip executable is missing: ${executable}`) +await mkdir(outputDirectory, { recursive: true }) + +const runNative = (mode: 'create' | 'verify', path: string, resaved = '') => { + const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_COLOR_ROUNDTRIP_MODE: mode, + FREECAD_PROPERTY_COLOR_ROUNDTRIP_PATH: path, + FREECAD_PROPERTY_COLOR_ROUNDTRIP_RESAVED_PATH: resaved, + 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}` : ''}`, + }, + }) + const output = `${execution.stdout || ''}\n${execution.stderr || ''}` + const marker = 'FREECAD_PROPERTY_COLOR_ROUNDTRIP_RESULT=' + const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) + if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyColor ${mode} probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) + return JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +} + +const target: ColorValue = [0.2, 0.4, 0.6, 0.8] +const initial: ColorValue = [17 / 255, 34 / 255, 51 / 255, 68 / 255] +const native = runNative('create', nativePath) +const nativeBytes = new Uint8Array(await readFile(nativePath)) +const facade = createWebCadFacade({ runtimeMode: 'mock' }) +const inspectedBefore = facade.project.fcstd.inspect(nativeBytes) +const editedBytes = facade.project.fcstd.rewriteColor(nativeBytes, { + objectName: 'ColorProbe', + propertyName: 'Colour', + value: target, + expectedValue: initial, +}) +const inspectedAfter = facade.project.fcstd.inspect(editedBytes) +await facade.project.dispose() +await writeFile(webPath, editedBytes) +const initialFiles = unzipSync(nativeBytes) +const editedFiles = unzipSync(editedBytes) +const opaquePaths = Object.keys(initialFiles).filter((path) => path.toLowerCase() !== 'document.xml') +const opaqueEntriesPreserved = opaquePaths.every((path) => Buffer.from(initialFiles[path]).equals(Buffer.from(editedFiles[path] ?? new Uint8Array()))) +const withoutEditedProperty = (inspection: typeof inspectedBefore) => inspection.objects.map((object) => ({ ...object, properties: object.name === 'ColorProbe' ? object.properties.filter((property) => property.name !== 'Colour') : object.properties })) +const semanticObjectsPreserved = isDeepStrictEqual(withoutEditedProperty(inspectedBefore), withoutEditedProperty(inspectedAfter)) +const nativeAfter = runNative('verify', webPath, resavedPath) +const resavedBytes = new Uint8Array(await readFile(resavedPath)) +const approximatelyTarget = (value: unknown) => Array.isArray(value) && value.length === target.length && value.every((channel, index) => typeof channel === 'number' && Math.abs(channel - target[index]) <= 1e-7) +const nativeOutputMatches = [nativeAfter.result.reopened, nativeAfter.result.resaved].every((snapshot: any) => approximatelyTarget(snapshot.object.value)) && isDeepStrictEqual(nativeAfter.result.reopened.object.value, nativeAfter.result.resaved.object.value) +const objectSetPreserved = isDeepStrictEqual(native.result.objectSet, nativeAfter.result.reopened.objectSet) && isDeepStrictEqual(native.result.objectSet, nativeAfter.result.resaved.objectSet) +const zeroUnknownDrift = opaqueEntriesPreserved && semanticObjectsPreserved && nativeOutputMatches && objectSetPreserved +const property = (inspection: typeof inspectedBefore) => inspection.objects.find((object) => object.name === 'ColorProbe')?.properties.find((candidate) => candidate.name === 'Colour') +const report = { + schemaVersion: 1, + status: zeroUnknownDrift ? 'pass' : 'fail', + baselineId: 'freecad-1.1.1-property-color-roundtrip', + freecadVersion: native.freecadVersion, + gitCommit: native.gitCommit, + archives: { + nativeInitial: { path: '.cache/freecad/property-color-roundtrip/native-initial.FCStd', bytes: nativeBytes.byteLength, sha256: createHash('sha256').update(nativeBytes).digest('hex') }, + webEdited: { path: '.cache/freecad/property-color-roundtrip/web-edited.FCStd', bytes: editedBytes.byteLength, sha256: createHash('sha256').update(editedBytes).digest('hex') }, + nativeResaved: { path: '.cache/freecad/property-color-roundtrip/native-resaved.FCStd', bytes: resavedBytes.byteLength, sha256: createHash('sha256').update(resavedBytes).digest('hex') }, + }, + nativeInitial: native.result, + web: { + before: property(inspectedBefore), + after: property(inspectedAfter), + objectSetPreserved, + semanticObjectsPreserved, + opaquePathsPreserved: opaquePaths.length, + opaqueEntriesPreserved, + }, + nativeAfter: nativeAfter.result, + classification: { + requestedValue: target, + webValue: property(inspectedAfter)?.value, + reopenedValue: nativeAfter.result.reopened.object.value, + resavedValue: nativeAfter.result.resaved.object.value, + nativeOutputMatches, + unknownSemanticDrift: !zeroUnknownDrift, + zeroUnknownDrift, + }, +} +await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-color-roundtrip.json', values: report.classification, opaqueEntriesPreserved }, null, 2)) diff --git a/scripts/run-freecad-property-color-success.mjs b/scripts/run-freecad-property-color-success.mjs new file mode 100644 index 0000000..fac61eb --- /dev/null +++ b/scripts/run-freecad-property-color-success.mjs @@ -0,0 +1,27 @@ +import { existsSync } from 'node:fs' +import { readFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-color-success.py') +const outputPath = resolve(root, 'config/freecad-property-color-success.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyColor executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_COLOR_SUCCESS_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_COLOR_SUCCESS_RESULT=')) throw new Error(`FreeCAD PropertyColor success probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-color-success.json', caseCount: report.caseCount, cases: report.cases.map(({ objectTypeId, propertyName, phases }) => ({ objectTypeId, propertyName, values: Object.fromEntries(Object.entries(phases).map(([phase, snapshot]) => [phase, snapshot.value])), finalState: phases.restored.objectState, finalStatus: phases.restored.statusString })) }, null, 2)) diff --git a/scripts/run-freecad-property-colorlist-failure.mjs b/scripts/run-freecad-property-colorlist-failure.mjs new file mode 100644 index 0000000..1d8777a --- /dev/null +++ b/scripts/run-freecad-property-colorlist-failure.mjs @@ -0,0 +1,27 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-colorlist-failure.py') +const outputPath = resolve(root, 'config/freecad-property-colorlist-failure.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyColorList executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_COLORLIST_FAILURE_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_COLORLIST_FAILURE_RESULT=')) throw new Error(`FreeCAD PropertyColorList failure probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-colorlist-failure.json', coercions: report.coercions.map(({ id, accepted, after, exception }) => ({ id, accepted, after, exception })), failures: report.failures.map(({ id, exception, valuePreserved, after }) => ({ id, exception, valuePreserved, after })), disabled: report.disabled, transaction: report.transaction, cancellationBoundary: report.cancellationBoundary }, null, 2)) diff --git a/scripts/run-freecad-property-colorlist-mutation.mjs b/scripts/run-freecad-property-colorlist-mutation.mjs new file mode 100644 index 0000000..2191b95 --- /dev/null +++ b/scripts/run-freecad-property-colorlist-mutation.mjs @@ -0,0 +1,27 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-colorlist-mutation.py') +const outputPath = resolve(root, 'config/freecad-property-colorlist-mutation.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyColorList executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_COLORLIST_MUTATION_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_COLORLIST_MUTATION_RESULT=')) throw new Error(`FreeCAD PropertyColorList mutation probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-colorlist-mutation.json', caseCount: report.caseCount, cases: report.cases.map(({ objectTypeId, before, touchedAfterEdit, edited, touchedAfterRestore, restored, mutationDetected, restoredExactly }) => ({ objectTypeId, values: { before: before.value, touchedAfterEdit: touchedAfterEdit.value, edited: edited.value, touchedAfterRestore: touchedAfterRestore.value, restored: restored.value }, states: { before: before.objectState, touchedAfterEdit: touchedAfterEdit.objectState, edited: edited.objectState, touchedAfterRestore: touchedAfterRestore.objectState, restored: restored.objectState }, mutationDetected, restoredExactly })) }, null, 2)) diff --git a/scripts/run-freecad-property-colorlist-roundtrip.ts b/scripts/run-freecad-property-colorlist-roundtrip.ts new file mode 100644 index 0000000..0975c99 --- /dev/null +++ b/scripts/run-freecad-property-colorlist-roundtrip.ts @@ -0,0 +1,120 @@ +import { createHash } from 'node:crypto' +import { existsSync } from 'node:fs' +import { mkdir, readFile, writeFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' +import { isDeepStrictEqual } from 'node:util' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import type { ColorListValue } from '../src/facade/types' + +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 scriptPath = resolve(root, 'scripts/freecad-property-colorlist-roundtrip.py') +const outputDirectory = resolve(root, '.cache/freecad/property-colorlist-roundtrip') +const nativePath = resolve(outputDirectory, 'native-initial.FCStd') +const webPath = resolve(outputDirectory, 'web-edited.FCStd') +const resavedPath = resolve(outputDirectory, 'native-resaved.FCStd') +const reportPath = resolve(root, 'config/freecad-property-colorlist-roundtrip.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyColorList roundtrip executable is missing: ${executable}`) +await mkdir(outputDirectory, { recursive: true }) + +const runNative = (mode: 'create' | 'verify', path: string, resaved = '') => { + const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_COLORLIST_ROUNDTRIP_MODE: mode, + FREECAD_PROPERTY_COLORLIST_ROUNDTRIP_PATH: path, + FREECAD_PROPERTY_COLORLIST_ROUNDTRIP_RESAVED_PATH: resaved, + 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}` : ''}`, + }, + }) + const output = `${execution.stdout || ''}\n${execution.stderr || ''}` + const marker = 'FREECAD_PROPERTY_COLORLIST_ROUNDTRIP_RESULT=' + const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) + if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyColorList ${mode} probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) + return JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +} + +const initial: ColorListValue = [[17 / 255, 34 / 255, 51 / 255, 68 / 255]] +const target: ColorListValue = [ + [51 / 255, 102 / 255, 153 / 255, 204 / 255], + [17 / 255, 34 / 255, 51 / 255, 68 / 255], +] +const native = runNative('create', nativePath) +const nativeBytes = new Uint8Array(await readFile(nativePath)) +const facade = createWebCadFacade({ runtimeMode: 'mock' }) +const inspectedBefore = facade.project.fcstd.inspect(nativeBytes) +const property = (inspection: typeof inspectedBefore) => inspection.objects.find((object) => object.name === 'ColorListProbe')?.properties.find((candidate) => candidate.name === 'ColourList') +const resourcePath = property(inspectedBefore)?.resourcePath +if (!resourcePath) throw new Error('Native PropertyColorList archive has no external resource path.') +const editedBytes = facade.project.fcstd.rewriteColorList(nativeBytes, { + objectName: 'ColorListProbe', + propertyName: 'ColourList', + value: target, + expectedValue: initial, +}) +const inspectedAfter = facade.project.fcstd.inspect(editedBytes) +await facade.project.dispose() +await writeFile(webPath, editedBytes) +const initialFiles = unzipSync(nativeBytes) +const editedFiles = unzipSync(editedBytes) +const opaquePaths = Object.keys(initialFiles).filter((path) => path.toLowerCase() !== 'document.xml' && path !== resourcePath) +const opaqueEntriesPreserved = opaquePaths.every((path) => Buffer.from(initialFiles[path]).equals(Buffer.from(editedFiles[path] ?? new Uint8Array()))) +const editedResourceChanged = Boolean(editedFiles[resourcePath]) && !Buffer.from(initialFiles[resourcePath]).equals(Buffer.from(editedFiles[resourcePath])) +const withoutEditedProperty = (inspection: typeof inspectedBefore) => inspection.objects.map((object) => ({ ...object, properties: object.name === 'ColorListProbe' ? object.properties.filter((candidate) => candidate.name !== 'ColourList') : object.properties })) +const semanticObjectsPreserved = isDeepStrictEqual(withoutEditedProperty(inspectedBefore), withoutEditedProperty(inspectedAfter)) +const nativeAfter = runNative('verify', webPath, resavedPath) +const resavedBytes = new Uint8Array(await readFile(resavedPath)) +const approximatelyTarget = (value: unknown) => Array.isArray(value) && value.length === target.length && value.every((color, colorIndex) => Array.isArray(color) && color.length === 4 && color.every((channel, channelIndex) => typeof channel === 'number' && Math.abs(channel - target[colorIndex][channelIndex]) <= 1e-7)) +const nativeOutputMatches = [nativeAfter.result.reopened, nativeAfter.result.resaved].every((snapshot: any) => approximatelyTarget(snapshot.object.value)) && isDeepStrictEqual(nativeAfter.result.reopened.object.value, nativeAfter.result.resaved.object.value) +const objectSetPreserved = isDeepStrictEqual(native.result.objectSet, nativeAfter.result.reopened.objectSet) && isDeepStrictEqual(native.result.objectSet, nativeAfter.result.resaved.objectSet) +const resourcePathPreserved = property(inspectedAfter)?.resourcePath === resourcePath +const zeroUnknownDrift = opaqueEntriesPreserved && editedResourceChanged && semanticObjectsPreserved && nativeOutputMatches && objectSetPreserved && resourcePathPreserved +const report = { + schemaVersion: 1, + status: zeroUnknownDrift ? 'pass' : 'fail', + baselineId: 'freecad-1.1.1-property-colorlist-roundtrip', + freecadVersion: native.freecadVersion, + gitCommit: native.gitCommit, + propertyType: 'App::PropertyColorList', + archives: { + nativeInitial: { path: '.cache/freecad/property-colorlist-roundtrip/native-initial.FCStd', bytes: nativeBytes.byteLength, sha256: createHash('sha256').update(nativeBytes).digest('hex') }, + webEdited: { path: '.cache/freecad/property-colorlist-roundtrip/web-edited.FCStd', bytes: editedBytes.byteLength, sha256: createHash('sha256').update(editedBytes).digest('hex') }, + nativeResaved: { path: '.cache/freecad/property-colorlist-roundtrip/native-resaved.FCStd', bytes: resavedBytes.byteLength, sha256: createHash('sha256').update(resavedBytes).digest('hex') }, + }, + nativeInitial: native.result, + web: { + before: property(inspectedBefore), + after: property(inspectedAfter), + resource: { + path: resourcePath, + pathPreserved: resourcePathPreserved, + beforeBytes: initialFiles[resourcePath].byteLength, + afterBytes: editedFiles[resourcePath]?.byteLength ?? 0, + changed: editedResourceChanged, + }, + objectSetPreserved, + semanticObjectsPreserved, + opaquePathsPreserved: opaquePaths.length, + opaqueEntriesPreserved, + }, + nativeAfter: nativeAfter.result, + classification: { + requestedValue: target, + webValue: property(inspectedAfter)?.value, + reopenedValue: nativeAfter.result.reopened.object.value, + resavedValue: nativeAfter.result.resaved.object.value, + nativeOutputMatches, + unknownSemanticDrift: !zeroUnknownDrift, + zeroUnknownDrift, + }, +} +await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-colorlist-roundtrip.json', values: report.classification, resource: report.web.resource, opaqueEntriesPreserved }, null, 2)) diff --git a/scripts/run-freecad-property-colorlist-success.mjs b/scripts/run-freecad-property-colorlist-success.mjs new file mode 100644 index 0000000..c9b77fb --- /dev/null +++ b/scripts/run-freecad-property-colorlist-success.mjs @@ -0,0 +1,26 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-colorlist-success.py') +const outputPath = resolve(root, 'config/freecad-property-colorlist-success.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyColorList executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_COLORLIST_SUCCESS_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_COLORLIST_SUCCESS_RESULT=')) throw new Error(`FreeCAD PropertyColorList success probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await (await import('node:fs/promises')).readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-colorlist-success.json', caseCount: report.caseCount, cases: report.cases.map(({ objectTypeId, phases }) => ({ objectTypeId, lengths: Object.fromEntries(Object.entries(phases).map(([phase, snapshot]) => [phase, snapshot.value.length])), finalState: phases.restored.objectState, finalStatus: phases.restored.statusString })) }, null, 2)) diff --git a/scripts/run-freecad-property-direction-failure.mjs b/scripts/run-freecad-property-direction-failure.mjs new file mode 100644 index 0000000..ff851a1 --- /dev/null +++ b/scripts/run-freecad-property-direction-failure.mjs @@ -0,0 +1,98 @@ +import { existsSync, mkdtempSync, rmSync } from 'node:fs' +import { readFile, writeFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { join, resolve } from 'node:path' +import { tmpdir } from 'node:os' + +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 scriptPath = resolve(root, 'scripts/freecad-property-direction-failure.py') +const outputPath = resolve(root, 'config/freecad-property-direction-failure.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyDirection executable is missing: ${executable}`) +const baseEnv = { + ...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}` : ''}`, +} +const runProbe = ({ mode = 'main', target = outputPath, timeout = 120_000 } = {}) => spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout, + maxBuffer: 32 * 1024 * 1024, + env: { + ...baseEnv, + FREECAD_PROPERTY_DIRECTION_FAILURE_OUTPUT: target, + FREECAD_PROPERTY_DIRECTION_FAILURE_MODE: mode, + }, +}) +const execution = runProbe({ timeout: Number(process.env.FREECAD_PROPERTY_DIRECTION_FAILURE_TIMEOUT_MS || 120_000) }) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_DIRECTION_FAILURE_RESULT=')) throw new Error(`FreeCAD PropertyDirection failure probe failed with status ${execution.status}: ${execution.error?.message || 'process failed'}\n${output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +const isolatedRoot = mkdtempSync(join(tmpdir(), 'freecad-property-direction-')) +try { + report.nonFiniteConsumerBoundaries = [] + const isolatedTimeout = Number(process.env.FREECAD_PROPERTY_DIRECTION_NON_FINITE_TIMEOUT_MS || 5_000) + for (const hostId of ['Mirroring', 'ProjectOnSurface']) { + for (const valueId of ['nan', 'positive-infinity', 'negative-infinity']) { + const caseId = `${hostId}-${valueId}` + const attempts = [] + for (let attempt = 1; attempt <= 2; attempt += 1) { + const target = join(isolatedRoot, `${caseId}-${attempt}.json`) + const startedAt = Date.now() + const isolated = runProbe({ mode: `non-finite:${hostId}:${valueId}`, target, timeout: isolatedTimeout }) + const isolatedOutput = `${isolated.stdout || ''}\n${isolated.stderr || ''}`.trim() + const timedOut = isolated.error?.code === 'ETIMEDOUT' + let completedCase = null + if (!timedOut && isolated.status === 0 && isolatedOutput.includes('FREECAD_PROPERTY_DIRECTION_FAILURE_ISOLATED_RESULT=') && existsSync(target)) { + completedCase = JSON.parse(await readFile(target, 'utf8')).case + } + attempts.push({ + attempt, + timeoutMs: isolatedTimeout, + elapsedMs: Date.now() - startedAt, + timedOut, + exitStatus: isolated.status, + signal: isolated.signal, + errorCode: isolated.error?.code || null, + progressMarkerObserved: isolatedOutput.includes(`FREECAD_PROPERTY_DIRECTION_PROGRESS=${caseId}`), + completionMarkerObserved: isolatedOutput.includes('FREECAD_PROPERTY_DIRECTION_FAILURE_ISOLATED_RESULT='), + diagnostic: isolatedOutput.split('\n').filter((line) => line && !line.startsWith('FreeCAD 0.')).slice(-8), + completedCase, + outcome: timedOut ? 'timeout' : completedCase ? 'completed' : 'process-exited-without-completion', + }) + } + const outcomes = [...new Set(attempts.map(({ outcome }) => outcome))] + const stable = outcomes.length === 1 && attempts.every(({ progressMarkerObserved }) => progressMarkerObserved) + report.nonFiniteConsumerBoundaries.push({ + id: caseId, + mode: `non-finite:${hostId}:${valueId}`, + attemptCount: attempts.length, + attempts, + stable, + classification: !stable + ? 'native-nondeterministic' + : outcomes[0] === 'timeout' + ? 'native-synchronous-consumer-timeout' + : outcomes[0] === 'process-exited-without-completion' + ? 'native-process-exit-without-probe-completion' + : 'native-consumer-returned', + }) + } + } + report.status = report.nonFiniteConsumerBoundaries.every(({ stable, classification }) => stable && classification !== 'native-consumer-returned') ? 'pass' : 'fail' + await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +} finally { + rmSync(isolatedRoot, { recursive: true, force: true }) +} +console.log(JSON.stringify({ + status: report.status, + output: 'config/freecad-property-direction-failure.json', + acceptedCoercions: report.setterBoundaries.acceptedCoercions.map(({ id, accepted, after }) => ({ id, accepted, after })), + setterFailures: report.setterBoundaries.failures.map(({ id, exception, valuePreserved }) => ({ id, exception, valuePreserved })), + consumerFailures: report.consumerFailures.map(({ id, setterException, recomputeResult, afterRecompute }) => ({ id, setterException, recomputeResult, state: afterRecompute.state })), + nonFiniteConsumerBoundaries: report.nonFiniteConsumerBoundaries.map(({ id, classification, attemptCount, stable }) => ({ id, classification, attemptCount, stable })), + dependencyFailures: report.dependencyFailures.map(({ id, recomputeResult, afterRecompute }) => ({ id, recomputeResult, state: afterRecompute.state })), + transactionRestored: report.transaction.restored, +}, null, 2)) diff --git a/scripts/run-freecad-property-direction-mutation.mjs b/scripts/run-freecad-property-direction-mutation.mjs new file mode 100644 index 0000000..6a93990 --- /dev/null +++ b/scripts/run-freecad-property-direction-mutation.mjs @@ -0,0 +1,49 @@ +import { existsSync } from 'node:fs' +import { readFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-direction-mutation.py') +const outputPath = resolve(root, 'config/freecad-property-direction-mutation.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyDirection executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_DIRECTION_MUTATION_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_DIRECTION_MUTATION_RESULT=')) throw new Error(`FreeCAD PropertyDirection mutation probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ + status: report.status, + output: 'config/freecad-property-direction-mutation.json', + cases: report.cases.map(({ objectTypeId, propertyName, phases, valueChanged, valueRestored, geometryChanged, geometryRestored, objectsPreserved }) => ({ + objectTypeId, + propertyName, + values: { + before: phases.before.value, + edited: phases.afterRecompute.value, + restored: phases.afterRestoreRecompute.value, + }, + brepSha256: { + before: phases.before.shape.brepSha256, + edited: phases.afterRecompute.shape.brepSha256, + restored: phases.afterRestoreRecompute.shape.brepSha256, + }, + valueChanged, + valueRestored, + geometryChanged, + geometryRestored, + objectsPreserved, + })), +}, null, 2)) diff --git a/scripts/run-freecad-property-direction-roundtrip.ts b/scripts/run-freecad-property-direction-roundtrip.ts new file mode 100644 index 0000000..2889520 --- /dev/null +++ b/scripts/run-freecad-property-direction-roundtrip.ts @@ -0,0 +1,134 @@ +import { createHash } from 'node:crypto' +import { existsSync } from 'node:fs' +import { mkdir, readFile, writeFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' +import { isDeepStrictEqual } from 'node:util' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { decodeFcstdPropertyValue } from '../src/facade/fcstd' +import type { VectorValue } from '../src/facade/types' + +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 scriptPath = resolve(root, 'scripts/freecad-property-direction-roundtrip.py') +const outputDirectory = resolve(root, '.cache/freecad/property-direction-roundtrip') +const nativePath = resolve(outputDirectory, 'native-initial.FCStd') +const webPath = resolve(outputDirectory, 'web-edited.FCStd') +const resavedPath = resolve(outputDirectory, 'native-resaved.FCStd') +const repeatResavedPath = resolve(outputDirectory, 'native-resaved-repeat.FCStd') +const reportPath = resolve(root, 'config/freecad-property-direction-roundtrip.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyDirection roundtrip executable is missing: ${executable}`) +await mkdir(outputDirectory, { recursive: true }) + +const runNative = (mode: 'create' | 'verify', path: string, resaved = '') => { + const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_DIRECTION_ROUNDTRIP_MODE: mode, + FREECAD_PROPERTY_DIRECTION_ROUNDTRIP_PATH: path, + FREECAD_PROPERTY_DIRECTION_ROUNDTRIP_RESAVED_PATH: resaved, + 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}` : ''}`, + }, + }) + const output = `${execution.stdout || ''}\n${execution.stderr || ''}` + const marker = 'FREECAD_PROPERTY_DIRECTION_ROUNDTRIP_RESULT=' + const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) + if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyDirection ${mode} probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) + return JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +} + +const initial: VectorValue = { x: 0, y: 0, z: 1 } +const target: VectorValue = { x: 0.25, y: -0.5, z: 1.5 } +const native = runNative('create', nativePath) +const nativeBytes = new Uint8Array(await readFile(nativePath)) +const facade = createWebCadFacade({ runtimeMode: 'mock' }) +const inspectedBefore = facade.project.fcstd.inspect(nativeBytes) +const property = (inspection: typeof inspectedBefore) => inspection.objects.find((object) => object.name === 'DirectionMirror')?.properties.find((candidate) => candidate.name === 'Normal') +const editedBytes = facade.project.fcstd.rewriteDirection(nativeBytes, { + objectName: 'DirectionMirror', + propertyName: 'Normal', + value: target, + expectedValue: initial, +}) +const inspectedAfter = facade.project.fcstd.inspect(editedBytes) +await facade.project.dispose() +await writeFile(webPath, editedBytes) + +const initialFiles = unzipSync(nativeBytes) +const editedFiles = unzipSync(editedBytes) +const opaquePaths = Object.keys(initialFiles).filter((path) => path.toLowerCase() !== 'document.xml') +const opaqueEntriesPreserved = opaquePaths.every((path) => Buffer.from(initialFiles[path]).equals(Buffer.from(editedFiles[path] ?? new Uint8Array()))) +const withoutEditedProperty = (inspection: typeof inspectedBefore) => inspection.objects.map((object) => ({ ...object, properties: object.name === 'DirectionMirror' ? object.properties.filter((candidate) => candidate.name !== 'Normal') : object.properties })) +const semanticObjectsPreserved = isDeepStrictEqual(withoutEditedProperty(inspectedBefore), withoutEditedProperty(inspectedAfter)) +const editedDocumentXml = new TextDecoder().decode(editedFiles['Document.xml']) +const targetMarkedTouched = /]*name="DirectionMirror")(?=[^>]*Touched="1")[^>]*\/>/.test(editedDocumentXml) +const nativeAfter = runNative('verify', webPath, resavedPath) +const nativeRepeat = runNative('verify', webPath, repeatResavedPath) +const resavedBytes = new Uint8Array(await readFile(resavedPath)) +const repeatResavedBytes = new Uint8Array(await readFile(repeatResavedPath)) +const nativeSnapshots = [nativeAfter.result.reopened, nativeAfter.result.resaved, nativeRepeat.result.reopened, nativeRepeat.result.resaved] +const nativeOutputMatches = nativeSnapshots.every((snapshot: any) => isDeepStrictEqual(snapshot.object.value, target)) +const shapeStructure = ({ brepSha256: _brepSha256, ...shape }: Record) => shape +const nativeShapeStructureStable = nativeSnapshots.every((snapshot: any) => isDeepStrictEqual(shapeStructure(snapshot.object.shape), shapeStructure(nativeAfter.result.reopened.object.shape))) +const nativeBrepReserialized = nativeAfter.result.reopened.object.shape.brepSha256 !== nativeAfter.result.resaved.object.shape.brepSha256 +const nativeBrepEvolutionReproduced = nativeAfter.result.reopened.object.shape.brepSha256 === nativeRepeat.result.reopened.object.shape.brepSha256 && nativeAfter.result.resaved.object.shape.brepSha256 === nativeRepeat.result.resaved.object.shape.brepSha256 +const nativeShapeChanged = native.result.object.shape.brepSha256 !== nativeAfter.result.reopened.object.shape.brepSha256 && !isDeepStrictEqual(native.result.object.shape.bounds, nativeAfter.result.reopened.object.shape.bounds) +const objectSetPreserved = nativeSnapshots.every((snapshot: any) => isDeepStrictEqual(native.result.objectSet, snapshot.objectSet)) +const decodedAfter = property(inspectedAfter) ? decodeFcstdPropertyValue(property(inspectedAfter)!) : undefined +const webOutputMatches = decodedAfter?.decoded === true && isDeepStrictEqual(decodedAfter.value, target) +const nativeAllowedEvolution = nativeShapeStructureStable && nativeBrepReserialized && nativeBrepEvolutionReproduced +const zeroUnknownDrift = opaqueEntriesPreserved && semanticObjectsPreserved && targetMarkedTouched && webOutputMatches && nativeOutputMatches && nativeAllowedEvolution && nativeShapeChanged && objectSetPreserved +const report = { + schemaVersion: 1, + status: zeroUnknownDrift ? 'pass' : 'fail', + baselineId: 'freecad-1.1.1-property-direction-roundtrip', + freecadVersion: native.freecadVersion, + gitCommit: native.gitCommit, + propertyType: 'App::PropertyDirection', + archives: { + nativeInitial: { path: '.cache/freecad/property-direction-roundtrip/native-initial.FCStd', bytes: nativeBytes.byteLength, sha256: createHash('sha256').update(nativeBytes).digest('hex') }, + webEdited: { path: '.cache/freecad/property-direction-roundtrip/web-edited.FCStd', bytes: editedBytes.byteLength, sha256: createHash('sha256').update(editedBytes).digest('hex') }, + nativeResaved: { path: '.cache/freecad/property-direction-roundtrip/native-resaved.FCStd', bytes: resavedBytes.byteLength, sha256: createHash('sha256').update(resavedBytes).digest('hex') }, + nativeRepeatResaved: { path: '.cache/freecad/property-direction-roundtrip/native-resaved-repeat.FCStd', bytes: repeatResavedBytes.byteLength, sha256: createHash('sha256').update(repeatResavedBytes).digest('hex') }, + }, + nativeInitial: native.result, + web: { + before: property(inspectedBefore), + after: property(inspectedAfter), + targetMarkedTouched, + webOutputMatches, + objectSetPreserved, + semanticObjectsPreserved, + opaquePathsPreserved: opaquePaths.length, + opaqueEntriesPreserved, + }, + nativeAfter: nativeAfter.result, + nativeRepeat: nativeRepeat.result, + classification: { + requestedValue: target, + webValue: decodedAfter?.value, + reopenedValue: nativeAfter.result.reopened.object.value, + resavedValue: nativeAfter.result.resaved.object.value, + nativeOutputMatches, + nativeShapeChanged, + nativeShapeStructureStable, + nativeBrepReserialized, + nativeBrepEvolutionReproduced, + nativeAllowedEvolution: { + classification: nativeAllowedEvolution ? 'native-allowed-evolution' : 'unknown', + dimension: 'brep-serialization', + reason: 'FreeCAD save/reopen reserializes the recomputed Shape while direction, bounds, topology, mass properties and validity remain stable.', + }, + unknownSemanticDrift: !zeroUnknownDrift, + zeroUnknownDrift, + }, +} +await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-direction-roundtrip.json', values: report.classification, opaqueEntriesPreserved, semanticObjectsPreserved, targetMarkedTouched }, null, 2)) diff --git a/scripts/run-freecad-property-direction-success.mjs b/scripts/run-freecad-property-direction-success.mjs new file mode 100644 index 0000000..eb780a2 --- /dev/null +++ b/scripts/run-freecad-property-direction-success.mjs @@ -0,0 +1,27 @@ +import { existsSync } from 'node:fs' +import { readFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-direction-success.py') +const outputPath = resolve(root, 'config/freecad-property-direction-success.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyDirection executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_DIRECTION_SUCCESS_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_DIRECTION_SUCCESS_RESULT=')) throw new Error(`FreeCAD PropertyDirection success probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-direction-success.json', caseCount: report.caseCount, cases: report.cases.map(({ objectTypeId, propertyName, phases }) => ({ objectTypeId, propertyName, values: Object.fromEntries(Object.entries(phases).map(([phase, snapshots]) => [phase, snapshots.afterRecompute.value])), shapes: Object.fromEntries(Object.entries(phases).map(([phase, snapshots]) => [phase, { shapeType: snapshots.afterRecompute.shape.shapeType, valid: snapshots.afterRecompute.shape.valid, solids: snapshots.afterRecompute.shape.solids, faces: snapshots.afterRecompute.shape.faces, edges: snapshots.afterRecompute.shape.edges }])) })) }, null, 2)) diff --git a/scripts/run-freecad-property-file-failure.mjs b/scripts/run-freecad-property-file-failure.mjs new file mode 100644 index 0000000..ab13340 --- /dev/null +++ b/scripts/run-freecad-property-file-failure.mjs @@ -0,0 +1,19 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const executable = process.env.FREECAD_CMD || resolve(root, '.cache/freecad/install-desktop/bin/FreeCADCmd') +const outputPath = resolve(root, 'config/freecad-property-file-failure.json') +const scriptPath = resolve(root, 'scripts/freecad-property-file-failure.py') +const sysroot = resolve(root, '.cache/freecad/sysroot') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyFile failure probe executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { cwd: root, encoding: 'utf8', timeout: 120_000, maxBuffer: 16 * 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}` : ''}` } }) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +const marker = 'FREECAD_PROPERTY_FILE_FAILURE_RESULT=' +const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) +if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyFile failure probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-file-failure.json', failures: report.failures.length, transaction: report.transaction, cancellationBoundary: report.cancellationBoundary }, null, 2)) diff --git a/scripts/run-freecad-property-file-mutation.mjs b/scripts/run-freecad-property-file-mutation.mjs new file mode 100644 index 0000000..81794f7 --- /dev/null +++ b/scripts/run-freecad-property-file-mutation.mjs @@ -0,0 +1,19 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const executable = process.env.FREECAD_CMD || resolve(root, '.cache/freecad/install-desktop/bin/FreeCADCmd') +const outputPath = resolve(root, 'config/freecad-property-file-mutation.json') +const scriptPath = resolve(root, 'scripts/freecad-property-file-mutation.py') +const sysroot = resolve(root, '.cache/freecad/sysroot') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyFile mutation probe executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { cwd: root, encoding: 'utf8', timeout: 120_000, maxBuffer: 16 * 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}` : ''}` } }) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +const marker = 'FREECAD_PROPERTY_FILE_MUTATION_RESULT=' +const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) +if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyFile mutation probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-file-mutation.json', classification: report.classification }, null, 2)) diff --git a/scripts/run-freecad-property-file-roundtrip.ts b/scripts/run-freecad-property-file-roundtrip.ts new file mode 100644 index 0000000..ce33761 --- /dev/null +++ b/scripts/run-freecad-property-file-roundtrip.ts @@ -0,0 +1,123 @@ +import { createHash } from 'node:crypto' +import { existsSync } from 'node:fs' +import { mkdir, readFile, writeFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' +import { isDeepStrictEqual } from 'node:util' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { decodeFcstdPropertyValue } from '../src/facade/fcstd' + +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 scriptPath = resolve(root, 'scripts/freecad-property-file-roundtrip.py') +const outputDirectory = resolve(root, '.cache/freecad/property-file-roundtrip') +const nativePath = resolve(outputDirectory, 'native-initial.FCStd') +const webPath = resolve(outputDirectory, 'web-edited.FCStd') +const resavedPath = resolve(outputDirectory, 'native-resaved.FCStd') +const alternateAssetPath = resolve(outputDirectory, 'alternate.obj') +const reportPath = resolve(root, 'config/freecad-property-file-roundtrip.json') +const initial = '.cache/freecad/FreeCAD/data/tests/mesh.obj' +const target = '.cache/freecad/property-file-roundtrip/alternate.obj' +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyFile roundtrip executable is missing: ${executable}`) +if (!existsSync(resolve(root, initial))) throw new Error(`FreeCAD PropertyFile initial asset is missing: ${initial}`) +await mkdir(outputDirectory, { recursive: true }) +await writeFile(alternateAssetPath, '# PropertyFile roundtrip triangle\nv 0 0 0\nv 4 0 0\nv 0 3 0\nf 1 2 3\n') + +const runNative = (mode: 'create' | 'verify', path: string, resaved = '') => { + const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_FILE_ROUNDTRIP_MODE: mode, + FREECAD_PROPERTY_FILE_ROUNDTRIP_PATH: path, + FREECAD_PROPERTY_FILE_ROUNDTRIP_RESAVED_PATH: resaved, + FREECAD_PROPERTY_FILE_ROUNDTRIP_INITIAL: initial, + 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}` : ''}`, + }, + }) + const output = `${execution.stdout || ''}\n${execution.stderr || ''}` + const marker = 'FREECAD_PROPERTY_FILE_ROUNDTRIP_RESULT=' + const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) + if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyFile ${mode} probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) + return JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +} + +const native = runNative('create', nativePath) +const nativeBytes = new Uint8Array(await readFile(nativePath)) +const facade = createWebCadFacade({ runtimeMode: 'mock' }) +const inspectedBefore = facade.project.fcstd.inspect(nativeBytes) +const property = (inspection: typeof inspectedBefore) => inspection.objects.find((object) => object.name === 'FileProbe')?.properties.find((candidate) => candidate.name === 'FileName') +const editedBytes = facade.project.fcstd.rewriteFile(nativeBytes, { objectName: 'FileProbe', propertyName: 'FileName', value: target, expectedValue: initial }) +const inspectedAfter = facade.project.fcstd.inspect(editedBytes) +await facade.project.dispose() +await writeFile(webPath, editedBytes) + +const initialFiles = unzipSync(nativeBytes) +const editedFiles = unzipSync(editedBytes) +const opaquePaths = Object.keys(initialFiles).filter((path) => path.toLowerCase() !== 'document.xml') +const opaqueEntriesPreserved = opaquePaths.every((path) => Buffer.from(initialFiles[path]).equals(Buffer.from(editedFiles[path] ?? new Uint8Array()))) +const withoutEditedProperty = (inspection: typeof inspectedBefore) => inspection.objects.map((object) => ({ ...object, properties: object.name === 'FileProbe' ? object.properties.filter((candidate) => candidate.name !== 'FileName') : object.properties })) +const semanticObjectsPreserved = isDeepStrictEqual(withoutEditedProperty(inspectedBefore), withoutEditedProperty(inspectedAfter)) +const editedDocumentXml = new TextDecoder().decode(editedFiles['Document.xml']) +const targetMarkedTouched = /]*name="FileProbe")(?=[^>]*Touched="1")[^>]*\/>/.test(editedDocumentXml) +const decodedAfter = property(inspectedAfter) ? decodeFcstdPropertyValue(property(inspectedAfter)!) : undefined +const webOutputMatches = decodedAfter?.decoded === true && decodedAfter.value === target +const nativeAfter = runNative('verify', webPath, resavedPath) +const resavedBytes = new Uint8Array(await readFile(resavedPath)) +const nativeSnapshots = [nativeAfter.result.reopened, nativeAfter.result.resaved] +const nativeOutputMatches = nativeSnapshots.every((snapshot: any) => snapshot.object.value === target) +const objectSetPreserved = nativeSnapshots.every((snapshot: any) => isDeepStrictEqual(native.result.objectSet, snapshot.objectSet)) +const nativeMeshChanged = !isDeepStrictEqual(native.result.object.mesh, nativeAfter.result.reopened.object.mesh) +const nativeMeshStable = isDeepStrictEqual(nativeAfter.result.reopened.object.mesh, nativeAfter.result.resaved.object.mesh) +const asset = async (path: string) => { + const bytes = await readFile(resolve(root, path)) + return { path, bytes: bytes.byteLength, sha256: createHash('sha256').update(bytes).digest('hex') } +} +const assets = { initial: await asset(initial), target: await asset(target) } +const zeroUnknownDrift = opaqueEntriesPreserved && semanticObjectsPreserved && targetMarkedTouched && webOutputMatches && nativeOutputMatches && objectSetPreserved && nativeMeshChanged && nativeMeshStable +const report = { + schemaVersion: 1, + status: zeroUnknownDrift ? 'pass' : 'fail', + baselineId: 'freecad-1.1.1-property-file-roundtrip', + freecadVersion: native.freecadVersion, + gitCommit: native.gitCommit, + propertyType: 'App::PropertyFile', + assets, + archives: { + nativeInitial: { path: '.cache/freecad/property-file-roundtrip/native-initial.FCStd', bytes: nativeBytes.byteLength, sha256: createHash('sha256').update(nativeBytes).digest('hex') }, + webEdited: { path: '.cache/freecad/property-file-roundtrip/web-edited.FCStd', bytes: editedBytes.byteLength, sha256: createHash('sha256').update(editedBytes).digest('hex') }, + nativeResaved: { path: '.cache/freecad/property-file-roundtrip/native-resaved.FCStd', bytes: resavedBytes.byteLength, sha256: createHash('sha256').update(resavedBytes).digest('hex') }, + }, + nativeInitial: native.result, + web: { + before: property(inspectedBefore), + after: property(inspectedAfter), + targetMarkedTouched, + webOutputMatches, + semanticObjectsPreserved, + opaquePathsPreserved: opaquePaths.length, + opaqueEntriesPreserved, + }, + nativeAfter: nativeAfter.result, + classification: { + requestedValue: target, + webValue: decodedAfter?.value, + reopenedValue: nativeAfter.result.reopened.object.value, + resavedValue: nativeAfter.result.resaved.object.value, + nativeOutputMatches, + objectSetPreserved, + nativeMeshChanged, + nativeMeshStable, + externalResourceBoundary: 'project-relative-path; asset bytes remain external to FCStd', + unknownSemanticDrift: !zeroUnknownDrift, + zeroUnknownDrift, + }, +} +await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-file-roundtrip.json', values: report.classification, mesh: { initial: report.nativeInitial.object.mesh, reopened: report.nativeAfter.reopened.object.mesh }, opaqueEntriesPreserved }, null, 2)) diff --git a/scripts/run-freecad-property-file-success.mjs b/scripts/run-freecad-property-file-success.mjs new file mode 100644 index 0000000..41937fa --- /dev/null +++ b/scripts/run-freecad-property-file-success.mjs @@ -0,0 +1,22 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +const root = resolve(new URL('..', import.meta.url).pathname) +const executable = process.env.FREECAD_CMD || resolve(root, '.cache/freecad/install-desktop/bin/FreeCADCmd') +const outputPath = resolve(root, 'config/freecad-property-file-success.json') +const scriptPath = resolve(root, 'scripts/freecad-property-file-success.py') +const sysroot = resolve(root, '.cache/freecad/sysroot') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyFile success probe executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, encoding: 'utf8', timeout: 120_000, maxBuffer: 16 * 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}` : ''}` }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +const marker = 'FREECAD_PROPERTY_FILE_SUCCESS_RESULT=' +const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) +if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyFile success probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-file-success.json', phases: Object.keys(report.phases || {}), property: report.property }, null, 2)) diff --git a/scripts/run-freecad-property-fileincluded-failure.mjs b/scripts/run-freecad-property-fileincluded-failure.mjs new file mode 100644 index 0000000..3f4ad73 --- /dev/null +++ b/scripts/run-freecad-property-fileincluded-failure.mjs @@ -0,0 +1,27 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-fileincluded-failure.py') +const outputPath = resolve(root, 'config/freecad-property-fileincluded-failure.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyFileIncluded executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_FILEINCLUDED_FAILURE_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_FILEINCLUDED_FAILURE_RESULT=')) throw new Error(`FreeCAD PropertyFileIncluded failure probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-fileincluded-failure.json', failures: report.failures.map(({ id, assignmentException, valuePreserved }) => ({ id, assignmentException, valuePreserved })), acceptedRisks: report.acceptedRisks.map(({ id, assignmentException, oldFileRemoved, directoryAccepted }) => ({ id, assignmentException, oldFileRemoved, directoryAccepted })), filterOnly: report.filterOnly, editorReadOnly: report.editorReadOnly, immutable: report.immutable, transaction: { undoMode: report.transaction.undoMode, restored: report.transaction.restored, editedPathExistsAfterAbort: report.transaction.editedPathExistsAfterAbort } }, null, 2)) diff --git a/scripts/run-freecad-property-fileincluded-mutation.mjs b/scripts/run-freecad-property-fileincluded-mutation.mjs new file mode 100644 index 0000000..83a39a8 --- /dev/null +++ b/scripts/run-freecad-property-fileincluded-mutation.mjs @@ -0,0 +1,16 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-fileincluded-mutation.py') +const outputPath = resolve(root, 'config/freecad-property-fileincluded-mutation.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyFileIncluded executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { cwd: root, encoding: 'utf8', timeout: 120_000, maxBuffer: 32 * 1024 * 1024, env: { ...process.env, FREECAD_PROPERTY_FILEINCLUDED_MUTATION_OUTPUT: outputPath, 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}` : ''}` } }) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_FILEINCLUDED_MUTATION_RESULT=')) throw new Error(`FreeCAD PropertyFileIncluded mutation probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-fileincluded-mutation.json', caseCount: report.caseCount, restored: report.cases.map(({ objectTypeId, propertyName, pathStable, objectSetStable, before, edited, restored }) => ({ objectTypeId, propertyName, pathStable, objectSetStable, before: before.sha256, edited: edited.sha256, restored: restored.sha256 })) }, null, 2)) diff --git a/scripts/run-freecad-property-fileincluded-roundtrip.ts b/scripts/run-freecad-property-fileincluded-roundtrip.ts new file mode 100644 index 0000000..886003d --- /dev/null +++ b/scripts/run-freecad-property-fileincluded-roundtrip.ts @@ -0,0 +1,146 @@ +import { createHash } from 'node:crypto' +import { existsSync } from 'node:fs' +import { mkdir, readFile, writeFile } from 'node:fs/promises' +import { spawnSync } from 'node:child_process' +import { resolve } from 'node:path' +import { isDeepStrictEqual } from 'node:util' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import type { IncludedFileValue } from '../src/facade/types' + +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 scriptPath = resolve(root, 'scripts/freecad-property-fileincluded-roundtrip.py') +const outputDirectory = resolve(root, '.cache/freecad/property-fileincluded-roundtrip') +const initialAssetPath = resolve(outputDirectory, 'initial.bin') +const targetAssetPath = resolve(outputDirectory, 'target.bin') +const nativePath = resolve(outputDirectory, 'native-initial.FCStd') +const webPath = resolve(outputDirectory, 'web-edited.FCStd') +const resavedPath = resolve(outputDirectory, 'native-resaved.FCStd') +const reportPath = resolve(root, 'config/freecad-property-fileincluded-roundtrip.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyFileIncluded roundtrip executable is missing: ${executable}`) +await mkdir(outputDirectory, { recursive: true }) +const initialAsset = new Uint8Array([70, 114, 101, 101, 67, 65, 68, 0, 17, 34, 51, 255, 10]) +const targetAsset = new Uint8Array([87, 101, 98, 45, 101, 100, 105, 116, 101, 100, 0, 128, 64, 32, 16, 8, 4, 2, 1, 10]) +await writeFile(initialAssetPath, initialAsset) +await writeFile(targetAssetPath, targetAsset) + +const sha256 = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex') +const runNative = (mode: 'create' | 'verify', path: string, resaved = '') => { + const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_MODE: mode, + FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_PATH: path, + FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_RESAVED_PATH: resaved, + FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_SOURCE: initialAssetPath, + 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}` : ''}`, + }, + }) + const output = `${execution.stdout || ''}\n${execution.stderr || ''}` + const marker = 'FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_RESULT=' + const line = output.split(/\r?\n/).find((candidate) => candidate.includes(marker)) + if (execution.error || execution.status !== 0 || !line) throw new Error(`FreeCAD PropertyFileIncluded ${mode} probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) + return JSON.parse(line.slice(line.indexOf(marker) + marker.length)) +} + +const native = runNative('create', nativePath) +const nativeBytes = new Uint8Array(await readFile(nativePath)) +const facade = createWebCadFacade({ runtimeMode: 'mock' }) +const inspectedBefore = facade.project.fcstd.inspect(nativeBytes) +const property = (inspection: typeof inspectedBefore) => inspection.objects.find((object) => object.name === 'IncludedProbe')?.properties.find((candidate) => candidate.name === 'File') +const imported = await facade.project.fcstd.storeIncludedFiles(nativeBytes) +if (imported.length !== 1 || imported[0].path !== 'payload.bin') throw new Error('Native PropertyFileIncluded archive did not expose one payload.bin resource.') +const expectedValue = imported[0].value +const targetResource = await facade.project.resource.put(targetAsset, 'application/octet-stream') +const targetValue: IncludedFileValue = { schemaVersion: 1, archiveName: expectedValue.archiveName, resourceHash: targetResource.hash, byteLength: targetAsset.byteLength, mediaType: 'application/octet-stream' } +const editedBytes = await facade.project.fcstd.rewriteIncludedFile(nativeBytes, { objectName: 'IncludedProbe', propertyName: 'File', value: targetValue, expectedValue }) +const inspectedAfter = facade.project.fcstd.inspect(editedBytes) +await writeFile(webPath, editedBytes) + +const initialFiles = unzipSync(nativeBytes) +const editedFiles = unzipSync(editedBytes) +const resourcePath = property(inspectedBefore)?.resourcePath ?? '' +const opaquePaths = Object.keys(initialFiles).filter((path) => path.toLowerCase() !== 'document.xml' && path !== resourcePath) +const opaqueEntriesPreserved = opaquePaths.every((path) => Buffer.from(initialFiles[path]).equals(Buffer.from(editedFiles[path] ?? new Uint8Array()))) +const withoutEditedProperty = (inspection: typeof inspectedBefore) => inspection.objects.map((object) => ({ ...object, properties: object.name === 'IncludedProbe' ? object.properties.filter((candidate) => candidate.name !== 'File') : object.properties })) +const semanticObjectsPreserved = isDeepStrictEqual(withoutEditedProperty(inspectedBefore), withoutEditedProperty(inspectedAfter)) +const editedDocumentXml = new TextDecoder().decode(editedFiles['Document.xml']) +const targetMarkedTouched = /]*name="IncludedProbe")(?=[^>]*Touched="1")[^>]*\/>/.test(editedDocumentXml) +const webResource = property(inspectedAfter)?.includedFileResource +const webOutputMatches = resourcePath === 'payload.bin' && webResource?.path === resourcePath && webResource.byteLength === targetAsset.byteLength && Buffer.from(editedFiles[resourcePath]).equals(Buffer.from(targetAsset)) + +const nativeAfter = runNative('verify', webPath, resavedPath) +const resavedBytes = new Uint8Array(await readFile(resavedPath)) +const resavedInspection = facade.project.fcstd.inspect(resavedBytes) +const resavedProperty = property(resavedInspection) +const resavedFiles = unzipSync(resavedBytes) +await facade.project.resource.release(expectedValue.resourceHash) +await facade.project.resource.release(targetValue.resourceHash) +await facade.project.dispose() +const nativeSnapshots = [nativeAfter.result.reopened, nativeAfter.result.resaved] +const targetHash = sha256(targetAsset) +const nativeOutputMatches = nativeSnapshots.every((snapshot: any) => snapshot.object.baseName === 'payload.bin' && snapshot.object.exists === true && snapshot.object.bytes === targetAsset.byteLength && snapshot.object.sha256 === targetHash && snapshot.object.writeBits === 0 && snapshot.object.underTransientDir === true) +const objectSetPreserved = nativeSnapshots.every((snapshot: any) => isDeepStrictEqual(native.result.objectSet, snapshot.objectSet)) +const resavedResourceMatches = resavedProperty?.resourcePath === resourcePath && resavedProperty.includedFileResource?.byteLength === targetAsset.byteLength && Buffer.from(resavedFiles[resourcePath]).equals(Buffer.from(targetAsset)) +const zeroUnknownDrift = opaqueEntriesPreserved && semanticObjectsPreserved && targetMarkedTouched && webOutputMatches && nativeOutputMatches && objectSetPreserved && resavedResourceMatches +const artifact = (path: string, bytes: Uint8Array) => ({ path, bytes: bytes.byteLength, sha256: sha256(bytes) }) +const report = { + schemaVersion: 1, + status: zeroUnknownDrift ? 'pass' : 'fail', + baselineId: 'freecad-1.1.1-property-fileincluded-roundtrip', + freecadVersion: native.freecadVersion, + gitCommit: native.gitCommit, + propertyType: 'App::PropertyFileIncluded', + assets: { + initial: artifact('.cache/freecad/property-fileincluded-roundtrip/initial.bin', initialAsset), + target: artifact('.cache/freecad/property-fileincluded-roundtrip/target.bin', targetAsset), + }, + archives: { + nativeInitial: artifact('.cache/freecad/property-fileincluded-roundtrip/native-initial.FCStd', nativeBytes), + webEdited: artifact('.cache/freecad/property-fileincluded-roundtrip/web-edited.FCStd', editedBytes), + nativeResaved: artifact('.cache/freecad/property-fileincluded-roundtrip/native-resaved.FCStd', resavedBytes), + }, + nativeInitial: native.result, + web: { + before: property(inspectedBefore), + after: property(inspectedAfter), + resource: { + path: resourcePath, + pathPreserved: property(inspectedAfter)?.resourcePath === resourcePath, + beforeBytes: initialFiles[resourcePath]?.byteLength ?? 0, + afterBytes: editedFiles[resourcePath]?.byteLength ?? 0, + beforeSha256: sha256(initialFiles[resourcePath]), + afterSha256: sha256(editedFiles[resourcePath]), + changed: !Buffer.from(initialFiles[resourcePath]).equals(Buffer.from(editedFiles[resourcePath])), + }, + targetMarkedTouched, + webOutputMatches, + semanticObjectsPreserved, + opaquePathsPreserved: opaquePaths.length, + opaqueEntriesPreserved, + }, + nativeAfter: nativeAfter.result, + nativeResavedResource: resavedProperty?.includedFileResource, + classification: { + archiveName: resourcePath, + initialSha256: sha256(initialAsset), + targetSha256: targetHash, + reopenedSha256: nativeAfter.result.reopened.object.sha256, + resavedSha256: nativeAfter.result.resaved.object.sha256, + nativeOutputMatches, + objectSetPreserved, + resavedResourceMatches, + externalResourceBoundary: 'embedded FCStd ZIP entry restored to a read-only document transient file', + unknownSemanticDrift: !zeroUnknownDrift, + zeroUnknownDrift, + }, +} +await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-fileincluded-roundtrip.json', resource: report.web.resource, classification: report.classification }, null, 2)) diff --git a/scripts/run-freecad-property-fileincluded-success.mjs b/scripts/run-freecad-property-fileincluded-success.mjs new file mode 100644 index 0000000..e12c2a9 --- /dev/null +++ b/scripts/run-freecad-property-fileincluded-success.mjs @@ -0,0 +1,27 @@ +import { existsSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +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 scriptPath = resolve(root, 'scripts/freecad-property-fileincluded-success.py') +const outputPath = resolve(root, 'config/freecad-property-fileincluded-success.json') +if (!existsSync(executable)) throw new Error(`FreeCAD PropertyFileIncluded executable is missing: ${executable}`) +const execution = spawnSync(executable, ['--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), scriptPath], { + cwd: root, + encoding: 'utf8', + timeout: 120_000, + maxBuffer: 32 * 1024 * 1024, + env: { + ...process.env, + FREECAD_PROPERTY_FILEINCLUDED_SUCCESS_OUTPUT: outputPath, + 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}` : ''}`, + }, +}) +const output = `${execution.stdout || ''}\n${execution.stderr || ''}` +if (execution.error || execution.status !== 0 || !output.includes('FREECAD_PROPERTY_FILEINCLUDED_SUCCESS_RESULT=')) throw new Error(`FreeCAD PropertyFileIncluded success probe failed with status ${execution.status}: ${execution.error?.message || output.trim()}`) +const report = JSON.parse(await readFile(outputPath, 'utf8')) +console.log(JSON.stringify({ status: report.status, output: 'config/freecad-property-fileincluded-success.json', hostCaseCount: report.hostCaseCount, setterPhases: report.setterVariants.phases.map(({ id, baseName, bytes }) => ({ id, baseName, bytes })), collision: report.setterVariants.collision }, null, 2)) diff --git a/src/App.tsx b/src/App.tsx index ce3e757..0ce545e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -60,7 +60,7 @@ import { } from 'lucide-react' import { menuDefinitions, workbenchDefinitions, type MenuName, type WorkbenchId } from './freecadManifest' import { createLinuxcncIframeAdapter, createProductionFacade, createPumpHousingDemoDocument, NativeOcctHistoryWorkerProvider, prepareCamPipeline, submitCamPipelineToLinuxcnc, type BitBybitViewportAdapter, type BitBybitWebCadFacade, type CamAxisConfiguration, type CamCoolantMode, type CamCutDirection, type CamDressupKind, type CamKinematicOptions, type CamOperationKind, type CamPostprocessor, type CamPropertyValue, type CamRotaryAxis, type CamSnapshot, type CamStockMode, type DiagnosticTreeNode, type DocumentSnapshot, type FcstdInspection, type ModelTreeItem, type MultiTransformStep, type MultiTransformValue, type ObjectPropertySnapshot, type PlacementValue, type ProjectSummary, type PropertyValue, type ShapeHandle } from './facade' -import type { LinkSubListValue, LinkSubValue, ShapeResourceValue, TopoRefValue } from './facade/types' +import type { ColorListValue, ColorValue, IncludedFileValue, LinkSubListValue, LinkSubValue, ShapeResourceValue, TopoRefValue } from './facade/types' import { isFreecadPropertyHidden, isFreecadPropertyReadOnly } from './facade/propertyStatus' type Page = 'start' | 'projects' | 'workspace' | 'import' | 'export' | 'settings' | 'help' | 'diagnostics' | 'sync' @@ -975,7 +975,26 @@ function PropertyPanel({ facade, objectId, scope, showNotice }: { facade: BitByb return
{[...groups].map(([group, entries]) =>
{group}
{entries.map((property) => )}
)}
} -function PropertyEditor({ facade, objectId, property, showNotice }: { facade: BitBybitWebCadFacade; objectId: string; property: ObjectPropertySnapshot; showNotice: (message: string) => void }) { +const colorChannelByte = (value: number) => Math.max(0, Math.min(255, Math.round(value * 255))) +const colorValueHex = (value: ColorValue) => `#${value.slice(0, 3).map((channel) => colorChannelByte(channel).toString(16).padStart(2, '0')).join('')}` +const colorHexChannels = (value: string): [number, number, number] => [1, 3, 5].map((offset) => Number.parseInt(value.slice(offset, offset + 2), 16) / 255) as [number, number, number] + +function ColorListEditor({ label, value, commit }: { label: string; value: ColorListValue; commit: (value: ColorListValue) => boolean }) { + const replace = (index: number, color: ColorValue) => commit(value.map((entry, entryIndex) => entryIndex === index ? [...color] as ColorValue : [...entry] as ColorValue)) + return
+ {value.map((color, index) => { + const hex = colorValueHex(color) + return
+ { const [red, green, blue] = colorHexChannels(event.target.value); replace(index, [red, green, blue, color[3]]) }} /> + { const alpha = Number(event.target.value); if (!Number.isFinite(alpha) || !replace(index, [color[0], color[1], color[2], alpha])) event.target.value = String(color[3]) }} onKeyDown={(event) => { if (event.key === 'Enter') event.currentTarget.blur() }} /> + commit(value.filter((_, entryIndex) => entryIndex !== index).map((entry) => [...entry] as ColorValue))} /> +
+ })} +
commit([...value.map((entry) => [...entry] as ColorValue), [0, 0, 0, 1]])} />
+
+} + +export function PropertyEditor({ facade, objectId, property, showNotice }: { facade: BitBybitWebCadFacade; objectId: string; property: ObjectPropertySnapshot; showNotice: (message: string) => void }) { const commit = (value: PropertyValue) => { try { facade.app.document.setProperty({ objectId, propertyName: property.name, value }) @@ -985,9 +1004,11 @@ function PropertyEditor({ facade, objectId, property, showNotice }: { facade: Bi return false } } - const formatted = `${String(property.value ?? '')}${property.unit ? ` ${property.unit}` : ''}` + const includedFile = property.type === 'App::PropertyFileIncluded' && property.value && typeof property.value === 'object' && !Array.isArray(property.value) ? property.value as IncludedFileValue : null + const formatted = `${property.type === 'App::PropertyFileIncluded' ? includedFile?.archiveName ?? 'Empty' : String(property.value ?? '')}${property.unit ? ` ${property.unit}` : ''}` let editor: ReactNode if (property.readOnly || isFreecadPropertyReadOnly(property.nativeStatus)) editor = {formatted} + else if (property.type === 'App::PropertyFileIncluded') editor = else if (property.type === 'App::PropertyBool') editor = commit(event.target.checked)} /> else if (property.type === 'App::PropertyEnumeration') editor = else if (property.type === 'App::PropertyLink') { @@ -1029,13 +1050,20 @@ function PropertyEditor({ facade, objectId, property, showNotice }: { facade: Bi return commit(value) } editor =
{placement.position.x}, {placement.position.y}, {placement.position.z}
Position{(['x', 'y', 'z'] as const).map((key) => updatePlacement('position', key, Number(event.target.value))} />)}Axis{(['x', 'y', 'z'] as const).map((key) => updatePlacement('axis', key, Number(event.target.value))} />)}Angle updatePlacement('angle', null, Number(event.target.value))} />
- } else if (property.type === 'App::PropertyVector') { + } else if (property.type === 'App::PropertyVector' || property.type === 'App::PropertyDirection') { const vector = property.value as { x: number; y: number; z: number } editor =
{(['x', 'y', 'z'] as const).map((key) => commit({ ...vector, [key]: Number(event.target.value) })} />)}
} else if (property.type === 'App::PropertyLinkList' || property.type === 'App::PropertyStringList') editor = commit(event.target.value.split(',').map((entry) => entry.trim()).filter(Boolean))} /> + else if (property.type === 'App::PropertyBoolList') editor = entry ? 'true' : 'false').join(', ')} aria-label={property.label} onBlur={(event) => { const raw = event.target.value.split(',').map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0); const values = raw.map((entry) => entry === 'true' || entry === '1' ? true : entry === 'false' || entry === '0' ? false : null); if (values.some((value) => value === null) || !commit(values as boolean[])) event.target.value = (property.value as boolean[]).map((entry) => entry ? 'true' : 'false').join(', ') }} /> else if (property.type === 'App::PropertyFloatList') editor = { const values = event.target.value.split(',').map((entry) => Number(entry.trim())); if (!values.every((value) => Number.isFinite(value))) { event.target.value = (property.value as number[]).join(', '); return } if (!commit(values)) event.target.value = (property.value as number[]).join(', ') }} /> - else if (property.type === 'App::PropertyColor') editor = - else if (property.type === 'App::PropertyLength' || property.type === 'App::PropertyAngle' || property.type === 'App::PropertyPercent' || property.type === 'App::PropertyFloat' || property.type === 'App::PropertyInteger') editor = + else if (property.type === 'App::PropertyColorList') editor = + else if (property.type === 'App::PropertyColor' && property.scope === 'view') editor = + else if (property.type === 'App::PropertyColor') { + const color = property.value as ColorValue + const hex = colorValueHex(color) + editor = + } + else if (property.type === 'App::PropertyLength' || property.type === 'App::PropertyAngle' || property.type === 'App::PropertyAcceleration' || property.type === 'App::PropertyArea' || property.type === 'App::PropertyPercent' || property.type === 'App::PropertyFloat' || property.type === 'App::PropertyInteger') editor = else editor = { if (!commit(event.target.value)) event.target.value = String(property.value ?? '') }} onKeyDown={(event) => { if (event.key === 'Enter') event.currentTarget.blur() }} /> return <>
{property.label}
{editor}
{property.expression &&
{property.expression}
} } diff --git a/src/chromePropertyAccelerationHarness.tsx b/src/chromePropertyAccelerationHarness.tsx new file mode 100644 index 0000000..878f989 --- /dev/null +++ b/src/chromePropertyAccelerationHarness.tsx @@ -0,0 +1,185 @@ +import { useEffect, useState } from 'react' +import { createRoot } from 'react-dom/client' +import { PropertyEditor } from './App' +import { createProductionFacade } from './facade/productionFacade' +import type { BitBybitWebCadFacade, DocumentSnapshot, ObjectPropertySnapshot } from './facade/types' +import './styles.css' + +type WorkerTrace = { + constructed: Array<{ name: string; url: string }> + requestTypes: string[] + terminated: string[] +} + +type PropertyAccelerationReport = { + schemaVersion: 1 + status: 'running' | 'pass' | 'failed' + browserId: 'chrome' + userAgent: string + crossOriginIsolated: boolean + worker?: WorkerTrace + ui?: { inputType: string; label: string; unit: string; beforeValue: number; afterValue: number; documentVersion: number; dirty: boolean; objectState: string | null; errors: string[] } + persistence?: { mode: string; sqliteWasm: boolean; opfs: boolean; savedMode: string; loadedValue: number | null; loadedType: string | null; checkpointVersion: number | null; recoveryIntegrity: string; fcstdElement: string | null; fcstdValue: string | null } + resource?: { byteLength: number; roundTrip: boolean; released: boolean; markerRemoved: boolean } + release?: { shapeCount: number; kernelReferenceCount: number; workerTerminated: boolean } + error?: string +} + +const fixture = (): DocumentSnapshot => ({ + id: 'chrome-property-acceleration', + label: 'Chrome PropertyAcceleration', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [{ id: 'AccelerationProbe', label: 'Acceleration probe', type: 'feature', state: 'valid' }], + objects: [{ + id: 'AccelerationProbe', + typeId: 'Robot::TrajectoryDressUpObject', + properties: [{ name: 'Acceleration', label: 'Acceleration', group: 'TrajectoryDressUp', scope: 'data', type: 'App::PropertyAcceleration', value: 1000, unit: 'mm/s^2', recompute: true }], + }], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { AccelerationProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const accelerationProperty = (facade: BitBybitWebCadFacade) => facade.app.document.getObject('AccelerationProbe')?.properties.find((property) => property.name === 'Acceleration') + +function HarnessEditor({ facade, errors }: { facade: BitBybitWebCadFacade; errors: string[] }) { + const [property, setProperty] = useState(() => accelerationProperty(facade) ?? null) + useEffect(() => facade.subscribe((event) => { + if (event.type === 'state.changed') setProperty(accelerationProperty(facade) ?? null) + }), [facade]) + if (!property) return
Acceleration property is missing.
+ return
Property view

Acceleration probe

TrajectoryDressUp
errors.push(message)} />
+} + +const waitFor = async (predicate: () => boolean, message: string, timeoutMs = 30_000) => { + const deadline = performance.now() + timeoutMs + while (performance.now() < deadline) { + if (predicate()) return + await new Promise((resolve) => setTimeout(resolve, 25)) + } + throw new Error(`Timed out waiting for ${message}.`) +} + +const trace: WorkerTrace = { constructed: [], requestTypes: [], terminated: [] } +const BrowserWorker = globalThis.Worker +class TrackedWorker extends BrowserWorker { + private readonly traceName: string + + constructor(scriptURL: string | URL, options?: WorkerOptions) { + super(scriptURL, options) + this.traceName = options?.name ?? 'unnamed' + trace.constructed.push({ name: this.traceName, url: String(scriptURL) }) + } + + override postMessage(message: unknown, transferOrOptions?: StructuredSerializeOptions | Transferable[]) { + if (message && typeof message === 'object' && 'type' in message && typeof message.type === 'string') trace.requestTypes.push(message.type) + if (Array.isArray(transferOrOptions)) super.postMessage(message, transferOrOptions) + else if (transferOrOptions) super.postMessage(message, transferOrOptions) + else super.postMessage(message) + } + + override terminate() { + trace.terminated.push(this.traceName) + super.terminate() + } +} +Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: TrackedWorker }) + +const report: PropertyAccelerationReport = { schemaVersion: 1, status: 'running', browserId: 'chrome', userAgent: navigator.userAgent, crossOriginIsolated: globalThis.crossOriginIsolated === true } +const errors: string[] = [] +const facade = createProductionFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['AccelerationProbe'] }) +const root = createRoot(document.getElementById('root')!) +root.render() + +try { + await waitFor(() => document.querySelector('input[aria-label="Acceleration"]') !== null, 'the production PropertyAcceleration editor') + await waitFor(() => facade.project.capabilities().mode === 'sqlite-opfs', 'the SQLite OPFS Worker') + const input = document.querySelector('input[aria-label="Acceleration"]')! + const beforeValue = Number(input.value) + input.focus() + input.value = '500' + input.dispatchEvent(new Event('input', { bubbles: true })) + input.blur() + await waitFor(() => facade.app.document.getActive().version === 2, 'the UI property commit') + const edited = facade.app.document.getActive() + const editedProperty = accelerationProperty(facade) + const unit = input.closest('label')?.querySelector('span')?.textContent ?? '' + report.ui = { + inputType: input.type, + label: input.getAttribute('aria-label') ?? '', + unit, + beforeValue, + afterValue: Number(editedProperty?.value), + documentVersion: edited.version, + dirty: edited.dirty, + objectState: edited.recompute?.objectStates.AccelerationProbe ?? null, + errors, + } + + const saved = await facade.project.save() + const loaded = await facade.project.load(edited.id) + const checkpoint = await facade.project.loadCheckpoint(edited.id, edited.version) + const recovery = await facade.project.recovery(edited.id) + const loadedProperty = loaded?.objects.find((object) => object.id === 'AccelerationProbe')?.properties.find((property) => property.name === 'Acceleration') + const archive = facade.project.fcstd.serializeMetadata(edited) + const archiveProperty = facade.project.fcstd.inspect(archive).objects.find((object) => object.name === 'AccelerationProbe')?.properties.find((property) => property.name === 'Acceleration') + const capabilities = facade.project.capabilities() + report.persistence = { + mode: capabilities.mode, + sqliteWasm: capabilities.sqliteWasm, + opfs: capabilities.opfs, + savedMode: saved.mode, + loadedValue: typeof loadedProperty?.value === 'number' ? loadedProperty.value : null, + loadedType: loadedProperty?.type ?? null, + checkpointVersion: checkpoint?.version ?? null, + recoveryIntegrity: recovery.integrity, + fcstdElement: archiveProperty?.element ?? null, + fcstdValue: archiveProperty?.value ?? null, + } + + const payload = new TextEncoder().encode('PropertyAcceleration Chrome resource') + const stored = await facade.project.resource.put(payload, 'application/vnd.freecad.property-acceleration+json') + const restored = await facade.project.resource.get(stored.hash) + await facade.project.resource.release(stored.hash) + const released = await facade.project.resource.get(stored.hash) === null + const directory = await navigator.storage.getDirectory() + const markerName = 'property-acceleration-chrome-marker.json' + const marker = await directory.getFileHandle(markerName, { create: true }) + const writable = await marker.createWritable() + await writable.write(JSON.stringify({ suite: 'PROP-ACC-H', value: 500 })) + await writable.close() + await directory.removeEntry(markerName) + let markerRemoved = false + try { await directory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' } + report.resource = { byteLength: stored.byteLength, roundTrip: restored !== null && new TextDecoder().decode(restored) === new TextDecoder().decode(payload), released, markerRemoved } +} catch (error) { + report.error = error instanceof Error ? error.stack || error.message : String(error) +} finally { + root.unmount() + facade.geometry.dispose() + await facade.project.dispose().catch((error: unknown) => { report.error = `${report.error ? `${report.error}\n` : ''}${error instanceof Error ? error.stack || error.message : String(error)}` }) + Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: BrowserWorker }) + const geometry = facade.geometry.capabilities() + report.worker = trace + report.release = { shapeCount: geometry.shapeCount, kernelReferenceCount: geometry.kernelReferenceCount, workerTerminated: trace.terminated.includes('bitbybit-persistence') } +} + +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +report.status = !report.error + && report.crossOriginIsolated + && report.worker?.constructed.some(({ name }) => name === 'bitbybit-persistence') === true + && requiredWorkerRequests.every((type) => report.worker?.requestTypes.includes(type)) + && report.ui?.inputType === 'number' && report.ui.label === 'Acceleration' && report.ui.unit === 'mm/s^2' && report.ui.beforeValue === 1000 && report.ui.afterValue === 500 && report.ui.documentVersion === 2 && report.ui.dirty && report.ui.objectState === 'touched' && report.ui.errors.length === 0 + && report.persistence?.mode === 'sqlite-opfs' && report.persistence.sqliteWasm && report.persistence.opfs && report.persistence.savedMode === 'sqlite-opfs' && report.persistence.loadedValue === 500 && report.persistence.loadedType === 'App::PropertyAcceleration' && report.persistence.checkpointVersion === 2 && report.persistence.recoveryIntegrity === 'ok' && report.persistence.fcstdElement === 'Float' && report.persistence.fcstdValue === '500' + && report.resource !== undefined && report.resource.byteLength > 0 && report.resource.roundTrip && report.resource.released && report.resource.markerRemoved + && report.release?.shapeCount === 0 && report.release.kernelReferenceCount === 0 && report.release.workerTerminated + ? 'pass' : 'failed' + +document.documentElement.dataset.status = report.status +document.body.textContent = JSON.stringify(report, null, 2) +await fetch('/__chrome-property-acceleration-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) }) +if (report.status !== 'pass') throw new Error(report.error || 'Chrome PropertyAcceleration harness failed.') + +export {} diff --git a/src/chromePropertyAreaHarness.tsx b/src/chromePropertyAreaHarness.tsx new file mode 100644 index 0000000..8a4e312 --- /dev/null +++ b/src/chromePropertyAreaHarness.tsx @@ -0,0 +1,231 @@ +import { useEffect, useState } from 'react' +import { createRoot } from 'react-dom/client' +import { PropertyEditor } from './App' +import { createProductionFacade } from './facade/productionFacade' +import { encodeFreecadPropertyStatus } from './facade/propertyStatus' +import type { BitBybitWebCadFacade, DocumentSnapshot, ObjectPropertySnapshot } from './facade/types' +import './styles.css' + +type WorkerTrace = { + constructed: Array<{ name: string; url: string }> + requestTypes: string[] + terminated: string[] +} + +type PropertyAreaReport = { + schemaVersion: 1 + status: 'running' | 'pass' | 'failed' + browserId: 'chrome' + userAgent: string + crossOriginIsolated: boolean + worker?: WorkerTrace + ui?: { areaReadOnly: boolean; beforeText: string; afterText: string; beforeArea: number; afterArea: number; beforeElementCount: number; afterElementCount: number; triggerLabel: string; documentVersion: number; dirty: boolean; objectState: string | null; errors: string[] } + persistence?: { mode: string; sqliteWasm: boolean; opfs: boolean; savedMode: string; loadedArea: number | null; loadedAreaType: string | null; loadedElementCount: number | null; loadedElementsType: string | null; checkpointVersion: number | null; recoveryIntegrity: string; fcstdAreaElement: string | null; fcstdAreaValue: string | null; fcstdElementsElement: string | null; fcstdElementCount: number | null } + resource?: { byteLength: number; roundTrip: boolean; released: boolean; markerRemoved: boolean } + release?: { shapeCount: number; kernelReferenceCount: number; workerTerminated: boolean } + error?: string +} + +const outputStatus = encodeFreecadPropertyStatus(['PropReadOnly', 'PropOutput']) +const faceEntry = (persistentId: string, area: number, index: number) => ({ + ref: { shapeId: 'AreaBox-shape', kind: 'face' as const, persistentId, topologyVersion: 1, status: 'stable' as const }, + signature: { kind: 'face' as const, canonical: persistentId, hash: persistentId, centroid: [index, 0, 0] as [number, number, number], bounds: { min: [index, 0, 0] as [number, number, number], max: [index + 1, 1, 0] as [number, number, number] }, area, normal: [0, 0, 1] as [number, number, number] }, +}) + +const fixture = (): DocumentSnapshot => ({ + id: 'chrome-property-area', + label: 'Chrome PropertyArea', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [ + { id: 'AreaBox', label: 'Area box', type: 'feature', state: 'valid' }, + { id: 'AreaProbe', label: 'Area probe', type: 'feature', state: 'valid' }, + ], + objects: [ + { + id: 'AreaBox', + typeId: 'Part::Box', + properties: [ + { name: 'Length', label: 'Length', group: 'Box', scope: 'data', type: 'App::PropertyLength', value: 10, unit: 'mm', recompute: true }, + { name: 'Width', label: 'Width', group: 'Box', scope: 'data', type: 'App::PropertyLength', value: 5, unit: 'mm', recompute: true }, + { name: 'Height', label: 'Height', group: 'Box', scope: 'data', type: 'App::PropertyLength', value: 2, unit: 'mm', recompute: true }, + ], + topology: { + shapeId: 'AreaBox-shape', + documentVersion: 1, + generation: 1, + entries: [faceEntry('box-face-1', 10, 0), faceEntry('box-face-2', 10, 1)], + migration: { previousGeneration: null, matches: [] }, + history: { operationId: 'AreaBox:1', provider: 'occt-native', relations: [], counts: { preserved: 0, modified: 0, generated: 0, deleted: 0, ambiguous: 0 } }, + }, + }, + { + id: 'AreaProbe', + typeId: 'Measure::MeasureArea', + properties: [ + { name: 'Area', label: 'Area', group: 'Measurement', scope: 'data', type: 'App::PropertyArea', value: 20, unit: 'mm^2', nativeStatus: outputStatus, readOnly: true, recompute: false }, + { name: 'Elements', label: 'Elements', group: 'Measurement', scope: 'data', type: 'App::PropertyLinkSubList', value: { schemaVersion: 1, entries: [{ objectId: 'AreaBox', subElement: 'Face1' }, { objectId: 'AreaBox', subElement: 'Face2' }] }, recompute: true }, + ], + }, + ], + dependencies: [{ sourceId: 'AreaProbe', targetId: 'AreaBox', relation: 'topo-ref', propertyName: 'Elements', reference: 'Face1' }], + recompute: { generation: 0, status: 'idle', objectStates: { AreaBox: 'up-to-date', AreaProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const areaProperties = (facade: BitBybitWebCadFacade) => facade.app.document.getObject('AreaProbe')?.properties.filter((property) => property.name === 'Area' || property.name === 'Elements') ?? [] +const property = (facade: BitBybitWebCadFacade, name: 'Area' | 'Elements') => facade.app.document.getObject('AreaProbe')?.properties.find((candidate) => candidate.name === name) +const elementCount = (value: unknown) => value && typeof value === 'object' && !Array.isArray(value) && 'entries' in value && Array.isArray(value.entries) ? value.entries.length : null + +function HarnessEditor({ facade, errors }: { facade: BitBybitWebCadFacade; errors: string[] }) { + const [properties, setProperties] = useState(() => areaProperties(facade)) + useEffect(() => facade.subscribe((event) => { + if (event.type === 'state.changed') setProperties(areaProperties(facade)) + }), [facade]) + if (properties.length !== 2) return
MeasureArea properties are missing.
+ return
Property view

Area probe

Measurement
{properties.map((entry) =>
errors.push(message)} />
)}
+} + +const waitFor = async (predicate: () => boolean, message: string, timeoutMs = 30_000) => { + const deadline = performance.now() + timeoutMs + while (performance.now() < deadline) { + if (predicate()) return + await new Promise((resolve) => setTimeout(resolve, 25)) + } + throw new Error(`Timed out waiting for ${message}.`) +} + +const trace: WorkerTrace = { constructed: [], requestTypes: [], terminated: [] } +const BrowserWorker = globalThis.Worker +class TrackedWorker extends BrowserWorker { + private readonly traceName: string + + constructor(scriptURL: string | URL, options?: WorkerOptions) { + super(scriptURL, options) + this.traceName = options?.name ?? 'unnamed' + trace.constructed.push({ name: this.traceName, url: String(scriptURL) }) + } + + override postMessage(message: unknown, transferOrOptions?: StructuredSerializeOptions | Transferable[]) { + if (message && typeof message === 'object' && 'type' in message && typeof message.type === 'string') trace.requestTypes.push(message.type) + if (Array.isArray(transferOrOptions)) super.postMessage(message, transferOrOptions) + else if (transferOrOptions) super.postMessage(message, transferOrOptions) + else super.postMessage(message) + } + + override terminate() { + trace.terminated.push(this.traceName) + super.terminate() + } +} +Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: TrackedWorker }) + +const report: PropertyAreaReport = { schemaVersion: 1, status: 'running', browserId: 'chrome', userAgent: navigator.userAgent, crossOriginIsolated: globalThis.crossOriginIsolated === true } +const errors: string[] = [] +const facade = createProductionFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['AreaProbe'] }) +const root = createRoot(document.getElementById('root')!) +root.render() + +try { + await waitFor(() => document.querySelector('button[aria-label="Clear subshape links"]') !== null, 'the production MeasureArea Elements editor') + await waitFor(() => facade.project.capabilities().mode === 'sqlite-opfs', 'the SQLite OPFS Worker') + const clearButton = document.querySelector('button[aria-label="Clear subshape links"]')! + const beforeText = document.querySelector('[data-property="Area"] .property-readonly')?.textContent ?? '' + const beforeArea = Number(property(facade, 'Area')?.value) + const beforeElementCount = elementCount(property(facade, 'Elements')?.value) + const areaReadOnly = document.querySelector('input[aria-label="Area"]') === null + clearButton.click() + await waitFor(() => facade.app.document.getActive().version === 2, 'the UI Elements commit') + await waitFor(() => document.querySelector('[data-property="Area"] .property-readonly')?.textContent === '0 mm^2', 'the derived Area UI update') + const edited = facade.app.document.getActive() + const editedArea = property(facade, 'Area') + const editedElements = property(facade, 'Elements') + report.ui = { + areaReadOnly, + beforeText, + afterText: document.querySelector('[data-property="Area"] .property-readonly')?.textContent ?? '', + beforeArea, + afterArea: Number(editedArea?.value), + beforeElementCount: beforeElementCount ?? -1, + afterElementCount: elementCount(editedElements?.value) ?? -1, + triggerLabel: clearButton.getAttribute('aria-label') ?? '', + documentVersion: edited.version, + dirty: edited.dirty, + objectState: edited.recompute?.objectStates.AreaProbe ?? null, + errors, + } + + const saved = await facade.project.save() + const loaded = await facade.project.load(edited.id) + const checkpoint = await facade.project.loadCheckpoint(edited.id, edited.version) + const recovery = await facade.project.recovery(edited.id) + const loadedObject = loaded?.objects.find((object) => object.id === 'AreaProbe') + const loadedArea = loadedObject?.properties.find((candidate) => candidate.name === 'Area') + const loadedElements = loadedObject?.properties.find((candidate) => candidate.name === 'Elements') + const archive = facade.project.fcstd.serializeMetadata(edited) + const archiveObject = facade.project.fcstd.inspect(archive).objects.find((object) => object.name === 'AreaProbe') + const archiveArea = archiveObject?.properties.find((candidate) => candidate.name === 'Area') + const archiveElements = archiveObject?.properties.find((candidate) => candidate.name === 'Elements') + const capabilities = facade.project.capabilities() + report.persistence = { + mode: capabilities.mode, + sqliteWasm: capabilities.sqliteWasm, + opfs: capabilities.opfs, + savedMode: saved.mode, + loadedArea: typeof loadedArea?.value === 'number' ? loadedArea.value : null, + loadedAreaType: loadedArea?.type ?? null, + loadedElementCount: elementCount(loadedElements?.value), + loadedElementsType: loadedElements?.type ?? null, + checkpointVersion: checkpoint?.version ?? null, + recoveryIntegrity: recovery.integrity, + fcstdAreaElement: archiveArea?.element ?? null, + fcstdAreaValue: archiveArea?.value ?? null, + fcstdElementsElement: archiveElements?.element ?? null, + fcstdElementCount: archiveElements?.linkSubs?.length ?? null, + } + + const payload = new TextEncoder().encode('PropertyArea Chrome resource') + const stored = await facade.project.resource.put(payload, 'application/vnd.freecad.property-area+json') + const restored = await facade.project.resource.get(stored.hash) + await facade.project.resource.release(stored.hash) + const released = await facade.project.resource.get(stored.hash) === null + const directory = await navigator.storage.getDirectory() + const markerName = 'property-area-chrome-marker.json' + const marker = await directory.getFileHandle(markerName, { create: true }) + const writable = await marker.createWritable() + await writable.write(JSON.stringify({ suite: 'PROP-AREA-H', area: 0, elements: 0 })) + await writable.close() + await directory.removeEntry(markerName) + let markerRemoved = false + try { await directory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' } + report.resource = { byteLength: stored.byteLength, roundTrip: restored !== null && new TextDecoder().decode(restored) === new TextDecoder().decode(payload), released, markerRemoved } +} catch (error) { + report.error = error instanceof Error ? error.stack || error.message : String(error) +} finally { + root.unmount() + facade.geometry.dispose() + await facade.project.dispose().catch((error: unknown) => { report.error = `${report.error ? `${report.error}\n` : ''}${error instanceof Error ? error.stack || error.message : String(error)}` }) + Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: BrowserWorker }) + const geometry = facade.geometry.capabilities() + report.worker = trace + report.release = { shapeCount: geometry.shapeCount, kernelReferenceCount: geometry.kernelReferenceCount, workerTerminated: trace.terminated.includes('bitbybit-persistence') } +} + +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +report.status = !report.error + && report.crossOriginIsolated + && report.worker?.constructed.some(({ name }) => name === 'bitbybit-persistence') === true + && requiredWorkerRequests.every((type) => report.worker?.requestTypes.includes(type)) + && report.ui?.areaReadOnly === true && report.ui.beforeText === '20 mm^2' && report.ui.afterText === '0 mm^2' && report.ui.beforeArea === 20 && report.ui.afterArea === 0 && report.ui.beforeElementCount === 2 && report.ui.afterElementCount === 0 && report.ui.triggerLabel === 'Clear subshape links' && report.ui.documentVersion === 2 && report.ui.dirty && report.ui.objectState === 'touched' && report.ui.errors.length === 0 + && report.persistence?.mode === 'sqlite-opfs' && report.persistence.sqliteWasm && report.persistence.opfs && report.persistence.savedMode === 'sqlite-opfs' && report.persistence.loadedArea === 0 && report.persistence.loadedAreaType === 'App::PropertyArea' && report.persistence.loadedElementCount === 0 && report.persistence.loadedElementsType === 'App::PropertyLinkSubList' && report.persistence.checkpointVersion === 2 && report.persistence.recoveryIntegrity === 'ok' && report.persistence.fcstdAreaElement === 'Float' && Number(report.persistence.fcstdAreaValue) === 0 && report.persistence.fcstdElementsElement === 'LinkSubList' && report.persistence.fcstdElementCount === 0 + && report.resource !== undefined && report.resource.byteLength > 0 && report.resource.roundTrip && report.resource.released && report.resource.markerRemoved + && report.release?.shapeCount === 0 && report.release.kernelReferenceCount === 0 && report.release.workerTerminated + ? 'pass' : 'failed' + +document.documentElement.dataset.status = report.status +document.body.textContent = JSON.stringify(report, null, 2) +await fetch('/__chrome-property-area-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) }) +if (report.status !== 'pass') throw new Error(report.error || 'Chrome PropertyArea harness failed.') + +export {} diff --git a/src/chromePropertyBoolListHarness.tsx b/src/chromePropertyBoolListHarness.tsx new file mode 100644 index 0000000..a8b700e --- /dev/null +++ b/src/chromePropertyBoolListHarness.tsx @@ -0,0 +1,188 @@ +import { useEffect, useState } from 'react' +import { createRoot } from 'react-dom/client' +import { PropertyEditor } from './App' +import { createProductionFacade } from './facade/productionFacade' +import type { BitBybitWebCadFacade, DocumentSnapshot, ObjectPropertySnapshot } from './facade/types' +import './styles.css' + +type WorkerTrace = { + constructed: Array<{ name: string; url: string }> + requestTypes: string[] + terminated: string[] +} + +type PropertyBoolListReport = { + schemaVersion: 1 + status: 'running' | 'pass' | 'failed' + browserId: 'chrome' + userAgent: string + crossOriginIsolated: boolean + worker?: WorkerTrace + ui?: { inputType: string; label: string; beforeText: string; afterText: string; beforeValue: boolean[]; afterValue: boolean[]; documentVersion: number; dirty: boolean; objectState: string | null; errors: string[] } + persistence?: { mode: string; sqliteWasm: boolean; opfs: boolean; savedMode: string; loadedValue: boolean[] | null; loadedType: string | null; checkpointVersion: number | null; recoveryIntegrity: string; fcstdElement: string | null; fcstdValue: string | null } + resource?: { byteLength: number; roundTrip: boolean; released: boolean; markerRemoved: boolean } + release?: { shapeCount: number; kernelReferenceCount: number; workerTerminated: boolean } + error?: string +} + +const fixture = (): DocumentSnapshot => ({ + id: 'chrome-property-boollist', + label: 'Chrome PropertyBoolList', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [{ id: 'BoolListProbe', label: 'Bool list probe', type: 'feature', state: 'valid' }], + objects: [{ + id: 'BoolListProbe', + typeId: 'App::FeatureTest', + properties: [{ name: 'BoolList', label: 'Bool list', group: 'Test', scope: 'data', type: 'App::PropertyBoolList', value: [false], recompute: true }], + }], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { BoolListProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const boolListProperty = (facade: BitBybitWebCadFacade) => facade.app.document.getObject('BoolListProbe')?.properties.find((property) => property.name === 'BoolList') + +function HarnessEditor({ facade, errors }: { facade: BitBybitWebCadFacade; errors: string[] }) { + const [property, setProperty] = useState(() => boolListProperty(facade) ?? null) + useEffect(() => facade.subscribe((event) => { + if (event.type === 'state.changed') setProperty(boolListProperty(facade) ?? null) + }), [facade]) + if (!property) return
Bool list property is missing.
+ return
Property view

Bool list probe

Test
errors.push(message)} />
+} + +const waitFor = async (predicate: () => boolean, message: string, timeoutMs = 30_000) => { + const deadline = performance.now() + timeoutMs + while (performance.now() < deadline) { + if (predicate()) return + await new Promise((resolve) => setTimeout(resolve, 25)) + } + throw new Error(`Timed out waiting for ${message}.`) +} + +const trace: WorkerTrace = { constructed: [], requestTypes: [], terminated: [] } +const BrowserWorker = globalThis.Worker +class TrackedWorker extends BrowserWorker { + private readonly traceName: string + + constructor(scriptURL: string | URL, options?: WorkerOptions) { + super(scriptURL, options) + this.traceName = options?.name ?? 'unnamed' + trace.constructed.push({ name: this.traceName, url: String(scriptURL) }) + } + + override postMessage(message: unknown, transferOrOptions?: StructuredSerializeOptions | Transferable[]) { + if (message && typeof message === 'object' && 'type' in message && typeof message.type === 'string') trace.requestTypes.push(message.type) + if (Array.isArray(transferOrOptions)) super.postMessage(message, transferOrOptions) + else if (transferOrOptions) super.postMessage(message, transferOrOptions) + else super.postMessage(message) + } + + override terminate() { + trace.terminated.push(this.traceName) + super.terminate() + } +} +Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: TrackedWorker }) + +const target = [true, false, true, false] +const report: PropertyBoolListReport = { schemaVersion: 1, status: 'running', browserId: 'chrome', userAgent: navigator.userAgent, crossOriginIsolated: globalThis.crossOriginIsolated === true } +const errors: string[] = [] +const facade = createProductionFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['BoolListProbe'] }) +const root = createRoot(document.getElementById('root')!) +root.render() + +try { + await waitFor(() => document.querySelector('input[aria-label="Bool list"]') !== null, 'the production PropertyBoolList editor') + await waitFor(() => facade.project.capabilities().mode === 'sqlite-opfs', 'the SQLite OPFS Worker') + const input = document.querySelector('input[aria-label="Bool list"]')! + const beforeText = input.value + const beforeValue = [...(boolListProperty(facade)?.value as boolean[])] + input.focus() + input.value = 'true, false, true, false' + input.dispatchEvent(new Event('input', { bubbles: true })) + input.blur() + await waitFor(() => facade.app.document.getActive().version === 2, 'the UI property commit') + const edited = facade.app.document.getActive() + const editedProperty = boolListProperty(facade) + report.ui = { + inputType: input.type, + label: input.getAttribute('aria-label') ?? '', + beforeText, + afterText: (editedProperty?.value as boolean[]).map((entry) => entry ? 'true' : 'false').join(', '), + beforeValue, + afterValue: [...(editedProperty?.value as boolean[])], + documentVersion: edited.version, + dirty: edited.dirty, + objectState: edited.recompute?.objectStates.BoolListProbe ?? null, + errors, + } + + const saved = await facade.project.save() + const loaded = await facade.project.load(edited.id) + const checkpoint = await facade.project.loadCheckpoint(edited.id, edited.version) + const recovery = await facade.project.recovery(edited.id) + const loadedProperty = loaded?.objects.find((object) => object.id === 'BoolListProbe')?.properties.find((property) => property.name === 'BoolList') + const archive = facade.project.fcstd.serializeMetadata(edited) + const archiveProperty = facade.project.fcstd.inspect(archive).objects.find((object) => object.name === 'BoolListProbe')?.properties.find((property) => property.name === 'BoolList') + const capabilities = facade.project.capabilities() + report.persistence = { + mode: capabilities.mode, + sqliteWasm: capabilities.sqliteWasm, + opfs: capabilities.opfs, + savedMode: saved.mode, + loadedValue: Array.isArray(loadedProperty?.value) && loadedProperty.value.every((entry) => typeof entry === 'boolean') ? [...loadedProperty.value] : null, + loadedType: loadedProperty?.type ?? null, + checkpointVersion: checkpoint?.version ?? null, + recoveryIntegrity: recovery.integrity, + fcstdElement: archiveProperty?.element ?? null, + fcstdValue: archiveProperty?.value ?? null, + } + + const payload = new TextEncoder().encode('PropertyBoolList Chrome resource') + const stored = await facade.project.resource.put(payload, 'application/vnd.freecad.property-boollist+json') + const restored = await facade.project.resource.get(stored.hash) + await facade.project.resource.release(stored.hash) + const released = await facade.project.resource.get(stored.hash) === null + const directory = await navigator.storage.getDirectory() + const markerName = 'property-boollist-chrome-marker.json' + const marker = await directory.getFileHandle(markerName, { create: true }) + const writable = await marker.createWritable() + await writable.write(JSON.stringify({ suite: 'PROP-BOOLLIST-H', value: target })) + await writable.close() + await directory.removeEntry(markerName) + let markerRemoved = false + try { await directory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' } + report.resource = { byteLength: stored.byteLength, roundTrip: restored !== null && new TextDecoder().decode(restored) === new TextDecoder().decode(payload), released, markerRemoved } +} catch (error) { + report.error = error instanceof Error ? error.stack || error.message : String(error) +} finally { + root.unmount() + facade.geometry.dispose() + await facade.project.dispose().catch((error: unknown) => { report.error = `${report.error ? `${report.error}\n` : ''}${error instanceof Error ? error.stack || error.message : String(error)}` }) + Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: BrowserWorker }) + const geometry = facade.geometry.capabilities() + report.worker = trace + report.release = { shapeCount: geometry.shapeCount, kernelReferenceCount: geometry.kernelReferenceCount, workerTerminated: trace.terminated.includes('bitbybit-persistence') } +} + +const same = (left: boolean[] | null | undefined, right: boolean[]) => Array.isArray(left) && left.length === right.length && left.every((entry, index) => entry === right[index]) +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +report.status = !report.error + && report.crossOriginIsolated + && report.worker?.constructed.some(({ name }) => name === 'bitbybit-persistence') === true + && requiredWorkerRequests.every((type) => report.worker?.requestTypes.includes(type)) + && report.ui?.inputType === 'text' && report.ui.label === 'Bool list' && report.ui.beforeText === 'false' && report.ui.afterText === 'true, false, true, false' && same(report.ui.beforeValue, [false]) && same(report.ui.afterValue, target) && report.ui.documentVersion === 2 && report.ui.dirty && report.ui.objectState === 'touched' && report.ui.errors.length === 0 + && report.persistence?.mode === 'sqlite-opfs' && report.persistence.sqliteWasm && report.persistence.opfs && report.persistence.savedMode === 'sqlite-opfs' && same(report.persistence.loadedValue, target) && report.persistence.loadedType === 'App::PropertyBoolList' && report.persistence.checkpointVersion === 2 && report.persistence.recoveryIntegrity === 'ok' && report.persistence.fcstdElement === 'BoolList' && report.persistence.fcstdValue === '[true,false,true,false]' + && report.resource !== undefined && report.resource.byteLength > 0 && report.resource.roundTrip && report.resource.released && report.resource.markerRemoved + && report.release?.shapeCount === 0 && report.release.kernelReferenceCount === 0 && report.release.workerTerminated + ? 'pass' : 'failed' + +document.documentElement.dataset.status = report.status +document.body.textContent = JSON.stringify(report, null, 2) +await fetch('/__chrome-property-boollist-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) }) +if (report.status !== 'pass') throw new Error(report.error || 'Chrome PropertyBoolList harness failed.') + +export {} diff --git a/src/chromePropertyColorHarness.tsx b/src/chromePropertyColorHarness.tsx new file mode 100644 index 0000000..005d4ec --- /dev/null +++ b/src/chromePropertyColorHarness.tsx @@ -0,0 +1,207 @@ +import { useEffect, useState } from 'react' +import { createRoot } from 'react-dom/client' +import { PropertyEditor } from './App' +import { createProductionFacade } from './facade/productionFacade' +import type { BitBybitWebCadFacade, ColorValue, DocumentSnapshot, ObjectPropertySnapshot } from './facade/types' +import './styles.css' + +type WorkerTrace = { + constructed: Array<{ name: string; url: string }> + requestTypes: string[] + terminated: string[] +} + +type PropertyColorReport = { + schemaVersion: 1 + status: 'running' | 'pass' | 'failed' + browserId: 'chrome' + userAgent: string + crossOriginIsolated: boolean + worker?: WorkerTrace + ui?: { rgbInputType: string; alphaInputType: string; rgbLabel: string; alphaLabel: string; beforeHex: string; afterHex: string; beforeAlpha: string; afterAlpha: number; beforeValue: ColorValue; afterValue: ColorValue; documentVersion: number; dirty: boolean; objectState: string | null; errors: string[] } + persistence?: { mode: string; sqliteWasm: boolean; opfs: boolean; savedMode: string; loadedValue: ColorValue | null; loadedType: string | null; checkpointVersion: number | null; recoveryIntegrity: string; fcstdElement: string | null; fcstdValue: string | null } + resource?: { byteLength: number; roundTrip: boolean; released: boolean; markerRemoved: boolean } + release?: { shapeCount: number; kernelReferenceCount: number; workerTerminated: boolean } + error?: string +} + +const fixture = (): DocumentSnapshot => ({ + id: 'chrome-property-color', + label: 'Chrome PropertyColor', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [{ id: 'ColorProbe', label: 'Color probe', type: 'feature', state: 'valid' }], + objects: [{ + id: 'ColorProbe', + typeId: 'App::FeatureTest', + properties: [{ name: 'Colour', label: 'Colour', group: 'Test', scope: 'data', type: 'App::PropertyColor', value: [0, 0, 0, 1], recompute: true }], + }], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { ColorProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const colorProperty = (facade: BitBybitWebCadFacade) => facade.app.document.getObject('ColorProbe')?.properties.find((property) => property.name === 'Colour') + +function HarnessEditor({ facade, errors }: { facade: BitBybitWebCadFacade; errors: string[] }) { + const [property, setProperty] = useState(() => colorProperty(facade) ?? null) + useEffect(() => facade.subscribe((event) => { + if (event.type === 'state.changed') setProperty(colorProperty(facade) ?? null) + }), [facade]) + if (!property) return
Color property is missing.
+ return
Property view

Color probe

Test
errors.push(message)} />
+} + +const waitFor = async (predicate: () => boolean, message: string, timeoutMs = 30_000) => { + const deadline = performance.now() + timeoutMs + while (performance.now() < deadline) { + if (predicate()) return + await new Promise((resolve) => setTimeout(resolve, 25)) + } + throw new Error(`Timed out waiting for ${message}.`) +} + +const setNativeInputValue = (input: HTMLInputElement, value: string) => { + const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set + if (!setter) throw new Error('The native HTMLInputElement value setter is unavailable.') + setter.call(input, value) +} + +const trace: WorkerTrace = { constructed: [], requestTypes: [], terminated: [] } +const BrowserWorker = globalThis.Worker +class TrackedWorker extends BrowserWorker { + private readonly traceName: string + + constructor(scriptURL: string | URL, options?: WorkerOptions) { + super(scriptURL, options) + this.traceName = options?.name ?? 'unnamed' + trace.constructed.push({ name: this.traceName, url: String(scriptURL) }) + } + + override postMessage(message: unknown, transferOrOptions?: StructuredSerializeOptions | Transferable[]) { + if (message && typeof message === 'object' && 'type' in message && typeof message.type === 'string') trace.requestTypes.push(message.type) + if (Array.isArray(transferOrOptions)) super.postMessage(message, transferOrOptions) + else if (transferOrOptions) super.postMessage(message, transferOrOptions) + else super.postMessage(message) + } + + override terminate() { + trace.terminated.push(this.traceName) + super.terminate() + } +} +Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: TrackedWorker }) + +const target: ColorValue = [0.2, 0.4, 0.6, 0.8] +const report: PropertyColorReport = { schemaVersion: 1, status: 'running', browserId: 'chrome', userAgent: navigator.userAgent, crossOriginIsolated: globalThis.crossOriginIsolated === true } +const errors: string[] = [] +const facade = createProductionFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['ColorProbe'] }) +const root = createRoot(document.getElementById('root')!) +root.render() + +try { + await waitFor(() => document.querySelector('input[aria-label="Colour RGB"]') !== null && document.querySelector('input[aria-label="Colour alpha"]') !== null, 'the production PropertyColor editor') + await waitFor(() => facade.project.capabilities().mode === 'sqlite-opfs', 'the SQLite OPFS Worker') + const rgb = document.querySelector('input[aria-label="Colour RGB"]')! + const initialAlpha = document.querySelector('input[aria-label="Colour alpha"]')! + const beforeHex = rgb.value + const beforeAlpha = initialAlpha.value + const beforeValue = [...(colorProperty(facade)?.value as ColorValue)] as ColorValue + rgb.focus() + setNativeInputValue(rgb, '#336699') + rgb.dispatchEvent(new Event('input', { bubbles: true })) + rgb.dispatchEvent(new Event('change', { bubbles: true })) + await waitFor(() => facade.app.document.getActive().version === 2, 'the RGB UI property commit') + const alpha = document.querySelector('input[aria-label="Colour alpha"]')! + alpha.focus() + alpha.value = '0.8' + alpha.dispatchEvent(new Event('input', { bubbles: true })) + alpha.blur() + await waitFor(() => facade.app.document.getActive().version === 3, 'the alpha UI property commit') + const edited = facade.app.document.getActive() + const editedProperty = colorProperty(facade) + report.ui = { + rgbInputType: rgb.type, + alphaInputType: alpha.type, + rgbLabel: rgb.getAttribute('aria-label') ?? '', + alphaLabel: alpha.getAttribute('aria-label') ?? '', + beforeHex, + afterHex: document.querySelector('input[aria-label="Colour RGB"]')?.value ?? '', + beforeAlpha, + afterAlpha: (editedProperty?.value as ColorValue)[3], + beforeValue, + afterValue: [...(editedProperty?.value as ColorValue)] as ColorValue, + documentVersion: edited.version, + dirty: edited.dirty, + objectState: edited.recompute?.objectStates.ColorProbe ?? null, + errors, + } + + const saved = await facade.project.save() + const loaded = await facade.project.load(edited.id) + const checkpoint = await facade.project.loadCheckpoint(edited.id, edited.version) + const recovery = await facade.project.recovery(edited.id) + const loadedProperty = loaded?.objects.find((object) => object.id === 'ColorProbe')?.properties.find((property) => property.name === 'Colour') + const archive = facade.project.fcstd.serializeMetadata(edited) + const archiveProperty = facade.project.fcstd.inspect(archive).objects.find((object) => object.name === 'ColorProbe')?.properties.find((property) => property.name === 'Colour') + const capabilities = facade.project.capabilities() + const loadedValue = loadedProperty?.value + report.persistence = { + mode: capabilities.mode, + sqliteWasm: capabilities.sqliteWasm, + opfs: capabilities.opfs, + savedMode: saved.mode, + loadedValue: Array.isArray(loadedValue) && loadedValue.length === 4 && loadedValue.every((entry) => typeof entry === 'number' && Number.isFinite(entry)) ? [...loadedValue] as ColorValue : null, + loadedType: loadedProperty?.type ?? null, + checkpointVersion: checkpoint?.version ?? null, + recoveryIntegrity: recovery.integrity, + fcstdElement: archiveProperty?.element ?? null, + fcstdValue: archiveProperty?.value ?? null, + } + + const payload = new TextEncoder().encode('PropertyColor Chrome resource') + const stored = await facade.project.resource.put(payload, 'application/vnd.freecad.property-color+json') + const restored = await facade.project.resource.get(stored.hash) + await facade.project.resource.release(stored.hash) + const released = await facade.project.resource.get(stored.hash) === null + const directory = await navigator.storage.getDirectory() + const markerName = 'property-color-chrome-marker.json' + const marker = await directory.getFileHandle(markerName, { create: true }) + const writable = await marker.createWritable() + await writable.write(JSON.stringify({ suite: 'PROP-COLOR-H', value: target })) + await writable.close() + await directory.removeEntry(markerName) + let markerRemoved = false + try { await directory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' } + report.resource = { byteLength: stored.byteLength, roundTrip: restored !== null && new TextDecoder().decode(restored) === new TextDecoder().decode(payload), released, markerRemoved } +} catch (error) { + report.error = error instanceof Error ? error.stack || error.message : String(error) +} finally { + root.unmount() + facade.geometry.dispose() + await facade.project.dispose().catch((error: unknown) => { report.error = `${report.error ? `${report.error}\n` : ''}${error instanceof Error ? error.stack || error.message : String(error)}` }) + Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: BrowserWorker }) + const geometry = facade.geometry.capabilities() + report.worker = trace + report.release = { shapeCount: geometry.shapeCount, kernelReferenceCount: geometry.kernelReferenceCount, workerTerminated: trace.terminated.includes('bitbybit-persistence') } +} + +const same = (left: ColorValue | null | undefined, right: ColorValue) => Array.isArray(left) && left.length === right.length && left.every((entry, index) => entry === right[index]) +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +report.status = !report.error + && report.crossOriginIsolated + && report.worker?.constructed.some(({ name }) => name === 'bitbybit-persistence') === true + && requiredWorkerRequests.every((type) => report.worker?.requestTypes.includes(type)) + && report.ui?.rgbInputType === 'color' && report.ui.alphaInputType === 'number' && report.ui.rgbLabel === 'Colour RGB' && report.ui.alphaLabel === 'Colour alpha' && report.ui.beforeHex === '#000000' && report.ui.afterHex === '#336699' && report.ui.beforeAlpha === '1' && report.ui.afterAlpha === 0.8 && same(report.ui.beforeValue, [0, 0, 0, 1]) && same(report.ui.afterValue, target) && report.ui.documentVersion === 3 && report.ui.dirty && report.ui.objectState === 'touched' && report.ui.errors.length === 0 + && report.persistence?.mode === 'sqlite-opfs' && report.persistence.sqliteWasm && report.persistence.opfs && report.persistence.savedMode === 'sqlite-opfs' && same(report.persistence.loadedValue, target) && report.persistence.loadedType === 'App::PropertyColor' && report.persistence.checkpointVersion === 3 && report.persistence.recoveryIntegrity === 'ok' && report.persistence.fcstdElement === 'PropertyColor' && report.persistence.fcstdValue === '862362060' + && report.resource !== undefined && report.resource.byteLength > 0 && report.resource.roundTrip && report.resource.released && report.resource.markerRemoved + && report.release?.shapeCount === 0 && report.release.kernelReferenceCount === 0 && report.release.workerTerminated + ? 'pass' : 'failed' + +document.documentElement.dataset.status = report.status +document.body.textContent = JSON.stringify(report, null, 2) +await fetch('/__chrome-property-color-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) }) +if (report.status !== 'pass') throw new Error(report.error || 'Chrome PropertyColor harness failed.') + +export {} diff --git a/src/chromePropertyColorListHarness.tsx b/src/chromePropertyColorListHarness.tsx new file mode 100644 index 0000000..a8b6f42 --- /dev/null +++ b/src/chromePropertyColorListHarness.tsx @@ -0,0 +1,282 @@ +import { useEffect, useState } from 'react' +import { createRoot } from 'react-dom/client' +import { unzipSync } from 'fflate' +import { PropertyEditor } from './App' +import { createProductionFacade } from './facade/productionFacade' +import type { BitBybitWebCadFacade, ColorListValue, DocumentSnapshot, ObjectPropertySnapshot } from './facade/types' +import './styles.css' + +type WorkerTrace = { + constructed: Array<{ name: string; url: string }> + requestTypes: string[] + terminated: string[] +} + +type PropertyColorListReport = { + schemaVersion: 1 + status: 'running' | 'pass' | 'failed' + browserId: 'chrome' + userAgent: string + crossOriginIsolated: boolean + worker?: WorkerTrace + ui?: { + rgbInputTypes: string[] + alphaInputTypes: string[] + rgbLabels: string[] + alphaLabels: string[] + addLabel: string + removeLabel: string + beforeHex: string[] + afterHex: string[] + beforeAlpha: string[] + afterAlpha: number[] + beforeValue: ColorListValue + afterValue: ColorListValue + beforeItemCount: number + peakItemCount: number + afterItemCount: number + documentVersion: number + dirty: boolean + objectState: string | null + errors: string[] + } + persistence?: { + mode: string + sqliteWasm: boolean + opfs: boolean + savedMode: string + loadedValue: ColorListValue | null + loadedType: string | null + checkpointVersion: number | null + recoveryIntegrity: string + fcstdElement: string | null + fcstdValue: string | null + fcstdResourcePath: string | null + fcstdResourceBytes: number + } + resource?: { byteLength: number; roundTrip: boolean; released: boolean; markerRemoved: boolean } + release?: { shapeCount: number; kernelReferenceCount: number; workerTerminated: boolean } + error?: string +} + +const fixture = (): DocumentSnapshot => ({ + id: 'chrome-property-colorlist', + label: 'Chrome PropertyColorList', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [{ id: 'ColorListProbe', label: 'Color list probe', type: 'feature', state: 'valid' }], + objects: [{ + id: 'ColorListProbe', + typeId: 'App::FeatureTest', + properties: [{ name: 'ColourList', label: 'Colour list', group: 'Test', scope: 'data', type: 'App::PropertyColorList', value: [[0, 0, 0, 1]], recompute: true }], + }], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { ColorListProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const colorListProperty = (facade: BitBybitWebCadFacade) => facade.app.document.getObject('ColorListProbe')?.properties.find((property) => property.name === 'ColourList') +const clone = (value: ColorListValue): ColorListValue => value.map((color) => [...color]) + +function HarnessEditor({ facade, errors }: { facade: BitBybitWebCadFacade; errors: string[] }) { + const [property, setProperty] = useState(() => colorListProperty(facade) ?? null) + useEffect(() => facade.subscribe((event) => { + if (event.type === 'state.changed') setProperty(colorListProperty(facade) ?? null) + }), [facade]) + if (!property) return
Color list property is missing.
+ return
Property view

Color list probe

Test
errors.push(message)} />
+} + +const waitFor = async (predicate: () => boolean, message: string, timeoutMs = 30_000) => { + const deadline = performance.now() + timeoutMs + while (performance.now() < deadline) { + if (predicate()) return + await new Promise((resolve) => setTimeout(resolve, 25)) + } + throw new Error(`Timed out waiting for ${message}.`) +} + +const setNativeInputValue = (input: HTMLInputElement, value: string) => { + const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set + if (!setter) throw new Error('The native HTMLInputElement value setter is unavailable.') + setter.call(input, value) +} + +const trace: WorkerTrace = { constructed: [], requestTypes: [], terminated: [] } +const BrowserWorker = globalThis.Worker +class TrackedWorker extends BrowserWorker { + private readonly traceName: string + + constructor(scriptURL: string | URL, options?: WorkerOptions) { + super(scriptURL, options) + this.traceName = options?.name ?? 'unnamed' + trace.constructed.push({ name: this.traceName, url: String(scriptURL) }) + } + + override postMessage(message: unknown, transferOrOptions?: StructuredSerializeOptions | Transferable[]) { + if (message && typeof message === 'object' && 'type' in message && typeof message.type === 'string') trace.requestTypes.push(message.type) + if (Array.isArray(transferOrOptions)) super.postMessage(message, transferOrOptions) + else if (transferOrOptions) super.postMessage(message, transferOrOptions) + else super.postMessage(message) + } + + override terminate() { + trace.terminated.push(this.traceName) + super.terminate() + } +} +Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: TrackedWorker }) + +const target: ColorListValue = [ + [0.2, 0.4, 0.6, 0.8], + [17 / 255, 34 / 255, 51 / 255, 0.4], +] +const report: PropertyColorListReport = { schemaVersion: 1, status: 'running', browserId: 'chrome', userAgent: navigator.userAgent, crossOriginIsolated: globalThis.crossOriginIsolated === true } +const errors: string[] = [] +const facade = createProductionFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['ColorListProbe'] }) +const root = createRoot(document.getElementById('root')!) +root.render() + +try { + await waitFor(() => document.querySelector('input[aria-label="Colour list 1 RGB"]') !== null && document.querySelector('button[aria-label="Add Colour list color"]') !== null, 'the production PropertyColorList editor') + await waitFor(() => facade.project.capabilities().mode === 'sqlite-opfs', 'the SQLite OPFS Worker') + const beforeRgb = [...document.querySelectorAll('.property-color-list-item input[type="color"]')] + const beforeAlphaInputs = [...document.querySelectorAll('.property-color-list-item input[type="number"]')] + const beforeHex = beforeRgb.map((input) => input.value) + const beforeAlpha = beforeAlphaInputs.map((input) => input.value) + const beforeValue = clone(colorListProperty(facade)?.value as ColorListValue) + const addButton = document.querySelector('button[aria-label="Add Colour list color"]')! + const addLabel = addButton.getAttribute('aria-label') ?? '' + + addButton.click() + await waitFor(() => facade.app.document.getActive().version === 2 && document.querySelectorAll('.property-color-list-item').length === 2, 'the first ColorList item addition') + document.querySelector('button[aria-label="Add Colour list color"]')!.click() + await waitFor(() => facade.app.document.getActive().version === 3 && document.querySelectorAll('.property-color-list-item').length === 3, 'the second ColorList item addition') + const peakItemCount = document.querySelectorAll('.property-color-list-item').length + const removeButton = document.querySelector('button[aria-label="Remove Colour list 3"]')! + const removeLabel = removeButton.getAttribute('aria-label') ?? '' + removeButton.click() + await waitFor(() => facade.app.document.getActive().version === 4 && document.querySelectorAll('.property-color-list-item').length === 2, 'the ColorList item removal') + + const editRgb = async (index: number, value: string, version: number) => { + const input = document.querySelector(`input[aria-label="Colour list ${index + 1} RGB"]`) + if (!input) throw new Error(`ColorList RGB input ${index + 1} is missing.`) + input.focus() + setNativeInputValue(input, value) + input.dispatchEvent(new Event('input', { bubbles: true })) + input.dispatchEvent(new Event('change', { bubbles: true })) + await waitFor(() => facade.app.document.getActive().version === version, `ColorList RGB commit ${index + 1}`) + } + const editAlpha = async (index: number, value: string, version: number) => { + const input = document.querySelector(`input[aria-label="Colour list ${index + 1} alpha"]`) + if (!input) throw new Error(`ColorList alpha input ${index + 1} is missing.`) + input.focus() + input.value = value + input.dispatchEvent(new Event('input', { bubbles: true })) + input.blur() + await waitFor(() => facade.app.document.getActive().version === version, `ColorList alpha commit ${index + 1}`) + } + await editRgb(0, '#336699', 5) + await editAlpha(0, '0.8', 6) + await editRgb(1, '#112233', 7) + await editAlpha(1, '0.4', 8) + + const edited = facade.app.document.getActive() + const editedProperty = colorListProperty(facade) + const rgbInputs = [...document.querySelectorAll('.property-color-list-item input[type="color"]')] + const alphaInputs = [...document.querySelectorAll('.property-color-list-item input[type="number"]')] + report.ui = { + rgbInputTypes: rgbInputs.map((input) => input.type), + alphaInputTypes: alphaInputs.map((input) => input.type), + rgbLabels: rgbInputs.map((input) => input.getAttribute('aria-label') ?? ''), + alphaLabels: alphaInputs.map((input) => input.getAttribute('aria-label') ?? ''), + addLabel, + removeLabel, + beforeHex, + afterHex: rgbInputs.map((input) => input.value), + beforeAlpha, + afterAlpha: (editedProperty?.value as ColorListValue).map((color) => color[3]), + beforeValue, + afterValue: clone(editedProperty?.value as ColorListValue), + beforeItemCount: beforeRgb.length, + peakItemCount, + afterItemCount: rgbInputs.length, + documentVersion: edited.version, + dirty: edited.dirty, + objectState: edited.recompute?.objectStates.ColorListProbe ?? null, + errors, + } + + const saved = await facade.project.save() + const loaded = await facade.project.load(edited.id) + const checkpoint = await facade.project.loadCheckpoint(edited.id, edited.version) + const recovery = await facade.project.recovery(edited.id) + const loadedProperty = loaded?.objects.find((object) => object.id === 'ColorListProbe')?.properties.find((property) => property.name === 'ColourList') + const archive = facade.project.fcstd.serializeMetadata(edited) + const archiveProperty = facade.project.fcstd.inspect(archive).objects.find((object) => object.name === 'ColorListProbe')?.properties.find((property) => property.name === 'ColourList') + const archiveFiles = unzipSync(archive) + const resourcePath = archiveProperty?.resourcePath ?? '' + const capabilities = facade.project.capabilities() + const loadedValue = loadedProperty?.value + const validLoadedValue = Array.isArray(loadedValue) && loadedValue.every((color) => Array.isArray(color) && color.length === 4 && color.every((channel) => typeof channel === 'number' && Number.isFinite(channel))) + report.persistence = { + mode: capabilities.mode, + sqliteWasm: capabilities.sqliteWasm, + opfs: capabilities.opfs, + savedMode: saved.mode, + loadedValue: validLoadedValue ? clone(loadedValue as ColorListValue) : null, + loadedType: loadedProperty?.type ?? null, + checkpointVersion: checkpoint?.version ?? null, + recoveryIntegrity: recovery.integrity, + fcstdElement: archiveProperty?.element ?? null, + fcstdValue: archiveProperty?.value ?? null, + fcstdResourcePath: resourcePath || null, + fcstdResourceBytes: resourcePath && archiveFiles[resourcePath] ? archiveFiles[resourcePath].byteLength : 0, + } + + const payload = new TextEncoder().encode('PropertyColorList Chrome resource') + const stored = await facade.project.resource.put(payload, 'application/vnd.freecad.property-colorlist+json') + const restored = await facade.project.resource.get(stored.hash) + await facade.project.resource.release(stored.hash) + const released = await facade.project.resource.get(stored.hash) === null + const directory = await navigator.storage.getDirectory() + const markerName = 'property-colorlist-chrome-marker.json' + const marker = await directory.getFileHandle(markerName, { create: true }) + const writable = await marker.createWritable() + await writable.write(JSON.stringify({ suite: 'PROP-COLORLIST-H', value: target })) + await writable.close() + await directory.removeEntry(markerName) + let markerRemoved = false + try { await directory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' } + report.resource = { byteLength: stored.byteLength, roundTrip: restored !== null && new TextDecoder().decode(restored) === new TextDecoder().decode(payload), released, markerRemoved } +} catch (error) { + report.error = error instanceof Error ? error.stack || error.message : String(error) +} finally { + root.unmount() + facade.geometry.dispose() + await facade.project.dispose().catch((error: unknown) => { report.error = `${report.error ? `${report.error}\n` : ''}${error instanceof Error ? error.stack || error.message : String(error)}` }) + Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: BrowserWorker }) + const geometry = facade.geometry.capabilities() + report.worker = trace + report.release = { shapeCount: geometry.shapeCount, kernelReferenceCount: geometry.kernelReferenceCount, workerTerminated: trace.terminated.includes('bitbybit-persistence') } +} + +const same = (left: ColorListValue | null | undefined, right: ColorListValue) => Array.isArray(left) && left.length === right.length && left.every((color, index) => color.length === right[index]?.length && color.every((channel, channelIndex) => channel === right[index][channelIndex])) +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +report.status = !report.error + && report.crossOriginIsolated + && report.worker?.constructed.some(({ name }) => name === 'bitbybit-persistence') === true + && requiredWorkerRequests.every((type) => report.worker?.requestTypes.includes(type)) + && report.ui?.rgbInputTypes.every((type) => type === 'color') === true && report.ui.alphaInputTypes.every((type) => type === 'number') && report.ui.rgbLabels.join('|') === 'Colour list 1 RGB|Colour list 2 RGB' && report.ui.alphaLabels.join('|') === 'Colour list 1 alpha|Colour list 2 alpha' && report.ui.addLabel === 'Add Colour list color' && report.ui.removeLabel === 'Remove Colour list 3' && report.ui.beforeHex.join('|') === '#000000' && report.ui.afterHex.join('|') === '#336699|#112233' && report.ui.beforeAlpha.join('|') === '1' && report.ui.afterAlpha.join('|') === '0.8|0.4' && same(report.ui.beforeValue, [[0, 0, 0, 1]]) && same(report.ui.afterValue, target) && report.ui.beforeItemCount === 1 && report.ui.peakItemCount === 3 && report.ui.afterItemCount === 2 && report.ui.documentVersion === 8 && report.ui.dirty && report.ui.objectState === 'touched' && report.ui.errors.length === 0 + && report.persistence?.mode === 'sqlite-opfs' && report.persistence.sqliteWasm && report.persistence.opfs && report.persistence.savedMode === 'sqlite-opfs' && same(report.persistence.loadedValue, target) && report.persistence.loadedType === 'App::PropertyColorList' && report.persistence.checkpointVersion === 8 && report.persistence.recoveryIntegrity === 'ok' && report.persistence.fcstdElement === 'ColorList' && report.persistence.fcstdValue === JSON.stringify(target) && report.persistence.fcstdResourcePath === 'ColourList' && report.persistence.fcstdResourceBytes === 12 + && report.resource !== undefined && report.resource.byteLength > 0 && report.resource.roundTrip && report.resource.released && report.resource.markerRemoved + && report.release?.shapeCount === 0 && report.release.kernelReferenceCount === 0 && report.release.workerTerminated + ? 'pass' : 'failed' + +document.documentElement.dataset.status = report.status +document.body.textContent = JSON.stringify(report, null, 2) +await fetch('/__chrome-property-colorlist-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) }) +if (report.status !== 'pass') throw new Error(report.error || 'Chrome PropertyColorList harness failed.') + +export {} diff --git a/src/chromePropertyDirectionHarness.tsx b/src/chromePropertyDirectionHarness.tsx new file mode 100644 index 0000000..46d9cae --- /dev/null +++ b/src/chromePropertyDirectionHarness.tsx @@ -0,0 +1,189 @@ +import { useEffect, useState } from 'react' +import { createRoot } from 'react-dom/client' +import { PropertyEditor } from './App' +import { createProductionFacade } from './facade/productionFacade' +import type { BitBybitWebCadFacade, DocumentSnapshot, ObjectPropertySnapshot, VectorValue } from './facade/types' +import './styles.css' + +type WorkerTrace = { + constructed: Array<{ name: string; url: string }> + requestTypes: string[] + terminated: string[] +} + +type PropertyDirectionReport = { + schemaVersion: 1 + status: 'running' | 'pass' | 'failed' + browserId: 'chrome' + userAgent: string + crossOriginIsolated: boolean + worker?: WorkerTrace + ui?: { inputTypes: string[]; labels: string[]; beforeValue: VectorValue; afterValue: VectorValue; documentVersion: number; dirty: boolean; objectState: string | null; errors: string[] } + persistence?: { mode: string; sqliteWasm: boolean; opfs: boolean; savedMode: string; loadedValue: VectorValue | null; loadedType: string | null; checkpointVersion: number | null; recoveryIntegrity: string; fcstdElement: string | null; fcstdValue: string | null } + resource?: { byteLength: number; roundTrip: boolean; released: boolean; markerRemoved: boolean } + release?: { shapeCount: number; kernelReferenceCount: number; workerTerminated: boolean } + error?: string +} + +const fixture = (): DocumentSnapshot => ({ + id: 'chrome-property-direction', + label: 'Chrome PropertyDirection', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [{ id: 'DirectionProbe', label: 'Direction probe', type: 'feature', state: 'valid' }], + objects: [{ + id: 'DirectionProbe', + typeId: 'Part::Mirroring', + properties: [{ name: 'Normal', label: 'Normal', group: 'Plane', scope: 'data', type: 'App::PropertyDirection', value: { x: 0, y: 0, z: 1 }, recompute: true }], + }], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { DirectionProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const directionProperty = (facade: BitBybitWebCadFacade) => facade.app.document.getObject('DirectionProbe')?.properties.find((property) => property.name === 'Normal') + +function HarnessEditor({ facade, errors }: { facade: BitBybitWebCadFacade; errors: string[] }) { + const [property, setProperty] = useState(() => directionProperty(facade) ?? null) + useEffect(() => facade.subscribe((event) => { + if (event.type === 'state.changed') setProperty(directionProperty(facade) ?? null) + }), [facade]) + if (!property) return
Direction property is missing.
+ return
Property view

Direction probe

Plane
errors.push(message)} />
+} + +const waitFor = async (predicate: () => boolean, message: string, timeoutMs = 30_000) => { + const deadline = performance.now() + timeoutMs + while (performance.now() < deadline) { + if (predicate()) return + await new Promise((resolve) => setTimeout(resolve, 25)) + } + throw new Error(`Timed out waiting for ${message}.`) +} + +const trace: WorkerTrace = { constructed: [], requestTypes: [], terminated: [] } +const BrowserWorker = globalThis.Worker +class TrackedWorker extends BrowserWorker { + private readonly traceName: string + + constructor(scriptURL: string | URL, options?: WorkerOptions) { + super(scriptURL, options) + this.traceName = options?.name ?? 'unnamed' + trace.constructed.push({ name: this.traceName, url: String(scriptURL) }) + } + + override postMessage(message: unknown, transferOrOptions?: StructuredSerializeOptions | Transferable[]) { + if (message && typeof message === 'object' && 'type' in message && typeof message.type === 'string') trace.requestTypes.push(message.type) + if (Array.isArray(transferOrOptions)) super.postMessage(message, transferOrOptions) + else if (transferOrOptions) super.postMessage(message, transferOrOptions) + else super.postMessage(message) + } + + override terminate() { + trace.terminated.push(this.traceName) + super.terminate() + } +} +Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: TrackedWorker }) + +const initial: VectorValue = { x: 0, y: 0, z: 1 } +const target: VectorValue = { x: 0.25, y: -0.5, z: 1.5 } +const report: PropertyDirectionReport = { schemaVersion: 1, status: 'running', browserId: 'chrome', userAgent: navigator.userAgent, crossOriginIsolated: globalThis.crossOriginIsolated === true } +const errors: string[] = [] +const facade = createProductionFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['DirectionProbe'] }) +const root = createRoot(document.getElementById('root')!) +root.render() + +try { + await waitFor(() => ['x', 'y', 'z'].every((axis) => document.querySelector(`input[aria-label="Normal ${axis}"]`) !== null), 'the production PropertyDirection editor') + await waitFor(() => facade.project.capabilities().mode === 'sqlite-opfs', 'the SQLite OPFS Worker') + const inputs = (['x', 'y', 'z'] as const).map((axis) => document.querySelector(`input[aria-label="Normal ${axis}"]`)!) + const beforeValue = { ...(directionProperty(facade)?.value as VectorValue) } + for (const [index, input] of inputs.entries()) { + input.focus() + input.value = String([target.x, target.y, target.z][index]) + input.dispatchEvent(new Event('input', { bubbles: true })) + input.blur() + await waitFor(() => facade.app.document.getActive().version === index + 2, `the Normal ${['x', 'y', 'z'][index]} property commit`) + } + const edited = facade.app.document.getActive() + const editedProperty = directionProperty(facade) + report.ui = { + inputTypes: inputs.map((input) => input.type), + labels: inputs.map((input) => input.getAttribute('aria-label') ?? ''), + beforeValue, + afterValue: { ...(editedProperty?.value as VectorValue) }, + documentVersion: edited.version, + dirty: edited.dirty, + objectState: edited.recompute?.objectStates.DirectionProbe ?? null, + errors, + } + + const saved = await facade.project.save() + const loaded = await facade.project.load(edited.id) + const checkpoint = await facade.project.loadCheckpoint(edited.id, edited.version) + const recovery = await facade.project.recovery(edited.id) + const loadedProperty = loaded?.objects.find((object) => object.id === 'DirectionProbe')?.properties.find((property) => property.name === 'Normal') + const archive = facade.project.fcstd.serializeMetadata(edited) + const archiveProperty = facade.project.fcstd.inspect(archive).objects.find((object) => object.name === 'DirectionProbe')?.properties.find((property) => property.name === 'Normal') + const capabilities = facade.project.capabilities() + const loadedValue = loadedProperty?.value + report.persistence = { + mode: capabilities.mode, + sqliteWasm: capabilities.sqliteWasm, + opfs: capabilities.opfs, + savedMode: saved.mode, + loadedValue: loadedValue && typeof loadedValue === 'object' && !Array.isArray(loadedValue) && 'x' in loadedValue ? { x: Number(loadedValue.x), y: Number(loadedValue.y), z: Number(loadedValue.z) } : null, + loadedType: loadedProperty?.type ?? null, + checkpointVersion: checkpoint?.version ?? null, + recoveryIntegrity: recovery.integrity, + fcstdElement: archiveProperty?.element ?? null, + fcstdValue: archiveProperty?.value ?? null, + } + + const payload = new TextEncoder().encode('PropertyDirection Chrome resource') + const stored = await facade.project.resource.put(payload, 'application/vnd.freecad.property-direction+json') + const restored = await facade.project.resource.get(stored.hash) + await facade.project.resource.release(stored.hash) + const released = await facade.project.resource.get(stored.hash) === null + const directory = await navigator.storage.getDirectory() + const markerName = 'property-direction-chrome-marker.json' + const marker = await directory.getFileHandle(markerName, { create: true }) + const writable = await marker.createWritable() + await writable.write(JSON.stringify({ suite: 'PROP-DIRECTION-H', value: target })) + await writable.close() + await directory.removeEntry(markerName) + let markerRemoved = false + try { await directory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' } + report.resource = { byteLength: stored.byteLength, roundTrip: restored !== null && new TextDecoder().decode(restored) === new TextDecoder().decode(payload), released, markerRemoved } +} catch (error) { + report.error = error instanceof Error ? error.stack || error.message : String(error) +} finally { + root.unmount() + facade.geometry.dispose() + await facade.project.dispose().catch((error: unknown) => { report.error = `${report.error ? `${report.error}\n` : ''}${error instanceof Error ? error.stack || error.message : String(error)}` }) + Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: BrowserWorker }) + const geometry = facade.geometry.capabilities() + report.worker = trace + report.release = { shapeCount: geometry.shapeCount, kernelReferenceCount: geometry.kernelReferenceCount, workerTerminated: trace.terminated.includes('bitbybit-persistence') } +} + +const sameVector = (left: VectorValue | null | undefined, right: VectorValue) => !!left && (['x', 'y', 'z'] as const).every((axis) => left[axis] === right[axis]) +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +report.status = !report.error + && report.crossOriginIsolated + && report.worker?.constructed.some(({ name }) => name === 'bitbybit-persistence') === true + && requiredWorkerRequests.every((type) => report.worker?.requestTypes.includes(type)) + && report.ui?.inputTypes.every((type) => type === 'number') && sameVector(report.ui?.beforeValue, initial) && sameVector(report.ui?.afterValue, target) && report.ui?.labels.join('|') === 'Normal x|Normal y|Normal z' && report.ui.documentVersion === 4 && report.ui.dirty && report.ui.objectState === 'touched' && report.ui.errors.length === 0 + && report.persistence?.mode === 'sqlite-opfs' && report.persistence.sqliteWasm && report.persistence.opfs && report.persistence.savedMode === 'sqlite-opfs' && sameVector(report.persistence.loadedValue, target) && report.persistence.loadedType === 'App::PropertyDirection' && report.persistence.checkpointVersion === 4 && report.persistence.recoveryIntegrity === 'ok' && report.persistence.fcstdElement === 'PropertyVector' && report.persistence.fcstdValue === JSON.stringify(target) + && report.resource !== undefined && report.resource.byteLength > 0 && report.resource.roundTrip && report.resource.released && report.resource.markerRemoved + && report.release?.shapeCount === 0 && report.release.kernelReferenceCount === 0 && report.release.workerTerminated + ? 'pass' : 'failed' + +document.documentElement.dataset.status = report.status +document.body.textContent = JSON.stringify(report, null, 2) +await fetch('/__chrome-property-direction-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) }) +if (report.status !== 'pass') throw new Error(report.error || 'Chrome PropertyDirection harness failed.') + +export {} diff --git a/src/chromePropertyFileHarness.tsx b/src/chromePropertyFileHarness.tsx new file mode 100644 index 0000000..4c6c803 --- /dev/null +++ b/src/chromePropertyFileHarness.tsx @@ -0,0 +1,184 @@ +import { useEffect, useState } from 'react' +import { createRoot } from 'react-dom/client' +import { PropertyEditor } from './App' +import { createProductionFacade } from './facade/productionFacade' +import type { BitBybitWebCadFacade, DocumentSnapshot, ObjectPropertySnapshot } from './facade/types' +import './styles.css' + +type WorkerTrace = { + constructed: Array<{ name: string; url: string }> + requestTypes: string[] + terminated: string[] +} + +type PropertyFileReport = { + schemaVersion: 1 + status: 'running' | 'pass' | 'failed' + browserId: 'chrome' + userAgent: string + crossOriginIsolated: boolean + worker?: WorkerTrace + ui?: { inputType: string; label: string; beforeValue: string; afterValue: string; documentVersion: number; dirty: boolean; objectState: string | null; errors: string[] } + persistence?: { mode: string; sqliteWasm: boolean; opfs: boolean; savedMode: string; loadedValue: string | null; loadedType: string | null; checkpointVersion: number | null; recoveryIntegrity: string; fcstdElement: string | null; fcstdValue: string | null } + resource?: { byteLength: number; roundTrip: boolean; released: boolean; markerRemoved: boolean } + release?: { shapeCount: number; kernelReferenceCount: number; workerTerminated: boolean } + error?: string +} + +const fixture = (): DocumentSnapshot => ({ + id: 'chrome-property-file', + label: 'Chrome PropertyFile', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [{ id: 'FileProbe', label: 'File probe', type: 'feature', state: 'valid' }], + objects: [{ + id: 'FileProbe', + typeId: 'Mesh::Import', + properties: [{ name: 'FileName', label: 'File name', group: '', scope: 'data', type: 'App::PropertyFile', value: 'project-files/initial.obj', recompute: true }], + }], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { FileProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const fileProperty = (facade: BitBybitWebCadFacade) => facade.app.document.getObject('FileProbe')?.properties.find((property) => property.name === 'FileName') + +function HarnessEditor({ facade, errors }: { facade: BitBybitWebCadFacade; errors: string[] }) { + const [property, setProperty] = useState(() => fileProperty(facade) ?? null) + useEffect(() => facade.subscribe((event) => { + if (event.type === 'state.changed') setProperty(fileProperty(facade) ?? null) + }), [facade]) + if (!property) return
File property is missing.
+ return
Property view

File probe

File
errors.push(message)} />
+} + +const waitFor = async (predicate: () => boolean, message: string, timeoutMs = 30_000) => { + const deadline = performance.now() + timeoutMs + while (performance.now() < deadline) { + if (predicate()) return + await new Promise((resolve) => setTimeout(resolve, 25)) + } + throw new Error(`Timed out waiting for ${message}.`) +} + +const trace: WorkerTrace = { constructed: [], requestTypes: [], terminated: [] } +const BrowserWorker = globalThis.Worker +class TrackedWorker extends BrowserWorker { + private readonly traceName: string + + constructor(scriptURL: string | URL, options?: WorkerOptions) { + super(scriptURL, options) + this.traceName = options?.name ?? 'unnamed' + trace.constructed.push({ name: this.traceName, url: String(scriptURL) }) + } + + override postMessage(message: unknown, transferOrOptions?: StructuredSerializeOptions | Transferable[]) { + if (message && typeof message === 'object' && 'type' in message && typeof message.type === 'string') trace.requestTypes.push(message.type) + if (Array.isArray(transferOrOptions)) super.postMessage(message, transferOrOptions) + else if (transferOrOptions) super.postMessage(message, transferOrOptions) + else super.postMessage(message) + } + + override terminate() { + trace.terminated.push(this.traceName) + super.terminate() + } +} +Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: TrackedWorker }) + +const initial = 'project-files/initial.obj' +const target = 'project-files/chrome-updated.obj' +const report: PropertyFileReport = { schemaVersion: 1, status: 'running', browserId: 'chrome', userAgent: navigator.userAgent, crossOriginIsolated: globalThis.crossOriginIsolated === true } +const errors: string[] = [] +const facade = createProductionFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['FileProbe'] }) +const root = createRoot(document.getElementById('root')!) +root.render() + +try { + await waitFor(() => document.querySelector('input[aria-label="File name"]') !== null, 'the production PropertyFile editor') + await waitFor(() => facade.project.capabilities().mode === 'sqlite-opfs', 'the SQLite OPFS Worker') + const input = document.querySelector('input[aria-label="File name"]')! + const beforeValue = String(fileProperty(facade)?.value ?? '') + input.focus() + input.value = target + input.dispatchEvent(new Event('input', { bubbles: true })) + input.blur() + await waitFor(() => facade.app.document.getActive().version === 2, 'the FileName property commit') + const edited = facade.app.document.getActive() + report.ui = { + inputType: input.type, + label: input.getAttribute('aria-label') ?? '', + beforeValue, + afterValue: String(fileProperty(facade)?.value ?? ''), + documentVersion: edited.version, + dirty: edited.dirty, + objectState: edited.recompute?.objectStates.FileProbe ?? null, + errors, + } + + const saved = await facade.project.save() + const loaded = await facade.project.load(edited.id) + const checkpoint = await facade.project.loadCheckpoint(edited.id, edited.version) + const recovery = await facade.project.recovery(edited.id) + const loadedProperty = loaded?.objects.find((object) => object.id === 'FileProbe')?.properties.find((property) => property.name === 'FileName') + const archive = facade.project.fcstd.serializeMetadata(edited) + const archiveProperty = facade.project.fcstd.inspect(archive).objects.find((object) => object.name === 'FileProbe')?.properties.find((property) => property.name === 'FileName') + const capabilities = facade.project.capabilities() + report.persistence = { + mode: capabilities.mode, + sqliteWasm: capabilities.sqliteWasm, + opfs: capabilities.opfs, + savedMode: saved.mode, + loadedValue: typeof loadedProperty?.value === 'string' ? loadedProperty.value : null, + loadedType: loadedProperty?.type ?? null, + checkpointVersion: checkpoint?.version ?? null, + recoveryIntegrity: recovery.integrity, + fcstdElement: archiveProperty?.element ?? null, + fcstdValue: archiveProperty?.value ?? null, + } + + const payload = new TextEncoder().encode('# PropertyFile Chrome resource\nv 0 0 0\nv 1 0 0\nv 0 1 0\nf 1 2 3\n') + const stored = await facade.project.resource.put(payload, 'model/obj') + const restored = await facade.project.resource.get(stored.hash) + await facade.project.resource.release(stored.hash) + const released = await facade.project.resource.get(stored.hash) === null + const directory = await navigator.storage.getDirectory() + const markerName = 'property-file-chrome-marker.json' + const marker = await directory.getFileHandle(markerName, { create: true }) + const writable = await marker.createWritable() + await writable.write(JSON.stringify({ suite: 'PROP-FILE-H', value: target })) + await writable.close() + await directory.removeEntry(markerName) + let markerRemoved = false + try { await directory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' } + report.resource = { byteLength: stored.byteLength, roundTrip: restored !== null && new TextDecoder().decode(restored) === new TextDecoder().decode(payload), released, markerRemoved } +} catch (error) { + report.error = error instanceof Error ? error.stack || error.message : String(error) +} finally { + root.unmount() + facade.geometry.dispose() + await facade.project.dispose().catch((error: unknown) => { report.error = `${report.error ? `${report.error}\n` : ''}${error instanceof Error ? error.stack || error.message : String(error)}` }) + Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: BrowserWorker }) + const geometry = facade.geometry.capabilities() + report.worker = trace + report.release = { shapeCount: geometry.shapeCount, kernelReferenceCount: geometry.kernelReferenceCount, workerTerminated: trace.terminated.includes('bitbybit-persistence') } +} + +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +report.status = !report.error + && report.crossOriginIsolated + && report.worker?.constructed.some(({ name }) => name === 'bitbybit-persistence') === true + && requiredWorkerRequests.every((type) => report.worker?.requestTypes.includes(type)) + && report.ui?.inputType === 'text' && report.ui.label === 'File name' && report.ui.beforeValue === initial && report.ui.afterValue === target && report.ui.documentVersion === 2 && report.ui.dirty && report.ui.objectState === 'touched' && report.ui.errors.length === 0 + && report.persistence?.mode === 'sqlite-opfs' && report.persistence.sqliteWasm && report.persistence.opfs && report.persistence.savedMode === 'sqlite-opfs' && report.persistence.loadedValue === target && report.persistence.loadedType === 'App::PropertyFile' && report.persistence.checkpointVersion === 2 && report.persistence.recoveryIntegrity === 'ok' && report.persistence.fcstdElement === 'String' && report.persistence.fcstdValue === target + && report.resource !== undefined && report.resource.byteLength > 0 && report.resource.roundTrip && report.resource.released && report.resource.markerRemoved + && report.release?.shapeCount === 0 && report.release.kernelReferenceCount === 0 && report.release.workerTerminated + ? 'pass' : 'failed' + +document.documentElement.dataset.status = report.status +document.body.textContent = JSON.stringify(report, null, 2) +await fetch('/__chrome-property-file-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) }) +if (report.status !== 'pass') throw new Error(report.error || 'Chrome PropertyFile harness failed.') + +export {} diff --git a/src/chromePropertyFileIncludedHarness.tsx b/src/chromePropertyFileIncludedHarness.tsx new file mode 100644 index 0000000..c743ad0 --- /dev/null +++ b/src/chromePropertyFileIncludedHarness.tsx @@ -0,0 +1,202 @@ +import { useEffect, useState } from 'react' +import { createRoot } from 'react-dom/client' +import { unzipSync } from 'fflate' +import { PropertyEditor } from './App' +import { createProductionFacade } from './facade/productionFacade' +import type { BitBybitWebCadFacade, DocumentSnapshot, IncludedFileValue, ObjectPropertySnapshot } from './facade/types' +import './styles.css' + +type WorkerTrace = { + constructed: Array<{ name: string; url: string }> + requestTypes: string[] + terminated: string[] +} + +type PropertyFileIncludedReport = { + schemaVersion: 1 + status: 'running' | 'pass' | 'failed' + browserId: 'chrome' + userAgent: string + crossOriginIsolated: boolean + worker?: WorkerTrace + ui?: { inputType: string; label: string; beforeName: string; afterName: string; afterValue: IncludedFileValue | null; documentVersion: number; dirty: boolean; objectState: string | null; notices: string[] } + persistence?: { mode: string; sqliteWasm: boolean; opfs: boolean; savedMode: string; loadedValue: IncludedFileValue | null; loadedType: string | null; checkpointVersion: number | null; recoveryIntegrity: string; fcstdElement: string | null; fcstdResourcePath: string | null; fcstdResourceBytes: number; fcstdResourceMatches: boolean } + resource?: { documentByteLength: number; documentRoundTrip: boolean; independentByteLength: number; independentRoundTrip: boolean; independentReleased: boolean; markerRemoved: boolean } + release?: { shapeCount: number; kernelReferenceCount: number; workerTerminated: boolean } + error?: string +} + +const fixture = (): DocumentSnapshot => ({ + id: 'chrome-property-fileincluded', + label: 'Chrome PropertyFileIncluded', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [{ id: 'IncludedProbe', label: 'Included file probe', type: 'feature', state: 'valid' }], + objects: [{ + id: 'IncludedProbe', + typeId: 'App::DocumentObjectFileIncluded', + properties: [{ name: 'File', label: 'Embedded file', group: 'Resource', scope: 'data', type: 'App::PropertyFileIncluded', value: null, recompute: true }], + }], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { IncludedProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const includedProperty = (facade: BitBybitWebCadFacade) => facade.app.document.getObject('IncludedProbe')?.properties.find((property) => property.name === 'File') +const includedValue = (facade: BitBybitWebCadFacade) => includedProperty(facade)?.value as IncludedFileValue | null + +function HarnessEditor({ facade, notices }: { facade: BitBybitWebCadFacade; notices: string[] }) { + const [property, setProperty] = useState(() => includedProperty(facade) ?? null) + useEffect(() => facade.subscribe((event) => { + if (event.type === 'state.changed') setProperty(includedProperty(facade) ?? null) + }), [facade]) + if (!property) return
Included file property is missing.
+ return
Property view

Included file probe

Resource
notices.push(message)} />
+} + +const waitFor = async (predicate: () => boolean, message: string, timeoutMs = 30_000) => { + const deadline = performance.now() + timeoutMs + while (performance.now() < deadline) { + if (predicate()) return + await new Promise((resolve) => setTimeout(resolve, 25)) + } + throw new Error(`Timed out waiting for ${message}.`) +} + +const trace: WorkerTrace = { constructed: [], requestTypes: [], terminated: [] } +const BrowserWorker = globalThis.Worker +class TrackedWorker extends BrowserWorker { + private readonly traceName: string + + constructor(scriptURL: string | URL, options?: WorkerOptions) { + super(scriptURL, options) + this.traceName = options?.name ?? 'unnamed' + trace.constructed.push({ name: this.traceName, url: String(scriptURL) }) + } + + override postMessage(message: unknown, transferOrOptions?: StructuredSerializeOptions | Transferable[]) { + if (message && typeof message === 'object' && 'type' in message && typeof message.type === 'string') trace.requestTypes.push(message.type) + if (Array.isArray(transferOrOptions)) super.postMessage(message, transferOrOptions) + else if (transferOrOptions) super.postMessage(message, transferOrOptions) + else super.postMessage(message) + } + + override terminate() { + trace.terminated.push(this.traceName) + super.terminate() + } +} +Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: TrackedWorker }) + +const targetName = 'chrome-resource.bin' +const targetBytes = new Uint8Array([67, 104, 114, 111, 109, 101, 0, 255, 128, 64, 32, 16, 8, 4, 2, 1]) +const report: PropertyFileIncludedReport = { schemaVersion: 1, status: 'running', browserId: 'chrome', userAgent: navigator.userAgent, crossOriginIsolated: globalThis.crossOriginIsolated === true } +const notices: string[] = [] +const facade = createProductionFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['IncludedProbe'] }) +const root = createRoot(document.getElementById('root')!) +root.render() + +try { + await waitFor(() => document.querySelector('input[aria-label="Embedded file"]') !== null, 'the production PropertyFileIncluded editor') + await waitFor(() => facade.project.capabilities().mode === 'sqlite-opfs', 'the SQLite OPFS Worker') + const input = document.querySelector('input[aria-label="Embedded file"]')! + const beforeName = document.querySelector('.property-included-file > span')?.textContent ?? '' + const transfer = new DataTransfer() + transfer.items.add(new File([targetBytes], targetName, { type: 'application/octet-stream' })) + input.files = transfer.files + input.dispatchEvent(new Event('change', { bubbles: true })) + await waitFor(() => facade.app.document.getActive().version === 2 && notices.length > 0, 'the included-file property commit') + const edited = facade.app.document.getActive() + const value = includedValue(facade) + report.ui = { + inputType: input.type, + label: input.getAttribute('aria-label') ?? '', + beforeName, + afterName: document.querySelector('.property-included-file > span')?.textContent ?? '', + afterValue: value, + documentVersion: edited.version, + dirty: edited.dirty, + objectState: edited.recompute?.objectStates.IncludedProbe ?? null, + notices, + } + if (!value) throw new Error('PropertyFileIncluded UI did not commit a structured value.') + + const saved = await facade.project.save() + const loaded = await facade.project.load(edited.id) + const checkpoint = await facade.project.loadCheckpoint(edited.id, edited.version) + const recovery = await facade.project.recovery(edited.id) + const loadedProperty = loaded?.objects.find((object) => object.id === 'IncludedProbe')?.properties.find((property) => property.name === 'File') + const archive = await facade.project.fcstd.serializeMetadataWithResources(edited) + const archiveProperty = facade.project.fcstd.inspect(archive).objects.find((object) => object.name === 'IncludedProbe')?.properties.find((property) => property.name === 'File') + const archiveFiles = unzipSync(archive) + const archiveResource = archiveFiles[targetName] + const capabilities = facade.project.capabilities() + report.persistence = { + mode: capabilities.mode, + sqliteWasm: capabilities.sqliteWasm, + opfs: capabilities.opfs, + savedMode: saved.mode, + loadedValue: loadedProperty?.value as IncludedFileValue | null, + loadedType: loadedProperty?.type ?? null, + checkpointVersion: checkpoint?.version ?? null, + recoveryIntegrity: recovery.integrity, + fcstdElement: archiveProperty?.element ?? null, + fcstdResourcePath: archiveProperty?.resourcePath ?? null, + fcstdResourceBytes: archiveResource?.byteLength ?? 0, + fcstdResourceMatches: archiveResource?.byteLength === targetBytes.byteLength && archiveResource.every((byte, index) => byte === targetBytes[index]), + } + + const documentResource = await facade.project.resource.get(value.resourceHash) + const independentPayload = new TextEncoder().encode('PropertyFileIncluded Chrome independent resource') + const independent = await facade.project.resource.put(independentPayload, 'text/plain') + const independentRestored = await facade.project.resource.get(independent.hash) + await facade.project.resource.release(independent.hash) + const independentReleased = await facade.project.resource.get(independent.hash) === null + const directory = await navigator.storage.getDirectory() + const markerName = 'property-fileincluded-chrome-marker.json' + const marker = await directory.getFileHandle(markerName, { create: true }) + const writable = await marker.createWritable() + await writable.write(JSON.stringify({ suite: 'PROP-FILEINCLUDED-H', archiveName: targetName })) + await writable.close() + await directory.removeEntry(markerName) + let markerRemoved = false + try { await directory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' } + report.resource = { + documentByteLength: documentResource?.byteLength ?? 0, + documentRoundTrip: documentResource?.byteLength === targetBytes.byteLength && documentResource.every((byte, index) => byte === targetBytes[index]), + independentByteLength: independent.byteLength, + independentRoundTrip: independentRestored !== null && new TextDecoder().decode(independentRestored) === new TextDecoder().decode(independentPayload), + independentReleased, + markerRemoved, + } +} catch (error) { + report.error = error instanceof Error ? error.stack || error.message : String(error) +} finally { + root.unmount() + facade.geometry.dispose() + await facade.project.dispose().catch((error: unknown) => { report.error = `${report.error ? `${report.error}\n` : ''}${error instanceof Error ? error.stack || error.message : String(error)}` }) + Object.defineProperty(globalThis, 'Worker', { configurable: true, writable: true, value: BrowserWorker }) + const geometry = facade.geometry.capabilities() + report.worker = trace + report.release = { shapeCount: geometry.shapeCount, kernelReferenceCount: geometry.kernelReferenceCount, workerTerminated: trace.terminated.includes('bitbybit-persistence') } +} + +const requiredWorkerRequests = ['initialize', 'save-document', 'load-document', 'load-checkpoint', 'recovery-report', 'put-resource', 'get-resource', 'release-resource', 'dispose'] +const value = report.ui?.afterValue +report.status = !report.error + && report.crossOriginIsolated + && report.worker?.constructed.some(({ name }) => name === 'bitbybit-persistence') === true + && requiredWorkerRequests.every((type) => report.worker?.requestTypes.includes(type)) + && report.ui?.inputType === 'file' && report.ui.label === 'Embedded file' && report.ui.beforeName === 'Empty' && report.ui.afterName === targetName && value?.schemaVersion === 1 && value.archiveName === targetName && /^[a-f0-9]{64}$/.test(value.resourceHash) && value.byteLength === targetBytes.byteLength && value.mediaType === 'application/octet-stream' && report.ui.documentVersion === 2 && report.ui.dirty && report.ui.objectState === 'touched' && report.ui.notices.length === 1 && report.ui.notices[0] === `${targetName} embedded` + && report.persistence?.mode === 'sqlite-opfs' && report.persistence.sqliteWasm && report.persistence.opfs && report.persistence.savedMode === 'sqlite-opfs' && JSON.stringify(report.persistence.loadedValue) === JSON.stringify(value) && report.persistence.loadedType === 'App::PropertyFileIncluded' && report.persistence.checkpointVersion === 2 && report.persistence.recoveryIntegrity === 'ok' && report.persistence.fcstdElement === 'FileIncluded' && report.persistence.fcstdResourcePath === targetName && report.persistence.fcstdResourceBytes === targetBytes.byteLength && report.persistence.fcstdResourceMatches + && report.resource?.documentByteLength === targetBytes.byteLength && report.resource.documentRoundTrip && report.resource.independentByteLength > 0 && report.resource.independentRoundTrip && report.resource.independentReleased && report.resource.markerRemoved + && report.release?.shapeCount === 0 && report.release.kernelReferenceCount === 0 && report.release.workerTerminated + ? 'pass' : 'failed' + +document.documentElement.dataset.status = report.status +document.body.textContent = JSON.stringify(report, null, 2) +await fetch('/__chrome-property-fileincluded-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) }) +if (report.status !== 'pass') throw new Error(report.error || 'Chrome PropertyFileIncluded harness failed.') + +export {} diff --git a/src/facade/fcstd.ts b/src/facade/fcstd.ts index ec781cf..b58c547 100644 --- a/src/facade/fcstd.ts +++ b/src/facade/fcstd.ts @@ -1,5 +1,5 @@ import { unzipSync, zipSync } from 'fflate' -import { XMLParser } from 'fast-xml-parser' +import { XMLBuilder, XMLParser } from 'fast-xml-parser' import { ATTACHMENT_MAP_MODES, validateAttachmentOffset, validateAttachmentSupport } from './attachment' import { validateSketchSnapshot } from './sketcher' import { decodeFreecadPropertyStatus, hasFreecadPropertyStatus, isFreecadPropertyNoPersist, isFreecadPropertyPersistenceSuppressed, isFreecadPropertyTransient, normalizeFreecadPropertyStatusMask } from './propertyStatus' @@ -9,7 +9,8 @@ import type { AnyElementMap2Document, ElementMap2Document } from './elementMap2' import { migrateStringHasherSchema, parseStringHasherTable, validateElementMap2StringHasherEvidence, validateStringHasherTable, writeStringHasherTable } from './stringHasher' import type { AnyStringHasherTable, StringHasherTable, StringHasherValidationReport } from './stringHasher' import type { SketchConstraint, SketchExternalGeometry, SketchExternalMode, SketchGeometry, SketchPointRef, SketchSnapshot } from './sketcher' -import type { AttachmentSupportValue, DocumentSnapshot, DocumentObjectSnapshot, ElementMapSnapshot, ModelTreeItem, ObjectPropertySnapshot, PathCommandValue, PathPropertyValue, PlacementValue, PropertyValue, TopoRefValue } from './types' +import { includedFileMediaType, validateIncludedFileArchiveName, validateIncludedFileValue } from './includedFile' +import type { AttachmentSupportValue, ColorListValue, ColorValue, DocumentSnapshot, DocumentObjectSnapshot, ElementMapSnapshot, IncludedFileValue, LinkSubListValue, ModelTreeItem, ObjectPropertySnapshot, PathCommandValue, PathPropertyValue, PlacementValue, PropertyValue, TopoRefValue, VectorValue } from './types' export type FcstdArchiveLimits = { maxArchiveBytes: number @@ -45,6 +46,8 @@ export type FcstdPropertySummary = { links?: string[] linkSubs?: Array<{ objectId: string; subElement: string }> enumOptions?: string[] + resourcePath?: string + includedFileResource?: FcstdIncludedFileResource shapeResource?: { path: string; hasherIndex?: number; elementMap?: string; elementMapEntries?: Array<{ key: string; value: string }>; elementMapResource?: string } expression?: string } @@ -52,6 +55,15 @@ export type FcstdPropertySummary = { export type FcstdDecodedPropertyValue = { value: unknown; decoded: boolean; error?: string } export type FcstdPathAccessOptions = { allowFeaturePython?: boolean } export type FcstdPathEdit = { objectName: string; propertyName?: string; value: PathPropertyValue; allowFeaturePython?: boolean } +export type FcstdNumericPropertyEdit = { objectName: string; propertyName: string; typeId: 'App::PropertyAcceleration'; value: number; expectedValue?: number } +export type FcstdMeasureAreaEdit = { objectName: string; elements: LinkSubListValue; area: number; expectedElements?: LinkSubListValue; expectedArea?: number } +export type FcstdBoolListEdit = { objectName: string; propertyName: string; value: boolean[]; expectedValue?: boolean[] } +export type FcstdColorEdit = { objectName: string; propertyName: string; value: ColorValue; expectedValue?: ColorValue } +export type FcstdColorListEdit = { objectName: string; propertyName: string; value: ColorListValue; expectedValue?: ColorListValue } +export type FcstdDirectionEdit = { objectName: string; propertyName: string; value: VectorValue; expectedValue?: VectorValue } +export type FcstdFileEdit = { objectName: string; propertyName: string; value: string; expectedValue?: string } +export type FcstdIncludedFileEdit = { objectName: string; propertyName: string; value: IncludedFileValue; expectedValue?: IncludedFileValue } +export type FcstdIncludedFileResourceEdit = FcstdIncludedFileEdit & { resourceBytes: Uint8Array; expectedResourceBytes?: Uint8Array } export type FcstdObjectSummary = { name: string @@ -78,6 +90,30 @@ export type FcstdShapeResourcePayload = FcstdShapeResource & { bytes: Uint8Array export type FcstdStoredShapeResource = FcstdShapeResource & { hash: string } +export type FcstdIncludedFileReference = { + objectName: string + propertyName: string +} + +export type FcstdIncludedFileResource = { + path: string + mediaType: string + byteLength: number + contentHash: string + status: 'available' +} + +export type FcstdIncludedFileResourcePayload = FcstdIncludedFileResource & { + references: FcstdIncludedFileReference[] + bytes: Uint8Array +} + +export type FcstdStoredIncludedFileResource = FcstdIncludedFileResource & { + references: FcstdIncludedFileReference[] + hash: string + value: IncludedFileValue +} + export type FcstdShapeResourceReference = { objectName: string propertyName: string @@ -225,6 +261,8 @@ const recognizedTypeIds = new Set([ 'Part::Sweep', 'Part::Fillet', 'Part::Chamfer', + 'Part::Mirroring', + 'Part::ProjectOnSurface', 'PartDesign::Body', 'PartDesign::Feature', 'PartDesign::Pad', @@ -250,7 +288,39 @@ const recognizedTypeIds = new Set([ 'PartDesign::ShapeBinder', 'PartDesign::SubShapeBinder', 'Sketcher::SketchObject', + 'Sketcher::SketchObjectSF', + 'Mesh::Import', + 'App::DocumentObjectFileIncluded', + 'App::VRMLObject', + 'Image::ImagePlane', 'Path::Feature', + 'Robot::RobotObject', + 'Robot::TrajectoryObject', + 'Robot::TrajectoryDressUpObject', + 'Measure::MeasureArea', + 'App::Part', + 'App::FeatureTest', + 'App::FeatureTestException', + 'Assembly::AssemblyLink', + 'Assembly::AssemblyObject', + 'TechDraw::DrawComplexSection', + 'TechDraw::DrawComplexSectionPython', + 'TechDraw::DrawGeomHatch', + 'TechDraw::DrawHatch', + 'TechDraw::DrawSVGTemplate', + 'TechDraw::DrawTileWeld', + 'TechDraw::DrawTileWeldPython', + 'TechDraw::DrawViewImage', + 'TechDraw::DrawViewSection', + 'TechDraw::DrawViewSectionPython', + 'TechDraw::DrawViewAnnotation', + 'TechDraw::DrawViewDraft', + 'TechDraw::DrawViewSpreadsheet', + 'Surface::GeomFillSurface', + 'App::Link', + 'App::LinkGroup', + 'App::LinkGroupPython', + 'App::LinkPython', ]) const nativeTypeIdAliases = new Map([ @@ -277,6 +347,33 @@ const colorToPacked = (value: unknown, name: string) => { return Number.parseInt(`${value.slice(1, 7)}${value.length === 9 ? value.slice(7, 9) : 'ff'}`, 16) >>> 0 } const packedToColor = (value: number) => `#${(value >>> 0).toString(16).padStart(8, '0')}` +const colorChannelRound = (value: number) => value < 0 ? -Math.round(-value) : Math.round(value) +const colorChannelsToPacked = (value: unknown, name: string) => { + if (!Array.isArray(value) || value.length !== 4 || !value.every((entry) => typeof entry === 'number' && Number.isFinite(entry))) throw new TypeError(`FCStd Color property ${name} requires four finite RGBA channels.`) + const channels = (value as number[]).map((entry) => { + const scaled = entry * 255 + if (!Number.isSafeInteger(colorChannelRound(scaled))) throw new RangeError(`FCStd Color property ${name} channel is outside the safely packable range.`) + return colorChannelRound(scaled) >>> 0 + }) + return ((channels[0] << 24) | (channels[1] << 16) | (channels[2] << 8) | channels[3]) >>> 0 +} +const colorListValue = (value: unknown, name: string): ColorListValue => { + if (!Array.isArray(value) || !value.every((color) => Array.isArray(color) && color.length === 4 && color.every((channel) => typeof channel === 'number' && Number.isFinite(channel)))) throw new TypeError(`FCStd ColorList property ${name} requires a list of four finite RGBA channels.`) + return value.map((color) => [...color] as ColorValue) +} +const colorListResourceBytes = (value: ColorListValue, name: string) => { + const bytes = new Uint8Array(4 + value.length * 4) + const view = new DataView(bytes.buffer) + view.setUint32(0, value.length, true) + value.forEach((color, index) => view.setUint32(4 + index * 4, colorChannelsToPacked(color, `${name}[${index}]`), true)) + return bytes +} +const packedToColorChannels = (value: number): [number, number, number, number] => [ + (value >>> 24) / 255, + ((value >>> 16) & 0xff) / 255, + ((value >>> 8) & 0xff) / 255, + (value & 0xff) / 255, +] const materialAppearanceBytes = (diffuseColor: unknown, transparency: unknown, name: string) => { const diffuse = colorToPacked(diffuseColor, name) const transparencyValue = transparency === undefined ? 0 : finiteComponent(transparency, `${name}.Transparency`) / 100 @@ -302,6 +399,12 @@ const finiteComponent = (value: unknown, name: string) => { if (typeof value !== 'number' || !Number.isFinite(value)) throw new TypeError(`FCStd ${name} must be finite.`) return value } +const propertyFileValue = (value: unknown, name: string) => { + if (typeof value !== 'string') throw new TypeError(`FCStd PropertyFile ${name} requires a string.`) + if (value.length > 4096) throw new RangeError(`FCStd PropertyFile ${name} reference is too long.`) + if (value && (value.includes('\0') || value.includes('\\') || value.startsWith('/') || /^[A-Za-z]:/.test(value) || /^[A-Za-z][A-Za-z0-9+.-]*:/.test(value) || value.split('/').some((segment) => segment === '.' || segment === '..' || segment.length === 0))) throw new RangeError(`FCStd PropertyFile ${name} requires a safe project-relative file reference.`) + return value +} const guiPropertyXml = (property: ObjectPropertySnapshot) => { const nativeType = property.type === 'App::PropertyFloat' && ['Deviation', 'LineWidth', 'PointSize'].includes(property.name) ? 'App::PropertyFloatConstraint' : property.type @@ -327,6 +430,39 @@ const guiPropertyXml = (property: ObjectPropertySnapshot) => { } const nativeDataPropertyNames = new Map>([ ['Path::Feature', new Set(['Path'])], + ['Robot::TrajectoryDressUpObject', new Set(['Acceleration'])], + ['Measure::MeasureArea', new Set(['Area', 'Elements'])], + ['Mesh::Import', new Set(['FileName'])], + ['App::DocumentObjectFileIncluded', new Set(['File'])], + ['App::VRMLObject', new Set(['VrmlFile'])], + ['Image::ImagePlane', new Set(['ImageFile'])], + ['Robot::RobotObject', new Set(['RobotKinematicFile', 'RobotVrmlFile'])], + ['Sketcher::SketchObjectSF', new Set(['SketchFlatFile'])], + ['TechDraw::DrawComplexSection', new Set(['PatIncluded', 'SvgIncluded'])], + ['TechDraw::DrawComplexSectionPython', new Set(['PatIncluded', 'SvgIncluded'])], + ['TechDraw::DrawGeomHatch', new Set(['PatIncluded'])], + ['TechDraw::DrawHatch', new Set(['SvgIncluded'])], + ['TechDraw::DrawSVGTemplate', new Set(['PageResult'])], + ['TechDraw::DrawTileWeld', new Set(['SymbolIncluded'])], + ['TechDraw::DrawTileWeldPython', new Set(['SymbolIncluded'])], + ['TechDraw::DrawViewImage', new Set(['ImageIncluded'])], + ['TechDraw::DrawViewSection', new Set(['PatIncluded', 'SvgIncluded'])], + ['TechDraw::DrawViewSectionPython', new Set(['PatIncluded', 'SvgIncluded'])], + ['App::FeatureTest', new Set(['BoolList', 'Colour', 'ColourList'])], + ['App::FeatureTestException', new Set(['BoolList', 'Colour', 'ColourList'])], + ['App::Part', new Set(['Color'])], + ['Assembly::AssemblyLink', new Set(['Color'])], + ['Assembly::AssemblyObject', new Set(['Color'])], + ['TechDraw::DrawViewAnnotation', new Set(['TextColor'])], + ['TechDraw::DrawViewDraft', new Set(['Color'])], + ['TechDraw::DrawViewSpreadsheet', new Set(['TextColor'])], + ['Surface::GeomFillSurface', new Set(['ReversedList'])], + ['App::Link', new Set(['VisibilityList'])], + ['App::LinkGroup', new Set(['VisibilityList'])], + ['App::LinkGroupPython', new Set(['VisibilityList'])], + ['App::LinkPython', new Set(['VisibilityList'])], + ['Part::Mirroring', new Set(['Normal'])], + ['Part::ProjectOnSurface', new Set(['Direction'])], ['Part::Box', new Set(['Length', 'Width', 'Height'])], ['Part::Cylinder', new Set(['Radius', 'Height', 'Angle'])], ['Part::Sphere', new Set(['Radius', 'Angle1', 'Angle2', 'Angle3'])], @@ -940,7 +1076,7 @@ const nativeLinkTopoRefName = (value: TopoRefValue, context: string, expectedObj return value.persistentId } -const propertyXml = (property: ObjectPropertySnapshot, native: boolean, objectId?: string, topologyElementMap?: ElementMapSnapshot) => { +const propertyXml = (property: ObjectPropertySnapshot, native: boolean, objectId?: string, topologyElementMap?: ElementMapSnapshot, colorListResource?: string) => { if (!native && property.nativeStatus !== undefined && !hasFreecadPropertyStatus(property.nativeStatus, 'PropDynamic')) throw new Error(`FCStd dynamic property ${property.name} requires PropDynamic in its native Property status mask.`) const defaultNativeStatus = property.type === 'Part::PropertyPartShape' ? 1 : property.type === 'App::PropertyPlacement' ? 8388608 : undefined const nativeStatus = property.nativeStatus === undefined ? defaultNativeStatus : normalizeFreecadPropertyStatusMask(property.nativeStatus) @@ -962,7 +1098,7 @@ const propertyXml = (property: ObjectPropertySnapshot, native: boolean, objectId const customList = native ? '' : `${property.options.map((option) => ``).join('')}` return `${customList}` } - if (property.type === 'App::PropertyVector') { + if (property.type === 'App::PropertyVector' || property.type === 'App::PropertyDirection') { if (!property.value || typeof property.value !== 'object' || Array.isArray(property.value) || !('x' in property.value)) throw new TypeError(`FCStd Vector property ${property.name} requires a vector.`) const x = finiteComponent(property.value.x, `${property.name}.x`) const y = finiteComponent(property.value.y, `${property.name}.y`) @@ -1054,15 +1190,35 @@ const propertyXml = (property: ObjectPropertySnapshot, native: boolean, objectId const values = (property.value as string[]).map((entry) => ``).join('') return `${values}` } + if (property.type === 'App::PropertyBoolList') { + if (!Array.isArray(property.value) || !property.value.every((entry) => typeof entry === 'boolean')) throw new TypeError(`FCStd BoolList property ${property.name} requires a boolean list.`) + // FreeCAD serializes dynamic_bitset low-to-high values as a reversed bit string. + const bitset = [...(property.value as boolean[])].reverse().map((entry) => entry ? '1' : '0').join('') + return `` + } + if (property.type === 'App::PropertyColorList') { + const value = colorListValue(property.value, property.name) + if (value.length === 0) return `` + if (!colorListResource) throw new Error(`FCStd ColorList property ${property.name} requires an external resource path.`) + validateEntryPath(colorListResource) + return `` + } + if (property.type === 'App::PropertyFileIncluded') { + if (property.value === null) return `` + const value = validateIncludedFileValue(property.value, `FCStd PropertyFileIncluded ${property.name}`) + return `` + } + if (property.type === 'App::PropertyColor') return `` if (property.type === 'App::PropertyString') { if (typeof property.value !== 'string') throw new TypeError(`FCStd String property ${property.name} requires a string.`) return `` } + if (property.type === 'App::PropertyFile') return `` if (property.type === 'App::PropertyBool') { if (typeof property.value !== 'boolean') throw new TypeError(`FCStd Bool property ${property.name} requires a boolean.`) return `` } - if (property.type === 'App::PropertyLength' || property.type === 'App::PropertyDistance' || property.type === 'App::PropertyAngle' || property.type === 'App::PropertyQuantityConstraint' || property.type === 'App::PropertyFloat' || property.type === 'App::PropertyFloatConstraint' || property.type === 'App::PropertyPrecision') { + if (property.type === 'App::PropertyLength' || property.type === 'App::PropertyDistance' || property.type === 'App::PropertyAngle' || property.type === 'App::PropertyAcceleration' || property.type === 'App::PropertyArea' || property.type === 'App::PropertyQuantityConstraint' || property.type === 'App::PropertyFloat' || property.type === 'App::PropertyFloatConstraint' || property.type === 'App::PropertyPrecision') { if (typeof property.value !== 'number' || !Number.isFinite(property.value)) throw new TypeError(`FCStd numeric property ${property.name} requires a finite number.`) return `` } @@ -1077,6 +1233,7 @@ const propertyXml = (property: ObjectPropertySnapshot, native: boolean, objectId 'App::PropertyLinkSub': 'LinkSub', 'App::PropertyLinkList': 'LinkList', 'App::PropertyVector': 'PropertyVector', + 'App::PropertyDirection': 'PropertyVector', 'App::PropertyPlacement': 'PropertyPlacement', 'App::PropertyMultiTransform': 'MultiTransform', } as Record)[property.type] ?? 'String' @@ -1116,6 +1273,26 @@ const pathResourceReferences = (document: DocumentSnapshot): Array<{ objectId: s return [{ objectId: object.id, path, value }] })) +const colorListResourceReferences = (document: DocumentSnapshot): Array<{ objectId: string; propertyName: string; path: string; value: ColorListValue }> => { + const used = new Set() + return document.objects.flatMap((object) => object.properties.flatMap((property) => { + if (property.scope !== 'data' || isFreecadPropertyPersistenceSuppressed(property.nativeStatus) || property.type !== 'App::PropertyColorList') return [] + const value = colorListValue(property.value, `${object.id}.${property.name}`) + if (value.length === 0) return [] + const base = property.name + let path = base + let suffix = 1 + while (used.has(path)) path = `${base}${suffix++}` + used.add(path) + return [{ objectId: object.id, propertyName: property.name, path, value }] + })) +} + +const includedFileResourceReferences = (document: DocumentSnapshot): Array<{ objectId: string; propertyName: string; value: IncludedFileValue }> => document.objects.flatMap((object) => object.properties.flatMap((property) => { + if (property.scope !== 'data' || isFreecadPropertyPersistenceSuppressed(property.nativeStatus) || property.type !== 'App::PropertyFileIncluded' || property.value === null) return [] + return [{ objectId: object.id, propertyName: property.name, value: validateIncludedFileValue(property.value, `${object.id}.${property.name}`) }] +})) + /** * Writes the metadata portion of an FCStd archive while keeping unknown files opaque. * Shape/BRep payloads and FreeCAD feature-specific serializers remain separate gates. @@ -1147,6 +1324,15 @@ export const serializeFcstdMetadataArchive = (document: DocumentSnapshot, option if (!objectIdSet.has(edge.sourceId) || !objectIdSet.has(edge.targetId)) throw new Error(`FCStd dependency ${edge.sourceId} -> ${edge.targetId} references an undeclared object.`) if (edge.relation !== 'view') dependencies.get(edge.sourceId)?.push(edge.targetId) } + const colorListResources = colorListResourceReferences(document) + const colorListResourceByProperty = new Map(colorListResources.map((resource) => [`${resource.objectId}\0${resource.propertyName}`, resource.path])) + const includedFileReferences = includedFileResourceReferences(document) + const includedFiles = new Map() + for (const reference of includedFileReferences) { + const existing = includedFiles.get(reference.value.archiveName) + if (existing && (existing.resourceHash !== reference.value.resourceHash || existing.byteLength !== reference.value.byteLength || existing.mediaType !== reference.value.mediaType)) throw new Error(`FCStd PropertyFileIncluded archive name ${reference.value.archiveName} refers to conflicting project resources.`) + includedFiles.set(reference.value.archiveName, reference.value) + } const objectDeclarations = document.objects.map((object) => { const targets = dependencies.get(object.id) ?? [] const dependencyXml = targets.length === 0 ? `` : `${targets.map((target) => ``).join('')}` @@ -1166,7 +1352,7 @@ export const serializeFcstdMetadataArchive = (document: DocumentSnapshot, option const transientMetadata = transientProperties.map((property) => `<_Property name="${xmlEscape(property.name)}" type="${xmlEscape(property.type)}" status="${normalizeFreecadPropertyStatusMask(property.nativeStatus as number)}"/>`).join('') const propertyCount = properties.length + sketchProperties.length + (expressionEngine ? 1 : 0) const transientCount = transientProperties.length + (hasShapeProperty ? 1 : 0) - return `${shapeMetadata}${transientMetadata}${properties.map((property) => propertyXml(property, isNativeDataProperty(object, property), object.id, object.topology?.elementMap)).join('')}${sketchProperties.join('')}${expressionEngine}` + return `${shapeMetadata}${transientMetadata}${properties.map((property) => propertyXml(property, isNativeDataProperty(object, property), object.id, object.topology?.elementMap, colorListResourceByProperty.get(`${object.id}\0${property.name}`))).join('')}${sketchProperties.join('')}${expressionEngine}` }).join('') const hasShapeResources = shapeResourceReferences(document).length > 0 const usesStringHasher = document.objects.some((object) => object.properties.some((property) => property.type === 'Part::PropertyPartShape' && property.value && typeof property.value === 'object' && !Array.isArray(property.value) && 'hasherIndex' in property.value && property.value.hasherIndex !== undefined)) @@ -1209,7 +1395,12 @@ export const serializeFcstdMetadataArchive = (document: DocumentSnapshot, option const mapPaths = elementMapResourceReferences(document) const pathResources = pathResourceReferences(document) const pathPaths = pathResources.map((resource) => resource.path) + const colorListPaths = colorListResources.map((resource) => resource.path) + const includedFilePaths = [...includedFiles.keys()] if (new Set(pathPaths).size !== pathPaths.length) throw new Error('FCStd Path properties must use unique resource paths.') + if (new Set(colorListPaths).size !== colorListPaths.length) throw new Error('FCStd ColorList properties must use unique resource paths.') + if (colorListPaths.some((path) => shapePaths.includes(path) || mapPaths.includes(path) || pathPaths.includes(path) || includedFilePaths.includes(path))) throw new Error('FCStd ColorList resource path collides with another native resource.') + if (includedFilePaths.some((path) => shapePaths.includes(path) || mapPaths.includes(path) || pathPaths.includes(path))) throw new Error('FCStd PropertyFileIncluded resource path collides with another native resource.') const opaqueEntries: Record = { ...(options.opaqueEntries ?? {}) } if (stringHasherTable) { if (Object.prototype.hasOwnProperty.call(opaqueEntries, 'StringHasher.Table.txt')) throw new Error('FCStd writer accepts StringHasher.Table.txt either as structured table evidence or as an opaque entry, not both.') @@ -1234,6 +1425,18 @@ export const serializeFcstdMetadataArchive = (document: DocumentSnapshot, option opaqueEntries[path] = new TextEncoder().encode(pathResourceText(resource.value.commands)) } } + for (const [path, value] of includedFiles) { + validateEntryPath(path) + const bytes = opaqueEntries[path] + if (!bytes) throw new Error(`FCStd PropertyFileIncluded references missing project resource bytes: ${path}`) + if (bytes.byteLength !== value.byteLength) throw new Error(`FCStd PropertyFileIncluded resource ${path} byte length does not match its project resource metadata.`) + if (Object.prototype.hasOwnProperty.call(generatedGuiEntries, path)) throw new Error(`FCStd PropertyFileIncluded resource collides with a generated GUI entry: ${path}`) + } + for (const resource of colorListResources) { + validateEntryPath(resource.path) + if (Object.prototype.hasOwnProperty.call(opaqueEntries, resource.path)) throw new Error(`FCStd ColorList resource collides with an opaque entry: ${resource.path}`) + if (Object.prototype.hasOwnProperty.call(generatedGuiEntries, resource.path)) throw new Error(`FCStd ColorList resource collides with a generated GUI entry: ${resource.path}`) + } if (usesStringHasher && !Object.prototype.hasOwnProperty.call(opaqueEntries, 'StringHasher.Table.txt')) throw new Error('FCStd HasherIndex requires StringHasher.Table.txt in the archive.') for (const path of Object.keys(opaqueEntries)) { validateEntryPath(path) @@ -1247,30 +1450,37 @@ export const serializeFcstdMetadataArchive = (document: DocumentSnapshot, option entries[path] = new Uint8Array(opaqueEntries[path]) emittedOpaque.add(path) } - for (const path of [...(usesStringHasher ? ['StringHasher.Table.txt'] : []), ...shapePaths, ...mapPaths, ...pathPaths]) emitOpaque(path) + for (const path of [...(usesStringHasher ? ['StringHasher.Table.txt'] : []), ...shapePaths, ...mapPaths, ...pathPaths, ...includedFilePaths]) emitOpaque(path) + for (const resource of colorListResources) entries[resource.path] = colorListResourceBytes(resource.value, `${resource.objectId}.${resource.propertyName}`) entries['GuiDocument.xml'] = new TextEncoder().encode(guiXml) if (!options.guiDocumentXml && !options.guiViews) for (const [path, bytes] of Object.entries(generatedGuiEntries)) entries[path] = bytes for (const path of Object.keys(opaqueEntries)) if (!emittedOpaque.has(path)) emitOpaque(path) return zipSync(entries, { level: 6 }) } -export const rewriteFcstdMetadataArchive = (archive: Uint8Array, document: DocumentSnapshot, options: Omit = {}): Uint8Array => { +export const rewriteFcstdMetadataArchive = (archive: Uint8Array, document: DocumentSnapshot, options: FcstdWriteOptions = {}): Uint8Array => { if (document.readOnly) { if (options.guiDocumentXml !== undefined || options.guiViews !== undefined) throw new Error('Read-only FCStd proxy archives cannot override GuiDocument metadata.') + if (Object.keys(options.opaqueEntries ?? {}).length > 0) throw new Error('Read-only FCStd proxy archives cannot override archive resources.') const proxyDocument = inspectFcstdArchive(archive).proxyDocument if (JSON.stringify(document) !== JSON.stringify(proxyDocument)) throw new Error('Read-only FCStd proxy archives cannot be modified during byte-preserving rewrite.') return new Uint8Array(archive) } const entries = inspectZipDirectory(archive, DEFAULT_FCSTD_LIMITS) const files = unzipSync(archive) + const inspection = inspectFcstdArchive(archive) + const knownColorListResources = new Set(inspection.objects.flatMap((object) => object.properties.filter((property) => property.typeId === 'App::PropertyColorList' && property.resourcePath).map((property) => property.resourcePath!))) + const knownIncludedFileResources = new Set(inspection.objects.flatMap((object) => object.properties.filter((property) => property.typeId === 'App::PropertyFileIncluded' && property.resourcePath).map((property) => property.resourcePath!))) const opaqueEntries: Record = {} for (const entry of entries) { const lower = entry.path.toLowerCase() if (lower === 'document.xml' || lower === 'guidocument.xml') continue + if (knownColorListResources.has(entry.path) || knownIncludedFileResources.has(entry.path)) continue const bytes = files[entry.path] if (!bytes) throw new Error(`FCStd entry ${entry.path} is missing after decompression.`) opaqueEntries[entry.path] = new Uint8Array(bytes) } + for (const [path, payload] of Object.entries(options.opaqueEntries ?? {})) opaqueEntries[path] = new Uint8Array(payload) const guiDocumentXml = options.guiDocumentXml ?? (files['GuiDocument.xml'] ? new TextDecoder('utf-8', { fatal: true }).decode(files['GuiDocument.xml']) : undefined) if (options.stringHasherTable) delete opaqueEntries['StringHasher.Table.txt'] return serializeFcstdMetadataArchive(document, { guiDocumentXml, opaqueEntries, stringHasherTable: options.stringHasherTable }) @@ -1419,12 +1629,27 @@ const parsedShapeResource = (element: string, elementValue: unknown, property?: } const structuredPropertyValue = (element: string, elementValue: unknown, property?: Record): string | undefined => { + if (element === 'ColorList' && elementValue && typeof elementValue === 'object') { + const resourcePath = attribute(elementValue, 'file') + if (!resourcePath) return JSON.stringify([]) + validateEntryPath(resourcePath) + return JSON.stringify({ resourcePath }) + } + if (element === 'FileIncluded' && elementValue && typeof elementValue === 'object') { + const resourcePath = attribute(elementValue, 'file') + const inlineData = attribute(elementValue, 'data') + if (inlineData) throw new Error('FCStd force-XML inline FileIncluded payloads are not supported by the archive codec.') + if (!resourcePath) return JSON.stringify(null) + validateIncludedFileArchiveName(resourcePath, 'FCStd PropertyFileIncluded') + return JSON.stringify({ resourcePath }) + } if (element === 'PropertyVector') return JSON.stringify({ x: finiteAttribute(elementValue, 'valueX', element), y: finiteAttribute(elementValue, 'valueY', element), z: finiteAttribute(elementValue, 'valueZ', element), }) if (element === 'FloatList' && elementValue && typeof elementValue === 'object') { + if (attribute(elementValue, 'file')) return undefined const values = asArray((elementValue as Record).Float as Record | Record[] | undefined).map((entry) => finiteAttribute(entry, 'value', element)) const countText = attribute(elementValue, 'count') if (!/^\d+$/.test(countText) || Number(countText) !== values.length) throw new Error(`FCStd FloatList count does not match its child elements.`) @@ -1447,6 +1672,11 @@ const structuredPropertyValue = (element: string, elementValue: unknown, propert if (!/^\d+$/.test(countText) || Number(countText) !== values.length) throw new Error(`FCStd StringList count does not match its child elements.`) return JSON.stringify(values) } + if (element === 'BoolList' && elementValue && typeof elementValue === 'object') { + const encoded = attribute(elementValue, 'value') + if (!/^[01]*$/.test(encoded)) throw new Error('FCStd BoolList value must contain only 0 and 1 bits.') + return JSON.stringify([...encoded].reverse().map((entry) => entry === '1')) + } if (element === 'GeometryList' && elementValue && typeof elementValue === 'object') { const records = asArray((elementValue as Record).Geometry as Record | Record[] | undefined).map((geometry, index) => { const type = attribute(geometry, 'type') @@ -1541,6 +1771,7 @@ const structuredPropertyValue = (element: string, elementValue: unknown, propert return JSON.stringify(records) } if (element === 'Path' && elementValue && typeof elementValue === 'object') { + if (attribute(property, 'type') !== 'Path::PropertyPath') return undefined const resourcePath = attribute(elementValue, 'file') if (!resourcePath.trim()) throw new Error('FCStd Path property resource path is missing.') validateEntryPath(resourcePath) @@ -1614,6 +1845,7 @@ const propertySummaries = (properties: Record[]): FcstdProperty if (!/^\d+$/.test(countText) || Number(countText) !== enumOptions?.length) throw new Error('FCStd CustomEnumList count does not match its Enum children.') } const shapeResource = parsedShapeResource(element, elementValue, property) + const resourcePath = (element === 'ColorList' || element === 'FileIncluded') && elementValue && typeof elementValue === 'object' ? attribute(elementValue, 'file') : undefined if ((subElements || links || linkSubs) && elementValue && typeof elementValue === 'object') { const countText = attribute(elementValue, 'count') const count = Number(countText) @@ -1630,7 +1862,7 @@ const propertySummaries = (properties: Record[]): FcstdProperty nativeStatus = decoded.mask statusNames = decoded.names } - return { name: attribute(property, 'name') || '', typeId: attribute(property, 'type') || element || 'unknown', element, value, ...(nativeStatus === undefined ? {} : { nativeStatus, statusNames }), ...(subElements ? { subElements } : {}), ...(links ? { links } : {}), ...(linkSubs ? { linkSubs } : {}), ...(enumOptions ? { enumOptions } : {}), ...(shapeResource ? { shapeResource } : {}), ...(expression ? { expression } : {}) } + return { name: attribute(property, 'name') || '', typeId: attribute(property, 'type') || element || 'unknown', element, value, ...(nativeStatus === undefined ? {} : { nativeStatus, statusNames }), ...(subElements ? { subElements } : {}), ...(links ? { links } : {}), ...(linkSubs ? { linkSubs } : {}), ...(enumOptions ? { enumOptions } : {}), ...(resourcePath === undefined ? {} : { resourcePath }), ...(shapeResource ? { shapeResource } : {}), ...(expression ? { expression } : {}) } }) const sketchFromPropertySummaries = (objectId: string, summaries: FcstdPropertySummary[]): SketchSnapshot | undefined => { @@ -1893,7 +2125,7 @@ const sketchFromPropertySummaries = (objectId: string, summaries: FcstdPropertyS } export const decodeFcstdPropertyValue = (property: FcstdPropertySummary): FcstdDecodedPropertyValue => { - const numericTypes = new Set(['App::PropertyLength', 'App::PropertyDistance', 'App::PropertyAngle', 'App::PropertyQuantityConstraint', 'App::PropertyFloat', 'App::PropertyFloatConstraint', 'App::PropertyPrecision', 'App::PropertyInteger', 'App::PropertyIntegerConstraint', 'App::PropertyPercent']) + const numericTypes = new Set(['App::PropertyLength', 'App::PropertyDistance', 'App::PropertyAngle', 'App::PropertyAcceleration', 'App::PropertyArea', 'App::PropertyQuantityConstraint', 'App::PropertyFloat', 'App::PropertyFloatConstraint', 'App::PropertyPrecision', 'App::PropertyInteger', 'App::PropertyIntegerConstraint', 'App::PropertyPercent']) if (numericTypes.has(property.typeId)) { const value = Number(property.value) return Number.isFinite(value) ? { value, decoded: true } : { value: property.value, decoded: false, error: `Property ${property.name} is not a finite number.` } @@ -1911,6 +2143,35 @@ export const decodeFcstdPropertyValue = (property: FcstdPropertySummary): FcstdD if (property.value === 'true' || property.value === 'false') return { value: property.value === 'true', decoded: true } return { value: property.value, decoded: false, error: `Property ${property.name} is not a boolean.` } } + if (property.typeId === 'App::PropertyColor') { + if (property.element !== 'PropertyColor' || !/^\d+$/.test(property.value)) return { value: property.value, decoded: false, error: `Property ${property.name} is not a packed RGBA color.` } + const packed = Number(property.value) + if (!Number.isSafeInteger(packed) || packed < 0 || packed > 0xffffffff) return { value: property.value, decoded: false, error: `Property ${property.name} packed RGBA value is outside uint32.` } + return { value: packedToColorChannels(packed), decoded: true } + } + if (property.typeId === 'App::PropertyColorList') { + if (property.element !== 'ColorList') return { value: property.value, decoded: false, error: `Property ${property.name} is not a native ColorList payload.` } + try { + const value = JSON.parse(property.value) as unknown + if (!Array.isArray(value) || !value.every((color) => Array.isArray(color) && color.length === 4 && color.every((channel) => typeof channel === 'number' && Number.isFinite(channel)))) throw new Error('value is not a list of four finite RGBA channels') + return { value, decoded: true } + } catch (error) { + return { value: property.value, decoded: false, error: `Property ${property.name} contains invalid ColorList data: ${error instanceof Error ? error.message : String(error)}` } + } + } + if (property.typeId === 'App::PropertyFile') { + if (property.element !== 'String') return { value: property.value, decoded: false, error: `Property ${property.name} is not a native String payload.` } + try { + return { value: propertyFileValue(property.value, property.name), decoded: true } + } catch (error) { + return { value: property.value, decoded: false, error: error instanceof Error ? error.message : String(error) } + } + } + if (property.typeId === 'App::PropertyFileIncluded') { + if (property.element !== 'FileIncluded') return { value: property.value, decoded: false, error: `Property ${property.name} is not a native FileIncluded payload.` } + if (!property.resourcePath) return { value: null, decoded: true } + return { value: property.includedFileResource ?? property.value, decoded: false, error: `Property ${property.name} bytes must be stored through project.fcstd.storeIncludedFiles before the value becomes editable.` } + } if (property.typeId === 'App::PropertyLinkSub' && property.subElements) return { value: { schemaVersion: 1, objectId: property.value, subElements: [...property.subElements] }, decoded: true, @@ -1927,7 +2188,8 @@ export const decodeFcstdPropertyValue = (property: FcstdPropertySummary): FcstdD return { value: property.value, decoded: false, error: `Property ${property.name} contains invalid Path data: ${error instanceof Error ? error.message : String(error)}` } } } - if (property.typeId === 'App::PropertyLinkSub' || property.typeId === 'App::PropertyLinkSubList' || property.typeId === 'App::PropertyLinkList' || property.typeId === 'App::PropertyFloatList' || property.typeId === 'App::PropertyIntegerList' || property.typeId === 'App::PropertyStringList' || property.typeId === 'App::PropertyVector' || property.typeId === 'App::PropertyPlacement' || property.typeId === 'App::PropertyMultiTransform' || property.typeId === 'Part::PropertyGeometryList' || property.typeId === 'Sketcher::PropertyConstraintList') { + if (property.typeId === 'App::PropertyDirection' && property.element !== 'PropertyVector') return { value: property.value, decoded: false, error: `Property ${property.name} is not a native PropertyVector payload.` } + if (property.typeId === 'App::PropertyLinkSub' || property.typeId === 'App::PropertyLinkSubList' || property.typeId === 'App::PropertyLinkList' || property.typeId === 'App::PropertyBoolList' || property.typeId === 'App::PropertyFloatList' || property.typeId === 'App::PropertyIntegerList' || property.typeId === 'App::PropertyStringList' || property.typeId === 'App::PropertyVector' || property.typeId === 'App::PropertyDirection' || property.typeId === 'App::PropertyPlacement' || property.typeId === 'App::PropertyMultiTransform' || property.typeId === 'Part::PropertyGeometryList' || property.typeId === 'Sketcher::PropertyConstraintList') { try { return { value: JSON.parse(property.value), decoded: true } } catch (error) { return { value: property.value, decoded: false, error: `Property ${property.name} contains invalid JSON: ${error instanceof Error ? error.message : String(error)}` } } } return { value: property.value, decoded: true } @@ -1973,6 +2235,408 @@ export const rewriteFcstdPathProperty = (bytes: Uint8Array, edit: FcstdPathEdit) return new Uint8Array(zipSync(output, { level: 6 })) } +/** Rewrites one locked native Float property while preserving every other archive entry. */ +export const rewriteFcstdNumericProperty = (bytes: Uint8Array, edit: FcstdNumericPropertyEdit): Uint8Array => { + if (!edit.objectName.trim() || !edit.propertyName.trim()) throw new TypeError('FCStd numeric property rewrite requires non-empty object and property names.') + if (!Number.isFinite(edit.value)) throw new TypeError(`FCStd numeric property ${edit.objectName}.${edit.propertyName} requires a finite value.`) + if (edit.expectedValue !== undefined && !Number.isFinite(edit.expectedValue)) throw new TypeError('FCStd numeric property expectedValue must be finite.') + + const inspection = inspectFcstdArchive(bytes) + const object = inspection.objects.find((candidate) => candidate.name === edit.objectName) + if (!object) throw new Error(`FCStd numeric property object does not exist: ${edit.objectName}`) + const summary = object.properties.find((candidate) => candidate.name === edit.propertyName) + if (!summary) throw new Error(`FCStd numeric property does not exist: ${edit.objectName}.${edit.propertyName}`) + if (summary.typeId !== edit.typeId || summary.element !== 'Float') throw new TypeError(`FCStd numeric property ${edit.objectName}.${edit.propertyName} must be ${edit.typeId} with a Float payload.`) + const decoded = decodeFcstdPropertyValue(summary) + if (!decoded.decoded || typeof decoded.value !== 'number' || !Number.isFinite(decoded.value)) throw new TypeError(`FCStd numeric property ${edit.objectName}.${edit.propertyName} is not decodable.`) + if (edit.expectedValue !== undefined && !Object.is(decoded.value, edit.expectedValue)) throw new RangeError(`FCStd numeric property ${edit.objectName}.${edit.propertyName} expected ${edit.expectedValue}, found ${decoded.value}.`) + + const entries = inspectZipDirectory(bytes, DEFAULT_FCSTD_LIMITS) + const files = unzipSync(bytes) + const documentPath = entries.find((entry) => entry.path.toLowerCase() === 'document.xml')?.path + if (!documentPath || !files[documentPath]) throw new Error('FCStd archive does not contain Document.xml.') + const parsed = parseXmlRoot(files[documentPath], documentPath, 'Document', DEFAULT_FCSTD_LIMITS) + const objectDeclarations = asArray((((parsed.root.Objects as Record | undefined)?.Object) as Record | Record[] | undefined)) + const declaration = objectDeclarations.find((candidate) => attribute(candidate, 'name') === edit.objectName) + if (!declaration) throw new Error(`FCStd numeric property object declaration does not exist: ${edit.objectName}`) + declaration['@_Touched'] = '1' + const objectData = asArray((((parsed.root.ObjectData as Record | undefined)?.Object) as Record | Record[] | undefined)) + const data = objectData.find((candidate) => attribute(candidate, 'name') === edit.objectName) + const properties = asArray(((((data?.Properties as Record | undefined)?.Property)) as Record | Record[] | undefined)) + const property = properties.find((candidate) => attribute(candidate, 'name') === edit.propertyName && attribute(candidate, 'type') === edit.typeId) + if (!property || !property.Float || typeof property.Float !== 'object' || Array.isArray(property.Float)) throw new TypeError(`FCStd numeric property ${edit.objectName}.${edit.propertyName} has no unique Float payload.`) + ;(property.Float as Record)['@_value'] = String(edit.value) + const documentXml = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', format: false, processEntities: false, suppressBooleanAttributes: false, suppressEmptyNode: true }).build({ Document: parsed.root }) + files[documentPath] = new TextEncoder().encode(documentXml) + const output: Record = {} + for (const entry of entries) output[entry.path] = new Uint8Array(files[entry.path]) + const rewritten = new Uint8Array(zipSync(output, { level: 6 })) + const rewrittenSummary = inspectFcstdArchive(rewritten).objects.find((candidate) => candidate.name === edit.objectName)?.properties.find((candidate) => candidate.name === edit.propertyName) + const rewrittenValue = rewrittenSummary ? decodeFcstdPropertyValue(rewrittenSummary) : undefined + if (!rewrittenValue?.decoded || rewrittenValue.value !== edit.value) throw new Error(`FCStd numeric property ${edit.objectName}.${edit.propertyName} did not rewrite exactly.`) + return rewritten +} + +/** Rewrites one native App::PropertyBoolList bitset while preserving every other archive entry. */ +export const rewriteFcstdBoolListProperty = (bytes: Uint8Array, edit: FcstdBoolListEdit): Uint8Array => { + if (!edit.objectName.trim() || !edit.propertyName.trim()) throw new TypeError('FCStd BoolList rewrite requires non-empty object and property names.') + const validateValue = (value: boolean[], context: string) => { + if (!Array.isArray(value) || !value.every((entry) => typeof entry === 'boolean')) throw new TypeError(`FCStd BoolList ${context} requires a boolean list.`) + } + const equal = (left: boolean[], right: boolean[]) => left.length === right.length && left.every((entry, index) => entry === right[index]) + const encoded = (value: boolean[]) => [...value].reverse().map((entry) => entry ? '1' : '0').join('') + validateValue(edit.value, 'value') + if (edit.expectedValue !== undefined) validateValue(edit.expectedValue, 'expectedValue') + + const inspection = inspectFcstdArchive(bytes) + const object = inspection.objects.find((candidate) => candidate.name === edit.objectName) + if (!object) throw new Error(`FCStd BoolList object does not exist: ${edit.objectName}`) + const summary = object.properties.find((candidate) => candidate.name === edit.propertyName) + if (!summary) throw new Error(`FCStd BoolList property does not exist: ${edit.objectName}.${edit.propertyName}`) + if (summary.typeId !== 'App::PropertyBoolList' || summary.element !== 'BoolList') throw new TypeError(`FCStd property ${edit.objectName}.${edit.propertyName} must be App::PropertyBoolList with a BoolList payload.`) + const decoded = decodeFcstdPropertyValue(summary) + if (!decoded.decoded || !Array.isArray(decoded.value) || !decoded.value.every((entry) => typeof entry === 'boolean')) throw new TypeError(`FCStd BoolList ${edit.objectName}.${edit.propertyName} is not decodable.`) + if (edit.expectedValue !== undefined && !equal(decoded.value as boolean[], edit.expectedValue)) throw new RangeError(`FCStd BoolList ${edit.objectName}.${edit.propertyName} does not match expectedValue.`) + + const entries = inspectZipDirectory(bytes, DEFAULT_FCSTD_LIMITS) + const files = unzipSync(bytes) + const documentPath = entries.find((entry) => entry.path.toLowerCase() === 'document.xml')?.path + if (!documentPath || !files[documentPath]) throw new Error('FCStd archive does not contain Document.xml.') + const parsed = parseXmlRoot(files[documentPath], documentPath, 'Document', DEFAULT_FCSTD_LIMITS) + const objectDeclarations = asArray((((parsed.root.Objects as Record | undefined)?.Object) as Record | Record[] | undefined)) + const declarations = objectDeclarations.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (declarations.length !== 1) throw new Error(`FCStd BoolList object declaration is not unique: ${edit.objectName}`) + declarations[0]['@_Touched'] = '1' + const objectData = asArray((((parsed.root.ObjectData as Record | undefined)?.Object) as Record | Record[] | undefined)) + const data = objectData.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (data.length !== 1) throw new Error(`FCStd BoolList object data is not unique: ${edit.objectName}`) + const properties = asArray(((((data[0].Properties as Record | undefined)?.Property)) as Record | Record[] | undefined)) + const candidates = properties.filter((candidate) => attribute(candidate, 'name') === edit.propertyName && attribute(candidate, 'type') === 'App::PropertyBoolList') + if (candidates.length !== 1 || !candidates[0].BoolList || typeof candidates[0].BoolList !== 'object' || Array.isArray(candidates[0].BoolList)) throw new TypeError(`FCStd BoolList ${edit.objectName}.${edit.propertyName} has no unique BoolList payload.`) + ;(candidates[0].BoolList as Record)['@_value'] = encoded(edit.value) + const documentXml = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', format: false, processEntities: false, suppressBooleanAttributes: false, suppressEmptyNode: true }).build({ Document: parsed.root }) + files[documentPath] = new TextEncoder().encode(documentXml) + const output: Record = {} + for (const entry of entries) output[entry.path] = new Uint8Array(files[entry.path]) + const rewritten = new Uint8Array(zipSync(output, { level: 6 })) + const rewrittenSummary = inspectFcstdArchive(rewritten).objects.find((candidate) => candidate.name === edit.objectName)?.properties.find((candidate) => candidate.name === edit.propertyName) + const rewrittenValue = rewrittenSummary ? decodeFcstdPropertyValue(rewrittenSummary) : undefined + if (!rewrittenValue?.decoded || !Array.isArray(rewrittenValue.value) || !equal(rewrittenValue.value as boolean[], edit.value)) throw new Error(`FCStd BoolList ${edit.objectName}.${edit.propertyName} did not rewrite exactly.`) + return rewritten +} + +/** Rewrites one native App::PropertyColor packed RGBA value while preserving every other archive entry. */ +export const rewriteFcstdColorProperty = (bytes: Uint8Array, edit: FcstdColorEdit): Uint8Array => { + if (!edit.objectName.trim() || !edit.propertyName.trim()) throw new TypeError('FCStd PropertyColor rewrite requires non-empty object and property names.') + const validateValue = (value: ColorValue, context: string) => { + if (!Array.isArray(value) || value.length !== 4 || !value.every((channel) => typeof channel === 'number' && Number.isFinite(channel))) throw new TypeError(`FCStd PropertyColor ${context} requires four finite RGBA channels.`) + } + const equal = (left: ColorValue, right: ColorValue) => left.every((channel, index) => Object.is(channel, right[index])) + validateValue(edit.value, 'value') + if (edit.expectedValue !== undefined) validateValue(edit.expectedValue, 'expectedValue') + + const inspection = inspectFcstdArchive(bytes) + const object = inspection.objects.find((candidate) => candidate.name === edit.objectName) + if (!object) throw new Error(`FCStd PropertyColor object does not exist: ${edit.objectName}`) + const summary = object.properties.find((candidate) => candidate.name === edit.propertyName) + if (!summary) throw new Error(`FCStd PropertyColor property does not exist: ${edit.objectName}.${edit.propertyName}`) + if (summary.typeId !== 'App::PropertyColor' || summary.element !== 'PropertyColor') throw new TypeError(`FCStd property ${edit.objectName}.${edit.propertyName} must be App::PropertyColor with a PropertyColor payload.`) + const decoded = decodeFcstdPropertyValue(summary) + if (!decoded.decoded || !Array.isArray(decoded.value) || decoded.value.length !== 4 || !decoded.value.every((channel) => typeof channel === 'number' && Number.isFinite(channel))) throw new TypeError(`FCStd PropertyColor ${edit.objectName}.${edit.propertyName} is not decodable.`) + if (edit.expectedValue !== undefined && !equal(decoded.value as ColorValue, edit.expectedValue)) throw new RangeError(`FCStd PropertyColor ${edit.objectName}.${edit.propertyName} does not match expectedValue.`) + + const packed = colorChannelsToPacked(edit.value, `${edit.objectName}.${edit.propertyName}`) + const nativeValue = packedToColorChannels(packed) + const entries = inspectZipDirectory(bytes, DEFAULT_FCSTD_LIMITS) + const files = unzipSync(bytes) + const documentPath = entries.find((entry) => entry.path.toLowerCase() === 'document.xml')?.path + if (!documentPath || !files[documentPath]) throw new Error('FCStd archive does not contain Document.xml.') + const parsed = parseXmlRoot(files[documentPath], documentPath, 'Document', DEFAULT_FCSTD_LIMITS) + const objectDeclarations = asArray((((parsed.root.Objects as Record | undefined)?.Object) as Record | Record[] | undefined)) + const declarations = objectDeclarations.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (declarations.length !== 1) throw new Error(`FCStd PropertyColor object declaration is not unique: ${edit.objectName}`) + declarations[0]['@_Touched'] = '1' + const objectData = asArray((((parsed.root.ObjectData as Record | undefined)?.Object) as Record | Record[] | undefined)) + const data = objectData.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (data.length !== 1) throw new Error(`FCStd PropertyColor object data is not unique: ${edit.objectName}`) + const properties = asArray(((((data[0].Properties as Record | undefined)?.Property)) as Record | Record[] | undefined)) + const candidates = properties.filter((candidate) => attribute(candidate, 'name') === edit.propertyName && attribute(candidate, 'type') === 'App::PropertyColor') + if (candidates.length !== 1 || !candidates[0].PropertyColor || typeof candidates[0].PropertyColor !== 'object' || Array.isArray(candidates[0].PropertyColor)) throw new TypeError(`FCStd PropertyColor ${edit.objectName}.${edit.propertyName} has no unique PropertyColor payload.`) + ;(candidates[0].PropertyColor as Record)['@_value'] = String(packed) + const documentXml = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', format: false, processEntities: false, suppressBooleanAttributes: false, suppressEmptyNode: true }).build({ Document: parsed.root }) + files[documentPath] = new TextEncoder().encode(documentXml) + const output: Record = {} + for (const entry of entries) output[entry.path] = new Uint8Array(files[entry.path]) + const rewritten = new Uint8Array(zipSync(output, { level: 6 })) + const rewrittenSummary = inspectFcstdArchive(rewritten).objects.find((candidate) => candidate.name === edit.objectName)?.properties.find((candidate) => candidate.name === edit.propertyName) + const rewrittenValue = rewrittenSummary ? decodeFcstdPropertyValue(rewrittenSummary) : undefined + if (!rewrittenValue?.decoded || !Array.isArray(rewrittenValue.value) || !equal(rewrittenValue.value as ColorValue, nativeValue)) throw new Error(`FCStd PropertyColor ${edit.objectName}.${edit.propertyName} did not rewrite exactly.`) + return rewritten +} + +/** Rewrites one native App::PropertyColorList external resource while preserving every other archive entry. */ +export const rewriteFcstdColorListProperty = (bytes: Uint8Array, edit: FcstdColorListEdit): Uint8Array => { + if (!edit.objectName.trim() || !edit.propertyName.trim()) throw new TypeError('FCStd ColorList rewrite requires non-empty object and property names.') + const validateValue = (value: ColorListValue, context: string) => { + if (!Array.isArray(value) || !value.every((color) => Array.isArray(color) && color.length === 4 && color.every((channel) => typeof channel === 'number' && Number.isFinite(channel)))) throw new TypeError(`FCStd ColorList ${context} requires a list of four finite RGBA channels.`) + } + const equal = (left: ColorListValue, right: ColorListValue) => left.length === right.length && left.every((color, index) => color.every((channel, channelIndex) => Object.is(channel, right[index]?.[channelIndex]))) + validateValue(edit.value, 'value') + if (edit.expectedValue !== undefined) validateValue(edit.expectedValue, 'expectedValue') + const nativeValue = edit.value.map((color, index) => packedToColorChannels(colorChannelsToPacked(color, `${edit.objectName}.${edit.propertyName}[${index}]`))) + + const inspection = inspectFcstdArchive(bytes) + const object = inspection.objects.find((candidate) => candidate.name === edit.objectName) + if (!object) throw new Error(`FCStd ColorList object does not exist: ${edit.objectName}`) + const summary = object.properties.find((candidate) => candidate.name === edit.propertyName) + if (!summary) throw new Error(`FCStd ColorList property does not exist: ${edit.objectName}.${edit.propertyName}`) + if (summary.typeId !== 'App::PropertyColorList' || summary.element !== 'ColorList') throw new TypeError(`FCStd property ${edit.objectName}.${edit.propertyName} must be App::PropertyColorList with a ColorList payload.`) + const decoded = decodeFcstdPropertyValue(summary) + if (!decoded.decoded || !Array.isArray(decoded.value)) throw new TypeError(`FCStd ColorList ${edit.objectName}.${edit.propertyName} is not decodable.`) + const current = decoded.value as ColorListValue + if (edit.expectedValue !== undefined && !equal(current, edit.expectedValue)) throw new RangeError(`FCStd ColorList ${edit.objectName}.${edit.propertyName} does not match expectedValue.`) + const resourcePath = summary.resourcePath + if (!resourcePath) throw new Error(`FCStd ColorList ${edit.objectName}.${edit.propertyName} has no external resource to rewrite.`) + + const entries = inspectZipDirectory(bytes, DEFAULT_FCSTD_LIMITS) + const files = unzipSync(bytes) + if (!files[resourcePath]) throw new Error(`FCStd ColorList resource is missing: ${resourcePath}`) + const documentPath = entries.find((entry) => entry.path.toLowerCase() === 'document.xml')?.path + if (!documentPath || !files[documentPath]) throw new Error('FCStd archive does not contain Document.xml.') + const parsed = parseXmlRoot(files[documentPath], documentPath, 'Document', DEFAULT_FCSTD_LIMITS) + const objectDeclarations = asArray((((parsed.root.Objects as Record | undefined)?.Object) as Record | Record[] | undefined)) + const declarations = objectDeclarations.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (declarations.length !== 1) throw new Error(`FCStd ColorList object declaration is not unique: ${edit.objectName}`) + declarations[0]['@_Touched'] = '1' + const objectData = asArray((((parsed.root.ObjectData as Record | undefined)?.Object) as Record | Record[] | undefined)) + const data = objectData.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (data.length !== 1) throw new Error(`FCStd ColorList object data is not unique: ${edit.objectName}`) + const properties = asArray(((((data[0].Properties as Record | undefined)?.Property)) as Record | Record[] | undefined)) + const candidates = properties.filter((candidate) => attribute(candidate, 'name') === edit.propertyName && attribute(candidate, 'type') === 'App::PropertyColorList') + if (candidates.length !== 1 || !candidates[0].ColorList || typeof candidates[0].ColorList !== 'object' || Array.isArray(candidates[0].ColorList) || attribute(candidates[0].ColorList as Record, 'file') !== resourcePath) throw new TypeError(`FCStd ColorList ${edit.objectName}.${edit.propertyName} has no unique matching ColorList payload.`) + files[resourcePath] = colorListResourceBytes(edit.value, `${edit.objectName}.${edit.propertyName}`) + files[documentPath] = new TextEncoder().encode(new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', format: false, processEntities: false, suppressBooleanAttributes: false, suppressEmptyNode: true }).build({ Document: parsed.root })) + const output: Record = {} + for (const entry of entries) output[entry.path] = new Uint8Array(files[entry.path]) + const rewritten = new Uint8Array(zipSync(output, { level: 6 })) + const rewrittenSummary = inspectFcstdArchive(rewritten).objects.find((candidate) => candidate.name === edit.objectName)?.properties.find((candidate) => candidate.name === edit.propertyName) + const rewrittenValue = rewrittenSummary ? decodeFcstdPropertyValue(rewrittenSummary) : undefined + if (!rewrittenValue?.decoded || !Array.isArray(rewrittenValue.value) || !equal(rewrittenValue.value as ColorListValue, nativeValue)) throw new Error(`FCStd ColorList ${edit.objectName}.${edit.propertyName} did not rewrite exactly.`) + return rewritten +} + +/** Rewrites one native App::PropertyDirection PropertyVector payload while preserving every other archive entry. */ +export const rewriteFcstdDirectionProperty = (bytes: Uint8Array, edit: FcstdDirectionEdit): Uint8Array => { + if (!edit.objectName.trim() || !edit.propertyName.trim()) throw new TypeError('FCStd PropertyDirection rewrite requires non-empty object and property names.') + const validateValue = (value: VectorValue, context: string) => { + if (!value || typeof value !== 'object' || Array.isArray(value)) throw new TypeError(`FCStd PropertyDirection ${context} requires a vector.`) + for (const axis of ['x', 'y', 'z'] as const) if (typeof value[axis] !== 'number' || !Number.isFinite(value[axis])) throw new TypeError(`FCStd PropertyDirection ${context}.${axis} must be finite.`) + } + const equal = (left: VectorValue, right: VectorValue) => (['x', 'y', 'z'] as const).every((axis) => Object.is(left[axis], right[axis])) + validateValue(edit.value, 'value') + if (edit.expectedValue !== undefined) validateValue(edit.expectedValue, 'expectedValue') + + const inspection = inspectFcstdArchive(bytes) + const object = inspection.objects.find((candidate) => candidate.name === edit.objectName) + if (!object) throw new Error(`FCStd PropertyDirection object does not exist: ${edit.objectName}`) + const summary = object.properties.find((candidate) => candidate.name === edit.propertyName) + if (!summary) throw new Error(`FCStd PropertyDirection property does not exist: ${edit.objectName}.${edit.propertyName}`) + if (summary.typeId !== 'App::PropertyDirection' || summary.element !== 'PropertyVector') throw new TypeError(`FCStd property ${edit.objectName}.${edit.propertyName} must be App::PropertyDirection with a PropertyVector payload.`) + const decoded = decodeFcstdPropertyValue(summary) + if (!decoded.decoded || !decoded.value || typeof decoded.value !== 'object' || Array.isArray(decoded.value)) throw new TypeError(`FCStd PropertyDirection ${edit.objectName}.${edit.propertyName} is not decodable.`) + validateValue(decoded.value as VectorValue, `${edit.objectName}.${edit.propertyName}`) + if (edit.expectedValue !== undefined && !equal(decoded.value as VectorValue, edit.expectedValue)) throw new RangeError(`FCStd PropertyDirection ${edit.objectName}.${edit.propertyName} does not match expectedValue.`) + + const entries = inspectZipDirectory(bytes, DEFAULT_FCSTD_LIMITS) + const files = unzipSync(bytes) + const documentPath = entries.find((entry) => entry.path.toLowerCase() === 'document.xml')?.path + if (!documentPath || !files[documentPath]) throw new Error('FCStd archive does not contain Document.xml.') + const parsed = parseXmlRoot(files[documentPath], documentPath, 'Document', DEFAULT_FCSTD_LIMITS) + const objectDeclarations = asArray((((parsed.root.Objects as Record | undefined)?.Object) as Record | Record[] | undefined)) + const declarations = objectDeclarations.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (declarations.length !== 1) throw new Error(`FCStd PropertyDirection object declaration is not unique: ${edit.objectName}`) + declarations[0]['@_Touched'] = '1' + const objectData = asArray((((parsed.root.ObjectData as Record | undefined)?.Object) as Record | Record[] | undefined)) + const data = objectData.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (data.length !== 1) throw new Error(`FCStd PropertyDirection object data is not unique: ${edit.objectName}`) + const properties = asArray(((((data[0].Properties as Record | undefined)?.Property)) as Record | Record[] | undefined)) + const candidates = properties.filter((candidate) => attribute(candidate, 'name') === edit.propertyName && attribute(candidate, 'type') === 'App::PropertyDirection') + if (candidates.length !== 1 || !candidates[0].PropertyVector || typeof candidates[0].PropertyVector !== 'object' || Array.isArray(candidates[0].PropertyVector)) throw new TypeError(`FCStd PropertyDirection ${edit.objectName}.${edit.propertyName} has no unique PropertyVector payload.`) + const payload = candidates[0].PropertyVector as Record + payload['@_valueX'] = String(edit.value.x) + payload['@_valueY'] = String(edit.value.y) + payload['@_valueZ'] = String(edit.value.z) + const documentXml = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', format: false, processEntities: false, suppressBooleanAttributes: false, suppressEmptyNode: true }).build({ Document: parsed.root }) + files[documentPath] = new TextEncoder().encode(documentXml) + const output: Record = {} + for (const entry of entries) output[entry.path] = new Uint8Array(files[entry.path]) + const rewritten = new Uint8Array(zipSync(output, { level: 6 })) + const rewrittenSummary = inspectFcstdArchive(rewritten).objects.find((candidate) => candidate.name === edit.objectName)?.properties.find((candidate) => candidate.name === edit.propertyName) + const rewrittenValue = rewrittenSummary ? decodeFcstdPropertyValue(rewrittenSummary) : undefined + if (!rewrittenValue?.decoded || !rewrittenValue.value || typeof rewrittenValue.value !== 'object' || Array.isArray(rewrittenValue.value) || !equal(rewrittenValue.value as VectorValue, edit.value)) throw new Error(`FCStd PropertyDirection ${edit.objectName}.${edit.propertyName} did not rewrite exactly.`) + return rewritten +} + +/** Rewrites one native App::PropertyFile String payload without exposing host filesystem paths. */ +export const rewriteFcstdFileProperty = (bytes: Uint8Array, edit: FcstdFileEdit): Uint8Array => { + if (!edit.objectName.trim() || !edit.propertyName.trim()) throw new TypeError('FCStd PropertyFile rewrite requires non-empty object and property names.') + const value = propertyFileValue(edit.value, `${edit.objectName}.${edit.propertyName}`) + const expectedValue = edit.expectedValue === undefined ? undefined : propertyFileValue(edit.expectedValue, `${edit.objectName}.${edit.propertyName}.expectedValue`) + + const inspection = inspectFcstdArchive(bytes) + const object = inspection.objects.find((candidate) => candidate.name === edit.objectName) + if (!object) throw new Error(`FCStd PropertyFile object does not exist: ${edit.objectName}`) + const summary = object.properties.find((candidate) => candidate.name === edit.propertyName) + if (!summary) throw new Error(`FCStd PropertyFile property does not exist: ${edit.objectName}.${edit.propertyName}`) + if (summary.typeId !== 'App::PropertyFile' || summary.element !== 'String') throw new TypeError(`FCStd property ${edit.objectName}.${edit.propertyName} must be App::PropertyFile with a String payload.`) + const decoded = decodeFcstdPropertyValue(summary) + if (!decoded.decoded || typeof decoded.value !== 'string') throw new TypeError(`FCStd PropertyFile ${edit.objectName}.${edit.propertyName} is not decodable.`) + if (expectedValue !== undefined && decoded.value !== expectedValue) throw new RangeError(`FCStd PropertyFile ${edit.objectName}.${edit.propertyName} does not match expectedValue.`) + + const entries = inspectZipDirectory(bytes, DEFAULT_FCSTD_LIMITS) + const files = unzipSync(bytes) + const documentPath = entries.find((entry) => entry.path.toLowerCase() === 'document.xml')?.path + if (!documentPath || !files[documentPath]) throw new Error('FCStd archive does not contain Document.xml.') + const parsed = parseXmlRoot(files[documentPath], documentPath, 'Document', DEFAULT_FCSTD_LIMITS) + const objectDeclarations = asArray((((parsed.root.Objects as Record | undefined)?.Object) as Record | Record[] | undefined)) + const declarations = objectDeclarations.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (declarations.length !== 1) throw new Error(`FCStd PropertyFile object declaration is not unique: ${edit.objectName}`) + declarations[0]['@_Touched'] = '1' + const objectData = asArray((((parsed.root.ObjectData as Record | undefined)?.Object) as Record | Record[] | undefined)) + const data = objectData.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (data.length !== 1) throw new Error(`FCStd PropertyFile object data is not unique: ${edit.objectName}`) + const properties = asArray(((((data[0].Properties as Record | undefined)?.Property)) as Record | Record[] | undefined)) + const candidates = properties.filter((candidate) => attribute(candidate, 'name') === edit.propertyName && attribute(candidate, 'type') === 'App::PropertyFile') + if (candidates.length !== 1 || !candidates[0].String || typeof candidates[0].String !== 'object' || Array.isArray(candidates[0].String)) throw new TypeError(`FCStd PropertyFile ${edit.objectName}.${edit.propertyName} has no unique String payload.`) + ;(candidates[0].String as Record)['@_value'] = value + files[documentPath] = new TextEncoder().encode(new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', format: false, processEntities: false, suppressBooleanAttributes: false, suppressEmptyNode: true }).build({ Document: parsed.root })) + const output: Record = {} + for (const entry of entries) output[entry.path] = new Uint8Array(files[entry.path]) + const rewritten = new Uint8Array(zipSync(output, { level: 6 })) + const rewrittenSummary = inspectFcstdArchive(rewritten).objects.find((candidate) => candidate.name === edit.objectName)?.properties.find((candidate) => candidate.name === edit.propertyName) + const rewrittenValue = rewrittenSummary ? decodeFcstdPropertyValue(rewrittenSummary) : undefined + if (!rewrittenValue?.decoded || rewrittenValue.value !== value) throw new Error(`FCStd PropertyFile ${edit.objectName}.${edit.propertyName} did not rewrite exactly.`) + return rewritten +} + +/** Rewrites one native App::PropertyFileIncluded entry while preserving its archive identity. */ +export const rewriteFcstdIncludedFileProperty = (bytes: Uint8Array, edit: FcstdIncludedFileResourceEdit): Uint8Array => { + if (!edit.objectName.trim() || !edit.propertyName.trim()) throw new TypeError('FCStd PropertyFileIncluded rewrite requires non-empty object and property names.') + const value = validateIncludedFileValue(edit.value, `${edit.objectName}.${edit.propertyName}`) + const expectedValue = edit.expectedValue === undefined ? undefined : validateIncludedFileValue(edit.expectedValue, `${edit.objectName}.${edit.propertyName}.expectedValue`) + if (!(edit.resourceBytes instanceof Uint8Array)) throw new TypeError(`FCStd PropertyFileIncluded ${edit.objectName}.${edit.propertyName} requires Uint8Array resource bytes.`) + if (edit.resourceBytes.byteLength !== value.byteLength) throw new RangeError(`FCStd PropertyFileIncluded ${edit.objectName}.${edit.propertyName} resource byte length does not match value.`) + if (expectedValue !== undefined && !(edit.expectedResourceBytes instanceof Uint8Array)) throw new TypeError(`FCStd PropertyFileIncluded ${edit.objectName}.${edit.propertyName} requires expected resource bytes.`) + if (expectedValue !== undefined && edit.expectedResourceBytes!.byteLength !== expectedValue.byteLength) throw new RangeError(`FCStd PropertyFileIncluded ${edit.objectName}.${edit.propertyName} expected resource byte length does not match expectedValue.`) + + const inspection = inspectFcstdArchive(bytes) + const object = inspection.objects.find((candidate) => candidate.name === edit.objectName) + if (!object) throw new Error(`FCStd PropertyFileIncluded object does not exist: ${edit.objectName}`) + const summary = object.properties.find((candidate) => candidate.name === edit.propertyName) + if (!summary) throw new Error(`FCStd PropertyFileIncluded property does not exist: ${edit.objectName}.${edit.propertyName}`) + if (summary.typeId !== 'App::PropertyFileIncluded' || summary.element !== 'FileIncluded') throw new TypeError(`FCStd property ${edit.objectName}.${edit.propertyName} must be App::PropertyFileIncluded with a FileIncluded payload.`) + const resourcePath = summary.resourcePath + const currentResource = summary.includedFileResource + if (!resourcePath || !currentResource) throw new Error(`FCStd PropertyFileIncluded ${edit.objectName}.${edit.propertyName} has no external resource to rewrite.`) + if (value.archiveName !== resourcePath) throw new RangeError(`FCStd PropertyFileIncluded ${edit.objectName}.${edit.propertyName} cannot change the native archive name.`) + if (expectedValue !== undefined && (expectedValue.archiveName !== resourcePath || expectedValue.byteLength !== currentResource.byteLength)) throw new RangeError(`FCStd PropertyFileIncluded ${edit.objectName}.${edit.propertyName} does not match expectedValue.`) + + const entries = inspectZipDirectory(bytes, DEFAULT_FCSTD_LIMITS) + const files = unzipSync(bytes) + const currentBytes = files[resourcePath] + if (!currentBytes) throw new Error(`FCStd PropertyFileIncluded resource is missing: ${resourcePath}`) + if (expectedValue !== undefined && (currentBytes.byteLength !== edit.expectedResourceBytes!.byteLength || currentBytes.some((byte, index) => byte !== edit.expectedResourceBytes![index]))) throw new RangeError(`FCStd PropertyFileIncluded ${edit.objectName}.${edit.propertyName} resource does not match expectedValue.`) + const documentPath = entries.find((entry) => entry.path.toLowerCase() === 'document.xml')?.path + if (!documentPath || !files[documentPath]) throw new Error('FCStd archive does not contain Document.xml.') + const parsed = parseXmlRoot(files[documentPath], documentPath, 'Document', DEFAULT_FCSTD_LIMITS) + const objectDeclarations = asArray((((parsed.root.Objects as Record | undefined)?.Object) as Record | Record[] | undefined)) + const declarations = objectDeclarations.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (declarations.length !== 1) throw new Error(`FCStd PropertyFileIncluded object declaration is not unique: ${edit.objectName}`) + declarations[0]['@_Touched'] = '1' + const objectData = asArray((((parsed.root.ObjectData as Record | undefined)?.Object) as Record | Record[] | undefined)) + const data = objectData.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (data.length !== 1) throw new Error(`FCStd PropertyFileIncluded object data is not unique: ${edit.objectName}`) + const properties = asArray(((((data[0].Properties as Record | undefined)?.Property)) as Record | Record[] | undefined)) + const candidates = properties.filter((candidate) => attribute(candidate, 'name') === edit.propertyName && attribute(candidate, 'type') === 'App::PropertyFileIncluded') + if (candidates.length !== 1 || !candidates[0].FileIncluded || typeof candidates[0].FileIncluded !== 'object' || Array.isArray(candidates[0].FileIncluded) || attribute(candidates[0].FileIncluded as Record, 'file') !== resourcePath) throw new TypeError(`FCStd PropertyFileIncluded ${edit.objectName}.${edit.propertyName} has no unique matching FileIncluded payload.`) + files[resourcePath] = new Uint8Array(edit.resourceBytes) + files[documentPath] = new TextEncoder().encode(new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', format: false, processEntities: false, suppressBooleanAttributes: false, suppressEmptyNode: true }).build({ Document: parsed.root })) + const output: Record = {} + for (const entry of entries) output[entry.path] = new Uint8Array(files[entry.path]) + const rewritten = new Uint8Array(zipSync(output, { level: 6 })) + const rewrittenSummary = inspectFcstdArchive(rewritten).objects.find((candidate) => candidate.name === edit.objectName)?.properties.find((candidate) => candidate.name === edit.propertyName) + const rewrittenResource = rewrittenSummary?.includedFileResource + if (rewrittenSummary?.typeId !== 'App::PropertyFileIncluded' || rewrittenSummary.element !== 'FileIncluded' || rewrittenSummary.resourcePath !== resourcePath || rewrittenResource?.path !== resourcePath || rewrittenResource.byteLength !== value.byteLength || rewrittenResource.contentHash !== hashBytes(edit.resourceBytes)) throw new Error(`FCStd PropertyFileIncluded ${edit.objectName}.${edit.propertyName} did not rewrite exactly.`) + return rewritten +} + +/** Rewrites one native MeasureArea input/output pair without touching other archive entries. */ +export const rewriteFcstdMeasureArea = (bytes: Uint8Array, edit: FcstdMeasureAreaEdit): Uint8Array => { + if (!edit.objectName.trim()) throw new TypeError('FCStd MeasureArea rewrite requires a non-empty object name.') + if (!Number.isFinite(edit.area) || edit.area < 0) throw new TypeError('FCStd MeasureArea rewrite requires a finite non-negative area.') + if (edit.expectedArea !== undefined && (!Number.isFinite(edit.expectedArea) || edit.expectedArea < 0)) throw new TypeError('FCStd MeasureArea expectedArea must be finite and non-negative.') + const validateElements = (value: LinkSubListValue, context: string) => { + if (!value || value.schemaVersion !== 1 || !Array.isArray(value.entries)) throw new TypeError(`FCStd MeasureArea ${context} requires a LinkSubList value.`) + const identities = value.entries.map((entry, index) => { + if (!entry || typeof entry.objectId !== 'string' || !entry.objectId.trim()) throw new TypeError(`FCStd MeasureArea ${context} entry ${index} requires an object name.`) + if (entry.subElement !== null && (typeof entry.subElement !== 'string' || !/^Face[1-9]\d*$/.test(entry.subElement))) throw new TypeError(`FCStd MeasureArea ${context} entry ${index} must reference a native FaceN or the whole object.`) + return `${entry.objectId}\0${entry.subElement ?? ''}` + }) + if (new Set(identities).size !== identities.length) throw new RangeError(`FCStd MeasureArea ${context} contains duplicate references.`) + } + validateElements(edit.elements, 'elements') + if (edit.expectedElements) validateElements(edit.expectedElements, 'expectedElements') + + const inspection = inspectFcstdArchive(bytes) + const object = inspection.objects.find((candidate) => candidate.name === edit.objectName) + if (!object) throw new Error(`FCStd MeasureArea object does not exist: ${edit.objectName}`) + if (object.typeId !== 'Measure::MeasureArea') throw new TypeError(`FCStd MeasureArea rewrite requires Measure::MeasureArea, found ${object.typeId}.`) + const areaSummary = object.properties.find((candidate) => candidate.name === 'Area') + const elementsSummary = object.properties.find((candidate) => candidate.name === 'Elements') + if (areaSummary?.typeId !== 'App::PropertyArea' || areaSummary.element !== 'Float') throw new TypeError(`FCStd MeasureArea ${edit.objectName}.Area must be App::PropertyArea with a Float payload.`) + if (elementsSummary?.typeId !== 'App::PropertyLinkSubList' || elementsSummary.element !== 'LinkSubList') throw new TypeError(`FCStd MeasureArea ${edit.objectName}.Elements must be App::PropertyLinkSubList.`) + const decodedArea = decodeFcstdPropertyValue(areaSummary) + const decodedElements = decodeFcstdPropertyValue(elementsSummary) + if (!decodedArea.decoded || typeof decodedArea.value !== 'number' || !Number.isFinite(decodedArea.value) || !decodedElements.decoded) throw new TypeError(`FCStd MeasureArea ${edit.objectName} properties are not decodable.`) + if (edit.expectedArea !== undefined && !Object.is(decodedArea.value, edit.expectedArea)) throw new RangeError(`FCStd MeasureArea ${edit.objectName}.Area expected ${edit.expectedArea}, found ${decodedArea.value}.`) + if (edit.expectedElements && JSON.stringify(decodedElements.value) !== JSON.stringify(edit.expectedElements)) throw new RangeError(`FCStd MeasureArea ${edit.objectName}.Elements does not match expectedElements.`) + const objectNames = new Set(inspection.objects.map((candidate) => candidate.name)) + for (const entry of edit.elements.entries) if (!objectNames.has(entry.objectId)) throw new RangeError(`FCStd MeasureArea target does not exist: ${entry.objectId}`) + + const entries = inspectZipDirectory(bytes, DEFAULT_FCSTD_LIMITS) + const files = unzipSync(bytes) + const documentPath = entries.find((entry) => entry.path.toLowerCase() === 'document.xml')?.path + if (!documentPath || !files[documentPath]) throw new Error('FCStd archive does not contain Document.xml.') + const parsed = parseXmlRoot(files[documentPath], documentPath, 'Document', DEFAULT_FCSTD_LIMITS) + const objectDeclarations = asArray((((parsed.root.Objects as Record | undefined)?.Object) as Record | Record[] | undefined)) + const declarations = objectDeclarations.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (declarations.length !== 1) throw new Error(`FCStd MeasureArea object declaration is not unique: ${edit.objectName}`) + declarations[0]['@_Touched'] = '1' + const objectData = asArray((((parsed.root.ObjectData as Record | undefined)?.Object) as Record | Record[] | undefined)) + const data = objectData.filter((candidate) => attribute(candidate, 'name') === edit.objectName) + if (data.length !== 1) throw new Error(`FCStd MeasureArea object data is not unique: ${edit.objectName}`) + const properties = asArray(((((data[0].Properties as Record | undefined)?.Property)) as Record | Record[] | undefined)) + const areaProperties = properties.filter((candidate) => attribute(candidate, 'name') === 'Area' && attribute(candidate, 'type') === 'App::PropertyArea') + const elementsProperties = properties.filter((candidate) => attribute(candidate, 'name') === 'Elements' && attribute(candidate, 'type') === 'App::PropertyLinkSubList') + if (areaProperties.length !== 1 || !areaProperties[0].Float || typeof areaProperties[0].Float !== 'object' || Array.isArray(areaProperties[0].Float)) throw new TypeError(`FCStd MeasureArea ${edit.objectName}.Area has no unique Float payload.`) + if (elementsProperties.length !== 1 || !elementsProperties[0].LinkSubList || typeof elementsProperties[0].LinkSubList !== 'object' || Array.isArray(elementsProperties[0].LinkSubList)) throw new TypeError(`FCStd MeasureArea ${edit.objectName}.Elements has no unique LinkSubList payload.`) + ;(areaProperties[0].Float as Record)['@_value'] = String(edit.area) + elementsProperties[0].LinkSubList = { + '@_count': String(edit.elements.entries.length), + ...(edit.elements.entries.length === 0 ? {} : { Link: edit.elements.entries.map((entry) => ({ '@_obj': entry.objectId, '@_sub': entry.subElement ?? '' })) }), + } + const documentXml = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', format: false, processEntities: false, suppressBooleanAttributes: false, suppressEmptyNode: true }).build({ Document: parsed.root }) + files[documentPath] = new TextEncoder().encode(documentXml) + const output: Record = {} + for (const entry of entries) output[entry.path] = new Uint8Array(files[entry.path]) + const rewritten = new Uint8Array(zipSync(output, { level: 6 })) + const rewrittenObject = inspectFcstdArchive(rewritten).objects.find((candidate) => candidate.name === edit.objectName) + const rewrittenArea = rewrittenObject?.properties.find((candidate) => candidate.name === 'Area') + const rewrittenElements = rewrittenObject?.properties.find((candidate) => candidate.name === 'Elements') + if (decodeFcstdPropertyValue(rewrittenArea as FcstdPropertySummary).value !== edit.area || JSON.stringify(decodeFcstdPropertyValue(rewrittenElements as FcstdPropertySummary).value) !== JSON.stringify(edit.elements)) throw new Error(`FCStd MeasureArea ${edit.objectName} did not rewrite exactly.`) + return rewritten +} + const parseXmlRoot = (bytes: Uint8Array, entryName: string, rootName: string | string[], limits: FcstdArchiveLimits) => { const xml = new TextDecoder('utf-8', { fatal: true }).decode(bytes) if (/ { + if (bytes.byteLength < 4) throw new Error(`FCStd ColorList resource is truncated: ${path}`) + const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength) + const count = view.getUint32(0, true) + if (count > Math.floor((bytes.byteLength - 4) / 4) || bytes.byteLength !== 4 + count * 4) throw new Error(`FCStd ColorList resource count does not match its payload: ${path}`) + return Array.from({ length: count }, (_, index) => packedToColorChannels(view.getUint32(4 + index * 4, true))) +} + const hydratePathProperties = (document: ReturnType, files: Record) => { for (const object of document.objects) for (const property of object.properties) { if (property.typeId !== 'Path::PropertyPath') continue @@ -2147,6 +2819,37 @@ const hydratePathProperties = (document: ReturnType, fi } } +const hydrateColorListProperties = (document: ReturnType, files: Record) => { + for (const object of document.objects) for (const property of object.properties) { + if (property.typeId !== 'App::PropertyColorList' || property.element !== 'ColorList') continue + const resourcePath = property.resourcePath ?? '' + if (!resourcePath) { + property.value = '[]' + continue + } + validateIncludedFileArchiveName(resourcePath, `FCStd PropertyFileIncluded ${object.name}.${property.name}`) + const bytes = files[resourcePath] + if (!bytes) throw new Error(`FCStd ColorList property ${object.name}.${property.name} references missing resource: ${resourcePath}`) + property.value = JSON.stringify(parseColorListResource(bytes, resourcePath)) + } +} + +const hydrateIncludedFileProperties = (document: ReturnType, files: Record) => { + for (const object of document.objects) for (const property of object.properties) { + if (property.typeId !== 'App::PropertyFileIncluded' || property.element !== 'FileIncluded') continue + const resourcePath = property.resourcePath ?? '' + if (!resourcePath) { + property.value = 'null' + continue + } + validateIncludedFileArchiveName(resourcePath, `FCStd PropertyFileIncluded ${object.name}.${property.name}`) + const bytes = files[resourcePath] + if (!bytes) throw new Error(`FCStd PropertyFileIncluded ${object.name}.${property.name} references missing resource: ${resourcePath}`) + property.includedFileResource = { path: resourcePath, mediaType: includedFileMediaType(resourcePath), byteLength: bytes.byteLength, contentHash: hashBytes(bytes), status: 'available' } + property.value = JSON.stringify(property.includedFileResource) + } +} + const countXmlNodes = (value: unknown, name: string): number => { if (!value || typeof value !== 'object') return 0 const record = value as Record @@ -2442,6 +3145,8 @@ export const inspectFcstdArchive = (bytes: Uint8Array, limitOverrides: Partial entry.role === 'shape').map((entry): FcstdShapeResource => { const payload = files[entry.path] @@ -2502,6 +3207,37 @@ export const extractFcstdShapeResources = (bytes: Uint8Array, limitOverrides: Pa return inspection.shapeResources.map((resource) => ({ ...resource, bytes: new Uint8Array(files[resource.path]) })) } +export const extractFcstdIncludedFileResources = (bytes: Uint8Array, limitOverrides: Partial = {}): FcstdIncludedFileResourcePayload[] => { + const inspection = inspectFcstdArchive(bytes, limitOverrides) + const files = unzipSync(bytes) + const resources = new Map() + for (const object of inspection.objects) for (const property of object.properties) { + const resource = property.includedFileResource + if (property.typeId !== 'App::PropertyFileIncluded' || !resource) continue + const reference = { objectName: object.name, propertyName: property.name } + const existing = resources.get(resource.path) + if (existing) { + existing.references.push(reference) + continue + } + const payload = files[resource.path] + if (!payload || payload.byteLength !== resource.byteLength) throw new Error(`FCStd PropertyFileIncluded resource could not be extracted: ${resource.path}`) + resources.set(resource.path, { ...resource, references: [reference], bytes: new Uint8Array(payload) }) + } + return [...resources.values()] +} + +export const storeFcstdIncludedFileResources = async ( + bytes: Uint8Array, + put: (payload: Uint8Array, mediaType: string) => Promise<{ hash: string }>, + limitOverrides: Partial = {}, +): Promise => Promise.all(extractFcstdIncludedFileResources(bytes, limitOverrides).map(async (resource) => { + const stored = await put(resource.bytes, resource.mediaType) + if (!stored || typeof stored.hash !== 'string' || !/^[a-f0-9]{64}$/i.test(stored.hash)) throw new Error(`FCStd PropertyFileIncluded resource ${resource.path} returned an invalid SHA-256 project resource hash.`) + const value = validateIncludedFileValue({ schemaVersion: 1, archiveName: resource.path, resourceHash: stored.hash, byteLength: resource.byteLength, mediaType: resource.mediaType }, resource.path) + return { path: resource.path, mediaType: resource.mediaType, byteLength: resource.byteLength, contentHash: resource.contentHash, status: resource.status, references: resource.references.map((reference) => ({ ...reference })), hash: value.resourceHash, value } +})) + const throwIfShapeInstantiationAborted = (signal?: AbortSignal) => { if (signal?.aborted) throw new DOMException('FCStd Shape instantiation was cancelled.', 'AbortError') } diff --git a/src/facade/includedFile.ts b/src/facade/includedFile.ts new file mode 100644 index 0000000..e8806b0 --- /dev/null +++ b/src/facade/includedFile.ts @@ -0,0 +1,53 @@ +import type { DocumentSnapshot, IncludedFileValue } from './types' + +export const MAX_INCLUDED_FILE_BYTES = 128 * 1024 * 1024 + +export const includedFileMediaType = (archiveName: string) => { + const extension = archiveName.slice(archiveName.lastIndexOf('.') + 1).toLowerCase() + return ({ + bin: 'application/octet-stream', + csv: 'text/csv', + jpeg: 'image/jpeg', + jpg: 'image/jpeg', + pat: 'text/plain', + png: 'image/png', + skf: 'application/octet-stream', + svg: 'image/svg+xml', + vrml: 'model/vrml', + wrl: 'model/vrml', + } as Record)[extension] ?? 'application/octet-stream' +} + +export const validateIncludedFileArchiveName = (value: unknown, context = 'Included file') => { + if (typeof value !== 'string' || value.length === 0 || value.length > 255) throw new TypeError(`${context} archive name must contain between 1 and 255 characters.`) + if (value === '.' || value === '..' || value.includes('/') || value.includes('\\') || /[\0-\x1f\x7f]/.test(value)) throw new RangeError(`${context} archive name must be a safe file basename.`) + return value +} + +export const validateIncludedFileValue = (value: unknown, context = 'Included file'): IncludedFileValue => { + if (!value || typeof value !== 'object' || Array.isArray(value)) throw new TypeError(`${context} requires a structured project resource value.`) + const record = value as Record + if (record.schemaVersion !== 1) throw new TypeError(`${context} schemaVersion must be 1.`) + const archiveName = validateIncludedFileArchiveName(record.archiveName, context) + if (typeof record.resourceHash !== 'string' || !/^[a-f0-9]{64}$/i.test(record.resourceHash)) throw new TypeError(`${context} resourceHash must be a SHA-256 hex digest.`) + if (typeof record.byteLength !== 'number' || !Number.isSafeInteger(record.byteLength) || record.byteLength < 0 || record.byteLength > MAX_INCLUDED_FILE_BYTES) throw new RangeError(`${context} byteLength must be between 0 and ${MAX_INCLUDED_FILE_BYTES}.`) + if (typeof record.mediaType !== 'string' || record.mediaType.length === 0 || record.mediaType.length > 255 || !/^[A-Za-z0-9!#$&^_.+-]+\/[A-Za-z0-9!#$&^_.+-]+$/.test(record.mediaType)) throw new TypeError(`${context} mediaType must be a simple MIME type.`) + return { schemaVersion: 1, archiveName, resourceHash: record.resourceHash.toLowerCase(), byteLength: record.byteLength, mediaType: record.mediaType.toLowerCase() } +} + +export const uniqueIncludedFileArchiveName = (document: DocumentSnapshot, requestedName: string, exclude?: { objectId: string; propertyName: string }) => { + const name = validateIncludedFileArchiveName(requestedName) + const used = new Set(document.objects.flatMap((object) => object.properties.flatMap((property) => { + if (property.type !== 'App::PropertyFileIncluded' || property.value === null || (exclude?.objectId === object.id && exclude.propertyName === property.name)) return [] + return [validateIncludedFileValue(property.value, `${object.id}.${property.name}`).archiveName] + }))) + if (!used.has(name)) return name + const dot = name.lastIndexOf('.') + const stem = dot > 0 ? name.slice(0, dot) : name + const extension = dot > 0 ? name.slice(dot) : '' + for (let suffix = 1; suffix < 1_000_000; suffix += 1) { + const candidate = `${stem}${suffix}${extension}` + if (candidate.length <= 255 && !used.has(candidate)) return candidate + } + throw new Error(`Unable to allocate a unique included-file archive name for ${name}.`) +} diff --git a/src/facade/index.ts b/src/facade/index.ts index 6db1950..1efed49 100644 --- a/src/facade/index.ts +++ b/src/facade/index.ts @@ -18,7 +18,7 @@ export { decodeFreecadPropertyStatus, encodeFreecadPropertyStatus, freecadProper export type { FreecadPropertyRecomputeEffect, FreecadPropertyStatus, FreecadPropertyStatusName } from './propertyStatus' export { assessResourceQuota, planResourceSweep } from './resourcePolicy' export type { ResourceQuotaAssessment, ResourceSweepPlan, ResourceSweepRecord } from './resourcePolicy' -export type { ApplyPlacementInput, AttachmentSupportValue, BitBybitViewportAdapter, BitBybitWebCadFacade, BooleanCutInput, BooleanIntersectionInput, BooleanUnionInput, ChamferInput, CommandState, CreateBoxInput, CreateConeInput, CreateCylinderInput, CreateSphereInput, CreateTorusInput, Diagnostic, DiagnosticRepairAction, DiagnosticRepairResult, DiagnosticTreeNode, DocumentObjectSnapshot, DocumentSnapshot, ElementMapEntry, ElementMapSnapshot, FacadeEvent, FacadeState, FilletInput, GeometryCapabilities, GeometryDocumentContext, GeometryFileExport, GeometryFileImport, GrooveInput, LinearFeatureParameters, LoftInput, MeshAsset, MirrorInput, ModelTreeItem, MultiTransformStep, MultiTransformValue, ObjectPropertySnapshot, ObjectTopologySnapshot, PadInput, PathCommandValue, PathPropertyValue, PersistenceCapabilities, PipeInput, Placement, PlacementValue, PlanarProfile, PocketInput, Point3, ProfileClassification, ProjectRecoveryReport, ProjectResource, ProjectResourceSweepReport, ProjectSaveResult, ProjectSummary, PropertyValue, RecomputeResult, RemoveObjectInput, ReorderBodyFeatureInput, ResolveTopologyReferenceInput, RevolutionInput, SetExpressionInput, SetPropertyInput, ShapeHandle, ShapeMassProperties, ShapeQualityReport, SubshapeRef, SubshapeSelection, SubshapeSignature, SubshapeTopology, TaskSnapshot, TopoRefValue, TopologyAdjacency, TopologyMigrationMatch, TopologySnapshotEntry, VectorValue, ViewportInteractionHandlers, ViewportMeshAsset } from './types' +export type { ApplyPlacementInput, AttachmentSupportValue, BitBybitViewportAdapter, BitBybitWebCadFacade, BooleanCutInput, BooleanIntersectionInput, BooleanUnionInput, ChamferInput, ColorListValue, ColorValue, CommandState, CreateBoxInput, CreateConeInput, CreateCylinderInput, CreateSphereInput, CreateTorusInput, Diagnostic, DiagnosticRepairAction, DiagnosticRepairResult, DiagnosticTreeNode, DocumentObjectSnapshot, DocumentSnapshot, ElementMapEntry, ElementMapSnapshot, FacadeEvent, FacadeState, FilletInput, GeometryCapabilities, GeometryDocumentContext, GeometryFileExport, GeometryFileImport, GrooveInput, IncludedFileValue, LinearFeatureParameters, LoftInput, MeshAsset, MirrorInput, ModelTreeItem, MultiTransformStep, MultiTransformValue, ObjectPropertySnapshot, ObjectTopologySnapshot, PadInput, PathCommandValue, PathPropertyValue, PersistenceCapabilities, PipeInput, Placement, PlacementValue, PlanarProfile, PocketInput, Point3, ProfileClassification, ProjectRecoveryReport, ProjectResource, ProjectResourceSweepReport, ProjectSaveResult, ProjectSummary, PropertyValue, RecomputeResult, RemoveObjectInput, ReorderBodyFeatureInput, ResolveTopologyReferenceInput, RevolutionInput, SetExpressionInput, SetIncludedFileInput, SetPropertyInput, ShapeHandle, ShapeMassProperties, ShapeQualityReport, SubshapeRef, SubshapeSelection, SubshapeSignature, SubshapeTopology, TaskSnapshot, TopoRefValue, TopologyAdjacency, TopologyMigrationMatch, TopologySnapshotEntry, VectorValue, ViewportInteractionHandlers, ViewportMeshAsset } from './types' export { createAnalyticSubshapeRefs, createEdgeSubshapeRefs, createSubshapeRefs, createTopologyAdjacency, createVertexSubshapeRefs, matchSubshapes, matchSubshapesWithAdjacency, scoreAdjacencyCompatibility, signatureForAnalyticEdge, signatureForAnalyticFace, signatureForAnalyticVertex, signatureForEdge, signatureForFace, signatureForVertex } from './topologyNaming' export type { AnalyticEdgeInput, AnalyticFaceInput, AnalyticVertexInput, TopologyAdjacencyMatch } from './topologyNaming' export { cloneObjectTopologySnapshot, createPersistedTopoRef, migrateDocumentTopologyReferences, migrateTopoRefs, parseTopoRef, resolveDocumentTopologyReference, resolveTopoRef, serializeTopoRef, validateTopologySnapshotForPersistence } from './topologyReferences' @@ -105,8 +105,8 @@ export type { AttachmentFrame, AttachmentMapMode, AttachmentSupport } from './at export { redirectBodyTips, resolveBodyTip } from './bodyRules' export type { BodyFeatureState } from './bodyRules' export type { RecomputeExecutionError, RecomputeExecutionOptions, RecomputeExecutionResult, RecomputeExecutionStatus, RecomputeGeometryRuntime, RecomputeNodeContext, RecomputeNodeExecutor, RecomputeNodeResult, RecomputeProgress } from './recomputeEngine' -export { DEFAULT_FCSTD_LIMITS, decodeFcstdPathProperty, decodeFcstdPropertyValue, encodeFcstdPathResource, extractFcstdShapeResources, inspectFcstdArchive, rewriteFcstdMetadataArchive, rewriteFcstdPathProperty, serializeElementMap2Resource, serializeFcstdMetadataArchive, serializeStringHasherTableResource, storeFcstdShapeResources } from './fcstd' -export type { FcstdArchiveLimits, FcstdCompatibilityReport, FcstdDecodedPropertyValue, FcstdElementMapResource, FcstdEntryMetadata, FcstdEntryRole, FcstdGuiInspection, FcstdInspection, FcstdObjectSummary, FcstdObjectSupport, FcstdPathEdit, FcstdPropertySummary, FcstdShapeResource, FcstdShapeResourcePayload, FcstdStoredShapeResource, FcstdStringHasherResource, FcstdWriteOptions } from './fcstd' +export { DEFAULT_FCSTD_LIMITS, decodeFcstdPathProperty, decodeFcstdPropertyValue, encodeFcstdPathResource, extractFcstdShapeResources, inspectFcstdArchive, rewriteFcstdBoolListProperty, rewriteFcstdColorListProperty, rewriteFcstdColorProperty, rewriteFcstdDirectionProperty, rewriteFcstdFileProperty, rewriteFcstdIncludedFileProperty, rewriteFcstdMeasureArea, rewriteFcstdMetadataArchive, rewriteFcstdNumericProperty, rewriteFcstdPathProperty, serializeElementMap2Resource, serializeFcstdMetadataArchive, serializeStringHasherTableResource, storeFcstdShapeResources } from './fcstd' +export type { FcstdArchiveLimits, FcstdBoolListEdit, FcstdColorEdit, FcstdColorListEdit, FcstdCompatibilityReport, FcstdDecodedPropertyValue, FcstdDirectionEdit, FcstdElementMapResource, FcstdEntryMetadata, FcstdEntryRole, FcstdFileEdit, FcstdGuiInspection, FcstdIncludedFileEdit, FcstdIncludedFileResourceEdit, FcstdInspection, FcstdMeasureAreaEdit, FcstdNumericPropertyEdit, FcstdObjectSummary, FcstdObjectSupport, FcstdPathEdit, FcstdPropertySummary, FcstdShapeResource, FcstdShapeResourcePayload, FcstdStoredShapeResource, FcstdStringHasherResource, FcstdWriteOptions } from './fcstd' export { cloneStringHasherTable, migrateStringHasherSchema, parseStringHasherTable, StringHasherFlag, validateElementMap2StringHasherEvidence, validateStringHasherTable, writeStringHasherTable } from './stringHasher' export type { AnyStringHasherTable, StringHasherEntry, StringHasherTable, StringHasherTableV1, StringHasherValidationIssue, StringHasherValidationReport, ElementMap2StringHasherEvidenceIssue } from './stringHasher' export { appendElementMap2NameEntry, canonicalizeElementMap2, cloneElementMap2, createElementMap2MultiStageNameMapping, createElementMap2NameEntry, createElementMap2NameToken, elementMap2NameTokenToReference, elementMap2SemanticDigest, formatElementMap2NameToken, migrateElementMap2Schema, parseElementMap2, parseElementMap2MultiStageNameMapping, validateElementMap2, validateElementMap2MultiStageNameMapping, writeElementMap2, writeElementMap2MultiStageNameMapping } from './elementMap2' diff --git a/src/facade/mockFacade.ts b/src/facade/mockFacade.ts index cdb878b..52d2384 100644 --- a/src/facade/mockFacade.ts +++ b/src/facade/mockFacade.ts @@ -24,6 +24,7 @@ import type { RemoveDynamicPropertyInput, RenameDynamicPropertyInput, SetPropertyInput, + SetIncludedFileInput, SetExpressionInput, RecomputeResult, ResolveTopologyReferenceInput, @@ -44,13 +45,15 @@ import { DependencyGraph, createRecomputeSnapshot, type DependencyEdge } from '. import { convertQuantity, evaluateQuantityExpression, getUnit, quantityDimensionForUnit, quantityFromNumber, quantityFromUnit, type Quantity } from './units' import { carbonCopySketchGeometry, cloneSketch, cloneSketchConstraint, cloneSketchGeometry, createSketch, projectSketchGeometry, solveSketch, type SketchConstraint, type SketchExternalGeometry, type SketchGeometry, type SketchSnapshot } from './sketcher' import { createFacadeGeometryRecomputeExecutor, RecomputeCoordinator, sketchProfile, type RecomputeExecutionOptions } from './recomputeEngine' -import { decodeFcstdPathProperty, extractFcstdShapeResources, inspectFcstdArchive, instantiateFcstdShapeResource, rewriteFcstdMetadataArchive, rewriteFcstdPathProperty, serializeFcstdMetadataArchive, storeFcstdShapeResources } from './fcstd' +import { decodeFcstdPathProperty, extractFcstdIncludedFileResources, extractFcstdShapeResources, inspectFcstdArchive, instantiateFcstdShapeResource, rewriteFcstdBoolListProperty, rewriteFcstdColorListProperty, rewriteFcstdColorProperty, rewriteFcstdDirectionProperty, rewriteFcstdFileProperty, rewriteFcstdIncludedFileProperty, rewriteFcstdMeasureArea, rewriteFcstdMetadataArchive, rewriteFcstdNumericProperty, rewriteFcstdPathProperty, serializeFcstdMetadataArchive, storeFcstdIncludedFileResources, storeFcstdShapeResources } from './fcstd' +import type { FcstdWriteOptions } from './fcstd' import { buildDiagnosticTree, buildRecomputeDiagnostics, cloneDiagnostic, replaceRecomputeDiagnostics } from './diagnostics' import { cloneObjectTopologySnapshot, migrateDocumentTopologyReferences, parseTopoRef, resolveDocumentTopologyReference } from './topologyReferences' import { createCamJob } from './cam' import { PUMP_HOUSING_DEMO_TEMPLATE, type DocumentTemplate } from './documentTemplates' import { assertPartDesignParameterSet, parameterValuesForObject, validatePartDesignParameterSet } from './partDesignParameters' -import { freecadPropertyRecomputeEffect, hasFreecadPropertyStatus, isFreecadPropertyDocumentModifiedSuppressed, isFreecadPropertyDynamicMutationLocked, isFreecadPropertyPartialDocumentTrigger, isFreecadPropertyReadOnly, withFreecadPropertyStatus } from './propertyStatus' +import { freecadPropertyRecomputeEffect, hasFreecadPropertyStatus, isFreecadPropertyDocumentModifiedSuppressed, isFreecadPropertyDynamicMutationLocked, isFreecadPropertyPartialDocumentTrigger, isFreecadPropertyPersistenceSuppressed, isFreecadPropertyReadOnly, withFreecadPropertyStatus } from './propertyStatus' +import { includedFileMediaType, uniqueIncludedFileArchiveName, validateIncludedFileValue } from './includedFile' const typeIdForItem = (item: ModelTreeItem) => item.type === 'body' ? 'PartDesign::Body' : item.type === 'sketch' ? 'Sketcher::SketchObject' : item.id.startsWith('box') ? 'Part::Box' : item.id.startsWith('cylinder') ? 'Part::Cylinder' : item.id.startsWith('sphere') ? 'Part::Sphere' : item.id.startsWith('ellipsoid') ? 'Part::Ellipsoid' : item.id.startsWith('cone') ? 'Part::Cone' : item.id.startsWith('torus') ? 'Part::Torus' : item.id.startsWith('helix') ? 'Part::Helix' : item.id.startsWith('prism') ? 'Part::Prism' : item.id.startsWith('wedge') ? 'Part::Wedge' : item.id.startsWith('union') ? 'Part::Fuse' : item.id.startsWith('cut') ? 'Part::Cut' : item.id.startsWith('intersection') ? 'Part::Common' : item.id.startsWith('pad') ? 'PartDesign::Pad' : item.id.startsWith('pocket') ? 'PartDesign::Pocket' : item.id.startsWith('revolution') ? 'PartDesign::Revolution' : item.id.startsWith('groove') ? 'PartDesign::Groove' : item.id.startsWith('fillet') ? 'PartDesign::Fillet' : item.id.startsWith('chamfer') ? 'PartDesign::Chamfer' : item.id.startsWith('mirrored') ? 'PartDesign::Mirrored' : item.id.startsWith('multi-transform') ? 'PartDesign::MultiTransform' : item.id.startsWith('linear-pattern') ? 'PartDesign::LinearPattern' : item.id.startsWith('polar-pattern') ? 'PartDesign::PolarPattern' : item.id.startsWith('hole') ? 'PartDesign::Hole' : item.type === 'feature' ? 'PartDesign::Feature' : 'App::DocumentObjectGroup' @@ -322,7 +325,11 @@ const featureProperties = (item: ModelTreeItem): ObjectPropertySnapshot[] => { const createObjectSnapshot = (item: ModelTreeItem): DocumentObjectSnapshot => ({ id: item.id, typeId: typeIdForItem(item), properties: [...commonProperties(item), ...featureProperties(item), ...viewProperties()], sketch: item.type === 'sketch' ? createSketch(item.id) : undefined }) const clonePropertyValue = (value: PropertyValue): PropertyValue => { - if (Array.isArray(value)) return value.every((entry) => typeof entry === 'number') ? [...value] as number[] : [...value] as string[] + if (Array.isArray(value)) { + if (value.every((entry) => Array.isArray(entry))) return value.map((entry) => [...entry]) as PropertyValue + if (value.every((entry) => typeof entry === 'boolean')) return [...value] as boolean[] + return value.every((entry) => typeof entry === 'number') ? [...value] as number[] : [...value] as string[] + } if (!value || typeof value !== 'object') return value if ('position' in value && 'rotation' in value) return { position: { ...value.position }, rotation: { axis: { ...value.rotation.axis }, angle: value.rotation.angle } } if ('steps' in value && Array.isArray(value.steps)) return { steps: value.steps.map((step) => ({ ...step })) } @@ -382,6 +389,30 @@ const collectDependencyEdges = (document: Pick): De return edges } +const measureAreaFromElements = (document: DocumentSnapshot, value: LinkSubListValue): number => { + let total = 0 + for (const entry of value.entries) { + const source = document.objects.find((object) => object.id === entry.objectId) + const topology = source?.topology + if (!source || !topology) throw new Error('Cannot calculate area') + const faces = topology.entries.filter((candidate) => candidate.ref.kind === 'face') + if (entry.subElement === null) { + if (faces.length === 0) throw new Error('Cannot calculate area') + total += faces.reduce((sum, candidate) => sum + candidate.signature.area, 0) + continue + } + const persistentId = typeof entry.subElement === 'string' + ? topology.elementMap?.entries.find((candidate) => candidate.name === entry.subElement)?.persistentId + ?? (/^Face([1-9]\d*)$/.test(entry.subElement) ? faces[Number(entry.subElement.slice(4)) - 1]?.ref.persistentId : entry.subElement) + : entry.subElement.status === 'stable' || entry.subElement.status === 'new' ? entry.subElement.persistentId : '' + const face = faces.find((candidate) => candidate.ref.persistentId === persistentId) + if (!face || !Number.isFinite(face.signature.area) || face.signature.area < 0) throw new Error('Cannot calculate area') + total += face.signature.area + } + if (!Number.isFinite(total)) throw new Error('Cannot calculate area') + return total +} + const expressionReferences = (expression: string): string[] => { try { return evaluateQuantityExpression(expression).references @@ -538,15 +569,32 @@ const commandState = (commandId: string, activeWorkbench: WorkbenchId, selectedO const validatePropertyValue = (document: DocumentSnapshot, property: ObjectPropertySnapshot, value: PropertyValue) => { if (property.readOnly || isFreecadPropertyReadOnly(property.nativeStatus)) throw new Error(`${property.label} is read-only.`) if (property.type === 'App::PropertyBool' && typeof value !== 'boolean') throw new TypeError(`${property.label} requires a boolean value.`) - if ((property.type === 'App::PropertyString' || property.type === 'App::PropertyEnumeration' || property.type === 'App::PropertyColor') && typeof value !== 'string') throw new TypeError(`${property.label} requires a string value.`) - if ((property.type === 'App::PropertyLength' || property.type === 'App::PropertyDistance' || property.type === 'App::PropertyAngle' || property.type === 'App::PropertyQuantityConstraint' || property.type === 'App::PropertyPercent' || property.type === 'App::PropertyFloat' || property.type === 'App::PropertyFloatConstraint' || property.type === 'App::PropertyPrecision' || property.type === 'App::PropertyInteger' || property.type === 'App::PropertyIntegerConstraint') && (typeof value !== 'number' || !Number.isFinite(value))) throw new TypeError(`${property.label} requires a finite numeric value.`) + if (property.type === 'App::PropertyBoolList' && (!Array.isArray(value) || !value.every((entry) => typeof entry === 'boolean'))) throw new TypeError(`${property.label} requires a boolean list.`) + if (property.type === 'App::PropertyColorList' && (!Array.isArray(value) || !value.every((color) => Array.isArray(color) && color.length === 4 && color.every((channel) => typeof channel === 'number' && Number.isFinite(channel))))) throw new TypeError(`${property.label} requires a list of four finite RGBA channels.`) + if ((property.type === 'App::PropertyString' || property.type === 'App::PropertyEnumeration') && typeof value !== 'string') throw new TypeError(`${property.label} requires a string value.`) + if (property.type === 'App::PropertyFile') { + if (typeof value !== 'string') throw new TypeError(`${property.label} requires a project-relative file reference.`) + if (value.length > 4096) throw new RangeError(`${property.label} file reference is too long.`) + if (value && (value.includes('\0') || value.includes('\\') || value.startsWith('/') || /^[A-Za-z]:/.test(value) || /^[A-Za-z][A-Za-z0-9+.-]*:/.test(value) || value.split('/').some((segment) => segment === '.' || segment === '..' || segment.length === 0))) throw new RangeError(`${property.label} requires a safe project-relative file reference.`) + } + if (property.type === 'App::PropertyFileIncluded') { + if (value === null) { + if (property.value !== null) throw new RangeError(`${property.label} cannot be cleared because native PropertyFileIncluded treats an empty setter as a no-op.`) + } else validateIncludedFileValue(value, property.label) + } + if (property.type === 'App::PropertyColor') { + if (property.scope === 'view') { + if (typeof value !== 'string') throw new TypeError(`${property.label} requires a #RRGGBB color.`) + } else if (!Array.isArray(value) || value.length !== 4 || !value.every((entry) => typeof entry === 'number' && Number.isFinite(entry))) throw new TypeError(`${property.label} requires four finite RGBA channels.`) + } + if ((property.type === 'App::PropertyLength' || property.type === 'App::PropertyDistance' || property.type === 'App::PropertyAngle' || property.type === 'App::PropertyAcceleration' || property.type === 'App::PropertyArea' || property.type === 'App::PropertyQuantityConstraint' || property.type === 'App::PropertyPercent' || property.type === 'App::PropertyFloat' || property.type === 'App::PropertyFloatConstraint' || property.type === 'App::PropertyPrecision' || property.type === 'App::PropertyInteger' || property.type === 'App::PropertyIntegerConstraint') && (typeof value !== 'number' || !Number.isFinite(value))) throw new TypeError(`${property.label} requires a finite numeric value.`) if ((property.type === 'App::PropertyInteger' || property.type === 'App::PropertyIntegerConstraint') && !Number.isSafeInteger(value)) throw new TypeError(`${property.label} requires an integer value.`) if (property.name === 'Occurrences' && ((value as number) < 2 || (value as number) > 100)) throw new RangeError('Occurrences must be between 2 and 100.') if ((property.type === 'App::PropertyLength' || property.type === 'App::PropertyQuantityConstraint') && (value as number) < 0) throw new RangeError(`${property.label} cannot be negative.`) if (property.type === 'App::PropertyPercent' && ((value as number) < 0 || (value as number) > 100)) throw new RangeError(`${property.label} must be between 0 and 100.`) if (property.type === 'App::PropertyEnumeration' && !property.options?.includes(value as string)) throw new RangeError(`${property.label} is not a registered enumeration value.`) - if (property.type === 'App::PropertyColor' && !/^#[0-9a-f]{6}$/i.test(value as string)) throw new RangeError(`${property.label} requires a #RRGGBB color.`) - if (property.type === 'App::PropertyVector') validateVectorValue(property.label, value) + if (property.type === 'App::PropertyColor' && property.scope === 'view' && !/^#[0-9a-f]{6}$/i.test(value as string)) throw new RangeError(`${property.label} requires a #RRGGBB color.`) + if (property.type === 'App::PropertyVector' || property.type === 'App::PropertyDirection') validateVectorValue(property.label, value) if (property.type === 'App::PropertyPlacement') { if (!value || typeof value !== 'object' || Array.isArray(value) || !('position' in value) || !('rotation' in value)) throw new TypeError(`${property.label} requires a Placement value.`) const placement = value as PlacementValue @@ -1012,11 +1060,11 @@ export function createWebCadFacade(options: WebCadFacadeOptions = {}): BitBybitW if (property.type === 'App::PropertyLink' && sourceObject && property.name === 'Profile' && sourceObject.typeId === 'Sketcher::SketchObject') return { ...property, value: sourceObject.id } if (property.type === 'App::PropertyLink' && sourceObject && property.name === 'Base' && shapeTypeIds.has(sourceObject.typeId)) return { ...property, value: sourceObject.id } if (property.type === 'App::PropertyLinkSub' && property.name === 'Spine' && typeof candidate === 'string' && candidate.length > 0) return { ...property, value: { schemaVersion: 1, objectId: candidate, subElements: [] } } - if (property.type === 'App::PropertyVector' && candidate && typeof candidate === 'object') return { ...property, value: clonePropertyValue(candidate as PropertyValue) } + if ((property.type === 'App::PropertyVector' || property.type === 'App::PropertyDirection') && candidate && typeof candidate === 'object') return { ...property, value: clonePropertyValue(candidate as PropertyValue) } if (property.type === 'App::PropertyLinkList' && Array.isArray(candidate) && candidate.every((entry) => typeof entry === 'string')) return { ...property, value: loftCommands.has(commandId) && commandId !== 'loft-part' ? candidate.slice(1) : [...candidate] } if (property.type === 'App::PropertyBool' && typeof candidate === 'boolean') return { ...property, value: candidate } if (property.type === 'App::PropertyMultiTransform' && candidate && typeof candidate === 'object') return { ...property, value: clonePropertyValue(candidate as MultiTransformValue) } - if ((property.type === 'App::PropertyLength' || property.type === 'App::PropertyDistance' || property.type === 'App::PropertyAngle' || property.type === 'App::PropertyQuantityConstraint' || property.type === 'App::PropertyPercent' || property.type === 'App::PropertyFloat' || property.type === 'App::PropertyInteger' || property.type === 'App::PropertyIntegerConstraint') && typeof candidate === 'number' && Number.isFinite(candidate)) return { ...property, value: candidate } + if ((property.type === 'App::PropertyLength' || property.type === 'App::PropertyDistance' || property.type === 'App::PropertyAngle' || property.type === 'App::PropertyAcceleration' || property.type === 'App::PropertyArea' || property.type === 'App::PropertyQuantityConstraint' || property.type === 'App::PropertyPercent' || property.type === 'App::PropertyFloat' || property.type === 'App::PropertyInteger' || property.type === 'App::PropertyIntegerConstraint') && typeof candidate === 'number' && Number.isFinite(candidate)) return { ...property, value: candidate } if (property.type === 'App::PropertyEnumeration' && typeof candidate === 'string' && property.options?.includes(candidate)) return { ...property, value: candidate } return property }) @@ -1061,7 +1109,9 @@ export function createWebCadFacade(options: WebCadFacadeOptions = {}): BitBybitW markDocumentTouched(nextDocument, tipObject ? [objectId, tipObject.id] : [objectId]) return { document: nextDocument, objectId } } - const setProperty = ({ objectId, propertyName, value }: SetPropertyInput) => { + const setProperty = ({ objectId, propertyName, value, expectedDocumentVersion, signal }: SetPropertyInput) => { + if (signal?.aborted) throw new DOMException('Property mutation cancelled before transaction start.', 'AbortError') + if (expectedDocumentVersion !== undefined && expectedDocumentVersion !== state.document.version) throw new RangeError(`Stale document version: expected ${expectedDocumentVersion}, current ${state.document.version}.`) const objectIndex = state.document.objects.findIndex((object) => object.id === objectId) if (objectIndex < 0) throw new Error(`Document object does not exist: ${objectId}`) const sourceObject = state.document.objects[objectIndex] @@ -1069,6 +1119,9 @@ export function createWebCadFacade(options: WebCadFacadeOptions = {}): BitBybitW if (propertyIndex < 0) throw new Error(`Property does not exist: ${objectId}.${propertyName}`) const sourceProperty = sourceObject.properties[propertyIndex] validatePropertyValue(state.document, sourceProperty, value) + const derivedArea = sourceObject.typeId === 'Measure::MeasureArea' && propertyName === 'Elements' + ? measureAreaFromElements(state.document, value as LinkSubListValue) + : undefined if (Object.is(sourceProperty.value, value)) return const beforeVersion = state.document.version @@ -1080,6 +1133,11 @@ export function createWebCadFacade(options: WebCadFacadeOptions = {}): BitBybitW const document = cloneDocumentSnapshot(state.document) const object = document.objects[objectIndex] object.properties[propertyIndex] = { ...object.properties[propertyIndex], value: clonePropertyValue(value), expression: undefined, expressionError: undefined } + if (derivedArea !== undefined) { + const areaProperty = object.properties.find((property) => property.name === 'Area' && property.type === 'App::PropertyArea') + if (!areaProperty || !(areaProperty.readOnly || isFreecadPropertyReadOnly(areaProperty.nativeStatus))) throw new Error('Measure::MeasureArea requires a read-only App::PropertyArea output.') + areaProperty.value = derivedArea + } const parameterReport = validatePartDesignParameterSet(object.typeId, parameterValuesForObject(object), { requireComplete: false }) if (!parameterReport.valid) throw new RangeError(`${object.typeId}.${parameterReport.issues[0].propertyName}: ${parameterReport.issues[0].message}`) const treeItem = document.tree.find((item) => item.id === objectId) @@ -1089,6 +1147,7 @@ export function createWebCadFacade(options: WebCadFacadeOptions = {}): BitBybitW if (sourceProperty.recompute && recomputeEffect !== 'none') markDocumentTouched(document, [objectId], recomputeEffect === 'owner') document.version += 1 document.dirty = isFreecadPropertyDocumentModifiedSuppressed(sourceProperty.nativeStatus) ? state.document.dirty : true + if (signal?.aborted) throw new DOMException('Property mutation cancelled before transaction commit.', 'AbortError') commit({ ...state, document }) emit({ type: 'property.changed', transactionId, documentId: document.id, documentVersion: document.version, objectId, propertyName, partialDocument, partialTrigger }) emit({ type: 'transaction.committed', transactionId, operation: 'property.set', documentId: document.id, beforeVersion, afterVersion: document.version }) @@ -1109,6 +1168,42 @@ export function createWebCadFacade(options: WebCadFacadeOptions = {}): BitBybitW } notify(`${sourceProperty.label} updated`) } + const setIncludedFile = async ({ objectId, propertyName, fileName, bytes, mediaType, expectedDocumentVersion, signal }: SetIncludedFileInput) => { + if (signal?.aborted) throw new DOMException('Included-file mutation cancelled before resource storage.', 'AbortError') + if (expectedDocumentVersion !== undefined && expectedDocumentVersion !== state.document.version) throw new RangeError(`Stale document version: expected ${expectedDocumentVersion}, current ${state.document.version}.`) + const object = state.document.objects.find((candidate) => candidate.id === objectId) + const property = object?.properties.find((candidate) => candidate.name === propertyName) + if (!object) throw new Error(`Document object does not exist: ${objectId}`) + if (!property) throw new Error(`Property does not exist: ${objectId}.${propertyName}`) + if (property.type !== 'App::PropertyFileIncluded') throw new TypeError(`${objectId}.${propertyName} is not App::PropertyFileIncluded.`) + if (property.readOnly || isFreecadPropertyReadOnly(property.nativeStatus)) throw new Error(`${property.label} is read-only.`) + if (!(bytes instanceof Uint8Array)) throw new TypeError(`${property.label} requires Uint8Array resource bytes.`) + const archiveName = uniqueIncludedFileArchiveName(state.document, fileName, { objectId, propertyName }) + const payload = new Uint8Array(bytes) + const resource = await projectPersistence.resource.put(payload, mediaType || includedFileMediaType(archiveName)) + try { + const value = validateIncludedFileValue({ schemaVersion: 1, archiveName, resourceHash: resource.hash, byteLength: payload.byteLength, mediaType: resource.mediaType }, property.label) + setProperty({ objectId, propertyName, value, expectedDocumentVersion, signal }) + return value + } catch (error) { + await projectPersistence.resource.release(resource.hash) + throw error + } + } + const fcstdOptionsWithIncludedFileResources = async (document: DocumentSnapshot, options: FcstdWriteOptions = {}): Promise => { + const opaqueEntries = Object.fromEntries(Object.entries(options.opaqueEntries ?? {}).map(([path, payload]) => [path, new Uint8Array(payload)])) + for (const object of document.objects) for (const property of object.properties) { + if (property.type !== 'App::PropertyFileIncluded' || property.value === null || isFreecadPropertyPersistenceSuppressed(property.nativeStatus)) continue + const value = validateIncludedFileValue(property.value, `${object.id}.${property.name}`) + const payload = await projectPersistence.resource.get(value.resourceHash) + if (!payload) throw new Error(`Project resource is missing for ${object.id}.${property.name}: ${value.resourceHash}`) + if (payload.byteLength !== value.byteLength) throw new Error(`Project resource byte length changed for ${object.id}.${property.name}.`) + const existing = opaqueEntries[value.archiveName] + if (existing && (existing.byteLength !== payload.byteLength || existing.some((byte, index) => byte !== payload[index]))) throw new Error(`FCStd PropertyFileIncluded archive name ${value.archiveName} has conflicting resource bytes.`) + opaqueEntries[value.archiveName] = new Uint8Array(payload) + } + return { ...options, opaqueEntries } + } const addDynamicProperty = ({ objectId, property: inputProperty }: AddDynamicPropertyInput): ObjectPropertySnapshot => { const objectIndex = state.document.objects.findIndex((object) => object.id === objectId) if (objectIndex < 0) throw new Error(`Document object does not exist: ${objectId}`) @@ -1270,7 +1365,7 @@ export function createWebCadFacade(options: WebCadFacadeOptions = {}): BitBybitW if (propertyIndex < 0) throw new Error(`Property does not exist: ${objectId}.${propertyName}`) const sourceProperty = sourceObject.properties[propertyIndex] if (sourceProperty.readOnly || isFreecadPropertyReadOnly(sourceProperty.nativeStatus)) throw new Error(`${sourceProperty.label} is read-only.`) - if (!['App::PropertyLength', 'App::PropertyAngle', 'App::PropertyFloat', 'App::PropertyPercent'].includes(sourceProperty.type)) throw new TypeError(`${sourceProperty.label} does not accept expressions.`) + if (!['App::PropertyLength', 'App::PropertyAngle', 'App::PropertyAcceleration', 'App::PropertyFloat', 'App::PropertyPercent'].includes(sourceProperty.type)) throw new TypeError(`${sourceProperty.label} does not accept expressions.`) const evaluated = expectedExpressionValue(sourceProperty, expression, state.document) const references = expressionReferences(expression) const variables = expressionVariables(state.document) @@ -1612,14 +1707,52 @@ export function createWebCadFacade(options: WebCadFacadeOptions = {}): BitBybitW const facade: BitBybitWebCadFacade = { runtime, - app: { document: { getActive: () => getState().document, getObject: (objectId) => { const object = state.document.objects.find((candidate) => candidate.id === objectId); return object ? { ...object, properties: object.properties.map((property) => ({ ...property, value: clonePropertyValue(property.value), options: property.options ? [...property.options] : undefined })), sketch: object.sketch ? cloneSketch(object.sketch) : undefined, topology: object.topology ? cloneObjectTopologySnapshot(object.topology) : undefined } : null }, create: (label) => { recomputeCoordinator.cancel(); clearFeatureShapes(); commit({ ...state, document: nextBlankDocument(label), selectedObjectId: '', selectedObjectIds: [] }); return getState().document }, load: loadDocument, markDirty: () => { commit({ ...state, document: { ...state.document, dirty: true } }) }, setProperty, addDynamicProperty, removeDynamicProperty, renameDynamicProperty, reorderBodyFeature, removeObject, resolveTopologyReference, setExpression, recompute: recomputeDocument, recomputeAsync: recomputeDocumentAsync, cancelRecompute: () => recomputeCoordinator.cancel(), getDependencies: () => (state.document.dependencies ?? []).map((edge) => ({ ...edge })) }, expression: { evaluate: (expression, variables = {}) => evaluateQuantityExpression(expression, new Map(Object.entries(variables))), dimensionForUnit: quantityDimensionForUnit }, sketcher: { get: getSketch, addGeometry: addSketchGeometry, projectGeometry: projectSketch, carbonCopy: carbonCopySketch, addExternalGeometry: addSketchExternalGeometry, addConstraint: addSketchConstraint, solve: solveSketchObject } }, + app: { document: { getActive: () => getState().document, getObject: (objectId) => { const object = state.document.objects.find((candidate) => candidate.id === objectId); return object ? { ...object, properties: object.properties.map((property) => ({ ...property, value: clonePropertyValue(property.value), options: property.options ? [...property.options] : undefined })), sketch: object.sketch ? cloneSketch(object.sketch) : undefined, topology: object.topology ? cloneObjectTopologySnapshot(object.topology) : undefined } : null }, create: (label) => { recomputeCoordinator.cancel(); clearFeatureShapes(); commit({ ...state, document: nextBlankDocument(label), selectedObjectId: '', selectedObjectIds: [] }); return getState().document }, load: loadDocument, markDirty: () => { commit({ ...state, document: { ...state.document, dirty: true } }) }, setProperty, setIncludedFile, addDynamicProperty, removeDynamicProperty, renameDynamicProperty, reorderBodyFeature, removeObject, resolveTopologyReference, setExpression, recompute: recomputeDocument, recomputeAsync: recomputeDocumentAsync, cancelRecompute: () => recomputeCoordinator.cancel(), getDependencies: () => (state.document.dependencies ?? []).map((edge) => ({ ...edge })) }, expression: { evaluate: (expression, variables = {}) => evaluateQuantityExpression(expression, new Map(Object.entries(variables))), dimensionForUnit: quantityDimensionForUnit }, sketcher: { get: getSketch, addGeometry: addSketchGeometry, projectGeometry: projectSketch, carbonCopy: carbonCopySketch, addExternalGeometry: addSketchExternalGeometry, addConstraint: addSketchConstraint, solve: solveSketchObject } }, history: { canUndo: () => undoStack.length > 0, canRedo: () => redoStack.length > 0, undo: () => { const previous = undoStack.pop(); if (!previous) return; clearFeatureShapes(); redoStack.push(getState()); state = previous; emitState(); notify('Undo applied') }, redo: () => { const next = redoStack.pop(); if (!next) return; clearFeatureShapes(); undoStack.push(getState()); state = next; emitState(); notify('Redo applied') } }, gui: { workbench: { list: () => Object.keys(workbenchDefinitions) as WorkbenchId[], getActive: () => state.activeWorkbench, setActive }, command: { getState: (commandId) => commandState(commandId, state.activeWorkbench, state.selectedObjectId, state.document.objects.find((object) => object.id === state.selectedObjectId), state.selectedSubshape), list: (workbench) => workbenchDefinitions[workbench].groups.flatMap((group) => group.commands), execute } }, selection: { getObjectId: () => state.selectedObjectId, getObjectIds: () => [...(state.selectedObjectIds ?? (state.selectedObjectId ? [state.selectedObjectId] : []))], getSubshape: () => cloneSelection(state.selectedSubshape) ?? null, getPreselection: () => cloneSelection(state.preselectedSubshape) ?? null, select, selectObjects, selectSubshape, preselectSubshape, clear: () => select('') }, task: { getActive: () => getState().task, begin: beginTask, update: (draft) => { if (state.task) state = { ...state, task: { ...state.task, draft: { ...state.task.draft, ...draft } } }; emitState() }, apply: applyTask, cancel: () => { if (state.task) state = { ...state, task: { ...state.task, status: 'cancelled' } }; emitState() } }, diagnostics: { list: () => state.diagnostics.map(cloneDiagnostic), tree: () => buildDiagnosticTree(state.diagnostics), repair: repairDiagnostic }, cam: camJob, - project: { capabilities: () => projectPersistence.capabilities(), subscribeExternalChanges: (listener) => projectPersistence.subscribeExternalChanges(listener), list: () => projectPersistence.list(), save: (document = getState().document) => projectPersistence.save(document), load: (documentId) => projectPersistence.load(documentId), loadCheckpoint: (documentId, version) => projectPersistence.loadCheckpoint(documentId, version), recovery: (documentId) => projectPersistence.recovery(documentId), fcstd: { inspect: (bytes, limits) => inspectFcstdArchive(bytes, limits), extractShapes: (bytes, limits) => extractFcstdShapeResources(bytes, limits), storeShapes: (bytes, limits) => storeFcstdShapeResources(bytes, (payload, mediaType) => projectPersistence.resource.put(payload, mediaType).then((resource) => ({ hash: resource.hash })), limits), instantiateShape: (bytes, resourcePath, signal, limits) => { const document = getState().document; return instantiateFcstdShapeResource(bytes, resourcePath, ({ format, text }) => geometryRuntime.importShape({ format, text, documentId: document.id, documentVersion: document.version }), { limits, signal, release: (shape) => geometryRuntime.release(shape) }) }, serializeMetadata: (document, options) => serializeFcstdMetadataArchive(document, options), rewriteMetadata: (bytes, document, options) => rewriteFcstdMetadataArchive(bytes, document, options), decodePath: (bytes, objectName, propertyName) => decodeFcstdPathProperty(bytes, objectName, propertyName), rewritePath: (bytes, edit) => rewriteFcstdPathProperty(bytes, edit) }, resource: projectPersistence.resource }, + project: { + capabilities: () => projectPersistence.capabilities(), + subscribeExternalChanges: (listener) => projectPersistence.subscribeExternalChanges(listener), + list: () => projectPersistence.list(), + save: (document = getState().document) => projectPersistence.save(document), + load: (documentId) => projectPersistence.load(documentId), + loadCheckpoint: (documentId, version) => projectPersistence.loadCheckpoint(documentId, version), + recovery: (documentId) => projectPersistence.recovery(documentId), + fcstd: { + inspect: (bytes, limits) => inspectFcstdArchive(bytes, limits), + extractShapes: (bytes, limits) => extractFcstdShapeResources(bytes, limits), + storeShapes: (bytes, limits) => storeFcstdShapeResources(bytes, (payload, mediaType) => projectPersistence.resource.put(payload, mediaType).then((resource) => ({ hash: resource.hash })), limits), + extractIncludedFiles: (bytes, limits) => extractFcstdIncludedFileResources(bytes, limits), + storeIncludedFiles: (bytes, limits) => storeFcstdIncludedFileResources(bytes, (payload, mediaType) => projectPersistence.resource.put(payload, mediaType).then((resource) => ({ hash: resource.hash })), limits), + instantiateShape: (bytes, resourcePath, signal, limits) => { const document = getState().document; return instantiateFcstdShapeResource(bytes, resourcePath, ({ format, text }) => geometryRuntime.importShape({ format, text, documentId: document.id, documentVersion: document.version }), { limits, signal, release: (shape) => geometryRuntime.release(shape) }) }, + serializeMetadata: (document, options) => serializeFcstdMetadataArchive(document, options), + serializeMetadataWithResources: async (document, options) => serializeFcstdMetadataArchive(document, await fcstdOptionsWithIncludedFileResources(document, options)), + rewriteMetadata: (bytes, document, options) => rewriteFcstdMetadataArchive(bytes, document, options), + rewriteMetadataWithResources: async (bytes, document, options) => rewriteFcstdMetadataArchive(bytes, document, await fcstdOptionsWithIncludedFileResources(document, options)), + decodePath: (bytes, objectName, propertyName) => decodeFcstdPathProperty(bytes, objectName, propertyName), + rewritePath: (bytes, edit) => rewriteFcstdPathProperty(bytes, edit), + rewriteNumeric: (bytes, edit) => rewriteFcstdNumericProperty(bytes, edit), + rewriteMeasureArea: (bytes, edit) => rewriteFcstdMeasureArea(bytes, edit), + rewriteBoolList: (bytes, edit) => rewriteFcstdBoolListProperty(bytes, edit), + rewriteColor: (bytes, edit) => rewriteFcstdColorProperty(bytes, edit), + rewriteColorList: (bytes, edit) => rewriteFcstdColorListProperty(bytes, edit), + rewriteDirection: (bytes, edit) => rewriteFcstdDirectionProperty(bytes, edit), + rewriteFile: (bytes, edit) => rewriteFcstdFileProperty(bytes, edit), + rewriteIncludedFile: async (bytes, edit) => { + const resourceBytes = await projectPersistence.resource.get(edit.value.resourceHash) + if (!resourceBytes) throw new Error(`Project resource is missing for FCStd PropertyFileIncluded rewrite: ${edit.value.resourceHash}`) + const expectedResourceBytes = edit.expectedValue ? await projectPersistence.resource.get(edit.expectedValue.resourceHash) : undefined + if (edit.expectedValue && !expectedResourceBytes) throw new Error(`Expected project resource is missing for FCStd PropertyFileIncluded rewrite: ${edit.expectedValue.resourceHash}`) + return rewriteFcstdIncludedFileProperty(bytes, { ...edit, resourceBytes, ...(expectedResourceBytes ? { expectedResourceBytes } : {}) }) + }, + }, + resource: projectPersistence.resource, + dispose: async () => { autosave.cancel(); await projectPersistence.dispose() }, + }, geometry: { capabilities: () => geometryRuntime.capabilities(), configureNativeHistory: (provider, timeoutMs) => geometryRuntime.configureNativeHistory(provider, timeoutMs), diff --git a/src/facade/projectStore.ts b/src/facade/projectStore.ts index 1fc2499..12251c8 100644 --- a/src/facade/projectStore.ts +++ b/src/facade/projectStore.ts @@ -9,7 +9,11 @@ type WorkerResponse = { id: number; ok: true; type: 'initialized'; capabilities: const unavailable: PersistenceCapabilities = { mode: 'unavailable', sqliteWasm: false, opfs: false, schemaVersion: 0, reason: 'Persistence Worker is unavailable in this environment.' } const clonePropertyValue = (value: PropertyValue): PropertyValue => { - if (Array.isArray(value)) return value.every((entry) => typeof entry === 'number') ? [...value] as number[] : [...value] as string[] + if (Array.isArray(value)) { + if (value.every((entry) => Array.isArray(entry))) return value.map((entry) => [...entry]) as PropertyValue + if (value.every((entry) => typeof entry === 'boolean')) return [...value] as boolean[] + return value.every((entry) => typeof entry === 'number') ? [...value] as number[] : [...value] as string[] + } if (!value || typeof value !== 'object') return value if ('position' in value && 'rotation' in value) return { position: { ...value.position }, rotation: { axis: { ...value.rotation.axis }, angle: value.rotation.angle } } if ('steps' in value && Array.isArray(value.steps)) return { steps: value.steps.map((step) => ({ ...step })) } @@ -90,6 +94,7 @@ export class SqliteProjectPersistence implements ProjectPersistenceClient { private nextRequestId = 0 private currentCapabilities = unavailable private initialized: Promise | null = null + private disposed = false private readonly fallbackSnapshots = new Map() private readonly fallbackCheckpoints = new Map>() private readonly fallbackResources = new Map() @@ -206,7 +211,9 @@ export class SqliteProjectPersistence implements ProjectPersistenceClient { put: (bytes: Uint8Array, mediaType: string) => this.writeQueue.run(() => this.withCrossTabWriteLock(async () => { await this.initialize() if (!this.worker) { - const hash = `memory-${[...bytes].map((value) => value.toString(16).padStart(2, '0')).join('')}` + if (!globalThis.crypto?.subtle) throw new Error('SHA-256 is unavailable for project resource storage.') + const digest = await globalThis.crypto.subtle.digest('SHA-256', bytes.slice().buffer) + const hash = [...new Uint8Array(digest)].map((value) => value.toString(16).padStart(2, '0')).join('') const existing = this.fallbackResources.get(hash) const resource = { hash, byteLength: bytes.byteLength, mediaType, refCount: (existing?.resource.refCount || 0) + 1 } this.fallbackResources.set(hash, { resource, bytes: new Uint8Array(bytes) }) @@ -241,12 +248,14 @@ export class SqliteProjectPersistence implements ProjectPersistenceClient { } async dispose() { + if (this.disposed) return await this.writeQueue.drain() if (this.worker) { await this.request({ type: 'dispose' }) this.worker.terminate() } this.changeChannel?.close() + this.disposed = true } private crossTabWriteLockMode(): 'web-locks' | 'local-queue' { @@ -266,6 +275,7 @@ export class SqliteProjectPersistence implements ProjectPersistenceClient { } private request(input: WorkerInput, transfer: Transferable[] = []) { + if (this.disposed) return Promise.reject(new Error('Persistence Worker has been disposed.')) if (!this.worker) return Promise.reject(new Error(this.currentCapabilities.reason)) const id = ++this.nextRequestId return new Promise((resolve, reject) => { diff --git a/src/facade/types.ts b/src/facade/types.ts index c8afece..ed9e662 100644 --- a/src/facade/types.ts +++ b/src/facade/types.ts @@ -3,7 +3,7 @@ import type { DependencyEdge, RecomputeSnapshot, RecomputePlan } from './depende import type { Quantity, QuantityDimension } from './units' import type { SketchConstraint, SketchExternalGeometry, SketchGeometry, SketchSnapshot, SketchSolveResult } from './sketcher' import type { RecomputeExecutionOptions, RecomputeExecutionResult } from './recomputeEngine' -import type { FcstdArchiveLimits, FcstdInspection, FcstdInstantiatedShape, FcstdPathEdit, FcstdShapeResourcePayload, FcstdStoredShapeResource, FcstdWriteOptions } from './fcstd' +import type { FcstdArchiveLimits, FcstdBoolListEdit, FcstdColorEdit, FcstdColorListEdit, FcstdDirectionEdit, FcstdFileEdit, FcstdIncludedFileEdit, FcstdIncludedFileResourcePayload, FcstdInspection, FcstdInstantiatedShape, FcstdMeasureAreaEdit, FcstdNumericPropertyEdit, FcstdPathEdit, FcstdShapeResourcePayload, FcstdStoredIncludedFileResource, FcstdStoredShapeResource, FcstdWriteOptions } from './fcstd' import type { NativeOcctHistoryCapabilities, NativeOcctHistoryProvider } from './nativeHistoryProtocol' import type { FacadeRuntimeProfile } from './runtimeProfile' import type { CamApi } from './cam' @@ -47,6 +47,21 @@ export type LinkSubListValue = { export type VectorValue = { x: number; y: number; z: number } +/** Canonical App::PropertyColor value returned by FreeCAD's Python API. */ +export type ColorValue = [number, number, number, number] + +/** Canonical ordered App::PropertyColorList value. */ +export type ColorListValue = ColorValue[] + +/** Portable App::PropertyFileIncluded identity; authoritative bytes live in the project resource store. */ +export type IncludedFileValue = { + schemaVersion: 1 + archiveName: string + resourceHash: string + byteLength: number + mediaType: string +} + export type PlacementValue = { position: VectorValue rotation: { axis: VectorValue; angle: number } @@ -87,16 +102,16 @@ export type ShapeResourceValue = { elementMapResource?: string } -export type PropertyValue = string | number | boolean | string[] | number[] | VectorValue | PlacementValue | AttachmentSupportValue | MultiTransformValue | PathPropertyValue | ShapeResourceValue | TopoRefValue | LinkSubValue | LinkSubListValue | null +export type PropertyValue = string | number | boolean | string[] | number[] | boolean[] | ColorValue | ColorListValue | IncludedFileValue | VectorValue | PlacementValue | AttachmentSupportValue | MultiTransformValue | PathPropertyValue | ShapeResourceValue | TopoRefValue | LinkSubValue | LinkSubListValue | null export type NativeEditablePropertyType = - | 'App::PropertyString' | 'App::PropertyLength' | 'App::PropertyDistance' | 'App::PropertyAngle' - | 'App::PropertyQuantityConstraint' | 'App::PropertyBool' | 'App::PropertyEnumeration' + | 'App::PropertyString' | 'App::PropertyLength' | 'App::PropertyDistance' | 'App::PropertyAngle' | 'App::PropertyAcceleration' | 'App::PropertyArea' + | 'App::PropertyQuantityConstraint' | 'App::PropertyBool' | 'App::PropertyBoolList' | 'App::PropertyEnumeration' | 'App::PropertyLink' | 'App::PropertyLinkHidden' | 'App::PropertyLinkSub' | 'App::PropertyLinkSubList' | 'App::PropertyLinkList' | 'App::PropertyStringList' | 'App::PropertyFloatList' - | 'App::PropertyIntegerList' | 'App::PropertyVector' | 'App::PropertyPlacement' + | 'App::PropertyIntegerList' | 'App::PropertyVector' | 'App::PropertyDirection' | 'App::PropertyFile' | 'App::PropertyFileIncluded' | 'App::PropertyPlacement' | 'App::PropertyMultiTransform' | 'Path::PropertyPath' | 'Part::PropertyPartShape' - | 'App::PropertyColor' | 'App::PropertyPercent' | 'App::PropertyFloat' + | 'App::PropertyColor' | 'App::PropertyColorList' | 'App::PropertyPercent' | 'App::PropertyFloat' | 'App::PropertyFloatConstraint' | 'App::PropertyPrecision' | 'App::PropertyInteger' | 'App::PropertyIntegerConstraint' @@ -159,6 +174,20 @@ export type SetPropertyInput = { objectId: string propertyName: string value: PropertyValue + /** Reject the mutation before emitting events when the caller observed an older document. */ + expectedDocumentVersion?: number + /** Property writes are synchronous; a pre-aborted signal cancels before the transaction opens. */ + signal?: AbortSignal +} + +export type SetIncludedFileInput = { + objectId: string + propertyName: string + fileName: string + bytes: Uint8Array + mediaType?: string + expectedDocumentVersion?: number + signal?: AbortSignal } export type AddDynamicPropertyInput = { @@ -907,6 +936,7 @@ export interface BitBybitWebCadFacade { load(documentId: string): Promise markDirty(): void setProperty(input: SetPropertyInput): void + setIncludedFile(input: SetIncludedFileInput): Promise addDynamicProperty(input: AddDynamicPropertyInput): ObjectPropertySnapshot removeDynamicProperty(input: RemoveDynamicPropertyInput): boolean renameDynamicProperty(input: RenameDynamicPropertyInput): boolean @@ -987,11 +1017,23 @@ export interface BitBybitWebCadFacade { inspect(bytes: Uint8Array, limits?: Partial): FcstdInspection extractShapes(bytes: Uint8Array, limits?: Partial): FcstdShapeResourcePayload[] storeShapes(bytes: Uint8Array, limits?: Partial): Promise + extractIncludedFiles(bytes: Uint8Array, limits?: Partial): FcstdIncludedFileResourcePayload[] + storeIncludedFiles(bytes: Uint8Array, limits?: Partial): Promise instantiateShape(bytes: Uint8Array, resourcePath: string, signal?: AbortSignal, limits?: Partial): Promise> serializeMetadata(document: DocumentSnapshot, options?: FcstdWriteOptions): Uint8Array - rewriteMetadata(bytes: Uint8Array, document: DocumentSnapshot, options?: Omit): Uint8Array + serializeMetadataWithResources(document: DocumentSnapshot, options?: FcstdWriteOptions): Promise + rewriteMetadata(bytes: Uint8Array, document: DocumentSnapshot, options?: FcstdWriteOptions): Uint8Array + rewriteMetadataWithResources(bytes: Uint8Array, document: DocumentSnapshot, options?: FcstdWriteOptions): Promise decodePath(bytes: Uint8Array, objectName: string, propertyName?: string): PathPropertyValue rewritePath(bytes: Uint8Array, edit: FcstdPathEdit): Uint8Array + rewriteNumeric(bytes: Uint8Array, edit: FcstdNumericPropertyEdit): Uint8Array + rewriteMeasureArea(bytes: Uint8Array, edit: FcstdMeasureAreaEdit): Uint8Array + rewriteBoolList(bytes: Uint8Array, edit: FcstdBoolListEdit): Uint8Array + rewriteColor(bytes: Uint8Array, edit: FcstdColorEdit): Uint8Array + rewriteColorList(bytes: Uint8Array, edit: FcstdColorListEdit): Uint8Array + rewriteDirection(bytes: Uint8Array, edit: FcstdDirectionEdit): Uint8Array + rewriteFile(bytes: Uint8Array, edit: FcstdFileEdit): Uint8Array + rewriteIncludedFile(bytes: Uint8Array, edit: FcstdIncludedFileEdit): Promise } resource: { put(bytes: Uint8Array, mediaType: string): Promise @@ -999,6 +1041,7 @@ export interface BitBybitWebCadFacade { release(hash: string): Promise sweep(): Promise } + dispose(): Promise } readonly geometry: { capabilities(): GeometryCapabilities diff --git a/src/facade/units.ts b/src/facade/units.ts index 1c4e0ed..57e2796 100644 --- a/src/facade/units.ts +++ b/src/facade/units.ts @@ -1,4 +1,4 @@ -export type QuantityDimension = 'dimensionless' | 'length' | 'angle' | 'area' | 'volume' | 'percent' +export type QuantityDimension = 'dimensionless' | 'length' | 'angle' | 'area' | 'volume' | 'acceleration' | 'percent' export type Quantity = { value: number @@ -24,6 +24,11 @@ const definitions: UnitDefinition[] = [ { id: 'mm3', symbol: 'mm3', dimension: 'volume', factor: 1 }, { id: 'cm3', symbol: 'cm3', dimension: 'volume', factor: 1_000 }, { id: 'm3', symbol: 'm3', dimension: 'volume', factor: 1_000_000_000 }, + { id: 'mm/s^2', symbol: 'mm/s^2', dimension: 'acceleration', factor: 1 }, + { id: 'cm/s^2', symbol: 'cm/s^2', dimension: 'acceleration', factor: 10 }, + { id: 'm/s^2', symbol: 'm/s^2', dimension: 'acceleration', factor: 1000 }, + { id: 'in/s^2', symbol: 'in/s^2', dimension: 'acceleration', factor: 25.4 }, + { id: 'ft/s^2', symbol: 'ft/s^2', dimension: 'acceleration', factor: 304.8 }, { id: 'deg', symbol: 'deg', dimension: 'angle', factor: 1 }, { id: 'rad', symbol: 'rad', dimension: 'angle', factor: 180 / Math.PI }, { id: '%', symbol: '%', dimension: 'percent', factor: 1 }, diff --git a/src/styles.css b/src/styles.css index d33dd2d..4398e5c 100644 --- a/src/styles.css +++ b/src/styles.css @@ -377,6 +377,10 @@ button:focus-visible, input:focus-visible, select:focus-visible { outline: 2px s .property-number { width: 100%; display: flex; align-items: center; gap: 4px; color: var(--text-muted); font-size: 9px; } .property-number .property-control { min-width: 0; } .property-link-control { color: var(--cyan); } +.property-included-file { width: 100%; min-width: 0; display: grid; gap: 3px; color: var(--text-soft); font-size: 9px; } +.property-included-file > span { overflow: hidden; text-align: right; text-overflow: ellipsis; white-space: nowrap; } +.property-included-file input[type="file"] { height: 26px; padding: 2px; font-size: 8px; text-align: left; } +.property-included-file input[type="file"]::file-selector-button { height: 20px; margin-right: 4px; border: 1px solid var(--line); border-radius: 2px; background: var(--bg-raised); color: var(--text-soft); font-size: 8px; } .property-link-sub { display: flex; min-width: 0; align-items: center; gap: 4px; color: var(--cyan); font-size: 10px; } .property-link-sub > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .property-link-sub .icon-button { width: 24px; height: 24px; flex: 0 0 24px; } @@ -387,7 +391,16 @@ button:focus-visible, input:focus-visible, select:focus-visible { outline: 2px s .property-link-sub-item > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .topology-repair { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; margin: 8px 0 0 34px; } .property-color { display: flex; align-items: center; gap: 5px; color: var(--text-muted); font-size: 9px; } -.property-color input { width: 22px; height: 18px; padding: 0; border: 1px solid var(--line); border-radius: 2px; background: transparent; } +.property-color input[type="color"] { width: 22px; height: 18px; flex: 0 0 22px; padding: 0; border: 1px solid var(--line); border-radius: 2px; background: transparent; } +.property-color-rgba { min-width: 0; } +.property-color .property-color-alpha { width: 50px; min-width: 0; height: 22px; padding: 2px 4px; font-size: 9px; } +.property-color-rgba span { min-width: 0; overflow: hidden; text-overflow: ellipsis; } +.property-color-list { width: 100%; display: grid; gap: 3px; padding: 3px 0; } +.property-color-list-item { min-width: 0; display: grid; grid-template-columns: 22px minmax(0, 1fr) 24px; align-items: center; gap: 3px; } +.property-color-list-item input[type="color"] { width: 22px; height: 18px; padding: 0; border: 1px solid var(--line); border-radius: 2px; background: transparent; } +.property-color-list-item .property-color-alpha { height: 22px; padding: 2px 4px; font-size: 9px; } +.property-color-list-item .icon-button, .property-color-list-actions .icon-button { width: 24px; height: 22px; } +.property-color-list-actions { display: flex; justify-content: flex-end; } .property-expression { min-height: 20px; display: flex; align-items: center; justify-content: flex-end; gap: 5px; color: var(--cyan); font-size: 9px; } @media (max-width: 1050px) { diff --git a/tests/propertyAccelerationFacade.test.ts b/tests/propertyAccelerationFacade.test.ts new file mode 100644 index 0000000..f49921d --- /dev/null +++ b/tests/propertyAccelerationFacade.test.ts @@ -0,0 +1,56 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { decodeFcstdPropertyValue } from '../src/facade/fcstd' +import { convertQuantity, quantityFromUnit } from '../src/facade/units' +import type { DocumentSnapshot } from '../src/facade/types' + +const fixture = (): DocumentSnapshot => ({ + id: 'property-acceleration-facade', + label: 'PropertyAcceleration Facade', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [ + { id: 'SourceTrajectory', label: 'Source trajectory', type: 'feature', state: 'valid' }, + { id: 'AccelerationProbe', label: 'Acceleration probe', type: 'feature', state: 'valid' }, + ], + objects: [ + { id: 'SourceTrajectory', typeId: 'Robot::TrajectoryObject', properties: [] }, + { + id: 'AccelerationProbe', + typeId: 'Robot::TrajectoryDressUpObject', + properties: [{ name: 'Acceleration', label: 'Acceleration', group: 'TrajectoryDressUp', scope: 'data', type: 'App::PropertyAcceleration', value: 1000, unit: 'mm/s^2', recompute: true }], + }, + ], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { SourceTrajectory: 'up-to-date', AccelerationProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +test('App::PropertyAcceleration uses the typed Facade and native FCStd Float codec', () => { + const facade = createWebCadFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['AccelerationProbe'], runtimeMode: 'mock' }) + const before = facade.app.document.getActive() + facade.app.document.setProperty({ objectId: 'AccelerationProbe', propertyName: 'Acceleration', value: 500 }) + const edited = facade.app.document.getActive() + const property = edited.objects.find((object) => object.id === 'AccelerationProbe')?.properties.find((candidate) => candidate.name === 'Acceleration') + assert.equal(property?.type, 'App::PropertyAcceleration') + assert.equal(property?.value, 500) + assert.equal(property?.unit, 'mm/s^2') + assert.equal(edited.version, before.version + 1) + assert.equal(edited.dirty, true) + assert.equal(edited.recompute?.objectStates.AccelerationProbe, 'touched') + assert.throws(() => facade.app.document.setProperty({ objectId: 'AccelerationProbe', propertyName: 'Acceleration', value: '500 mm/s^2' }), /finite numeric value/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'AccelerationProbe', propertyName: 'Acceleration', value: Number.POSITIVE_INFINITY }), /finite numeric value/) + + const archive = facade.project.fcstd.serializeMetadata(edited) + const documentXml = new TextDecoder().decode(unzipSync(archive)['Document.xml']) + assert.match(documentXml, /<\/Property><\/Properties><\/Object>/) + assert.doesNotMatch(documentXml, /]+group=/) + const summary = facade.project.fcstd.inspect(archive).objects.find((object) => object.name === 'AccelerationProbe')?.properties.find((candidate) => candidate.name === 'Acceleration') + assert.equal(summary?.typeId, 'App::PropertyAcceleration') + assert.equal(summary?.element, 'Float') + assert.deepEqual(decodeFcstdPropertyValue(summary!), { value: 500, decoded: true }) + assert.equal(convertQuantity(quantityFromUnit(9.81, 'm/s^2'), 'mm/s^2'), 9810) +}) diff --git a/tests/propertyAccelerationTransaction.test.ts b/tests/propertyAccelerationTransaction.test.ts new file mode 100644 index 0000000..f8365b0 --- /dev/null +++ b/tests/propertyAccelerationTransaction.test.ts @@ -0,0 +1,79 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { createWebCadFacade } from '../src/facade/mockFacade' +import type { DocumentSnapshot, FacadeEvent } from '../src/facade/types' + +const fixture = (): DocumentSnapshot => ({ + id: 'property-acceleration-transaction', + label: 'PropertyAcceleration Transaction', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [{ id: 'AccelerationProbe', label: 'Acceleration probe', type: 'feature', state: 'valid' }], + objects: [{ + id: 'AccelerationProbe', + typeId: 'Robot::TrajectoryDressUpObject', + properties: [{ name: 'Acceleration', label: 'Acceleration', group: 'TrajectoryDressUp', scope: 'data', type: 'App::PropertyAcceleration', value: 1000, unit: 'mm/s^2', recompute: true }], + }], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { AccelerationProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const acceleration = (facade: ReturnType) => facade.app.document.getObject('AccelerationProbe')?.properties.find((property) => property.name === 'Acceleration')?.value + +test('App::PropertyAcceleration transaction closes undo, redo, abort, stale, failure and resource ownership', () => { + const facade = createWebCadFacade({ initialDocument: fixture(), runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const resourcesBefore = facade.geometry.capabilities() + + facade.app.document.setProperty({ objectId: 'AccelerationProbe', propertyName: 'Acceleration', value: 500, expectedDocumentVersion: 1 }) + assert.equal(acceleration(facade), 500) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + const transactionIds = events.map((event) => 'transactionId' in event ? event.transactionId : '') + assert.equal(new Set(transactionIds).size, 1) + const committed = events[2] + assert.equal(committed.type, 'transaction.committed') + if (committed.type === 'transaction.committed') assert.deepEqual({ operation: committed.operation, beforeVersion: committed.beforeVersion, afterVersion: committed.afterVersion }, { operation: 'property.set', beforeVersion: 1, afterVersion: 2 }) + + facade.history.undo() + assert.equal(acceleration(facade), 1000) + assert.equal(facade.app.document.getActive().version, 1) + assert.equal(facade.history.canUndo(), false) + assert.equal(facade.history.canRedo(), true) + facade.history.redo() + assert.equal(acceleration(facade), 500) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const stableState = JSON.stringify(facade.app.document.getActive()) + const stableEvents = events.length + assert.throws(() => facade.app.document.setProperty({ objectId: 'AccelerationProbe', propertyName: 'Acceleration', value: 250, expectedDocumentVersion: 1 }), /Stale document version: expected 1, current 2/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stableState) + assert.equal(events.length, stableEvents) + + const cancelled = new AbortController() + cancelled.abort() + assert.throws(() => facade.app.document.setProperty({ objectId: 'AccelerationProbe', propertyName: 'Acceleration', value: 250, expectedDocumentVersion: 2, signal: cancelled.signal }), (error: unknown) => error instanceof DOMException && error.name === 'AbortError') + assert.equal(JSON.stringify(facade.app.document.getActive()), stableState) + assert.equal(events.length, stableEvents) + + assert.throws(() => facade.app.document.setProperty({ objectId: 'AccelerationProbe', propertyName: 'Acceleration', value: 'invalid' }), /finite numeric value/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stableState) + assert.equal(events.length, stableEvents) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const resourcesAfter = facade.geometry.capabilities() + assert.deepEqual( + { shapeCount: resourcesAfter.shapeCount, kernelReferenceCount: resourcesAfter.kernelReferenceCount, releasedShapeCount: resourcesAfter.releasedShapeCount }, + { shapeCount: resourcesBefore.shapeCount, kernelReferenceCount: resourcesBefore.kernelReferenceCount, releasedShapeCount: resourcesBefore.releasedShapeCount }, + ) +}) diff --git a/tests/propertyAreaFacade.test.ts b/tests/propertyAreaFacade.test.ts new file mode 100644 index 0000000..070c8ec --- /dev/null +++ b/tests/propertyAreaFacade.test.ts @@ -0,0 +1,94 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { decodeFcstdPropertyValue } from '../src/facade/fcstd' +import { encodeFreecadPropertyStatus } from '../src/facade/propertyStatus' +import type { DocumentSnapshot, FacadeEvent } from '../src/facade/types' + +const outputStatus = encodeFreecadPropertyStatus(['PropReadOnly', 'PropOutput']) +const faceEntry = (persistentId: string, area: number, index: number) => ({ + ref: { shapeId: 'AreaBox-shape', kind: 'face' as const, persistentId, topologyVersion: 1, status: 'stable' as const }, + signature: { kind: 'face' as const, canonical: persistentId, hash: persistentId, centroid: [index, 0, 0] as [number, number, number], bounds: { min: [index, 0, 0] as [number, number, number], max: [index + 1, 1, 0] as [number, number, number] }, area, normal: [0, 0, 1] as [number, number, number] }, +}) + +const fixture = (): DocumentSnapshot => ({ + id: 'property-area-facade', + label: 'PropertyArea Facade', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [ + { id: 'AreaBox', label: 'Area box', type: 'feature', state: 'valid' }, + { id: 'AreaProbe', label: 'Area probe', type: 'feature', state: 'valid' }, + ], + objects: [ + { + id: 'AreaBox', + typeId: 'Part::Box', + properties: [ + { name: 'Length', label: 'Length', group: 'Box', scope: 'data', type: 'App::PropertyLength', value: 10, unit: 'mm', recompute: true }, + { name: 'Width', label: 'Width', group: 'Box', scope: 'data', type: 'App::PropertyLength', value: 5, unit: 'mm', recompute: true }, + { name: 'Height', label: 'Height', group: 'Box', scope: 'data', type: 'App::PropertyLength', value: 2, unit: 'mm', recompute: true }, + ], + topology: { + shapeId: 'AreaBox-shape', + documentVersion: 1, + generation: 1, + entries: [faceEntry('box-face-1', 10, 0), faceEntry('box-face-2', 10, 1)], + migration: { previousGeneration: null, matches: [] }, + history: { operationId: 'AreaBox:1', provider: 'occt-native', relations: [], counts: { preserved: 0, modified: 0, generated: 0, deleted: 0, ambiguous: 0 } }, + }, + }, + { + id: 'AreaProbe', + typeId: 'Measure::MeasureArea', + properties: [ + { name: 'Area', label: 'Area', group: 'Measurement', scope: 'data', type: 'App::PropertyArea', value: 10, unit: 'mm^2', nativeStatus: outputStatus, readOnly: true, recompute: false }, + { name: 'Elements', label: 'Elements', group: 'Measurement', scope: 'data', type: 'App::PropertyLinkSubList', value: { schemaVersion: 1, entries: [{ objectId: 'AreaBox', subElement: 'Face1' }] }, recompute: true }, + ], + }, + ], + dependencies: [{ sourceId: 'AreaProbe', targetId: 'AreaBox', relation: 'topo-ref', propertyName: 'Elements', reference: 'Face1' }], + recompute: { generation: 0, status: 'idle', objectStates: { AreaBox: 'up-to-date', AreaProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +test('App::PropertyArea is a typed read-only Facade value with native FCStd codecs', () => { + const facade = createWebCadFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['AreaProbe'], runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => events.push(event)) + const before = facade.app.document.getActive() + const area = facade.app.document.getObject('AreaProbe')?.properties.find((property) => property.name === 'Area') + assert.deepEqual({ type: area?.type, value: area?.value, unit: area?.unit, nativeStatus: area?.nativeStatus, readOnly: area?.readOnly }, { type: 'App::PropertyArea', value: 10, unit: 'mm^2', nativeStatus: outputStatus, readOnly: true }) + assert.throws(() => facade.app.document.setProperty({ objectId: 'AreaProbe', propertyName: 'Area', value: 20 }), /Area is read-only/) + assert.deepEqual(facade.app.document.getActive(), before) + assert.equal(events.length, 0) + + facade.app.document.setProperty({ objectId: 'AreaProbe', propertyName: 'Elements', value: { schemaVersion: 1, entries: [{ objectId: 'AreaBox', subElement: 'Face1' }, { objectId: 'AreaBox', subElement: 'Face2' }] } }) + const edited = facade.app.document.getActive() + assert.equal(edited.objects.find((candidate) => candidate.id === 'AreaProbe')?.properties.find((property) => property.name === 'Area')?.value, 20) + assert.equal(edited.recompute?.objectStates.AreaProbe, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'state.changed', 'property.changed', 'transaction.committed', 'notice', 'state.changed']) + const stableEvents = events.length + assert.throws(() => facade.app.document.setProperty({ objectId: 'AreaProbe', propertyName: 'Elements', value: { schemaVersion: 1, entries: [{ objectId: 'AreaBox', subElement: 'Edge1' }] } }), /Cannot calculate area/) + assert.deepEqual(facade.app.document.getActive(), edited) + assert.equal(events.length, stableEvents) + + const archive = facade.project.fcstd.serializeMetadata(before) + const documentXml = new TextDecoder().decode(unzipSync(archive)['Document.xml']) + assert.match(documentXml, /`)) + assert.match(documentXml, /<\/LinkSubList><\/Property>/) + assert.doesNotMatch(documentXml, /]+group=/) + + const inspection = facade.project.fcstd.inspect(archive) + const object = inspection.objects.find((candidate) => candidate.name === 'AreaProbe') + assert.equal(object?.typeId, 'Measure::MeasureArea') + assert.equal(object?.support, 'recognized') + const areaSummary = object?.properties.find((property) => property.name === 'Area') + const elementsSummary = object?.properties.find((property) => property.name === 'Elements') + assert.deepEqual({ typeId: areaSummary?.typeId, element: areaSummary?.element, nativeStatus: areaSummary?.nativeStatus, statusNames: areaSummary?.statusNames }, { typeId: 'App::PropertyArea', element: 'Float', nativeStatus: outputStatus, statusNames: ['PropReadOnly', 'PropOutput'] }) + assert.deepEqual(decodeFcstdPropertyValue(areaSummary!), { value: 10, decoded: true }) + assert.deepEqual(decodeFcstdPropertyValue(elementsSummary!), { value: { schemaVersion: 1, entries: [{ objectId: 'AreaBox', subElement: 'Face1' }] }, decoded: true }) +}) diff --git a/tests/propertyAreaTransaction.test.ts b/tests/propertyAreaTransaction.test.ts new file mode 100644 index 0000000..ca2f752 --- /dev/null +++ b/tests/propertyAreaTransaction.test.ts @@ -0,0 +1,100 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { encodeFreecadPropertyStatus } from '../src/facade/propertyStatus' +import type { DocumentSnapshot, FacadeEvent } from '../src/facade/types' + +const faceEntry = (persistentId: string, area: number, index: number) => ({ + ref: { shapeId: 'AreaBox-shape', kind: 'face' as const, persistentId, topologyVersion: 1, status: 'stable' as const }, + signature: { kind: 'face' as const, canonical: persistentId, hash: persistentId, centroid: [index, 0, 0] as [number, number, number], bounds: { min: [index, 0, 0] as [number, number, number], max: [index + 1, 1, 0] as [number, number, number] }, area, normal: [0, 0, 1] as [number, number, number] }, +}) + +const fixture = (): DocumentSnapshot => ({ + id: 'property-area-transaction', + label: 'PropertyArea Transaction', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [{ id: 'AreaBox', label: 'Area box', type: 'feature', state: 'valid' }, { id: 'AreaProbe', label: 'Area probe', type: 'feature', state: 'valid' }], + objects: [ + { + id: 'AreaBox', + typeId: 'Part::Box', + properties: [], + topology: { + shapeId: 'AreaBox-shape', documentVersion: 1, generation: 1, + entries: [faceEntry('box-face-1', 10, 0), faceEntry('box-face-2', 10, 1)], + migration: { previousGeneration: null, matches: [] }, + history: { operationId: 'AreaBox:1', provider: 'occt-native', relations: [], counts: { preserved: 0, modified: 0, generated: 0, deleted: 0, ambiguous: 0 } }, + }, + }, + { + id: 'AreaProbe', + typeId: 'Measure::MeasureArea', + properties: [ + { name: 'Area', label: 'Area', group: 'Measurement', scope: 'data', type: 'App::PropertyArea', value: 10, unit: 'mm^2', nativeStatus: encodeFreecadPropertyStatus(['PropReadOnly', 'PropOutput']), readOnly: true, recompute: false }, + { name: 'Elements', label: 'Elements', group: 'Measurement', scope: 'data', type: 'App::PropertyLinkSubList', value: { schemaVersion: 1, entries: [{ objectId: 'AreaBox', subElement: 'Face1' }] }, recompute: true }, + ], + }, + ], + dependencies: [{ sourceId: 'AreaProbe', targetId: 'AreaBox', relation: 'link', propertyName: 'Elements', reference: 'Elements[0]' }], + recompute: { generation: 0, status: 'idle', objectStates: { AreaBox: 'up-to-date', AreaProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const propertyValue = (facade: ReturnType, name: 'Area' | 'Elements') => facade.app.document.getObject('AreaProbe')?.properties.find((property) => property.name === name)?.value + +test('App::PropertyArea transaction closes undo, redo, stale, cancel, failure and resource ownership', async () => { + const facade = createWebCadFacade({ initialDocument: fixture(), runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const resourcesBefore = facade.geometry.capabilities() + const editedElements = { schemaVersion: 1 as const, entries: [{ objectId: 'AreaBox', subElement: 'Face1' }, { objectId: 'AreaBox', subElement: 'Face2' }] } + + facade.app.document.setProperty({ objectId: 'AreaProbe', propertyName: 'Elements', value: editedElements, expectedDocumentVersion: 1 }) + assert.equal(propertyValue(facade, 'Area'), 20) + assert.deepEqual(propertyValue(facade, 'Elements'), editedElements) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().dirty, true) + assert.equal(facade.app.document.getActive().recompute?.objectStates.AreaProbe, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + assert.equal(new Set(events.map((event) => 'transactionId' in event ? event.transactionId : '')).size, 1) + const committed = events[2] + assert.equal(committed.type, 'transaction.committed') + if (committed.type === 'transaction.committed') assert.deepEqual({ operation: committed.operation, beforeVersion: committed.beforeVersion, afterVersion: committed.afterVersion }, { operation: 'property.set', beforeVersion: 1, afterVersion: 2 }) + + facade.history.undo() + assert.equal(propertyValue(facade, 'Area'), 10) + assert.deepEqual(propertyValue(facade, 'Elements'), { schemaVersion: 1, entries: [{ objectId: 'AreaBox', subElement: 'Face1' }] }) + assert.equal(facade.app.document.getActive().version, 1) + assert.equal(facade.history.canUndo(), false) + assert.equal(facade.history.canRedo(), true) + facade.history.redo() + assert.equal(propertyValue(facade, 'Area'), 20) + assert.deepEqual(propertyValue(facade, 'Elements'), editedElements) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const stableState = JSON.stringify(facade.app.document.getActive()) + const stableEvents = events.length + assert.throws(() => facade.app.document.setProperty({ objectId: 'AreaProbe', propertyName: 'Elements', value: { schemaVersion: 1, entries: [] }, expectedDocumentVersion: 1 }), /Stale document version: expected 1, current 2/) + const cancelled = new AbortController() + cancelled.abort() + assert.throws(() => facade.app.document.setProperty({ objectId: 'AreaProbe', propertyName: 'Elements', value: { schemaVersion: 1, entries: [] }, expectedDocumentVersion: 2, signal: cancelled.signal }), (error: unknown) => error instanceof DOMException && error.name === 'AbortError') + assert.throws(() => facade.app.document.setProperty({ objectId: 'AreaProbe', propertyName: 'Elements', value: { schemaVersion: 1, entries: [{ objectId: 'AreaBox', subElement: 'Edge1' }] }, expectedDocumentVersion: 2 }), /Cannot calculate area/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'AreaProbe', propertyName: 'Area', value: 30, expectedDocumentVersion: 2 }), /Area is read-only/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stableState) + assert.equal(events.length, stableEvents) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const resourcesAfter = facade.geometry.capabilities() + assert.deepEqual( + { shapeCount: resourcesAfter.shapeCount, kernelReferenceCount: resourcesAfter.kernelReferenceCount, releasedShapeCount: resourcesAfter.releasedShapeCount }, + { shapeCount: resourcesBefore.shapeCount, kernelReferenceCount: resourcesBefore.kernelReferenceCount, releasedShapeCount: resourcesBefore.releasedShapeCount }, + ) + await facade.project.dispose() +}) diff --git a/tests/propertyBoolListFacade.test.ts b/tests/propertyBoolListFacade.test.ts new file mode 100644 index 0000000..d978ca2 --- /dev/null +++ b/tests/propertyBoolListFacade.test.ts @@ -0,0 +1,73 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { decodeFcstdPropertyValue } from '../src/facade/fcstd' +import { encodeFreecadPropertyStatus } from '../src/facade/propertyStatus' +import type { DocumentSnapshot, FacadeEvent } from '../src/facade/types' + +const visibilityStatus = encodeFreecadPropertyStatus(['Immutable', 'Hidden', 'LockDynamic']) + +const fixture = (): DocumentSnapshot => ({ + id: 'property-boollist-facade', + label: 'PropertyBoolList Facade', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [ + { id: 'BoolListProbe', label: 'Bool list probe', type: 'feature', state: 'valid' }, + { id: 'VisibilityProbe', label: 'Visibility probe', type: 'feature', state: 'valid' }, + ], + objects: [ + { + id: 'BoolListProbe', + typeId: 'App::FeatureTest', + properties: [{ name: 'BoolList', label: 'Bool list', group: 'Test', scope: 'data', type: 'App::PropertyBoolList', value: [false], recompute: true }], + }, + { + id: 'VisibilityProbe', + typeId: 'App::Link', + properties: [{ name: 'VisibilityList', label: 'Visibility list', group: 'Link', scope: 'data', type: 'App::PropertyBoolList', value: [true, true], nativeStatus: visibilityStatus, hidden: true, readOnly: true, recompute: true }], + }, + ], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { BoolListProbe: 'up-to-date', VisibilityProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const valueOf = (facade: ReturnType, objectId: string, propertyName: string) => facade.app.document.getObject(objectId)?.properties.find((property) => property.name === propertyName)?.value + +test('App::PropertyBoolList uses typed boolean values and the native BoolList bitset codec', () => { + const facade = createWebCadFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['BoolListProbe'], runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + + facade.app.document.setProperty({ objectId: 'BoolListProbe', propertyName: 'BoolList', value: [true, false, true] }) + assert.deepEqual(valueOf(facade, 'BoolListProbe', 'BoolList'), [true, false, true]) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().recompute?.objectStates.BoolListProbe, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + + assert.throws(() => facade.app.document.setProperty({ objectId: 'BoolListProbe', propertyName: 'BoolList', value: [true, 1 as unknown as boolean] }), /boolean list/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'BoolListProbe', propertyName: 'BoolList', value: '101' }), /boolean list/) + assert.deepEqual(valueOf(facade, 'BoolListProbe', 'BoolList'), [true, false, true]) + + assert.throws(() => facade.app.document.setProperty({ objectId: 'VisibilityProbe', propertyName: 'VisibilityList', value: [false, true] }), /Visibility list is read-only/) + assert.deepEqual(valueOf(facade, 'VisibilityProbe', 'VisibilityList'), [true, true]) + + const archive = facade.project.fcstd.serializeMetadata(facade.app.document.getActive()) + const documentXml = new TextDecoder().decode(unzipSync(archive)['Document.xml']) + assert.match(documentXml, /<\/Property>/) + assert.match(documentXml, /<\/Property>/) + assert.doesNotMatch(documentXml, /]+group=/) + + const inspection = facade.project.fcstd.inspect(archive) + const object = inspection.objects.find((candidate) => candidate.name === 'BoolListProbe') + assert.equal(object?.support, 'recognized') + const summary = object?.properties.find((property) => property.name === 'BoolList') + assert.deepEqual({ typeId: summary?.typeId, element: summary?.element }, { typeId: 'App::PropertyBoolList', element: 'BoolList' }) + assert.deepEqual(decodeFcstdPropertyValue(summary!), { value: [true, false, true], decoded: true }) +}) diff --git a/tests/propertyBoolListTransaction.test.ts b/tests/propertyBoolListTransaction.test.ts new file mode 100644 index 0000000..0c9881f --- /dev/null +++ b/tests/propertyBoolListTransaction.test.ts @@ -0,0 +1,90 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { encodeFreecadPropertyStatus } from '../src/facade/propertyStatus' +import type { DocumentSnapshot, FacadeEvent } from '../src/facade/types' + +const fixture = (): DocumentSnapshot => ({ + id: 'property-boollist-transaction', + label: 'PropertyBoolList Transaction', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [ + { id: 'BoolListProbe', label: 'Bool list probe', type: 'feature', state: 'valid' }, + { id: 'VisibilityProbe', label: 'Visibility probe', type: 'feature', state: 'valid' }, + ], + objects: [ + { + id: 'BoolListProbe', + typeId: 'App::FeatureTest', + properties: [{ name: 'BoolList', label: 'Bool list', group: 'Test', scope: 'data', type: 'App::PropertyBoolList', value: [false], recompute: true }], + }, + { + id: 'VisibilityProbe', + typeId: 'App::Link', + properties: [{ name: 'VisibilityList', label: 'Visibility list', group: 'Link', scope: 'data', type: 'App::PropertyBoolList', value: [true, true], nativeStatus: encodeFreecadPropertyStatus(['Immutable', 'Hidden', 'LockDynamic']), hidden: true, readOnly: true, recompute: true }], + }, + ], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { BoolListProbe: 'up-to-date', VisibilityProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const valueOf = (facade: ReturnType, objectId = 'BoolListProbe', propertyName = 'BoolList') => facade.app.document.getObject(objectId)?.properties.find((property) => property.name === propertyName)?.value + +test('App::PropertyBoolList transaction closes undo, redo, stale, cancel, failure and resource ownership', async () => { + const facade = createWebCadFacade({ initialDocument: fixture(), runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const resourcesBefore = facade.geometry.capabilities() + const requested = [true, false, true] + + facade.app.document.setProperty({ objectId: 'BoolListProbe', propertyName: 'BoolList', value: requested, expectedDocumentVersion: 1 }) + requested[0] = false + assert.deepEqual(valueOf(facade), [true, false, true]) + const exposed = valueOf(facade) as boolean[] + exposed[1] = true + assert.deepEqual(valueOf(facade), [true, false, true]) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().dirty, true) + assert.equal(facade.app.document.getActive().recompute?.objectStates.BoolListProbe, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + assert.equal(new Set(events.map((event) => 'transactionId' in event ? event.transactionId : '')).size, 1) + const committed = events[2] + assert.equal(committed.type, 'transaction.committed') + if (committed.type === 'transaction.committed') assert.deepEqual({ operation: committed.operation, beforeVersion: committed.beforeVersion, afterVersion: committed.afterVersion }, { operation: 'property.set', beforeVersion: 1, afterVersion: 2 }) + + facade.history.undo() + assert.deepEqual(valueOf(facade), [false]) + assert.equal(facade.app.document.getActive().version, 1) + assert.equal(facade.history.canUndo(), false) + assert.equal(facade.history.canRedo(), true) + facade.history.redo() + assert.deepEqual(valueOf(facade), [true, false, true]) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const stableState = JSON.stringify(facade.app.document.getActive()) + const stableEvents = events.length + assert.throws(() => facade.app.document.setProperty({ objectId: 'BoolListProbe', propertyName: 'BoolList', value: [], expectedDocumentVersion: 1 }), /Stale document version: expected 1, current 2/) + const cancelled = new AbortController() + cancelled.abort() + assert.throws(() => facade.app.document.setProperty({ objectId: 'BoolListProbe', propertyName: 'BoolList', value: [], expectedDocumentVersion: 2, signal: cancelled.signal }), (error: unknown) => error instanceof DOMException && error.name === 'AbortError') + assert.throws(() => facade.app.document.setProperty({ objectId: 'BoolListProbe', propertyName: 'BoolList', value: [true, 'false' as unknown as boolean] }), /boolean list/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'VisibilityProbe', propertyName: 'VisibilityList', value: [false, true] }), /Visibility list is read-only/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stableState) + assert.equal(events.length, stableEvents) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const resourcesAfter = facade.geometry.capabilities() + assert.deepEqual( + { shapeCount: resourcesAfter.shapeCount, kernelReferenceCount: resourcesAfter.kernelReferenceCount, releasedShapeCount: resourcesAfter.releasedShapeCount }, + { shapeCount: resourcesBefore.shapeCount, kernelReferenceCount: resourcesBefore.kernelReferenceCount, releasedShapeCount: resourcesBefore.releasedShapeCount }, + ) + await facade.project.dispose() +}) diff --git a/tests/propertyColorFacade.test.ts b/tests/propertyColorFacade.test.ts new file mode 100644 index 0000000..65676fe --- /dev/null +++ b/tests/propertyColorFacade.test.ts @@ -0,0 +1,107 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { decodeFcstdPropertyValue, serializeFcstdMetadataArchive } from '../src/facade/fcstd' +import type { ColorValue, DocumentSnapshot, FacadeEvent, ObjectPropertySnapshot } from '../src/facade/types' + +const hosts: Array<[string, string, string, ColorValue]> = [ + ['FeatureTestColor', 'App::FeatureTest', 'Colour', [0, 0, 0, 1]], + ['FeatureTestExceptionColor', 'App::FeatureTestException', 'Colour', [0, 0, 0, 1]], + ['PartColor', 'App::Part', 'Color', [1, 1, 1, 0]], + ['AssemblyLinkColor', 'Assembly::AssemblyLink', 'Color', [1, 1, 1, 0]], + ['AssemblyObjectColor', 'Assembly::AssemblyObject', 'Color', [1, 1, 1, 0]], + ['AnnotationColor', 'TechDraw::DrawViewAnnotation', 'TextColor', [0, 0, 0, 1]], + ['DraftColor', 'TechDraw::DrawViewDraft', 'Color', [0, 0, 0, 1]], + ['SpreadsheetColor', 'TechDraw::DrawViewSpreadsheet', 'TextColor', [0, 0, 0, 1]], +] + +const colorProperty = (name: string, value: ColorValue): ObjectPropertySnapshot => ({ name, label: name, group: 'Color', scope: 'data', type: 'App::PropertyColor', value: [...value] as ColorValue, recompute: true }) + +const fixture = (): DocumentSnapshot => ({ + id: 'property-color-facade', + label: 'PropertyColor Facade', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: hosts.map(([id]) => ({ id, label: id, type: 'feature', state: 'valid' })), + objects: hosts.map(([id, typeId, propertyName, value], index) => ({ + id, + typeId, + properties: [ + colorProperty(propertyName, value), + ...(index === 0 ? [{ name: 'LineColor', label: 'Line color', group: 'Appearance', scope: 'view' as const, type: 'App::PropertyColor' as const, value: '#123456' }] : []), + ], + })), + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: Object.fromEntries(hosts.map(([id]) => [id, 'up-to-date'])), dirtyObjects: [], order: [], errors: [] }, +}) + +const valueOf = (facade: ReturnType, objectId: string, propertyName: string) => facade.app.document.getObject(objectId)?.properties.find((property) => property.name === propertyName)?.value + +test('App::PropertyColor data values use four RGBA channels while view values retain #RRGGBB', () => { + const facade = createWebCadFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['FeatureTestColor'], runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const target: ColorValue = [17 / 255, 34 / 255, 51 / 255, 68 / 255] + facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'Colour', value: target }) + target[0] = 1 + assert.deepEqual(valueOf(facade, 'FeatureTestColor', 'Colour'), [17 / 255, 34 / 255, 51 / 255, 68 / 255]) + const exposed = valueOf(facade, 'FeatureTestColor', 'Colour') as number[] + exposed[1] = 1 + assert.deepEqual(valueOf(facade, 'FeatureTestColor', 'Colour'), [17 / 255, 34 / 255, 51 / 255, 68 / 255]) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().recompute?.objectStates.FeatureTestColor, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + + facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'Colour', value: [2, -1, 0.5, 1.5] }) + assert.deepEqual(valueOf(facade, 'FeatureTestColor', 'Colour'), [2, -1, 0.5, 1.5]) + facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'LineColor', value: '#abcdef' }) + assert.equal(valueOf(facade, 'FeatureTestColor', 'LineColor'), '#abcdef') + + const stable = JSON.stringify(facade.app.document.getActive()) + assert.throws(() => facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'Colour', value: '#112233' }), /four finite RGBA channels/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'Colour', value: [0, 0, 0] }), /four finite RGBA channels/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'Colour', value: [0, 0, 0, Number.NaN] }), /four finite RGBA channels/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'LineColor', value: [0, 0, 0, 1] }), /#RRGGBB color/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stable) +}) + +test('App::PropertyColor serializes all eight native hosts with packed RRGGBBAA values', () => { + const document = fixture() + ;(document.objects[0].properties[0].value as ColorValue) = [17 / 255, 34 / 255, 51 / 255, 68 / 255] + const archive = serializeFcstdMetadataArchive(document) + const documentXml = new TextDecoder().decode(unzipSync(archive)['Document.xml']) + const guiXml = new TextDecoder().decode(unzipSync(archive)['GuiDocument.xml']) + assert.equal((documentXml.match(/type="App::PropertyColor"/g) ?? []).length, 8) + assert.match(documentXml, /<\/Property>/) + assert.match(documentXml, /<\/Property>/) + assert.match(documentXml, /<\/Property>/) + assert.doesNotMatch(documentXml, /]+(?:group|doc|attr|ro|hide)=/) + assert.match(guiXml, /<\/Property>/) + + const inspection = createWebCadFacade({ initialDocument: document, runtimeMode: 'mock' }).project.fcstd.inspect(archive) + assert.equal(inspection.objects.length, 8) + assert.ok(inspection.objects.every((object) => object.support === 'recognized')) + const summary = inspection.objects[0].properties.find((property) => property.name === 'Colour') + assert.deepEqual({ typeId: summary?.typeId, element: summary?.element, value: summary?.value }, { typeId: 'App::PropertyColor', element: 'PropertyColor', value: '287454020' }) + assert.deepEqual(decodeFcstdPropertyValue(summary!), { value: [17 / 255, 34 / 255, 51 / 255, 68 / 255], decoded: true }) + assert.equal(decodeFcstdPropertyValue({ name: 'Colour', typeId: 'App::PropertyColor', element: 'PropertyColor', value: '4294967296' }).decoded, false) + assert.equal(decodeFcstdPropertyValue({ name: 'Colour', typeId: 'App::PropertyColor', element: 'String', value: '287454020' }).decoded, false) + + const target: ColorValue = [51 / 255, 102 / 255, 153 / 255, 204 / 255] + const rewritten = createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteColor(archive, { + objectName: 'FeatureTestColor', + propertyName: 'Colour', + value: target, + expectedValue: [17 / 255, 34 / 255, 51 / 255, 68 / 255], + }) + const rewrittenProperty = createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.inspect(rewritten).objects[0].properties.find((property) => property.name === 'Colour') + assert.equal(rewrittenProperty?.value, '862362060') + assert.deepEqual(decodeFcstdPropertyValue(rewrittenProperty!), { value: target, decoded: true }) + assert.throws(() => createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteColor(archive, { objectName: 'FeatureTestColor', propertyName: 'Colour', value: target, expectedValue: [0, 0, 0, 1] }), /does not match expectedValue/) + assert.throws(() => createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteColor(archive, { objectName: 'FeatureTestColor', propertyName: 'Colour', value: [0, 0, 0, Number.NaN] }), /four finite RGBA channels/) +}) diff --git a/tests/propertyColorListFacade.test.ts b/tests/propertyColorListFacade.test.ts new file mode 100644 index 0000000..5348f81 --- /dev/null +++ b/tests/propertyColorListFacade.test.ts @@ -0,0 +1,137 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { unzipSync, zipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { decodeFcstdPropertyValue, serializeFcstdMetadataArchive } from '../src/facade/fcstd' +import type { ColorListValue, DocumentSnapshot, FacadeEvent, ObjectPropertySnapshot } from '../src/facade/types' + +const hosts: Array<[string, string]> = [ + ['FeatureTestColorList', 'App::FeatureTest'], + ['FeatureTestExceptionColorList', 'App::FeatureTestException'], +] + +const colorListProperty = (value: ColorListValue): ObjectPropertySnapshot => ({ + name: 'ColourList', + label: 'Colour list', + group: 'Color', + scope: 'data', + type: 'App::PropertyColorList', + value: value.map((color) => [...color]), + recompute: true, +}) + +const fixture = (): DocumentSnapshot => ({ + id: 'property-colorlist-facade', + label: 'PropertyColorList Facade', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: hosts.map(([id]) => ({ id, label: id, type: 'feature', state: 'valid' })), + objects: hosts.map(([id, typeId]) => ({ id, typeId, properties: [colorListProperty([[0, 0, 0, 1]])] })), + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: Object.fromEntries(hosts.map(([id]) => [id, 'up-to-date'])), dirtyObjects: [], order: [], errors: [] }, +}) + +const valueOf = (facade: ReturnType, objectId: string) => facade.app.document.getObject(objectId)?.properties.find((property) => property.name === 'ColourList')?.value + +test('App::PropertyColorList uses atomic ordered RGBA lists with deep snapshot isolation', () => { + const facade = createWebCadFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['FeatureTestColorList'], runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const target: ColorListValue = [ + [0.125, 0.375, 0.625, 0.875], + [17 / 255, 34 / 255, 51 / 255, 68 / 255], + ] + facade.app.document.setProperty({ objectId: 'FeatureTestColorList', propertyName: 'ColourList', value: target }) + target[0][0] = 1 + assert.deepEqual(valueOf(facade, 'FeatureTestColorList'), [ + [0.125, 0.375, 0.625, 0.875], + [17 / 255, 34 / 255, 51 / 255, 68 / 255], + ]) + const exposed = valueOf(facade, 'FeatureTestColorList') as ColorListValue + exposed[1][1] = 1 + assert.deepEqual(valueOf(facade, 'FeatureTestColorList'), [ + [0.125, 0.375, 0.625, 0.875], + [17 / 255, 34 / 255, 51 / 255, 68 / 255], + ]) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().recompute?.objectStates.FeatureTestColorList, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + + const stable = JSON.stringify(facade.app.document.getActive()) + const eventCount = events.length + assert.throws(() => facade.app.document.setProperty({ objectId: 'FeatureTestColorList', propertyName: 'ColourList', value: [[0, 0, 0, Number.NaN]] }), /list of four finite RGBA channels/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'FeatureTestColorList', propertyName: 'ColourList', value: [[0, 0, 0], [0, 0, 0, 1]] as unknown as ColorListValue }), /list of four finite RGBA channels/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'FeatureTestColorList', propertyName: 'ColourList', value: '#112233' }), /list of four finite RGBA channels/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stable) + assert.equal(events.length, eventCount) +}) + +test('App::PropertyColorList uses native external little-endian ColorList resources', () => { + const document = fixture() + document.objects[0].properties[0].value = [ + [17 / 255, 34 / 255, 51 / 255, 68 / 255], + [51 / 255, 102 / 255, 153 / 255, 204 / 255], + ] + document.objects[1].properties[0].value = [[0, 0, 0, 1]] + const archive = serializeFcstdMetadataArchive(document) + const files = unzipSync(archive) + const documentXml = new TextDecoder().decode(files['Document.xml']) + assert.equal((documentXml.match(/type="App::PropertyColorList"/g) ?? []).length, 2) + assert.match(documentXml, /<\/Property>/) + assert.match(documentXml, /<\/Property>/) + assert.doesNotMatch(documentXml, /]+(?:group|doc|attr|ro|hide)=/) + + const first = new DataView(files.ColourList.buffer, files.ColourList.byteOffset, files.ColourList.byteLength) + assert.equal(first.byteLength, 12) + assert.equal(first.getUint32(0, true), 2) + assert.equal(first.getUint32(4, true), 0x11223344) + assert.equal(first.getUint32(8, true), 0x336699cc) + const second = new DataView(files.ColourList1.buffer, files.ColourList1.byteOffset, files.ColourList1.byteLength) + assert.equal(second.byteLength, 8) + assert.equal(second.getUint32(0, true), 1) + assert.equal(second.getUint32(4, true), 0x000000ff) + + const inspection = createWebCadFacade({ initialDocument: document, runtimeMode: 'mock' }).project.fcstd.inspect(archive) + assert.ok(inspection.objects.every((object) => object.support === 'recognized')) + const summaries = inspection.objects.map((object) => object.properties.find((property) => property.name === 'ColourList')) + assert.ok(summaries.every((summary) => summary?.typeId === 'App::PropertyColorList' && summary.element === 'ColorList')) + assert.deepEqual(decodeFcstdPropertyValue(summaries[0]!), { value: document.objects[0].properties[0].value, decoded: true }) + assert.deepEqual(decodeFcstdPropertyValue(summaries[1]!), { value: document.objects[1].properties[0].value, decoded: true }) + assert.equal(decodeFcstdPropertyValue({ name: 'ColourList', typeId: 'App::PropertyColorList', element: 'String', value: '[]' }).decoded, false) + + const directlyRewritten = createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteColorList(archive, { + objectName: 'FeatureTestColorList', + propertyName: 'ColourList', + value: [[1, 0.5, 0.25, 0]], + expectedValue: document.objects[0].properties[0].value as ColorListValue, + }) + const directlyRewrittenSummary = createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.inspect(directlyRewritten).objects[0].properties.find((property) => property.name === 'ColourList') + assert.deepEqual(decodeFcstdPropertyValue(directlyRewrittenSummary!), { value: [[1, 128 / 255, 64 / 255, 0]], decoded: true }) + assert.throws(() => createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteColorList(archive, { objectName: 'FeatureTestColorList', propertyName: 'ColourList', value: [], expectedValue: [[0, 0, 0, 1]] }), /does not match expectedValue/) + assert.throws(() => createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteColorList(archive, { objectName: 'FeatureTestColorList', propertyName: 'ColourList', value: [[0, 0, 0, Number.NaN]] }), /list of four finite RGBA channels/) + + const replacement: ColorListValue = [[1, 0.5, 0.25, 0]] + document.objects[0].properties[0].value = replacement + const rewritten = createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteMetadata(archive, document) + const rewrittenSummary = createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.inspect(rewritten).objects[0].properties.find((property) => property.name === 'ColourList') + assert.deepEqual(decodeFcstdPropertyValue(rewrittenSummary!), { value: [ + [1, 128 / 255, 64 / 255, 0], + ], decoded: true }) + assert.equal(unzipSync(rewritten).ColourList.byteLength, 8) + + const emptyDocument = fixture() + emptyDocument.objects.forEach((object) => { object.properties[0].value = [] }) + const emptyFiles = unzipSync(serializeFcstdMetadataArchive(emptyDocument)) + assert.equal((new TextDecoder().decode(emptyFiles['Document.xml']).match(//g) ?? []).length, 2) + assert.equal(emptyFiles.ColourList, undefined) + const emptyInspection = createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.inspect(zipSync(emptyFiles)) + assert.ok(emptyInspection.objects.every((object) => decodeFcstdPropertyValue(object.properties.find((property) => property.name === 'ColourList')!).decoded)) + + const missingResource = { ...files } + delete missingResource.ColourList + assert.throws(() => createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.inspect(zipSync(missingResource)), /references missing resource: ColourList/) +}) diff --git a/tests/propertyColorListTransaction.test.ts b/tests/propertyColorListTransaction.test.ts new file mode 100644 index 0000000..fa327ec --- /dev/null +++ b/tests/propertyColorListTransaction.test.ts @@ -0,0 +1,102 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { encodeFreecadPropertyStatus } from '../src/facade/propertyStatus' +import type { ColorListValue, DocumentSnapshot, FacadeEvent } from '../src/facade/types' + +const fixture = (): DocumentSnapshot => ({ + id: 'property-colorlist-transaction', + label: 'PropertyColorList Transaction', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [ + { id: 'ColorListProbe', label: 'Color list probe', type: 'feature', state: 'valid' }, + { id: 'ImmutableColorListProbe', label: 'Immutable color list probe', type: 'feature', state: 'valid' }, + ], + objects: [ + { + id: 'ColorListProbe', + typeId: 'App::FeatureTest', + properties: [{ name: 'ColourList', label: 'Colour list', group: 'Test', scope: 'data', type: 'App::PropertyColorList', value: [[0, 0, 0, 1]], recompute: true }], + }, + { + id: 'ImmutableColorListProbe', + typeId: 'App::FeatureTestException', + properties: [{ name: 'ColourList', label: 'Immutable colour list', group: 'Test', scope: 'data', type: 'App::PropertyColorList', value: [[1, 1, 1, 0]], nativeStatus: encodeFreecadPropertyStatus(['Immutable']), readOnly: true, recompute: true }], + }, + ], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { ColorListProbe: 'up-to-date', ImmutableColorListProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const valueOf = (facade: ReturnType, objectId = 'ColorListProbe') => facade.app.document.getObject(objectId)?.properties.find((property) => property.name === 'ColourList')?.value + +test('App::PropertyColorList transaction closes undo, redo, stale, cancel, failure and resource ownership', async () => { + const facade = createWebCadFacade({ initialDocument: fixture(), runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const resourcesBefore = facade.geometry.capabilities() + const requested: ColorListValue = [ + [0.125, 0.375, 0.625, 0.875], + [17 / 255, 34 / 255, 51 / 255, 68 / 255], + ] + + facade.app.document.setProperty({ objectId: 'ColorListProbe', propertyName: 'ColourList', value: requested, expectedDocumentVersion: 1 }) + requested[0][0] = 1 + assert.deepEqual(valueOf(facade), [ + [0.125, 0.375, 0.625, 0.875], + [17 / 255, 34 / 255, 51 / 255, 68 / 255], + ]) + const exposed = valueOf(facade) as ColorListValue + exposed[1][1] = 1 + assert.deepEqual(valueOf(facade), [ + [0.125, 0.375, 0.625, 0.875], + [17 / 255, 34 / 255, 51 / 255, 68 / 255], + ]) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().dirty, true) + assert.equal(facade.app.document.getActive().recompute?.objectStates.ColorListProbe, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + assert.equal(new Set(events.map((event) => 'transactionId' in event ? event.transactionId : '')).size, 1) + const committed = events[2] + assert.equal(committed.type, 'transaction.committed') + if (committed.type === 'transaction.committed') assert.deepEqual({ operation: committed.operation, beforeVersion: committed.beforeVersion, afterVersion: committed.afterVersion }, { operation: 'property.set', beforeVersion: 1, afterVersion: 2 }) + + facade.history.undo() + assert.deepEqual(valueOf(facade), [[0, 0, 0, 1]]) + assert.equal(facade.app.document.getActive().version, 1) + assert.equal(facade.history.canUndo(), false) + assert.equal(facade.history.canRedo(), true) + facade.history.redo() + assert.deepEqual(valueOf(facade), [ + [0.125, 0.375, 0.625, 0.875], + [17 / 255, 34 / 255, 51 / 255, 68 / 255], + ]) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const stableState = JSON.stringify(facade.app.document.getActive()) + const stableEvents = events.length + assert.throws(() => facade.app.document.setProperty({ objectId: 'ColorListProbe', propertyName: 'ColourList', value: [], expectedDocumentVersion: 1 }), /Stale document version: expected 1, current 2/) + const cancelled = new AbortController() + cancelled.abort() + assert.throws(() => facade.app.document.setProperty({ objectId: 'ColorListProbe', propertyName: 'ColourList', value: [], expectedDocumentVersion: 2, signal: cancelled.signal }), (error: unknown) => error instanceof DOMException && error.name === 'AbortError') + assert.throws(() => facade.app.document.setProperty({ objectId: 'ColorListProbe', propertyName: 'ColourList', value: [[0, 0, 0, 1], [1, Number.NaN, 1, 1]] }), /list of four finite RGBA channels/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'ImmutableColorListProbe', propertyName: 'ColourList', value: [[0, 0, 0, 1]] }), /Immutable colour list is read-only/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stableState) + assert.equal(events.length, stableEvents) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const resourcesAfter = facade.geometry.capabilities() + assert.deepEqual( + { shapeCount: resourcesAfter.shapeCount, kernelReferenceCount: resourcesAfter.kernelReferenceCount, releasedShapeCount: resourcesAfter.releasedShapeCount }, + { shapeCount: resourcesBefore.shapeCount, kernelReferenceCount: resourcesBefore.kernelReferenceCount, releasedShapeCount: resourcesBefore.releasedShapeCount }, + ) + await facade.project.dispose() +}) diff --git a/tests/propertyColorTransaction.test.ts b/tests/propertyColorTransaction.test.ts new file mode 100644 index 0000000..6c1e255 --- /dev/null +++ b/tests/propertyColorTransaction.test.ts @@ -0,0 +1,90 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { encodeFreecadPropertyStatus } from '../src/facade/propertyStatus' +import type { ColorValue, DocumentSnapshot, FacadeEvent } from '../src/facade/types' + +const fixture = (): DocumentSnapshot => ({ + id: 'property-color-transaction', + label: 'PropertyColor Transaction', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [ + { id: 'ColorProbe', label: 'Color probe', type: 'feature', state: 'valid' }, + { id: 'ImmutableColorProbe', label: 'Immutable color probe', type: 'feature', state: 'valid' }, + ], + objects: [ + { + id: 'ColorProbe', + typeId: 'App::FeatureTest', + properties: [{ name: 'Colour', label: 'Colour', group: 'Test', scope: 'data', type: 'App::PropertyColor', value: [0, 0, 0, 1], recompute: true }], + }, + { + id: 'ImmutableColorProbe', + typeId: 'App::FeatureTest', + properties: [{ name: 'Colour', label: 'Immutable colour', group: 'Test', scope: 'data', type: 'App::PropertyColor', value: [1, 1, 1, 0], nativeStatus: encodeFreecadPropertyStatus(['Immutable']), readOnly: true, recompute: true }], + }, + ], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { ColorProbe: 'up-to-date', ImmutableColorProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const valueOf = (facade: ReturnType, objectId = 'ColorProbe') => facade.app.document.getObject(objectId)?.properties.find((property) => property.name === 'Colour')?.value + +test('App::PropertyColor transaction closes undo, redo, stale, cancel, failure and resource ownership', async () => { + const facade = createWebCadFacade({ initialDocument: fixture(), runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const resourcesBefore = facade.geometry.capabilities() + const requested: ColorValue = [0.125, 0.375, 0.625, 0.875] + + facade.app.document.setProperty({ objectId: 'ColorProbe', propertyName: 'Colour', value: requested, expectedDocumentVersion: 1 }) + requested[0] = 1 + assert.deepEqual(valueOf(facade), [0.125, 0.375, 0.625, 0.875]) + const exposed = valueOf(facade) as number[] + exposed[1] = 1 + assert.deepEqual(valueOf(facade), [0.125, 0.375, 0.625, 0.875]) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().dirty, true) + assert.equal(facade.app.document.getActive().recompute?.objectStates.ColorProbe, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + assert.equal(new Set(events.map((event) => 'transactionId' in event ? event.transactionId : '')).size, 1) + const committed = events[2] + assert.equal(committed.type, 'transaction.committed') + if (committed.type === 'transaction.committed') assert.deepEqual({ operation: committed.operation, beforeVersion: committed.beforeVersion, afterVersion: committed.afterVersion }, { operation: 'property.set', beforeVersion: 1, afterVersion: 2 }) + + facade.history.undo() + assert.deepEqual(valueOf(facade), [0, 0, 0, 1]) + assert.equal(facade.app.document.getActive().version, 1) + assert.equal(facade.history.canUndo(), false) + assert.equal(facade.history.canRedo(), true) + facade.history.redo() + assert.deepEqual(valueOf(facade), [0.125, 0.375, 0.625, 0.875]) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const stableState = JSON.stringify(facade.app.document.getActive()) + const stableEvents = events.length + assert.throws(() => facade.app.document.setProperty({ objectId: 'ColorProbe', propertyName: 'Colour', value: [0, 0, 0, 0], expectedDocumentVersion: 1 }), /Stale document version: expected 1, current 2/) + const cancelled = new AbortController() + cancelled.abort() + assert.throws(() => facade.app.document.setProperty({ objectId: 'ColorProbe', propertyName: 'Colour', value: [0, 0, 0, 0], expectedDocumentVersion: 2, signal: cancelled.signal }), (error: unknown) => error instanceof DOMException && error.name === 'AbortError') + assert.throws(() => facade.app.document.setProperty({ objectId: 'ColorProbe', propertyName: 'Colour', value: [0, 0, 0, Number.NaN] }), /four finite RGBA channels/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'ImmutableColorProbe', propertyName: 'Colour', value: [0, 0, 0, 1] }), /Immutable colour is read-only/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stableState) + assert.equal(events.length, stableEvents) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const resourcesAfter = facade.geometry.capabilities() + assert.deepEqual( + { shapeCount: resourcesAfter.shapeCount, kernelReferenceCount: resourcesAfter.kernelReferenceCount, releasedShapeCount: resourcesAfter.releasedShapeCount }, + { shapeCount: resourcesBefore.shapeCount, kernelReferenceCount: resourcesBefore.kernelReferenceCount, releasedShapeCount: resourcesBefore.releasedShapeCount }, + ) + await facade.project.dispose() +}) diff --git a/tests/propertyDirectionFacade.test.ts b/tests/propertyDirectionFacade.test.ts new file mode 100644 index 0000000..8a12a5d --- /dev/null +++ b/tests/propertyDirectionFacade.test.ts @@ -0,0 +1,101 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { decodeFcstdPropertyValue, serializeFcstdMetadataArchive } from '../src/facade/fcstd' +import type { DocumentSnapshot, FacadeEvent, ObjectPropertySnapshot, VectorValue } from '../src/facade/types' + +const hosts: Array<{ id: string; typeId: string; propertyName: string; group: string }> = [ + { id: 'DirectionMirror', typeId: 'Part::Mirroring', propertyName: 'Normal', group: 'Plane' }, + { id: 'DirectionProjection', typeId: 'Part::ProjectOnSurface', propertyName: 'Direction', group: 'Projection' }, +] + +const directionProperty = (name: string, group: string, value: VectorValue): ObjectPropertySnapshot => ({ + name, + label: name, + group, + scope: 'data', + type: 'App::PropertyDirection', + value: { ...value }, + unit: 'mm', + recompute: true, +}) + +const fixture = (): DocumentSnapshot => ({ + id: 'property-direction-facade', + label: 'PropertyDirection Facade', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: hosts.map(({ id }) => ({ id, label: id, type: 'feature', state: 'valid' })), + objects: hosts.map(({ id, typeId, propertyName, group }) => ({ id, typeId, properties: [directionProperty(propertyName, group, { x: 0, y: 0, z: 1 })] })), + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: Object.fromEntries(hosts.map(({ id }) => [id, 'up-to-date'])), dirtyObjects: [], order: [], errors: [] }, +}) + +const valueOf = (facade: ReturnType, objectId = 'DirectionMirror') => facade.app.document.getObject(objectId)?.properties[0].value as VectorValue + +test('App::PropertyDirection keeps finite non-normalized vectors isolated in Facade snapshots', () => { + const facade = createWebCadFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['DirectionMirror'], runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const target = { x: 0.25, y: -0.5, z: 1.5 } + facade.app.document.setProperty({ objectId: 'DirectionMirror', propertyName: 'Normal', value: target }) + target.x = 99 + assert.deepEqual(valueOf(facade), { x: 0.25, y: -0.5, z: 1.5 }) + const exposed = valueOf(facade) + exposed.y = 99 + assert.deepEqual(valueOf(facade), { x: 0.25, y: -0.5, z: 1.5 }) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().dirty, true) + assert.equal(facade.app.document.getActive().recompute?.objectStates.DirectionMirror, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + + facade.app.document.setProperty({ objectId: 'DirectionMirror', propertyName: 'Normal', value: { x: 0, y: 0, z: 0 } }) + assert.deepEqual(valueOf(facade), { x: 0, y: 0, z: 0 }) + const stable = JSON.stringify(facade.app.document.getActive()) + const eventCount = events.length + assert.throws(() => facade.app.document.setProperty({ objectId: 'DirectionMirror', propertyName: 'Normal', value: { x: Number.NaN, y: 0, z: 1 } }), /components must be finite/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'DirectionMirror', propertyName: 'Normal', value: [0, 0, 1] as unknown as VectorValue }), /requires a Vector value/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'DirectionMirror', propertyName: 'Normal', value: { x: 0, y: 1 } as unknown as VectorValue }), /components must be finite/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stable) + assert.equal(events.length, eventCount) +}) + +test('App::PropertyDirection uses its native TypeId around PropertyVector FCStd payloads', () => { + const document = fixture() + document.objects[0].properties[0].value = { x: 0.25, y: -0.5, z: 1.5 } + document.objects[1].properties[0].value = { x: 1, y: 2, z: 3 } + const archive = serializeFcstdMetadataArchive(document) + const documentXml = new TextDecoder().decode(unzipSync(archive)['Document.xml']) + assert.match(documentXml, /<\/Property>/) + assert.match(documentXml, /<\/Property>/) + assert.doesNotMatch(documentXml, /]+(?:group|doc|attr|ro|hide)=/) + + const inspection = createWebCadFacade({ initialDocument: document, runtimeMode: 'mock' }).project.fcstd.inspect(archive) + assert.equal(inspection.objects.filter(({ support }) => support === 'recognized').length, 2) + for (const [index, host] of hosts.entries()) { + const object = inspection.objects.find(({ name }) => name === host.id) + assert.equal(object?.support, 'recognized') + const summary = object?.properties.find(({ name }) => name === host.propertyName) + assert.deepEqual({ typeId: summary?.typeId, element: summary?.element }, { typeId: 'App::PropertyDirection', element: 'PropertyVector' }) + assert.deepEqual(decodeFcstdPropertyValue(summary!), { value: document.objects[index].properties[0].value, decoded: true }) + } + assert.equal(decodeFcstdPropertyValue({ name: 'Normal', typeId: 'App::PropertyDirection', element: 'String', value: '{"x":0,"y":0,"z":1}' }).decoded, false) + + const rewritten = createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteDirection(archive, { + objectName: 'DirectionMirror', + propertyName: 'Normal', + value: { x: 3, y: -2, z: 0.5 }, + expectedValue: { x: 0.25, y: -0.5, z: 1.5 }, + }) + const rewrittenProperty = createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.inspect(rewritten).objects[0].properties.find(({ name }) => name === 'Normal') + assert.deepEqual(decodeFcstdPropertyValue(rewrittenProperty!), { value: { x: 3, y: -2, z: 0.5 }, decoded: true }) + assert.throws(() => createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteDirection(archive, { objectName: 'DirectionMirror', propertyName: 'Normal', value: { x: 1, y: 0, z: 0 }, expectedValue: { x: 0, y: 0, z: 1 } }), /does not match expectedValue/) + assert.throws(() => createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteDirection(archive, { objectName: 'DirectionMirror', propertyName: 'Normal', value: { x: Number.NaN, y: 0, z: 1 } }), /value.x must be finite/) +}) diff --git a/tests/propertyDirectionTransaction.test.ts b/tests/propertyDirectionTransaction.test.ts new file mode 100644 index 0000000..0860d36 --- /dev/null +++ b/tests/propertyDirectionTransaction.test.ts @@ -0,0 +1,90 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { encodeFreecadPropertyStatus } from '../src/facade/propertyStatus' +import type { DocumentSnapshot, FacadeEvent, VectorValue } from '../src/facade/types' + +const fixture = (): DocumentSnapshot => ({ + id: 'property-direction-transaction', + label: 'PropertyDirection Transaction', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [ + { id: 'DirectionProbe', label: 'Direction probe', type: 'feature', state: 'valid' }, + { id: 'ImmutableDirectionProbe', label: 'Immutable direction probe', type: 'feature', state: 'valid' }, + ], + objects: [ + { + id: 'DirectionProbe', + typeId: 'Part::Mirroring', + properties: [{ name: 'Normal', label: 'Normal', group: 'Plane', scope: 'data', type: 'App::PropertyDirection', value: { x: 0, y: 0, z: 1 }, recompute: true }], + }, + { + id: 'ImmutableDirectionProbe', + typeId: 'Part::Mirroring', + properties: [{ name: 'Normal', label: 'Immutable normal', group: 'Plane', scope: 'data', type: 'App::PropertyDirection', value: { x: 0, y: 1, z: 0 }, nativeStatus: encodeFreecadPropertyStatus(['Immutable']), readOnly: true, recompute: true }], + }, + ], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { DirectionProbe: 'up-to-date', ImmutableDirectionProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const valueOf = (facade: ReturnType, objectId = 'DirectionProbe') => facade.app.document.getObject(objectId)?.properties.find((property) => property.name === 'Normal')?.value as VectorValue + +test('App::PropertyDirection transaction closes undo, redo, stale, cancel, failure and resource ownership', async () => { + const facade = createWebCadFacade({ initialDocument: fixture(), runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const resourcesBefore = facade.geometry.capabilities() + const requested: VectorValue = { x: 0.25, y: -0.5, z: 1.5 } + + facade.app.document.setProperty({ objectId: 'DirectionProbe', propertyName: 'Normal', value: requested, expectedDocumentVersion: 1 }) + requested.x = 99 + assert.deepEqual(valueOf(facade), { x: 0.25, y: -0.5, z: 1.5 }) + const exposed = valueOf(facade) + exposed.y = 99 + assert.deepEqual(valueOf(facade), { x: 0.25, y: -0.5, z: 1.5 }) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().dirty, true) + assert.equal(facade.app.document.getActive().recompute?.objectStates.DirectionProbe, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + assert.equal(new Set(events.map((event) => 'transactionId' in event ? event.transactionId : '')).size, 1) + const committed = events[2] + assert.equal(committed.type, 'transaction.committed') + if (committed.type === 'transaction.committed') assert.deepEqual({ operation: committed.operation, beforeVersion: committed.beforeVersion, afterVersion: committed.afterVersion }, { operation: 'property.set', beforeVersion: 1, afterVersion: 2 }) + + facade.history.undo() + assert.deepEqual(valueOf(facade), { x: 0, y: 0, z: 1 }) + assert.equal(facade.app.document.getActive().version, 1) + assert.equal(facade.history.canUndo(), false) + assert.equal(facade.history.canRedo(), true) + facade.history.redo() + assert.deepEqual(valueOf(facade), { x: 0.25, y: -0.5, z: 1.5 }) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const stableState = JSON.stringify(facade.app.document.getActive()) + const stableEvents = events.length + assert.throws(() => facade.app.document.setProperty({ objectId: 'DirectionProbe', propertyName: 'Normal', value: { x: 0, y: 0, z: 0 }, expectedDocumentVersion: 1 }), /Stale document version: expected 1, current 2/) + const cancelled = new AbortController() + cancelled.abort() + assert.throws(() => facade.app.document.setProperty({ objectId: 'DirectionProbe', propertyName: 'Normal', value: { x: 0, y: 0, z: 0 }, expectedDocumentVersion: 2, signal: cancelled.signal }), (error: unknown) => error instanceof DOMException && error.name === 'AbortError') + assert.throws(() => facade.app.document.setProperty({ objectId: 'DirectionProbe', propertyName: 'Normal', value: { x: 0, y: Number.POSITIVE_INFINITY, z: 1 } }), /components must be finite/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'ImmutableDirectionProbe', propertyName: 'Normal', value: { x: 0, y: 0, z: 1 } }), /Immutable normal is read-only/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stableState) + assert.equal(events.length, stableEvents) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const resourcesAfter = facade.geometry.capabilities() + assert.deepEqual( + { shapeCount: resourcesAfter.shapeCount, kernelReferenceCount: resourcesAfter.kernelReferenceCount, releasedShapeCount: resourcesAfter.releasedShapeCount }, + { shapeCount: resourcesBefore.shapeCount, kernelReferenceCount: resourcesBefore.kernelReferenceCount, releasedShapeCount: resourcesBefore.releasedShapeCount }, + ) + await facade.project.dispose() +}) diff --git a/tests/propertyFileFacade.test.ts b/tests/propertyFileFacade.test.ts new file mode 100644 index 0000000..65734b6 --- /dev/null +++ b/tests/propertyFileFacade.test.ts @@ -0,0 +1,67 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { unzipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { decodeFcstdPropertyValue } from '../src/facade/fcstd' +import type { DocumentSnapshot, FacadeEvent } from '../src/facade/types' + +const fixture = (): DocumentSnapshot => ({ + id: 'property-file-facade', + label: 'PropertyFile Facade', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [{ id: 'FileProbe', label: 'File probe', type: 'feature', state: 'valid' }], + objects: [{ id: 'FileProbe', typeId: 'Mesh::Import', properties: [{ name: 'FileName', label: 'File name', group: '', scope: 'data', type: 'App::PropertyFile', value: 'mesh-data/cube.stl', recompute: true }] }], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { FileProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +test('App::PropertyFile accepts only project-relative resource references through the Facade', () => { + const facade = createWebCadFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['FileProbe'], runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + facade.app.document.setProperty({ objectId: 'FileProbe', propertyName: 'FileName', value: 'project-files/updated.stl' }) + assert.equal(facade.app.document.getObject('FileProbe')?.properties[0].value, 'project-files/updated.stl') + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().dirty, true) + assert.equal(facade.app.document.getActive().recompute?.objectStates.FileProbe, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + + const stable = JSON.stringify(facade.app.document.getActive()) + for (const value of ['/home/user/model.stl', '../model.stl', 'folder/../model.stl', 'C:\\model.stl', 'https://example.test/model.stl', 'folder\\model.stl', 'folder//model.stl', `model\0.stl`]) { + assert.throws(() => facade.app.document.setProperty({ objectId: 'FileProbe', propertyName: 'FileName', value }), /safe project-relative file reference/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stable) + } + assert.throws(() => facade.app.document.setProperty({ objectId: 'FileProbe', propertyName: 'FileName', value: 42 as unknown as string }), /project-relative file reference/) +}) + +test('App::PropertyFile uses the native String element and keeps unsafe host paths non-editable', () => { + const document = fixture() + const facade = createWebCadFacade({ initialDocument: document, runtimeMode: 'mock' }) + const archive = facade.project.fcstd.serializeMetadata(document) + const documentXml = new TextDecoder().decode(unzipSync(archive)['Document.xml']) + assert.match(documentXml, /<\/Property>/) + const inspection = facade.project.fcstd.inspect(archive) + const object = inspection.objects.find(({ name }) => name === 'FileProbe') + assert.equal(object?.support, 'recognized') + const summary = object?.properties.find(({ name }) => name === 'FileName') + assert.deepEqual({ typeId: summary?.typeId, element: summary?.element }, { typeId: 'App::PropertyFile', element: 'String' }) + assert.deepEqual(decodeFcstdPropertyValue(summary!), { value: 'mesh-data/cube.stl', decoded: true }) + assert.equal(decodeFcstdPropertyValue({ name: 'FileName', typeId: 'App::PropertyFile', element: 'String', value: '/home/user/model.stl' }).decoded, false) + assert.equal(decodeFcstdPropertyValue({ name: 'FileName', typeId: 'App::PropertyFile', element: 'PropertyFile', value: 'mesh-data/cube.stl' }).decoded, false) + + const rewritten = facade.project.fcstd.rewriteFile(archive, { objectName: 'FileProbe', propertyName: 'FileName', value: 'project-files/rewritten.stl', expectedValue: 'mesh-data/cube.stl' }) + const rewrittenProperty = facade.project.fcstd.inspect(rewritten).objects[0].properties.find(({ name }) => name === 'FileName') + assert.deepEqual(decodeFcstdPropertyValue(rewrittenProperty!), { value: 'project-files/rewritten.stl', decoded: true }) + assert.match(new TextDecoder().decode(unzipSync(rewritten)['Document.xml']), /]*name="FileProbe")(?=[^>]*type="Mesh::Import")(?=[^>]*Touched="1")[^>]*\/>/) + assert.throws(() => facade.project.fcstd.rewriteFile(archive, { objectName: 'FileProbe', propertyName: 'FileName', value: 'project-files/rewritten.stl', expectedValue: 'mesh-data/other.stl' }), /does not match expectedValue/) + assert.throws(() => facade.project.fcstd.rewriteFile(archive, { objectName: 'FileProbe', propertyName: 'FileName', value: '/home/user/model.stl' }), /safe project-relative file reference/) + + document.objects[0].properties[0].value = '/home/user/model.stl' + assert.throws(() => facade.project.fcstd.serializeMetadata(document), /safe project-relative file reference/) +}) diff --git a/tests/propertyFileIncludedFacade.test.ts b/tests/propertyFileIncludedFacade.test.ts new file mode 100644 index 0000000..96a278d --- /dev/null +++ b/tests/propertyFileIncludedFacade.test.ts @@ -0,0 +1,151 @@ +import { createHash } from 'node:crypto' +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { unzipSync, zipSync } from 'fflate' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { decodeFcstdPropertyValue } from '../src/facade/fcstd' +import { encodeFreecadPropertyStatus } from '../src/facade/propertyStatus' +import type { DocumentSnapshot, FacadeEvent, IncludedFileValue, ObjectPropertySnapshot } from '../src/facade/types' + +const hosts: Array<{ id: string; typeId: string; properties: Array<{ name: string; status?: 'ReadOnly' | 'PropOutput' }> }> = [ + { id: 'IncludedProbe', typeId: 'App::DocumentObjectFileIncluded', properties: [{ name: 'File' }] }, + { id: 'VrmlProbe', typeId: 'App::VRMLObject', properties: [{ name: 'VrmlFile' }] }, + { id: 'ImagePlaneProbe', typeId: 'Image::ImagePlane', properties: [{ name: 'ImageFile' }] }, + { id: 'RobotProbe', typeId: 'Robot::RobotObject', properties: [{ name: 'RobotKinematicFile' }, { name: 'RobotVrmlFile' }] }, + { id: 'SketchFlatProbe', typeId: 'Sketcher::SketchObjectSF', properties: [{ name: 'SketchFlatFile' }] }, + { id: 'ComplexSectionProbe', typeId: 'TechDraw::DrawComplexSection', properties: [{ name: 'PatIncluded', status: 'ReadOnly' }, { name: 'SvgIncluded', status: 'ReadOnly' }] }, + { id: 'ComplexSectionPythonProbe', typeId: 'TechDraw::DrawComplexSectionPython', properties: [{ name: 'PatIncluded', status: 'ReadOnly' }, { name: 'SvgIncluded', status: 'ReadOnly' }] }, + { id: 'GeomHatchProbe', typeId: 'TechDraw::DrawGeomHatch', properties: [{ name: 'PatIncluded' }] }, + { id: 'HatchProbe', typeId: 'TechDraw::DrawHatch', properties: [{ name: 'SvgIncluded' }] }, + { id: 'SvgTemplateProbe', typeId: 'TechDraw::DrawSVGTemplate', properties: [{ name: 'PageResult', status: 'PropOutput' }] }, + { id: 'TileWeldProbe', typeId: 'TechDraw::DrawTileWeld', properties: [{ name: 'SymbolIncluded' }] }, + { id: 'TileWeldPythonProbe', typeId: 'TechDraw::DrawTileWeldPython', properties: [{ name: 'SymbolIncluded' }] }, + { id: 'ViewImageProbe', typeId: 'TechDraw::DrawViewImage', properties: [{ name: 'ImageIncluded' }] }, + { id: 'ViewSectionProbe', typeId: 'TechDraw::DrawViewSection', properties: [{ name: 'PatIncluded', status: 'ReadOnly' }, { name: 'SvgIncluded', status: 'ReadOnly' }] }, + { id: 'ViewSectionPythonProbe', typeId: 'TechDraw::DrawViewSectionPython', properties: [{ name: 'PatIncluded', status: 'ReadOnly' }, { name: 'SvgIncluded', status: 'ReadOnly' }] }, +] + +const property = (name: string, value: IncludedFileValue | null, status?: 'ReadOnly' | 'PropOutput'): ObjectPropertySnapshot => ({ + name, + label: name, + group: 'Resource', + scope: 'data', + type: 'App::PropertyFileIncluded', + value, + ...(status ? { nativeStatus: encodeFreecadPropertyStatus([status]) } : {}), + recompute: true, +}) + +const fixture = (value?: (objectId: string, propertyName: string, index: number) => IncludedFileValue | null): DocumentSnapshot => { + let index = 0 + return { + id: 'property-fileincluded-facade', + label: 'PropertyFileIncluded Facade', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: hosts.map(({ id }) => ({ id, label: id, type: 'feature', state: 'valid' })), + objects: hosts.map((host) => ({ id: host.id, typeId: host.typeId, properties: host.properties.map(({ name, status }) => property(name, value?.(host.id, name, index++) ?? null, status)) })), + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: Object.fromEntries(hosts.map(({ id }) => [id, 'up-to-date'])), dirtyObjects: [], order: [], errors: [] }, + } +} + +test('App::PropertyFileIncluded stores authoritative bytes before committing a structured Facade value', async () => { + const facade = createWebCadFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['IncludedProbe'], runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const bytes = new Uint8Array([0, 255, 17, 42, 99]) + const first = await facade.app.document.setIncludedFile({ objectId: 'IncludedProbe', propertyName: 'File', fileName: 'payload.bin', bytes }) + bytes[0] = 88 + assert.match(first.resourceHash, /^[a-f0-9]{64}$/) + assert.deepEqual(first, { schemaVersion: 1, archiveName: 'payload.bin', resourceHash: first.resourceHash, byteLength: 5, mediaType: 'application/octet-stream' }) + assert.deepEqual(facade.app.document.getObject('IncludedProbe')?.properties[0].value, first) + assert.deepEqual([...(await facade.project.resource.get(first.resourceHash))!], [0, 255, 17, 42, 99]) + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + + const second = await facade.app.document.setIncludedFile({ objectId: 'RobotProbe', propertyName: 'RobotKinematicFile', fileName: 'payload.bin', bytes: new Uint8Array([1, 2, 3]), mediaType: 'text/csv' }) + assert.equal(second.archiveName, 'payload1.bin') + assert.equal(second.mediaType, 'text/csv') + + const stable = JSON.stringify(facade.app.document.getActive()) + assert.throws(() => facade.app.document.setProperty({ objectId: 'IncludedProbe', propertyName: 'File', value: null }), /cannot be cleared/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'IncludedProbe', propertyName: 'File', value: { ...first, archiveName: '../payload.bin' } }), /safe file basename/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'IncludedProbe', propertyName: 'File', value: { ...first, resourceHash: 'not-a-hash' } }), /SHA-256/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'IncludedProbe', propertyName: 'File', value: { ...first, byteLength: -1 } }), /byteLength/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stable) + await assert.rejects(facade.app.document.setIncludedFile({ objectId: 'ComplexSectionProbe', propertyName: 'PatIncluded', fileName: 'pattern.pat', bytes: new Uint8Array([1]) }), /read-only/) + await facade.project.dispose() +}) + +test('App::PropertyFileIncluded writes, inspects, extracts and stores all 20 native host properties', async () => { + const payload = new Uint8Array([60, 115, 118, 103, 62, 0, 255, 60, 47, 115, 118, 103, 62]) + const resourceHash = createHash('sha256').update(payload).digest('hex') + const document = fixture((_objectId, propertyName, index) => ({ schemaVersion: 1, archiveName: `${String(index).padStart(2, '0')}-${propertyName}.bin`, resourceHash, byteLength: payload.byteLength, mediaType: 'application/octet-stream' })) + const facade = createWebCadFacade({ initialDocument: document, runtimeMode: 'mock' }) + const stored = await facade.project.resource.put(payload, 'application/octet-stream') + assert.equal(stored.hash, resourceHash) + assert.throws(() => facade.project.fcstd.serializeMetadata(document), /missing project resource bytes/) + + const archive = await facade.project.fcstd.serializeMetadataWithResources(document) + const files = unzipSync(archive) + const documentXml = new TextDecoder().decode(files['Document.xml']) + assert.equal((documentXml.match(/type="App::PropertyFileIncluded"/g) ?? []).length, 20) + assert.equal((documentXml.match(//g) ?? []).length, 20) + for (const match of documentXml.matchAll(/]+type="App::PropertyFileIncluded"[^>]*>/g)) assert.doesNotMatch(match[0], /\s(?:group|doc|attr|ro|hide)=/) + const archiveNames = document.objects.flatMap((object) => object.properties.map((candidate) => (candidate.value as IncludedFileValue).archiveName)) + assert.equal(new Set(archiveNames).size, 20) + for (const archiveName of archiveNames) assert.deepEqual([...files[archiveName]], [...payload]) + + const inspection = facade.project.fcstd.inspect(archive) + const summaries = inspection.objects.flatMap((object) => object.properties.filter((candidate) => candidate.typeId === 'App::PropertyFileIncluded')) + assert.equal(summaries.length, 20) + assert.ok(summaries.every((summary) => summary.element === 'FileIncluded' && summary.includedFileResource?.byteLength === payload.byteLength && summary.includedFileResource.contentHash.length === 8)) + assert.equal(decodeFcstdPropertyValue(summaries[0]).decoded, false) + const extracted = facade.project.fcstd.extractIncludedFiles(archive) + assert.equal(extracted.length, 20) + assert.ok(extracted.every((resource) => resource.references.length === 1 && resource.byteLength === payload.byteLength && resource.bytes.every((byte, index) => byte === payload[index]))) + const imported = await facade.project.fcstd.storeIncludedFiles(archive) + assert.equal(imported.length, 20) + assert.ok(imported.every((resource) => resource.hash === resourceHash && resource.value.resourceHash === resourceHash && resource.value.archiveName === resource.path)) + + const missing = { ...files } + delete missing[archiveNames[0]] + assert.throws(() => facade.project.fcstd.inspect(zipSync(missing)), /references missing resource/) + const emptyDocument = fixture() + const emptyArchive = facade.project.fcstd.serializeMetadata(emptyDocument) + const emptySummary = facade.project.fcstd.inspect(emptyArchive).objects[0].properties.find((candidate) => candidate.typeId === 'App::PropertyFileIncluded')! + assert.match(new TextDecoder().decode(unzipSync(emptyArchive)['Document.xml']), //) + assert.deepEqual(decodeFcstdPropertyValue(emptySummary), { value: null, decoded: true }) + await facade.project.dispose() +}) + +test('App::PropertyFileIncluded rewrites one native resource through project resource identities', async () => { + const initialBytes = new Uint8Array([0, 17, 34, 51]) + const targetBytes = new Uint8Array([255, 128, 64, 32, 16]) + const initialHash = createHash('sha256').update(initialBytes).digest('hex') + const document = fixture((objectId, propertyName) => objectId === 'IncludedProbe' && propertyName === 'File' ? { schemaVersion: 1, archiveName: 'payload.bin', resourceHash: initialHash, byteLength: initialBytes.byteLength, mediaType: 'application/octet-stream' } : null) + const facade = createWebCadFacade({ initialDocument: document, runtimeMode: 'mock' }) + const initialResource = await facade.project.resource.put(initialBytes, 'application/octet-stream') + const targetResource = await facade.project.resource.put(targetBytes, 'application/octet-stream') + const archive = await facade.project.fcstd.serializeMetadataWithResources(document) + const before = facade.project.fcstd.inspect(archive).objects.find((object) => object.name === 'IncludedProbe')!.properties.find((candidate) => candidate.name === 'File')! + const expectedValue = document.objects[0].properties[0].value as IncludedFileValue + const value: IncludedFileValue = { schemaVersion: 1, archiveName: 'payload.bin', resourceHash: targetResource.hash, byteLength: targetBytes.byteLength, mediaType: 'application/octet-stream' } + const rewritten = await facade.project.fcstd.rewriteIncludedFile(archive, { objectName: 'IncludedProbe', propertyName: 'File', value, expectedValue }) + const files = unzipSync(rewritten) + const after = facade.project.fcstd.inspect(rewritten).objects.find((object) => object.name === 'IncludedProbe')!.properties.find((candidate) => candidate.name === 'File')! + assert.deepEqual([...files['payload.bin']], [...targetBytes]) + assert.equal(before.includedFileResource?.byteLength, initialBytes.byteLength) + assert.equal(after.includedFileResource?.byteLength, targetBytes.byteLength) + assert.equal(after.resourcePath, 'payload.bin') + assert.match(new TextDecoder().decode(files['Document.xml']), /]*name="IncludedProbe")(?=[^>]*Touched="1")[^>]*\/>/) + await assert.rejects(facade.project.fcstd.rewriteIncludedFile(archive, { objectName: 'IncludedProbe', propertyName: 'File', value: { ...value, archiveName: 'renamed.bin' }, expectedValue }), /cannot change the native archive name/) + await assert.rejects(facade.project.fcstd.rewriteIncludedFile(rewritten, { objectName: 'IncludedProbe', propertyName: 'File', value, expectedValue }), /does not match expectedValue/) + await facade.project.resource.release(initialResource.hash) + await facade.project.resource.release(targetResource.hash) + await facade.project.dispose() +}) diff --git a/tests/propertyFileIncludedTransaction.test.ts b/tests/propertyFileIncludedTransaction.test.ts new file mode 100644 index 0000000..c30e5a0 --- /dev/null +++ b/tests/propertyFileIncludedTransaction.test.ts @@ -0,0 +1,126 @@ +import { createHash } from 'node:crypto' +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { encodeFreecadPropertyStatus } from '../src/facade/propertyStatus' +import type { DocumentSnapshot, FacadeEvent, IncludedFileValue } from '../src/facade/types' + +const fixture = (): DocumentSnapshot => ({ + id: 'property-fileincluded-transaction', + label: 'PropertyFileIncluded Transaction', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [ + { id: 'IncludedProbe', label: 'Included file probe', type: 'feature', state: 'valid' }, + { id: 'ImmutableIncludedProbe', label: 'Immutable included file probe', type: 'feature', state: 'valid' }, + ], + objects: [ + { + id: 'IncludedProbe', + typeId: 'App::DocumentObjectFileIncluded', + properties: [{ name: 'File', label: 'Included file', group: 'Resource', scope: 'data', type: 'App::PropertyFileIncluded', value: null, recompute: true }], + }, + { + id: 'ImmutableIncludedProbe', + typeId: 'App::DocumentObjectFileIncluded', + properties: [{ name: 'File', label: 'Immutable included file', group: 'Resource', scope: 'data', type: 'App::PropertyFileIncluded', value: null, nativeStatus: encodeFreecadPropertyStatus(['Immutable']), readOnly: true, recompute: true }], + }, + ], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { IncludedProbe: 'up-to-date', ImmutableIncludedProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const valueOf = (facade: ReturnType) => facade.app.document.getObject('IncludedProbe')?.properties.find((property) => property.name === 'File')?.value as IncludedFileValue | null +const sha256 = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex') + +test('App::PropertyFileIncluded transaction closes undo, redo, stale, abort, failure and resource ownership', async () => { + const facade = createWebCadFacade({ initialDocument: fixture(), runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const resourcesBefore = facade.geometry.capabilities() + const requested = new Uint8Array([0, 17, 34, 51, 255]) + + const committedValue = await facade.app.document.setIncludedFile({ objectId: 'IncludedProbe', propertyName: 'File', fileName: 'payload.bin', bytes: requested, expectedDocumentVersion: 1 }) + requested[0] = 99 + assert.deepEqual(valueOf(facade), committedValue) + assert.deepEqual([...(await facade.project.resource.get(committedValue.resourceHash))!], [0, 17, 34, 51, 255]) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().dirty, true) + assert.equal(facade.app.document.getActive().recompute?.objectStates.IncludedProbe, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + assert.equal(new Set(events.map((event) => 'transactionId' in event ? event.transactionId : '')).size, 1) + const committed = events[2] + assert.equal(committed.type, 'transaction.committed') + if (committed.type === 'transaction.committed') assert.deepEqual({ operation: committed.operation, beforeVersion: committed.beforeVersion, afterVersion: committed.afterVersion }, { operation: 'property.set', beforeVersion: 1, afterVersion: 2 }) + + facade.history.undo() + assert.equal(valueOf(facade), null) + assert.equal(facade.app.document.getActive().version, 1) + assert.equal(facade.history.canUndo(), false) + assert.equal(facade.history.canRedo(), true) + assert.deepEqual([...(await facade.project.resource.get(committedValue.resourceHash))!], [0, 17, 34, 51, 255]) + facade.history.redo() + assert.deepEqual(valueOf(facade), committedValue) + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const stableState = JSON.stringify(facade.app.document.getActive()) + const stableEvents = events.length + await assert.rejects(facade.app.document.setIncludedFile({ objectId: 'IncludedProbe', propertyName: 'File', fileName: 'stale.bin', bytes: new Uint8Array([1]), expectedDocumentVersion: 1 }), /Stale document version: expected 1, current 2/) + + const preCancelled = new AbortController() + preCancelled.abort() + await assert.rejects(facade.app.document.setIncludedFile({ objectId: 'IncludedProbe', propertyName: 'File', fileName: 'pre-cancelled.bin', bytes: new Uint8Array([2]), expectedDocumentVersion: 2, signal: preCancelled.signal }), (error: unknown) => error instanceof DOMException && error.name === 'AbortError') + + const cancelledBytes = new Uint8Array([3, 4, 5, 6]) + const cancelledHash = sha256(cancelledBytes) + const cancelled = new AbortController() + const cancelledMutation = facade.app.document.setIncludedFile({ objectId: 'IncludedProbe', propertyName: 'File', fileName: 'cancelled.bin', bytes: cancelledBytes, expectedDocumentVersion: 2, signal: cancelled.signal }) + cancelled.abort() + await assert.rejects(cancelledMutation, (error: unknown) => error instanceof DOMException && error.name === 'AbortError') + assert.equal(await facade.project.resource.get(cancelledHash), null) + + const invalidBytes = new Uint8Array([7, 8, 9]) + const invalidHash = sha256(invalidBytes) + await assert.rejects(facade.app.document.setIncludedFile({ objectId: 'IncludedProbe', propertyName: 'File', fileName: 'invalid.bin', bytes: invalidBytes, mediaType: 'invalid', expectedDocumentVersion: 2 }), /simple MIME type/) + assert.equal(await facade.project.resource.get(invalidHash), null) + await assert.rejects(facade.app.document.setIncludedFile({ objectId: 'ImmutableIncludedProbe', propertyName: 'File', fileName: 'locked.bin', bytes: new Uint8Array([10]), expectedDocumentVersion: 2 }), /Immutable included file is read-only/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stableState) + assert.equal(events.length, stableEvents) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const raceLeft = new Uint8Array([11, 12, 13]) + const raceRight = new Uint8Array([14, 15, 16]) + const race = await Promise.allSettled([ + facade.app.document.setIncludedFile({ objectId: 'IncludedProbe', propertyName: 'File', fileName: 'race-left.bin', bytes: raceLeft, expectedDocumentVersion: 2 }), + facade.app.document.setIncludedFile({ objectId: 'IncludedProbe', propertyName: 'File', fileName: 'race-right.bin', bytes: raceRight, expectedDocumentVersion: 2 }), + ]) + assert.equal(race.filter((result) => result.status === 'fulfilled').length, 1) + assert.equal(race.filter((result) => result.status === 'rejected').length, 1) + const winner = race.find((result): result is PromiseFulfilledResult => result.status === 'fulfilled')!.value + const loserHash = winner.resourceHash === sha256(raceLeft) ? sha256(raceRight) : sha256(raceLeft) + assert.deepEqual(valueOf(facade), winner) + assert.ok(await facade.project.resource.get(winner.resourceHash)) + assert.equal(await facade.project.resource.get(loserHash), null) + assert.equal(facade.app.document.getActive().version, 3) + assert.deepEqual(events.slice(stableEvents).map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + + facade.history.undo() + assert.deepEqual(valueOf(facade), committedValue) + assert.ok(await facade.project.resource.get(winner.resourceHash)) + facade.history.redo() + assert.deepEqual(valueOf(facade), winner) + + const resourcesAfter = facade.geometry.capabilities() + assert.deepEqual( + { shapeCount: resourcesAfter.shapeCount, kernelReferenceCount: resourcesAfter.kernelReferenceCount, releasedShapeCount: resourcesAfter.releasedShapeCount }, + { shapeCount: resourcesBefore.shapeCount, kernelReferenceCount: resourcesBefore.kernelReferenceCount, releasedShapeCount: resourcesBefore.releasedShapeCount }, + ) + await facade.project.dispose() +}) diff --git a/tests/propertyFileTransaction.test.ts b/tests/propertyFileTransaction.test.ts new file mode 100644 index 0000000..3daab7a --- /dev/null +++ b/tests/propertyFileTransaction.test.ts @@ -0,0 +1,86 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { createWebCadFacade } from '../src/facade/mockFacade' +import { encodeFreecadPropertyStatus } from '../src/facade/propertyStatus' +import type { DocumentSnapshot, FacadeEvent } from '../src/facade/types' + +const fixture = (): DocumentSnapshot => ({ + id: 'property-file-transaction', + label: 'PropertyFile Transaction', + version: 1, + dirty: false, + readOnly: false, + units: 'mm', + tree: [ + { id: 'FileProbe', label: 'File probe', type: 'feature', state: 'valid' }, + { id: 'ImmutableFileProbe', label: 'Immutable file probe', type: 'feature', state: 'valid' }, + ], + objects: [ + { + id: 'FileProbe', + typeId: 'Mesh::Import', + properties: [{ name: 'FileName', label: 'File name', group: '', scope: 'data', type: 'App::PropertyFile', value: 'mesh-data/cube.stl', recompute: true }], + }, + { + id: 'ImmutableFileProbe', + typeId: 'Mesh::Import', + properties: [{ name: 'FileName', label: 'Immutable file name', group: '', scope: 'data', type: 'App::PropertyFile', value: 'mesh-data/locked.stl', nativeStatus: encodeFreecadPropertyStatus(['Immutable']), readOnly: true, recompute: true }], + }, + ], + dependencies: [], + recompute: { generation: 0, status: 'idle', objectStates: { FileProbe: 'up-to-date', ImmutableFileProbe: 'up-to-date' }, dirtyObjects: [], order: [], errors: [] }, +}) + +const valueOf = (facade: ReturnType, objectId = 'FileProbe') => facade.app.document.getObject(objectId)?.properties.find((property) => property.name === 'FileName')?.value + +test('App::PropertyFile transaction closes undo, redo, stale, cancel, failure and resource ownership', async () => { + const facade = createWebCadFacade({ initialDocument: fixture(), runtimeMode: 'mock' }) + const events: FacadeEvent[] = [] + facade.subscribe((event) => { + if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event) + }) + const resourcesBefore = facade.geometry.capabilities() + + facade.app.document.setProperty({ objectId: 'FileProbe', propertyName: 'FileName', value: 'project-files/updated.stl', expectedDocumentVersion: 1 }) + assert.equal(valueOf(facade), 'project-files/updated.stl') + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.app.document.getActive().dirty, true) + assert.equal(facade.app.document.getActive().recompute?.objectStates.FileProbe, 'touched') + assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed']) + assert.equal(new Set(events.map((event) => 'transactionId' in event ? event.transactionId : '')).size, 1) + const committed = events[2] + assert.equal(committed.type, 'transaction.committed') + if (committed.type === 'transaction.committed') assert.deepEqual({ operation: committed.operation, beforeVersion: committed.beforeVersion, afterVersion: committed.afterVersion }, { operation: 'property.set', beforeVersion: 1, afterVersion: 2 }) + + facade.history.undo() + assert.equal(valueOf(facade), 'mesh-data/cube.stl') + assert.equal(facade.app.document.getActive().version, 1) + assert.equal(facade.history.canUndo(), false) + assert.equal(facade.history.canRedo(), true) + facade.history.redo() + assert.equal(valueOf(facade), 'project-files/updated.stl') + assert.equal(facade.app.document.getActive().version, 2) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const stableState = JSON.stringify(facade.app.document.getActive()) + const stableEvents = events.length + assert.throws(() => facade.app.document.setProperty({ objectId: 'FileProbe', propertyName: 'FileName', value: 'project-files/stale.stl', expectedDocumentVersion: 1 }), /Stale document version: expected 1, current 2/) + const cancelled = new AbortController() + cancelled.abort() + assert.throws(() => facade.app.document.setProperty({ objectId: 'FileProbe', propertyName: 'FileName', value: 'project-files/cancelled.stl', expectedDocumentVersion: 2, signal: cancelled.signal }), (error: unknown) => error instanceof DOMException && error.name === 'AbortError') + assert.throws(() => facade.app.document.setProperty({ objectId: 'FileProbe', propertyName: 'FileName', value: '../outside.stl' }), /safe project-relative file reference/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'FileProbe', propertyName: 'FileName', value: `${'a'.repeat(4097)}.stl` }), /file reference is too long/) + assert.throws(() => facade.app.document.setProperty({ objectId: 'ImmutableFileProbe', propertyName: 'FileName', value: 'project-files/unlocked.stl' }), /Immutable file name is read-only/) + assert.equal(JSON.stringify(facade.app.document.getActive()), stableState) + assert.equal(events.length, stableEvents) + assert.equal(facade.history.canUndo(), true) + assert.equal(facade.history.canRedo(), false) + + const resourcesAfter = facade.geometry.capabilities() + assert.deepEqual( + { shapeCount: resourcesAfter.shapeCount, kernelReferenceCount: resourcesAfter.kernelReferenceCount, releasedShapeCount: resourcesAfter.releasedShapeCount }, + { shapeCount: resourcesBefore.shapeCount, kernelReferenceCount: resourcesBefore.kernelReferenceCount, releasedShapeCount: resourcesBefore.releasedShapeCount }, + ) + await facade.project.dispose() +}) diff --git a/后续工作.txt b/后续工作.txt index 868ebd4..58de4c3 100644 --- a/后续工作.txt +++ b/后续工作.txt @@ -14,6 +14,8 @@ - A-I 后续任务的完成证据账本;完成项必须形成连续前缀。 5. `config/freecad-ordered-operation-pair-classification.json` - 19x19 有序操作对的原生接受/拒绝、builder、变异、诊断和 FCStd 证据。 +6. `docs/freecad-native-differential-execution-plan.zh-CN.md` + - 通过真实 FreeCAD/Bitbybit/浏览器执行进行逐字段差分、缺陷纠正、20 步微任务和阶段里程碑的实施规范。 禁止在本文复制实时完成数或手工指定下一任务。需要查看状态时运行: @@ -2218,4 +2220,3120 @@ git diff --check - FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持有效 1 Solid、10 Face、21 Edge、13 Vertex、体积 `74.0026667`、面积 `106.6536521` 及 naming evidence hash `ec6b2670...` 一致;focused ordered-pair gate 已通过。 - 机器队列已自动前移一项;新的活动任务仍以 `config/freecad-active-work-queue.json.nextTask` 为唯一来源。 +### `TSN-PAIR-chamfer-rotate` + +`chamfer->rotate` 已完成真实 FreeCAD/OCCT 接受分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,对 10x10x10 Box 全部边执行倒角,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 下游使用真实 `BRepBuilderAPI_Transform` 单输入 builder 绕 Z 轴旋转;名义结果保持相同 Solid、拓扑数、体积和面积,并生成 314 条原生 history。 +- `15 -> 22.5 -> 15` 角度轨迹将包围盒从 `[-2.4846629, 0.1035275, -1e-7, 9.5557307, 12.1439212, 10.0000001]` 改为 `[-3.6737611, 0.1530733, -1e-7, 9.0857221, 12.9125564, 10.0000001]` 后精确恢复;history hash 和语义 naming 同时恢复。 +- 上游 Chamfer naming evidence 向下游传播;下游对称拓扑保持 `ambiguous`,未按索引伪造唯一 token,JSON round-trip 稳定。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 及 naming evidence hash `d5ff71d2...` 一致。 +- 真实执行未发现 `web-implementation-defect`、过度接受或过度拒绝;focused gate 已通过,机器队列只前移一项。 + +### 真实 desktop oracle BIM 首启隔离纠正 + +- 基线审计先发现旧 desktop report 缺少确定性归一化声明,`check:freecad-desktop-oracle` 正确 fail-closed;没有继续使用陈旧报告。 +- 完整真实 desktop probe 随后在 `BIMWorkbench` 激活处达到默认 300 秒超时,而 BIM registration-only 探针正常完成,问题被缩小到 full-scope 首启路径。 +- 根因是 `scripts/freecad-reference-probe.py` 只为 `gui-commands` scope 设置 BIM `FirstTime=false`,却对所有隔离 scope 声称首启已抑制。 +- harness 已改为所有隔离 GUI probe 在 workbench 激活前设置并读回 BIM 首启参数;报告只在真实读回 false 时声明抑制成功。 +- 修复后完整 FreeCAD 1.1.1 desktop probe 通过,重新锁定 34 模块、352 个 TypeId 候选、348 个可实例化对象、4 个明确不可实例化对象和 5510 条 Property 记录。 +- desktop oracle、oracle coverage、1111 命令 GUI 清册和 26 个三方 Boolean 场景均通过;该纠正提高 oracle 可信度,不提升 WEB exact 等级。 +- 派生 Property 语义报告已按新 desktop report hash 重新生成并通过:85 种/5510 条记录中 4987 条由原生 codec 表示,523 条仍为 opaque proxy,未被错误提升。 + +### `TSN-PAIR-chamfer-pad` + +`chamfer->pad` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,对 10x10x10 Box 全部边执行倒角,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 下游真实 `BRepPrimAPI_MakePrism` builder 对实体输入执行 `5 -> 7.5 -> 5` 长度轨迹;三次均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,且不产出 result、Shape 或 history,恢复尝试保持相同拒绝签名。 +- FreeCAD 1.1.1 文档内构造真实 `PartDesign::Pad` 并重算,锁定诊断 `FeatureExtrusion: Length: Could not extrude the sketch!`、`Touched/Invalid` 状态以及 null/invalid Shape;没有用通用 Shape fallback 伪造接受。 +- abort 前后对象集与 Chamfer 源 Shape 完全一致,只保留有效 `Part::Feature`;临时 Body、Origin 和失败 Pad 均未污染文档。 +- FCStd save/reopen/resave 三阶段均保持有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 及源 BREP hash `fa5d7bd7...` 一致。 +- focused ordered-pair gate 已锁定 OCCT 拒绝阶段、参数轨迹、FreeCAD 精确诊断、事务回滚和干净持久化;该原生拒绝是正确分类,不提升为 Web 接受。 + +### `TSN-PAIR-chamfer-pocket` + +`chamfer->pocket` 已完成真实 FreeCAD/OCCT 接受分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 下游使用真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder,在 Chamfer 结果上切除矩形棱柱;名义结果为有效 1 Solid、28 Face、57 Edge、31 Vertex、体积 `961.4986667`、面积 `573.5635876` 和 97 条原生 history。 +- `5 -> 4 -> 5` 深度轨迹使体积在 `961.4986667 -> 967.4186667 -> 961.4986667` 间变化,面积同步变化;恢复态精确回到名义几何摘要、history hash 与语义 naming。 +- 上游 Chamfer naming evidence 向下游传播;下游对称拓扑保持 `ambiguous`,JSON round-trip 稳定,没有按索引伪造唯一 token。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持有效单 Solid、相同拓扑、体积、面积及 naming evidence hash `0292a471...` 一致;focused gate 已锁定 builder、变异、恢复、naming 和持久化证据。 + +### `TSN-PAIR-chamfer-loft` + +`chamfer->loft` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- OCCT `BRepOffsetAPI_ThruSections` 对实体与第二 section 执行 `false -> true -> false` ruled 轨迹,三次均生成有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `704.4`、面积 `552.5525865` 和 24 条 history;恢复态与名义态完全一致,但该结果只代表 kernel superset。 +- 真实 FreeCAD `Part::Loft` 文档重算以 `Profile shape is not a single vertex, edge, wire nor face.` 拒绝实体 section,状态为 `Touched/Invalid` 且 Shape 为 null/invalid;分类权威是 `freecad-document`,未把 OCCT 可构造性误报为生产接受。 +- abort 前后只保留原 Chamfer `Part::Feature`,对象集、Shape 与 BREP hash `fa5d7bd7...` 完全恢复;临时 Section 和失败 Loft 未污染文档。 +- FCStd save/reopen/resave 三阶段均保持原 Chamfer 有效单 Solid、相同拓扑、体积和面积;focused gate 已锁定 kernel 诊断、FreeCAD 精确拒绝、回滚和干净持久化。 + +### `TSN-PAIR-chamfer-pipe` + +`chamfer->pipe` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- OCCT `BRepOffsetAPI_MakePipe` 对实体 profile 与线性 spine 执行 `15 -> 12 -> 15` 轨迹;三次均产生 Shape 和 28 条原生 history,但 Shape 无效且体积为 0,编辑态面积与 Z 上界变化,恢复态精确回到名义 invalid-result 摘要。 +- 真实 FreeCAD `Part::Sweep` 文档重算返回 `A fatal error occurred when making the sweep`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid;没有把“产生了无效 Shape”误报为接受。 +- abort 前后只保留原 Chamfer `Part::Feature`,对象集、Shape 与 BREP hash `fa5d7bd7...` 完全一致;临时 Spine 和失败 Sweep 均未污染文档。 +- FCStd save/reopen/resave 三阶段保持原 Chamfer 的有效单 Solid、拓扑、体积和面积;focused gate 已锁定 kernel invalid-result、FreeCAD 精确诊断、事务回滚和干净持久化。 + +### `TSN-PAIR-chamfer-revolution` + +`chamfer->revolution` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 下游真实 `BRepPrimAPI_MakeRevol` 对实体输入执行 `360 -> 270 -> 360` 角度轨迹;三次均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history,恢复态拒绝签名一致。 +- 真实 FreeCAD `Part::Revolution` 文档重算返回 `Solids are not Processed`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid;没有用通用旋转 Shape 代理替代原生 profile 合同。 +- abort 前后只保留原 Chamfer `Part::Feature`,对象集、Shape 与 BREP hash `fa5d7bd7...` 完全一致;失败 Revolution 未污染文档。 +- FCStd save/reopen/resave 三阶段保持原 Chamfer 有效单 Solid、相同拓扑、体积和面积;focused gate 已锁定 builder 拒绝、FreeCAD 精确诊断、事务恢复和干净持久化。 + +### `TSN-PAIR-chamfer-groove` + +`chamfer->groove` 已完成真实 FreeCAD/OCCT 接受分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 下游使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder;360 度名义结果为有效 1 Solid、30 Face、60 Edge、32 Vertex、体积 `986.0289444`、面积 `577.966554` 和 18 条原生 history。 +- `360 -> 180 -> 360` 角度轨迹使编辑态回到体积 `990.7413333`、27 Face、52 Edge,随后精确恢复名义几何摘要、history hash 和语义 naming。 +- 上游 Chamfer naming evidence 向下游传播;下游保持显式 `ambiguous`,JSON round-trip 稳定,没有索引型伪唯一 token。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持相同有效单 Solid、拓扑、体积、面积及 naming evidence hash `d8501450...`;focused gate 已锁定 builder、变异、恢复、naming 和持久化证据。 + +### `TSN-PAIR-chamfer-fillet` + +`chamfer->fillet` 已完成真实 FreeCAD/OCCT 差异拒绝分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- Web 原生 `BRepFilletAPI_MakeFillet` 对全边 Chamfer 结果执行 `0.4 -> 0.6 -> 0.4` 半径轨迹;首次无覆盖探针真实触发 Wasm `memory access out of bounds`,锁定后续三次均为相同 builder crash signature,且不伪造 result、Shape、history 或 naming。 +- 独立 FreeCAD 1.1.1 `Part::Fillet` 对相同 48 Edge、半径 `0.4` 的 profile 重算成功,生成有效 1 Solid、98 Face、192 Edge、96 Vertex、体积 `989.9595415`、面积 `567.3942825`;该差异证明当前 Web builder 仍不能提升为接受。 +- FreeCAD 成功 feature 在事务内完成诊断后 abort;前后只保留原 Chamfer `Part::Feature`,对象集、源 Shape 与 BREP hash `fa5d7bd7...` 完全恢复。 +- 源 FCStd save/reopen/resave 三阶段保持相同有效单 Solid、拓扑、体积和面积;focused gate 已锁定 Wasm crash、FreeCAD profile acceptance、事务恢复和干净持久化。 + +### `TSN-PAIR-chamfer-chamfer` + +`chamfer->chamfer` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- Web 原生 `BRepFilletAPI_MakeChamfer` 对全边 Chamfer 结果执行 `0.4 -> 0.6 -> 0.4` 距离轨迹;首次无覆盖探针真实触发 Wasm `memory access out of bounds`,锁定的三次尝试均保持相同 crash signature,且不伪造 result、Shape、history 或 naming。 +- 独立 FreeCAD 1.1.1 `Part::Chamfer` 对相同 48 Edge、距离 `0.4` 的文档重算以 `BRep_API: command not done` 拒绝,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- abort 前后只保留原 Chamfer `Part::Feature`,对象集、源 Shape 与 BREP hash `fa5d7bd7...` 完全一致;失败的第二个 Chamfer 未污染文档。 +- FCStd save/reopen/resave 三阶段保持原 Chamfer 有效单 Solid、相同拓扑、体积和面积;focused gate 已锁定 Wasm crash、FreeCAD 精确拒绝、事务恢复和干净持久化。 + +### `TSN-PAIR-chamfer-hole` + +`chamfer->hole` 已完成真实 FreeCAD/OCCT 接受分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 下游使用真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` builder 构造中心贯穿孔;名义结果为有效 1 Solid、27 Face、51 Edge、26 Vertex、体积 `959.3254068`、面积 `627.9488512` 和 23 条原生 history。 +- `1 -> 1.5 -> 1` 半径轨迹使体积在 `959.3254068 -> 920.0554986 -> 959.3254068` 间变化,面积同步变化;恢复态精确回到名义几何摘要、history hash 和语义 naming。 +- 下游获得唯一 `native-evidence` naming,2 条选择记录无歧义;上游 Chamfer naming evidence 正确传播,JSON round-trip 稳定。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持相同有效单 Solid、拓扑、体积、面积及 naming evidence hash `c09894a0...`;focused gate 已锁定 builder、变异、恢复、naming 和持久化证据。 + +### `TSN-PAIR-chamfer-draft` + +`chamfer->draft` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 下游真实 `BRepOffsetAPI_DraftAngle` 对锁定 Face、中性面和方向执行 `5 -> 8 -> 5` 角度轨迹;三次均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- 真实 FreeCAD `PartDesign::Draft` 使用 Body 内 `DraftBase/DatumPlane/DatumLine` 重算,状态为 `Touched/Invalid` 且 Shape 为 null/invalid;原生 status string 为空,检查器同时锁定结构化状态而不伪造诊断文本。 +- `DraftBase` 与源 Chamfer 的 Shape 摘要逐字段一致,源/副本 BREP hash 的序列化差异被显式记录;abort 后临时 Body、datum 和 Draft 全部移除,源对象集与 Shape 完全恢复。 +- FCStd save/reopen/resave 三阶段保持原 Chamfer 有效单 Solid、相同拓扑、体积、面积及源 BREP hash `fa5d7bd7...`;focused gate 已锁定拒绝、输入转移、事务恢复和干净持久化。 + +### `TSN-PAIR-chamfer-thickness` + +`chamfer->thickness` 已完成真实 FreeCAD/OCCT no-op 拒绝分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- OCCT `BRepOffsetAPI_MakeThickSolid` 对锁定 `Face2` 执行 `-0.4 -> -0.6 -> -0.4` offset 轨迹;三次均返回有效 1 Solid 和 1 条原生 history,但 Shape 摘要与上游逐字段相同,因此明确记为 `kernel-no-op`,不伪造接受变异。 +- 真实 FreeCAD `Part::Thickness` 对同一 Chamfer Solid 返回 `Valid/Up-to-date`,结果 Shape 非空且有效,但输入与结果的有效性、拓扑数、体积、面积和边界完全一致,分类为 `freecadProfileNoOp`。 +- 事务 abort 后对象集和实体几何恢复;源 BREP 因 FreeCAD 元素映射从 `fa5d7bd7...` 重序列化为稳定的 `0c4fbfd8...`,TShape identity 不同,但有效性、拓扑数、体积、面积和边界逐字段一致,双向布尔差体积均为 `0`,该差异已显式登记而未冒充字节级恢复。 +- 干净 FCStd save/reopen/resave 三阶段保持唯一源对象和相同 Shape 摘要,文档无临时 Thickness 污染;focused probe 独立复跑两次得到相同目标 artifact SHA-256 `9e3811fc...`。 +- focused ordered-pair gate 已锁定 OCCT/FreeCAD 双 no-op、参数恢复、几何等价回滚、BREP 重序列化和持久化证据;机器队列只推进一项。 + +### `TSN-PAIR-chamfer-linear-pattern` + +`chamfer->linear-pattern` 已完成真实 OCCT 接受分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder 沿 X 方向复制并融合 Chamfer 结果;名义结果为有效 1 Solid、42 Face、80 Edge、40 Vertex、体积 `1788.1813333`、面积 `883.902117` 和 258 条原生 history。 +- `8 -> 9 -> 8` 平移轨迹使体积在 `1788.1813333 -> 1887.8613333 -> 1788.1813333` 间变化,X 上界从 `18` 扩展到 `19` 后恢复;几何摘要、history hash 和语义 naming 精确恢复。 +- 上游 Chamfer naming evidence 向下游传播;下游保持原生 `ambiguous` 分类,JSON round-trip 稳定,没有按索引伪造唯一 token。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持相同有效单 Solid、拓扑、体积、面积及 naming evidence hash `0de89018...`;focused gate 已锁定交叠融合、变异、恢复、naming 和持久化证据。 +- 机器队列只推进一项;后继任务继续由最新 `nextTask` 唯一决定。 + +### `TSN-PAIR-chamfer-polar-pattern` + +`chamfer->polar-pattern` 已完成真实 OCCT 接受分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder 绕 Z 轴旋转复制并融合 Chamfer 结果;30 度名义结果为有效 1 Solid、46 Face、90 Edge、46 Vertex、体积 `1411.0585231`、面积 `735.5718725` 和 228 条原生 history。 +- `30 -> 45 -> 30` 角度轨迹使体积在 `1411.0585231 -> 1573.5395566 -> 1411.0585231` 间变化,面积和边界同步变化;恢复态精确回到名义几何摘要、history hash 和语义 naming。 +- 上游 Chamfer naming evidence 向下游传播;下游保持原生 `ambiguous` 分类,JSON round-trip 稳定,没有伪造唯一 token。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持相同有效单 Solid、拓扑、体积、面积及 naming evidence hash `271f87be...`;focused gate 已锁定旋转融合、变异、恢复、naming 和持久化证据。 +- 机器队列只推进一项;后继任务继续由最新 `nextTask` 唯一决定。 + +### `TSN-PAIR-chamfer-mirrored` + +`chamfer->mirrored` 已完成真实 OCCT 接受分类: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 默认 `x=5` 镜像面位于对称 Chamfer 实体中心,名义 Shape 与输入完全相同,未被误记为接受;改用保持副本相交且名义态真实改变几何的 `6 -> 7 -> 6` 专用轨迹。 +- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder 镜像复制并融合;名义结果为有效 1 Solid、42 Face、80 Edge、40 Vertex、体积 `1190.1013333`、面积 `649.5256668` 和 258 条原生 history。 +- 镜像面轨迹使体积在 `1190.1013333 -> 1389.4613333 -> 1190.1013333` 间变化,X 上界从 `12` 扩展到 `14` 后恢复;几何摘要、history hash 和语义 naming 精确恢复。 +- 上游 Chamfer naming evidence 向下游传播;下游保持原生 `ambiguous` 分类,JSON round-trip 稳定,没有伪造唯一 token。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持相同有效单 Solid、拓扑、体积、面积及 naming evidence hash `f63fc775...`;focused gate 已锁定非 no-op 镜像、变异、恢复、naming 和持久化证据,机器队列只推进一项。 + +### `TSN-PAIR-chamfer-multi-transform` + +`chamfer->multi-transform` 已完成真实 OCCT 接受分类,并闭合 Chamfer 起始行中尚需分类的全部有序操作对: + +- 上游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder,生成有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- 下游使用 ordered `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` builder,依次执行 X 平移和关于 `x=5` 的镜像并融合;名义结果为有效 1 Solid、58 Face、112 Edge、56 Vertex、体积 `2585.6213333`、面积 `1196.4040506` 和 1027 条原生 history。 +- `8 -> 9 -> 8` 首步 X 平移轨迹使体积在 `2585.6213333 -> 2784.9813333 -> 2585.6213333` 间变化,边界从 `[-8, 18]` 扩展为 `[-9, 19]` 后恢复;几何摘要、history hash 和语义 naming 精确恢复。 +- 上游 Chamfer naming evidence 向下游传播;下游保持原生 `ambiguous` 分类,JSON round-trip 稳定,没有伪造唯一 token。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持相同有效单 Solid、拓扑、体积、面积及 naming evidence hash `9abb2623...`;focused gate 已锁定 ordered builder、变异、恢复、naming 和持久化证据。 +- 机器队列从 Chamfer 行末严格跨到下一起始操作行,没有跳号或第二个活动微任务;后继任务仍只读取最新 `nextTask`。 + +### `TSN-PAIR-hole-fuse` + +`hole->fuse` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游使用真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` builder 对 10x10x10 Box 执行中心贯穿孔,生成有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `968.5840735`、面积 `656.5486678` 和 23 条原生 history。 +- 下游使用真实 `BRepAlgoAPI_Fuse` 双输入 builder,以相交工具融合 Hole 结果;名义结果为有效 1 Solid、14 Face、32 Edge、20 Vertex、体积 `1043.5840735`、面积 `716.5486678` 和 52 条原生 history。 +- `8 -> 7 -> 8` 工具 X 偏移轨迹使体积在 `1043.5840735 -> 1018.5840735 -> 1043.5840735` 间变化,X 上界从 `13` 变为 `12` 后恢复;几何摘要、history hash 和语义 naming 精确恢复。 +- 上游 Hole 的无歧义 `native-evidence` naming 向下游传播;下游对称拓扑保持 `ambiguous` 分类,JSON round-trip 稳定,没有按索引伪造唯一 token。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持相同有效单 Solid、拓扑、体积、面积及 naming evidence hash `91e34b16...`;聚焦原生探针重跑仍得到相同分类。 +- focused ordered-pair gate 已锁定两阶段 builder、双输入、变异、恢复、history、naming 和持久化证据;队列仅前移一项,后继任务仍以机器队列的最新 `nextTask` 为唯一来源。 + +### `TSN-PAIR-hole-cut` + +`hole->cut` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游使用真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` builder 对 10x10x10 Box 执行中心贯穿孔,生成有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `968.5840735`、面积 `656.5486678` 和 23 条原生 history。 +- 下游使用真实 `BRepAlgoAPI_Cut` 双输入 builder 对 Hole 结果再次减料;名义结果为有效 1 Solid、12 Face、31 Edge、20 Vertex、体积 `904.5840735`、面积 `688.5486678` 和 36 条原生 history。 +- `4 -> 3 -> 4` 工具尺寸轨迹使体积在 `904.5840735 -> 941.5840735 -> 904.5840735` 间变化,拓扑和面积同步变化;恢复态精确回到名义几何摘要、history hash 和语义 naming hash。 +- 上游 Hole 的无歧义 `native-evidence` naming 向下游传播;下游保持 `ambiguous` 分类且 JSON round-trip 稳定,没有按索引伪造唯一 token。 +- 连续三次聚焦原生探针均得到 accepted、相同几何/history/语义 naming 和 FCStd 结果;跨进程只有恢复态完整原始 naming evidence 的序列化 hash 变化,未被误记为字节级恢复或语义漂移。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持相同有效单 Solid、拓扑、体积、面积及名义态 naming evidence hash `a115b41a...`;focused gate 已锁定两阶段 builder、双输入、变异、语义恢复、history、naming 和持久化证据。 +- 机器队列仅前移一项,且只保留一个 `in_progress`;后继任务仍以最新 `nextTask` 为唯一来源。 + +### `TSN-PAIR-hole-common` + +#### 执行过程 + +1. 从机器队列读取唯一活动任务,确认依赖已闭合,且退出条件要求接受证据包含 builder、变异、naming 和 FCStd resave。 +2. 审计 Common 默认输入后发现 `x=10` 工具仅与 Hole 边界接触,不能形成有效体积交集;因此锁定保持实体交叠的 `7 -> 6 -> 7` X 偏移轨迹,没有将空交集误记为接受。 +3. 执行器追加该有序操作对的连续前缀和专用参数;检查器同步锁定两阶段 builder、输入数、变异轨迹与分类汇总。 +4. 真实聚焦探针执行 4 次 OCCT builder 和 FreeCAD 1.1.1 的 3 个 FCStd 阶段,然后通过 ordered-pair focused gate。 +5. 生成器将刚完成任务标记为 `completed`,队列只前移一项,并继续保持唯一 `in_progress`。 + +#### 完成证据 + +`hole->common` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游使用真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` builder 生成有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `968.5840735`、面积 `656.5486678` 和 23 条原生 history。 +- 下游使用真实 `BRepAlgoAPI_Common` 双输入 builder 求交;名义结果为有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `75`、面积 `110` 和 140 条原生 history。 +- `7 -> 6 -> 7` 工具 X 偏移轨迹使体积在 `75 -> 100 -> 75` 间变化,面积在 `110 -> 130 -> 110` 间变化,X 下界从 `7` 移至 `6` 后恢复;几何摘要、history hash 和语义 naming 精确恢复。 +- 上游 Hole 的 `native-evidence` naming 向下游传播;下游对称拓扑保持 `ambiguous` 分类,JSON round-trip 稳定,没有伪造唯一 token。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持相同有效单 Solid、拓扑、体积、面积及 naming evidence hash `7202e431...`;focused gate 已锁定 builder、变异、恢复、history、naming 和持久化证据。 + +### `TSN-PAIR-hole-rotate` + +#### 执行过程 + +1. 在前一任务生成队列后重新读取唯一 `nextTask`,确认新任务是连续前缀中的下一有序操作对。 +2. 执行器显式锁定 `BRepBuilderAPI_Transform` 和 `15 -> 22.5 -> 15` 角度轨迹;检查器追加单输入 builder、变异与分类汇总断言。 +3. 聚焦原生探针完成 4 次 OCCT builder 和 3 个 FreeCAD FCStd 阶段;ordered-pair focused gate 通过后才重建队列。 +4. 队列生成器只将本项改为 `completed`,同时将下一项维持为唯一 `in_progress`。 + +#### 完成证据 + +`hole->rotate` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游 Hole 保持有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `968.5840735`、面积 `656.5486678` 和 23 条原生 history。 +- 下游使用真实 `BRepBuilderAPI_Transform` 单输入 builder 绕 Z 轴旋转;名义结果保持相同 Solid、拓扑、体积和面积,并生成 97 条原生 history。 +- `15 -> 22.5 -> 15` 角度轨迹将世界坐标边界从 `[-2.5881906, 0, 0, 9.6592584, 12.2474488, 10]` 改为 `[-3.8268344, 0, 0, 9.2387954, 13.0656297, 10]` 后恢复;未因体积不变而误判为 no-op。 +- 恢复态精确回到名义几何摘要、history hash 和语义 naming;上游 Hole naming 向下游传播,下游保持 `ambiguous` 而没有伪造唯一 token。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段均保持名义 Shape 及 naming evidence hash `99df97fe...`;focused gate 已锁定 builder、边界变异、恢复、history、naming 和持久化证据。 + +### `TSN-PAIR-hole-pad` + +#### 执行过程 + +1. 从新生成的队列读取唯一活动项,将 Solid-as-Profile 预期明确为待探测的原生拒绝,没有预先伪造接受结果。 +2. 执行器锁定 `BRepPrimAPI_MakePrism`、`5 -> 7.5 -> 5` 长度轨迹和 `occt-builder` 决策权;检查器锁定 `PartDesign::Pad` 类型与精确诊断。 +3. 聚焦探针完成 OCCT 拒绝尝试、FreeCAD 文档重算、transaction abort 和 FCStd save/reopen/resave;focused gate 通过后队列才前移一项。 + +#### 完成证据 + +`hole->pad` 已完成真实 OCCT/FreeCAD 拒绝分类: + +- 上游 Hole 保持有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `968.5840735`、面积 `656.5486678` 和 23 条原生 history。 +- `BRepPrimAPI_MakePrism` 对 Hole Solid 执行 `5 -> 7.5 -> 5` 长度轨迹,三次均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产生 result、Shape 或 history。 +- FreeCAD 1.1.1 `PartDesign::Pad` 文档重算返回 `FeatureExtrusion: Length: Could not extrude the sketch!`,状态为 `Touched/Invalid`,Shape 为 null/invalid;没有使用通用 Shape fallback。 +- transaction abort 前后只保留原 `Part::Feature`,对象集、Shape 摘要和源 BREP hash `d3a3dd33...` 精确恢复;失败 Pad、Body 和 Origin 没有污染文档。 +- 干净 FCStd save/reopen/resave 三阶段均保持唯一源对象与相同有效 Shape;focused gate 已锁定拒绝阶段、参数轨迹、精确诊断、回滚和持久化证据。 + +### `TSN-PAIR-hole-pocket` + +#### 执行过程 + +1. 重读机器队列并领取唯一活动项,锁定 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 两阶段减料和 `5 -> 4 -> 5` 深度轨迹。 +2. 聚焦探针完成 4 次原生 builder 和 3 个 FreeCAD FCStd 阶段;检查器确认 Shape 变化、恢复、history、naming 和持久化后,队列生成器只前移一项。 + +#### 完成证据 + +`hole->pocket` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游 Hole 生成有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `968.5840735` 和 23 条原生 history。 +- 下游使用真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder;名义结果为有效 1 Solid、10 Face、24 Edge、16 Vertex、体积 `938.5840735` 和 42 条原生 history。 +- `5 -> 4 -> 5` 深度轨迹使体积在 `938.5840735 -> 944.5840735 -> 938.5840735` 间变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 上游 Hole naming 向下游传播,下游保持 `ambiguous` 分类与稳定 JSON round-trip;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `e47fa122...`。 +- focused gate 已锁定 builder、变异、恢复、history、naming 和持久化证据;队列继续保持唯一 `in_progress`。 + +### `TSN-PAIR-hole-loft` + +#### 执行过程 + +1. 从队列领取唯一活动项,将 OCCT kernel 可构造性与 FreeCAD 文档 profile 适用性分层检查。 +2. 执行 `false -> true -> false` ruled 轨迹、FreeCAD `Part::Loft` 重算、transaction abort 和干净 FCStd 三阶段;聚焦门禁通过后才生成新队列。 + +#### 完成证据 + +`hole->loft` 已完成真实 OCCT/FreeCAD 分层拒绝分类: + +- 上游 Hole 保持有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `968.5840735` 和 23 条原生 history。 +- OCCT `BRepOffsetAPI_ThruSections` 在 `false -> true -> false` 轨迹中均生成有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `750`、面积 `580.2775638` 和 24 条 history;该结果只记为 `kernel-superset-only`。 +- FreeCAD 1.1.1 `Part::Loft` 以 `Profile shape is not a single vertex, edge, wire nor face.` 拒绝 Solid section,状态为 `Touched/Invalid` 且 Shape 为 null/invalid;分类权威保持 `freecad-document`。 +- abort 前后只保留原 Hole `Part::Feature`,对象集、Shape 摘要和 BREP hash `d3a3dd33...` 精确恢复;FCStd save/reopen/resave 三阶段无临时 Section 或 Loft 污染。 +- focused gate 已锁定 kernel 超集证据、FreeCAD 精确诊断、回滚和干净持久化;队列只前移一项。 + +### `TSN-PAIR-hole-pipe` + +#### 执行过程 + +1. 从最新队列领取唯一活动项,锁定 `15 -> 12 -> 15` spine 长度轨迹。 +2. 分开采集 OCCT Shape 有效性、FreeCAD `Part::Sweep` 诊断、transaction abort 和 FCStd 往返;focused gate 通过后队列只前移一项。 + +#### 完成证据 + +`hole->pipe` 已完成真实 OCCT/FreeCAD 拒绝分类: + +- OCCT `BRepOffsetAPI_MakePipe` 在 `15 -> 12 -> 15` 轨迹中每次都产生 Shape 和 28 条 history,但 Shape 无效且体积为 `0`;面积在 `500 -> 440 -> 500` 间变化,恢复态回到名义 invalid-result 摘要。 +- FreeCAD 1.1.1 `Part::Sweep` 返回 `A fatal error occurred when making the sweep`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid;没有把“产生了无效 Shape”误报为接受。 +- abort 前后只保留原 Hole `Part::Feature`,对象集、Shape 和 BREP hash `d3a3dd33...` 一致;临时 Spine/Sweep 未污染文档。 +- FCStd save/reopen/resave 三阶段保持源 Shape;focused gate 已锁定 kernel invalid-result、FreeCAD 精确诊断、回滚和持久化证据。 + +### `TSN-PAIR-hole-revolution` + +#### 执行过程 + +1. 重读队列后领取唯一活动项,锁定 `BRepPrimAPI_MakeRevol`、`360 -> 270 -> 360` 角度轨迹与 `Part::Revolution` 文档诊断。 +2. 完成原生拒绝探针、FreeCAD 重算、transaction abort、FCStd 三阶段和 focused gate;队列只前移一项。 + +#### 完成证据 + +`hole->revolution` 已完成真实 OCCT/FreeCAD 拒绝分类: + +- OCCT `BRepPrimAPI_MakeRevol` 对 Hole Solid 执行 `360 -> 270 -> 360` 轨迹,三次均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产生 result、Shape 或 history。 +- FreeCAD 1.1.1 `Part::Revolution` 返回 `Solids are not Processed`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid;没有使用通用旋转 Shape 代替 profile 合同。 +- abort 前后唯一 Hole 源对象、Shape 摘要和 BREP hash `d3a3dd33...` 精确恢复;FCStd save/reopen/resave 三阶段一致。 +- focused gate 已锁定 builder 拒绝、FreeCAD 精确诊断、回滚和干净持久化证据。 + +### `TSN-PAIR-hole-groove` + +#### 执行过程 + +1. 从队列领取唯一活动项,锁定真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder 与 `360 -> 180 -> 360` 轨迹。 +2. 完成原生探针、变异恢复、naming、FCStd 三阶段和 focused gate;队列只前移一项。 + +#### 完成证据 + +`hole->groove` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游 360 度名义结果为有效 1 Solid、11 Face、27 Edge、18 Vertex、体积 `963.8716845`、面积 `663.1150384` 和 18 条原生 history。 +- `360 -> 180 -> 360` 轨迹使编辑态变为 8 Face、19 Edge、14 Vertex、体积 `968.5840735`;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 上游 Hole naming 向下游传播,下游保持 `ambiguous` 分类;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `05e968b8...`。 +- focused gate 已锁定 builder、变异、恢复、history、naming 和持久化证据。 + +### `TSN-PAIR-hole-fillet` + +#### 执行过程 + +1. 从最新队列领取唯一活动项,锁定 `BRepFilletAPI_MakeFillet` 和 `0.4 -> 0.6 -> 0.4` 半径轨迹。 +2. 执行原生 builder、变异恢复、naming、FCStd 三阶段和 focused gate;全部通过后队列只前移一项。 + +#### 完成证据 + +`hole->fillet` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游使用真实 `BRepFilletAPI_MakeFillet` 单输入 builder;名义结果为有效 1 Solid、29 Face、63 Edge、28 Vertex、体积 `964.0793949`、面积 `633.7505843` 和 173 条原生 history。 +- `0.4 -> 0.6 -> 0.4` 半径轨迹使体积在 `964.0793949 -> 958.5016007 -> 964.0793949` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 上游 Hole naming 向下游传播,下游保持 `ambiguous` 分类;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `6313804f...`。 +- focused gate 已锁定 builder、变异、恢复、history、naming 和持久化证据。 + +### `TSN-PAIR-hole-chamfer` + +#### 执行过程 + +1. 从最新队列领取唯一活动项,锁定 `BRepFilletAPI_MakeChamfer` 和 `0.4 -> 0.6 -> 0.4` 距离轨迹。 +2. 聚焦探针完成 builder、变异恢复、naming 和 FCStd 往返;focused gate 通过后队列只前移一项。 + +#### 完成证据 + +`hole->chamfer` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游使用真实 `BRepFilletAPI_MakeChamfer` 单输入 builder;名义结果为有效 1 Solid、29 Face、55 Edge、28 Vertex、体积 `958.1860559`、面积 `625.4207803` 和 173 条原生 history。 +- `0.4 -> 0.6 -> 0.4` 距离轨迹使体积在 `958.1860559 -> 945.4217374 -> 958.1860559` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 上游 Hole naming 向下游传播,下游保持 `ambiguous` 分类;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `b9282639...`。 +- focused gate 已锁定 builder、变异、恢复、history、naming 和持久化证据。 + +### `TSN-PAIR-hole-hole` + +#### 执行过程 + +1. 从最新队列领取唯一活动项;审计发现复用默认中心与半径会使名义下游退化为 no-op,因此将第二贯穿孔锁定在 `(2, 2)`。 +2. 执行 `1 -> 1.5 -> 1` 半径轨迹、原生 history/naming、FCStd 三阶段和 focused gate;证明名义态真实改变上游 Shape 后才推进队列。 + +#### 完成证据 + +`hole->hole` 已完成真实 OCCT/FreeCAD 接受分类: + +- 第二阶段使用真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` builder 生成偏置贯穿孔;名义结果为有效 1 Solid、8 Face、18 Edge、12 Vertex、体积 `937.1681469`、面积 `713.0973355` 和 23 条原生 history。 +- `1 -> 1.5 -> 1` 半径轨迹使体积在 `937.1681469 -> 897.8982388 -> 937.1681469` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 上下游都获得无歧义 `native-evidence` naming,没有伪造私有 token;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `daeee873...`。 +- focused gate 已锁定偏置输入、变异、恢复、history、naming 和持久化证据。 + 后续任务必须从机器队列的最新 `nextTask` 继续,不在本文手工维护任务名称。 + +### `TSN-PAIR-hole-draft` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,使用真实 `BRepOffsetAPI_DraftAngle` 对 Hole 结果执行 `5 -> 8 -> 5` 角度轨迹。 +2. 采集原生 builder、Shape 变化与恢复、history/naming 和 FCStd save/reopen/resave 证据;聚焦门禁通过后队列只前移一项。 + +#### 完成证据 + +`hole->draft` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游 Hole 为有效 1 Solid、7 Face、15 Edge、10 Vertex,体积 `968.5840735`、面积 `656.5486678` 和 23 条原生 history。 +- 下游拔模名义结果保持有效单 Solid,体积 `924.8397417`、面积 `639.4329188` 和 5 条原生 history。 +- `5 -> 8 -> 5` 角度轨迹使体积在 `924.8397417 -> 898.3136561 -> 924.8397417` 间变化,恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 上下游均为无歧义 `native-evidence` naming;FCStd 三阶段保持 Shape 及 naming evidence hash `7e449b85...`。 + +### `TSN-PAIR-hole-thickness` + +#### 执行过程 + +1. 从最新队列领取唯一活动项;先对 Hole 的候选面与两档 offset 做只读原生可构造性探测,确认默认面不是 no-op。 +2. 将该对加入连续分类前缀和聚焦检查器,执行 4 次真实 `BRepOffsetAPI_MakeThickSolid` builder 及 3 个 FreeCAD FCStd 阶段。 +3. 聚焦门禁、`git diff --check` 通过后生成队列;完成数只增加 1,且仍只有一个 `in_progress`。 + +#### 完成证据 + +`hole->thickness` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游厚度使用真实 `BRepOffsetAPI_MakeThickSolid` 单输入 builder;名义结果为有效 1 Solid、13 Face、30 Edge、20 Vertex,体积 `212.6892722`、面积 `1078.4410513` 和 55 条原生 history。 +- `-0.4 -> -0.6 -> -0.4` offset 轨迹使体积在 `212.6892722 -> 311.4218728 -> 212.6892722` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- Hole 的无歧义 naming 向下游传播,厚度结果保持原生 `ambiguous` 分类和稳定 JSON round-trip,没有伪造唯一 token。 +- FreeCAD 1.1.1 FCStd save/reopen/resave 三阶段保持相同有效单 Solid、拓扑、体积、面积及 naming evidence hash `49370f17...`。 +- focused ordered-pair gate 已锁定 builder、变异、恢复、history、naming 和持久化证据;队列仅前移一项。 + +### `TSN-PAIR-hole-linear-pattern` + +#### 执行过程 + +1. 从机器队列读取唯一活动项 `TSN-PAIR-hole-linear-pattern`,确认前置 `TSN-PROD-DRIFT-001` 已满足,领取该任务。 +2. 审计执行器与既有阵列合同,锁定下游候选为真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse`,先按 `8 -> 9 -> 8` 平移轨迹执行聚焦探针;当前不预设超出原生结果的 fallback 或能力结论。 +3. 聚焦探针完成 4 次原生 builder 和 3 个 FreeCAD FCStd 阶段,实测分类为 `accepted`;逐字段确认 Shape 变化、恢复、history、naming 和持久化后,仅同步检查器的精确汇总常量。 + +#### 完成证据 + +`hole->linear-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游 Hole 保持有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `968.5840735` 和 23 条原生 history。 +- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 单输入阵列 builder;名义结果为有效 1 Solid、16 Face、34 Edge、20 Vertex、体积 `1737.1681469`、面积 `1033.0973355` 和 66 条原生 history。 +- `8 -> 9 -> 8` 平移轨迹使体积在 `1737.1681469 -> 1837.1681469 -> 1737.1681469` 间变化,边界同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 上游 Hole naming 向下游传播,下游保持 `ambiguous` 原生分类;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence 稳定。 +- ordered-pair focused gate、活动队列 gate、execution-plan gate、全部 JSON 解析和 `git diff --check` 通过;队列从 `370` 完成项前移到 `371`,唯一新活动项为 `TSN-PAIR-hole-polar-pattern`。 + +### `TSN-PAIR-hole-polar-pattern` + +#### 执行过程 + +1. 从新生成的机器队列领取唯一活动项 `TSN-PAIR-hole-polar-pattern`,锁定真实旋转变换加 Fuse 的极轴阵列路径与 `30 -> 45 -> 30` 角度轨迹。 + +#### 完成证据 + +`hole->polar-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 单输入极轴阵列 builder;名义结果为有效 1 Solid、16 Face、30 Edge、20 Vertex、体积 `1422.6497308`、面积 `769.0598923` 和 96 条原生 history。 +- `30 -> 45 -> 30` 角度轨迹使编辑态变为 21 Face、51 Edge、28 Vertex、体积 `1554.3705111` 和 127 条 history;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 上游 Hole naming 向下游传播,下游保持 `ambiguous` 分类;FCStd save/reopen/resave 三阶段保持相同 Shape 及 naming evidence hash `f773ce34...`。 +- focused gate、活动队列 gate 和 `git diff --check` 通过;队列完成项增加到 `372`,唯一新活动项为 `TSN-PAIR-hole-mirrored`。 + +### `TSN-PAIR-hole-mirrored` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;审计发现 Hole 关于默认 `x=5` 镜像面对称,会使名义镜像退化为 no-op,因此锁定 `6 -> 7 -> 6` 非对称平面轨迹后再采集真实 builder 证据。 + +#### 完成证据 + +`hole->mirrored` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 单输入镜像 builder;名义结果为有效 1 Solid、18 Face、32 Edge、18 Vertex、体积 `1200`、面积 `680` 和 108 条原生 history。 +- 非退化 `6 -> 7 -> 6` 镜像面轨迹使编辑态变为 18 Face、40 Edge、24 Vertex、体积 `1400`、面积 `760`;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `ff14b8f0...`。 +- focused gate、活动队列 gate 和 `git diff --check` 通过;队列完成项增加到 `373`,唯一新活动项为 `TSN-PAIR-hole-multi-transform`。 + +### `TSN-PAIR-hole-multi-transform` + +#### 执行过程 + +1. 从机器队列领取 Hole 行最后一个活动项;确认 builder 按“线性副本后镜像整个中间结果”的固定顺序执行,因此沿用非退化 `8 -> 9 -> 8` 线性距离轨迹与 `x=5` 镜像面。 + +#### 完成证据 + +`hole->multi-transform` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游使用真实有序 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)` 单输入 builder;名义结果为有效 1 Solid、26 Face、56 Edge、32 Vertex、体积 `2505.7522204`、面积 `1409.6460033` 和 441 条原生 history。 +- `8 -> 9 -> 8` 线性距离轨迹使体积在 `2505.7522204 -> 2705.7522204 -> 2505.7522204` 间变化,边界同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `a4b7e760...`。 +- focused gate 和 `git diff --check` 通过;Hole 行 19/19 有序操作对全部闭合,队列完成项增加到 `374`,唯一新活动项为 `TSN-PAIR-draft-fuse`。 + +### `TSN-PAIR-draft-fuse` + +#### 执行过程 + +1. 从新生成的机器队列领取唯一活动项 `TSN-PAIR-draft-fuse`;在开始新行前先执行 Hole 行边界的完整项目门禁,确保已有增量可作为稳定接续基线。 +2. 完整 `./npmw run verify` 通过,包括构建、PWA、79 个签名发布文件、release closure 和 Ed25519 验签;系统能力仍保持 `0 exact / 26 compatible / 5 proxy / 3 development` 的 fail-closed 状态。 +3. 对照相邻实体 dress-up 行,将 Fuse 工具锁定为有重叠的 `8 -> 7 -> 8` 偏移轨迹,避免默认偏移 12 产生断开 Compound 后误当作代表性接受证据。 + +#### 完成证据 + +`draft->fuse` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游 Draft 为有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `956.2556682`、面积 `582.884251` 和 5 条原生 history。 +- 下游真实 `BRepAlgoAPI_Fuse` 双输入结果为有效 1 Solid、13 Face、29 Edge、18 Vertex、体积 `1031.2556682`、面积 `642.884251` 和 52 条原生 history。 +- `8 -> 7 -> 8` 工具偏移轨迹使体积在 `1031.2556682 -> 1006.2556682 -> 1031.2556682` 间变化,恢复态精确回到名义 Shape、history hash 和语义 naming;FCStd 三阶段稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `375`,唯一新活动项为 `TSN-PAIR-draft-cut`。 + +### `TSN-PAIR-draft-cut` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;确认默认 Cut 工具位于 Draft 实体内部,采用真实 `BRepAlgoAPI_Cut` 与 `4 -> 3 -> 4` 工具尺寸轨迹采样。 + +#### 完成证据 + +`draft->cut` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepAlgoAPI_Cut` 双输入结果为有效 1 Solid、10 Face、24 Edge、16 Vertex、体积 `892.2556682`、面积 `614.884251` 和 22 条原生 history。 +- `4 -> 3 -> 4` 工具尺寸轨迹使体积在 `892.2556682 -> 929.2556682 -> 892.2556682` 间变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游原生 naming 为 `ambiguous`;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `092779b6...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `376`,唯一新活动项为 `TSN-PAIR-draft-common`。 + +### `TSN-PAIR-draft-common` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;默认 Common 工具从 `x=10` 起只与 Draft 边界接触,因此锁定有实体重叠的 `7 -> 6 -> 7` 工具偏移轨迹。 + +#### 完成证据 + +`draft->common` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepAlgoAPI_Common` 双输入结果为有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `75`、面积 `110` 和 121 条原生 history。 +- `7 -> 6 -> 7` 工具偏移轨迹使体积在 `75 -> 100 -> 75` 间变化,边界同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游原生 naming 为 `ambiguous`;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `6bafa6dc...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `377`,唯一新活动项为 `TSN-PAIR-draft-rotate`。 + +### `TSN-PAIR-draft-rotate` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;沿用真实 `BRepBuilderAPI_Transform` 单输入 builder 和 `15 -> 22.5 -> 15` 角度轨迹,采集 Draft 实体的旋转、恢复、history/naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`draft->rotate` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepBuilderAPI_Transform` 单输入结果保持有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `956.2556682`、面积 `582.884251`,生成 78 条原生 history。 +- `15 -> 22.5 -> 15` 角度轨迹将包围盒从 `[-2.5881906, -1e-7, -1e-7, 9.6592584, 12.2474488, 10.0000001]` 改为 `[-3.8268344, -1e-7, -1e-7, 9.2387954, 13.0656297, 10.0000001]` 后精确恢复;history hash 与语义 naming 同步恢复。 +- 上游 Draft 为无歧义 `native-evidence`,下游旋转保持 `ambiguous`;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `cceb25e8...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `378`,唯一新活动项为 `TSN-PAIR-draft-pad`。 + +### `TSN-PAIR-draft-pad` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;按实体输入合同执行真实 `BRepPrimAPI_MakePrism` 的 `5 -> 7.5 -> 5` 长度轨迹,并以真实 `PartDesign::Pad` 文档重算、事务回滚和干净 FCStd 三阶段作为拒绝分类证据。 + +#### 完成证据 + +`draft->pad` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 下游真实 `BRepPrimAPI_MakePrism` 对 Draft 实体执行 `5 -> 7.5 -> 5` 长度轨迹;三次均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 真实 `PartDesign::Pad` 重算返回 `FeatureExtrusion: Length: Could not extrude the sketch!`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 前后只保留有效源 `Part::Feature`,对象集与源 BREP hash `a18f0adb...` 完全一致;失败 Pad、Body 和 Origin 未污染文档。 +- FCStd save/reopen/resave 三阶段保持 Draft 源实体的有效单 Solid、拓扑、体积和面积;focused gate 与 `git diff --check` 通过,队列完成项增加到 `379`。 + +### `TSN-PAIR-draft-pocket` + +#### 执行过程 + +1. 从最新队列领取唯一活动项;使用真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入 builder 执行 `5 -> 4 -> 5` 深度轨迹,并采集 Shape/history/naming 恢复和 FCStd 三阶段证据。 + +#### 完成证据 + +`draft->pocket` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 双输入结果为有效 1 Solid、9 Face、21 Edge、14 Vertex、体积 `929.5364931`、面积 `581.5146235` 和 58 条原生 history。 +- `5 -> 4 -> 5` 深度轨迹使体积在 `929.5364931 -> 934.3553962 -> 929.5364931` 间变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `d487a421...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `380`,唯一新活动项为 `TSN-PAIR-draft-loft`。 + +### `TSN-PAIR-draft-loft` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;使用真实 `BRepOffsetAPI_ThruSections` 执行 `false -> true -> false` ruled 轨迹,同时以真实 `Part::Loft` 文档重算判定实体 section 是否满足 FreeCAD profile 合同。 + +#### 完成证据 + +`draft->loft` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT `BRepOffsetAPI_ThruSections` 的三次 ruled 尝试均生成有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `315.6164976`、面积 `549.6140595` 和 24 条 history;恢复态一致,但只属于 kernel superset。 +- FreeCAD 1.1.1 真实 `Part::Loft` 文档重算以 `Profile shape is not a single vertex, edge, wire nor face.` 拒绝实体 section,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后只保留 Draft 源对象,Shape 与 BREP hash `a18f0adb...` 完全恢复;FCStd save/reopen/resave 三阶段干净稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `381`,唯一新活动项为 `TSN-PAIR-draft-pipe`。 + +### `TSN-PAIR-draft-pipe` + +#### 执行过程 + +1. 从最新队列领取唯一活动项;以真实 `BRepOffsetAPI_MakePipe` 执行 `15 -> 12 -> 15` spine 长度轨迹,并用真实 `Part::Sweep` 文档重算区分 kernel invalid-result 与 FreeCAD 拒绝。 +2. 首轮聚焦探针 fail-closed:Draft 输入上的 OCCT Pipe 实测生成有效 1 Solid,并非相邻实体常见的 `invalid-result`;将该对的 kernel 预期纠正为实测 `accepted` 后重新采样,最终权威仍保持 `freecad-document`。 + +#### 完成证据 + +`draft->pipe` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT `BRepOffsetAPI_MakePipe` 的三次尝试均生成有效 1 Solid、6 Face、12 Edge、8 Vertex 和 28 条 history;`15 -> 12 -> 15` 轨迹使体积在 `131.2329953 -> 104.9863962 -> 131.2329953` 间变化后精确恢复。 +- 真实 FreeCAD `Part::Sweep` 文档重算返回 `A fatal error occurred when making the sweep`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid;kernel 接受仅作为 superset 诊断。 +- 事务 abort 后源对象集、Shape 与 BREP hash `a18f0adb...` 完全恢复;FCStd 三阶段保持干净稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `382`,唯一新活动项为 `TSN-PAIR-draft-revolution`。 + +### `TSN-PAIR-draft-revolution` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;以真实 `BRepPrimAPI_MakeRevol` 执行 `360 -> 270 -> 360` 角度轨迹,并用真实 `Part::Revolution` 重算、回滚和 FCStd 三阶段锁定实体输入拒绝合同。 + +#### 完成证据 + +`draft->revolution` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 下游真实 `BRepPrimAPI_MakeRevol` 对 Draft 实体执行 `360 -> 270 -> 360` 角度轨迹;三次均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- 真实 FreeCAD `Part::Revolution` 文档重算返回 `Solids are not Processed`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 前后源对象集与 BREP hash `a18f0adb...` 完全一致;FCStd 三阶段保持有效 Draft 源实体且无失败 Revolution 污染。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `383`,唯一新活动项为 `TSN-PAIR-draft-groove`。 + +### `TSN-PAIR-draft-groove` + +#### 执行过程 + +1. 从最新队列领取唯一活动项;使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 双输入 builder 执行 `360 -> 180 -> 360` 角度轨迹,采集切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`draft->groove` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 结果为有效 1 Solid、10 Face、24 Edge、16 Vertex、体积 `951.8050786`、面积 `588.75249` 和 18 条原生 history。 +- `360 -> 180 -> 360` 轨迹使编辑态变为 7 Face、16 Edge、12 Vertex,体积回到 Draft 源值 `956.2556682`;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `7f3be10c...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `384`,唯一新活动项为 `TSN-PAIR-draft-fillet`。 + +### `TSN-PAIR-draft-fillet` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;先仅扩展连续执行前缀,以真实 `BRepFilletAPI_MakeFillet` 对 Draft 边集合执行 `0.4 -> 0.6 -> 0.4` 半径轨迹,结论完全由原生探针决定。 + +#### 完成证据 + +`draft->fillet` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepFilletAPI_MakeFillet` 结果为有效 1 Solid、26 Face、56 Edge、24 Vertex、体积 `952.2666777`、面积 `562.3270603` 和 150 条原生 history。 +- `0.4 -> 0.6 -> 0.4` 半径轨迹使体积在 `952.2666777 -> 947.3773367 -> 952.2666777` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `03590c56...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `385`,唯一新活动项为 `TSN-PAIR-draft-chamfer`。 + +### `TSN-PAIR-draft-chamfer` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;先只扩展连续前缀,以真实 `BRepFilletAPI_MakeChamfer` 对 Draft 全边执行 `0.4 -> 0.6 -> 0.4` 距离轨迹,再按实测结果锁定分类。 + +#### 完成证据 + +`draft->chamfer` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepFilletAPI_MakeChamfer` 结果为有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `947.1369614`、面积 `554.6660823` 和 150 条原生 history。 +- `0.4 -> 0.6 -> 0.4` 距离轨迹使体积在 `947.1369614 -> 936.1225793 -> 947.1369614` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `86475869...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `386`,唯一新活动项为 `TSN-PAIR-draft-hole`。 + +### `TSN-PAIR-draft-hole` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;以真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` 对 Draft 实体执行 `1 -> 1.5 -> 1` 半径轨迹,先采集原生结果再锁定分类。 + +#### 完成证据 + +`draft->hole` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` 结果为有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `924.8397417`、面积 `639.4329188` 和 23 条原生 history。 +- `1 -> 1.5 -> 1` 半径轨迹使体积在 `924.8397417 -> 885.5698335 -> 924.8397417` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 上下游均为无歧义 `native-evidence` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `4d76f9b3...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `387`,唯一新活动项为 `TSN-PAIR-draft-draft`。 + +### `TSN-PAIR-draft-draft` + +#### 执行过程 + +1. 从最新队列领取唯一活动项;以真实 `BRepOffsetAPI_DraftAngle` 对已拔模实体再次执行 `5 -> 8 -> 5` 角度轨迹,先由 builder 的有效 Shape 或拒绝签名确定分类。 + +#### 完成证据 + +`draft->draft` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepOffsetAPI_DraftAngle` 名义 5 度结果保持有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `956.2556682`、面积 `582.884251`,并产生独立原生 history。 +- `5 -> 8 -> 5` 轨迹使编辑态体积变为 `929.7295826`、面积变为 `572.8745903`,随后精确恢复名义 Shape、history hash 和语义 naming;因此该能力不是恒定 no-op。 +- 上下游均为无歧义 `native-evidence` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `1e36c081...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `388`,唯一新活动项为 `TSN-PAIR-draft-thickness`。 + +### `TSN-PAIR-draft-thickness` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;先以真实 `BRepOffsetAPI_MakeThickSolid` 对锁定面执行 `-0.4 -> -0.6 -> -0.4` offset 轨迹,由有效变异、invalid-result 或 no-op 实测决定分类。 + +#### 完成证据 + +`draft->thickness` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepOffsetAPI_MakeThickSolid` 结果为有效 1 Solid、11 Face、24 Edge、16 Vertex、体积 `180.8661951`、面积 `920.33342` 和 38 条原生 history。 +- `-0.4 -> -0.6 -> -0.4` offset 轨迹使体积在 `180.8661951 -> 262.3727637 -> 180.8661951` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `502f0c67...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `389`,唯一新活动项为 `TSN-PAIR-draft-linear-pattern`。 + +### `TSN-PAIR-draft-linear-pattern` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;以真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `8 -> 9 -> 8` 平移轨迹,采集交叠副本的 Shape、history、naming 和 FCStd 三阶段证据。 + +#### 完成证据 + +`draft->linear-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 结果为有效 1 Solid、14 Face、28 Edge、16 Vertex、体积 `1756.2556682`、面积 `902.884251` 和 66 条原生 history。 +- `8 -> 9 -> 8` 平移轨迹使体积在 `1756.2556682 -> 1856.2556682 -> 1756.2556682` 间变化,X 上界同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `35cb7d6b...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `390`,唯一新活动项为 `TSN-PAIR-draft-polar-pattern`。 + +### `TSN-PAIR-draft-polar-pattern` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;以真实旋转 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `30 -> 45 -> 30` 角度轨迹,采集拓扑、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`draft->polar-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实旋转 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 结果为有效 1 Solid、14 Face、30 Edge、18 Vertex、体积 `1378.1688669`、面积 `754.9351384` 和 66 条原生 history。 +- `30 -> 45 -> 30` 角度轨迹使体积在 `1378.1688669 -> 1540.7663948 -> 1378.1688669` 间变化,边界同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `d1dd374c...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `391`,唯一新活动项为 `TSN-PAIR-draft-mirrored`。 + +### `TSN-PAIR-draft-mirrored` + +#### 执行过程 + +1. 从最新队列领取唯一活动项;先以默认真实镜像变换加 Fuse 的 `5 -> 6 -> 5` 平面轨迹探测 Draft 实体是否仍关于 x=5 对称,再据实锁定代表性分类。 + +#### 完成证据 + +`draft->mirrored` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 的 x=5 镜像结果为有效 1 Solid、12 Face、22 Edge、12 Vertex、体积 `1000`、面积 `600` 和 118 条原生 history;镜像补齐了非对称 Draft 的楔形差异,不是 no-op。 +- `5 -> 6 -> 5` 镜像面轨迹使编辑态变为 14 Face、28 Edge、16 Vertex、体积 `1112.5113365`;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `7a5113cd...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `392`,唯一新活动项为 `TSN-PAIR-draft-multi-transform`。 + +### `TSN-PAIR-draft-multi-transform` + +#### 执行过程 + +1. 从机器队列领取 Draft 行最后一个活动项;使用真实有序 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)` 执行 `8 -> 9 -> 8` 线性距离轨迹,并锁定后续镜像整个中间结果的顺序语义。 + +#### 完成证据 + +`draft->multi-transform` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实有序 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)` 结果为有效 1 Solid、28 Face、54 Edge、28 Vertex、体积 `2600`、面积 `1240` 和 376 条原生 history。 +- `8 -> 9 -> 8` 距离轨迹使编辑态变为 32 Face、62 Edge、32 Vertex、体积 `2800`、面积 `1320`;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `bed9f818...`。 +- focused gate 与 `git diff --check` 通过;Draft 行 19/19 有序操作对全部闭合,队列完成项增加到 `393`,唯一新活动项为 `TSN-PAIR-thickness-fuse`。 + +### Draft 行边界完整验证 + +#### 执行过程 + +1. 在跨入 Thickness 行前运行完整 `./npmw run verify`,验证本批分类、活动队列、构建、PWA、发布文件与签名闭环。 + +#### 完成证据 + +- 完整 `./npmw run verify` 通过:263 个有序操作对分类、全套浏览器与单元测试、fuzz、生产构建、PWA、79 个发布文件、release closure 与 Ed25519 签名均通过。 +- 发布矩阵仍严格保持 `0 exact / 26 compatible / 5 proxy / 3 development`,没有因局部有序操作对闭合而提升系统级 exact 声明。 + +### `TSN-PAIR-thickness-fuse` + +#### 执行过程 + +1. 从机器队列领取 Thickness 行首个活动项;将 Fuse 工具锁定为与厚度实体有重叠的 `8 -> 7 -> 8` 偏移轨迹,避免默认断开 Compound,并执行真实 `BRepAlgoAPI_Fuse`、恢复与 FCStd 三阶段采样。 + +#### 完成证据 + +`thickness->fuse` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游 Thickness 为有效 1 Solid、11 Face、24 Edge、16 Vertex、体积 `187.456`、面积 `953.28` 和 38 条原生 history。 +- 下游真实 `BRepAlgoAPI_Fuse` 结果为有效 1 Solid、19 Face、47 Edge、30 Vertex、体积 `304.776`、面积 `1055.6` 和 58 条原生 history。 +- `8 -> 7 -> 8` 工具偏移轨迹使体积在 `304.776 -> 300.936 -> 304.776` 间变化,恢复态精确回到名义 Shape、history hash 和语义 naming;FCStd 三阶段稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `394`,唯一新活动项为 `TSN-PAIR-thickness-cut`。 + +### `TSN-PAIR-thickness-cut` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;使用真实 `BRepAlgoAPI_Cut` 和默认内部工具的 `4 -> 3 -> 4` 尺寸轨迹,采集厚度壳体的切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`thickness->cut` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepAlgoAPI_Cut` 结果为有效 1 Solid、15 Face、42 Edge、28 Vertex、体积 `175.296`、面积 `901.76` 和 54 条原生 history。 +- `4 -> 3 -> 4` 工具尺寸轨迹使体积在 `175.296 -> 180.736 -> 175.296` 间变化,恢复态精确回到名义 Shape、history hash 和语义 naming;FCStd 三阶段稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `395`,唯一新活动项为 `TSN-PAIR-thickness-common`。 + +### `TSN-PAIR-thickness-common` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;将 Common 工具锁定为有实体交叠的 `7 -> 6 -> 7` 偏移轨迹,使用真实 `BRepAlgoAPI_Common` 采集交集、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`thickness->common` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepAlgoAPI_Common` 结果为有效 1 Solid、8 Face、18 Edge、12 Vertex、体积 `11.52`、面积 `67.68` 和 203 条原生 history。 +- `7 -> 6 -> 7` 工具偏移轨迹使体积在 `11.52 -> 15.36 -> 11.52` 间变化;恢复态精确回到名义 Shape、history hash 和语义 naming,FCStd 三阶段稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `396`,唯一新活动项为 `TSN-PAIR-thickness-rotate`。 + +### `TSN-PAIR-thickness-rotate` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;使用真实 `BRepBuilderAPI_Transform` 对 Thickness 实体执行 `15 -> 22.5 -> 15` 角度轨迹,采集刚体边界变化、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`thickness->rotate` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepBuilderAPI_Transform` 保持有效 1 Solid、11 Face、24 Edge、16 Vertex、体积 `187.456`、面积 `953.28`,生成 155 条原生 history。 +- `15 -> 22.5 -> 15` 角度轨迹改变包围盒后精确恢复名义 Shape、history hash 和语义 naming;FCStd save/reopen/resave 三阶段保持稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `397`,唯一新活动项为 `TSN-PAIR-thickness-pad`。 + +### `TSN-PAIR-thickness-pad` + +#### 执行过程 + +1. 从机器队列领取唯一活动项;以真实 `BRepPrimAPI_MakePrism` 执行 `5 -> 7.5 -> 5` 长度轨迹,并使用真实 `PartDesign::Pad` 重算、事务回滚和干净 FCStd 三阶段锁定实体输入合同。 + +#### 完成证据 + +`thickness->pad` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 下游真实 `BRepPrimAPI_MakePrism` 的 `5 -> 7.5 -> 5` 三次尝试均在 builder 阶段稳定拒绝,不产出 result、Shape 或 history。 +- 真实 FreeCAD `PartDesign::Pad` 重算返回 `FeatureExtrusion: Length: Could not extrude the sketch!`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- abort 前后只保留 Thickness 源对象,Shape 与 BREP hash `eafb7b89...` 完全一致;FCStd save/reopen/resave 三阶段无临时 Body/Pad 污染。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `398`,唯一新活动项为 `TSN-PAIR-thickness-pocket`。 + +### `TSN-PAIR-thickness-pocket` + +#### 执行过程 + +1. 从最新队列领取唯一活动项;使用真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 执行 `5 -> 4 -> 5` 深度轨迹,采集厚度实体的切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`thickness->pocket` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 结果为有效 1 Solid、14 Face、39 Edge、26 Vertex、体积 `176.592`、面积 `906.32` 和 72 条原生 history。 +- `5 -> 4 -> 5` 深度轨迹使体积在 `176.592 -> 178.432 -> 176.592` 间变化,恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `6cb05565...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `399`,唯一新活动项为 `TSN-PAIR-thickness-loft`。 + +### `TSN-PAIR-thickness-loft` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepOffsetAPI_ThruSections` 执行 `false -> true -> false` ruled 轨迹,并用真实 `Part::Loft` 重算区分 OCCT kernel 能力与 FreeCAD 实体 profile 合同。 + +#### 完成证据 + +`thickness->loft` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT `BRepOffsetAPI_ThruSections` 的三次 ruled 尝试均生成有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `750`、面积 `580.2775638` 和 24 条 history;恢复态一致,但只属于 kernel superset。 +- FreeCAD 1.1.1 真实 `Part::Loft` 文档重算以 `Profile shape is not a single vertex, edge, wire nor face.` 拒绝 Thickness 实体 section,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后仅保留有效 Thickness 源对象,Shape 与 BREP hash `eafb7b89...` 完全恢复;FCStd save/reopen/resave 三阶段干净稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `400`,唯一新活动项为 `TSN-PAIR-thickness-pipe`。 + +### `TSN-PAIR-thickness-pipe` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepOffsetAPI_MakePipe` 执行 `15 -> 12 -> 15` spine 长度轨迹,并以真实 `Part::Sweep` 重算锁定最终 FreeCAD 合同。 + +#### 完成证据 + +`thickness->pipe` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT `BRepOffsetAPI_MakePipe` 的三次尝试均返回无效 Shape:1 Solid、6 Face、12 Edge、8 Vertex、体积 `0` 和 28 条 history;`15 -> 12 -> 15` 使面积 `500 -> 440 -> 500` 后恢复,kernel 结论为稳定 `invalid-result`。 +- FreeCAD 1.1.1 真实 `Part::Sweep` 文档重算返回 `A fatal error occurred when making the sweep`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后仅保留有效 Thickness 源对象,Shape 与 BREP hash `eafb7b89...` 完全恢复;FCStd 三阶段干净稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `401`,唯一新活动项为 `TSN-PAIR-thickness-revolution`。 + +### `TSN-PAIR-thickness-revolution` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepPrimAPI_MakeRevol` 执行 `360 -> 270 -> 360` 角度轨迹,并用真实 `Part::Revolution` 重算、回滚和 FCStd 三阶段锁定实体输入合同。 + +#### 完成证据 + +`thickness->revolution` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 下游真实 `BRepPrimAPI_MakeRevol` 对 Thickness 实体执行 `360 -> 270 -> 360`;三次均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 真实 `Part::Revolution` 文档重算返回 `Solids are not Processed`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 前后只保留 Thickness 源对象,Shape 与 BREP hash `eafb7b89...` 完全一致;FCStd 三阶段无失败 Revolution 污染。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `402`,唯一新活动项为 `TSN-PAIR-thickness-groove`。 + +### `TSN-PAIR-thickness-groove` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 执行 `360 -> 180 -> 360` 角度轨迹,采集薄壁实体切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`thickness->groove` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 结果为有效 1 Solid、16 Face、45 Edge、30 Vertex、体积 `184.9681824`、面积 `947.4500354` 和 29 条原生 history。 +- `360 -> 180 -> 360` 轨迹使编辑态回到 Thickness 源体积 `187.456` 和面积 `953.28`,恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `3aeb7354...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `403`,唯一新活动项为 `TSN-PAIR-thickness-fillet`。 + +### `TSN-PAIR-thickness-fillet` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepFilletAPI_MakeFillet` 对 Thickness 边集合执行 `0.4 -> 0.6 -> 0.4` 半径轨迹,并采集 FreeCAD profile、回滚与 FCStd 证据。 + +#### 完成证据 + +`thickness->fillet` 已完成原生 builder 拒绝与 FreeCAD 选边接受的分层分类: + +- 原生 history WASM 对 Thickness 全边 Fillet 的首次真实执行触发 `null function or function signature mismatch`;锁定后的 `0.4 -> 0.6 -> 0.4` 三次 builder 轨迹均为无 result、无 Shape、无 history 的稳定 abort。 +- 原始 FreeCAD 全边 fixture 同样触发 SIGSEGV;将真实 profile 输入收窄为 GUI/生产合同中的显式 `Edge1` 后,`Part::Fillet` 重算成功为有效 1 Solid、12 Face、27 Edge、18 Vertex、体积 `187.1126371`、面积 `951.4945127`。 +- 事务 abort 后仅保留 Thickness 源对象,Shape 与 BREP hash `eafb7b89...` 完全恢复;FCStd save/reopen/resave 三阶段干净稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `404`,唯一新活动项为 `TSN-PAIR-thickness-chamfer`。 + +### `TSN-PAIR-thickness-chamfer` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepFilletAPI_MakeChamfer` 对 Thickness 边集合执行 `0.4 -> 0.6 -> 0.4` 距离轨迹,先由实测 builder 结果决定分类。 + +#### 完成证据 + +`thickness->chamfer` 已完成原生 builder 拒绝与 FreeCAD 选边接受的分层分类: + +- 原生 `BRepFilletAPI_MakeChamfer` 对 Thickness 全边距离轨迹 `0.4 -> 0.6 -> 0.4` 三次均以 Emscripten C++ exception 拒绝,不产出 result、Shape 或 history。 +- FreeCAD 全边 fixture 在同一薄壁输入上触发原生 SIGSEGV;按 GUI 显式选边合同收窄为 `Edge1` 后,真实 `Part::Chamfer` 重算成功为有效 1 Solid、12 Face、27 Edge、18 Vertex、体积 `186.656`、面积 `950.7768542`。 +- 事务 abort 后仅保留 Thickness 源对象,Shape 与 BREP hash `eafb7b89...` 完全恢复;FCStd 三阶段干净稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `405`,唯一新活动项为 `TSN-PAIR-thickness-hole`。 + +### `TSN-PAIR-thickness-hole` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` 执行 `1 -> 1.5 -> 1` 半径轨迹,采集孔切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`thickness->hole` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` 结果为有效 1 Solid、13 Face、30 Edge、20 Vertex、体积 `184.9427259`、面积 `945.7401776` 和 28 条原生 history。 +- `1 -> 1.5 -> 1` 半径轨迹使体积在 `184.9427259 -> 181.8011332 -> 184.9427259` 间变化,恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游为无歧义 `native-evidence` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `6d68be45...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `406`,唯一新活动项为 `TSN-PAIR-thickness-draft`。 + +### `TSN-PAIR-thickness-draft` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepOffsetAPI_DraftAngle` 对锁定薄壁面执行 `5 -> 8 -> 5` 角度轨迹,由有效 Shape 或原生拒绝决定分类。 + +#### 完成证据 + +`thickness->draft` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepOffsetAPI_DraftAngle` 结果为有效 1 Solid、11 Face、24 Edge、16 Vertex、体积 `143.7116682`、面积 `936.164251` 和 5 条原生 history。 +- `5 -> 8 -> 5` 角度轨迹使体积在 `143.7116682 -> 117.1855826 -> 143.7116682` 间变化,恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游为无歧义 `native-evidence` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `facf324c...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `407`,唯一新活动项为 `TSN-PAIR-thickness-thickness`。 + +### `TSN-PAIR-thickness-thickness` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepOffsetAPI_MakeThickSolid` 对已厚度实体执行 `-0.4 -> -0.6 -> -0.4` offset 轨迹,由有效变异、no-op、invalid-result 或拒绝实测确定分类。 + +#### 完成证据 + +`thickness->thickness` 已完成 OCCT/FreeCAD 双层 no-op 分类: + +- OCCT `BRepOffsetAPI_MakeThickSolid` 的 `-0.4 -> -0.6 -> -0.4` 三次尝试均返回与上游输入摘要完全一致的有效 1 Solid、11 Face、24 Edge、16 Vertex、体积 `187.456`、面积 `953.28` 和 1 条稳定 history。 +- FreeCAD 1.1.1 真实 `Part::Thickness` 对 `Face2` 重算保持 `Valid/Up-to-date`,结果 Shape 与输入逐字段一致,明确归类为 no-op 而非 accepted mutation。 +- 事务 abort 后源对象集与 BREP hash `eafb7b89...` 完全一致;FCStd save/reopen/resave 三阶段干净稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `408`,唯一新活动项为 `TSN-PAIR-thickness-linear-pattern`。 + +### `TSN-PAIR-thickness-linear-pattern` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `8 -> 9 -> 8` 平移轨迹,采集薄壁实体阵列、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`thickness->linear-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 结果为有效 1 Solid、29 Face、60 Edge、36 Vertex、体积 `344.192`、面积 `1722.24` 和 130 条原生 history。 +- `8 -> 9 -> 8` 平移轨迹使体积在 `344.192 -> 359.552 -> 344.192` 间变化,X 上界同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `52354b96...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `409`,唯一新活动项为 `TSN-PAIR-thickness-polar-pattern`。 + +### `TSN-PAIR-thickness-polar-pattern` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实旋转 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `30 -> 45 -> 30` 角度轨迹,采集拓扑、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`thickness->polar-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实旋转 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 结果为有效 1 Solid、27 Face、66 Edge、42 Vertex、体积 `326.5688209`、面积 `1625.3550126` 和 152 条原生 history。 +- `30 -> 45 -> 30` 角度轨迹使体积在 `326.5688209 -> 339.6931926 -> 326.5688209` 间变化,history 与边界同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `60e3972b...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `410`,唯一新活动项为 `TSN-PAIR-thickness-mirrored`。 + +### `TSN-PAIR-thickness-mirrored` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实镜像 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `5 -> 6 -> 5` 平面轨迹,采集对称态、偏移态、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`linear-pattern->mirrored` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实镜像 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 的 x=5 结果为有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2600`、面积 `1240`、X 下界 `-8` 和 258 条原生 history。 +- `5 -> 6 -> 5` 镜像面轨迹使编辑态变为 30 Face、60 Edge、32 Vertex、体积 `2400`、X 下界 `-6`;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `02771940...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `430`,唯一新活动项为 `TSN-PAIR-linear-pattern-multi-transform`。 + +### `TSN-PAIR-linear-pattern-multi-transform` + +#### 执行过程 + +1. 从最新机器队列领取 Linear Pattern 行最后一个活动项;扩展连续探针前缀,使用真实有序 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)` 执行 `8 -> 9 -> 8` 线性距离轨迹,并锁定后续镜像整个中间结果的顺序语义。 + +#### 完成证据 + +`linear-pattern->multi-transform` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实有序 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)` 结果为有效 1 Solid、38 Face、76 Edge、40 Vertex、体积 `4200`、面积 `1880` 和 783 条原生 history。 +- `8 -> 9 -> 8` 距离轨迹使编辑态变为 54 Face、108 Edge、56 Vertex、体积 `4400`、面积 `1960`,边界与 history 同步扩展;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `7770e81b...`。 +- focused gate 与 `git diff --check` 通过;Linear Pattern 行 19/19 有序操作对全部闭合,队列完成项增加到 `431`,唯一新活动项为 `TSN-PAIR-polar-pattern-fuse`。 + +### Linear Pattern 行边界完整验证 + +#### 执行过程 + +1. 在跨入 Polar Pattern 行前运行完整 `./npmw run verify`,验证新增分类、no-op/BREP 重序列化合同、活动队列、构建、PWA、发布文件与签名闭环。 + +#### 完成证据 + +- 完整 `./npmw run verify` 通过:301 个逐对原生分类与 4 个既有生产转换覆盖、全套浏览器与单元测试、FCStd/几何/Sketch fuzz、生产构建、PWA、79 个发布文件、release closure 与 Ed25519 签名全部通过。 +- 发布矩阵继续严格保持 `0 exact / 26 compatible / 5 proxy / 3 development`,系统级 `systemExact=false`;局部有序操作对闭合没有越权提升能力声明。 + +### `TSN-PAIR-polar-pattern-fuse` + +#### 执行过程 + +1. 从完整验证后的最新机器队列领取 Polar Pattern 行首个活动项;扩展连续探针前缀,以真实上游旋转阵列和下游 `BRepAlgoAPI_Fuse` 工具执行变异、恢复、naming 与 FCStd 三阶段采样。首轮默认 x=12 工具与上游不相交,返回 2 Solid Compound 且无 history,被门禁正确阻止;将工具轨迹修正为真实相交的 `8 -> 7 -> 8` 后重跑。 + +#### 完成证据 + +`polar-pattern->fuse` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游 Polar Pattern 为有效 1 Solid、12 Face、26 Edge、16 Vertex、体积 `1422.6497308`、面积 `769.0598923` 和 78 条原生 history。 +- 下游真实 `BRepAlgoAPI_Fuse` 结果为有效 1 Solid、21 Face、46 Edge、27 Vertex、体积 `1497.6497308`、面积 `829.0598923` 和 64 条原生 history。 +- x=`8 -> 7 -> 8` 工具轨迹使体积在 `1497.6497308 -> 1472.6497308 -> 1497.6497308` 间变化,恢复态精确回到名义 Shape、history hash 和语义 naming;FCStd 三阶段保持 naming evidence hash `7edcf077...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `432`,唯一新活动项为 `TSN-PAIR-polar-pattern-cut`。 + +### `TSN-PAIR-polar-pattern-cut` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepAlgoAPI_Cut` 执行 `4 -> 3 -> 4` 工具尺寸轨迹,采集旋转阵列切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`polar-pattern->cut` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepAlgoAPI_Cut` 结果为有效 1 Solid、17 Face、41 Edge、26 Vertex、体积 `1358.6497308`、面积 `801.0598923` 和 34 条原生 history。 +- `4 -> 3 -> 4` 工具尺寸轨迹使体积在 `1358.6497308 -> 1395.6497308 -> 1358.6497308` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `567c4970...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `433`,唯一新活动项为 `TSN-PAIR-polar-pattern-common`。 + +### `TSN-PAIR-polar-pattern-common` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;根据上游实测 X 上界 `10` 避免默认 x=10 的退化接触,以真实 `BRepAlgoAPI_Common` 执行 `7 -> 6 -> 7` 工具偏移轨迹,采集体积交集、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`polar-pattern->common` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepAlgoAPI_Common` 名义结果为有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `75`、面积 `110` 和 213 条原生 history。 +- `7 -> 6 -> 7` 工具偏移轨迹使编辑态体积变为 `100`、面积变为 `130`;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `726029e7...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `434`,唯一新活动项为 `TSN-PAIR-polar-pattern-rotate`。 + +### `TSN-PAIR-polar-pattern-rotate` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;使用真实 `BRepBuilderAPI_Transform` 执行 `15 -> 22.5 -> 15` 角度轨迹,采集刚体边界变化、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`polar-pattern->rotate` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游 Polar Pattern 为有效 1 Solid、12 Face、26 Edge、16 Vertex、体积 `1422.6497308`、面积 `769.0598923` 和 78 条原生 history。 +- 下游真实 `BRepBuilderAPI_Transform` 保持有效 1 Solid、12 Face、26 Edge、16 Vertex、体积 `1422.6497308`、面积 `769.0598923`,生成 168 条原生 history。 +- `15 -> 22.5 -> 15` 角度轨迹改变包围盒但保持质量属性,恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `0f073ae2...`。 +- 单对原生探针、focused gate 与队列生成通过,队列完成项增加到 `435`,唯一新活动项为 `TSN-PAIR-polar-pattern-pad`。 + +### `TSN-PAIR-polar-pattern-pad` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepPrimAPI_MakePrism` 执行 `5 -> 7.5 -> 5` 长度轨迹,并用真实 `PartDesign::Pad` 重算、事务回滚和 FCStd 三阶段锁定实体 Profile 拒绝合同。 + +#### 完成证据 + +`polar-pattern->pad` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 下游真实 `BRepPrimAPI_MakePrism` 的三次长度尝试均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 真实 `PartDesign::Pad` 重算返回 `FeatureExtrusion: Length: Could not extrude the sketch!`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- abort 前后只保留有效 Polar Pattern 源对象,Shape 与 BREP hash `35c40a35...` 完全一致;FCStd save/reopen/resave 三阶段无临时 Body/Pad 污染。 +- focused gate 与队列生成通过,队列完成项增加到 `436`,唯一新活动项为 `TSN-PAIR-polar-pattern-pocket`。 + +### `TSN-PAIR-polar-pattern-pocket` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,使用真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 执行 `5 -> 4 -> 5` 深度轨迹,采集阵列实体切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`polar-pattern->pocket` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 结果为有效 1 Solid、16 Face、38 Edge、24 Vertex、体积 `1392.6497308`、面积 `799.0598923` 和 55 条原生 history。 +- `5 -> 4 -> 5` 深度轨迹使体积在 `1392.6497308 -> 1398.6497308 -> 1392.6497308` 间变化,恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `c0fb0f57...`。 +- focused gate 与队列生成通过,队列完成项增加到 `437`,唯一新活动项为 `TSN-PAIR-polar-pattern-loft`。 + +### `TSN-PAIR-polar-pattern-loft` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepOffsetAPI_ThruSections` 执行 `false -> true -> false` ruled 轨迹,并用真实 `Part::Loft` 重算区分 OCCT kernel 能力与 FreeCAD 实体 section 合同。 + +#### 完成证据 + +`polar-pattern->loft` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT `BRepOffsetAPI_ThruSections` 的三次 ruled 尝试均生成有效 1 Solid、6 Face、12 Edge、8 Vertex、面积 `556.1837862` 和 24 条 history;恢复态一致,但只属于 kernel superset。 +- FreeCAD 1.1.1 真实 `Part::Loft` 重算以 `Profile shape is not a single vertex, edge, wire nor face.` 拒绝 Polar Pattern 实体 section,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后只保留有效 Polar Pattern 源对象,Shape 与 BREP hash `35c40a35...` 完全恢复;FCStd 三阶段干净稳定。 +- focused gate 与队列生成通过,队列完成项增加到 `438`,唯一新活动项为 `TSN-PAIR-polar-pattern-pipe`。 + +### `TSN-PAIR-polar-pattern-pipe` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepOffsetAPI_MakePipe` 执行 `15 -> 12 -> 15` spine 长度轨迹,并以真实 `Part::Sweep` 重算锁定最终 FreeCAD 合同。 + +#### 完成证据 + +`polar-pattern->pipe` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT `BRepOffsetAPI_MakePipe` 三次尝试均返回无效 Shape:1 Solid、6 Face、12 Edge、8 Vertex、体积 `0`;`15 -> 12 -> 15` 使面积 `500 -> 440 -> 500` 后恢复,kernel 结论为稳定 `invalid-result`。 +- FreeCAD 1.1.1 真实 `Part::Sweep` 重算返回 `A fatal error occurred when making the sweep`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后仅保留有效 Polar Pattern 源对象,Shape 与 BREP hash `35c40a35...` 完全恢复;FCStd 三阶段干净稳定。 +- focused gate 与队列生成通过,队列完成项增加到 `439`,唯一新活动项为 `TSN-PAIR-polar-pattern-revolution`。 + +### `TSN-PAIR-polar-pattern-revolution` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepPrimAPI_MakeRevol` 执行 `360 -> 270 -> 360` 角度轨迹,并用真实 `Part::Revolution` 重算、回滚和 FCStd 三阶段锁定实体输入合同。 + +#### 完成证据 + +`polar-pattern->revolution` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 下游真实 `BRepPrimAPI_MakeRevol` 的三次角度尝试均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 真实 `Part::Revolution` 重算返回该拓扑特有的 `BRep_API: command not done`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid;检查器据原生事实锁定该诊断,没有套用其他实体的通用文本。 +- 事务 abort 前后只保留 Polar Pattern 源对象,Shape 与 BREP hash `35c40a35...` 完全一致;FCStd 三阶段无失败 Revolution 污染。 +- focused gate 与队列生成通过,队列完成项增加到 `440`,唯一新活动项为 `TSN-PAIR-polar-pattern-groove`。 + +### `TSN-PAIR-polar-pattern-groove` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 执行 `360 -> 180 -> 360` 角度轨迹,采集旋转阵列实体切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`polar-pattern->groove` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Groove 结果为有效 1 Solid、16 Face、41 Edge、26 Vertex、体积 `1413.279598`、面积 `787.2071345` 和 23 条原生 history。 +- `360 -> 180 -> 360` 角度轨迹使编辑态回到 Polar Pattern 源体积与面积,但拓扑与 history 同步改变;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `bbb3977c...`。 +- focused gate 与队列生成通过,队列完成项增加到 `441`,唯一新活动项为 `TSN-PAIR-polar-pattern-fillet`。 + +### `TSN-PAIR-polar-pattern-fillet` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;首次按接受路径运行真实 `BRepFilletAPI_MakeFillet`,原生 WASM 在构造阶段崩溃,门禁 fail-closed;随后显式转为拒绝探针,重复 `0.4 -> 0.6 -> 0.4` 并采集 FreeCAD 文档重算、事务回滚与 FCStd 三阶段证据。 + +#### 完成证据 + +`polar-pattern->fillet` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- OCCT 全边 `BRepFilletAPI_MakeFillet` 的三次半径尝试均在 builder 阶段稳定触发 `null function or function signature mismatch`,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 真实 `Part::Fillet` 对全部 26 条边重算返回 `BRep_API: command not done`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 前后只保留 Polar Pattern 源对象,Shape 与 BREP hash `35c40a35...` 完全一致;FCStd 三阶段无失败 Fillet 污染。 +- focused gate 与队列生成通过,队列完成项增加到 `442`,唯一新活动项为 `TSN-PAIR-polar-pattern-chamfer`。 + +### `TSN-PAIR-polar-pattern-chamfer` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;首次按接受路径运行真实 `BRepFilletAPI_MakeChamfer` 时 builder 抛出原生 C++ exception,门禁 fail-closed;随后显式转为拒绝探针,执行 `0.4 -> 0.6 -> 0.4` 并采集 FreeCAD 文档重算、事务回滚和 FCStd 三阶段证据。 + +#### 完成证据 + +`polar-pattern->chamfer` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- OCCT 全边 `BRepFilletAPI_MakeChamfer` 的三次距离尝试均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 真实 `Part::Chamfer` 对全部 26 条边重算返回 `BRep_API: command not done`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 前后只保留 Polar Pattern 源对象,Shape 与 BREP hash `35c40a35...` 完全一致;FCStd 三阶段无失败 Chamfer 污染。 +- focused gate 与队列生成通过,队列完成项增加到 `443`,唯一新活动项为 `TSN-PAIR-polar-pattern-hole`。 + +### `TSN-PAIR-polar-pattern-hole` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` 执行 `1 -> 1.5 -> 1` 半径轨迹,采集孔切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`polar-pattern->hole` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Hole 结果为有效 1 Solid、13 Face、29 Edge、18 Vertex、体积 `1391.2338043`、面积 `825.6085601` 和 23 条原生 history。 +- `1 -> 1.5 -> 1` 半径轨迹使体积在 `1391.2338043 -> 1351.9638961 -> 1391.2338043` 间变化,恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游为无歧义 `native-evidence` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `82648785...`。 +- focused gate 与队列生成通过,队列完成项增加到 `444`,唯一新活动项为 `TSN-PAIR-polar-pattern-draft`。 + +### `TSN-PAIR-polar-pattern-draft` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;首次按接受路径运行真实 `BRepOffsetAPI_DraftAngle` 时 builder 抛出原生 C++ exception,门禁 fail-closed;随后切换为拒绝探针,执行 `5 -> 8 -> 5` 并采集真实 `PartDesign::Draft` 重算、Shape 转移、事务回滚和 FCStd 三阶段证据。 + +#### 完成证据 + +`polar-pattern->draft` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- OCCT Draft 的三次角度尝试均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 真实 `PartDesign::Draft` 通过 `DraftBase` 接收逐字段一致的 Shape 摘要,但 BREP 明确重序列化;重算状态为 `Touched/Invalid`、Shape 为 null/invalid,诊断字符串为空,均被检查器精确锁定。 +- 事务 abort 后源对象集、Shape 摘要与原始 BREP hash `35c40a35...` 完全恢复;FCStd 三阶段无 DraftBase、Datum 或失败 Draft 污染。 +- focused gate 与队列生成通过,队列完成项增加到 `445`,唯一新活动项为 `TSN-PAIR-polar-pattern-thickness`。 + +### `TSN-PAIR-polar-pattern-thickness` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;接受路径因 `-0.4 -> -0.6 -> -0.4` 三阶段 Shape/history 不变而 fail-closed,随后转入显式 `occt-no-op` 分支。STEP 往返带来单个边界值 `1e-7` 的重序列化差异,因此新增仅对该任务启用的“拓扑精确 + 几何度量 `1e-6` 容差”no-op 合同,并采集 FreeCAD 文档状态与回滚证据。 + +#### 完成证据 + +`polar-pattern->thickness` 已完成 OCCT/FreeCAD 双层 no-op 分类: + +- OCCT `BRepOffsetAPI_MakeThickSolid` 的三次 offset 尝试均返回有效 1 Solid、12 Face、26 Edge、16 Vertex、体积 `1422.6497308`、面积 `769.0598923` 和 1 条稳定 history;参数变异没有产生厚壳效果。 +- 输出与输入仅在 Y 上界存在约 `1e-7` 的 STEP 数值重序列化,检查器显式要求 `noOpComparison=topology-and-metrics-within-1e-6`,未把该漂移隐藏为逐字段 exact。 +- FreeCAD 1.1.1 真实 `Part::Thickness` 对 `Face2` 重算保持 `Valid/Up-to-date`,结果 Shape 摘要与输入一致;事务 abort 后几何双向差体积为零,但 BREP hash 从 `35c40a35...` 变为 `3258844f...`,该重序列化已明确分类。 +- focused gate 与队列生成通过,队列完成项增加到 `446`,唯一新活动项为 `TSN-PAIR-polar-pattern-linear-pattern`。 + +### `TSN-PAIR-thickness-multi-transform` + +#### 执行过程 + +1. 从最新机器队列领取 Thickness 行最后一个活动项;扩展连续探针前缀,使用真实有序 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)` 执行 `8 -> 9 -> 8` 线性距离轨迹,并锁定后续镜像整个中间结果的顺序语义。 + +#### 完成证据 + +`thickness->multi-transform` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实有序 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)` 结果为有效 1 Solid、50 Face、104 Edge、64 Vertex、体积 `534.784`、面积 `2645.76` 和 714 条原生 history。 +- `8 -> 9 -> 8` 距离轨迹使编辑态体积变为 `565.504`、面积变为 `2799.36`,边界同步扩展;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `9b00aefd...`。 +- focused gate 与 `git diff --check` 通过;Thickness 行 19/19 有序操作对全部闭合,队列完成项增加到 `412`,唯一新活动项为 `TSN-PAIR-linear-pattern-fuse`。 + +### Thickness 行边界完整验证 + +#### 执行过程 + +1. 在跨入 Linear Pattern 行前运行完整 `./npmw run verify`,验证新增分类、原生崩溃/选边分层合同、活动队列、构建、PWA、发布文件与签名闭环。 + +#### 完成证据 + +- 完整 `./npmw run verify` 通过:282 个逐对原生分类与 4 个既有生产转换覆盖、全套浏览器与单元测试、FCStd/几何/Sketch fuzz、生产构建、PWA、79 个发布文件、release closure 与 Ed25519 签名全部通过。 +- 发布矩阵继续严格保持 `0 exact / 26 compatible / 5 proxy / 3 development`,系统级 `systemExact=false`;局部有序操作对闭合没有越权提升能力声明。 + +### `TSN-PAIR-linear-pattern-fuse` + +#### 执行过程 + +1. 从最新机器队列领取 Linear Pattern 行首个活动项;扩展连续探针前缀,以真实上游平移阵列和下游 `BRepAlgoAPI_Fuse` 工具执行变异、恢复、naming 与 FCStd 三阶段采样。 + +#### 完成证据 + +`linear-pattern->fuse` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游 Linear Pattern 为有效 1 Solid、14 Face、28 Edge、16 Vertex、体积 `1800`、面积 `920` 和 66 条原生 history。 +- 默认工具完全位于上游实体内部而成为 no-op;将下游 Fuse 工具修正为部分越出实体的 `16 -> 15 -> 16` 偏移轨迹后,名义结果体积 `1875`、编辑态体积 `1850`,恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游真实 `BRepAlgoAPI_Fuse` 结果为有效 1 Solid、21 Face、45 Edge、26 Vertex 和 52 条原生 history;FCStd 三阶段保持 Shape 及 naming evidence hash `2834ea3b...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `413`,唯一新活动项为 `TSN-PAIR-linear-pattern-cut`。 + +### `TSN-PAIR-linear-pattern-cut` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepAlgoAPI_Cut` 执行 `4 -> 3 -> 4` 工具尺寸轨迹,采集阵列实体切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`linear-pattern->cut` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepAlgoAPI_Cut` 结果为有效 1 Solid、18 Face、40 Edge、24 Vertex、体积 `1736`、面积 `952` 和 22 条原生 history。 +- `4 -> 3 -> 4` 工具尺寸轨迹使体积在 `1736 -> 1773 -> 1736` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `2c8836f5...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `414`,唯一新活动项为 `TSN-PAIR-linear-pattern-common`。 + +### `TSN-PAIR-linear-pattern-common` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepAlgoAPI_Common` 执行 `10 -> 9 -> 10` 工具偏移轨迹,采集交集、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`linear-pattern->common` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepAlgoAPI_Common` 名义结果为有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `125`、面积 `150` 和 205 条原生 history。 +- `10 -> 9 -> 10` 工具偏移轨迹保持体积 `125`,但编辑态变为 8 Face、17 Edge、11 Vertex,边界与 history 同步改变;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `655fa2c5...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `415`,唯一新活动项为 `TSN-PAIR-linear-pattern-rotate`。 + +### `TSN-PAIR-linear-pattern-rotate` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,使用真实 `BRepBuilderAPI_Transform` 执行 `15 -> 22.5 -> 15` 角度轨迹,采集刚体边界变化、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`linear-pattern->rotate` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepBuilderAPI_Transform` 保持有效 1 Solid、14 Face、28 Edge、16 Vertex、体积 `1800`、面积 `920`,生成 182 条原生 history。 +- `15 -> 22.5 -> 15` 角度轨迹改变包围盒但保持质量属性,恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `aceb3c19...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `416`,唯一新活动项为 `TSN-PAIR-linear-pattern-pad`。 + +### `TSN-PAIR-linear-pattern-pad` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepPrimAPI_MakePrism` 执行 `5 -> 7.5 -> 5` 长度轨迹,并用真实 `PartDesign::Pad` 重算、回滚和 FCStd 三阶段锁定实体输入合同。 + +#### 完成证据 + +`linear-pattern->pad` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 下游真实 `BRepPrimAPI_MakePrism` 的 `5 -> 7.5 -> 5` 三次尝试均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 真实 `PartDesign::Pad` 重算返回 `FeatureExtrusion: Length: Could not extrude the sketch!`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- abort 前后仅保留 Linear Pattern 源对象,Shape 与 BREP hash `3294bb87...` 完全一致;FCStd save/reopen/resave 三阶段无临时 Body/Pad 污染。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `417`,唯一新活动项为 `TSN-PAIR-linear-pattern-pocket`。 + +### `TSN-PAIR-linear-pattern-pocket` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,使用真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 执行 `5 -> 4 -> 5` 深度轨迹,采集阵列实体切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`linear-pattern->pocket` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 结果为有效 1 Solid、17 Face、37 Edge、22 Vertex、体积 `1770`、面积 `920` 和 42 条原生 history。 +- `5 -> 4 -> 5` 深度轨迹使体积在 `1770 -> 1776 -> 1770` 间变化,恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `b06bd539...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `418`,唯一新活动项为 `TSN-PAIR-linear-pattern-loft`。 + +### `TSN-PAIR-linear-pattern-loft` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepOffsetAPI_ThruSections` 执行 `false -> true -> false` ruled 轨迹,并用真实 `Part::Loft` 重算区分 OCCT kernel 能力与 FreeCAD 实体 section 合同。 + +#### 完成证据 + +`linear-pattern->loft` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT `BRepOffsetAPI_ThruSections` 的三次 ruled 尝试均生成有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `750`、面积 `580.2775638` 和 24 条 history;恢复态一致,但只属于 kernel superset。 +- FreeCAD 1.1.1 真实 `Part::Loft` 文档重算以 `Profile shape is not a single vertex, edge, wire nor face.` 拒绝 Linear Pattern 实体 section,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后仅保留有效 Linear Pattern 源对象,Shape 与 BREP hash `3294bb87...` 完全恢复;FCStd save/reopen/resave 三阶段干净稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `419`,唯一新活动项为 `TSN-PAIR-linear-pattern-pipe`。 + +### `TSN-PAIR-linear-pattern-pipe` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepOffsetAPI_MakePipe` 执行 `15 -> 12 -> 15` spine 长度轨迹,并以真实 `Part::Sweep` 重算锁定最终 FreeCAD 合同。 + +#### 完成证据 + +`linear-pattern->pipe` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT `BRepOffsetAPI_MakePipe` 的三次尝试均返回无效 Shape:1 Solid、6 Face、12 Edge、8 Vertex、体积 `0` 和 28 条 history;`15 -> 12 -> 15` 使面积 `500 -> 440 -> 500` 后恢复,kernel 结论为稳定 `invalid-result`。 +- FreeCAD 1.1.1 真实 `Part::Sweep` 文档重算返回 `A fatal error occurred when making the sweep`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后仅保留有效 Linear Pattern 源对象,Shape 与 BREP hash `3294bb87...` 完全恢复;FCStd 三阶段干净稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `420`,唯一新活动项为 `TSN-PAIR-linear-pattern-revolution`。 + +### `TSN-PAIR-linear-pattern-revolution` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepPrimAPI_MakeRevol` 执行 `360 -> 270 -> 360` 角度轨迹,并用真实 `Part::Revolution` 重算、回滚和 FCStd 三阶段锁定实体输入合同。 + +#### 完成证据 + +`linear-pattern->revolution` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 下游真实 `BRepPrimAPI_MakeRevol` 对 Linear Pattern 实体执行 `360 -> 270 -> 360`;三次均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 真实 `Part::Revolution` 文档重算返回 `Solids are not Processed`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 前后只保留 Linear Pattern 源对象,Shape 与 BREP hash `3294bb87...` 完全一致;FCStd 三阶段无失败 Revolution 污染。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `421`,唯一新活动项为 `TSN-PAIR-linear-pattern-groove`。 + +### `TSN-PAIR-linear-pattern-groove` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,使用真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 执行 `360 -> 180 -> 360` 角度轨迹,采集阵列实体切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`linear-pattern->groove` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 结果为有效 1 Solid、18 Face、40 Edge、24 Vertex、体积 `1795.287611`、面积 `926.5663706` 和 18 条原生 history。 +- `360 -> 180 -> 360` 角度轨迹使编辑态回到 Linear Pattern 源体积 `1800` 和面积 `920`,但拓扑与 history 同步改变;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `1200720c...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `422`,唯一新活动项为 `TSN-PAIR-linear-pattern-fillet`。 + +### `TSN-PAIR-linear-pattern-fillet` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepFilletAPI_MakeFillet` 对 Linear Pattern 边集合执行 `0.4 -> 0.6 -> 0.4` 半径轨迹,先由实测 builder 结果决定分类。 + +#### 完成证据 + +`linear-pattern->fillet` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepFilletAPI_MakeFillet` 结果为有效 1 Solid、42 Face、88 Edge、40 Vertex、体积 `1794.8665943`、面积 `893.7231781` 和 270 条原生 history。 +- `0.4 -> 0.6 -> 0.4` 半径轨迹使体积在 `1794.8665943 -> 1788.5462621 -> 1794.8665943` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `b22c4cbd...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `423`,唯一新活动项为 `TSN-PAIR-linear-pattern-chamfer`。 + +### `TSN-PAIR-linear-pattern-chamfer` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepFilletAPI_MakeChamfer` 对 Linear Pattern 边集合执行 `0.4 -> 0.6 -> 0.4` 距离轨迹,先由实测 builder 结果决定分类。 + +#### 完成证据 + +`linear-pattern->chamfer` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepFilletAPI_MakeChamfer` 结果为有效 1 Solid、42 Face、80 Edge、40 Vertex、体积 `1788.1813333`、面积 `883.902117` 和 270 条原生 history。 +- `0.4 -> 0.6 -> 0.4` 距离轨迹使体积在 `1788.1813333 -> 1773.792 -> 1788.1813333` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `a68b7d31...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `424`,唯一新活动项为 `TSN-PAIR-linear-pattern-hole`。 + +### `TSN-PAIR-linear-pattern-hole` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` 执行 `1 -> 1.5 -> 1` 半径轨迹,采集孔切除、恢复、naming 与 FCStd 三阶段证据。 + +#### 完成证据 + +`linear-pattern->hole` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` 结果为有效 1 Solid、15 Face、31 Edge、18 Vertex、体积 `1768.5840735`、面积 `976.5486678` 和 23 条原生 history。 +- `1 -> 1.5 -> 1` 半径轨迹使体积在 `1768.5840735 -> 1729.3141653 -> 1768.5840735` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游为无歧义 `native-evidence` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `c92719e0...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `425`,唯一新活动项为 `TSN-PAIR-linear-pattern-draft`。 + +### `TSN-PAIR-linear-pattern-draft` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepOffsetAPI_DraftAngle` 对锁定阵列面执行 `5 -> 8 -> 5` 角度轨迹,由有效 Shape 或原生拒绝决定分类。 + +#### 完成证据 + +`linear-pattern->draft` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepOffsetAPI_DraftAngle` 结果为有效 1 Solid、14 Face、28 Edge、16 Vertex、体积 `1756.2556682`、面积 `902.884251` 和 5 条原生 history。 +- `5 -> 8 -> 5` 角度轨迹使体积在 `1756.2556682 -> 1729.7295826 -> 1756.2556682` 间变化,面积同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游为无歧义 `native-evidence` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `43f06ae0...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `426`,唯一新活动项为 `TSN-PAIR-linear-pattern-thickness`。 + +### `TSN-PAIR-linear-pattern-thickness` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实 `BRepOffsetAPI_MakeThickSolid` 对阵列实体执行 `-0.4 -> -0.6 -> -0.4` offset 轨迹,由有效变异、no-op、invalid-result 或拒绝实测确定分类。首次按 accepted mutation 运行因三阶段 Shape/history 完全不变而 fail-closed,随后显式转入 `occt-no-op` 分支采集 FreeCAD 文档合同。 + +#### 完成证据 + +`linear-pattern->thickness` 已完成 OCCT/FreeCAD 双层 no-op 分类: + +- OCCT `BRepOffsetAPI_MakeThickSolid` 的 `-0.4 -> -0.6 -> -0.4` 三次尝试均返回与上游输入摘要完全一致的有效 1 Solid、14 Face、28 Edge、16 Vertex、体积 `1800`、面积 `920` 和 1 条稳定 history。 +- FreeCAD 1.1.1 真实 `Part::Thickness` 对 `Face2` 重算保持 `Valid/Up-to-date`,结果 Shape 与输入逐字段一致,明确归类为 no-op 而非 accepted mutation。 +- 事务 abort 后源 Shape 的几何、拓扑摘要与双向对称差体积精确恢复,但 FreeCAD 明确重序列化 BREP,hash 从 `3294bb87...` 变为 `aa2fbaf6...`;FCStd save/reopen/resave 三阶段稳定。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `427`,唯一新活动项为 `TSN-PAIR-linear-pattern-linear-pattern`。 + +### `TSN-PAIR-linear-pattern-linear-pattern` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以第二次真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `8 -> 9 -> 8` 平移轨迹,采集重复阵列的顺序几何、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`linear-pattern->linear-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游第二次真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 结果为有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2600`、面积 `1240`、X 上界 `26` 和 258 条原生 history。 +- `8 -> 9 -> 8` 平移轨迹使编辑态变为 30 Face、60 Edge、32 Vertex、体积 `2700`、X 上界 `27`;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `d86c008d...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `428`,唯一新活动项为 `TSN-PAIR-linear-pattern-polar-pattern`。 + +### `TSN-PAIR-linear-pattern-polar-pattern` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实旋转 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `30 -> 45 -> 30` 角度轨迹,采集顺序阵列几何、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`linear-pattern->polar-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实旋转 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 结果为有效 1 Solid、34 Face、74 Edge、42 Vertex、体积 `2745.5216016`、面积 `1227.4462449` 和 190 条原生 history。 +- `30 -> 45 -> 30` 角度轨迹使编辑态变为 31 Face、65 Edge、36 Vertex、体积 `3100`、面积 `1398.5786438`,边界与 history 同步变化;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `786f8db0...`。 +- focused gate 与 `git diff --check` 通过,队列完成项增加到 `429`,唯一新活动项为 `TSN-PAIR-linear-pattern-mirrored`。 + +### `TSN-PAIR-linear-pattern-mirrored` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;扩展连续探针前缀,以真实镜像 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `5 -> 6 -> 5` 平面轨迹,采集对称态、偏移态、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`linear-pattern->mirrored` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游镜像与 Fuse 结果为有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2600`、面积 `1240` 和 258 条原生 history。 +- `5 -> 6 -> 5` 平面轨迹使编辑态变为 30 Face、60 Edge、32 Vertex、体积 `2400`、面积 `1160`;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `027719405b2d...`。 +- focused gate 通过,队列完成项增加到 `430`,唯一新活动项为 `TSN-PAIR-linear-pattern-multi-transform`。 + +### `TSN-PAIR-linear-pattern-multi-transform` + +#### 执行过程 + +1. 扩展连续探针前缀,以有序的真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `8 -> 9 -> 8` 多变换平移轨迹,采集顺序几何、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`linear-pattern->multi-transform` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游有序多变换结果为有效 1 Solid、38 Face、76 Edge、40 Vertex、体积 `4200`、面积 `1880` 和 783 条原生 history。 +- `8 -> 9 -> 8` 轨迹使编辑态变为 54 Face、108 Edge、56 Vertex、体积 `4400`、面积 `1960`;恢复态精确回到名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd 三阶段保持 Shape 及 naming evidence hash `7770e81b7b87...`。 +- focused gate 通过,队列完成项增加到 `431`,唯一新活动项为 `TSN-PAIR-polar-pattern-fuse`。 + +### `TSN-PAIR-polar-pattern-fuse` + +#### 执行过程 + +1. 进入 Polar Pattern 行,以真实 `BRepAlgoAPI_Fuse` 执行 `8 -> 7 -> 8` 工具偏移轨迹,采集布尔、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`polar-pattern->fuse` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游 Fuse 结果为有效 1 Solid、21 Face、46 Edge、27 Vertex、体积 `1497.6497308`、面积 `829.0598923` 和 64 条原生 history。 +- `8 -> 7 -> 8` 轨迹使体积在 `1497.6497308 -> 1472.6497308 -> 1497.6497308` 间变化,恢复态精确返回名义 Shape、history hash 和语义 naming。 +- FCStd 三阶段保持 Shape 及 naming evidence hash `7edcf0776ed0...`;队列完成项增加到 `432`,唯一新活动项为 `TSN-PAIR-polar-pattern-cut`。 + +### `TSN-PAIR-polar-pattern-cut` + +#### 执行过程 + +1. 以真实 `BRepAlgoAPI_Cut` 执行 `4 -> 3 -> 4` 工具尺寸轨迹,采集切除、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`polar-pattern->cut` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游 Cut 结果为有效 1 Solid、17 Face、41 Edge、26 Vertex、体积 `1358.6497308`、面积 `801.0598923` 和 34 条原生 history。 +- `4 -> 3 -> 4` 轨迹使体积在 `1358.6497308 -> 1395.6497308 -> 1358.6497308` 间变化,恢复态精确返回名义证据。 +- FCStd 三阶段保持 Shape 及 naming evidence hash `567c4970bb66...`;队列完成项增加到 `433`,唯一新活动项为 `TSN-PAIR-polar-pattern-common`。 + +### `TSN-PAIR-polar-pattern-common` + +#### 执行过程 + +1. 以真实 `BRepAlgoAPI_Common` 执行 `7 -> 6 -> 7` 工具偏移轨迹,采集交集、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`polar-pattern->common` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游 Common 结果为有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `75`、面积 `110` 和 213 条原生 history。 +- `7 -> 6 -> 7` 轨迹使编辑态体积变为 `100`、面积变为 `130`,恢复态精确返回名义证据。 +- FCStd 三阶段保持 Shape 及 naming evidence hash `726029e76f1c...`;队列完成项增加到 `434`,唯一新活动项为 `TSN-PAIR-polar-pattern-rotate`。 + +### `TSN-PAIR-polar-pattern-rotate` + +#### 执行过程 + +1. 以真实 `BRepBuilderAPI_Transform` 执行 `15 -> 22.5 -> 15` 角度轨迹,采集刚体边界变化、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`polar-pattern->rotate` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游 Rotate 保持有效 1 Solid、12 Face、26 Edge、16 Vertex、体积 `1422.6497308`、面积 `769.0598923`,并生成 168 条原生 history。 +- 角度轨迹改变包围盒而保持质量属性,恢复态精确返回名义 Shape、history hash 和语义 naming。 +- FCStd 三阶段保持 Shape 及 naming evidence hash `0f073ae2b76e...`;队列完成项增加到 `435`,唯一新活动项为 `TSN-PAIR-polar-pattern-pad`。 + +### `TSN-PAIR-polar-pattern-pad` + +#### 执行过程 + +1. 以真实 `BRepPrimAPI_MakePrism` 执行 `5 -> 7.5 -> 5` 长度轨迹,并用真实 `PartDesign::Pad` 重算、回滚和 FCStd 三阶段锁定实体输入合同。 + +#### 完成证据 + +`polar-pattern->pad` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 下游 Prism builder 的三次尝试均以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 `PartDesign::Pad` 重算返回 `FeatureExtrusion: Length: Could not extrude the sketch!`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- abort 前后仅保留 Polar Pattern 源对象,Shape 与 BREP hash `35c40a356cdc...` 恢复;FCStd 三阶段无失败 Pad 污染。 +- focused gate 通过,队列完成项增加到 `436`,唯一新活动项为 `TSN-PAIR-polar-pattern-pocket`。 + +### `TSN-PAIR-polar-pattern-pocket` + +#### 执行过程 + +1. 以真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 执行 `5 -> 4 -> 5` 深度轨迹,采集切除、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`polar-pattern->pocket` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游 Pocket 结果为有效 1 Solid、16 Face、38 Edge、24 Vertex、体积 `1392.6497308`、面积 `799.0598923` 和 55 条原生 history。 +- `5 -> 4 -> 5` 轨迹使编辑态体积变为 `1398.6497308`、面积变为 `793.0598923`,恢复态精确返回名义证据。 +- FCStd 三阶段保持 Shape 及 naming evidence hash `c0fb0f578a88...`;队列完成项增加到 `437`,唯一新活动项为 `TSN-PAIR-polar-pattern-loft`。 + +### `TSN-PAIR-polar-pattern-loft` + +#### 执行过程 + +1. 以真实 `BRepOffsetAPI_ThruSections` 执行 `false -> true -> false` ruled 轨迹,并用真实 `Part::Loft` 重算锁定 FreeCAD 实体 section 合同。 + +#### 完成证据 + +`polar-pattern->loft` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT `BRepOffsetAPI_ThruSections` 生成有效 1 Solid、6 Face、12 Edge、8 Vertex 和 24 条 history,恢复态一致,但该结果只属于 kernel superset。 +- FreeCAD 1.1.1 `Part::Loft` 以 `Profile shape is not a single vertex, edge, wire nor face.` 拒绝 Polar Pattern 实体 section,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- abort 后源 Shape 与 BREP hash `35c40a356cdc...` 恢复,FCStd 三阶段干净稳定;队列完成项增加到 `438`,唯一新活动项为 `TSN-PAIR-polar-pattern-pipe`。 + +### `TSN-PAIR-polar-pattern-pipe` + +#### 执行过程 + +1. 以真实 `BRepOffsetAPI_MakePipe` 执行 `15 -> 12 -> 15` spine 长度轨迹,并用真实 `Part::Sweep` 重算锁定最终 FreeCAD 合同。 + +#### 完成证据 + +`polar-pattern->pipe` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT Pipe 三次均返回无效 Shape:1 Solid、6 Face、12 Edge、8 Vertex、体积 `0` 和 28 条 history,并在参数恢复后精确返回名义无效结果。 +- FreeCAD 1.1.1 `Part::Sweep` 返回 `A fatal error occurred when making the sweep`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- abort 后源 Shape 与 BREP hash `35c40a356cdc...` 恢复,FCStd 三阶段干净稳定;队列完成项增加到 `439`,唯一新活动项为 `TSN-PAIR-polar-pattern-revolution`。 + +### `TSN-PAIR-polar-pattern-revolution` + +#### 执行过程 + +1. 以真实 `BRepPrimAPI_MakeRevol` 执行 `360 -> 270 -> 360` 角度轨迹,并用真实 `Part::Revolution` 重算、回滚和 FCStd 三阶段锁定实体输入合同。 + +#### 完成证据 + +`polar-pattern->revolution` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- Revol builder 三次均以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 `Part::Revolution` 重算返回 `BRep_API: command not done`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- abort 后源 Shape 与 BREP hash `35c40a356cdc...` 恢复,FCStd 三阶段无失败 Revolution 污染;队列完成项增加到 `440`,唯一新活动项为 `TSN-PAIR-polar-pattern-groove`。 + +### `TSN-PAIR-polar-pattern-groove` + +#### 执行过程 + +1. 以真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 执行 `360 -> 180 -> 360` 角度轨迹,采集旋转减料、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`polar-pattern->groove` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游 Groove 结果为有效 1 Solid、16 Face、41 Edge、26 Vertex、体积 `1413.279598`、面积 `787.2071345` 和 23 条原生 history。 +- `360 -> 180 -> 360` 轨迹使编辑态变为 14 Face、36 Edge、25 Vertex,质量属性回到上游值;恢复态精确返回名义证据。 +- FCStd 三阶段保持 Shape 及 naming evidence hash `bbb3977c389a...`;队列完成项增加到 `441`,唯一新活动项为 `TSN-PAIR-polar-pattern-fillet`。 + +### `TSN-PAIR-polar-pattern-fillet` + +#### 执行过程 + +1. 以真实 `BRepFilletAPI_MakeFillet` 对 Polar Pattern 全边执行 `0.4 -> 0.6 -> 0.4` 半径轨迹,并用真实 `Part::Fillet` 验证失败回滚。 + +#### 完成证据 + +`polar-pattern->fillet` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- Fillet builder 三次均在 builder 阶段以稳定 Emscripten wasm abort `null function or function signature mismatch` 拒绝,不产出 Shape 或 history。 +- FreeCAD 1.1.1 `Part::Fillet` 重算返回 `BRep_API: command not done`,状态为 `Touched/Invalid`。 +- abort 后源 Shape 与 BREP hash `35c40a356cdc...` 恢复,FCStd 三阶段干净稳定;队列完成项增加到 `442`,唯一新活动项为 `TSN-PAIR-polar-pattern-chamfer`。 + +### `TSN-PAIR-polar-pattern-chamfer` + +#### 执行过程 + +1. 以真实 `BRepFilletAPI_MakeChamfer` 对 Polar Pattern 全边执行 `0.4 -> 0.6 -> 0.4` 距离轨迹,并用真实 `Part::Chamfer` 验证失败回滚。 + +#### 完成证据 + +`polar-pattern->chamfer` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- Chamfer builder 三次均在 builder 阶段以稳定 Emscripten C++ exception 拒绝,不产出 Shape 或 history。 +- FreeCAD 1.1.1 `Part::Chamfer` 重算返回 `BRep_API: command not done`,状态为 `Touched/Invalid`。 +- abort 后源 Shape 与 BREP hash `35c40a356cdc...` 恢复,FCStd 三阶段干净稳定;队列完成项增加到 `443`,唯一新活动项为 `TSN-PAIR-polar-pattern-hole`。 + +### `TSN-PAIR-polar-pattern-hole` + +#### 执行过程 + +1. 以真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` 执行 `1 -> 1.5 -> 1` 半径轨迹,采集孔切除、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`polar-pattern->hole` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游 Hole 结果为有效 1 Solid、13 Face、29 Edge、18 Vertex、体积 `1391.2338043`、面积 `825.6085601` 和 23 条原生 history。 +- `1 -> 1.5 -> 1` 轨迹使编辑态体积变为 `1351.9638961`、面积变为 `849.170505`,恢复态精确返回名义证据。 +- 下游获得无歧义 `native-evidence` naming;FCStd 三阶段保持 Shape 及 naming evidence hash `826487854eec...`。 +- focused gate 通过,队列完成项增加到 `444`,唯一新活动项为 `TSN-PAIR-polar-pattern-draft`。 + +### `TSN-PAIR-polar-pattern-draft` + +#### 执行过程 + +1. 以真实 `BRepOffsetAPI_DraftAngle` 对锁定阵列面执行 `5 -> 8 -> 5` 角度轨迹,并用真实 `PartDesign::Draft` 重算锁定失败合同。 + +#### 完成证据 + +`polar-pattern->draft` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- Draft builder 的三次尝试均以 Emscripten C++ exception 稳定拒绝,不产出 Shape 或 history。 +- FreeCAD 1.1.1 `PartDesign::Draft` 产出 null/invalid Shape 和 `Touched/Invalid` 状态,无伪造成功结果。 +- abort 后源 Shape 与 BREP hash `35c40a356cdc...` 恢复,FCStd 三阶段干净稳定;队列完成项增加到 `445`,唯一新活动项为 `TSN-PAIR-polar-pattern-thickness`。 + +### `TSN-PAIR-polar-pattern-thickness` + +#### 执行过程 + +1. 以真实 `BRepOffsetAPI_MakeThickSolid` 执行 `-0.4 -> -0.6 -> -0.4` offset 轨迹,并通过真实 `Part::Thickness` 重算区分接受变异与 no-op。 + +#### 完成证据 + +`polar-pattern->thickness` 已完成 OCCT/FreeCAD 双层 no-op 分类: + +- OCCT ThickSolid 三次均返回与上游输入摘要一致的有效 1 Solid、12 Face、26 Edge、16 Vertex、体积 `1422.6497308`、面积 `769.0598923` 和 1 条稳定 history。 +- FreeCAD 1.1.1 `Part::Thickness` 保持 `Valid/Up-to-date`,结果 Shape 与输入摘要一致,明确归类为 no-op。 +- abort 后几何和拓扑摘要精确恢复,但 FreeCAD 重序列化 BREP,hash 从 `35c40a356cdc...` 变为 `3258844f37ad...`;FCStd 三阶段稳定。 +- focused gate 通过,队列完成项增加到 `446`,唯一新活动项为 `TSN-PAIR-polar-pattern-linear-pattern`。 + +### `TSN-PAIR-polar-pattern-linear-pattern` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;以真实平移 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `8 -> 9 -> 8` 轨迹,采集顺序阵列几何、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`polar-pattern->linear-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游 Linear Pattern 结果为有效 1 Solid、36 Face、78 Edge、44 Vertex、体积 `2376.9059892`、面积 `1149.1931763` 和 175 条原生 history。 +- `8 -> 9 -> 8` 轨迹使编辑态变为 33 Face、71 Edge、40 Vertex、体积 `2477.3502692`、面积 `1190.9401077`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd 三阶段保持 Shape 及 naming evidence hash `fa130287b001...`。 +- `./npmw run check:freecad-ordered-operation-pairs` 通过,队列完成项增加到 `447`,唯一新活动项为 `TSN-PAIR-polar-pattern-polar-pattern`。 + +### `TSN-PAIR-polar-pattern-polar-pattern` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器,以第二次真实旋转 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `30 -> 45 -> 30` 角度轨迹。 +2. 首次聚焦检查仅因汇总锁停在 317 项而失败;将汇总同步为已分类 318、接受 230、拒绝 88、剩余 43 后重跑通过。 + +#### 完成证据 + +`polar-pattern->polar-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游第二次 Polar Pattern 结果为有效 1 Solid、20 Face、44 Edge、26 Vertex、体积 `1845.2994616`、面积 `938.1197846` 和 228 条原生 history。 +- `30 -> 45 -> 30` 轨迹使编辑态变为 30 Face、66 Edge、38 Vertex、体积 `2077.9724736`、面积 `1031.1889895`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `47e7c088e25a...`。 +- focused gate 通过,队列完成项增加到 `448`,唯一新活动项为 `TSN-PAIR-polar-pattern-mirrored`。 + +### `TSN-PAIR-polar-pattern-mirrored` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器,以真实镜像 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `5 -> 6 -> 5` 平面轨迹。 + +#### 完成证据 + +`polar-pattern->mirrored` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游 Mirrored 结果为有效 1 Solid、21 Face、47 Edge、28 Vertex、体积 `1834.9364905`、面积 `920.5771366` 和 250 条原生 history。 +- `5 -> 6 -> 5` 轨迹使编辑态变为 32 Face、70 Edge、40 Vertex、体积 `2045.2994616`、面积 `1018.1197846`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `72f0a2e0f8fa...`。 +- focused gate 通过,队列完成项增加到 `449`,唯一新活动项为 `TSN-PAIR-polar-pattern-multi-transform`。 + +### `TSN-PAIR-polar-pattern-multi-transform` + +#### 执行过程 + +1. 从最新机器队列领取 Polar Pattern 行最后一项;将操作对加入连续探针前缀与聚焦检查器,以有序的真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `8 -> 9 -> 8` 多变换平移轨迹。 + +#### 完成证据 + +`polar-pattern->multi-transform` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游有序 Multi Transform 结果为有效 1 Solid、115 Face、241 Edge、128 Vertex、体积 `3052.108193`、面积 `1415.9432402` 和 1187 条原生 history。 +- `8 -> 9 -> 8` 轨迹使编辑态变为 91 Face、193 Edge、104 Vertex、体积 `3291.7085548`、面积 `1506.9573233`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `2fe760a0f6d3...`。 +- focused gate 通过,队列完成项增加到 `450`,唯一新活动项为 `TSN-PAIR-mirrored-fuse`。 +- 批次收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;机器队列保持恰好一个 `in_progress` 任务。 + +### `TSN-PAIR-mirrored-fuse` + +#### 执行过程 + +1. 从最新机器队列领取 Mirrored 行首项;将操作对加入连续探针前缀与聚焦检查器,首先以通用 `12 -> 11 -> 12` 工具偏移轨迹执行真实 `BRepAlgoAPI_Fuse`。 +2. 首次探针 fail-closed:工具与上游实体脱离,OCCT 返回有效 2-Solid Compound、体积 `1125`,但 history 为空,不符合接受证据合同。 +3. 为该操作对锁定部分相交的 `8 -> 7 -> 8` 工具偏移轨迹,重跑真实 Fuse、参数恢复、naming 和 FCStd 三阶段。 + +#### 完成证据 + +`mirrored->fuse` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游 Mirrored 为有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `1000`、面积 `600` 和 156 条原生 history。 +- 下游真实 `BRepAlgoAPI_Fuse` 结果为有效 1 Solid、13 Face、29 Edge、18 Vertex、体积 `1075`、面积 `660` 和 52 条原生 history。 +- `8 -> 7 -> 8` 轨迹使编辑态体积变为 `1050`、面积变为 `640`、X 上界变为 `12`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `79a9b1faa46b...`。 +- focused gate 通过,队列完成项增加到 `451`,唯一新活动项为 `TSN-PAIR-mirrored-cut`。 + +### `TSN-PAIR-mirrored-cut` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器,以真实 `BRepAlgoAPI_Cut` 执行 `4 -> 3 -> 4` 工具尺寸轨迹。 + +#### 完成证据 + +`mirrored->cut` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepAlgoAPI_Cut` 结果为有效 1 Solid、10 Face、24 Edge、16 Vertex、体积 `936`、面积 `632` 和 22 条原生 history。 +- `4 -> 3 -> 4` 轨迹使编辑态体积变为 `973`、面积变为 `618`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `20a01c32bcfc...`。 +- focused gate 通过,队列完成项增加到 `452`,唯一新活动项为 `TSN-PAIR-mirrored-common`。 + +### `TSN-PAIR-mirrored-common` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;根据上游 X=`0..10` 边界,为该操作对锁定体交集 `7 -> 6 -> 7` 工具偏移轨迹,避免通用 X=`10` 边界接触产生空交集。 +2. 以真实 `BRepAlgoAPI_Common` 执行参数变异与恢复,采集 history、naming 和 FCStd save/reopen/resave 证据。 + +#### 完成证据 + +`mirrored->common` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 `BRepAlgoAPI_Common` 结果为有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `75`、面积 `110` 和 121 条原生 history。 +- `7 -> 6 -> 7` 轨迹使编辑态体积变为 `100`、面积变为 `130`、X 下界变为 `6`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd 三阶段保持 Shape 及 naming evidence hash `0e46d8968ef1...`。 +- focused gate 通过,队列完成项增加到 `453`,唯一新活动项为 `TSN-PAIR-mirrored-rotate`。 + +### `TSN-PAIR-mirrored-rotate` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器,以真实 `BRepBuilderAPI_Transform` 执行 `15 -> 22.5 -> 15` 角度轨迹。 + +#### 完成证据 + +`mirrored->rotate` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Rotate 保持有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `1000`、面积 `600`,并生成 78 条原生 history。 +- `15 -> 22.5 -> 15` 轨迹保持质量属性,但将包围盒从名义 X=`-2.5881906..9.6592584`、Y=`0..12.2474488` 改为编辑态 X=`-3.8268344..9.2387954`、Y=`0..13.0656297`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `2267188ff909...`。 +- focused gate 通过,队列完成项增加到 `454`,唯一新活动项为 `TSN-PAIR-mirrored-pad`。 +- 批次收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;队列只读重建确认恰好一个 `in_progress` 任务。 + +### `TSN-PAIR-mirrored-mirrored` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以第二次真实镜像 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `5 -> 6 -> 5` 平面轨迹,区分名义对称态、偏移变异态与恢复态。 + +#### 完成证据 + +`mirrored->mirrored` 已完成真实 OCCT/FreeCAD 接受分类: + +- 名义二次 Mirrored 保持有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `1000`、面积 `600`,但生成 156 条独立下游原生 history,不被误当作未执行。 +- `5 -> 6 -> 5` 平面轨迹使编辑态变为有效 1 Solid、14 Face、28 Edge、16 Vertex、体积 `1200`、面积 `680`、X 上界 `12`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `a4b701c6a129...`。 +- focused gate 通过,队列完成项增加到 `467`,唯一新活动项为 `TSN-PAIR-mirrored-multi-transform`。 + +### `TSN-PAIR-mirrored-multi-transform` + +#### 执行过程 + +1. 从最新机器队列领取 Mirrored 行最后一个机器任务;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以有序的真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 先执行线性变换、再执行镜像合并,对 `multiTranslationX` 执行 `8 -> 9 -> 8` 轨迹。 + +#### 完成证据 + +`mirrored->multi-transform` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游有序 Multi Transform 结果为有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2600`、面积 `1240`、X 边界 `-8..18` 和 355 条原生 history。 +- `8 -> 9 -> 8` 轨迹使编辑态体积变为 `2800`、面积变为 `1320`、X 边界变为 `-9..19`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `7daca50c6b9e...`。 +- focused gate 通过,Mirrored 行机器任务闭合,队列完成项增加到 `468`,唯一新活动项为 `TSN-PAIR-multi-transform-fuse`。 +- 行级收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;有序操作对剩余最后 19 项 Multi Transform 行任务。 + +### `TSN-PAIR-multi-transform-fuse` + +#### 执行过程 + +1. 从最新机器队列领取 Multi Transform 行首项;确认上游 X 范围为 `-8..18`,避免使用完全内含工具产生 Fuse no-op。 +2. 为该操作对锁定部分越出实体的 `16 -> 15 -> 16` 工具偏移轨迹,以真实 `BRepAlgoAPI_Fuse` 采集变异、恢复、naming 与 FCStd 证据。 + +#### 完成证据 + +`multi-transform->fuse` 已完成真实 OCCT/FreeCAD 接受分类: + +- 上游 Multi Transform 为有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2600`、面积 `1240` 和 355 条原生 history。 +- 下游真实 Fuse 结果为有效 1 Solid、29 Face、61 Edge、34 Vertex、体积 `2675`、面积 `1300`、X 上界 `21` 和 52 条原生 history。 +- `16 -> 15 -> 16` 轨迹使编辑态体积变为 `2650`、面积变为 `1280`、X 上界变为 `20`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `89d7ded3221b...`;focused gate 通过,队列完成项增加到 `469`。 +- 唯一新活动项为 `TSN-PAIR-multi-transform-cut`。 + +### `TSN-PAIR-multi-transform-cut` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以真实 `BRepAlgoAPI_Cut` 执行 `4 -> 3 -> 4` 工具尺寸轨迹,采集切除几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`multi-transform->cut` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Cut 结果为有效 1 Solid、26 Face、55 Edge、31 Vertex、体积 `2536`、面积 `1272` 和 47 条原生 history。 +- `4 -> 3 -> 4` 工具尺寸轨迹使编辑态体积变为 `2573`、面积变为 `1258`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `d9529dc97da1...`。 +- focused gate 通过,队列完成项增加到 `470`,唯一新活动项为 `TSN-PAIR-multi-transform-common`。 +- 批次收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;有序操作对剩余 17 项未分类任务。 + +### `TSN-PAIR-multi-transform-common` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以真实 `BRepAlgoAPI_Common` 执行 `10 -> 9 -> 10` 工具偏移轨迹,检查交集位置、拓扑、history、naming 和 FCStd 恢复。 + +#### 完成证据 + +`multi-transform->common` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Common 名义结果为有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `125`、面积 `150`、X 边界 `10..15` 和 309 条原生 history。 +- `10 -> 9 -> 10` 偏移轨迹保持体积与面积,但将编辑态变为 8 Face、17 Edge、11 Vertex、X 边界 `9..14` 和 304 条 history;该变异不以质量属性相同误判为 no-op。 +- 恢复态精确返回名义 Shape、history hash 和语义 naming;FCStd 三阶段保持 naming evidence hash `09387999ac8c...`。 +- focused gate 通过,队列完成项增加到 `471`,唯一新活动项为 `TSN-PAIR-multi-transform-rotate`。 + +### `TSN-PAIR-multi-transform-rotate` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以真实 `BRepBuilderAPI_Transform` 执行 `15 -> 22.5 -> 15` 角度轨迹,采集刚体边界变化、history、naming、恢复与 FCStd 证据。 + +#### 完成证据 + +`multi-transform->rotate` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Rotate 保持有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2600`、面积 `1240`,并生成 286 条原生 history。 +- `15 -> 22.5 -> 15` 轨迹保持质量属性,但将编辑态 X 边界改为 `-11.2178707..16.6298317`、Y 边界改为 `-3.0614676..16.1270972`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `6309013fed1b...`。 +- focused gate 通过,队列完成项增加到 `472`,唯一新活动项为 `TSN-PAIR-multi-transform-pad`。 +- 批次收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;有序操作对剩余 15 项机器任务。 + +### `TSN-PAIR-multi-transform-pad` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与拒绝检查器。 +2. 以真实 `BRepPrimAPI_MakePrism` 执行 `5 -> 7.5 -> 5` 长度轨迹,并以真实 `PartDesign::Pad` 文档重算、事务 abort 与 FCStd 三阶段锁定实体输入合同。 + +#### 完成证据 + +`multi-transform->pad` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- OCCT `BRepPrimAPI_MakePrism` 的 `5 -> 7.5 -> 5` 三次尝试均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 `PartDesign::Pad` 重算返回 `FeatureExtrusion: Length: Could not extrude the sketch!`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 前后只保留 Multi Transform 源对象,Shape 与 BREP hash `77e9b4530db9...` 精确恢复;FCStd 三阶段无临时 Body/Pad 污染。 +- focused gate 通过,队列完成项增加到 `473`,唯一新活动项为 `TSN-PAIR-multi-transform-pocket`。 + +### `TSN-PAIR-multi-transform-pocket` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 执行 `5 -> 4 -> 5` 深度轨迹,采集切除几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`multi-transform->pocket` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Pocket 结果为有效 1 Solid、26 Face、54 Edge、30 Vertex、体积 `2570`、面积 `1270` 和 74 条原生 history。 +- `5 -> 4 -> 5` 深度轨迹使编辑态体积变为 `2576`、面积变为 `1264`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `54344de3b84e...`。 +- focused gate 通过,队列完成项增加到 `474`,唯一新活动项为 `TSN-PAIR-multi-transform-loft`。 +- 批次收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;有序操作对剩余 13 项机器任务。 + +### `TSN-PAIR-mirrored-thickness` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器,先按 accepted mutation 合同实测。 +2. 以真实 `BRepOffsetAPI_MakeThickSolid` 执行 `-0.4 -> -0.6 -> -0.4` offset 轨迹,由是否产生有效变异、no-op、invalid-result 或拒绝决定最终分类。 + +#### 完成证据 + +`mirrored->thickness` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 ThickSolid 结果为有效 1 Solid、11 Face、24 Edge、16 Vertex、体积 `187.456`、面积 `953.28` 和 38 条原生 history,不是 no-op。 +- `-0.4 -> -0.6 -> -0.4` offset 轨迹使编辑态体积变为 `272.064`、面积变为 `930.88`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `42ff0285de04...`。 +- focused gate 通过,队列完成项增加到 `465`;`mirrored->linear-pattern` 已由既有顺序命名证据覆盖,因此唯一新活动项为 `TSN-PAIR-mirrored-polar-pattern`。 + +### `TSN-PAIR-mirrored-polar-pattern` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以真实旋转 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `30 -> 45 -> 30` 角度轨迹,采集阵列几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`mirrored->polar-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Polar Pattern 结果为有效 1 Solid、12 Face、26 Edge、16 Vertex、体积 `1422.6497308`、面积 `769.0598923` 和 78 条原生 history。 +- `30 -> 45 -> 30` 角度轨迹使编辑态体积变为 `1585.7864376`、面积变为 `834.3145751`,同时改变 X/Y 边界;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `d24473db6bed...`。 +- focused gate 通过,队列完成项增加到 `466`,唯一新活动项为 `TSN-PAIR-mirrored-mirrored`。 +- 批次收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;队列只读重建确认恰好一个 `in_progress` 任务。 + +### `TSN-PAIR-mirrored-hole` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` 执行 `1 -> 1.5 -> 1` 半径轨迹,采集孔切除、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`mirrored->hole` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Hole 结果为有效 1 Solid、7 Face、15 Edge、10 Vertex、体积 `968.5840735`、面积 `656.5486678` 和 23 条原生 history。 +- `1 -> 1.5 -> 1` 半径轨迹使编辑态体积变为 `929.3141653`、面积变为 `680.1106127`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游获得无歧义 `native-evidence` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `676552c44f78...`。 +- focused gate 通过,队列完成项增加到 `463`,唯一新活动项为 `TSN-PAIR-mirrored-draft`。 + +### `TSN-PAIR-mirrored-draft` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器,不预设复杂阵列实体的拒绝结论。 +2. 以真实 `BRepOffsetAPI_DraftAngle` 对锁定面执行 `5 -> 8 -> 5` 角度轨迹,采集拔模几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`mirrored->draft` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Draft 结果为有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `956.2556682`、面积 `582.884251` 和 5 条原生 history。 +- `5 -> 8 -> 5` 角度轨迹使编辑态体积变为 `929.7295826`、面积变为 `572.8745903`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游获得无歧义 `native-evidence` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `e187fbca3911...`。 +- focused gate 通过,队列完成项增加到 `464`,唯一新活动项为 `TSN-PAIR-mirrored-thickness`。 +- 批次收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;队列只读重建确认恰好一个 `in_progress` 任务。 + +### `TSN-PAIR-mirrored-fillet` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以真实 `BRepFilletAPI_MakeFillet` 对 Mirrored 全边集合执行 `0.4 -> 0.6 -> 0.4` 半径轨迹,采集圆角几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`mirrored->fillet` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Fillet 结果为有效 1 Solid、26 Face、56 Edge、24 Vertex、体积 `995.9653557`、面积 `579.2169851` 和 150 条原生 history。 +- `0.4 -> 0.6 -> 0.4` 半径轨迹使编辑态体积变为 `991.0184753`、面积变为 `568.6895487`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `fdf15e219a78...`。 +- focused gate 通过,队列完成项增加到 `461`,唯一新活动项为 `TSN-PAIR-mirrored-chamfer`。 + +### `TSN-PAIR-mirrored-chamfer` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以真实 `BRepFilletAPI_MakeChamfer` 对 Mirrored 全边集合执行 `0.4 -> 0.6 -> 0.4` 距离轨迹,采集倒角几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`mirrored->chamfer` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Chamfer 结果为有效 1 Solid、26 Face、48 Edge、24 Vertex、体积 `990.7413333`、面积 `571.4001834` 和 150 条原生 history。 +- `0.4 -> 0.6 -> 0.4` 距离轨迹使编辑态体积变为 `979.552`、面积变为 `556.7387245`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `167858fc2d46...`。 +- focused gate 通过,队列完成项增加到 `462`,唯一新活动项为 `TSN-PAIR-mirrored-hole`。 +- 批次收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;队列只读重建确认恰好一个 `in_progress` 任务。 + +### `TSN-PAIR-mirrored-revolution` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与拒绝检查器。 +2. 以真实 `BRepPrimAPI_MakeRevol` 执行 `360 -> 270 -> 360` 角度轨迹,并以真实 `Part::Revolution` 文档重算、事务 abort 与 FCStd 三阶段锁定实体输入合同。 + +#### 完成证据 + +`mirrored->revolution` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- OCCT `BRepPrimAPI_MakeRevol` 的 `360 -> 270 -> 360` 三次尝试均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 `Part::Revolution` 重算返回 `Solids are not Processed`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 前后只保留 Mirrored 源对象,Shape 与 BREP hash `a7a1463754da...` 精确恢复;FCStd save/reopen/resave 三阶段无失败 Revolution 污染。 +- focused gate 通过,队列完成项增加到 `459`,唯一新活动项为 `TSN-PAIR-mirrored-groove`。 + +### `TSN-PAIR-mirrored-groove` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 执行 `360 -> 180 -> 360` 角度轨迹,采集旋转减料、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`mirrored->groove` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Groove 结果为有效 1 Solid、10 Face、24 Edge、16 Vertex、体积 `995.287611`、面积 `606.5663706` 和 18 条原生 history。 +- `360 -> 180 -> 360` 轨迹使编辑态变为 7 Face、16 Edge、12 Vertex、体积 `1000`、面积 `600` 和 56 条 history;虽质量属性回到上游值,拓扑与 history 明确变化。 +- 恢复态精确返回名义 Shape、history hash 和语义 naming;下游保持原生 `ambiguous` naming。 +- FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `dc3dd5eb0ad3...`。 +- focused gate 通过,队列完成项增加到 `460`,唯一新活动项为 `TSN-PAIR-mirrored-fillet`。 +- 批次收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;队列只读重建确认恰好一个 `in_progress` 任务。 + +### `TSN-PAIR-mirrored-loft` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与分层拒绝检查器。 +2. 以真实 `BRepOffsetAPI_ThruSections` 执行 `false -> true -> false` ruled 轨迹,再以真实 `Part::Loft` 重算、事务 abort 和 FCStd 三阶段锁定 FreeCAD 文档层输入合同。 + +#### 完成证据 + +`mirrored->loft` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT `BRepOffsetAPI_ThruSections` 在三次 ruled 轨迹中均生成有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `750`、面积 `580.2775638` 和 24 条 history;恢复态精确一致,但该结果只属于 kernel superset。 +- FreeCAD 1.1.1 `Part::Loft` 以 `Profile shape is not a single vertex, edge, wire nor face.` 拒绝 Mirrored 实体 section,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后只保留源对象,Shape 与 BREP hash `a7a1463754da...` 精确恢复;FCStd save/reopen/resave 三阶段干净稳定。 +- focused gate 通过,队列完成项增加到 `457`,唯一新活动项为 `TSN-PAIR-mirrored-pipe`。 + +### `TSN-PAIR-mirrored-pipe` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与分层拒绝检查器。 +2. 以真实 `BRepOffsetAPI_MakePipe` 执行 `15 -> 12 -> 15` spine 长度轨迹,再以真实 `Part::Sweep` 文档重算、事务 abort 和 FCStd 三阶段锁定最终合同。 + +#### 完成证据 + +`mirrored->pipe` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- OCCT `BRepOffsetAPI_MakePipe` 三次均返回可生成但无效的 Shape:1 Solid、6 Face、12 Edge、8 Vertex、体积 `0` 和 28 条 history。 +- `15 -> 12 -> 15` 轨迹使无效结果面积在 `500 -> 440 -> 500` 间变化、Z 上界在 `25 -> 22 -> 25` 间变化,恢复态精确一致;kernel 权威为 `invalid-result`。 +- FreeCAD 1.1.1 `Part::Sweep` 重算返回 `A fatal error occurred when making the sweep`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后只保留源对象,Shape 与 BREP hash `a7a1463754da...` 精确恢复;FCStd 三阶段干净稳定。 +- focused gate 通过,队列完成项增加到 `458`,唯一新活动项为 `TSN-PAIR-mirrored-revolution`。 +- 批次收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;队列只读重建确认恰好一个 `in_progress` 任务。 + +### `TSN-PAIR-mirrored-pad` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦拒绝检查器。 +2. 以真实 `BRepPrimAPI_MakePrism` 执行 `5 -> 7.5 -> 5` 长度轨迹,并以真实 `PartDesign::Pad` 文档重算、事务 abort 和 FCStd save/reopen/resave 锁定实体输入合同。 + +#### 完成证据 + +`mirrored->pad` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 下游 Prism builder 的 `5 -> 7.5 -> 5` 三次尝试均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 `PartDesign::Pad` 重算返回 `FeatureExtrusion: Length: Could not extrude the sketch!`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 前后只保留 Mirrored 源对象,Shape 与 BREP hash `a7a1463754da...` 精确恢复;FCStd 三阶段无临时 Body/Pad 污染。 +- focused gate 通过,队列完成项增加到 `455`,唯一新活动项为 `TSN-PAIR-mirrored-pocket`。 + +### `TSN-PAIR-mirrored-pocket` + +#### 执行过程 + +1. 从最新机器队列领取唯一活动项;将该操作对加入连续探针前缀与聚焦检查器。 +2. 以真实 `BRepPrimAPI_MakePrism+BRepAlgoAPI_Cut` 执行 `5 -> 4 -> 5` 深度轨迹,采集切除几何、history、naming、恢复和 FCStd 三阶段证据。 + +#### 完成证据 + +`mirrored->pocket` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Pocket 结果为有效 1 Solid、9 Face、21 Edge、14 Vertex、体积 `970`、面积 `600` 和 42 条原生 history。 +- `5 -> 4 -> 5` 深度轨迹使编辑态体积变为 `976`,同时保持面积与包围盒;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `41a368e2c236...`。 +- focused gate 通过,队列完成项增加到 `456`,唯一新活动项为 `TSN-PAIR-mirrored-loft`。 +- 批次收尾运行 `./npmw run check:execution-plan` 与 `git diff --check` 均通过;队列只读重建确认恰好一个 `in_progress` 任务。 + +### `TSN-PAIR-multi-transform-loft` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,以 `FREECAD_ONLY_PAIR='multi-transform->loft'` 重跑真实 OCCT/FreeCAD 聚焦探针。 +2. 以真实 `BRepOffsetAPI_ThruSections` 执行 `false -> true -> false` ruled 轨迹,再以 `Part::Loft` 重算、事务 abort 和 FCStd save/reopen/resave 锁定 FreeCAD 文档层输入合同。 + +#### 完成证据 + +`multi-transform->loft` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- 上游 Multi Transform 使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)`,生成有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2600`、面积 `1240` 和 355 条原生 history。 +- OCCT `BRepOffsetAPI_ThruSections` 在三次 ruled 轨迹中均生成有效 1 Solid、6 Face、12 Edge、8 Vertex、体积 `1150`、面积 `758.6473016` 和 24 条 history;恢复态精确一致,但该结果只属于 kernel superset。 +- FreeCAD 1.1.1 `Part::Loft` 以 `Profile shape is not a single vertex, edge, wire nor face.` 拒绝 Multi Transform 实体 section,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后只保留源对象,Shape 几何与 BREP hash `77e9b4530db9...` 恢复;FCStd save/reopen/resave 三阶段干净稳定。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `475`,唯一新活动项为 `TSN-PAIR-multi-transform-pipe`。 + +### `TSN-PAIR-multi-transform-pipe` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,将 `multi-transform->pipe` 加入连续探针前缀与 focused checker。 +2. 以真实 `BRepOffsetAPI_MakePipe` 执行 `15 -> 12 -> 15` spine 长度轨迹,再以 `Part::Sweep` 重算、事务 abort 和 FCStd 三阶段锁定拒绝合同。 + +#### 完成证据 + +`multi-transform->pipe` 已完成真实 FreeCAD/OCCT 分层拒绝分类: + +- 上游 Multi Transform 使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)`,生成有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2600`、面积 `1240` 和 355 条原生 history。 +- OCCT `BRepOffsetAPI_MakePipe` 在三次轨迹中均返回无效 Shape:1 Solid、6 Face、12 Edge、8 Vertex、体积 `0`,面积按 spine 长度为 `500 -> 440 -> 500`,且均有 28 条 history;恢复态精确一致,kernel 权威为 `invalid-result`。 +- FreeCAD 1.1.1 `Part::Sweep` 重算返回 `A fatal error occurred when making the sweep`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后只保留 Multi Transform 源对象,Shape 与 BREP hash `77e9b4530db9...` 精确恢复;FCStd save/reopen/resave 三阶段干净稳定。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `476`,唯一新活动项为 `TSN-PAIR-multi-transform-revolution`。 + +### `TSN-PAIR-multi-transform-revolution` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,将 `multi-transform->revolution` 加入连续探针前缀与 focused checker。 +2. 以真实 `BRepPrimAPI_MakeRevol` 执行 `360 -> 270 -> 360` 角度轨迹,再以 `Part::Revolution` 重算、事务 abort 和 FCStd 三阶段锁定拒绝合同。 + +#### 完成证据 + +`multi-transform->revolution` 已完成真实 FreeCAD/OCCT 拒绝分类: + +- 上游 Multi Transform 使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)`,生成有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2600`、面积 `1240` 和 355 条原生 history。 +- OCCT `BRepPrimAPI_MakeRevol` 在 `360 -> 270 -> 360` 三次尝试中均在 builder 阶段以 Emscripten C++ exception 稳定拒绝,不产出 result、Shape 或 history。 +- FreeCAD 1.1.1 `Part::Revolution` 重算返回精确诊断 `BRep_API: command not done`,状态为 `Touched/Invalid` 且 Shape 为 null/invalid。 +- 事务 abort 后只保留 Multi Transform 源对象,Shape 与 BREP hash `77e9b4530db9...` 精确恢复;FCStd save/reopen/resave 三阶段无失败 Revolution 污染。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `477`,唯一新活动项为 `TSN-PAIR-multi-transform-groove`。 + +### `TSN-PAIR-multi-transform-groove` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,将 `multi-transform->groove` 加入连续探针前缀与 focused checker。 +2. 以真实 `BRepPrimAPI_MakeRevol+BRepAlgoAPI_Cut` 执行 `360 -> 180 -> 360` 角度轨迹,采集旋转减料、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`multi-transform->groove` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Groove 名义结果为有效 1 Solid、26 Face、56 Edge、32 Vertex、体积 `2590.575222`、面积 `1259.1327412` 和 18 条原生 history。 +- `360 -> 180 -> 360` 轨迹使编辑态变为 24 Face、52 Edge、32 Vertex、体积 `2600`、面积 `1240` 和 34 条 history;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `7e1cca710b45...`。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `478`,唯一新活动项为 `TSN-PAIR-multi-transform-fillet`。 + +### `TSN-PAIR-multi-transform-fillet` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,将 `multi-transform->fillet` 加入连续探针前缀与 focused checker。 +2. 以真实 `BRepFilletAPI_MakeFillet` 执行 `0.4 -> 0.6 -> 0.4` 半径轨迹,采集圆角几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`multi-transform->fillet` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Fillet 名义结果为有效 1 Solid、58 Face、120 Edge、56 Vertex、体积 `2593.7678329`、面积 `1208.2293711` 和 390 条原生 history。 +- `0.4 -> 0.6 -> 0.4` 半径轨迹使编辑态体积为 `2586.0740489`、面积为 `1192.2081276`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `9a6a00ac52f1...`。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `479`,唯一新活动项为 `TSN-PAIR-multi-transform-chamfer`。 + +### `TSN-PAIR-multi-transform-chamfer` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,将 `multi-transform->chamfer` 加入连续探针前缀与 focused checker。 +2. 以真实 `BRepFilletAPI_MakeChamfer` 执行 `0.4 -> 0.6 -> 0.4` 距离轨迹,采集倒角几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`multi-transform->chamfer` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Chamfer 名义结果为有效 1 Solid、58 Face、112 Edge、56 Vertex、体积 `2585.6213333`、面积 `1196.4040506` 和 390 条原生 history。 +- `0.4 -> 0.6 -> 0.4` 距离轨迹使编辑态体积为 `2568.032`、面积为 `1174.2445253`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `0e83ffacf7be...`。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `480`,唯一新活动项为 `TSN-PAIR-multi-transform-hole`。 + +### `TSN-PAIR-multi-transform-hole` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,将 `multi-transform->hole` 加入连续探针前缀与 focused checker。 +2. 以真实 `BRepPrimAPI_MakeCylinder+BRepAlgoAPI_Cut` 执行 `1 -> 1.5 -> 1` 半径轨迹,采集孔切除、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`multi-transform->hole` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Hole 名义结果为有效 1 Solid、23 Face、47 Edge、26 Vertex、体积 `2568.5840735`、面积 `1296.5486678` 和 23 条原生 history。 +- `1 -> 1.5 -> 1` 半径轨迹使编辑态体积为 `2529.3141653`、面积为 `1320.1106127`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游获得原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `e44576e22071...`。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `481`,唯一新活动项为 `TSN-PAIR-multi-transform-draft`。 + +### `TSN-PAIR-multi-transform-draft` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,将 `multi-transform->draft` 加入连续探针前缀与 focused checker。 +2. 以真实 `BRepOffsetAPI_DraftAngle` 对锁定面执行 `5 -> 8 -> 5` 角度轨迹,采集拔模几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`multi-transform->draft` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Draft 名义结果为有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2486.2647374`、面积 `1209.4972389` 和 17 条原生 history。 +- `5 -> 8 -> 5` 角度轨迹使编辑态体积为 `2417.2969149`、面积为 `1191.9604684`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `3027a08991dc...`。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `482`,唯一新活动项为 `TSN-PAIR-multi-transform-thickness`。 + +### `TSN-PAIR-multi-transform-thickness` + +#### 执行过程 + +1. 先按接受合同执行真实 `BRepOffsetAPI_MakeThickSolid`,发现 `-0.4 -> -0.6 -> -0.4` 未改变几何/history;随后切换原生 no-op 分支重放。 +2. 采集 OCCT no-op 轨迹、FreeCAD `Part::Thickness` 重算状态、事务 abort 和 FCStd save/reopen/resave 三阶段证据。 + +#### 完成证据 + +`multi-transform->thickness` 已完成真实 FreeCAD/OCCT no-op 拒绝分类: + +- 上游 Multi Transform 使用真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)`,生成有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2600`、面积 `1240`和 355 条原生 history。 +- OCCT `BRepOffsetAPI_MakeThickSolid` 在 `-0.4 -> -0.6 -> -0.4` 三次均返回与输入同拓扑和指标的有效 Shape,每次仅 1 条 history,权威为 `kernel-no-op`。 +- FreeCAD 1.1.1 `Part::Thickness` 返回 `Valid/Up-to-date`,结果 Shape 等于输入 Shape,是明确 no-op,而非虚构成功几何。 +- abort 后对象集、体积、面积、拓扑全部恢复,仅 BREP 因原生重序列化发生漂移(`sourceBrepReserialized=true`);FCStd 三阶段干净稳定。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `483`,唯一新活动项为 `TSN-PAIR-multi-transform-linear-pattern`。 + +### `TSN-PAIR-multi-transform-linear-pattern` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,将 `multi-transform->linear-pattern` 加入连续探针前缀与 focused checker。 +2. 以真实 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `8 -> 9 -> 8` 平移轨迹,采集阵列几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`multi-transform->linear-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Linear Pattern 名义结果为有效 1 Solid、30 Face、60 Edge、32 Vertex、体积 `3400`、面积 `1560` 和 466 条原生 history,X 边界为 `-8..26`。 +- `8 -> 9 -> 8` 平移轨迹使编辑态体积为 `3500`、面积为 `1600`、X 边界扩展至 `-8..27`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `b394abb85573...`。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `484`,唯一新活动项为 `TSN-PAIR-multi-transform-polar-pattern`。 + +### `TSN-PAIR-multi-transform-polar-pattern` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,将 `multi-transform->polar-pattern` 加入连续探针前缀与 focused checker。 +2. 以真实旋转 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `30 -> 45 -> 30` 角度轨迹,采集阵列几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`multi-transform->polar-pattern` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Polar Pattern 名义结果为有效 1 Solid、55 Face、119 Edge、66 Vertex、体积 `3627.2391992`、面积 `1586.2768775`、XY 边界 `-11.9282034..18` / `-4..17.6602542` 和 317 条原生 history。 +- `30 -> 45 -> 30` 角度轨迹使编辑态体积为 `3974.4155877`、面积为 `1756.0606076`,XY 边界扩展至 `-12.7279222..18` / `-5.6568544..19.79899`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `9b336c1a8cd0...`。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `485`,唯一新活动项为 `TSN-PAIR-multi-transform-mirrored`。 + +### `TSN-PAIR-multi-transform-mirrored` + +#### 执行过程 + +1. 从机器队列领取唯一活动项,将 `multi-transform->mirrored` 加入连续探针前缀与 focused checker。 +2. 以真实镜像 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse` 执行 `5 -> 6 -> 5` 平面参数轨迹,采集几何、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`multi-transform->mirrored` 已完成真实 OCCT/FreeCAD 接受分类: + +- 下游真实 Mirrored 名义结果为有效 1 Solid、22 Face、44 Edge、24 Vertex、体积 `2600`、面积 `1240` 和 572 条原生 history。 +- `5 -> 6 -> 5` 轨迹使编辑态变为 38 Face、76 Edge、40 Vertex、体积 `2800`、面积 `1320`、X 上界 `20`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `a8d686199c1b...`。 +- 聚焦探针与 focused gate 通过,队列完成项增加到 `486`,唯一新活动项为 `TSN-PAIR-multi-transform-multi-transform`。 + +### `TSN-PAIR-multi-transform-multi-transform` + +#### 执行过程 + +1. 从机器队列领取最后一个有序操作对,将 `multi-transform->multi-transform` 加入连续探针前缀与 focused checker。 +2. 以真实有序 `BRepBuilderAPI_Transform+BRepAlgoAPI_Fuse(ordered)` 执行 `8 -> 9 -> 8` 多变换轨迹,采集复合阵列、history、naming、恢复与 FCStd 三阶段证据。 + +#### 完成证据 + +`multi-transform->multi-transform` 已完成真实 OCCT 接受分类,并闭合全部 19×19 有序操作对: + +- 下游真实 Multi Transform 名义结果为有效 1 Solid、38 Face、76 Edge、40 Vertex、体积 `4200`、面积 `1880`和 1187 条原生 history,X 边界为 `-16..26`。 +- `8 -> 9 -> 8` 轨迹使编辑态变为 62 Face、124 Edge、64 Vertex、体积 `4400`、面积 `1960`、X 边界为 `-17..27`;恢复态精确返回名义 Shape、history hash 和语义 naming。 +- 下游保持原生 `ambiguous` naming;FCStd save/reopen/resave 三阶段保持 Shape 及 naming evidence hash `ce7e7e2afb3a...`。 +- 聚焦探针与 focused gate 通过,19×19 有序操作对全部分类完成,队列完成项增加到 `487`,下一个唯一活动项为 `PROP-app-propertyacceleration-A`。 + +### `PROP-app-propertyacceleration-A/B` + +#### 执行过程与完成证据 + +- A 阶段生成 `config/freecad-property-acceleration-inventory.json`,锁定 `App::PropertyAcceleration` 的唯一原生记录:适用对象 `Robot::TrajectoryDressUpObject`、属性 `Acceleration`、分组 `TrajectoryDressUp`、默认 `1000.0 mm/s^2`、量纲 `length/time^2`、空依赖,且保留 `opaque-fcstd-proxy` 分类。`check:freecad-property-acceleration-inventory` 通过。 +- B 阶段使用真实 FreeCAD 1.1.1 实例化对象,采集默认 `1000`、名义 `500`、下界 `0`、负值边界 `-500 mm/s^2`;四次赋值均无异常,property status 为空,单位返回为 FreeCAD 加速度量纲,Shape 明确记为不适用。`check:freecad-property-acceleration-success` 通过。 +- 账本已追加 A/B 两项机器证据,队列完成项增加到 `489`,下一个唯一活动项为 `PROP-app-propertyacceleration-C`。 + +### `PROP-app-propertyacceleration-C` + +#### 执行过程 + +1. 从机器队列领取 `App::PropertyAcceleration` 的原生失败/取消任务,复跑既有探针后发现文档未启用 `UndoMode`,导致 `abortTransaction()` 未形成可回滚事务;同时既有产物缺少禁用态证据。 +2. 将探针收紧为两类非法输入、`ReadOnly + Immutable` 禁用态和启用 Undo 的事务取消,并逐阶段对比属性值与文档对象集。 +3. focused checker 锁定原生异常类型与精确消息、禁用状态、事务活动/关闭状态、回滚结果和文档无污染;不把同步属性 setter 伪装成支持原生 cancel hook。 + +#### 完成证据 + +- `5 mm` 以 `ArithmeticError: Not matching Unit!` 拒绝,`not-a-quantity` 以 `ParserError: syntax error` 拒绝;两次失败前后均保持 `1000 mm/s^2` 和唯一 `Robot::TrajectoryDressUpObject` 对象。 +- 禁用态同时记录 editor `ReadOnly` 与属性 `Immutable`,写入 `750 mm/s^2` 精确返回 `AttributeError: Object attribute 'Acceleration' is read-only`;解除状态后 status/editor mode 均恢复为空。 +- 原生 setter 为同步操作且没有 cancel hook,明确保持 `supported: false`;取消替代路径使用启用 `UndoMode=1` 的活动文档事务,`1000 -> 250 -> abort -> 1000 mm/s^2` 完整恢复,活动事务关闭且对象集不变。 +- `probe:freecad-property-acceleration-failure` 与 `check:freecad-property-acceleration-failure` 通过;C 阶段证据已追加到连续账本,等待机器队列生成并核对下一任务。 + +### `PROP-app-propertyacceleration-D` + +#### 执行过程与完成证据 + +- 先用 FreeCAD console 验证有效原生对象图:`Robot::TrajectoryObject` 提供两个 waypoint,`Robot::TrajectoryDressUpObject` 绑定 Source 并启用 `UseAcceleration` 后重算为 `Valid / Up-to-date`。 +- 新增变异探针,以 XML parser 解析原生 `Trajectory.Content`,执行 `1000 -> 500 -> 1000 mm/s^2`;三阶段重算计数为 `2 / 1 / 1`,两个 waypoint 的 `acc` 均按 `1000 -> 500 -> 1000` 变化。 +- 编辑后原生对象状态为 `Touched` 且 `MustExecute=false`;这是实际 FreeCAD 语义,重算仍执行一次并将输出轨迹 Duration 从 `0.141421356` 变为 `0.2`,恢复后返回原值。 +- 恢复态的属性值、轨迹结构、Duration、XML 内容 hash、property status、editor mode、Source link 和对象状态均与 before 逐字段一致;Source 轨迹和文档对象集全程不变。 +- 该对象没有 Shape,几何边界明确记录为 `not-applicable-no-shape-property`,未伪造拓扑证据。`probe/check:freecad-property-acceleration-mutation` 均通过,D 阶段证据已加入连续账本。 + +### `PROP-app-propertyacceleration-E` + +#### 执行过程与完成证据 + +- 将 `App::PropertyAcceleration` 加入 Facade 的 `NativeEditablePropertyType`,并接入数值校验、属性设置、表达式适用类型和 UI 数值编辑器;保留 FreeCAD 允许负加速度的原生边界,没有套用 Length 的非负限制。 +- 单位系统新增 acceleration 量纲及 `mm/cm/m/in/ft per s^2` 换算,Facade 快照使用原生基准单位 `mm/s^2`;聚焦测试确认 `9.81 m/s^2 = 9810 mm/s^2`。 +- FCStd writer/reader 将该类型作为原生 `` 编解码,并把 `Robot::TrajectoryObject`/`Robot::TrajectoryDressUpObject` 纳入识别清册;`Acceleration` 写入静态原生属性,不使用动态 `group/doc/attr` fallback。 +- 新增 `test:freecad-property-acceleration-facade`,只通过公开 Facade 设置 `1000 -> 500`,验证版本、dirty、重算 touched、类型/单位保持;字符串和 Infinity 均被有限数值校验拒绝,归档检查与 decoder 返回原生数值 `500`。 +- focused test 与完整 `./npmw run build` 通过;构建仅保留既有 OCCT chunk 体积警告。E 阶段生产实现与检查证据已加入连续账本。 + +### `PROP-app-propertyacceleration-F` + +#### 执行过程与完成证据 + +- 在 `SetPropertyInput` 增加可选 `expectedDocumentVersion` 和 `AbortSignal`;同步属性写入对预取消 signal 返回 `AbortError`,对旧版本返回精确 stale 诊断,两者都在 observer 事件和历史栈写入前 fail-closed。 +- 成功写入 `1000 -> 500` 只产生一组同 transaction ID 的 `property.before-change -> property.changed -> transaction.committed`,提交记录锁定版本 `1 -> 2` 和 `property.set` 操作。 +- Facade undo 将属性和值恢复到版本 1,redo 返回版本 2/值 500;redo 后旧版本写入、预取消写入和非法字符串写入均保持文档 JSON、事件数及 undo/redo 可用性不变。 +- 属性事务不分配几何 Shape;测试逐项比较 `shapeCount`、`kernelReferenceCount` 和 `releasedShapeCount`,前后完全一致。 +- `test:freecad-property-acceleration-transaction` 与 E 阶段 focused test 均通过,F 阶段证据已加入连续账本。 + +### `PROP-app-propertyacceleration-G` + +#### 执行过程与完成证据 + +- 新增受限的 `rewriteFcstdNumericProperty`:先用现有 ZIP/XML 安全边界校验对象、Property TypeId、`Float` payload、有限目标值和期望旧值,再用 `fast-xml-parser/XMLBuilder` 结构化修改,禁止正则替换原生 XML。 +- 首轮重写暴露 builder 会把 `CustomEnum=""` 压为被读取器禁止的布尔属性,并二次转义已编码实体;已明确设置保留空属性值、自闭合空节点和不重复处理实体,FreeCAD 可正常读取。 +- 第二轮原生检查发现只改 `` 会让 FreeCAD 沿用归档内旧派生轨迹;重写器现同时把目标对象声明标记为 `Touched="1"`,强制原生重算。这一缺陷曾使 focused check 失败,未被写成虚假通过。 +- 最终真实链路为 FreeCAD 创建 `1000` -> Web 校验并编辑 `500` -> FreeCAD reopen/recompute -> saveAs -> reopen;属性值为 `1000 -> 500 -> 500 -> 500`,两个 waypoint 的 `acc` 在后两次原生打开时均为 `500`。 +- Web 编辑前后对象集及除目标值外的属性语义一致;本次 FreeCADCmd 归档只含 `Document.xml`,外部 opaque 条目数为 0,保留判定为真且未虚构资源证据。`probe/check:freecad-property-acceleration-roundtrip` 均通过,G 阶段证据已加入连续账本。 + +### `PROP-app-propertyacceleration-H` + +#### 执行过程与完成证据 + +- 新增真实 Chrome harness,直接复用生产 `PropertyEditor` 和 `createProductionFacade`,通过数值输入框的真实 focus/input/blur 事件完成 `1000 -> 500 mm/s^2`;文档版本 `1 -> 2`、dirty 为真、对象状态变为 `touched`,UI 未产生错误。 +- 通过具名 `bitbybit-persistence` Worker 执行 initialize、save/load、checkpoint、recovery、resource put/get/release 和 dispose;Chrome 报告锁定 `sqlite-opfs`、SQLite WASM/OPFS 均可用、恢复完整性为 `ok`。 +- 浏览器内 FCStd metadata 仍编码为原生 `App::PropertyAcceleration` / ``;OPFS 资源 36 bytes 往返一致,release 后读取为 null,独立 marker 已删除。 +- Facade 新增显式 `project.dispose()`,取消待执行 autosave 并关闭持久化 Worker;最终 Shape 数和 kernel 引用数均为 0,Worker 终止事件已记录。 +- `build`、`test/check:chrome-property-acceleration`、E/F 聚焦测试均通过;H 阶段机器证据已追加到连续账本,等待队列重建后领取 I 阶段。 + +### `PROP-app-propertyacceleration-I` + +#### 执行过程与完成证据 + +- 新增独立 promotion 生成器与 focused checker,逐项读取 A-H 连续账本、原生成功/失败/变异、Facade/事务、FCStd 往返和 Chrome 报告;缺少任一阶段或任一报告非 pass 时均拒绝提升。 +- 将 `App::PropertyAcceleration` 加入全局原生可编辑 codec 清册;`config/freecad-native-property-semantics.json` 现记录该类型为 `native-editable-codec`,保持 1 个原生 record 和 1 个对象类型。 +- 全局支持分区由 `22 / 4304 native-editable`、`58 / 523 opaque` 收敛为 `23 / 4305 native-editable`、`57 / 522 opaque`;连同 5 类 specialized codec,native codec 总记录数为 4988。 +- exact blocker 同步为 `57 runtime property types and 522 records remain opaque-only`;系统级 exact 继续 fail-closed,不因单类型完成而提前宣称整体 exact。 +- 队列生成器现在会从进度账本携带已开始/已提升的 Property 类型,避免类型退出 opaque 集合后丢失 A-I 历史,同时继续从当前 opaque 清册生成后续任务。 +- `probe/check:freecad-native-property-semantics` 与 `generate/check:freecad-property-acceleration-promotion` 均通过;I 阶段证据已追加到连续账本。 + +### `PROP-app-propertyarea-A` + +#### 执行过程与完成证据 + +- 从锁定的 FreeCAD 1.1.1 runtime oracle 提取唯一 `App::PropertyArea` 记录:宿主 `Measure::MeasureArea`、属性 `Area`、分组 `Measurement`、默认 `0.0 mm^2`、状态位 `PropReadOnly + PropOutput`。 +- 原生值模型锁定为 `length^2` 的只读派生 quantity;结果不拥有 Shape,不能把测量值伪装成几何对象。 +- 输入合同锁定为 `Elements: App::PropertyLinkSubList`,scope 为 Global、允许外部文档且必须至少一个元素;`Elements` 变化会立即重算 `Area`。 +- 选择适用性锁定为非空且全部有效,只接受 PLANE/CYLINDER/SURFACE/VOLUME;INVALID/POINT/LINE/CURVE 明确不适用。执行语义为逐元素面积求和,失效诊断固定为 `Cannot calculate area`。 +- inventory 同时锁定 runtime oracle 与 `MeasureArea.cpp/.h` 的 bytes/SHA-256,并由 focused checker复核源代码中的 Global、allowExternal、ReadOnly/Output 与诊断声明;`generate/check:freecad-property-area-inventory` 均通过。 + +### `PROP-app-propertyarea-B` + +#### 执行过程与完成证据 + +- 使用真实 FreeCAD 1.1.1 创建 Box、Cylinder、Sphere 与 `Measure::MeasureArea`,覆盖 empty default、planar Face、cylindrical Face、surface Face、完整 solid 和多元素求和六个成功态。 +- 原生结果依次为 `0`、`10`、`75.398223877`、`50.265483856`、`160`、`95.398223877 mm^2`;每项都以源 Shape 的真实 `Area` 独立求和并在 OCCT 测量容差内一致。 +- 六个阶段的 `Area` TypeId 均为 `App::PropertyArea`,原生状态位固定为 `24/27`、editor mode 为 `ReadOnly`,对象均为 `Valid / Up-to-date`。 +- 测量对象全程没有 Shape,源几何则逐项锁定 ShapeType、有效性、Face/Edge/Vertex 数;未用伪造拓扑替代只读 quantity 的真实边界。 +- `probe/check:freecad-property-area-success` 均通过,B 阶段证据已加入连续账本。 + +### `PROP-app-propertyarea-C` + +#### 执行过程与完成证据 + +- 用真实 FreeCAD 1.1.1 将 `Measure::MeasureArea.Elements` 分别指向 `Vertex1` 和 `Edge1`;赋值本身不抛异常,`document.recompute()` 仍返回 true,但测量对象稳定进入 `Touched + Invalid`,精确诊断为 `Cannot calculate area`,旧的最后有效面积 `10 mm^2` 保持不变。 +- 每个失败态都恢复到 `AreaBox.Face1` 并重新计算,`Area`、`Elements`、对象状态和文档对象集精确回到初值;没有把重算返回值误当成对象成功状态。 +- 原生 `PropReadOnly + PropOutput`/editor `ReadOnly` 只限制 GUI,Python 仍可临时写入派生 `Area`;叠加 `Immutable` 后写入 `30 mm^2` 精确抛出 `AttributeError: Object attribute 'Area' is read-only`,解除状态并重算后恢复原生只读派生值。 +- 该测量重算没有原生 cancel hook,报告明确分类为同步重算并用活动 Document transaction abort 作为取消边界;`Elements` 从 Box Face 改到 Cylinder Face 后 abort,重算恢复 `10 mm^2`,事务、对象集和文档状态无污染。 +- `probe/check:freecad-property-area-failure` 与 execution-plan 门禁通过,C 阶段证据已加入连续账本。 + +### `PROP-app-propertyarea-D` + +#### 执行过程与完成证据 + +- 只变异输入 `Elements`:从 `AreaBox.Face1` 改为 `AreaBox.Face1 + AreaBox.Face2 + AreaCylinder.Face1`,派生值按原生同步通知从 `10` 变为 `95.398223877 mm^2`,随后恢复为 `10 mm^2`。 +- 首轮 checker 因用 JSON 字符串比较对象而错误地把键顺序当成语义差异,保持 fail-closed;已改为结构化深比较。原生 artifact 同时揭示 `MeasureArea::onChanged` 在 `Elements` 赋值时即同步更新 `Area`,对象进入 `Touched` 但 `MustExecute=false`,因此 checker 按真实行为锁定,而非假定等待 recompute 才更新。 +- before/edit/restore 三态均保持 `App::PropertyArea`、`ReadOnly`、状态位 `24/27`、无 Shape 和 `Valid / Up-to-date`;源 Box/Cylinder 的拓扑、边界、面积、体积全部未变,文档对象集保持三对象。 +- 原生探针独立复跑两次得到相同 artifact SHA-256 `fb9a6b4d6d396335e85bf242a270931ac40df5421ada0f48131a807d13e4972b`;`probe/check:freecad-property-area-mutation` 均通过,D 阶段证据已加入连续账本。 + +### `PROP-app-propertyarea-E` + +#### 执行过程与完成证据 + +- 将 `App::PropertyArea` 接入 typed Property snapshot、有限数值 codec 和 Property UI 分支;当前原生记录携带 `PropReadOnly + PropOutput`,因此生产 UI 走只读文本路径,公开 `setProperty(Area)` 在事件和版本变更前拒绝。 +- FCStd writer/reader 新增 `App::PropertyArea` 原生 `` 编解码,并把 `Measure::MeasureArea` 及其静态 `Area/Elements` 纳入原生对象清册;两项属性不再落入带 `group/doc/attr` 的动态 fallback,`Elements` 保持原生 ``。 +- 生产 Facade 在修改 `Measure::MeasureArea.Elements` 时,从源对象稳定 face topology signature 同步求和并更新只读 `Area`;支持 `FaceN`、ElementMap 映射、稳定 TopoRef 和 whole-object face 汇总,缺失拓扑、非 Face、歧义或非法面积统一在提交前以 `Cannot calculate area` fail-closed。 +- 聚焦测试锁定 `AreaBox.Face1 -> Face1+Face2` 时 `Area 10 -> 20 mm^2`、测量对象 touched、单事务事件序列,以及 `Edge1` 失败时状态/事件零变化;FCStd inspect 将对象识别为 `recognized` 并结构化解码 Area/Elements。 +- `test:freecad-property-area-facade`、完整 `test:facade` 199 项和 `build` 均通过;构建仅保留既有 OCCT chunk 体积警告,E 阶段证据已加入连续账本。 + +### `PROP-app-propertyarea-F` + +#### 执行过程与完成证据 + +- 通过公开 Facade 将 `Elements` 从 `AreaBox.Face1` 改为 `Face1 + Face2`,在同一 transaction ID 内只产生一组 `property.before-change -> property.changed -> transaction.committed`,文档版本 `1 -> 2`,派生 `Area 10 -> 20 mm^2`。 +- undo 同时恢复单 Face 输入、`Area=10` 和版本 1;redo 同时恢复双 Face 输入、`Area=20` 和版本 2,历史栈可用性按预期切换。 +- redo 后依次注入旧版本写入、预取消 signal、`Edge1` 非适用输入和直接写只读 `Area`;四项均在提交前 fail-closed,文档 JSON、属性事务事件数及 undo/redo 可用性完全不变。 +- 测量事务不分配几何 Shape;前后 `shapeCount`、`kernelReferenceCount` 和 `releasedShapeCount` 完全一致,并显式 dispose 项目持久化边界。 +- `test:freecad-property-area-transaction` 与 E 阶段 focused test 均通过,F 阶段证据已加入连续账本。 + +### `PROP-app-propertyarea-G/H/I` 与 `PROP-app-propertyboollist-A` + +#### 执行过程与完成证据 + +- Area G 首次真实 FreeCAD -> Web -> FreeCAD 回放发现 checker 用 JSON 字符串比较对象键顺序,误报 `nativeOutputMatches=false`;保持 fail-closed 后改为结构化深比较,并让 runner 顶层 status 跟随 `zeroUnknownDrift`,避免报告自称 pass。修正后 `Area 10 -> 20 -> 20 mm^2`、LinkSubList 两个面、源几何、对象集和唯一 opaque 归档项均无未知漂移。 +- Area H 新增真实 headless Chrome harness,复用生产 `PropertyEditor`。Area 按原生 `PropReadOnly + PropOutput` 保持只读,真实点击 `Clear subshape links` 将 `Elements 2 -> 0`,派生 UI 值 `20 -> 0 mm^2`;SQLite OPFS、FCStd Float/LinkSubList、checkpoint/recovery、OPFS 资源释放和 `bitbybit-persistence` Worker 终止均通过。 +- Area I 新增独立 promotion 生成器/checker,A-H 连续证据全部通过;`App::PropertyArea` 以 `read-only-derived-mm^2-with-link-sub-list-input` 值模型提升到 native codec。全局分区更新为 `24 / 4306 native-editable`、`56 / 521 opaque`,native codec 总记录 `4989`;exact blocker 同步为 `56 runtime property types and 521 records remain opaque-only`,系统 exact 仍为 false。 +- 随后领取 `PROP-app-propertyboollist-A`,从 FreeCAD 1.1.1 oracle 锁定 7 条 `App::PropertyBoolList` 记录:`App::FeatureTest`、`App::FeatureTestException`、四种 Link/LinkPython `VisibilityList` 和 `Surface::GeomFillSurface.ReversedList`。清册 checker 通过,3 条默认可写、4 条 `Immutable + Hidden + LockDynamic`,当前仍保持 `opaque-fcstd-proxy`。 +- 本轮门禁:Area Chrome、Area Facade/transaction/FCStd、Area promotion、native property semantics、execution plan、active queue、JSON parse、`git diff --check` 均通过;生产 build 通过,仅保留既有 OCCT chunk 体积警告。 + +### `PROP-app-propertyboollist-B` + +#### 执行过程与完成证据 + +- 首轮真实 FreeCAD 探针因错误使用不存在的 `App::Feature` 目标中止,未生成通过产物;修正为真实 `Part::Feature`,并用四条闭合边界为 `Surface::GeomFillSurface` 建立有效 Shape。 +- `App::FeatureTest` 与 `App::FeatureTestException.BoolList` 均接受 empty、singleton、mixed、257 项大列表和恢复值;后者的 `execute()` 按类型设计固定报 `Testexception ;-)`,artifact 将其分类为 intrinsic host diagnostic,不误判为 BoolList setter 失败。 +- `Surface::GeomFillSurface.ReversedList` 在 all-false、one-reversed、alternating、all-reversed 与恢复阶段均保持有效单 Face、4 Edge、4 Vertex 和 `Valid / Up-to-date`。 +- 四种 Link/LinkPython 宿主不绕过 `Immutable` 直接写值,而是使用原生 LinkBaseExtension `setElementVisible()`;四项都得到 `[true,true] -> [false,true] -> [true,true]`,返回码为 1,状态保持 `Immutable + Hidden + LockDynamic`。 +- `probe/check:freecad-property-boollist-success` 均通过,B 阶段证据已加入连续账本。 + +### `PROP-app-propertyboollist-C` + +#### 执行过程与完成证据 + +- 首轮失败探针发现标量整数 `7` 和字符串 `"10201"` 是原生接受分支,分别归一化为 `[true]` 与 `[true,false,false,false,true]`;两项移入 `acceptedCoercions`,没有伪造成拒绝。 +- 真正非法输入 `None`、含 float 子项和含 string 子项均以精确 `TypeError: type in list must be bool or int, not ...` 拒绝,值和对象集保持不变。 +- 普通 `BoolList` 在 `ReadOnly + Immutable` 状态下返回精确 `AttributeError`,解除状态后 status/editor mode 回空;活动事务将 `[false] -> [true,false,true] -> abort -> [false]` 完整恢复。 +- 四类 Link 的直接 `VisibilityList` 写入均因 immutable 拒绝,无效元素名返回 `-1` 且无变异;有效隐藏后 abort 立即恢复值但原生对象保持 `Touched`,随后一次 recompute 返回 `Up-to-date / Valid`,这一两阶段恢复由 checker 锁定。 +- 原生 setter/Link extension 没有 cancel hook,明确记录同步取消边界由 Document transaction abort 代替;`probe/check:freecad-property-boollist-failure` 均通过。 + +### `PROP-app-propertyboollist-D` + +#### 执行过程与完成证据 + +- 对 7 个宿主分别执行 before/edit/recompute/restore/recompute;所有 case 的 BoolList 值、文档对象集和适用 Shape 均恢复到原生初始态。 +- `App::FeatureTest` 执行 `[false] -> [true,false,true] -> [false]`,赋值后 `Touched`、重算后 `Up-to-date / Valid`;`FeatureTestException` 保留其固有 Invalid 诊断,但属性值仍精确恢复。 +- 有效 `GeomFillSurface` 在 reversal 编辑时面积、边界和拓扑计数不变,但 BREP SHA-256 从 `ea7baeb0...` 变为 `f6c587bb...`;恢复后精确返回 `ea7baeb0...`,证明不是仅比较最终数值。 +- 四类 Link 均执行 `[true,true] -> [false,true] -> [true,true]`;C++ Link 变体 touched 时 `MustExecute=false`,Python Link 变体为 true,重算后均回到 `Up-to-date / Valid`。 +- `probe/check:freecad-property-boollist-mutation` 均通过,D 阶段证据已加入连续账本。 + +### `PROP-app-propertyboollist-E` + +#### 执行过程与完成证据 + +- 将 `App::PropertyBoolList` 加入 Facade 原生可编辑类型和 `PropertyValue`,布尔数组在文档快照、事务历史及公开对象读取中保持独立深拷贝;生产 setter 只接受逐项 boolean 的数组,字符串、数字和混合数组在事件与版本变更前 fail-closed。 +- 对照锁定 FreeCAD `src/App/PropertyStandard.cpp` 的 `PropertyBoolList::Save/Restore` 实现,将 FCStd codec 固定为原生反序 `dynamic_bitset` 字符串:例如 `[true,false,false]` 编码为 ``,读取时按低位顺序恢复;未使用通用 JSON 或伪造的列表子节点。 +- `App::FeatureTest`、`App::FeatureTestException`、`Surface::GeomFillSurface` 及四类 Link 宿主进入 FCStd 识别清册;其 `BoolList/ReversedList/VisibilityList` 作为静态原生属性写入,不携带动态 `group/doc/attr` fallback。`VisibilityList` 的 `Immutable + Hidden + LockDynamic` 状态位保持为 266,公开 setter 明确拒绝直接写入。 +- 生产 `PropertyEditor` 新增可逆的 BoolList 编辑分支,接受 `true/false` 与 `1/0` 逗号列表,非法 token 恢复旧显示值;隐藏的 Link `VisibilityList` 继续由原生 Hidden 状态从属性面板过滤。 +- 聚焦测试锁定 `[false] -> [true,false,true]`、文档版本/dirty/touched、事务事件、非法输入零污染、immutable Link 拒绝、原生 bitset XML 和结构化 decoder;`test:freecad-property-boollist-facade`、完整 `test:facade` 199 项、`build` 与 `git diff --check` 均通过。构建仅保留既有 OCCT chunk 体积警告。 + +### `PROP-app-propertyboollist-F` + +#### 执行过程与完成证据 + +- 通过公开 Facade 将普通 `App::FeatureTest.BoolList` 从 `[false]` 改为 `[true,false,true]`;同一 transaction ID 内只产生 `property.before-change -> property.changed -> transaction.committed`,文档版本 `1 -> 2`、dirty 为真且宿主进入 touched。 +- setter 对调用方数组做深拷贝,`getObject()` 返回的数组也不能反向修改内部状态;undo 精确恢复 `[false]`/版本 1,redo 返回 `[true,false,true]`/版本 2,历史栈可用性按预期切换。 +- redo 后注入旧版本写入、预取消 signal、含字符串的混合数组和 immutable `VisibilityList` 直接写入;四项均在提交前 fail-closed,文档 JSON、属性事务事件数及 undo/redo 可用性完全不变。 +- BoolList 属性事务不分配 Shape;前后 `shapeCount`、`kernelReferenceCount` 和 `releasedShapeCount` 完全一致,并显式 dispose 项目持久化边界。 +- `test:freecad-property-boollist-transaction` 与 E 阶段 focused test 均通过,F 阶段证据已加入连续账本。 + +### `PROP-app-propertyboollist-G` + +#### 执行过程与完成证据 + +- 新增受限的 `rewriteFcstdBoolListProperty` 及 Facade `project.fcstd.rewriteBoolList`:先验证对象、属性、`App::PropertyBoolList` TypeId、原生 `BoolList` payload、纯布尔目标数组和预期旧值,再用结构化 XML parser/builder 修改反序 bitset;目标对象标记 touched,其他 ZIP 条目逐项复制。 +- 首次真实检查发现 `App::FeatureTest.FloatList` 使用合法的外部 ``,旧 parser 错误要求内联 `count`;已按 FreeCAD 格式把 resource-backed FloatList 留在 opaque 边界。第二次检查发现普通 `App::PropertyPath` 使用 ``,已按 TypeId 与 CAM `Path::PropertyPath file="*.nc"` 分流,两次失败均未写成通过报告。 +- 最终真实链路为 FreeCAD 1.1.1 创建 `[false]` -> Web 校验并编辑 `[true,false,true,false]` -> FreeCAD reopen/recompute -> saveAs -> reopen;原生重开与再保存均精确返回目标数组,宿主保持 `App::FeatureTest`、普通 property status/editor mode、无 Shape。 +- Web 编辑前后对象集及目标属性之外的 inspection 语义一致;原生归档的 `ColourList`、`FloatList`、`MaterialList`、`VectorList` 四个 opaque 条目逐字节保留,未知语义漂移为零。 +- `probe/check:freecad-property-boollist-roundtrip` 与生产 `build` 均通过;G 阶段证据已加入连续账本。 + +### `PROP-app-propertyboollist-H` + +#### 执行过程与完成证据 + +- 新增真实 Chrome harness,直接复用生产 `PropertyEditor` 和 `createProductionFacade`;通过文本输入框真实 focus/input/blur 将 `false` 改为 `true, false, true, false`,文档版本 `1 -> 2`、dirty 为真、宿主状态为 touched,UI 无错误。 +- 通过具名 `bitbybit-persistence` Worker 执行 initialize、save/load、checkpoint、recovery、resource put/get/release 和 dispose;报告锁定 `sqlite-opfs`、SQLite WASM/OPFS 可用及恢复完整性 `ok`。 +- 浏览器持久化重载保持 `App::PropertyBoolList` 和目标数组;FCStd metadata 识别为原生 `BoolList` 并结构化解码为 `[true,false,true,false]`。 +- OPFS 资源 32 bytes 往返一致,release 后读取为 null,独立 marker 已删除;最终 Shape/内核引用均为 0,持久化 Worker 终止事件已记录。 +- `build`、`test/check:chrome-property-boollist`、E/F 聚焦测试均通过;H 阶段机器证据已追加到连续账本。 + +### `PROP-app-propertyboollist-I` + +#### 执行过程与完成证据 + +- 新增 BoolList 独立 promotion 生成器/checker,对 A-H 的连续证据、原生值模型、FCStd `BoolList` payload、真实 FreeCAD 回放及 Chrome 持久化结果进行闭环校验。 +- `App::PropertyBoolList` 的 7 条记录全部从 opaque 提升为 native-editable:3 条普通可写属性,4 条 Link `VisibilityList` 保持 `Immutable + Hidden + LockDynamic`,没有因提升放宽原生编辑边界。 +- 全局语义分区更新为 `25 / 4313 native-editable`、`5 / 683 specialized`、`55 / 514 opaque`,native codec 总记录为 `4996`;exact blocker 同步为 `55 runtime property types and 514 records remain opaque-only`,系统 exact 仍为 false。 +- `EX-DOC-01` 及早期 Acceleration/Area promotion 报告已同步到当前全局快照,避免已完成证据携带过期分区统计;两项旧 promotion checker 重跑通过。 +- `generate/check:freecad-property-boollist-promotion`、`probe/check:freecad-native-property-semantics` 均通过;首次 execution-plan 总检仅在末尾指出活动队列尚未在 I 登记后重生成,本节记账后立即重建并复验。 + +### `PROP-app-propertycolor-A` + +#### 执行过程与完成证据 + +- BoolList I 登记后活动队列重建为 `514 completed / 1 in-progress / 1241 pending`,`check:execution-plan` 全部通过,唯一队首切换到 `PROP-app-propertycolor-A` 并直接接领。 +- 从 FreeCAD 1.1.1 运行时清册锁定 8 条 `App::PropertyColor` 记录,覆盖 `App::FeatureTest`、`App::FeatureTestException`、`App::Part`、两种 Assembly 对象和三种 TechDraw 视图;8 个宿主均 available、状态为空且可写。 +- 默认值精确分为黑色不透明 `[0,0,0,1]` 与白色全透明 `[1,1,1,0]`;值模型锁定为 RGBA 四通道浮点 tuple,alpha `1=opaque / 0=transparent`,无 Shape 前置且无跨属性依赖。 +- 源码溯源锁定三类 setter:3/4 元同类 float tuple、3/4 元同类 integer tuple(按 255 归一化)及 32 位 `0xRRGGBBAA` packed integer;FCStd 存储为 ``,1.1 前文档读取时单独反转 alpha byte。 +- `generate/check:freecad-property-color-inventory` 通过;A 阶段仅锁定 inventory/preconditions,能力分类仍为 `opaque-fcstd-proxy`,成功边界留给 B 的真实 FreeCAD 探针。 + +### `PROP-app-propertycolor-B` + +#### 执行过程与完成证据 + +- 在 8 个清册宿主上逐个新建独立 FreeCAD 文档,经公开 Python property setter 依次写入 3 元 float、4 元 float、3 元 byte、4 元 byte、`0x11223344` packed integer、全透明边界,最后恢复宿主原默认值。 +- 3 元 float 精确归一为 `[0.25,0.5,0.75,1]`;byte tuple 按 255 归一化,`0x11223344` 按 `RRGGBBAA` 顺序解码为 `17/255,34/255,51/255,68/255`;float32 回读精度和 alpha 全透明值均由 checker 锁定。 +- `TechDraw::DrawViewSpreadsheet` 首轮未关联 Source 时出现可避免的 `No spreadsheet linked`;探针补建有效 `Spreadsheet::Sheet` 后重跑,7 个普通宿主每个阶段均为 `Up-to-date / Valid`。 +- `App::FeatureTestException` 仍按类型设计在变更后固定报 `Testexception ;-)`,颜色值与恢复不受影响;该诊断标记为 intrinsic host diagnostic,没有误归类为 PropertyColor setter 失败。 +- 所有阶段的 TypeId、空 status/editor mode、宿主对象集、无 Shape 适用性、重算状态和诊断均已入机器产物;`probe/check:freecad-property-color-success` 通过。 + +### `PROP-app-propertycolor-C` + +#### 执行过程与完成证据 + +- 真实失败探针先分离原生接受的 coercion:float tuple 通道不夹取,超出 `[0,1]` 的值原样保留;integer tuple 即使超出 byte 范围仍直接除以 255;bool tuple 按 integer 处理。 +- packed integer 锁定低 32 位语义:`0xFFFFFFFF -> [1,1,1,1]`、`0x100000000 -> [0,0,0,0]`、`-1 -> [1,1,1,1]`,三项均为原生接受分支,未伪造成拒绝。 +- `None`、list、长度 2/5 tuple、首项 string、float/int 混合 tuple 及标量 float 共 8 类非法输入均以精确 `TypeError` 拒绝,属性值、文档对象集和后续事务基线零污染。 +- editor `ReadOnly` 只约束 UI,Python setter 仍可写;追加 `Immutable` 后精确拒绝并报 `Object attribute 'Colour' is read-only`,解除后 status/editor mode 恢复为空。 +- 活动事务中将 `[0,0,0,1]` 改为 `[0.75,0.5,0.25,0.125]`,abort 立即恢复 RGBA 但对象保持 Touched,后续 recompute 返回 `Up-to-date / Valid`;取消边界明确为同步 setter 无 cancel hook,由 Document transaction abort 替代。 +- `probe/check:freecad-property-color-failure` 通过,C 阶段机器证据已加入连续账本。 + +### `PROP-app-propertycolor-D` + +#### 执行过程与完成证据 + +- 对 8 个原生宿主分别执行 `before -> edit -> recompute -> restore -> recompute`,统一目标为 `[0.125,0.375,0.625,0.875]`;每个宿主都检测到真实值变异并恢复自身默认 RGBA。 +- 7 个普通宿主的状态序列精确为 `Valid -> Touched -> Valid -> Touched -> Valid`;这锁定了 setter 立即写值与 recompute 清除 touched 的两阶段语义。 +- `App::FeatureTestException` 在第一次重算后进入固有 `Touched + Invalid / Testexception ;-)`,恢复属性不清除该宿主诊断,但 RGBA 仍精确回到 `[0,0,0,1]`。 +- `TechDraw::DrawViewSpreadsheet` 使用有效 `Spreadsheet::Sheet` 前置;App::Part/Assembly 自动创建的 Origin 对象集以及所有其他宿主对象集在变异和恢复中完全不变。 +- 8/8 的 TypeId、空 status/editor mode、无 Shape 适用性、对象集与恢复值均通过 focused checker;`probe/check:freecad-property-color-mutation` 通过。 + +### `PROP-app-propertycolor-E` + +#### 执行过程与完成证据 + +- 将数据域 `App::PropertyColor` 固定为四通道有限数值 RGBA,并与视图域既有 `#RRGGBB` 表示分流;Facade 的输入、对象快照和事务历史均深拷贝颜色数组,错误长度、非数值和非有限通道在版本及事件变更前 fail-closed,原生允许的有限越界通道不被擅自夹取。 +- FCStd codec 按 FreeCAD 原生 `` 实现 `0xRRGGBBAA` 打包和读取,写出使用与 C++ `lround` 一致的半值远离零舍入;同时保留 GuiDocument 视图颜色的既有编码路径,未混淆数据属性与显示属性。 +- `App::FeatureTest`、`App::FeatureTestException`、`App::Part`、两类 Assembly 对象及三类 TechDraw 视图进入 FCStd 静态宿主清册;`Colour/Color/TextColor` 作为原生静态属性写入,不携带动态 `group/doc/attr` fallback,结构化 decoder 可恢复四通道 byte fraction。 +- 生产 `PropertyEditor` 为数据颜色增加原生颜色 swatch 与独立 alpha 数值输入;swatch 仅为浏览器显示夹取 RGB,提交仍保留原生有限数值语义,失败时控件恢复旧值;视图颜色继续使用原来的不透明十六进制编辑器。 +- 聚焦测试锁定八类宿主、深拷贝、事件/版本、非法输入零污染、有限越界值、透明/不透明 packed 边界、无动态属性元数据及数据/视图作用域分离;`test:freecad-property-color-facade`、完整 `test:facade` 199 项、生产 `build` 与 `git diff --check` 均通过。构建仅保留既有 OCCT chunk 体积警告。 + +### `PROP-app-propertycolor-F` + +#### 执行过程与完成证据 + +- 通过公开 Facade 将普通 `App::FeatureTest.Colour` 从 `[0,0,0,1]` 改为 `[0.125,0.375,0.625,0.875]`;同一 transaction ID 内只产生 `property.before-change -> property.changed -> transaction.committed`,文档版本 `1 -> 2`、dirty 为真且宿主进入 touched。 +- setter 对调用方 RGBA 数组做深拷贝,`getObject()` 暴露的数组也不能反向修改内部状态;undo 精确恢复黑色不透明值和版本 1,redo 返回目标 RGBA 和版本 2,历史栈可用性按预期切换。 +- redo 后依次注入旧版本写入、预取消 signal、NaN 通道和 immutable 颜色直接写入;四项均在提交前 fail-closed,文档 JSON、属性事务事件数及 undo/redo 可用性完全不变。 +- PropertyColor 属性事务不分配 Shape;前后 `shapeCount`、`kernelReferenceCount` 和 `releasedShapeCount` 完全一致,并显式 dispose 项目持久化边界。 +- `test:freecad-property-color-transaction` 与 E 阶段 focused test 均通过,F 阶段证据已加入连续账本。 + +### `PROP-app-propertycolor-G` + +#### 执行过程与完成证据 + +- 新增受限的 `rewriteFcstdColorProperty` 及 Facade `project.fcstd.rewriteColor`:先验证对象、属性、`App::PropertyColor` TypeId、唯一原生 `PropertyColor` payload、四通道有限目标值和预期旧值,再用结构化 XML parser/builder 修改 packed RGBA;目标对象标记 touched,其他 ZIP 条目逐项复制。 +- focused test 锁定 `0x11223344 -> 0x336699CC`、错误 expectedValue 和 NaN 目标的 fail-closed 边界;改写后重新 inspect/decode,确保 FCStd 的 byte 量化结果与目标四通道一致。 +- 真实链路由 FreeCAD 1.1.1 创建 `0x11223344` -> Web 校验并编辑为 `[0.2,0.4,0.6,0.8]`/packed `862362060` -> FreeCAD reopen/recompute -> saveAs -> reopen;两次原生回读均为同一组预期 float32 值 `[0.200000003,0.400000006,0.600000024,0.800000012]`。 +- Web 编辑前后对象集及目标属性之外的 inspection 语义一致;`Document.xml` 之外的 4 个原生归档条目逐字节保留,宿主保持 `App::FeatureTest`、普通 property status/editor mode、无 Shape,未知语义漂移为零。 +- `probe/check:freecad-property-color-roundtrip`、完整 `test:facade` 199 项、生产 `build` 与 `git diff --check` 均通过;G 阶段证据已加入连续账本,构建仅保留既有 OCCT chunk 体积警告。 + +### `PROP-app-propertycolor-H` + +#### 执行过程与完成证据 + +- 新增真实 Chrome harness,直接复用生产 `PropertyEditor` 和 `createProductionFacade`;通过原生 HTMLInputElement value setter 与浏览器事件真实操作颜色 swatch `#000000 -> #336699`,再将 alpha `1 -> 0.8`,最终 RGBA 为 `[0.2,0.4,0.6,0.8]`,文档版本 `1 -> 3`、dirty 为真、宿主 touched 且 UI 无错误。 +- 首次浏览器运行因直接赋 `input.value` 同步了 React value tracker,未触发颜色 `onChange`;该次报告保持 failed 并完整 dispose。harness 改为绕过 tracker 的原生 setter 后重新执行通过,没有把测试注入问题伪造成产品成功。 +- 通过具名 `bitbybit-persistence` Worker 执行 initialize、save/load、checkpoint、recovery、resource put/get/release 和 dispose;报告锁定 `sqlite-opfs`、SQLite WASM/OPFS 可用及恢复完整性 `ok`。 +- 浏览器持久化重载保持 `App::PropertyColor` 与四通道目标值;FCStd metadata 识别为原生 `PropertyColor`,packed 值为 `862362060`。OPFS 资源 29 bytes 往返一致,release 后读取为 null,独立 marker 已删除。 +- 最终 Shape/内核引用均为 0,持久化 Worker 终止事件已记录;`test/check:chrome-property-color`、E/F focused 测试、生产 `build` 与 `git diff --check` 均通过,H 阶段机器证据已追加到连续账本。 + +### `PROP-app-propertycolor-I` + +#### 执行过程与完成证据 + +- 新增 Color 独立 promotion 生成器/checker,对 A-H 的连续证据、四通道有限 RGBA 值模型、FCStd `PropertyColor` packed payload、真实 FreeCAD 回放及 Chrome 持久化结果进行闭环校验。 +- `App::PropertyColor` 的 8 条记录全部从 opaque 提升为 native-editable;8 个宿主属性均保持普通可写状态,数据域四通道 RGBA 与视图域 `#RRGGBB` 继续分流,FCStd 明确保留 8-bit packed 量化边界。 +- 全局语义分区更新为 `26 / 4321 native-editable`、`5 / 683 specialized`、`54 / 506 opaque`,native codec 总记录为 `5004`;exact blocker 同步为 `54 runtime property types and 506 records remain opaque-only`,系统 exact 仍为 false。 +- `EX-DOC-01`、当前工作文档、主执行计划及早期 Acceleration/Area/BoolList promotion 报告已同步到当前全局快照,避免已完成证据携带过期分区统计;三项旧 promotion checker 重跑通过。 +- `generate/check:freecad-property-color-promotion`、`probe/check:freecad-native-property-semantics`、Property status oracle 与 `git diff --check` 均通过;I 阶段证据已加入连续账本,下一步重建活动队列并运行 execution-plan 总检。 + +### `PROP-app-propertycolorlist-A` + +#### 执行过程与完成证据 + +- Color I 登记后活动队列重建为 `523 completed / 1 in-progress / 1232 pending`,`check:execution-plan` 全部通过,唯一队首切换到 `PROP-app-propertycolorlist-A` 并直接接领。 +- 从 FreeCAD 1.1.1 运行时清册锁定 2 条 `App::PropertyColorList` 记录,宿主为 `App::FeatureTest` 与 `App::FeatureTestException` 的 `ColourList`;两项均 available、状态为空且可写,默认值均为单个黑色不透明颜色 `[[0,0,0,1]]`,无 Shape 或跨属性前置。 +- 列表输入边界由 `PropertyListsBase` 与 `PropertyColorList::getPyValue` 源码共同锁定:接受 sequence、iterable、单个颜色值及整数索引字典,字典 `-1/current-size` 可追加;每个元素复用 PropertyColor 的 3/4 元 float tuple、3/4 元 integer tuple和 packed `0xRRGGBBAA` setter。 +- FCStd XML 为 ``,非空值写入同名外部二进制资源,布局固定为 little-endian `uint32 count` 后接逐项 `uint32 packed RRGGBBAA`;空列表使用空 file 属性,1.1 前读取时逐项反转 alpha。 +- `generate/check:freecad-property-colorlist-inventory` 与 `git diff --check` 均通过;A 阶段仍保持 `opaque-fcstd-proxy`,真实成功、失败和变异边界留给 B/C/D。 + +### `PROP-app-propertycolorlist-B` + +#### 执行过程与完成证据 + +- 在 `App::FeatureTest` 与 `App::FeatureTestException` 两个清册宿主上经公开 Python property setter 覆盖 empty、单 float tuple、混合 float/byte/packed 元素、单 packed 标量、generator iterable、字典索引更新/追加、257 项大列表和恢复值。 +- 原生容器归一化符合 A 阶段源码边界:单 packed 标量变为单项列表,generator 被完整消费;`{1: 0x11223344, -1: (0,255,0,128)}` 在两项基线上更新索引 1 并追加第三项,值顺序和 alpha 均精确锁定。 +- 混合元素逐项复用 PropertyColor float32/byte/packed 归一化;257 个 `0x01020304` 全部回读为同一 RGBA,未发生截断、重排或共享引用,最后精确恢复默认 `[[0,0,0,1]]`。 +- 普通宿主每阶段均为 `Up-to-date / Valid`;`FeatureTestException` 在第一次实际变更重算后固定进入 `Touched + Invalid / Testexception ;-)`,属性写入、列表长度和恢复不受影响,该诊断明确归类为 intrinsic host diagnostic。 +- 两宿主的 TypeId、空 status/editor mode、无 Shape 适用性和对象集均保持稳定;`probe/check:freecad-property-colorlist-success` 与 `git diff --check` 均通过,B 阶段机器证据已加入连续账本。 + +### `PROP-app-propertycolorlist-C` + +#### 执行过程与完成证据 + +- 真实失败探针分离 6 个原生接受 coercion:bool packed 标量、bytes 整数序列、裸 3/4 元同类 float/integer tuple 单颜色、2 元 packed tuple 颜色序列和空字典清空;tuple 的单颜色/列表消歧据实回写 A 清册,没有把接受分支伪造成失败。 +- `None`、裸 float list、float/int 混合 tuple、短 nested tuple、含 `None` 的列表、标量 float、字符串、nested list、非整数字典键和正负越界索引共 11 项精确拒绝且保持原列表;对象集全程不变。 +- 字典 `{0: 0x01020304, 1: None}` 是唯一非原子失败:索引 0 已变更后,索引 1 抛出 TypeError,原生属性留下部分变异;checker 显式锁定该行为,后续 Facade 必须把公开事务边界设计与此原生 Python setter 风险区分开。 +- editor `ReadOnly` 只约束 UI,Python setter 仍可将两项列表替换为一项;追加 `Immutable` 后精确拒绝并报 `Object attribute 'ColourList' is read-only`,解除状态后 status/editor mode 恢复为空。 +- 活动事务中将两项基线改为三项混合颜色,abort 立即恢复列表但对象保持 Touched,后续 recompute 返回 `Up-to-date / Valid`;同步 setter 无 cancel hook,由 Document transaction abort 替代。 +- `probe/check:freecad-property-colorlist-failure`、更新后的 A checker 与 `git diff --check` 均通过,C 阶段机器证据已加入连续账本。 + +### `PROP-app-propertycolorlist-D` + +#### 执行过程与完成证据 + +- 对 `App::FeatureTest` 与 `App::FeatureTestException` 分别执行 `before -> edit -> recompute -> restore -> recompute`;统一目标含 float、packed、byte 和全透明四种颜色,完整列表顺序与逐通道 float32 回读均由 checker 锁定。 +- 两宿主都从默认 `[[0,0,0,1]]` 真实变异为四项列表,并在恢复阶段精确返回默认值;对象集、无 Shape 适用性、TypeId、空 status/editor mode 全程保持不变。 +- 普通宿主状态序列精确为 `Valid -> Touched -> Valid -> Touched -> Valid`,证明整表 setter 立即触发 touched 且 recompute 清除状态。 +- `FeatureTestException` 在第一次重算后进入固有 `Touched + Invalid / Testexception ;-)`,恢复属性不清除该宿主诊断,但颜色列表仍精确恢复。 +- `probe/check:freecad-property-colorlist-mutation` 与 `git diff --check` 均通过,D 阶段机器证据已加入连续账本。 + +### `PROP-app-propertycolorlist-E` + +#### 执行过程与完成证据 + +- 将 `App::PropertyColorList` 接入 typed `ColorListValue`、Facade 原生可编辑类型与文档/持久化快照深拷贝;公开 setter 只接受有序四通道有限 RGBA 数组,非法长度、NaN 和字符串输入均在事件及版本变更前原子拒绝,未复刻原生 Python 字典逐项写入可能留下部分变异的非原子风险。 +- FCStd writer 按 FreeCAD 原生格式输出 `` 和 little-endian `uint32 count + uint32 packed RRGGBBAA[]` 外部资源;同名属性按 `ColourList`、`ColourList1` 唯一化,空列表固定 `file=""` 且不生成资源,数据属性不再携带动态 `group/doc/attr` fallback。 +- inspector 新增严格 ColorList hydration:缺失、截断、count/字节数不一致或非法资源路径全部 fail-closed;结构化 decoder 恢复逐项 8-bit RGBA 量化值。`rewriteMetadata` 会移除旧的已知 ColorList 条目并按当前文档重建,避免与 opaque 资源碰撞或保留陈旧 payload。 +- 生产 `PropertyEditor` 新增 ColorList 逐项编辑器,每项提供颜色 swatch、独立 alpha 数值输入和删除按钮,并提供添加颜色按钮;所有提交仍经公开 Facade,未从 UI 直接写文档状态。 +- 聚焦测试锁定嵌套数组双向深拷贝、单事务事件序列、非法嵌套值零污染、两个同名宿主的资源唯一化、二进制字节布局、空列表、缺失资源拒绝和 metadata rewrite 量化结果。`test:freecad-property-colorlist-facade`、完整 `test:facade` 199 项、PropertyColor/BoolList 相邻回归、`test:fcstd-roundtrip`、生产 `build` 与 `git diff --check` 均通过;构建仅保留既有 OCCT chunk 体积警告。 + +### `PROP-app-propertycolorlist-F` + +#### 执行过程与完成证据 + +- 通过公开 Facade 将普通 `App::FeatureTest.ColourList` 从单个黑色不透明项改为两个 RGBA 项;同一 transaction ID 只产生 `property.before-change -> property.changed -> transaction.committed`,文档版本 `1 -> 2`、dirty 为真且宿主进入 touched。 +- setter、Facade 快照、history undo/redo 均验证嵌套颜色项的深拷贝:修改调用方数组或 `getObject()` 返回值不会反向改变文档;undo 恢复单项和版本 1,redo 恢复双项和版本 2,历史栈可用性符合预期。 +- redo 后依次注入旧版本写入、预取消 signal、含 NaN 的嵌套颜色和 immutable ColorList 写入;四项均在提交前 fail-closed,文档 JSON、属性事务事件数及 undo/redo 可用性完全不变。 +- ColorList 事务不分配几何 Shape;前后 `shapeCount`、`kernelReferenceCount` 和 `releasedShapeCount` 完全一致,并显式 dispose 项目持久化边界。 +- `test:freecad-property-colorlist-transaction` 与 E 阶段 focused test 均通过,F 阶段证据已加入连续账本。 + +### `PROP-app-propertycolorlist-G` + +#### 执行过程与完成证据 + +- 新增受限 FCStd 直改入口 `rewriteFcstdColorListProperty` 并经公开 Facade `project.fcstd.rewriteColorList` 暴露;入口校验对象、属性、原生类型、唯一 XML declaration/data/payload、外部资源路径、旧值前置条件及目标 RGBA 有限值,任一歧义均 fail-closed。 +- 直改保持原有 `ColourList` 资源路径,只将目标二进制按 `uint32 count + packed RRGGBBAA[]` 重写并标记宿主 touched;写后重新 inspect/decode,按 8-bit 原生量化值闭环校验。聚焦测试同时锁定正常改写、旧值不匹配和 NaN 拒绝。 +- 真实 FreeCAD 链路从单项 `0x11223344` 文件开始,经 Web 改成 `[[0.2,0.4,0.6,0.8],[17/255,34/255,51/255,68/255]]`,随后由 FreeCAD 打开、recompute、另存并再次打开;两次原生回读均为相同 float32 量化结果,未发生顺序或 alpha 漂移。 +- `ColourList` 路径保持不变,资源由 8 字节变为 12 字节且内容确实改变;其余 3 个 opaque archive entry 逐字节保持,对象集合、TypeId、status/editor mode、无 Shape 状态及非目标语义对象均保持,`zeroUnknownDrift=true`。 +- `probe/check:freecad-property-colorlist-roundtrip`、E/F 聚焦测试、完整 `test:facade` 199 项、生产 `build` 与 `git diff --check` 均通过;G 阶段机器证据已加入连续账本。 + +### `PROP-app-propertycolorlist-H` + +#### 执行过程与完成证据 + +- 新增独立真实 Chrome `PropertyColorList` harness,直接挂载生产 `PropertyEditor` 和 `createProductionFacade`;页面在 cross-origin isolation 下启动实际 `bitbybit-persistence` Worker,没有使用 DOM 外捷径写文档。 +- 真实 UI 从单项黑色列表出发,连续点击两次新增达到 3 项、删除第 3 项回到 2 项,再通过两个原生 color input 和两个 alpha number input 写成 `[[0.2,0.4,0.6,0.8],[17/255,34/255,51/255,0.4]]`;所有 aria label、输入类型、颜色显示值、项目数和无 UI 错误均由 checker 锁定。 +- 7 次 UI 提交将文档版本从 1 推进到 8,dirty 为真且宿主为 touched;SQLite OPFS save/load、version 8 checkpoint 和 recovery integrity 均恢复完整嵌套列表与 `App::PropertyColorList` 类型。 +- 浏览器内 FCStd 检查确认原生 `ColorList` 元素、`ColourList` 外部资源路径和 12 字节二进制 payload;独立资源 put/get/release 往返成功,OPFS marker 创建后可删除。 +- Worker 请求覆盖 initialize/save/load/checkpoint/recovery/resource/dispose,最终 persistence Worker 已 terminate;几何 `shapeCount=0`、`kernelReferenceCount=0`。`test/check:chrome-property-colorlist`、E/F 聚焦测试、生产 `build`、JSON 校验与 `git diff --check` 均通过,H 阶段机器证据已加入连续账本。 + +### `PROP-app-propertycolorlist-I` + +#### 执行过程与完成证据 + +- 新增 ColorList 独立 promotion 生成器/checker,逐项核对 A-H 连续账本、两个可写原生宿主、有序变长 RGBA 值模型、外部 FCStd 二进制资源、真实 FreeCAD 往返和 Chrome OPFS 结果。 +- `App::PropertyColorList` 的 2 条记录从 `opaque-fcstd-proxy` 提升为 `native-editable-codec`;能力报告锁定 `ColorList` 元素、`ColourList` 路径、12 字节双项 payload、逐项 8-bit packing 和零未知语义漂移。 +- 全局 Property 分区同步为 `27 / 4323 native-editable`、`5 / 683 specialized`、`53 / 504 opaque`,native codec 总记录为 `5006`;exact blocker 更新为 `53 runtime property types and 504 records remain opaque-only`,系统 exact 保持 false,`EX-DOC-01` 继续 in-progress。 +- 主执行计划、当前工作文档、exact parity blocker 以及 Acceleration/Area/BoolList/Color 四份既有 promotion 报告均同步到新快照;四个旧 checker 与 ColorList 新 checker 全部重跑通过,没有保留陈旧分区数字。 +- `generate/check:freecad-property-colorlist-promotion`、`probe/check:freecad-native-property-semantics`、Property status oracle、exact parity plan、JSON 校验和 `git diff --check` 均通过;I 阶段证据已加入连续账本。 + +### `PROP-app-propertydirection-A` + +#### 执行过程与完成证据 + +- 从锁定 FreeCAD 1.1.1 运行时清册确认 2 条 `App::PropertyDirection`:`Part::Mirroring.Normal`(Plane 组)和 `Part::ProjectOnSurface.Direction`(Projection 组);两项均 available、无 status、可写,默认值均为 `[0,0,1]`。 +- 源码锁定 Direction 直接继承 `App::PropertyVector`,属性 setter 接受 `Base.Vector` 或恰好三个 float/integer 分量的 tuple,属性层不执行归一化;暴露 `x/y/z` 子路径,编辑器为 `Gui::PropertyEditor::PropertyDirectionItem`,并沿用 `Base::Unit::Length`。 +- FCStd 继承 `` 三个 decimal double 属性,无外部资源;外层 Property TypeId 仍为 `App::PropertyDirection`。 +- 属性写入本身不要求 Shape,但宿主成功执行依赖几何输入且下游 `gp_Dir` 要求非零方向:Mirroring 依赖 Source/Base,MirrorPlane 可覆盖 Base/Normal 并令两者 ReadOnly;ProjectOnSurface 依赖单一 SupportFace 与 Projection 列表。 +- `generate/check:freecad-property-direction-inventory`、JSON 校验和 `git diff --check` 均通过;A 阶段保持 `opaque-fcstd-proxy`,真实 setter、重算、失败和 Shape 变异证据留给 B/C/D。 + +### `PROP-app-propertydirection-B` + +#### 执行过程与完成证据 + +- 真实 FreeCAD 为 `Part::Mirroring.Normal` 建立 2×3×4 Box 镜像,为 `Part::ProjectOnSurface.Direction` 建立 z=-5 的封闭 Wire、z=0 平面 Face、Edges 模式投影夹具;两个宿主默认和恢复均为 `[0,0,1]`、Valid、Up-to-date。 +- 每个宿主依次接受轴向 tuple、整数 tuple `[1,1,2]`、非单位 float tuple `[0.25,-0.5,1.5]`、`Base.Vector`、近轴有限值和大有限值;属性回读逐分量保持请求值,没有隐式单位化。 +- Mirroring 每个成功阶段均产出有效 Solid(1 solid/6 faces/12 edges/8 vertices,volume 24,area 52);ProjectOnSurface 每个成功阶段均产出有效 Compound(4 edges/4 vertices,无 solids/faces),对象集和属性 TypeId/status/editor mode 均稳定。 +- setter 后两宿主都进入 Touched;Mirroring `MustExecute=true`,ProjectOnSurface 保持原生 `MustExecute=false`,随后 recompute 均返回成功并恢复 Up-to-date/Valid。除重复轴向项外,各方向均产生不同 BRep 哈希,恢复阶段与默认 BRep/bounds 精确一致。 +- `probe/check:freecad-property-direction-success`、JSON 校验与 `git diff --check` 均通过;B 阶段机器证据已加入连续账本,零向量、NaN/Inf、空依赖和取消行为留给 C。 + +### `PROP-app-propertydirection-C` + +#### 执行过程与完成证据 + +- 原生 setter 进一步锁定 Python coercion:混合 integer/float 三元 tuple 和 bool 三元 tuple 均被接受,bool 按 `1/0` 回读;`None`、list、长度 2/4 tuple、含 string 分量、标量 float/int 共 7 类输入精确 TypeError 拒绝,方向值和对象集零污染。 +- 零向量在 Property 层被接受,但两个真实宿主重算后均进入 `Touched + Invalid / gp_Dir() - input vector has zero norm`;`document.recompute()` 仍返回 true,最后有效 Solid/Compound Shape 及 BREP hash 保持不变,没有把宿主错误误报成 setter 拒绝。 +- NaN 与正负 Infinity 的宿主边界改用独立 FreeCAD 子进程并各复跑两次:Mirroring 六次均在 setter 触发的同步 `onChanged/recompute` 内达到 5 秒硬超时;ProjectOnSurface 六次均记录 `Courbes non jointives` 后以状态 0 提前退出且无完成标记。两类结果均稳定,主探针不会被单个原生挂起吞掉。 +- 移除 Mirroring Source 和 ProjectOnSurface SupportFace 分别得到 `No object linked`、`No support face specified` 并保留最后有效 Shape;清空 Projection 是原生合法边界,宿主保持 Valid 并产出 Null Shape,未伪造成依赖失败。 +- editor `ReadOnly` 仍只约束 UI,Python setter 可写;`Immutable` 精确拒绝并报 `Object attribute 'Normal' is read-only`。活动事务中方向变异后 abort 恢复 `[0,0,1]` 和对象集,宿主经重算回到 Up-to-date/Valid;同步 setter 无 cancel hook,由 Document transaction abort 替代。 +- `probe/check:freecad-property-direction-failure`、JSON 校验与 `git diff --check` 均通过;C 阶段机器证据已加入连续账本。 + +### `PROP-app-propertydirection-D` + +#### 执行过程与完成证据 + +- 对 `Part::Mirroring.Normal` 和 `Part::ProjectOnSurface.Direction` 分别执行 `before -> [0.25,-0.5,1.5] -> recompute -> [0,0,1] -> recompute`,两个宿主的属性值均真实变异并精确恢复。 +- Mirroring 的 BREP SHA-256 由 `ba656082...` 变为 `78c098a6...` 后恢复,ProjectOnSurface 由 `ba524197...` 变为 `3c78808d...` 后恢复;两者的 bounds、拓扑数、面积、体积和完整 Shape 快照均回到初值,不是仅比较方向数值。 +- 两个宿主状态序列均为 `Valid -> Touched -> Valid -> Touched -> Valid`;Mirroring setter 后 `MustExecute=true`,ProjectOnSurface 延续原生 `MustExecute=false`,重算后均回到 Up-to-date/Valid。 +- 属性 TypeId、空 status/editor mode、对象集和有效 Solid/Compound 拓扑全程不变;`probe/check:freecad-property-direction-mutation` 与 `git diff --check` 均通过,D 阶段机器证据已加入连续账本。 + +### `PROP-app-propertydirection-E` + +#### 执行过程与完成证据 + +- 将 `App::PropertyDirection` 加入 Facade 原生可编辑类型并复用 `VectorValue` 的三轴有限数值模型、深拷贝和事务路径;公开 setter 接受非单位有限向量及原生属性层允许的零向量,NaN、数组和缺分量对象在事件与版本变更前原子拒绝。 +- FCStd writer 保留外层 `App::PropertyDirection` TypeId,内层严格写为 ``;decoder 只接受该原生 payload,伪装成 String 的 JSON 向量保持 fail-closed。 +- `Part::Mirroring.Normal` 与 `Part::ProjectOnSurface.Direction` 加入静态原生宿主清册,写出时不携带动态 `group/doc/attr` fallback;两个对象 TypeId 进入 recognized 范围,结构化 inspector 可恢复完整非单位方向。 +- 生产 `PropertyEditor` 复用三轴数值编辑器,所有提交继续经过公开 Facade;没有增加 UI 到内核或 FCStd 的旁路,也没有在 UI 层擅自归一化方向。 +- 聚焦测试锁定深拷贝、事件/版本、零向量、非法值零污染、两个宿主的原生 XML 和严格 decoder;`test:freecad-property-direction-facade`、完整 `test:facade` 199 项、Color/ColorList 相邻回归、`test:fcstd-roundtrip`、生产 `build` 与 `git diff --check` 均通过,构建仅保留既有 OCCT chunk 体积警告。 + +### `PROP-app-propertydirection-F` + +#### 执行过程与完成证据 + +- 通过公开 Facade 将 `Part::Mirroring.Normal` 从 `{x:0,y:0,z:1}` 改为 `{x:0.25,y:-0.5,z:1.5}`;同一 transaction ID 内只产生 `property.before-change -> property.changed -> transaction.committed`,文档版本 `1 -> 2`、dirty 为真且宿主进入 touched。 +- setter、公开对象快照和 history 均保持向量深拷贝;undo 精确恢复初值/版本 1,redo 返回非单位目标值/版本 2,历史栈可用性按预期切换。 +- redo 后依次注入旧版本写入、预取消 signal、Infinity 分量和 immutable Direction 写入;四项均在提交前 fail-closed,文档 JSON、属性事务事件数及 undo/redo 可用性完全不变。 +- Direction 属性事务不分配 Shape;前后 `shapeCount`、`kernelReferenceCount` 和 `releasedShapeCount` 完全一致,并显式 dispose 项目持久化边界。 +- `test:freecad-property-direction-transaction` 与 E 阶段 focused test 均通过,F 阶段证据已加入连续账本。 + +### `PROP-app-propertydirection-G` + +#### 执行过程与完成证据 + +- 新增受限的 `rewriteFcstdDirectionProperty` 及 Facade `project.fcstd.rewriteDirection`:先验证对象、属性、`App::PropertyDirection` TypeId、唯一 `PropertyVector` payload、三轴有限目标值和预期旧值,再结构化修改 valueX/Y/Z 并标记宿主 touched;写后重新 inspect/decode 闭环确认。 +- 真实链路由 FreeCAD 1.1.1 创建 `Part::Box + Part::Mirroring`、初始 Normal `{x:0,y:0,z:1}`,经 Web 改成 `{x:0.25,y:-0.5,z:1.5}`,随后 FreeCAD reopen/recompute、saveAs/reopen;两次原生方向回读均精确保持目标值。 +- 目标 Direction 令镜像 Solid 的 bounds 与 BREP 确实变化,同时保持 1 solid/6 faces/12 edges/8 vertices、area 52、volume 24。首次真实检查发现重开重算 BREP hash `78c098a6...` 在 FreeCAD 保存再开后变为 `d2f2dec7...`,未把报告伪写为通过。 +- 第二次独立 verify/saveAs/reopen 精确复现相同 `78c098a6... -> d2f2dec7...` 演进;方向、bounds、拓扑、质量属性和 validity 在四个快照中一致,故按主文档登记为 `native-allowed-evolution / brep-serialization`,结构漂移与未知语义漂移均为零。 +- Web 编辑前后目标属性之外的 inspection 语义一致,`Document.xml` 外 3 个归档条目逐字节保持,对象集、TypeId、status/editor mode 均稳定;`probe/check:freecad-property-direction-roundtrip`、E/F 聚焦测试与 `git diff --check` 均通过。 + +### `PROP-app-propertyfile-E` + +#### 执行过程与完成证据 + +- 接续时机器队列唯一活动任务为 `PROP-app-propertyfile-E`;A-D 的原生清册、成功、失败和变异 checker 全部通过,锁定 `App::PropertyFile` 是继承 `PropertyString` 的外部文件路径语义,宿主绝对路径不能直接写入浏览器项目。 +- Facade 将 `App::PropertyFile` 纳入原生可编辑属性类型,公开 setter 只接受空值或最长 4096 字符的安全项目相对路径;绝对路径、盘符、URL scheme、反斜杠、NUL、空路径段和 `.`/`..` 路径段均在事务事件和文档版本变化前 fail-closed。 +- FCStd writer 保持 FreeCAD 原生 `` 结构;`Mesh::Import.FileName` 作为静态原生属性写出,不携带动态属性 fallback。decoder 只接受 `String` payload,并拒绝宿主绝对路径和伪造元素类型。 +- 生产 `PropertyEditor` 的普通文本输入仍只调用 `facade.app.document.setProperty()`,没有 UI 到文档或 FCStd 的旁路;`createProductionFacade` 与聚焦测试使用同一 Facade 核心,能力边界是显式项目资源引用代理,不伪装成宿主文件系统访问。 +- 首次 focused test 发现 `decodeFcstdPropertyValue()` 的 PropertyFile `try/catch` 分支缺少闭合花括号,已修复语法后重跑。`test:freecad-property-file-facade` 2/2、生产 `build`、四个 A-D checker 和 `git diff --check` 均通过;构建仅保留既有 OCCT chunk 体积警告。 + +### `PROP-app-propertyfile-F` + +#### 执行过程与完成证据 + +- 新增独立 PropertyFile 事务夹具,普通与 `Immutable` 两个 `Mesh::Import.FileName` 属性均通过公开 Facade 操作;一次成功写入只产生同一 transaction ID 的 `property.before-change -> property.changed -> transaction.committed`,版本 `1 -> 2`、dirty 和 touched 状态正确。 +- undo 精确恢复 `mesh-data/cube.stl` 与版本 1,redo 恢复 `project-files/updated.stl` 与版本 2;历史栈可用性按预期切换。 +- redo 后依次注入旧版本写入、预取消 signal、`..` 目录穿越、超过 4096 字符的引用和 Immutable 属性写入;五项均在提交前 fail-closed,文档 JSON、属性事务事件数和 undo/redo 状态完全不变。 +- PropertyFile 事务不分配 Shape;前后 `shapeCount`、`kernelReferenceCount` 和 `releasedShapeCount` 完全一致,并显式 dispose 项目持久化边界。 +- `test:freecad-property-file-transaction` 1/1、E 阶段 focused test 2/2 与 `git diff --check` 均通过,F 阶段证据已加入连续账本。 + +### `PROP-app-propertyfile-G` + +#### 执行过程与完成证据 + +- 新增受限 `rewriteFcstdFileProperty` 并经公开 Facade `project.fcstd.rewriteFile` 暴露;入口只接受唯一 `App::PropertyFile/String` payload、安全项目相对路径和可选旧值前置条件,结构化修改目标 XML、标记宿主 touched,并逐项复制其他归档条目。 +- focused test 锁定成功直改、旧值不匹配和宿主绝对路径拒绝;一次测试失败仅因 XML 属性顺序断言过窄,改为无序属性匹配后通过,未改动实现语义。 +- 真实 FreeCAD 链路创建 `Mesh::Import.FileName = .cache/freecad/FreeCAD/data/tests/mesh.obj`,Web 改为 `.cache/freecad/property-file-roundtrip/alternate.obj`,FreeCAD 再开、重算、另存并重开;三阶段路径值均与预期一致。 +- 外部资源没有伪装为 FCStd 内嵌数据:初始 OBJ 哈希对应 12 facets/8 points、bounds `[-5,-5,-5,5,5,5]`,目标 OBJ 哈希对应 1 facet/3 points、bounds `[0,0,0,4,3,0]`;目标 Mesh 在原生 resave 后完全稳定,证明 FreeCAD 实际消费了新引用。 +- Web 编辑前后目标属性之外的 inspection 语义一致,`Document.xml` 外原生归档条目逐字节保持,对象集、TypeId、status/editor mode、无 Shape/有 Mesh 边界均稳定,`zeroUnknownDrift=true`。 +- `probe/check:freecad-property-file-roundtrip`、E/F focused 测试、生产 `build`、JSON 校验与 `git diff --check` 均通过;构建仅保留既有 OCCT chunk 体积警告,G 阶段证据已加入连续账本。 + +### `PROP-app-propertyfile-H` + +#### 执行过程与完成证据 + +- 新增独立真实 Chrome `PropertyFile` harness,直接挂载生产 `PropertyEditor` 和 `createProductionFacade`;页面在 cross-origin isolation 下启动实际 `bitbybit-persistence` Worker,没有从 DOM 外直接修改文档。 +- 真实文本输入将 `FileName` 从 `project-files/initial.obj` 改为 `project-files/chrome-updated.obj`;文档版本 `1 -> 2`、dirty 为真、宿主进入 touched,UI 没有错误,输入类型和 aria label 分别为 `text`、`File name`。 +- SQLite OPFS save/load、version 2 checkpoint 和 recovery integrity `ok` 均恢复目标字符串与 `App::PropertyFile` TypeId;浏览器内 FCStd metadata 固定为原生 `String` 元素和相同项目相对路径。 +- 63 bytes OBJ 资源通过项目资源 API put/get/release,释放后读取为 null;独立 OPFS marker 创建并删除成功。Worker 请求覆盖 initialize/save/load/checkpoint/recovery/resource/dispose,最终 persistence Worker 已 terminate。 +- 最终 `shapeCount=0`、`kernelReferenceCount=0`;`test/check:chrome-property-file`、E/F focused、G checker、生产 `build`、JSON 校验与 `git diff --check` 均通过,H 阶段机器证据已加入连续账本。 + +### `PROP-app-propertyfile-I` + +#### 执行过程与完成证据 + +- 新增 PropertyFile 独立 promotion 生成器/checker,逐项核对 A-H 连续账本、16 条可写原生宿主、项目相对路径值模型、`String` FCStd payload、真实 FreeCAD 往返与 Chrome OPFS/Worker 释放证据。 +- `App::PropertyFile` 的 16 条记录从 `opaque-fcstd-proxy` 提升为 `native-editable-codec`;Facade 边界固定为最长 4096 字符的安全项目相对路径,宿主绝对路径、URL scheme、目录穿越和非法分隔符仍 fail-closed,外部资源字节不伪装成 FCStd 内嵌数据。 +- 全局 Property 分区同步为 `29 / 4341 native-editable`、`5 / 683 specialized`、`51 / 486 opaque`,native codec 总记录为 `5024`;exact blocker 更新为 `51 runtime property types and 486 records remain opaque-only`,系统 exact 保持 false,`EX-DOC-01` 继续 in-progress。 +- 主执行计划、当前工作文档、exact parity blocker 以及既有 Acceleration/Area/BoolList/Color/ColorList/Direction promotion 报告已同步到同一全局快照,未携带过期分区数字。 +- `generate/check:freecad-property-file-promotion`、`check:freecad-native-property-semantics` 及 Property status oracle 通过;I 阶段证据已追加到连续账本,下一步重建活动队列并直接接领 `PROP-app-propertyfileincluded-A`。 + +### `PROP-app-propertyfileincluded-A` + +#### 执行过程与完成证据 + +- PropertyFile I 登记后活动队列重建为 `550 completed / 1 in-progress / 1205 pending`,唯一队首切换到 `PROP-app-propertyfileincluded-A`并直接接领。 +- 从锁定 FreeCAD 1.1.1 运行时清册确认 20 条 `App::PropertyFileIncluded` 记录、15 个宿主类型;20/20 可实例化,状态分区为 11 条空状态、8 条 `ReadOnly`、1 条 `PropOutput`,8 条默认为空,12 条已有文档 transient 副本。 +- 源码锁定该类型不是普通路径字符串:setter 要求源文件存在,将外部文件复制到文档 transient 目录,或将可写 transient 文件重命名后接管,并将目标设为只读;替换、同名冲突、Copy/Paste 与 Undo/Redo 都维护每属性文件所有权。 +- FCStd 普通归档使用 `` 并将原始字节作为独立 ZIP entry,force-XML 模式使用 `data` 属性内嵌二进制流;重开后属性值是运行时 transient 路径,不是可移植语义值。浏览器边界因此必须保存项目资源标识与字节,不得暴露或持久化宿主路径。 +- 6 条 App/VRML/Image/Robot/Sketcher 记录为直接资源;14 条 TechDraw 记录分别从 `FileGeomPattern/FileHatchPattern/FilePattern/HatchPattern/Template/SymbolFile/ImageFile` 经宿主 `onChanged` 复制字节,派生关系已逐项进入机器清册。 +- `generate/check:freecad-property-fileincluded-inventory`、JSON 解析和 `git diff --check` 通过;A 阶段仍保持 `opaque-fcstd-proxy`,真实 setter、字节哈希、同名冲突和宿主派生成功边界留给 B。 + +### `PROP-app-propertyfileincluded-B` + +#### 执行过程与完成证据 + +- 在 `App::DocumentObjectFileIncluded.File` 上真实验证 UTF-8 字符串路径、bytes 路径、`(sourcePath, archiveName)` 改名、打开的 IO 文件和 `{filename,filter}` 字典五类入口;所有输入均复制到文档 transient 目录,目标字节 SHA-256 与源文件一致且写权限位为 0。 +- 已有值后设置空字符串是原生成功 no-op,路径、字节和状态不变;两个属性同时请求 `collision.bin` 时第二个稳定改名为 `collision1.bin`,两份资源路径和字节哈希均不同,没有覆盖。 +- 对清册中 20 条宿主属性分别注入匹配的 BIN/VRML/PNG/Robot CSV/SKF/PAT/SVG 真实资源;20/20 都返回 transient 只读文件、20/20 字节哈希精确一致、20/20 对象集不变且重算后为 `Up-to-date / Valid`。 +- 8 条 `ReadOnly` 记录的 Python setter 仍按 FreeCAD 原生语义写入,但 editor mode 保持 `ReadOnly`;普通属性写入后进入 Touched,唯一 `PropOutput` 的 `DrawSVGTemplate.PageResult` 按原生语义抑制 touch,`recompute()` 返回 false 且宿主保持 Valid。 +- 唯一带 Shape 的 `Sketcher::SketchObjectSF` 在资源写入前后均为空 Shape,边数/面数/点数为 0;其他 19 条明确记录 Shape 不适用,未用伪几何补足成功证据。 +- `probe/check:freecad-property-fileincluded-success`、A checker、JSON 解析和 `git diff --check` 均通过;B 阶段机器证据已追加到连续账本。 + +### `PROP-app-propertyfileincluded-C` + +#### 执行过程与完成证据 + +- 缺失源文件、错误标量类型、错误 tuple 长度、tuple 文件名类型、字典 filename 类型和当前 transient 路径重复设置共 6 类输入分别稳定抛出 `OSError/TypeError`;每项都保持旧路径、字节 SHA-256、只读权限和对象集。 +- 首次探针发现目录路径不被原生 setter 拒绝:FreeCAD 在无异常情况下先删除旧 transient 文件,随后将属性留为指向目录的非文件值。该行为已单独分类为 `accepted non-atomic risk`,并验证可通过合法文件重建有效只读副本;后续 Facade 必须预先原子拒绝目录。 +- 仅含 `filter` 的字典被接受为值 no-op,文件与对象集不变。editor `ReadOnly` 不禁止 Python setter,仍可生成新的只读 transient 副本;追加 `Immutable` 后精确拒绝并报 `Object attribute 'File' is read-only`,解除后 status 恢复为空。 +- 首次事务探针因未开启 `UndoMode=1` 而没有形成 pending transaction,该次报告保持失败并未伪写。补齐原生前置后重跑:编辑使用不同字节 hash,abort 后恢复旧路径与 hash,新 `transaction-write.bin` 副本已删除,pending/active transaction 归零,对象集不变。 +- setter 是同步边界且没有 native cancel hook,取消语义明确由活动 Document transaction abort 承担。`probe/check:freecad-property-fileincluded-failure`、B/A checker、JSON 解析和 `git diff --check` 均通过,C 阶段已入账。 + +### `PROP-app-propertyfileincluded-D` + +#### 执行过程与完成证据 + +- 对清册 20 条宿主属性分别执行 `before -> edited -> recompute -> restored -> recompute`,每个 case 都在同一归档名上用两份不同 BIN/VRML/PNG/Robot CSV/SKF/PAT/SVG 字节替换,排除仅路径改名的假变异。 +- 20/20 的 edited SHA-256 与 before 不同,20/20 的 restored SHA-256 精确返回 before;每个 case 的 transient 路径和 basename 三阶段不变,文件始终存在、位于文档 transient 目录且写权限位为 0。 +- 19 条非 `PropOutput` 记录的状态序列为 `Valid -> Touched -> Valid -> Touched -> Valid`;8 条 `ReadOnly` 仍保持原 editor mode。`DrawSVGTemplate.PageResult` 在两次替换中都保持 `Up-to-date / Valid`,两次 recompute 均返回 false,锁定 `PropOutput` touch 抑制。 +- 20/20 对象集全程不变;`Sketcher::SketchObjectSF` 的唯一 Shape 边界在 before/edited/restored 都为 Null Shape 且 0 edges/faces/vertices,其他宿主保持 Shape 不适用。 +- `probe/check:freecad-property-fileincluded-mutation`、A/B/C focused checker 和 `git diff --check` 均通过;D 阶段机器证据已追加到连续账本。 + +### `PROP-app-propertyfileincluded-E` + +#### 执行过程与完成证据 + +- 将 `App::PropertyFileIncluded` 接入 typed `IncludedFileValue` 与可编辑 Facade;可移植值只保存安全归档基名、SHA-256 资源标识、字节数和 MIME,权威字节始终由项目资源库持有,没有暴露宿主 transient 路径。 +- 新增专用 `setIncludedFile` 边界:先深拷贝并存储 `Uint8Array`,再提交结构化属性;同名资源按 FreeCAD 规则分配 `name1.ext`,失败时释放新资源,目录穿越、分隔符、控制字符、非 SHA-256 标识和过大 payload 均在事件及版本变更前 fail-closed。 +- FCStd writer 使用原生 `` 并将字节写为独立 ZIP entry;inspector 对缺失资源、非安全基名和冲突字节拒绝打开,`extractIncludedFiles/storeIncludedFiles` 在导入后重建项目资源标识,空值保持 ``。 +- 生产 `PropertyEditor` 新增文件选择器,读取浏览器 `File` 字节后仅通过 Facade 提交;20 条原生宿主的 XML、资源字节、解析、提取、存储、空值和缺失资源边界已由 focused 测试锁定。 +- `test:freecad-property-fileincluded-facade`、A-D focused checker 和 `git diff --check` 均通过;E 阶段证据已加入连续账本。 + +### `PROP-app-propertyfileincluded-F` + +#### 执行过程与完成证据 + +- 新增独立 PropertyFileIncluded 事务夹具,从空资源值经公开 `setIncludedFile` 提交 5 bytes 二进制负载;唯一 transaction ID 下仅产生 `property.before-change -> property.changed -> transaction.committed`,版本 `1 -> 2`、dirty 与 touched 状态正确。 +- 调用方 `Uint8Array` 在提交后变异不会污染已存字节;undo 精确恢复 null/版本 1,redo 恢复结构化资源值/版本 2,且权威字节在两侧都可读,没有将历史状态与资源生命周期割裂。 +- 预检 stale、预取消和 Immutable 写入全部在资源存储前拒绝;资源写入后取消和 MIME 校验失败均回收已存 hash,文档、事务事件和历史栈零污染。 +- 两个同版本并发提交稳定地只允许一个胜者进入版本 3,败者以 stale 拒绝并立即删除其资源;胜者资源仍能完成第二轮 undo/redo。PropertyFileIncluded 事务全程不分配几何 Shape。 +- 首次完整 Facade 回归发现 E 阶段将只读 FCStd 的 GuiDocument 和 resource 覆盖错误合并为泛化诊断;已恢复 GuiDocument 既有精确错误并为 opaque/resource 保留独立 fail-closed 分支。`test:freecad-property-fileincluded-transaction`、E 阶段 focused test、A-D checker、完整 `test:facade` 199 项、生产 `build`、JSON 校验与 `git diff --check` 均通过。 + +### `PROP-app-propertyfileincluded-G` + +#### 执行过程与完成证据 + +- 新增受限 `rewriteFcstdIncludedFileProperty` 并经公开 Facade `project.fcstd.rewriteIncludedFile` 暴露;目标与可选旧值均先按 SHA-256 从项目资源库取回权威字节,再校验唯一对象/属性/`FileIncluded` payload、字节数和逐字节旧值前置条件。 +- 直改严格保持原生 `file="payload.bin"` 归档身份,只替换对应 ZIP entry 并标记宿主 touched;改名、缺失项目资源、元数据/字节不匹配和旧值不符全部 fail-closed。写后重新 inspect 闭环核对路径、字节数和内容摘要。 +- 真实 FreeCAD 1.1.1 链路创建 `App::DocumentObjectFileIncluded.File`,内嵌 13 bytes `payload.bin`;Web 经项目资源身份替换为 20 bytes 二进制,FreeCAD 随后 reopen/recompute/saveAs/reopen 的 transient 文件 SHA-256 两次均精确为 `09f4e485...`。 +- 原生重开和再保存后的资源基名始终为 `payload.bin`,字节始终为 20,文件位于 Document transient 目录且写权限位为 0;对象集、TypeId、property status/editor mode、Up-to-date/Valid 和无 Shape 边界稳定。 +- 该最小原生归档精确只含 `Document.xml + payload.bin`,所以排除目标后 opaque 条目数锁定为 0,而非伪造“至少 1 条”。`probe/check:freecad-property-fileincluded-roundtrip`、E/F focused test、完整 `test:facade` 199 项、生产 `build`、JSON 校验与 `git diff --check` 均通过,`zeroUnknownDrift=true`。 + +### `PROP-app-propertyfileincluded-H` + +#### 执行过程与完成证据 + +- 新增独立真实 Chrome `PropertyFileIncluded` harness,直接挂载生产 `PropertyEditor` 和 `createProductionFacade`;通过 `DataTransfer + File` 驱动真实 `` change 事件,没有从 DOM 外直改文档。 +- UI 将空 `App::DocumentObjectFileIncluded.File` 提交为 16 bytes `chrome-resource.bin`;输入类型/标签为 `file / Embedded file`,显示从 `Empty` 变为目标归档名,成功通知只出现一次,文档版本 `1 -> 2`、dirty 和 touched 正确。 +- SQLite OPFS save/load、version 2 checkpoint 和 recovery integrity `ok` 均恢复完整 `IncludedFileValue` 与 `App::PropertyFileIncluded` TypeId;浏览器内 FCStd 检查确认 `FileIncluded file="chrome-resource.bin"`、16 bytes 内嵌 entry 与目标字节逐项一致。 +- 文档资源按 SHA-256 回读为同一 16 bytes;独立 48 bytes 资源的 put/get/release 后读取为 null,OPFS marker 已创建并删除。Worker 请求覆盖 initialize/save/load/checkpoint/recovery/resource/dispose,最终 persistence Worker 已 terminate。 +- 最终 `shapeCount=0`、`kernelReferenceCount=0`;`test/check:chrome-property-fileincluded`、E/F focused test、G checker、生产 `build`、JSON 校验与 `git diff --check` 均通过,H 阶段机器证据已加入连续账本。