Skip to content

OCCT + FreeCAD Runtime Architecture Audit

Operational source: D:\02_Code\45_merged_macos_colabui_dfmanim\docs\contracts\occt-freecad-runtime-architecture-audit.md

Scope: curated mirror of the current mixed FreeCAD + OCCT runtime audit. A no-FreeCAD architecture is intentionally left for a separate branch.

This audit documents the current mixed CAD runtime architecture in this repo. It covers the implemented FreeCAD + OCCT behavior only. A no-FreeCAD architecture is intentionally out of scope here and should be handled in a separate branch.

Code references are relative to the repository root.

Kernel Split Summary

Area Current runtime Primary code/artifact What it does If FreeCAD is removed today Evidence
Browser preview render FreeCAD + trimesh server/cad_service.py, preview.glb Loads CAD through Part.read, tessellates FreeCAD shapes, exports a GLB preview for Three.js Upload preview breaks until an OCCT GLB preview exporter replaces it server/cad_service.py:93-137, server/cad_service.py:287-369, web/src/components/ModelViewer.tsx:1945-1974
Canonical/selectable scene OCCT/pythonOCC server/canonical_scene_service.py, scene.json, scene_components/*.json Loads STEP through OCCT, resolves components, builds face/edge inventories, feature refs, face batches, edge batches Mostly survives conceptually, but worker runtime setup must stop depending on FreeCAD Python discovery server/canonical_scene_service.py:247-300, server/canonical_scene_service.py:523-622, server/canonical_scene_service.py:746-781, server/canonical_scene_warmup.py:376-383
DFM light/deep geometry facts OCCT/pythonOCC server/part_facts.py, server/cnc_geometry_occ.py, Part Facts JSON Extracts topology, face inventory, holes, pockets, CNC corners, internal radii, then maps facts to DFM inputs STEP DFM can survive if pythonOCC is packaged independently; IGES/DXF still need separate loader/bridge work server/part_facts.py:1473-1603, server/part_facts.py:1847-2026, server/cnc_geometry_occ.py:4018-4103, server/dfm_part_facts_bridge.py:67-202
OCC orthographic views OCCT/pythonOCC server/cad_service_occ.py, occ_views/*.png Uses OCCT HLR to generate projection PNGs Survives if pythonOCC runtime is available server/cad_service_occ.py:45-88, server/cad_service_occ.py:216-243, server/main.py:4331-4355
FreeCAD Shape2D/isometric views FreeCAD Draft + FreeCAD mesh projection server/cad_service.py, shape2d, isometric_shape2d, isometric_matplotlib Generates drafting-style or projected 2D view artifacts Breaks unless ported to OCCT HLR or retired server/cad_service.py:413-550, server/main.py:4072-4088, server/main.py:4391-4447
Candidate/remediation geometry FreeCAD server/dfm_candidate_geometry_worker.py, candidate STEP Applies simple booleans, cylinders, fillets, fuses, and STEP export for candidate sessions Breaks until ported to raw OCCT modeling/export APIs server/dfm_candidate_geometry_worker.py:62-100, server/dfm_candidate_geometry_worker.py:176-183, server/dfm_candidate_geometry_worker.py:230-237, server/dfm_candidate_geometry_worker.py:273, server/dfm_candidate_geometry_worker.py:324-325
Collaboration comments and pins Browser + backend storage; geometry source can be FreeCAD or OCCT web/src/components/ModelViewer.tsx, web/src/components/CollaborationWorkspace.tsx, server/review_store.py Emits pin payloads from viewer, posts tickets/reviews, stores pin data Can keep working if preview/canonical coordinates and component IDs remain stable web/src/components/ModelViewer.tsx:566-609, web/src/components/ModelViewer.tsx:1953-1985, web/src/components/CollaborationWorkspace.tsx:1262-1299, server/review_store.py:18-35, server/review_store.py:69-95
Runtime discovery FreeCAD-oriented server/freecad_setup.py Finds FreeCAD libraries, FreeCAD Python, and optionally probes OCC in that runtime Must be replaced by an OCCT/pythonOCC runtime setup before FreeCAD can be retired server/freecad_setup.py:119-136, server/freecad_setup.py:173-209, server/freecad_setup.py:212-239

Findings Validation

Finding Status Evidence Practical consequence
Fast rendering and fast feature detection are too tightly coupled Partially confirmed Preview upload is separate/backgrounded: server/main.py:3976-4045; docs say preview is ready before canonical: docs/contracts/canonical_scene_pipeline.md:41-42. But canonical component detail couples face inventory, edge inventory, detectors, feature refs, face batches, and edge batches: server/canonical_scene_service.py:523-622. Users can get a first GLB preview, but selectable/canonical geometry can still wait on semantic extraction work.
Intended architecture is preview first, canonical second Confirmed Contract says this directly: docs/contracts/canonical_scene_pipeline.md:3-5, docs/contracts/canonical_scene_pipeline.md:121-136. UI renders preview and overlays canonical when ready: web/src/components/ModelViewer.tsx:1333-1442, web/src/components/ModelViewer.tsx:1945-2007. This is the right large-model direction; keep it.
Canonical component detail does too much in one pass Confirmed _build_component_scene builds faces, edges, detectors, feature refs, face batches, and edge batches in one call. One slow exact step delays all canonical usability for that component. Evidence: server/canonical_scene_service.py:523-622.
Exact edge extraction is a hotspot Partially confirmed Edge inventory samples/measures edges: server/canonical_scene_service.py:693-744, server/canonical_scene_service.py:1057-1084; face batches remesh component geometry: server/canonical_scene_service.py:746-760. "Major hotspot" is inferred because canonical per-stage timings are not recorded. Edge-heavy parts likely make selectable detail feel stuck. Add timing before optimizing blindly.
Canonical warmup is serial for requested components Confirmed Worker loops requested components one-by-one. A selected component can wait behind earlier requested components in the same warmup request. Evidence: server/canonical_scene_warmup.py:490-531.
Deep Part Facts budgets exist but are not true stop conditions Confirmed Budgets/statuses exist: server/dfm_scanner_plan.py:46-88; Part Facts only records overtime: server/part_facts.py:1220-1279; warmup calls extraction directly without timeout enforcement: server/part_facts_warmup.py:490-502. Deep scans can continue long after the UI thinks they exceeded budget.
Large-part failure likely combines heavy canonical detail and deep Part Facts Partially confirmed Canonical heavy path: server/canonical_scene_service.py:523-622; deep scanners include exact inventory, CNC corner, internal radii: server/dfm_scanner_plan.py:236-241, server/dfm_scanner_plan.py:302-308; extraction paths: server/part_facts.py:1847-2026. Causality is inferred. Large parts have two independent expensive background workloads competing for responsiveness.
Viewer and DFM are sibling flows over same geometry/component identity Confirmed Upload returns preview/source/components plus optional scene URL: server/main.py:4026-4049; viewer uses preview/canonical: web/src/components/ModelViewer.tsx:1945-2007; DFM resolves Part Facts from model/component: server/main.py:1368-1447. Viewer fixes do not automatically fix DFM, and DFM should not depend on canonical scene payloads.
DFM consumes Part Facts/extracted facts, not canonical scene payloads Confirmed Main builds extracted_part_facts from Part Facts: server/main.py:1420-1447; DFM job does the same: server/dfm_review_pipeline.py:561-625, server/dfm_review_pipeline.py:690-713; bridge maps Part Facts to extracted facts: server/dfm_part_facts_bridge.py:67-202. DFM reliability work belongs in Part Facts/scanners/planning, not canonical scene rendering.
CoLab using HOOPS is unverified Not confirmed Repo search found no HOOPS, Tech Soft, or Communicator references. Rendering evidence points to FreeCAD/trimesh/GLB, OCCT analysis, and Three.js. Treat HOOPS as external/product inference only, not a code-backed fact. Evidence: server/cad_service.py:287-369, web/src/components/ModelViewer.tsx:1945-2007.

Runtime Audit Table

User action Format Pipeline stage Primary file/artifact Key code path Purpose Dependencies Current bottleneck or limitation Recommended improvement Likely code changes UX impact If removed Evidence
User imports a STEP file STEP/STP Upload, format gate, preview build source .step/.stp, preview.glb, metadata.json upload_model -> model_store.create -> cad_service.import_model Create model, preview, components, then prewarm Part Facts/canonical FreeCAD Part.read, FreeCAD tessellation, trimesh Preview generation is synchronous before response Keep preview/exact extraction decoupled; add OCCT preview parity before retiring FreeCAD server/main.py, server/cad_service.py, future OCCT preview service First usable model depends on GLB export time No upload preview/components server/main.py:3963-4050, server/cad_service.py:287-369, server/model_store.py:147-181
User imports IGS/IGES IGS/IGES Preview/comment-only import policy source .igs/.iges, maybe preview.glb format policy allows viewer/comments, blocks canonical/DFM Let users view/comment non-STEP CAD FreeCAD import support today; explicit bridge needed for exact path Exact path still uses STEP-centric loaders; no bridge cache Add format-aware loader branches and explicit IGES -> STEP bridge cache cad_import_formats.py, preview loader, canonical/Part Facts loaders, model store bridge artifact Users can inspect/comment IGES, but DFM/canonical remain blocked unless bridged IGES becomes unsupported or misleading server/cad_import_formats.py:78-93, server/main.py:4021-4049, docs/validation/cad-format-import-eval.md:42-44, docs/validation/cad-format-import-eval.md:100-107
User imports DXF DXF Format gate none unknown extension fallback, HTTP 415 Block unsupported CAD detect_cad_format No DXF policy, no loader branch Add DXF policy only if product wants 2D/vector preview/comment path server/cad_import_formats.py, upload validation, possible 2D viewer User gets unsupported-format failure today If fallback removed, DXF behavior becomes accidental server/cad_import_formats.py:199-207, server/main.py:3968-3970
User sees first preview render STEP/STP; IGES if importer succeeds Runtime preview rendering preview.glb frontend loads preview artifact and renders ModelContents Fast visual feedback GLB URL, Three.js scene Preview waits for server GLB generation; exact canonical overlay is separate Preserve browser viewer; replace only the backend preview generator when migrating off FreeCAD server/cad_service.py, new OCCT preview exporter, ModelViewer.tsx unchanged if GLB contract holds Faster perceived load if preview remains cheap No initial visual model server/main.py:4091-4100, web/src/components/ModelViewer.tsx:1127-1142, web/src/components/ModelViewer.tsx:1945-1974
User waits for canonical/selectable geometry STEP/STP only Manifest and component detail warmup scene.json, scene_status.json, scene_components/*.json canonical warmup worker -> manifest -> component detail Topology identity, selectable faces/edges, feature refs OCCT STEP source, analyzer, cache files Component detail bundles exact semantics and render batches Stage as preview mesh -> selectable faces -> feature hints -> exact specialty metrics Split _build_component_scene; add detail levels/status fields Selection appears earlier No face/edge selection or DFM anchors docs/contracts/canonical_scene_pipeline.md:87-150, server/canonical_scene_warmup.py:429-573, server/canonical_scene_service.py:523-622
User selects a component STEP/STP canonical; preview all supported viewer formats Focus and selected-component warmup component node name, canonical component JSON frontend queues warmup for focused component Make selected component selectable/canonical first component identity from import Requested components in one worker are serial Prioritize selected-component-first warmup, supersede stale queues canonical_scene_warmup.py, ModelViewer.tsx warmup request ordering Less waiting after click Component selection becomes preview-only web/src/components/ModelViewer.tsx:1578-1602, server/canonical_scene_warmup.py:490-531
User selects a face/edge STEP/STP canonical only Selection resolution canonical component scene /scene/resolve-selection Map click/face/edge to topology identity/features ready component scene Original model path returns 409 if detail missing Return partial resolution when selectable faces are ready; defer exact edge facts server/main.py, canonical_scene_service.py Earlier selection feedback Feature anchoring loses topology identity server/main.py:4228-4284, server/canonical_scene_service.py:451-513
User opens Part Facts STEP/STP DFM-capable models Cache read/status/warmup Part Facts JSON/status frontend GET facts/status, may enqueue warmup Show measured/inferred geometry facts PartFactsService, OCCT geometry analyzer Initial GET only returns cache; background warmup is light Keep light default; expose clear deep refresh when needed ModelViewer.tsx, main.py, part_facts_warmup.py Facts panel appears progressively DFM loses extracted fact source web/src/components/ModelViewer.tsx:1662-1805, server/main.py:2765-2818
User refreshes Part Facts STEP/STP Forced warmup Part Facts request/status/cache POST refresh -> enqueue Recompute facts background subprocess Refresh always enqueues geometry_scan_depth="light" from endpoint helper Add explicit depth param; default large parts to topology_light server/main.py, Part Facts API contract, UI button Users understand light vs deep cost Stale facts remain server/main.py:876-889, server/main.py:2804-2818, web/src/components/ModelViewer.tsx:1705-1724
User runs DFM light STEP/STP DFM job, planning, Part Facts light DFM job status, Part Facts, review payload sidebar job POST -> run_job -> Part Facts bridge -> rules Generate manufacturability review scanner plan, Part Facts cache, profile Light still may run nontrivial topology/feature inventory Cost heuristic: face/edge/component complexity, not face-count only dfm_scanner_plan.py, part_facts.py, dfm_review_pipeline.py More reliable first-pass DFM No automated review web/src/components/DfmSidebar.tsx:2232-2298, server/dfm_review_pipeline.py:454-771, server/dfm_scanner_plan.py:269-330
User runs DFM deep STEP/STP Exact extraction + DFM rules exact Part Facts, extracted facts deep context requests exact inventory/CNC/internal radii Richer evidence for corners/radii/plastics OCCT analyzers and caches Budgets are metadata; exact scans can overrun Make budgets real timeout/overtime controls; reuse one exact face inventory part_facts.py, part_facts_warmup.py, cnc_geometry_occ.py Deep review finishes or degrades predictably Deep DFM becomes unavailable web/src/components/DfmSidebar.tsx:2511-2529, server/part_facts.py:1473-1603, server/part_facts.py:1847-2026, server/dfm_scanner_plan.py:72-88
User comments or anchors geometry STEP/STP, IGES viewer/comment; mesh viewer/comment Pin/comment overlay reviews.json, tickets/design reviews viewer emits pin -> workspace POSTs ticket -> store persists pin Collaboration comments anchored to model coordinates/topology when available preview/canonical hit payload, auth/share checks Topology anchors depend on format/canonical readiness; mesh anchors are separate capability Keep format-aware anchor capability visible in UI; preserve coordinate and component contracts in any OCCT preview migration cad_import_formats.py, viewer pin payloads, review store Comments work even when DFM is unavailable Collaboration review loses spatial context server/cad_import_formats.py:21-59, web/src/components/ModelViewer.tsx:566-609, web/src/components/CollaborationWorkspace.tsx:1262-1299, server/review_store.py:69-95
User previews DFM candidate/remediation STEP/STP Candidate session/viewer path candidate scene/session sidebar creates candidate session; worker may materialize candidate STEP Compare proposed fix geometry FreeCAD candidate mutation worker today; viewer scene path Candidate mutation is FreeCAD-dependent Port candidate mutation separately or preserve FreeCAD until candidate branch is replaced dfm_candidate_geometry.py, dfm_candidate_geometry_worker.py, candidate scene endpoints Candidate previews fail if FreeCAD disappears too early Remediation UX disappears web/src/components/DfmSidebar.tsx:2448-2496, server/dfm_candidate_geometry.py:77-109, server/dfm_candidate_geometry_worker.py:62-100

Improvement Matrix

Improvement Applies to which user actions/stages Core files/services touched Why this helps Expected UX gain Technical risk / downside Recommended implementation approach Priority Evidence
Stage canonical detail as preview mesh -> selectable faces -> feature hints -> exact specialty metrics canonical wait, component select, face/edge select canonical_scene_service.py, canonical_scene_warmup.py, ModelViewer.tsx Removes feature/edge extraction from the critical selectable path Faster clickable model Requires cache/version contract changes Add detail_level artifacts and progressive status per component P0 server/canonical_scene_service.py:523-622, docs/contracts/canonical_scene_pipeline.md:121-150
Defer exact edge extraction canonical detail, selection canonical_scene_service.py Edge sampling/radius/bounds work is expensive and not always needed immediately Earlier face selection; less blocked warmup Edge-specific anchors may arrive later Build face batches first; compute edge inventory on demand or after idle P0 server/canonical_scene_service.py:693-744, server/canonical_scene_service.py:1057-1084
Prioritize selected-component-first warmup component select, canonical wait canonical_scene_warmup.py, ModelViewer.tsx Current worker serializes requested components Selected component becomes ready first Queue coordination complexity Supersede stale requests; process focused component before prefetch list P1 server/canonical_scene_warmup.py:490-531, web/src/components/ModelViewer.tsx:1578-1602
Make scanner budgets real timeout/overtime controls Part Facts refresh, DFM deep dfm_scanner_plan.py, part_facts.py, part_facts_warmup.py Budgets currently describe work but do not stop it DFM returns degraded results instead of hanging OCC calls may not be interruptible in-process Run heavy scanners in cancellable subprocesses or checkpointed loops; mark partial facts P0 server/dfm_scanner_plan.py:72-88, server/part_facts.py:1220-1279
Default large parts to topology_light unless exact scans are required Part Facts, DFM light/deep dfm_scanner_plan.py, part_facts.py, DfmSidebar.tsx Avoids accidental exact scans on costly parts More reliable first review Some findings may be lower confidence Use process/profile/evidence needs plus complexity heuristic P0 server/dfm_scanner_plan.py:211-250, server/dfm_scanner_plan.py:269-330, web/src/components/DfmSidebar.tsx:2511-2529
Reuse one exact face inventory across downstream detectors canonical, Part Facts deep, DFM cnc_geometry_occ.py, part_facts.py, possibly canonical cache Face inventory is rebuilt for exact detectors Less duplicated OCCT traversal Cache invalidation/versioning Promote inventory artifact with profile/depth/version keys P1 server/cnc_geometry_occ.py:4180-4360, server/cnc_geometry_occ.py:4364-4481, server/part_facts.py:1495-1547
Replace face-count-only fallback with cost heuristic canonical large components, DFM scan planning canonical_scene_service.py, dfm_scanner_plan.py, part_facts.py MAX_DETAILED_FACE_COUNT ignores edge count, curve complexity, and triangles Better large-part behavior Needs telemetry to tune Compute cost from face count, edge records, triangle count, bbox/features P1 server/canonical_scene_service.py:28, server/canonical_scene_service.py:525-533, server/cad_service.py:325-331
Add format-aware source/loader branches STEP, IGES, mesh, future DXF cad_import_formats.py, cad_service.py, cad_service_occ.py, canonical_scene_service.py, part_facts.py Current exact services are STEP-centric Fewer confusing format failures More code paths to validate Introduce loader interface: preview loader, exact STEP loader, bridge loader P1 server/cad_import_formats.py:21-59, server/cad_service_occ.py:61-69, docs/validation/cad-format-import-eval.md:100-107
Add explicit IGES -> STEP bridge caching IGES canonical/DFM model store, bridge service, canonical/Part Facts services IGES preview can be separate from exact analysis Makes IGES DFM possible without pretending native support Conversion quality and cache storage Store bridged STEP artifact with checksum/source format metadata P2 server/cad_import_formats.py:78-93, docs/validation/cad-format-import-eval.md:42-44, docs/validation/cad-format-import-eval.md:100-107
Keep preview render and exact semantic extraction decoupled upload, preview, canonical, DFM main.py, ModelViewer.tsx, docs This is already intended and partly implemented Preserves first-render speed Regression risk if new features call exact paths during upload Add tests/contract checks that upload success only requires preview P0 docs/contracts/canonical_scene_pipeline.md:3-5, docs/contracts/canonical_scene_pipeline.md:41-42, server/main.py:4021-4024
Replace FreeCAD preview with OCCT preview only after parity checks upload, preview, comments, canonical overlay new OCCT preview service, cad_service.py, model_store.py, ModelViewer.tsx Retires the biggest FreeCAD dependency without changing the web collaboration shell Cleaner runtime and consistent geometry identity Component order, meshing, units, and GLB output can drift Add OCCT preview behind a flag; compare GLB nonblank, component count/order, triangle counts, pins, selected component P1 FreeCAD preview: server/cad_service.py:287-369; OCCT canonical mesh proof: server/canonical_scene_service.py:746-781
Keep candidate geometry as a separate migration track DFM candidate/remediation dfm_candidate_geometry.py, dfm_candidate_geometry_worker.py Candidate mutation is the most FreeCAD-specific path Avoids blocking preview/DFM cleanup on remediation port Temporary mixed runtime remains Port booleans/fillets/STEP export to OCCT only in the no-FreeCAD branch P2 server/dfm_candidate_geometry_worker.py:62-100, server/dfm_candidate_geometry_worker.py:176-183, server/dfm_candidate_geometry_worker.py:273

FreeCAD Retirement Assessment

Question Current answer Evidence Risk
Can the app still render if FreeCAD is removed? Not yet. The main browser preview GLB is FreeCAD-backed today. server/cad_service.py:93-137, server/cad_service.py:287-369 High until an OCCT preview exporter produces the same ImportResult and preview.glb contract.
Can DFM light/deep still run? Yes for STEP in principle, because DFM facts are already OCCT-backed. Runtime setup still needs cleanup. server/part_facts.py:1473-1603, server/part_facts.py:1847-2026, server/cnc_geometry_occ.py:4018-4103 Medium. Packaging/runtime risk is larger than algorithmic risk for STEP.
Can collaboration still work? Yes, if preview/canonical coordinates, component node names, and anchor payloads stay stable. web/src/components/ModelViewer.tsx:566-609, web/src/components/CollaborationWorkspace.tsx:1262-1299, server/review_store.py:69-95 Medium. Identity drift would make old pins or selected components point to the wrong geometry.
Can IGES become DFM-capable just by using OCCT? Not automatically. The current exact loaders are STEP-centric. server/cad_import_formats.py:78-93, server/cnc_geometry_occ.py:4098-4103 Medium. Needs IGESControl_Reader support or bridge caching.
Can DXF be supported by retiring FreeCAD? No. DXF is currently unsupported and has no loader policy. server/cad_import_formats.py:199-207, server/main.py:3968-3970 Product decision plus separate 2D/vector implementation.

Top 5 Highest-ROI Changes

  1. Make scanner budgets real and degrade deep Part Facts gracefully. This is the highest DFM reliability win. It is an architectural change because heavy OCCT work may need subprocess cancellation or checkpointing.

  2. Stage canonical component detail and defer exact edge extraction. This is the highest viewer responsiveness win for large models. It is architectural, but the boundary is already documented.

  3. Add selected-component-first canonical warmup. This is a relatively safe refactor: change queue ordering/status behavior before redesigning all canonical artifacts.

  4. Default large parts to topology_light using a real cost heuristic. This is a safe-to-moderate refactor if introduced as planning policy first, then tuned with telemetry.

  5. Add an OCCT preview service behind a flag before removing FreeCAD. This is the key bridge from the current mixed architecture to a future no-FreeCAD branch. It is architectural because component identity, GLB output, and collaboration pins must remain stable.

Sources

  • Repo-local audit: D:\02_Code\45_merged_macos_colabui_dfmanim\docs\contracts\occt-freecad-runtime-architecture-audit.md
  • Runtime repo commit: 1dad556 (docs: add OCCT FreeCAD runtime architecture audit)
  • Active runtime repo: D:\02_Code\45_merged_macos_colabui_dfmanim