solid.shell refused an empty face list ("select 1…1000 faces"), and the
shell feature found its body from the first face picked. SMLib shells with no
face opened (the void sealed inside, its own shell): the command now takes
`faces: []`, the feature shells the one body there is or the one named
(`body`), and an outside or both-ways shell pushes no open face out of the
cavity. Rig shell/4009 declares the void's shell (`shells: 2`), as its method
says.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
doc: world_state, world_state_reusing, state_in_frame_at, state_in_frame, face_point_state,
face_point_names and construction_state return Result. A body that could not be placed, a
frame that could not be inverted, a sketch plane or thread axis that did not survive the
placement, or a failed placing worker used to leave things where they were without a word;
now the call fails with what could not be placed. is_placement is the one test of an
occurrence's placement (finite, a rotation that does not mirror, a translation within
1e9 mm). Opening a design names every occurrence that fails it; add_occurrence refuses
one; a joint solution that would place an occurrence outside one is not applied and the
joints placing it report it.
engine: Session::world_state returns Result and keeps a failure in its cache as it keeps a
placed model. bounds, home_camera, open_sketch_plane, the scene builders, the world
previews, frames::to_local and auto_operation pass the error on; helpers answering "not
found" take the placed model from their caller. Commands setting a placement check it
(valid_position, exploded view, fastener at a point, STEP insert matrix).
ui: panels, picks and hovers read the session's placed model through
open_meshing::session_world; a model that cannot be placed shows no placed bodies, and the
viewport says why across its bottom. Pictures and the control channel report the error.
cli, mcp: snapshots, renders, benches and the oracle report the error; the kernel-case rig
records it as the case's failure. Tests read the new Results with unwrap.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
* claim: #4585
* Sketch drag: a linkage held by redundant parallelograms still moves (#4585)
Cursor motion looks for the sketch's freedom in the null space of the
constraint Jacobian. Redundant constraints (a parallelogram held both
parallel and equal on each pair of sides) are dependent only at an exact
solution; after a correction to the solver's tolerance their rows differ
by about 1e-9, which the 1e-9 pivot tolerance counted as rank, so the
null space came out empty and a one-DoF linkage stayed locked. Use the
rank analysis' 1e-7, so the drag sees the freedom the sketch reports.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Model cache written by default: exact bodies, stored once, scaled caps (#3053)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* bench-open: say why bodies were not kept
* Exact planes and revolutions; budgets for large bodies (#3053)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Native B-rep: rebuild shells as the kernel made them (closed and seam edges) (#3053)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs: the model cache and the exact native B-rep (#3053)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* bench-open: time a save without the cache too
* Model cache entries are Deflate-compressed (#3053)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Model cache: one that does not fit the design file is left out, never a failed save (#3053)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Extrude: a profile edge short of a face is not grown through the skin beyond it (#1669)
A cut or join profile edge that lies on a face of the target is grown off it by 0.5 % of the body, so that the tool's wall does not lie in the face. Whether it lies on a face was judged half a growth step either side of it: empty just outside, material just inside. An edge 0.25 mm short of a 3.75 mm wall's far face reads the same, and the growth cut through the skin it should leave (55 050 mm³ instead of 56 130 on the test's wall). Now the space just past the edge, 1e-4 of the body out, must already be as the operation wants too.
In #1669, the pleat's window built directly at the far end of a case opened through the wall at 3.75 and 4 mm, while its mirror, built without the growth, rightly left the skin and then failed to join the loft through it. Built either way, the window now leaves the skin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Regression tests: the issue's pleats mirror and build at the far end (#1669)
The issue's battery case at 3.5 mm: the mirror of the window and the pleat builds (it needed #1670's meshing of twisted faces), and at 3 mm the same window and pleat built directly at the far end of the finished case join it (they needed #1667's end rounds).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Far-end pleat test: the direct build matches the mirror's volume
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Erikas <erkexzcx@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
A scale across a revolution's axis keeps the face a surface of revolution and is written as one; any other refusal from the writer is an export error, not a panic.