# Native OCCT history provider This provider is compiled from the cached OCCT checkout selected by `OCCT_SOURCE_DIR` and exposes native Boolean and PartDesign history APIs through Emscripten Embind. The provider keeps `TopoDS_Shape` handles and history queries in one WASM instance. A handle from `@bitbybit-dev/occt` must never be passed directly to this module because WebAssembly linear memories are independent. Build and verify it with the project wrapper: ```bash ./npmw run build:occt-history ./npmw run test:occt-history ``` The build also publishes the JS/WASM pair to `public/native/occt-history/`, which is the default URL used by `NativeOcctHistoryWorkerProvider`. The generated artifacts remain ignored; a clean checkout must run the build after restoring the pinned OCCT source and Emscripten toolchain. ## FreeCAD private naming build boundary The default build is intentionally OCCT-only. It does not export `freecadNamingAbiVersion`, `freecadNamingCapabilitiesJson`, or `freecadNamingEvidenceJson`, and it must not be described as exact FreeCAD naming support. A separate fail-closed build lane is available for an actual FreeCAD WASM SDK: ```bash FREECAD_WASM_SDK_DIR=/absolute/path/to/sdk ./npmw run check:freecad-naming-sdk FREECAD_WASM_SDK_DIR=/absolute/path/to/sdk ./npmw run build:freecad-naming-worker ./npmw run check:occt-history-artifact ``` The SDK layout is defined by `freecad-wasm-sdk-manifest.example.json`. The checker requires the locked FreeCAD 1.1.1 commit, Emscripten 3.1.69, wasm Qt and Python targets, private App headers, hashed static FreeCAD/Part/Qt/Python libraries, and a hashed bridge source exporting all three callbacks. If any input is absent, `build:freecad-naming-worker` exits before rebuilding or publishing the OCCT-only artifact. A successful artifact probe still only establishes ABI linkage; exact promotion additionally requires valid MappedNameRef, StringHasher, ElementMap2, stage history, and round-trip evidence. The repository also carries a prerequisite-only source probe. It builds QtBase 6.8.2 `Qt6Core` for wasm, then compiles the locked FreeCAD `IndexedName.cpp`, `MappedName.cpp`, `StringHasher.cpp`, `MappedElement.cpp`, `ElementNamingUtils.cpp`, `ElementMap.cpp`, and `Base/Handle.cpp` sources without exporting the production naming callbacks: ```bash ./npmw run build:qt6-wasm-core ./npmw run build:freecad-naming-source-probe ./npmw run test:freecad-naming-source-probe ./npmw run check:freecad-naming-sdk-readiness ./npmw run check:freecad-private-naming-boundary ``` Passing this probe establishes that the private source subset and toolchain are cross-compilable. Its runtime test covers mapped-name parsing, StringHasher deduplication, SHA-1 threshold handling, indexed mapped-name references, ElementMap encoding/lookup/history/save/restore, and stable mapped-element ordering. It also feeds native MappedNameRef, StringHasher, and ElementMap2 resources through the strict Web ABI validator using deliberately separate `freecadNamingCandidate*` callback names. The seven locked FreeCAD source units are first compiled into the isolated `libFreeCADPrivateNamingProbe.a` archive. The smoke test checks that it contains exactly seven wasm object members before linking the runnable probe. This archive remains host-adapter-bound and is not a substitute for FreeCADBase or FreeCADApp. Persistence, Python wrappers, type-system, logging, and Application/Document lifecycle interfaces remain standalone host adapters. FreeCADApp/Part/Python static libraries, real Application/Document integration, OCCT builder context, and the production bridge are not linked. The candidate callbacks are never published to the production Worker. The probe therefore does not close EX-TSN-02 and does not change `systemExact=false`. `check:freecad-naming-sdk-readiness` audits the pre-production SDK plan without publishing anything. It parses every present `.a` archive and rejects native ELF members; the current local resource set verifies QtCore plus its bundled Pcre2/Zlib wasm dependencies, but still lacks FreeCADBase, FreeCADApp, Part, Python, and the production bridge. `generate:freecad-naming-sdk-manifest` is fail-closed and writes no manifest until all inputs are present. The complete SDK checker applies the same wasm-archive rule, so an x86 static library cannot satisfy the manifest by hash alone. The versioned JSON request carries document `objectId`, stable positive `objectTag`, prior naming evidence, result object identity, result tag, stage DAG, STEP/BRep, and OCCT Generated/Modified/Deleted history. No Web fallback is allowed to synthesize a FreeCAD private token. The exported `booleanHistory(object, tool, operation)` function supports `fuse`, `cut`, and `common`. It returns the native result shape, per-input `modified`/`generated`/`deleted` records, a validity/topology/quality summary, and capability flags. `prismHistory(profile, dx, dy, dz)` adds the first PartDesign Pad contract: profile vertices can generate edges and profile edges can generate faces, while the profile face is preserved as a result face. `booleanProbe` and `booleanResult` are intentionally smaller operations for Worker stress/ownership gates; callers must delete every returned Embind shape handle. Primitive constructors cover positioned boxes, cylinders, spheres, cones and a test rectangle Face. The provider also exports `shapeToStep(shape)`, `booleanHistoryFromStep(objectStep, toolStep, operation)` and `prismHistoryFromStep(profileStep, dx, dy, dz)`. The STEP functions are the cross-WASM transport: Bitbybit exports STEP text, the native provider reads it with `STEPControl_Reader`, returns the result again as `resultStep`, and no linear-memory pointer crosses the boundary. Pad history currently requires a valid planar Face profile; solids are rejected by OCCT rather than silently treated as sketches. `loftHistoryFromStep(firstSectionStep, secondSectionStep, ruled)` adds a verified two-section solid loft using `BRepOffsetAPI_ThruSections`. It records generated edges/faces for both source profiles; more than two sections, closed lofts, and PartDesign base fusion/cut stay on the signature history path until their multi-source contract is implemented. `pipeHistoryFromStep(profileStep, spineStep)` adds a verified single-edge open-spine solid sweep using `BRepOffsetAPI_MakePipe`. It records profile vertex/edge generation, profile end caps, and spine edge/endpoint provenance; multi-edge spines, Frenet/transition modes, and hollow profiles remain explicit unsupported cases. `filletHistoryFromStep(baseStep, radius)` enables the first native dress-up slice: OCCT `BRepFilletAPI_MakeFillet` applies a fixed radius to all source edges and returns per-edge/face `Modified`, `Generated`, and `Deleted` relations with result-kind mapping. The native build enables `TKFillet` and its `TKBool` dependency. `chamferHistoryFromStep(baseStep, distance)` uses the same native history collector with `BRepFilletAPI_MakeChamfer` for a symmetric, fixed-distance, all-edge chamfer. `holeHistoryFromStep(baseStep, radius, depth, px, py, pz, dx, dy, dz)` composes an OCCT cylinder and `BRepAlgoAPI_Cut` for a straight cylindrical hole with explicit position and direction, returning the Boolean source history. Thread, counterbore, countersink, and face-attached hole semantics remain outside this minimal native contract. `draftHistoryFromStep(baseStep, faceIndex, angle, direction, neutralPlane, reversed)` uses `BRepOffsetAPI_DraftAngle` from `TKOffset` for one explicitly selected source face. It returns native per-subshape history and rejects an invalid face index, zero direction, zero angle, or invalid neutral plane before publishing a result. Multi-face propagation and STEP files whose imported face orientation OCCT cannot draft remain explicit unsupported/error cases. `thicknessHistoryFromStep(baseStep, faceIndex, offset, intersectionJoin)` uses `BRepOffsetAPI_MakeThickSolid` for one explicitly removed source face and returns native offset history. Zero offsets and invalid face indexes are rejected before execution. `linearPatternHistoryFromStep(baseStep, dx, dy, dz)` creates one transformed copy and fuses it with the source, preserving both Boolean input histories. The contract intentionally covers exactly two whole-shape instances. `polarPatternHistoryFromStep(baseStep, axis, angle)` creates one rotated copy and fuses it with the source. It likewise covers exactly two whole-shape instances around an explicit finite axis. `mirroredHistoryFromStep(baseStep, planeOrigin, planeNormal)` creates one plane reflected copy and fuses it with the source. The native contract is limited to one whole-shape base, one standard document plane, and a fused result. The `multiTransformHistoryFromStep(baseStep, steps)` binding accepts two to six ordered two-instance linear, polar, or mirrored whole-shape steps. Each created instance retains its transformed Base subshape mapping; one multi-argument Fuse then aggregates every instance history back to the original Base indexes. The single-step protocol continues to reuse the individual verified bindings. The TypeScript boundary mapper is `mapNativeOcctHistoryRecords`; the reusable `createNativeOcctStepHistoryBridge` exports Bitbybit ShapeHandles to STEP and converts provider source names into document object IDs before calling `captureNativeTopologyHistory`. The direct handle API remains for calls that stay inside this single native WASM instance.