Shape::new took (BrepId, id) keys but nothing to resolve them, so its
B-rep and face boxes were DISPATCH GAPs and its edge and vertex lists
stale UNPORTED stubs. It now takes a BrepStore ((BrepId, &Brep) for one
B-rep, NoBreps for none) and runs the whole constructor: the box union of
the listed objects, then each face, edge and vertex loaded into its tree
once (the constructor's mark as sets of loaded keys, since a shape may
span B-reps), statuses ignored as upstream. SmShell::RayFire's shape,
FindFacesToDelete and SmApiFaceClosestPoint pass their B-rep.
The geom.object shim built its box with SmApiCreateBox and numbered
entities by the B-rep lists, which the Rust side could not import. Both
sides now build the shared fixture's SmApiCreateBox solid; the Rust import
gets upstream's GetFaces/GetEdges/GetVertices orders
(sc_geom_object_list_orders), which order a whole B-rep's members. The
shim rejects the inputs SmShape dereferences (a face without surface, an
edge without curve, a lone B-rep without infinite region).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SmObject type system, AssertValid and Notify (user then system callback;
NotifyCallback::execute added to geom.context), the scoped
TemporaryChangeValue guard, and SmShape (empty shapes exact; non-empty
shapes return Unported on topology.brep_p1/face_p2/edge/vertex).
difftest: 624 cases, 593 pass bit-identical, 31 deferred.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>