feat(mcp): STEP import keeps B-rep instead of baking to mesh - #808
Open
ecto wants to merge 4 commits into
Open
Conversation
import_step tessellated every body on the way in, so an imported part arrived as a triangle soup: no analytic faces, booleans and fillets degraded to mesh operations, and export_cad STEP refused the part it had just imported. Round-tripping a vendor model through vcad was impossible. Imports now default to B-rep. Each body becomes a lazy `step_import` node carrying a path plus a solid index, resolved through a kernel-side registry of STEP bytes (the WASM kernel has no filesystem, so the bytes are handed to it explicitly). Analytic faces survive into booleans, fillets, and STEP export. `as_mesh: true` keeps the old tessellated import for the cases that actually want a mesh — rendering and physics colliders. Because the registry lives in WASM memory, it is empty for any document this process did not import itself. A document-entry hook re-registers a document's STEP sources when it is opened or rehydrated after a restart, so a reopened save stays B-rep-backed instead of failing to evaluate. Paths are confined to the same export root import_step writes into, so a crafted document cannot turn a reopen into an arbitrary file read. open_in_browser bakes step_import nodes to meshes for the trip only: the browser cannot resolve a reference into this server's registry and would otherwise render an empty part. The session keeps its B-rep. Two bugs surfaced while verifying this, both pre-existing: - Topology::half_edge_dest asserted `next.is_some()`, but a STEP import builds both directions of every edge and only loop-used half-edges get `next` wired. Exporting any imported solid panicked with "half-edge has no next". It now falls back to the twin's origin — the same vertex the loop would have named. This blocked the CLI too; it was simply unreachable through MCP while import was mesh-only. - A STEP assembly (vendor files routinely are one) reads as "no geometry": the flat reader follows the product anchor a single hop, so bodies reached through SHAPE_REPRESENTATION_RELATIONSHIP are invisible to it. That failure now names the assembly and its part/placement counts instead of claiming the file is empty. Traversing assembly structure on import is left as follow-up work — placing bodies without their transforms would stack them at the origin, which is worse than a clear error. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…-bb1f3a # Conflicts: # crates/vcad-eval/src/lib.rs # packages/engine/src/index.ts
cargo fmt --check flagged the signature of to_wasm_report as too long for one line. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
import-step emits one node per solid, but every one of them was built without a solid index — so before this field existed they all resolved to solid 0, and a multi-body STEP became N copies of the first body. Now each node names the body it came from. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
import_steptessellated every body on the way in, so an imported part arrived as a triangle soup: no analytic faces, booleans and fillets degraded to mesh operations, andexport_cadSTEP refused the part it had just imported. Round-tripping a vendor model through vcad was impossible.Imports now default to B-rep. Each body becomes a lazy
step_importnode carrying a path plus a solid index, resolved through a kernel-side registry of STEP bytes (the WASM kernel has no filesystem, so the bytes are handed to it explicitly).as_mesh: truekeeps the old tessellated import for the cases that actually want a mesh — rendering, physics colliders.Why the registry needs a rebind hook
The registry lives in WASM memory, so it is empty for any document this process did not import itself. A document-entry hook re-registers a document's STEP sources when it is opened or rehydrated after a restart — otherwise a reopened save would evaluate to nothing.
step_importresolution failures are a hard error naming the path, not a silent "no geometry", because a document that quietly evaluates to nothing because its STEP moved is far harder to diagnose.open_in_browserbakesstep_importnodes to meshes for the trip only — the browser cannot resolve a reference into this server's registry and would render an empty part. The session's own document keeps its B-rep.Two pre-existing bugs this surfaced
STEP export of any imported solid panicked.
Topology::half_edge_destassertednext.is_some(), but a STEP import builds both directions of every edge and only loop-used half-edges getnextwired — so an edge on a skipped face has a loop-less side. Exporting an imported body died withhalf-edge has no next. It now falls back to the twin's origin, which is the same vertex the loop would have named. This blocked the CLI too; it was just unreachable through MCP while import was mesh-only.A STEP assembly reads as "no geometry." The flat reader follows the product anchor exactly one hop, so bodies reached via
SHAPE_REPRESENTATION_RELATIONSHIPare invisible to it — and vendor files routinely are assemblies. The failure now names the assembly and its part/placement counts instead of claiming the file is empty.Reviewer notes
registerDocumentStepSourcesreads paths out of a caller-supplied document, so it is confined to the same export rootimport_stepwrites into — a crafted document cannot turn a reopen into an arbitrary file read.import_stephook is registered once per engine (createServerruns per connection).tool-surface.fixture.jsonis regenerated for the intendedimport_stepdescription +as_meshschema change, and nothing else.artifact-storetests now passas_mesh: true: they cover report surfacing and large-result offload against stub engines that only implement the mesh entry point. Real B-rep import is covered instep-import.test.tsagainst the live kernel.packages/kernel-wasm/vcad_kernel_wasm*artifacts are deliberately not committed, per CLAUDE.md — the kernel needs a rebuild (or thewasm-refreshworkflow on main) forregisterStepSourceto exist.Known gap
The named verification target — a SolidWorks
RMD-X6-P20-60vendor file — still cannot be imported end-to-end, because it is an assembly (16 part definitions, 24 placements). This is not a regression: the old mesh import failed on it identically. Real assembly import needs per-instance placement in the IR and world-transform composition through nested instances; placing bodies without transforms would stack them at the origin, so it is left as follow-up rather than half-implemented.Testing
cargo test -p vcad-eval -p vcad-ir -p vcad-kernel-step -p vcad-kernel-topo— green, including 3 new tests incrates/vcad-eval/tests/step_import_brep.rs(B-rep survives +can_export_step;solid_indexselects the right body; a missing source errors with the path named).cargo clippyon all touched crates — clean.packages/app(last-opened,circuit-build,ecad-feature-inspector,parameter-influence,pcb-interference) and were confirmed failing identically on a stashed clean tree — pre-existing, untouched by this branch.export_cadSTEP now succeeds where it previously panicked.🤖 Generated with Claude Code