Skip to main content

brep_kernel/offset/offset_shell/
pipeline.rs

1use super::*;
2
3/// Put every face on one normal convention (surface normal on the CCW
4/// parameter-winding side) and then restore outward normals. The offset shell's
5/// source and offset skins are assembled as independent components whose
6/// per-face `same_sense` can follow opposite conventions; `validate()` only
7/// checks coedge-direction coherence (the `forward` flags), so a joined,
8/// watertight, coedge-coherent manifold can still be normal-incoherent and
9/// report the wrong volume. Re-deriving `same_sense` from the loop winding makes
10/// the coedge-coherent manifold normal-coherent; the signed-volume flip then
11/// orients it outward. Only invoked after a non-coplanar rim weld, so the
12/// coplanar cylinder/prism shells keep their exact assembled orientation.
13fn coheres_face_normals(solid: &mut BrepSolid) -> Result<(), String> {
14    for face in solid.shells.iter_mut().flat_map(|shell| &mut shell.faces) {
15        face.same_sense = parameter_space_area(face)? > 0.0;
16    }
17    // Outward is a PER-SHELL property: a through-hole shelled at both ends
18    // legitimately produces two disjoint closed components (the outer wall
19    // tube and the hole wall tube), and a single global signed-volume flip
20    // cannot orient both.
21    for shell_index in 0..solid.shells.len() {
22        let single = BrepSolid {
23            id: solid.id,
24            vertices: solid.vertices.clone(),
25            edges: solid.edges.clone(),
26            shells: vec![solid.shells[shell_index].clone()],
27            genus: 0,
28        };
29        if crate::solid_signed_volume(&single)? < 0.0 {
30            flip_shell_faces(&mut solid.shells[shell_index])?;
31        }
32    }
33    Ok(())
34}
35
36/// Mint a vertex at every SELF-TOUCH of the source's faces before the shell
37/// reads their trims.
38///
39/// A face whose loops touch at an EDGE INTERIOR is a pinched region: the
40/// reported 2026-09-09 document's r = 6 through-hole kisses both r = 4 fillet
41/// setbacks on the top face, at (16, 20, 10) and (10, 20, 16), with no vertex
42/// there.  The fragment stage's 2D arrangement resolves such a pinch by
43/// carving the touched-off corner into its own region, whose loop walks the
44/// closed hole chain in a PARTIAL run — which `build_loop` can only assemble
45/// when the touch is a vertex of both touching edges, and otherwise refuses
46/// with "chain N fragmented into an incomplete run".
47///
48/// The boolean lane mints that vertex inside `build_imprints`
49/// (`imprint/self_touch.rs`).  Nothing minted it here: the shell fragments
50/// its SOURCE against an EMPTY imprint, and its offset carriers — whose trims
51/// are copied from the source faces — deliberately keep their boundaries
52/// un-split, so both arrived at the arrangement pinched.  Splitting the
53/// source once, before the carriers are built from it, fixes both: every
54/// carrier inherits the split trim by construction.
55///
56/// Returns `None` when no face self-touches, so every part that was never
57/// pinched keeps its exact previous path.  Escape hatch:
58/// `BREP_SELF_TOUCH_SPLIT=0`, the same one the imprint lane honours.
59fn split_self_touching_source(source: &BrepSolid) -> Result<Option<BrepSolid>, String> {
60    if std::env::var("BREP_SELF_TOUCH_SPLIT").as_deref() == Ok("0") {
61        return Ok(None);
62    }
63    // The same derivation `offset_shell_impl` uses for every other band, so
64    // the source scan and the carrier-pair scans agree on what "touching"
65    // means.
66    let scale = crate::solid_scale(source);
67    let tolerance = 1e-7f64.max(scale * 1e-9);
68    let edge_splits = crate::imprint::self_touch_edge_splits(source, SOURCE_OPERAND, tolerance, scale)?;
69    if edge_splits.is_empty() {
70        return Ok(None);
71    }
72    os_debug!(
73        "self-touch: source split on {} edge(s): {:?}",
74        edge_splits.len(),
75        edge_splits
76            .iter()
77            .map(|split| split.edge_id)
78            .collect::<Vec<_>>(),
79    );
80    let imprint = ImprintResultRecord {
81        edge_splits,
82        ..empty_imprint()
83    };
84    Ok(Some(apply_edge_splits(source, SOURCE_OPERAND, &imprint)?))
85}
86
87pub fn offset_shell(
88    source: &BrepSolid,
89    opening_face_ids: &[u64],
90    distance: f64,
91) -> Result<OffsetShellResultRecord, String> {
92    // Pinched source faces are un-modellable by the arrangement until the
93    // touch is a vertex; do it once here so BOTH `offset_shell_impl` attempts
94    // and every carrier built from the source see the same topology.
95    let prepared = split_self_touching_source(source)?;
96    let source = prepared.as_ref().unwrap_or(source);
97    // First try with oblique hole-wall carriers extended past their opening
98    // planes (the lane that closes tilted/conical through-holes). If that
99    // extension fired but the arrangement could not assemble the harder
100    // configuration it produced (e.g. the extended bore genuinely intersects
101    // other offset walls), fall back to the un-extended pipeline so every
102    // previously-supported shape keeps its exact path and every refusal keeps
103    // the canonical honesty-gate message.
104    let mut extension_fired = false;
105    let mut reflex_rebuilds = 0usize;
106    match offset_shell_impl(
107        source,
108        opening_face_ids,
109        distance,
110        true,
111        &mut extension_fired,
112        &mut reflex_rebuilds,
113    ) {
114        Ok(result) => {
115            // Attribution marker: which pipeline produced this result. A
116            // retry-produced Ok can silently mask a broken extension lane —
117            // always say which attempt won. The reflex-rebuild count rides
118            // along because that lane fires on BOTH attempts: "extension
119            // idle" alone would misread as "the plain pipeline did this".
120            os_debug!(
121                "offset_shell result: FIRST attempt (extension {}, reflex-rebuilt {})",
122                if extension_fired { "fired" } else { "idle" },
123                reflex_rebuilds,
124            );
125            Ok(result)
126        }
127        Err(error) if extension_fired => {
128            os_debug!("extended pipeline failed ({error}); retrying without carrier extension");
129            let mut unused = false;
130            let mut retry_reflex = 0usize;
131            let retried = offset_shell_impl(
132                source,
133                opening_face_ids,
134                distance,
135                false,
136                &mut unused,
137                &mut retry_reflex,
138            );
139            os_debug!(
140                "offset_shell result: RETRY without extension ({}, reflex-rebuilt {retry_reflex})",
141                if retried.is_ok() { "ok" } else { "err" },
142            );
143            retried
144        }
145        Err(error) => Err(error),
146    }
147}
148
149fn offset_shell_impl(
150    source: &BrepSolid,
151    opening_face_ids: &[u64],
152    distance: f64,
153    extend_oblique_carriers: bool,
154    extension_fired: &mut bool,
155    reflex_rebuilds: &mut usize,
156) -> Result<OffsetShellResultRecord, String> {
157    if !distance.is_finite() || distance.abs() <= 1e-7 {
158        return Err("offset_shell: distance must be finite and non-zero".into());
159    }
160    if opening_face_ids.is_empty() {
161        return Err("offset_shell: at least one opening face is required".into());
162    }
163    let source_faces = source
164        .shells
165        .iter()
166        .flat_map(|shell| &shell.faces)
167        .collect::<Vec<_>>();
168    let opening_set = opening_face_ids.iter().copied().collect::<HashSet<_>>();
169    if opening_set
170        .iter()
171        .any(|id| !source_faces.iter().any(|face| face.id == *id))
172    {
173        return Err("offset_shell: opening face does not belong to source".into());
174    }
175    let retained = source_faces
176        .iter()
177        .filter(|face| !opening_set.contains(&face.id))
178        .map(|face| face.id)
179        .collect::<Vec<_>>();
180    if retained.is_empty() {
181        return Err("offset_shell: removing every face cannot produce a shell".into());
182    }
183    let mut carriers = Vec::new();
184    for face_id in &retained {
185        let face = source_faces.iter().find(|face| face.id == *face_id).unwrap();
186        if offset_support_collapsed(face, distance)? {
187            os_debug!("omitting collapsed offset support for source face {face_id}");
188            continue;
189        }
190        // A planar carrier whose source face meets a neighbour at a REFLEX
191        // (concave) edge extends its trim by |distance|: at such a junction
192        // the offset skin must GROW past the source footprint to meet the
193        // neighbour's offset (a pocket wall's source [5,15] → skin
194        // [3.5,16.5]); a source-sized trim leaves a gap no miter can bridge.
195        // The surplus at the face's convex ends is clipped by the imprints +
196        // on-skin filter. Convex-only faces keep their exact source-sized
197        // trim — extending them perturbs delicately-selected fragment
198        // landscapes for no benefit.
199        let miter = source_faces
200            .iter()
201            .find(|face| face.id == *face_id)
202            .map(|face| face_reflex_miter_tan(source, face))
203            .transpose()?
204            .flatten();
205        // The offsets of two faces joined at a reflex edge meet d·tan(θn/2)
206        // past the source rim — d only for a perpendicular join. Scale the
207        // extension to the worst sampled miter (×1.5 headroom so the true
208        // intersection lands strictly INSIDE the extended trim, never on its
209        // boundary where the arrangement drops boundary-coincident cuts) and
210        // cap it: a near-tangential join would ask for an unbounded trim.
211        let reflex_extension = miter.map(|worst_tan| {
212            (distance.abs() * worst_tan * 1.5)
213                .max(distance.abs())
214                .min(distance.abs() * 12.0)
215        });
216        if let Some(extension) = reflex_extension {
217            os_debug!("carrier for src face {face_id}: reflex-extended by {extension:.4}");
218        }
219        // OUTWARD: every retained carrier grows by |distance| across its
220        // sharp and opening-facing sides (the offsets of a convex junction
221        // meet past both source rims; a wall plane cuts the surplus), and
222        // by nothing across a smooth junction into a retained neighbour —
223        // see `outward_carrier_extension`. A reflex junction needs no
224        // outward growth at all (those offsets cross inside the trims).
225        let extension = if distance < 0.0 {
226            outward_carrier_extension(source, face, &source_faces, &opening_set, distance.abs())?
227        } else {
228            crate::CarrierExtension::uniform(reflex_extension.unwrap_or(0.0))
229        };
230        if distance < 0.0 {
231            os_debug!(
232                "carrier for src face {face_id}: outward extension u=({:.3},{:.3}) v=({:.3},{:.3})",
233                extension.u_min,
234                extension.u_max,
235                extension.v_min,
236                extension.v_max,
237            );
238        }
239        let mut carrier = carrier_solid_sided(source, *face_id, distance, &extension)?;
240        if (distance < 0.0 || reflex_extension.is_some()) && face.surface.is_affine()? {
241            // PADDED planes: the pad slides the plane's net while the trim's
242            // loops are cloned in uv, so an INTERIOR loop (a bore or boss rim
243            // in the face) is carried outward with the grown outline instead
244            // of following the neighbour's offset.
245            //   OUTWARD: a bore's rim grew (r=4.68 → 5.15) while the shrunk
246            //   offset bore (r=3.68) that must hole this plane fell inside the
247            //   enlarged void, so neither the imprint nor the orphan-rim weld
248            //   could cut it.
249            //   INWARD, reflex-extended: the same slide moves a REFLEX hole
250            //   rim the wrong way — a sphere sitting under a frustum's base
251            //   annulus (the user's 2026-09-07 document) had its r=8.3 rim
252            //   scaled to 9.22 while the shrunk offset sphere (r=7.3) crosses
253            //   the offset plane at r=7.23, inside the enlarged hole: the
254            //   pair imprint found nothing and the rim stayed one-use.
255            // Drop the interior loops (as the wall carriers do): the
256            // neighbour's carrier imprints — or its rim, welded in as a
257            // hole — cut the true opening, and the seeded selection drops
258            // the disk over it. A CONVEX interior rim on the same face (a
259            // through-bore in a pocket floor) is safe to drop too: its
260            // offset bore imprints at r+d and the ring inside is rejected by
261            // class (Out) or by the on-skin filter, no seed involved.
262            drop_wall_interior_loops(&mut carrier)?;
263        }
264        carriers.push(Carrier {
265            solid: carrier,
266            source_face_id: *face_id,
267            kind: OffsetFaceRole::Offset,
268        });
269    }
270    // APEX-CAP carriers: a retained face whose DEGENERATE edge (an apex
271    // point, e.g. a conic crater's tip) offsets into a RING is an EXTERIOR
272    // cone offset — the parallel surface truncates at the ring and the exact
273    // rolling-ball offset closes it with a SPHERE of radius |distance| about
274    // the apex. Emit that sphere as an extra carrier: the ring imprint
275    // (sphere × offset frustum) splits it, the on-skin filter keeps exactly
276    // the cap sector (its points are |d| from the apex and ≥|d| from the
277    // rest of the face), and the ring becomes two-use.
278    let mut apex_cap_sources = HashSet::default();
279    let mut apex_cap_pairs: Vec<(usize, usize)> = Vec::new();
280    {
281        let retained_count = carriers.len();
282        for index in 0..retained_count {
283            let source_face = source_by_id_lookup(&source_faces, carriers[index].source_face_id);
284            let Some(source_face) = source_face else {
285                continue;
286            };
287            let carrier_surface = carriers[index].solid.shells[0].faces[0].surface.clone();
288            for coedge in source_face
289                .loops
290                .iter()
291                .flat_map(|loop_record| &loop_record.coedges)
292            {
293                let Some(edge) = source
294                    .edges
295                    .iter()
296                    .find(|edge| edge.id == coedge.edge_id)
297                else {
298                    continue;
299                };
300                if !edge.degenerate {
301                    continue;
302                }
303                // Image of the degenerate edge on the offset surface.
304                let [p0, p1] = coedge.pcurve.domain()?;
305                let mut ring = Vec::new();
306                for sample in 0..=8 {
307                    let uv = coedge
308                        .pcurve
309                        .evaluate(p0 + (p1 - p0) * sample as f64 / 8.0)?;
310                    ring.push(carrier_surface.evaluate(uv.x, uv.y)?);
311                }
312                let spread = ring
313                    .iter()
314                    .map(|point| point.sub(ring[0]).length())
315                    .fold(0.0f64, f64::max);
316                if spread <= distance.abs() * 1e-2 {
317                    continue;
318                }
319                let apex = source
320                    .vertices
321                    .iter()
322                    .find(|vertex| vertex.id == edge.start_vertex_id)
323                    .map(|vertex| vertex.point)
324                    .ok_or_else(|| "offset_shell: apex vertex missing".to_string())?;
325                let centroid = ring
326                    .iter()
327                    .fold(Vec3::default(), |sum, point| sum.add(*point))
328                    .scale(1.0 / ring.len() as f64);
329                let axis = apex.sub(centroid);
330                let axis = if axis.length() > 1e-9 {
331                    axis.normalized()?
332                } else {
333                    Vec3::new(0.0, 0.0, 1.0)
334                };
335                os_debug!(
336                    "apex-cap carrier for src face {} at ({:.3},{:.3},{:.3}) r={:.3}",
337                    carriers[index].source_face_id,
338                    apex.x,
339                    apex.y,
340                    apex.z,
341                    distance.abs(),
342                );
343                apex_cap_sources.insert(index);
344                apex_cap_sources.insert(carriers.len());
345                apex_cap_pairs.push((index, carriers.len()));
346                carriers.push(Carrier {
347                    solid: crate::make_sphere_brep(apex, distance.abs(), axis)?,
348                    source_face_id: carriers[index].source_face_id,
349                    kind: OffsetFaceRole::Offset,
350                });
351            }
352        }
353    }
354    for face_id in opening_face_ids {
355        let source_face = source_faces
356            .iter()
357            .find(|face| face.id == *face_id)
358            .unwrap();
359        carriers.push(Carrier {
360            solid: if distance < 0.0 && source_face.surface.is_affine()? {
361                let pad = outward_wall_pad(
362                    source,
363                    source_face,
364                    &source_faces,
365                    &opening_set,
366                    distance.abs(),
367                )?;
368                os_debug!("wall for opening face {face_id}: outward pad {pad:.4}");
369                let mut wall = carrier_solid(source, *face_id, 0.0, pad)?;
370                // The pad extends the wall by STRETCHING the plane's 2x2 net
371                // while the trim pcurves are cloned in UV, so every loop
372                // scales about the patch centre by (w+2|d|)/w. For the OUTER
373                // loop of a full-domain rectangle that lands exactly on the
374                // grown outline — the intended wall extent. But an INTERIOR
375                // loop (a carve outline: a bore, gouge or crater rim in the
376                // opening face) is scaled OUTWARD too, and the enlarged hole
377                // then swallows both circles the wall must be cut by (the
378                // source carve rim from the wall x source imprint and the
379                // shrunk rim from the wall x offset-carrier imprint) — the
380                // imprints clip to nothing and the rims dangle one-use. Drop
381                // interior loops instead: the wall covers the carve mouth,
382                // the imprints cut the true rims, and selection (void-wall
383                // guard + on-skin filter) drops the fragments over the void.
384                drop_wall_interior_loops(&mut wall)?;
385                wall
386            } else {
387                standalone_face(source, *face_id)?
388            },
389            source_face_id: *face_id,
390            kind: OffsetFaceRole::Wall,
391        });
392    }
393    if carriers.len() >= SOURCE_OPERAND as usize {
394        return Err("offset_shell: too many carrier faces for current ABI".into());
395    }
396    // The characteristic length every tolerance below is derived from.  This
397    // was `max ‖vertex‖` — the distance from the WORLD ORIGIN — until audit
398    // slice 0: that form made every band widen as the part was moved away from
399    // the origin while ignoring the part's actual size, so the same shell
400    // solved to different tolerances depending only on where it was modelled.
401    // `solid_scale` is the bbox diagonal, floored at 1.0 exactly as the old
402    // fold was, so this changes ONE thing: placement-dependence.
403    let scale = crate::solid_scale(source);
404    crate::report_scale_migration("offset_shell", scale, || {
405        source
406            .vertices
407            .iter()
408            .map(|vertex| vertex.point.length())
409            .fold(1.0, f64::max)
410    });
411    let smooth = synchronize_smooth_offset_boundaries(&mut carriers, &source_faces, scale)?;
412    // Reflex-rim rebuilds run on BOTH attempts: the fallback for a broken
413    // extension is an honest refusal, but the fallback for a skipped reflex
414    // rebuild is a silently WRONG (membrane-capped) shell.
415    let reflex_rebuilt = rebuild_reflex_rim_carriers(
416        &mut carriers,
417        source,
418        &source_faces,
419        &smooth.pairs,
420        scale,
421        distance,
422    )?;
423    *reflex_rebuilds = reflex_rebuilt.len();
424    if extend_oblique_carriers {
425        let oblique_extended = extend_offset_carriers_past_open_hole_rims(
426            &mut carriers,
427            source,
428            &source_faces,
429            &opening_set,
430            &smooth.pairs,
431            scale,
432        )?;
433        let mut already_extended = oblique_extended.clone();
434        already_extended.extend(reflex_rebuilt.iter().copied());
435        let fallshort_extended = extend_fallshort_curved_carriers(
436            &mut carriers,
437            source,
438            &source_faces,
439            &opening_set,
440            &smooth.pairs,
441            &already_extended,
442            scale,
443            distance,
444        )?;
445        *extension_fired = !oblique_extended.is_empty() || fallshort_extended > 0;
446        os_debug!(
447            "extended {} oblique + {fallshort_extended} fall-short carriers past their opening planes",
448            oblique_extended.len(),
449        );
450    }
451    let tolerance = 1e-7f64.max(scale * 1e-9);
452    let pair_tolerance = (scale * 1e-8).max(2e-6);
453    let reach = distance.abs() * 4.0 + pair_tolerance;
454    let carrier_samples = carriers
455        .iter()
456        .map(|carrier| carrier_extent_points(&carrier.solid))
457        .collect::<Result<Vec<_>, _>>()?;
458    let carrier_bounds = carrier_samples
459        .iter()
460        .map(|samples| Bounds::from_points(samples))
461        .collect::<Option<Vec<_>>>()
462        .ok_or_else(|| "offset_shell: carrier has no boundary samples".to_string())?;
463    let source_by_id = source_faces
464        .iter()
465        .map(|face| (face.id, *face))
466        .collect::<HashMap<_, _>>();
467    let source_samples = source_faces
468        .iter()
469        .map(|face| {
470            let standalone = standalone_face(source, face.id)?;
471            Ok((face.id, edge_sample_points(&standalone)?))
472        })
473        .collect::<Result<HashMap<_, _>, String>>()?;
474    if debug_enabled() {
475        for (index, carrier) in carriers.iter().enumerate() {
476            let face = &carrier.solid.shells[0].faces[0];
477            let samples = &carrier_samples[index];
478            let bounds =
479                samples
480                    .iter()
481                    .fold((Vec3::default(), Vec3::default()), |(low, high), point| {
482                        (
483                            Vec3 {
484                                x: low.x.min(point.x),
485                                y: low.y.min(point.y),
486                                z: low.z.min(point.z),
487                            },
488                            Vec3 {
489                                x: high.x.max(point.x),
490                                y: high.y.max(point.y),
491                                z: high.z.max(point.z),
492                            },
493                        )
494                    });
495            let surface = &face.surface;
496            let rational = surface
497                .control_points
498                .iter()
499                .flatten()
500                .any(|point| (point.w - 1.0).abs() > 1e-12);
501            os_debug!(
502                "carrier[{index}] kind={:?} source_face={} loops={} deg=({},{}) net={}x{} rational={rational} bounds=({:.3},{:.3},{:.3})..({:.3},{:.3},{:.3})",
503                carrier.kind, carrier.source_face_id, face.loops.len(),
504                surface.degree_u, surface.degree_v,
505                surface.control_points.len(),
506                surface.control_points.first().map(|row| row.len()).unwrap_or(0),
507                bounds.0.x, bounds.0.y, bounds.0.z, bounds.1.x, bounds.1.y, bounds.1.z,
508            );
509        }
510        for (index, carrier) in carriers.iter().enumerate() {
511            if !matches!(carrier.kind, OffsetFaceRole::Offset) {
512                continue;
513            }
514            let source_face = source_by_id[&carrier.source_face_id];
515            let carrier_surface = &carrier.solid.shells[0].faces[0].surface;
516            let (ku, kv) = (
517                crate::KnotVector::new(
518                    source_face.surface.knots_u.clone(),
519                    source_face.surface.degree_u,
520                ),
521                crate::KnotVector::new(
522                    source_face.surface.knots_v.clone(),
523                    source_face.surface.degree_v,
524                ),
525            );
526            if let (Ok(ku), Ok(kv)) = (ku, kv) {
527                let [u0, u1] = ku.domain();
528                let [v0, v1] = kv.domain();
529                let mut worst = 0.0f64;
530                let mut worst_at = (0.0f64, 0.0f64);
531                for iu in 0..=24 {
532                    for iv in 0..=24 {
533                        let u = u0 + (u1 - u0) * iu as f64 / 24.0;
534                        let v = v0 + (v1 - v0) * iv as f64 / 24.0;
535                        let expected = face_offsets(source_face)
536                            .at(u, v, -distance)
537                            .map(|sample| sample.point);
538                        let actual = carrier_surface.evaluate(u, v);
539                        if let (Ok(expected), Ok(actual)) = (expected, actual) {
540                            let error = expected.sub(actual).length();
541                            if error > worst {
542                                worst = error;
543                                worst_at = (u, v);
544                            }
545                        }
546                    }
547                }
548                let mut normal_swing = 0.0f64;
549                let mut previous: Option<Vec3> = None;
550                for iu in 0..=48 {
551                    let u = u0 + (u1 - u0) * iu as f64 / 48.0;
552                    let v = (v0 + v1) / 2.0;
553                    if let Ok(normal) = face_normal(source_face, u, v) {
554                        if let Some(previous) = previous {
555                            normal_swing = normal_swing.max(previous.sub(normal).length());
556                        }
557                        previous = Some(normal);
558                    }
559                }
560                let weights = source_face
561                    .surface
562                    .control_points
563                    .iter()
564                    .flatten()
565                    .map(|point| point.w)
566                    .fold((f64::MAX, f64::MIN), |(low, high), w| {
567                        (low.min(w), high.max(w))
568                    });
569                os_debug!(
570                    "carrier[{index}] offset fit error max={worst:.6} at=({:.4},{:.4}) domain_u=({u0:.4},{u1:.4}) normal_step_max={normal_swing:.4} src_net={}x{} src_deg=({},{}) src_w=({:.4},{:.4}) knots_u={:?}",
571                    worst_at.0, worst_at.1,
572                    source_face.surface.control_points.len(),
573                    source_face.surface.control_points.first().map(|row| row.len()).unwrap_or(0),
574                    source_face.surface.degree_u, source_face.surface.degree_v,
575                    weights.0, weights.1,
576                    &source_face.surface.knots_u,
577                );
578            }
579        }
580        os_debug!("smooth pairs: {:?}", smooth.pairs);
581    }
582    let mut imprint = empty_imprint();
583    let mut next_piece_id = 1;
584    let mut next_vertex_id = 1;
585    for first in 0..carriers.len() {
586        for second in first + 1..carriers.len() {
587            let first_source = source_by_id[&carriers[first].source_face_id];
588            let second_source = source_by_id[&carriers[second].source_face_id];
589            if matches!(carriers[first].kind, OffsetFaceRole::Wall)
590                && matches!(carriers[second].kind, OffsetFaceRole::Wall)
591            {
592                // INWARD walls are the opening faces themselves: two openings
593                // never overlap and adjacent ones only touch along their
594                // shared edge, so there is nothing to imprint. OUTWARD walls
595                // are the opening planes EXTENDED by |distance|: the walls of
596                // two ADJACENT openings cross along the line of their shared
597                // source edge, and each wall ring must stop there (the sheet
598                // past that line lies in front of the other opening). Without
599                // the cut the wall × source chain below stays open on the
600                // shared-edge side (its neighbour there is an opening, not a
601                // retained face), the wall never fragments into its ring, and
602                // every source rim along both openings dangles one-use.
603                if distance > 0.0 || !source_faces_adjacent(first_source, second_source) {
604                    continue;
605                }
606            }
607            if smooth.pairs.contains(&(first, second)) {
608                os_debug!("pair ({first},{second}) skipped: smooth");
609                continue;
610            }
611            if !carrier_bounds[first].intersects(carrier_bounds[second], pair_tolerance) {
612                os_debug!("pair ({first},{second}) skipped: bounds");
613                continue;
614            }
615            if !source_faces_adjacent(first_source, second_source)
616                && sample_separation(
617                    &source_samples[&first_source.id],
618                    &source_samples[&second_source.id],
619                ) > reach
620            {
621                os_debug!("pair ({first},{second}) skipped: separation");
622                continue;
623            }
624            let pair = match build_imprints(
625                &carriers[first].solid,
626                &carriers[second].solid,
627                &ImprintOptions {
628                    tolerance,
629                    maximum_fit_points: 96,
630                    local_fit: true,
631                    fit_chunk_points: None,
632                    // Offset carriers can meet in short, tightly curved
633                    // branches. The general SSI default (diagonal / 15) is
634                    // too coarse here and lets independently fitted branches
635                    // miss a shared junction when thickness crosses one of
636                    // those branches.
637                    maximum_ssi_step: Some((scale * 0.0005).max(tolerance * 100.0)),
638                },
639            ) {
640                Ok(pair) => pair,
641                // A failed pair imprint (e.g. the marching SSI exhausting its
642                // step budget on a long closed sphere/plane intersection) is
643                // not fatal to the shell: the affected rim simply stays
644                // unsplit and the rim-weld passes below get to close it. The
645                // final watertightness gate still refuses anything the welds
646                // cannot reach, so tolerating the miss only enlarges the
647                // honest success set.
648                Err(error) => {
649                    os_debug!("pair ({first},{second}) imprint failed: {error}");
650                    continue;
651                }
652            };
653            let pieces_before = imprint.pieces.len();
654            merge_pair_imprint(
655                &mut imprint,
656                pair,
657                first as u8,
658                second as u8,
659                &mut next_piece_id,
660                &mut next_vertex_id,
661                tolerance,
662                scale,
663            );
664            os_debug!(
665                "pair ({first},{second}) src=({},{}) pieces+={}",
666                carriers[first].source_face_id,
667                carriers[second].source_face_id,
668                imprint.pieces.len() - pieces_before,
669            );
670        }
671    }
672    if distance < 0.0 {
673        // OUTWARD shells: the opening-wall carrier is the opening face's
674        // plane EXTENDED by |distance|, so its trim carries only the GROWN
675        // outline. Its inner boundary — where the wall ring stops at the
676        // source solid — is the source outline, and the retained SOURCE faces
677        // are not carriers, so no carrier×carrier pair ever imprints it.
678        // Un-cut, the wall stays one whole-plane fragment covering the
679        // opening void, and the source faces' rim edges dangle one-use.
680        // Imprint each wall carrier against the retained source faces that
681        // share an edge with its opening: the wall then fragments into the
682        // ring (kept) and the opening hole (dropped by the void guard).
683        for index in 0..carriers.len() {
684            if !matches!(carriers[index].kind, OffsetFaceRole::Wall) {
685                continue;
686            }
687            let opening = source_by_id[&carriers[index].source_face_id];
688            for retained_id in &retained {
689                let retained_face = source_by_id[retained_id];
690                if !source_faces_adjacent(opening, retained_face) {
691                    continue;
692                }
693                let neighbor = standalone_face(source, *retained_id)?;
694                let pair = match build_imprints(
695                    &carriers[index].solid,
696                    &neighbor,
697                    &ImprintOptions {
698                        tolerance,
699                        maximum_fit_points: 96,
700                        local_fit: true,
701                        fit_chunk_points: None,
702                        maximum_ssi_step: Some((scale * 0.0005).max(tolerance * 100.0)),
703                    },
704                ) {
705                    Ok(pair) => pair,
706                    Err(error) => {
707                        os_debug!(
708                            "wall×source pair ({index},{retained_id}) imprint failed: {error}"
709                        );
710                        continue;
711                    }
712                };
713                let pieces_before = imprint.pieces.len();
714                merge_pair_imprint(
715                    &mut imprint,
716                    pair,
717                    index as u8,
718                    SOURCE_OPERAND,
719                    &mut next_piece_id,
720                    &mut next_vertex_id,
721                    tolerance,
722                    scale,
723                );
724                os_debug!(
725                    "wall×source pair ({index},{retained_id}) pieces+={}",
726                    imprint.pieces.len() - pieces_before,
727                );
728            }
729        }
730    }
731    // APEX-CAP ring splits: the cap × cone section lies ON the cone
732    // carrier's promoted ring edge (an overlap, not a crossing), so
733    // `build_imprints` mints no edge splits for the cone side. Without them
734    // the cone keeps ONE closed ring edge while the cap carries the section
735    // as arcs — mismatched segmentation, both sides one-use. Record the arc
736    // junctions as splits on the cone's coincident edge.
737    for (cone_index, cap_index) in &apex_cap_pairs {
738        let cap_face_id = carriers[*cap_index].solid.shells[0].faces[0].id;
739        let piece_ids = imprint
740            .by_face
741            .iter()
742            .find(|entry| entry.operand == *cap_index as u8 && entry.face_id == cap_face_id)
743            .map(|entry| entry.piece_ids.clone())
744            .unwrap_or_default();
745        let coincidence_band = 2e-5f64.max(scale * 1e-7);
746        for piece_id in piece_ids {
747            let Some((curve, t0, t1)) = imprint
748                .pieces
749                .iter()
750                .find(|piece| piece.id == piece_id)
751                .map(|piece| (piece.curve.clone(), piece.t0, piece.t1))
752            else {
753                continue;
754            };
755            for endpoint in [curve.evaluate(t0)?, curve.evaluate(t1)?] {
756                for edge in &carriers[*cone_index].solid.edges {
757                    if edge.degenerate {
758                        continue;
759                    }
760                    let projection = crate::project_point_to_curve(&edge.curve, endpoint)?;
761                    if projection.distance > coincidence_band
762                        || projection.u < edge.t0 + 1e-9
763                        || projection.u > edge.t1 - 1e-9
764                    {
765                        continue;
766                    }
767                    let parameter = projection.u;
768                    if let Some(existing) = imprint.edge_splits.iter_mut().find(|split| {
769                        split.operand == *cone_index as u8 && split.edge_id == edge.id
770                    }) {
771                        if !existing
772                            .parameters
773                            .iter()
774                            .any(|value| (*value - parameter).abs() <= 1e-8)
775                        {
776                            existing.parameters.push(parameter);
777                        }
778                    } else {
779                        imprint.edge_splits.push(EdgeSplitRecord {
780                            operand: *cone_index as u8,
781                            edge_id: edge.id,
782                            parameters: vec![parameter],
783                        });
784                    }
785                    os_debug!(
786                        "apex-cap ring split: cone carrier {cone_index} edge {} at t={parameter:.6}",
787                        edge.id,
788                    );
789                }
790            }
791        }
792    }
793    if debug_enabled() {
794        for piece in &imprint.pieces {
795            let start = piece.curve.evaluate(piece.t0);
796            let mid = piece.curve.evaluate((piece.t0 + piece.t1) * 0.5);
797            let end = piece.curve.evaluate(piece.t1);
798            if let (Ok(start), Ok(mid), Ok(end)) = (start, mid, end) {
799                os_debug!(
800                    "piece[{}] ({:.4},{:.4},{:.4})..({:.4},{:.4},{:.4})..({:.4},{:.4},{:.4})",
801                    piece.id,
802                    start.x,
803                    start.y,
804                    start.z,
805                    mid.x,
806                    mid.y,
807                    mid.z,
808                    end.x,
809                    end.y,
810                    end.z,
811                );
812            }
813        }
814    }
815    synchronize_smooth_edge_splits(&mut imprint, &smooth.edge_pairs);
816    // This decides whether an imprint is genuinely the carrier's existing
817    // trim, not whether independently fitted curves can later be sewn. The
818    // looser assembly tolerance can erase a short separating branch while it
819    // is still departing a boundary.
820    let boundary_coincidence_tolerance = 2e-5f64.max(scale * 1e-7);
821    let piece_geometry = imprint
822        .pieces
823        .iter()
824        .map(|piece| {
825            (
826                piece.id,
827                FragmentEdgeGeometry {
828                    curve: piece.curve.clone(),
829                    t0: piece.t0,
830                    t1: piece.t1,
831                },
832            )
833        })
834        .collect::<HashMap<_, _>>();
835    for (index, carrier) in carriers.iter().enumerate() {
836        if !matches!(carrier.kind, OffsetFaceRole::Offset) {
837            continue;
838        }
839        let boundaries = carrier
840            .solid
841            .edges
842            .iter()
843            .map(|edge| FragmentEdgeGeometry {
844                curve: edge.curve.clone(),
845                t0: edge.t0,
846                t1: edge.t1,
847            })
848            .collect::<Vec<_>>();
849        if let Some(by_face) = imprint
850            .by_face
851            .iter_mut()
852            .find(|entry| entry.operand == index as u8)
853        {
854            let before = by_face.piece_ids.clone();
855            by_face.piece_ids.retain(|piece_id| {
856                let piece = &piece_geometry[piece_id];
857                !boundaries.iter().any(|boundary| {
858                    fragment_edge_lies_on(piece, boundary, boundary_coincidence_tolerance)
859                        .unwrap_or(false)
860                })
861            });
862            if debug_enabled() && before.len() != by_face.piece_ids.len() {
863                os_debug!(
864                    "carrier[{index}] dropped boundary-coincident pieces: {:?} -> {:?}",
865                    before,
866                    by_face.piece_ids,
867                );
868            }
869        }
870    }
871
872    if debug_enabled() {
873        for entry in &imprint.by_face {
874            os_debug!(
875                "by_face operand={} face={} pieces={:?}",
876                entry.operand,
877                entry.face_id,
878                entry.piece_ids,
879            );
880        }
881    }
882    let mut split_carriers = Vec::new();
883    let mut fragments_by_carrier = Vec::new();
884    for (index, carrier) in carriers.iter().enumerate() {
885        // Offset carriers keep their boundary un-split (their trims never
886        // coincide with imprints — the boundary-coincidence filter drops such
887        // pieces instead). An apex-cap ring breaks that assumption: the
888        // frustum's ring is its TRIM boundary while the cap crosses it as TWO
889        // imprint arcs — without splitting, the two sides segment differently
890        // and both stay one-use. Split exactly the cap-affected carriers.
891        let split = if matches!(carrier.kind, OffsetFaceRole::Offset)
892            && !apex_cap_sources.contains(&index)
893        {
894            carrier.solid.clone()
895        } else {
896            apply_edge_splits(&carrier.solid, index as u8, &imprint)?
897        };
898        let fragments = fragment_solid(&split, index as u8, &imprint)?;
899        os_debug!(
900            "carrier[{index}] kind={:?} src={} fragments={}",
901            carrier.kind,
902            carrier.source_face_id,
903            fragments.len(),
904        );
905        if debug_enabled() {
906            for (fragment_index, fragment) in fragments.iter().enumerate() {
907                let mut boundary_count = 0usize;
908                let mut imprint_pieces = Vec::new();
909                let mut derived_count = 0usize;
910                for coedge in fragment
911                    .loops
912                    .iter()
913                    .flat_map(|loop_record| &loop_record.coedges)
914                {
915                    match &coedge.source {
916                        FragmentEdgeSource::Boundary { .. }
917                        | FragmentEdgeSource::SharedBoundary { .. } => boundary_count += 1,
918                        FragmentEdgeSource::Imprint { piece_id } => imprint_pieces.push(*piece_id),
919                        FragmentEdgeSource::Derived { .. } => derived_count += 1,
920                    }
921                }
922                os_debug!(
923                    "  frag[{index}.{fragment_index}] test=({:.3},{:.3},{:.3}) uv=({:.3},{:.3}) boundary={boundary_count} derived={derived_count} pieces={imprint_pieces:?}",
924                    fragment.test_point.x, fragment.test_point.y, fragment.test_point.z,
925                    fragment.test_uv.x, fragment.test_uv.y,
926                );
927            }
928        }
929        split_carriers.push(split);
930        fragments_by_carrier.push(fragments);
931    }
932    let mut assembly_sources = [(SOURCE_OPERAND, source)]
933        .into_iter()
934        .collect::<HashMap<_, _>>();
935    for (index, carrier) in split_carriers.iter().enumerate() {
936        assembly_sources.insert(index as u8, carrier);
937    }
938
939    let source_edge_by_id = source
940        .edges
941        .iter()
942        .map(|edge| (edge.id, edge))
943        .collect::<HashMap<_, _>>();
944    let retained_faces_with_edges = retained
945        .iter()
946        .map(|face_id| {
947            let face = source_by_id[face_id];
948            let edges = face
949                .loops
950                .iter()
951                .flat_map(|loop_record| &loop_record.coedges)
952                .filter_map(|coedge| source_edge_by_id.get(&coedge.edge_id).copied())
953                .collect::<Vec<_>>();
954            (face, edges)
955        })
956        .collect::<Vec<_>>();
957    let offset_skin_tolerance = 2e-3f64.max(scale * 5e-5).max(distance.abs() * 1e-3);
958    // OUTWARD shells: a wall fragment lying IN FRONT of another opening —
959    // past that opening's plane on its void side, within the extent of its
960    // (extended) wall carrier — is not material: an opening removes
961    // everything in front of it. Such a fragment is the sheet of this wall
962    // between the source outline and the grown outline on the far side of an
963    // ADJACENT opening's shared edge (the x∈[−1,0] strip of an opened −Z
964    // face's wall, in front of the opened −X face). It sits within |distance|
965    // of a retained face's corner edge, so the void-cross-section guard reads
966    // it as wall thickness; only the other opening's plane tells it apart.
967    let mut opening_planes: Vec<(usize, Vec3, Vec3)> = Vec::new();
968    if distance < 0.0 {
969        for (index, carrier) in carriers.iter().enumerate() {
970            if !matches!(carrier.kind, OffsetFaceRole::Wall) {
971                continue;
972            }
973            let opening = source_by_id[&carrier.source_face_id];
974            if !opening.surface.is_affine()? {
975                continue;
976            }
977            let [u0, u1] = opening.surface.domain_u()?;
978            let [v0, v1] = opening.surface.domain_v()?;
979            let (u, v) = ((u0 + u1) * 0.5, (v0 + v1) * 0.5);
980            opening_planes.push((
981                index,
982                opening.surface.evaluate(u, v)?,
983                face_normal(opening, u, v)?,
984            ));
985        }
986    }
987    let in_front_of_other_opening = |wall_index: usize, point: Vec3| -> Result<bool, String> {
988        let band = 2e-3f64.max(scale * 5e-5);
989        for (index, plane_point, outward) in &opening_planes {
990            if *index == wall_index || point.sub(*plane_point).dot(*outward) <= band {
991                continue;
992            }
993            let face = &split_carriers[*index].shells[0].faces[0];
994            let projection = project_point_to_surface(&face.surface, point)?;
995            let uv = Vec2 {
996                x: projection.u,
997                y: projection.v,
998            };
999            if parameter_point_in_face(face, uv, 1e-8)? != PolygonClass::Outside {
1000                return Ok(true);
1001            }
1002        }
1003        Ok(false)
1004    };
1005
1006    let mut chosen_offsets = Vec::new();
1007    let mut chosen_walls = Vec::new();
1008    for (index, carrier) in carriers.iter().enumerate() {
1009        let raw_seed = source_seed(source, carrier.source_face_id)?;
1010        let seed = if matches!(carrier.kind, OffsetFaceRole::Offset) {
1011            offset_seed(
1012                source_by_id[&carrier.source_face_id],
1013                raw_seed,
1014                &split_carriers[index].shells[0].faces[0].surface,
1015                distance,
1016                2e-3f64.max(scale * 5e-5),
1017            )?
1018            .unwrap_or(raw_seed)
1019        } else {
1020            raw_seed
1021        };
1022        if seed.sub(raw_seed).length() > 1e-9 {
1023            os_debug!(
1024                "  seed[{index}] moved from ({:.4},{:.4}) to the offset image ({:.4},{:.4})",
1025                raw_seed.x,
1026                raw_seed.y,
1027                seed.x,
1028                seed.y
1029            );
1030        }
1031        if matches!(carrier.kind, OffsetFaceRole::Offset) {
1032            // Fragments whose test point sits at the full offset distance
1033            // from every retained source face are the true offset-skin
1034            // regions. Fragments closer to some other face are shadowed
1035            // pockets/strips that another carrier owns. Only fall back to the
1036            // unfiltered set when nothing qualifies (numerical safety net).
1037            let on_skin = fragments_by_carrier[index]
1038                .iter()
1039                .map(|fragment| {
1040                    point_on_offset_skin(
1041                        fragment.test_point,
1042                        &retained_faces_with_edges,
1043                        distance,
1044                        offset_skin_tolerance,
1045                    )
1046                })
1047                .collect::<Result<Vec<_>, String>>()?;
1048            let skin_filter_active = on_skin.iter().any(|flag| *flag);
1049            let mut classified = Vec::new();
1050            let mut viable = Vec::new();
1051            for (fragment_index, fragment) in fragments_by_carrier[index].iter().enumerate() {
1052                let class = classify_point(fragment.test_point, source, tolerance * 10.0)?.class;
1053                let excluded_by_class = (distance > 0.0 && class == PointClass::Out)
1054                    || (distance < 0.0 && class == PointClass::In);
1055                let contact = if excluded_by_class {
1056                    false
1057                } else {
1058                    distance > 0.0
1059                        && fragment_has_sustained_source_contact(
1060                            fragment,
1061                            &source_faces,
1062                            &assembly_sources,
1063                            &imprint,
1064                            2e-3f64.max(scale * 5e-5),
1065                        )?
1066                };
1067                os_debug!(
1068                    "  select[{index}.{fragment_index}] class={class:?} contact={contact} on_skin={} seed_in={:?} uv=({:.3},{:.3})",
1069                    on_skin[fragment_index],
1070                    parameter_point_in_face(&fragment_as_trim(fragment), seed, 1e-8),
1071                    fragment.test_uv.x, fragment.test_uv.y,
1072                );
1073                if excluded_by_class || (skin_filter_active && !on_skin[fragment_index]) {
1074                    continue;
1075                }
1076                classified.push(fragment.clone());
1077                if contact {
1078                    continue;
1079                }
1080                viable.push(fragment.clone());
1081            }
1082            os_debug!("  select[{index}] seed=({:.4},{:.4})", seed.x, seed.y);
1083            let seeded = viable
1084                .iter()
1085                .filter(|fragment| {
1086                    parameter_point_in_face(&fragment_as_trim(fragment), seed, 1e-8)
1087                        .is_ok_and(|class| class != PolygonClass::Outside)
1088                })
1089                .cloned()
1090                .collect::<Vec<_>>();
1091            let seeded_classified = classified
1092                .iter()
1093                .filter(|fragment| {
1094                    parameter_point_in_face(&fragment_as_trim(fragment), seed, 1e-8)
1095                        .is_ok_and(|class| class != PolygonClass::Outside)
1096                })
1097                .cloned()
1098                .collect::<Vec<_>>();
1099            let selected = if viable.is_empty() {
1100                if !skin_filter_active {
1101                    // NOTHING on this carrier reads on-skin: every classified
1102                    // fragment's test point is measurably CLOSER than the
1103                    // offset distance to some retained face — a buried strip
1104                    // another carrier owns. Forcing the largest one in anyway
1105                    // plants a wrong skin patch that collides with the
1106                    // completion phase's reconstruction (3-use edges).
1107                    // Contribute nothing: `complete_opening_boundary_cycles`
1108                    // rebuilds the true skin from the carrier surface, and the
1109                    // watertight gate still refuses if it cannot.
1110                    None
1111                } else {
1112                    let mut by_area = classified
1113                        .into_iter()
1114                        .map(|fragment| {
1115                            let area = parameter_space_area(&fragment_as_trim(&fragment))?.abs();
1116                            Ok((fragment, area))
1117                        })
1118                        .collect::<Result<Vec<_>, String>>()?;
1119                    by_area.sort_by(|a, b| b.1.total_cmp(&a.1));
1120                    by_area.into_iter().next().map(|entry| entry.0)
1121                }
1122            } else if !seeded_classified.is_empty() {
1123                let mut candidates = seeded_classified;
1124                candidates.sort_by(|a, b| {
1125                    a.test_uv
1126                        .sub(seed)
1127                        .length()
1128                        .total_cmp(&b.test_uv.sub(seed).length())
1129                });
1130                candidates.into_iter().next()
1131            } else if viable.len() > 2 {
1132                let mut by_area = viable
1133                    .into_iter()
1134                    .map(|fragment| {
1135                        let area = parameter_space_area(&fragment_as_trim(&fragment))?.abs();
1136                        Ok((fragment, area))
1137                    })
1138                    .collect::<Result<Vec<_>, String>>()?;
1139                by_area.sort_by(|a, b| b.1.total_cmp(&a.1));
1140                by_area.into_iter().next().map(|entry| entry.0)
1141            } else {
1142                let mut candidates = if seeded.is_empty() { viable } else { seeded };
1143                candidates.sort_by(|a, b| {
1144                    a.test_uv
1145                        .sub(seed)
1146                        .length()
1147                        .total_cmp(&b.test_uv.sub(seed).length())
1148                });
1149                candidates.into_iter().next()
1150            };
1151            if let Some(fragment) = selected {
1152                chosen_offsets.push(fragment);
1153            }
1154        } else {
1155            // Keep arrangement order stable. Besides making the result
1156            // reproducible, this matches the reference kernel's Set insertion
1157            // order when the final manifold-wall guard admits fragments.
1158            let opening = source_by_id[&carrier.source_face_id];
1159            let wall_seeds = opening_wall_seeds(
1160                opening,
1161                &split_carriers[index].shells[0].faces[0],
1162                source,
1163                &opening_set,
1164                distance,
1165            )?;
1166            // The wall-seed exemptions below rest on "the coplanar-rim weld
1167            // cuts the void hole later" — which only ever happens on PLANAR
1168            // opening carriers. A curved carrier (e.g. the sphere face used
1169            // directly as the opening) keeps its un-split fragment forever:
1170            // exempting it would seal the opening with the source face itself
1171            // and fabricate a closed hollow solid. Curved carriers therefore
1172            // get the strict void guard.
1173            let carrier_planar =
1174                surface_is_planar(&split_carriers[index].shells[0].faces[0].surface, tolerance)
1175                    .unwrap_or(false);
1176            let mut selected_indices = Vec::new();
1177            for (fragment_index, fragment) in fragments_by_carrier[index].iter().enumerate() {
1178                if parameter_point_in_face(&fragment_as_trim(fragment), seed, 1e-8)?
1179                    == PolygonClass::Outside
1180                {
1181                    if in_front_of_other_opening(index, fragment.test_point)? {
1182                        os_debug!(
1183                            "  wall[{index}.{fragment_index}] skipped: in front of another \
1184                             opening at ({:.3},{:.3},{:.3})",
1185                            fragment.test_point.x,
1186                            fragment.test_point.y,
1187                            fragment.test_point.z,
1188                        );
1189                        continue;
1190                    }
1191                    // Wall = the material cross-section exposed at the
1192                    // opening: every point of a genuine wall fragment lies
1193                    // WITHIN the offset distance of some retained face (it is
1194                    // the thickness between that face and its offset skin). A
1195                    // fragment at ≥ distance from EVERY retained face — and
1196                    // containing no expected wall seed (an un-split cap
1197                    // fragment can span both the void AND the wall annulus;
1198                    // the coplanar-rim weld cuts its hole later) — is the
1199                    // core's own cross-section: a HOLE in the opening (e.g.
1200                    // the corner void where a carve's offset circle passes
1201                    // just inside the opening's corner). Welding it shut
1202                    // would fabricate a wall over the void.
1203                    if point_on_offset_skin(
1204                        fragment.test_point,
1205                        &retained_faces_with_edges,
1206                        distance,
1207                        offset_skin_tolerance,
1208                    )? && !(carrier_planar
1209                        && wall_seeds.iter().any(|wall_seed| {
1210                            parameter_point_in_face(&fragment_as_trim(fragment), *wall_seed, 1e-8)
1211                                .is_ok_and(|class| class != PolygonClass::Outside)
1212                        }))
1213                    {
1214                        os_debug!(
1215                            "  wall[{index}.{fragment_index}] skipped: void cross-section at \
1216                             ({:.3},{:.3},{:.3})",
1217                            fragment.test_point.x,
1218                            fragment.test_point.y,
1219                            fragment.test_point.z,
1220                        );
1221                        continue;
1222                    }
1223                    selected_indices.push(fragment_index);
1224                }
1225            }
1226            for wall_seed in wall_seeds {
1227                let fragments = &fragments_by_carrier[index];
1228                let nearest_containing = fragments
1229                    .iter()
1230                    .enumerate()
1231                    .filter(|(_, fragment)| {
1232                        parameter_point_in_face(&fragment_as_trim(fragment), wall_seed, 1e-8)
1233                            .is_ok_and(|class| class != PolygonClass::Outside)
1234                    })
1235                    .min_by(|(_, first), (_, second)| {
1236                        first
1237                            .test_uv
1238                            .sub(wall_seed)
1239                            .length()
1240                            .total_cmp(&second.test_uv.sub(wall_seed).length())
1241                    })
1242                    .map(|(fragment_index, _)| fragment_index);
1243                // Arrangement fitting can leave the seed just outside every
1244                // fragment by a small amount. Match the reference kernel's
1245                // geometric fallback instead of silently omitting the wall
1246                // fragment and leaving the assembled shell open.
1247                let nearest = if nearest_containing.is_some() {
1248                    nearest_containing
1249                } else {
1250                    let seed_point = split_carriers[index].shells[0].faces[0]
1251                        .surface
1252                        .evaluate(wall_seed.x, wall_seed.y)?;
1253                    fragments
1254                        .iter()
1255                        .enumerate()
1256                        .min_by(|(_, first), (_, second)| {
1257                            first
1258                                .test_point
1259                                .sub(seed_point)
1260                                .length()
1261                                .total_cmp(&second.test_point.sub(seed_point).length())
1262                        })
1263                        .map(|(fragment_index, _)| fragment_index)
1264                };
1265                if let Some(fragment_index) = nearest {
1266                    let candidate = &fragments_by_carrier[index][fragment_index];
1267                    if in_front_of_other_opening(index, candidate.test_point)? {
1268                        continue;
1269                    }
1270                    // Void-cross-section guard. On a PLANAR carrier it applies
1271                    // to the GEOMETRIC FALLBACK only: a fragment that
1272                    // genuinely contains this wall seed is wall content by
1273                    // construction (even when un-split it also spans void —
1274                    // the rim weld cuts the hole later), but a merely-nearest
1275                    // fragment must not resurrect a hole in the opening. On a
1276                    // CURVED carrier no later weld cuts the hole, so even a
1277                    // seed-containing fragment gets the strict guard.
1278                    if (nearest_containing.is_none() || !carrier_planar)
1279                        && point_on_offset_skin(
1280                            candidate.test_point,
1281                            &retained_faces_with_edges,
1282                            distance,
1283                            offset_skin_tolerance,
1284                        )?
1285                    {
1286                        os_debug!(
1287                            "  wall[{index}.{fragment_index}] seed-hit skipped: void \
1288                             cross-section (planar={carrier_planar}) at ({:.3},{:.3},{:.3})",
1289                            candidate.test_point.x,
1290                            candidate.test_point.y,
1291                            candidate.test_point.z,
1292                        );
1293                        continue;
1294                    }
1295                    let existing = chosen_offsets.iter().cloned().chain(
1296                        selected_indices
1297                            .iter()
1298                            .map(|selected| fragments_by_carrier[index][*selected].clone()),
1299                    );
1300                    if !selected_indices.contains(&fragment_index)
1301                        && !would_overuse_existing_boundary(
1302                            candidate,
1303                            existing,
1304                            &assembly_sources,
1305                            &imprint,
1306                            2e-3,
1307                        )?
1308                    {
1309                        selected_indices.push(fragment_index);
1310                    }
1311                }
1312            }
1313            for fragment_index in selected_indices.iter().copied() {
1314                chosen_walls.push(fragments_by_carrier[index][fragment_index].clone());
1315            }
1316        }
1317    }
1318    if debug_enabled() {
1319        for fragment in &chosen_offsets {
1320            os_debug!(
1321                "chosen offset: operand={} src={} test=({:.3},{:.3},{:.3})",
1322                fragment.operand,
1323                carriers[fragment.operand as usize].source_face_id,
1324                fragment.test_point.x,
1325                fragment.test_point.y,
1326                fragment.test_point.z,
1327            );
1328            for (loop_index, loop_record) in fragment.loops.iter().enumerate() {
1329                for coedge in &loop_record.coedges {
1330                    let surface = &fragment.surface;
1331                    let [c0, c1] = coedge.pcurve.domain().unwrap_or([0.0, 0.0]);
1332                    let uv0 = coedge.pcurve.evaluate(c0);
1333                    let uv1 = coedge.pcurve.evaluate(c1);
1334                    if let (Ok(uv0), Ok(uv1)) = (uv0, uv1) {
1335                        let p0 = surface.evaluate(uv0.x, uv0.y);
1336                        let p1 = surface.evaluate(uv1.x, uv1.y);
1337                        if let (Ok(p0), Ok(p1)) = (p0, p1) {
1338                            let kind = match &coedge.source {
1339                                FragmentEdgeSource::Boundary { edge_id, .. } => {
1340                                    format!("bnd:{edge_id}")
1341                                }
1342                                FragmentEdgeSource::SharedBoundary { edge_id, .. } => {
1343                                    format!("sbnd:{edge_id}")
1344                                }
1345                                FragmentEdgeSource::Imprint { piece_id } => {
1346                                    format!("imp:{piece_id}")
1347                                }
1348                                FragmentEdgeSource::Derived { .. } => "derived".to_string(),
1349                            };
1350                            os_debug!(
1351                                "    loop{loop_index} {kind} ({:.4},{:.4},{:.4})..({:.4},{:.4},{:.4})",
1352                                p0.x, p0.y, p0.z, p1.x, p1.y, p1.z,
1353                            );
1354                        }
1355                    }
1356                }
1357            }
1358        }
1359        for fragment in &chosen_walls {
1360            os_debug!(
1361                "chosen wall: operand={} src={} test=({:.3},{:.3},{:.3})",
1362                fragment.operand,
1363                carriers[fragment.operand as usize].source_face_id,
1364                fragment.test_point.x,
1365                fragment.test_point.y,
1366                fragment.test_point.z,
1367            );
1368        }
1369    }
1370    if chosen_offsets.is_empty() {
1371        return Err("offset_shell: carrier intersections produced no offset boundary".into());
1372    }
1373    // Opening-wall fragments can overlap at dense carrier junctions. The
1374    // seed-time guard above handles geometric containment; this final pass
1375    // mirrors the topology-level rule and counts exact fragment edge sources.
1376    let mut boundary_use_count = HashMap::<[i64; 9], usize>::default();
1377    for fragment in &chosen_offsets {
1378        for coedge in fragment
1379            .loops
1380            .iter()
1381            .flat_map(|loop_record| &loop_record.coedges)
1382        {
1383            let key = fragment_edge_segment_key(&coedge.source, &assembly_sources, &imprint)?;
1384            *boundary_use_count.entry(key).or_default() += 1;
1385        }
1386    }
1387    let mut manifold_walls = Vec::new();
1388    for fragment in chosen_walls {
1389        let keys = fragment
1390            .loops
1391            .iter()
1392            .flat_map(|loop_record| &loop_record.coedges)
1393            .map(|coedge| fragment_edge_segment_key(&coedge.source, &assembly_sources, &imprint))
1394            .collect::<Result<Vec<_>, _>>()?;
1395        if !keys
1396            .iter()
1397            .any(|key| boundary_use_count.get(key).copied().unwrap_or(0) >= 2)
1398        {
1399            for key in keys {
1400                *boundary_use_count.entry(key).or_default() += 1;
1401            }
1402            manifold_walls.push(fragment);
1403        }
1404    }
1405    os_debug!(
1406        "manifold walls kept: {} operands={:?}",
1407        manifold_walls.len(),
1408        manifold_walls
1409            .iter()
1410            .map(|fragment| fragment.operand)
1411            .collect::<Vec<_>>(),
1412    );
1413    let chosen_walls = manifold_walls;
1414
1415    let source_fragments = fragment_solid(source, SOURCE_OPERAND, &empty_imprint())?;
1416    let mut selected = source_fragments
1417        .into_iter()
1418        .filter(|fragment| retained.contains(&fragment.source_face_id))
1419        .collect::<Vec<_>>();
1420    let mut face_images = selected
1421        .iter()
1422        .map(|fragment| OffsetShellFaceImageRecord {
1423            role: OffsetFaceRole::Source,
1424            source_face_id: fragment.source_face_id,
1425        })
1426        .collect::<Vec<_>>();
1427    if distance < 0.0 {
1428        for fragment in &mut selected {
1429            flip_fragment(fragment)?;
1430        }
1431    }
1432    if distance > 0.0 {
1433        for fragment in &mut chosen_offsets {
1434            flip_fragment(fragment)?;
1435        }
1436    }
1437    face_images.extend(
1438        chosen_offsets
1439            .iter()
1440            .map(|fragment| OffsetShellFaceImageRecord {
1441                role: OffsetFaceRole::Offset,
1442                source_face_id: carriers[fragment.operand as usize].source_face_id,
1443            }),
1444    );
1445    face_images.extend(
1446        chosen_walls
1447            .iter()
1448            .map(|fragment| OffsetShellFaceImageRecord {
1449                role: OffsetFaceRole::Wall,
1450                source_face_id: carriers[fragment.operand as usize].source_face_id,
1451            }),
1452    );
1453    selected.extend(chosen_offsets);
1454    selected.extend(chosen_walls);
1455    let mut solid = assemble_open_fragments(
1456        selected,
1457        &assembly_sources,
1458        &imprint,
1459        2e-3f64.max(scale * 5e-5),
1460    )?;
1461    orient_open_solid_faces(&mut solid)?;
1462    let connector_images = complete_sharp_offset_connectors(
1463        &mut solid,
1464        source,
1465        &face_images,
1466        distance,
1467        2e-3f64.max(scale * 5e-5),
1468    )?;
1469    os_debug!(
1470        "sharp connector completion added {} faces",
1471        connector_images.len()
1472    );
1473    if !connector_images.is_empty() {
1474        // Wall fragments were arranged before the sharp seam was closed, so
1475        // their prospective inner boundary was an open chain. Rebuild the
1476        // wall from the now-closed source/offset cycles instead of retaining
1477        // that pre-connector fragment.
1478        for shell in &mut solid.shells {
1479            shell.faces.retain(|face| {
1480                !matches!(
1481                    face_images
1482                        .get(face.id.saturating_sub(1) as usize)
1483                        .map(|image| image.role),
1484                    Some(OffsetFaceRole::Wall)
1485                )
1486            });
1487        }
1488        solid.shells.retain(|shell| !shell.faces.is_empty());
1489    }
1490    face_images.extend(connector_images);
1491    orient_open_solid_faces(&mut solid)?;
1492    // Weld curved-face offset rims that the wall fragmentation left orphaned
1493    // into their coplanar opening cap (cylinder / straight-hole shells). This
1494    // is the seam-rim consistency step the offset pipeline previously lacked.
1495    let welded_rims = weld_coplanar_orphan_rims(&mut solid, 2e-3f64.max(scale * 5e-5))?;
1496    os_debug!("welded {welded_rims} coplanar orphan rims into opening caps");
1497    // Weld oblique-wall offset rims (truncated cone) into a ruled frustum
1498    // opening-wall band, rebuilding the flat cap the pipeline mis-builds.
1499    let ruled_rims = weld_ruled_offset_rims(&mut solid, 2e-3f64.max(scale * 5e-5))?;
1500    os_debug!("welded {ruled_rims} non-coplanar offset rims into ruled bands");
1501    // Weld leftover coaxial coplanar rim PAIRS (a through-hole's exposed wall
1502    // thickness at each opening) into new planar annulus faces.
1503    let pair_rims =
1504        weld_coplanar_rim_pair_annuli(&mut solid, &mut face_images, 2e-3f64.max(scale * 5e-5))?;
1505    os_debug!("welded {pair_rims} coplanar rim pairs into annulus walls");
1506    if debug_enabled() {
1507        for (shell_index, shell) in solid.shells.iter().enumerate() {
1508            for face in &shell.faces {
1509                os_debug!(
1510                    "POSTWELD shell {} face {} same_sense={} loops={}",
1511                    shell_index,
1512                    face.id,
1513                    face.same_sense,
1514                    face.loops.len()
1515                );
1516                for (loop_index, loop_record) in face.loops.iter().enumerate() {
1517                    let walk = loop_record
1518                        .coedges
1519                        .iter()
1520                        .map(|coedge| {
1521                            let spin = (|| -> Result<f64, String> {
1522                                let [d0, d1] = coedge.pcurve.domain()?;
1523                                let a = coedge.pcurve.evaluate(d0 + (d1 - d0) * 0.45)?;
1524                                let b = coedge.pcurve.evaluate(d0 + (d1 - d0) * 0.55)?;
1525                                let pa = face.surface.evaluate(a.x, a.y)?;
1526                                let pb = face.surface.evaluate(b.x, b.y)?;
1527                                Ok(pa.cross(pb).z)
1528                            })()
1529                            .unwrap_or(f64::NAN);
1530                            format!(
1531                                "{}{}(spin{:+.0})",
1532                                if coedge.forward { "+" } else { "-" },
1533                                coedge.edge_id,
1534                                spin.signum()
1535                            )
1536                        })
1537                        .collect::<Vec<_>>();
1538                    os_debug!("    loop {} {:?}", loop_index, walk);
1539                }
1540            }
1541        }
1542    }
1543    let completion_carriers = carriers.iter().collect::<Vec<_>>();
1544    let completion_tolerance = 2e-3f64.max(scale * 5e-5);
1545    // Unify geometric duplicate arc records BEFORE completion: a ring that is
1546    // already covered by both its faces (frustum + apex cap) must not read as
1547    // an open boundary, or completion papers over it with duplicate faces.
1548    let duplicate_welds = weld_duplicate_one_use_arcs(&mut solid, completion_tolerance)?;
1549    os_debug!("welded {duplicate_welds} duplicate one-use boundary arcs");
1550    if debug_enabled() {
1551        let mut use_counts = HashMap::<u64, usize>::default();
1552        for coedge in solid
1553            .shells
1554            .iter()
1555            .flat_map(|shell| &shell.faces)
1556            .flat_map(|face| &face.loops)
1557            .flat_map(|loop_record| &loop_record.coedges)
1558        {
1559            *use_counts.entry(coedge.edge_id).or_default() += 1;
1560        }
1561        let open = use_counts.values().filter(|count| **count == 1).count();
1562        os_debug!(
1563            "assembled: faces={} open_edges={open}",
1564            solid
1565                .shells
1566                .iter()
1567                .map(|shell| shell.faces.len())
1568                .sum::<usize>()
1569        );
1570    }
1571    let completed_images = complete_opening_boundary_cycles(
1572        &mut solid,
1573        &completion_carriers,
1574        &face_images,
1575        completion_tolerance,
1576    )?;
1577    os_debug!("completion added {} faces", completed_images.len());
1578    face_images.extend(completed_images);
1579    let solid = merge_same_surface_faces_open(&solid, (1e-7f64).max(scale * 1e-9))?;
1580    let assembly_tolerance = 2e-3f64.max(scale * 5e-5);
1581    // No faceted fallback here: an offset shell must be made of real analytic
1582    // surfaces. Failing loudly beats silently returning a tessellated BREP
1583    // with destroyed face provenance.
1584    let mut solid = finalize_assembled_solid(solid, assembly_tolerance)?;
1585    if ruled_rims + pair_rims > 0 {
1586        // A ruled-band or rim-pair weld joins independently-oriented skins;
1587        // put the whole finalized manifold on one normal convention so the
1588        // shell reports its exact wall volume (coplanar-only shells keep
1589        // their assembled sense).
1590        coheres_face_normals(&mut solid)?;
1591    }
1592    let solid = solid;
1593    face_images = solid
1594        .shells
1595        .iter()
1596        .flat_map(|shell| &shell.faces)
1597        .map(|face| {
1598            face_images
1599                .get(face.id.saturating_sub(1) as usize)
1600                .cloned()
1601                .ok_or_else(|| "offset_shell: merged face lost provenance".to_string())
1602        })
1603        .collect::<Result<Vec<_>, _>>()?;
1604    // A bore's end ring carries the bore wall's provenance whichever
1605    // construction built it (the opening's fragmentation or the rim-pair
1606    // weld), so its name does not depend on the path the rims took.
1607    let bore_rings = claim_bore_end_rings(&solid, &mut face_images)?;
1608    os_debug!("{bore_rings} bore end rings took the bore wall's provenance");
1609    // Honesty gate: a real rim left one-use is a hole in the shell that the
1610    // degenerate marking hides from `validate()` (degenerate edges are allowed
1611    // to be face-local). Refuse such a result instead of shipping a
1612    // non-watertight solid as valid. A rim is a CLOSED edge whose interior
1613    // sweeps measurably away from its seam vertex — a genuine circle, not a
1614    // legitimate pole point placeholder (which stays one-use by design).
1615    let mut rim_use_counts = HashMap::<u64, usize>::default();
1616    for coedge in solid
1617        .shells
1618        .iter()
1619        .flat_map(|shell| &shell.faces)
1620        .flat_map(|face| &face.loops)
1621        .flat_map(|loop_record| &loop_record.coedges)
1622    {
1623        *rim_use_counts.entry(coedge.edge_id).or_default() += 1;
1624    }
1625    if debug_enabled() {
1626        for (shell_index, shell) in solid.shells.iter().enumerate() {
1627            for face in &shell.faces {
1628                let role = face_images
1629                    .get(face.id.saturating_sub(1) as usize)
1630                    .map(|image| image.role);
1631                let c = face.surface.evaluate(0.5, 0.5).unwrap_or_default();
1632                os_debug!(
1633                    "DUMPFACE shell {} face {} affine={} role={:?} loops={} center=({:.3},{:.3},{:.3})",
1634                    shell_index, face.id, face.surface.is_affine().unwrap_or(false), role,
1635                    face.loops.len(), c.x, c.y, c.z
1636                );
1637                for (li, lp) in face.loops.iter().enumerate() {
1638                    let ids = lp.coedges.iter().map(|c| c.edge_id).collect::<Vec<_>>();
1639                    os_debug!("    loop {} edges {:?}", li, ids);
1640                }
1641            }
1642        }
1643        for edge in &solid.edges {
1644            let uses = rim_use_counts.get(&edge.id).copied().unwrap_or(0);
1645            let s = edge.curve.evaluate(edge.t0)?;
1646            let m = edge.curve.evaluate((edge.t0 + edge.t1) * 0.5)?;
1647            let q = edge.curve.evaluate(edge.t0 + (edge.t1 - edge.t0) * 0.25)?;
1648            os_debug!(
1649                "DUMPEDGE edge {} uses={} closed={} deg={} cpts={} cdeg={} knots={:?} start=({:.3},{:.3},{:.3}) q=({:.3},{:.3},{:.3}) mid=({:.3},{:.3},{:.3})",
1650                edge.id, uses, edge.start_vertex_id == edge.end_vertex_id, edge.degenerate,
1651                edge.curve.control_points.len(), edge.curve.degree, edge.curve.knots,
1652                s.x, s.y, s.z, q.x, q.y, q.z, m.x, m.y, m.z
1653            );
1654        }
1655    }
1656    for edge in &solid.edges {
1657        if rim_use_counts.get(&edge.id).copied().unwrap_or(0) != 1
1658            || edge.start_vertex_id != edge.end_vertex_id
1659        {
1660            continue;
1661        }
1662        let anchor = edge.curve.evaluate(edge.t0)?;
1663        let sweep_threshold = 1e-4f64.max(scale * 1e-6);
1664        let sweeps = [0.25, 0.5, 0.75].into_iter().any(|fraction| {
1665            edge.curve
1666                .evaluate(edge.t0 + (edge.t1 - edge.t0) * fraction)
1667                .map(|point| point.sub(anchor).length() > sweep_threshold)
1668                .unwrap_or(false)
1669        });
1670        if sweeps {
1671            if debug_enabled() {
1672                let rim_mid = edge.curve.evaluate((edge.t0 + edge.t1) * 0.5)?;
1673                os_debug!(
1674                    "PROBE orphan rim edge {} anchor=({:.4},{:.4},{:.4}) mid=({:.4},{:.4},{:.4})",
1675                    edge.id,
1676                    anchor.x,
1677                    anchor.y,
1678                    anchor.z,
1679                    rim_mid.x,
1680                    rim_mid.y,
1681                    rim_mid.z
1682                );
1683                for (shell_index, shell) in solid.shells.iter().enumerate() {
1684                    for face in &shell.faces {
1685                        let uses_rim = face
1686                            .loops
1687                            .iter()
1688                            .flat_map(|l| &l.coedges)
1689                            .any(|c| c.edge_id == edge.id);
1690                        let affine = face.surface.is_affine().unwrap_or(false);
1691                        let on = edge_on_surface(edge, &face.surface, 2e-3f64.max(scale * 5e-5))
1692                            .unwrap_or(false);
1693                        let proj = project_point_to_surface(&face.surface, rim_mid)?;
1694                        let contains = if on {
1695                            parameter_point_in_face(
1696                                face,
1697                                Vec2 {
1698                                    x: proj.u,
1699                                    y: proj.v,
1700                                },
1701                                2e-3f64.max(scale * 5e-5),
1702                            )? != PolygonClass::Outside
1703                        } else {
1704                            false
1705                        };
1706                        if on || uses_rim {
1707                            os_debug!(
1708                                "  face {} shell {} affine={} uses_rim={} on_surf={} proj_dist={:.5} contains={}",
1709                                face.id, shell_index, affine, uses_rim, on, proj.distance, contains
1710                            );
1711                        }
1712                    }
1713                }
1714            }
1715            return Err(format!(
1716                "offset_shell: unwelded rim leaves a non-watertight shell \
1717                 (one-use closed edge {} near ({:.3},{:.3},{:.3})); this \
1718                 curved-solid opening is not yet supported",
1719                edge.id, anchor.x, anchor.y, anchor.z
1720            ));
1721        }
1722    }
1723    Ok(OffsetShellResultRecord { solid, face_images })
1724}
1725
1726/// Run offset shell with stable counters and validation diagnostics suitable
1727/// for automated regressions and UI presentation.
1728pub fn offset_shell_with_diagnostics(
1729    source: &BrepSolid,
1730    opening_face_ids: &[u64],
1731    distance: f64,
1732    tolerances: Option<KernelTolerances>,
1733) -> Result<KernelOutcome<OffsetShellResultRecord>, String> {
1734    let policy = tolerances.unwrap_or_else(|| KernelTolerances::for_solid(source, 1e-7));
1735    policy.check()?;
1736    let mut diagnostics = KernelDiagnostics::default();
1737    diagnostics.count_n(
1738        "collect.source_faces",
1739        source
1740            .shells
1741            .iter()
1742            .map(|shell| shell.faces.len() as u64)
1743            .sum(),
1744    );
1745    diagnostics.count_n("collect.opening_faces", opening_face_ids.len() as u64);
1746    diagnostics.measure_max("offset.distance", distance.abs());
1747    diagnostics.measure_max("tolerance.model", policy.model);
1748    let result = offset_shell(source, opening_face_ids, distance)?;
1749    diagnostics.count_n(
1750        "sew.output_faces",
1751        result
1752            .solid
1753            .shells
1754            .iter()
1755            .map(|shell| shell.faces.len() as u64)
1756            .sum(),
1757    );
1758    diagnostics.count_n("sew.face_images", result.face_images.len() as u64);
1759    let validation = result.solid.validate_detailed(&policy);
1760    diagnostics.measure_max("validate.max_pcurve_error", validation.max_pcurve_error);
1761    diagnostics.count_n("validate.issues", validation.issues.len() as u64);
1762    diagnostics.count_n(
1763        "validate.wire_warnings",
1764        validation.wire_warnings.len() as u64,
1765    );
1766    for warning in validation.wire_warnings {
1767        diagnostics.event(
1768            DiagnosticSeverity::Warning,
1769            KernelStage::Validate,
1770            "validate.uv_wire",
1771            warning.message,
1772        );
1773    }
1774    if !validation.issues.is_empty() {
1775        for issue in &validation.issues {
1776            diagnostics.event(
1777                DiagnosticSeverity::Error,
1778                KernelStage::Validate,
1779                "validate.brep",
1780                issue.message.clone(),
1781            );
1782        }
1783        return Err(format!(
1784            "offset_shell: invalid diagnostic result: {:?}",
1785            validation.issues
1786        ));
1787    }
1788    Ok(KernelOutcome {
1789        value: result,
1790        diagnostics,
1791    })
1792}