Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,19 @@ No tests exist. No linter is configured.

The full cohort graduated to v1.0 on 2026-05-07 alongside OCCT 8.0.0 GA. SemVer-stable from these floors; only bump on documented breaking changes. Pre-1.0 dep history (which API landed in which 0.x tag) lives in git log; consult it when you actually need to support an older floor, otherwise treat the v1.0 surface as the contract.

- **OCCTSwift**: `https://github.com/SecondMouseAU/OCCTSwift.git` (>= 3.0.0; xcframework built against **OCCT 8.0.1**). The B-Rep kernel: ~400+ methods for parametric CAD, the full ISO drawings stack (Sheet/TitleBlock/ProjectionSymbol/Section2D/Hatch/AutoCentermarks/CuttingPlaneLine/CosmeticThread/SurfaceFinish/GDT/DetailView/DrawingScale), `FeatureReconstructor` for `reconstruct`, the `SheetMetal` namespace for `compose-sheet-metal`, and the XCAF surfaces (`AssemblyNode.labelId`, `Document.node(at:)`) for `inspect-assembly` / `set-metadata`. **Floored at v3.0.0** (OCCTSwiftScripts#118): a correctness/consolidation major (OCCT itself stays at 8.0.1; the kernel was only rebuilt to carry two patches the v2.0.0 asset was missing), not a wrapping one. Two breaking changes, both compile errors (see `docs/SEMVER.md#v300` in the OCCTSwift repo): (1) `Selector.SubShapeType.compsolid` renamed `.compSolid`, consolidating four drifted Swift mirrors of `TopAbs_ShapeEnum` onto `ShapeType` — zero source changes needed here, since this repo already spelled it `ShapeType.compSolid` (`LoadBrep.swift`, `Pattern.swift`, `RenderPreview.swift`), the surviving spelling. (2) `Shape.bounds`/`.size`/`.center`, `Wire.bounds`, `Edge.bounds`, `Face.bounds` (and `.exactBounds`, unused here) become `Optional`: they used to fabricate `(0,0,0)-(0,0,0)` for a shape with no bounding box, indistinguishable from a genuine zero-size shape at the world origin (`Shape.boundingBox`/`boundingBoxOptimal()` already behaved correctly and are unchanged). Every `.bounds` call site in this repo now unwraps: `QueryTopology.swift`/`LoadBrep.swift`/`MeasureDeviation.swift`/`RenderPreview.swift`/`Metrics.swift` throw a named `ScriptError` on a `nil` bounding box (a real error on a loaded BREP, not a state worth papering over with `?? .zero`), and the two recipe edge-selector predicates (`recipes/01-mounting-bracket`, `recipes/03-pipe-flange`) return `false` on a `nil` bounds rather than fabricate a match. `Tests/OcctkitCommandTests/OptionalBoundsTests.swift` regression-tests the throw path directly: it constructs a genuinely void shape (the intersection of two disjoint boxes) and asserts `LoadBrepCommand.buildResponse`/`MeasureDeviationCommand.defaultDeflection` throw rather than fabricate a zero-size box. **The rest of the cohort has not yet released an OCCTSwift-3.0.0-compatible version**: OCCTSwiftTools/Mesh's latest releases (and OCCTSwiftIO's, which has no direct OCCTSwift dependency but gates via Tools) all still cap `from: "2.0.0"` (`.upToNextMajor` excludes 3.0.0), and OCCTSwiftAIS inherits the cap transitively through Tools plus has 3 of its own unfixed `.bounds` call sites (`Dimension.swift`, `AreaSelection.swift`) — confirmed by attempting a real local build against the sibling checkouts, which fails inside OCCTSwiftAIS. This repo's own fix is complete and verified (`swift build`, `swift test`, and the recipe smoke suite all pass locally against a temporarily-patched AIS sibling, reverted after verification), but neither a fresh clone/CI run nor an as-is local sibling build can resolve the graph until Tools/Mesh/IO/AIS ship their own 3.0.0 repins. Per OCCTSwiftScripts#118, this repo's release should wait for that, same situation as the 2.0.0 bump. Previously **floored at v2.0.0** (OCCTSwiftScripts#111): a correctness major (17 breaking changes to the public Swift API; see `docs/SEMVER.md#v200` in the OCCTSwift repo). Two fixes landed in this repo alongside that bump: (1) `ShapeAnalysisResult.selfIntersectionCount` was removed (#763; always `0`, never computed), so `Heal.swift`/`GraphValidate.swift` now report `hasSelfIntersection`/`selfIntersecting` as `Bool?` via the real, opt-in `Shape.analyze(selfIntersectionTimeout:)` check (`nil` = "not checked" by default, since the check is ~3000x an ordinary scan on pathological input and both verbs would run it twice), rather than the fabricated always-`0`/always-`false` the removed field silently produced. (2) AAG builds nodes from face **occurrences** (#642): `AAGNode.faceIndex` / `PocketFeature.floorFaceIndex`/`wallFaceIndices` / `detectHoles()`'s `faceIndex` / `AAGEdge.face1Index`/`face2Index` now index `Shape.orientedFaces()`, not the `Shape.faces()` `face[N]` scheme `query-topology` emits (the two agreed automatically pre-2.0.0, since `faces()` was itself occurrence-based then). `FeatureRecognize.swift` (both the `occtkit` command and the legacy standalone target), `GraphSelect.swift`, and `GraphML.swift` all cross-reference AAG output against that `face[N]` scheme and now resolve through the new `AAGNode.distinctFaceIndex` bridge; a no-op on any shape that shares no face (every single-solid part, the only kind this repo's pre-#111 tests exercised), so it only bites a multi-solid compound with a shared face, exactly the shape a caller runs `feature-recognize`/`graph-select`/`graph-ml` against to look for cross-solid structure. `Tests/OcctkitCommandTests/AAGFaceIndexTests.swift` regression-tests the fix directly against `graph-select`/`graph-ml`'s JSON output on a split-box-compound fixture. Before that, **floored at v1.17.0** (raised in d5d31e8 for the OCCTSwift#377/#380 Pass 1a duplication and bug-fix audit; also carries the `Shape.drilled` direction fix, OCCTSwift#272, which lands between 1.12.0 and 1.12.9 and corrected recipe 01's through-holes). Before that, **floored at v1.15.0**: v1.15.0 renamed the Swift wrapper class `TopologyGraph` → `BRepGraph` (OCCTSwift#335) to match the C++ package it wraps; this repo has migrated off the deprecated `TopologyGraph` typealias onto `BRepGraph` directly (OCCTSwiftScripts#78), so the floor must guarantee the `BRepGraph` symbol exists. Earlier, v1.7.0 realigned the BRepGraph wrapper to OCCT's redesigned graph model (definitions vs references/usages, persistent UIDs, controlled layers) and v1.7.1 made the derived graph reads real again: `adjacentFaces`/`faces(of:)`/`edges(of:)`/`sharedEdges`, `faceSameDomain`, `faceIsNaturalRestriction`, plus durable `UID`/`RefUID`/`ItemUID` identity. Our graph verbs (graph-validate/compact/dedup/ml, query-topology) build and run **unchanged** against it. Behaviour changes are **confined to the BRepGraph domain**: `edgeMaxContinuity`/`setEdgeRegularity` are now no-ops (use `Shape.maxContinuity` for continuity); `degenerated`/`closed`/`sameParameter`/`sameRange` setters no-op while their getters return the live derived value. The cookbook ergonomics relied on since v1.3.1, namely `Shape.circularPatternCut` (#169), orientation-normalised `Shape.sweep` + `orientedForward`/`signedVolume` (#170), `concaveEdges`/`convexEdges`/`edges(where:)` selectors (#171), are unchanged. The 2.0.0-bump-era cohort gap (OCCTSwiftIO/Tools/AIS/Mesh all still on their "repin to 1.17.0" floors, blocking remote resolution) resolved by 2026-08-10, when OCCTSwiftIO v1.7.7, OCCTSwiftTools v1.6.3, and OCCTSwiftMesh v1.7.3 each shipped their own "repin OCCTSwift to 2.0.0" release; see the v3.0.0 cohort-gap note above this paragraph for the current (unresolved as of this writing) equivalent.
- **OCCTSwift**: `https://github.com/SecondMouseAU/OCCTSwift.git` (>= 3.0.0; xcframework built against **OCCT 8.0.1**). The B-Rep kernel: ~400+ methods for parametric CAD, the full ISO drawings stack (Sheet/TitleBlock/ProjectionSymbol/Section2D/Hatch/AutoCentermarks/CuttingPlaneLine/CosmeticThread/SurfaceFinish/GDT/DetailView/DrawingScale), `FeatureReconstructor` for `reconstruct`, the `SheetMetal` namespace for `compose-sheet-metal`, and the XCAF surfaces (`AssemblyNode.labelId`, `Document.node(at:)`) for `inspect-assembly` / `set-metadata`. **Floored at v3.0.0** (OCCTSwiftScripts#118): a correctness/consolidation major (OCCT itself stays at 8.0.1; the kernel was only rebuilt to carry two patches the v2.0.0 asset was missing), not a wrapping one. Two breaking changes, both compile errors (see `docs/SEMVER.md#v300` in the OCCTSwift repo): (1) `Selector.SubShapeType.compsolid` renamed `.compSolid`, consolidating four drifted Swift mirrors of `TopAbs_ShapeEnum` onto `ShapeType` — zero source changes needed here, since this repo already spelled it `ShapeType.compSolid` (`LoadBrep.swift`, `Pattern.swift`, `RenderPreview.swift`), the surviving spelling. (2) `Shape.bounds`/`.size`/`.center`, `Wire.bounds`, `Edge.bounds`, `Face.bounds` (and `.exactBounds`, unused here) become `Optional`: they used to fabricate `(0,0,0)-(0,0,0)` for a shape with no bounding box, indistinguishable from a genuine zero-size shape at the world origin (`Shape.boundingBox`/`boundingBoxOptimal()` already behaved correctly and are unchanged). Every `.bounds` call site in this repo now unwraps: `QueryTopology.swift`/`LoadBrep.swift`/`MeasureDeviation.swift`/`RenderPreview.swift`/`Metrics.swift` throw a named `ScriptError` on a `nil` bounding box (a real error on a loaded BREP, not a state worth papering over with `?? .zero`), and the two recipe edge-selector predicates (`recipes/01-mounting-bracket`, `recipes/03-pipe-flange`) return `false` on a `nil` bounds rather than fabricate a match. `Tests/OcctkitCommandTests/OptionalBoundsTests.swift` regression-tests the throw path directly: it constructs a genuinely void shape (the intersection of two disjoint boxes) and asserts `LoadBrepCommand.buildResponse`/`MeasureDeviationCommand.defaultDeflection` throw rather than fabricate a zero-size box. The rest of the cohort (OCCTSwiftTools v1.6.4, OCCTSwiftMesh v1.7.5, OCCTSwiftIO v1.7.8,
OCCTSwiftAIS v1.3.2, the last of which also fixed its own 3 `.bounds` call sites in
`Dimension.swift`/`AreaSelection.swift`) shipped OCCTSwift-3.0.0-compatible releases the same day,
and this repo released as **v1.6.2**. That release briefly left `main`'s CI red anyway: the
checked-in `Package.resolved` was stale from before the 2.0.0 bump (`occtswift` pinned at
`1.17.0`, `occtswiftais` at `1.3.1`), and SwiftPM's resolver kept the broken `occtswiftais@1.3.1`
pin since it still satisfied every *manifest-declared* range even though its actual source didn't
compile against 3.0.0 — manifest ranges can't see real source compatibility, so a merely-stale
lockfile silently locks in a broken transitive pin the moment the cohort catches up. Fixed in a
follow-up PR by regenerating `Package.resolved` from an isolated, sibling-free copy of this repo
(forcing genuine remote resolution instead of this repo's usual local-path substitution). See the
[full decision entry](okf/decisions/occtswift-3.0.0-floor-bump-blocked-on-cohort-releases.md) for
the timeline. Previously **floored at v2.0.0** (OCCTSwiftScripts#111): a correctness major (17 breaking changes to the public Swift API; see `docs/SEMVER.md#v200` in the OCCTSwift repo). Two fixes landed in this repo alongside that bump: (1) `ShapeAnalysisResult.selfIntersectionCount` was removed (#763; always `0`, never computed), so `Heal.swift`/`GraphValidate.swift` now report `hasSelfIntersection`/`selfIntersecting` as `Bool?` via the real, opt-in `Shape.analyze(selfIntersectionTimeout:)` check (`nil` = "not checked" by default, since the check is ~3000x an ordinary scan on pathological input and both verbs would run it twice), rather than the fabricated always-`0`/always-`false` the removed field silently produced. (2) AAG builds nodes from face **occurrences** (#642): `AAGNode.faceIndex` / `PocketFeature.floorFaceIndex`/`wallFaceIndices` / `detectHoles()`'s `faceIndex` / `AAGEdge.face1Index`/`face2Index` now index `Shape.orientedFaces()`, not the `Shape.faces()` `face[N]` scheme `query-topology` emits (the two agreed automatically pre-2.0.0, since `faces()` was itself occurrence-based then). `FeatureRecognize.swift` (both the `occtkit` command and the legacy standalone target), `GraphSelect.swift`, and `GraphML.swift` all cross-reference AAG output against that `face[N]` scheme and now resolve through the new `AAGNode.distinctFaceIndex` bridge; a no-op on any shape that shares no face (every single-solid part, the only kind this repo's pre-#111 tests exercised), so it only bites a multi-solid compound with a shared face, exactly the shape a caller runs `feature-recognize`/`graph-select`/`graph-ml` against to look for cross-solid structure. `Tests/OcctkitCommandTests/AAGFaceIndexTests.swift` regression-tests the fix directly against `graph-select`/`graph-ml`'s JSON output on a split-box-compound fixture. Before that, **floored at v1.17.0** (raised in d5d31e8 for the OCCTSwift#377/#380 Pass 1a duplication and bug-fix audit; also carries the `Shape.drilled` direction fix, OCCTSwift#272, which lands between 1.12.0 and 1.12.9 and corrected recipe 01's through-holes). Before that, **floored at v1.15.0**: v1.15.0 renamed the Swift wrapper class `TopologyGraph` → `BRepGraph` (OCCTSwift#335) to match the C++ package it wraps; this repo has migrated off the deprecated `TopologyGraph` typealias onto `BRepGraph` directly (OCCTSwiftScripts#78), so the floor must guarantee the `BRepGraph` symbol exists. Earlier, v1.7.0 realigned the BRepGraph wrapper to OCCT's redesigned graph model (definitions vs references/usages, persistent UIDs, controlled layers) and v1.7.1 made the derived graph reads real again: `adjacentFaces`/`faces(of:)`/`edges(of:)`/`sharedEdges`, `faceSameDomain`, `faceIsNaturalRestriction`, plus durable `UID`/`RefUID`/`ItemUID` identity. Our graph verbs (graph-validate/compact/dedup/ml, query-topology) build and run **unchanged** against it. Behaviour changes are **confined to the BRepGraph domain**: `edgeMaxContinuity`/`setEdgeRegularity` are now no-ops (use `Shape.maxContinuity` for continuity); `degenerated`/`closed`/`sameParameter`/`sameRange` setters no-op while their getters return the live derived value. The cookbook ergonomics relied on since v1.3.1, namely `Shape.circularPatternCut` (#169), orientation-normalised `Shape.sweep` + `orientedForward`/`signedVolume` (#170), `concaveEdges`/`convexEdges`/`edges(where:)` selectors (#171), are unchanged. The 2.0.0-bump-era cohort gap (OCCTSwiftIO/Tools/AIS/Mesh all still on their "repin to 1.17.0" floors, blocking remote resolution) resolved by 2026-08-10, when OCCTSwiftIO v1.7.7, OCCTSwiftTools v1.6.3, and OCCTSwiftMesh v1.7.3 each shipped their own "repin OCCTSwift to 2.0.0" release; see the v3.0.0 cohort-gap note above this paragraph for the current (unresolved as of this writing) equivalent.
- **OCCTSwiftViewport**: `https://github.com/gsdali/OCCTSwiftViewport.git` (>= 1.0.0). Provides `OffscreenRenderer`, `CameraState`, `DisplayMode`, `ViewportBody` for `render-preview`. Graduated to v1.0.0 on 2026-05-08, one day after the rest of the cohort; floor unblocked by Tools v1.0.2 (closes #45).
- **OCCTSwiftTools**: `https://github.com/gsdali/OCCTSwiftTools.git` (>= 1.0.0; resolves to v1.0.2+ for the widened Viewport constraint). Bridge layer between the B-Rep kernel and the Metal viewport. We use `CADFileLoader.shapeToBodyAndMetadata` in `render-preview` for Shape → `ViewportBody` conversion (both input bodies and highlight sub-shapes). Lives in its own repo since Viewport v0.55.0 split.
- **OCCTSwiftAIS**: `https://github.com/gsdali/OCCTSwiftAIS.git` (>= 1.0.0). Headless-friendly subset only: `Trihedron` / `WorkPlane` / `Axis` / `PointCloud` scene objects (each emits `[ViewportBody]` via `makeBodies()`) for `render-preview`'s `--show-axes` / `--show-workplane` overlays, plus the SubShape selection vocabulary for `--highlight face[N]/edge[M]/vertex[K]`. Selection / Manipulator / SwiftUI surfaces aren't relevant to a CLI. `Dimension` overlays render via a SwiftUI Canvas inside `MetalViewportView` and so can't reach `OffscreenRenderer`, so `--annotate-dimensions` is deferred (filed as OCCTSwiftViewport#26). Note: `OCCTSwiftAIS` re-exports a `DisplayMode` enum (3 cases) that collides with `OCCTSwiftViewport.DisplayMode` (6 cases); fully-qualify in `RenderPreview.swift` as `OCCTSwiftViewport.DisplayMode`.
Expand Down
7 changes: 4 additions & 3 deletions okf/decisions/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ that need standalone rationale.
OCCTSwiftIO's latest release still caps `occtswift` below 2.0.0 transitively, so a fresh
clone cannot resolve until the cohort ships. The PR is not blocked; the release is.
Resolved 2026-08-10.
* [OCCTSwift 3.0.0 floor bump blocked on cohort releases](occtswift-3.0.0-floor-bump-blocked-on-cohort-releases.md):
same shape of blocker, but this time OCCTSwiftAIS has 3 of its own unfixed `.bounds` call
sites, so even a local sibling-checkout build fails, not just remote/CI resolution.
* [OCCTSwift 3.0.0 floor bump blocked on cohort releases, then on a stale Package.resolved](occtswift-3.0.0-floor-bump-blocked-on-cohort-releases.md):
same shape of cohort blocker as 2.0.0, plus a second-order trap once the cohort caught up — a
pre-2.0.0-era `Package.resolved` let SwiftPM's resolver keep a manifest-compatible but
source-broken `occtswiftais` pin. Released as v1.6.2, `main` fixed green in a follow-up PR.
Loading
Loading