An assembly is a multi-body document. An instance is already expressible as
Transform with xf_copy=true, and a mate connector is already a CoordSys
feature, so this adds exactly one feature type: Mate.
No constraint solver. A mate rigidly transforms the body carrying connector B
so that B's frame lands on connector A's, applied in feature order like every
other feature. Chains resolve by composition; closed kinematic loops do not
converge (last mate wins) and are out of scope.
The vendored SolveSpace in src/libslic3r/slvs/ was evaluated for 3D extension
and rejected: it is built and linked but has zero callers, and SketchEngine's
solver is hand-rolled. Extending it would mean adopting a dependency to write
more code than the alternative.
- CadFeatureType::Mate appended; six fields (mate_kind, mate_cs_a, mate_cs_b,
mate_offset, mate_angle, mate_flip) appended at the END of both cereal lists
- SNAPORCA_CAD_RECIPE_VERSION 2 -> 3; v2 blobs are rejected, as by design there
is no migration path. Golden fixture renamed to cad_recipe_v3.bin and
regenerated once, extended with two CoordSys + one Mate so the new fields are
tripwired by the field-order assertions
- datum_frame() extracted from resolve_datum_coordsys() so a mate can resolve
its connectors against the in-progress bodies vector during replay
- apply_mate dispatched early-return, so Mate is deliberately absent from
starts_new (unreachable for that dispatch style)
- Planar: the degenerate branch splits on the sign of zB.z_target — antiparallel
needs a 180 deg rotation about a perpendicular axis, which an earlier revision
silently skipped, leaving the body's normal inverted
- MCP: mate command, named bare to match the other 38 methods
Drive-by: feature_type_name() was missing Mirror, ThickenSurface, SurfaceOffset,
SurfaceLoft and SurfaceFill, which reported as "Unknown" to MCP clients.
Suite 122 cases / 1741 assertions green. Note that kernel-test.sh builds only
libslic3r_tests, so McpControl.cpp is reviewed but not compiled here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>