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
87/// How far past the grown outline a planar opening wall that meets a RULED
88/// opening is padded, in units of the offset-skin band the wall selection reads
89/// (see the wall construction).
90///
91/// Measured on the torus wedge through the pipeline, grown by 0.05, 0.1, 0.5
92/// and 0.999 (band 2e-3): a clearance of 2 or 2.5 bands still shreds the cap
93/// into 22 to 36 faces with the area 5% to 11% high; from 4 bands on every
94/// member builds its 6 faces, and from 4 to 32 bands each member's volume moves
95/// by at most 1.2e-7. 16 sits four times above the first clean reading.
96const RULED_NEIGHBOUR_CLEARANCE_BANDS: f64 = 16.0;
97
98/// How far past its opening plane an inward carrier is grown, as a fraction of
99/// the shell distance (see the fall-short reach in the carrier loop).
100const REACH_CLEARANCE: f64 = 0.25;
101
102pub fn offset_shell(
103    source: &BrepSolid,
104    opening_face_ids: &[u64],
105    distance: f64,
106) -> Result<OffsetShellResultRecord, String> {
107    // Pinched source faces are un-modellable by the arrangement until the
108    // touch is a vertex; do it once here so BOTH `offset_shell_impl` attempts
109    // and every carrier built from the source see the same topology.
110    let prepared = split_self_touching_source(source)?;
111    let source = prepared.as_ref().unwrap_or(source);
112    // An outward shell of the one circular face of a partial revolve is planar
113    // in the meridian half-plane, fold band and all: build it there and revolve
114    // it once (`revolved_wedge.rs`). Anything else declines and takes the
115    // imprint pipeline, unchanged.
116    match revolved_wedge::recognize(source, opening_face_ids, distance) {
117        Ok(revolved_wedge::Recognition::Wedge(wedge)) => {
118            os_debug!("revolved wedge lane: {}", wedge.report());
119            return revolved_wedge::build(&wedge, source);
120        }
121        Ok(revolved_wedge::Recognition::Declined(reason)) => {
122            os_debug!("revolved wedge lane declined: {reason}");
123        }
124        // A source the lane cannot even read is not one it takes; the pipeline
125        // owns every refusal.
126        Err(error) => {
127            os_debug!("revolved wedge lane declined: could not read the source ({error})");
128        }
129    }
130    imprint_attempts(source, opening_face_ids, distance)
131}
132
133
134fn imprint_attempts(
135    source: &BrepSolid,
136    opening_face_ids: &[u64],
137    distance: f64,
138) -> Result<OffsetShellResultRecord, String> {
139    // First try with oblique hole-wall carriers extended past their opening
140    // planes (the lane that closes tilted/conical through-holes). If that
141    // extension fired but the arrangement could not assemble the harder
142    // configuration it produced (e.g. the extended bore genuinely intersects
143    // other offset walls), fall back to the un-extended pipeline so every
144    // previously-supported shape keeps its exact path and every refusal keeps
145    // the canonical honesty-gate message.
146    let mut extension_fired = false;
147    let mut reflex_rebuilds = 0usize;
148    let mut shadowed_points = Vec::new();
149    let mut omitted = HashSet::default();
150    let mut vacated_notes = Vec::new();
151    let result = match offset_shell_impl(
152        source,
153        opening_face_ids,
154        distance,
155        true,
156        &mut extension_fired,
157        &mut reflex_rebuilds,
158        &HashSet::default(),
159        &mut shadowed_points,
160        &mut omitted,
161        &mut vacated_notes,
162    ) {
163        Ok(result) => {
164            // Attribution marker: which pipeline produced this result. A
165            // retry-produced Ok can silently mask a broken extension lane —
166            // always say which attempt won. The reflex-rebuild count rides
167            // along because that lane fires on BOTH attempts: "extension
168            // idle" alone would misread as "the plain pipeline did this".
169            os_debug!(
170                "offset_shell result: FIRST attempt (extension {}, reflex-rebuilt {})",
171                if extension_fired { "fired" } else { "idle" },
172                reflex_rebuilds,
173            );
174            Ok(result)
175        }
176        Err(error) if extension_fired => {
177            os_debug!("extended pipeline failed ({error}); retrying without carrier extension");
178            let mut unused = false;
179            let mut retry_reflex = 0usize;
180            shadowed_points.clear();
181            omitted.clear();
182            let retried = offset_shell_impl(
183                source,
184                opening_face_ids,
185                distance,
186                false,
187                &mut unused,
188                &mut retry_reflex,
189                &HashSet::default(),
190                &mut shadowed_points,
191                &mut omitted,
192                &mut vacated_notes,
193            );
194            os_debug!(
195                "offset_shell result: RETRY without extension ({}, reflex-rebuilt {retry_reflex})",
196                if retried.is_ok() { "ok" } else { "err" },
197            );
198            retried
199        }
200        Err(error) => Err(error),
201    };
202    // A refusal from a shell whose selection saw two offsets CROSS inside
203    // material thinner than twice the distance says so first: a rib thinner
204    // than 2d shelled inward is that configuration, and the assembly's own
205    // message names only the symptom. A refusal that already names its cause
206    // keeps it. The crossing is looked for here, on the failure path only.
207    match result {
208        // A refusal that already names its CAUSE keeps its own sentence; one
209        // that names a symptom ("connector edge left its plane", an assembly
210        // message) is worth a cause in front of it. Reading the whole prefix as
211        // "anything this module wrote" was too wide: the twin bosses came out
212        // led by a notch sentence when their cause was the shadow cascade, and
213        // the partial cone lost its junction cause behind a connector's.
214        Err(error) if !refusal_names_its_cause(&error) => {
215            if let Some(crossing) =
216                name_offset_crossing(source, opening_face_ids, distance, &shadowed_points)
217            {
218                return Err(format!(
219                    "offset_shell: {crossing}; a skin partly shadowed that way is not yet \
220                     assembled ({error})"
221                ));
222            }
223            if let Some(junction) = name_retained_opening_junction(source, opening_face_ids, distance)
224            {
225                return Err(format!("offset_shell: {junction} ({error})"));
226            }
227            // A rim the closure could not bridge, with what it measured, in
228            // front of whatever the assembly then said about the hole it left.
229            match vacated_notes.first() {
230                Some(note) => Err(format!(
231                    "offset_shell: a rim vacated by an omitted support was left open — {note} \
232                     ({error})"
233                )),
234                None => Err(error),
235            }
236        }
237        result => result,
238    }
239}
240
241/// The refusals this module's own cause-naming lanes produce. Anything else is
242/// a symptom another stage reported, and takes a cause in front of it.
243fn refusal_names_its_cause(error: &str) -> bool {
244    [
245        " coincide near ",
246        "cannot tell whether",
247        "omitting the shadowed offsets of source faces",
248        "no retained face keeps any offset skin",
249        "is shadowed at every one of its",
250        "a rim vacated by an omitted support was left open",
251        "junction, so its offset ends inside the cavity",
252        "cross near",
253        // The opening-wall lane's own named refusals, so a cause of mine never
254        // arrives in front of one of theirs.
255        "folds where the carve",
256        "is curved and not a ruled surface",
257        "cannot be built",
258    ]
259    .iter()
260    .any(|name| error.contains(name))
261}
262
263fn offset_shell_impl(
264    source: &BrepSolid,
265    opening_face_ids: &[u64],
266    distance: f64,
267    extend_oblique_carriers: bool,
268    extension_fired: &mut bool,
269    reflex_rebuilds: &mut usize,
270    shadowed_supports: &HashSet<u64>,
271    shadowed_points: &mut Vec<(Vec3, u64)>,
272    omitted_supports: &mut HashSet<u64>,
273    vacated_notes: &mut Vec<String>,
274) -> Result<OffsetShellResultRecord, String> {
275    omitted_supports.clone_from(shadowed_supports);
276    vacated_notes.clear();
277    if !distance.is_finite() || distance.abs() <= MINIMUM_DISTANCE {
278        return Err("offset_shell: distance must be finite and non-zero".into());
279    }
280    if opening_face_ids.is_empty() {
281        return Err("offset_shell: at least one opening face is required".into());
282    }
283    let source_faces = source
284        .shells
285        .iter()
286        .flat_map(|shell| &shell.faces)
287        .collect::<Vec<_>>();
288    let opening_set = opening_face_ids.iter().copied().collect::<HashSet<_>>();
289    if opening_set
290        .iter()
291        .any(|id| !source_faces.iter().any(|face| face.id == *id))
292    {
293        return Err("offset_shell: opening face does not belong to source".into());
294    }
295    let retained = source_faces
296        .iter()
297        .filter(|face| !opening_set.contains(&face.id))
298        .map(|face| face.id)
299        .collect::<Vec<_>>();
300    if retained.is_empty() {
301        return Err("offset_shell: removing every face cannot produce a shell".into());
302    }
303    let mut carriers = Vec::new();
304    // Faces whose folded part was carved away, by source face id. Later stages
305    // that read a retained face's TRIM — the apex-cap scan below is the one —
306    // must read the carved trim, not the one the source still carries.
307    let mut carved_supports = HashMap::<u64, FaceRecord>::default();
308
309    for face_id in &retained {
310        let face = source_faces.iter().find(|face| face.id == *face_id).unwrap();
311        if offset_support_collapsed(face, distance)? {
312            os_debug!("omitting collapsed offset support for source face {face_id}");
313            continue;
314        }
315        // A support a previous pass found SHADOWED contributes no skin, and its
316        // carrier must not imprint its neighbours either — see the selection.
317        if shadowed_supports.contains(face_id) {
318            os_debug!("omitting shadowed offset support for source face {face_id}");
319            continue;
320        }
321        // A planar carrier whose source face meets a neighbour at a REFLEX
322        // (concave) edge extends its trim by |distance|: at such a junction
323        // the offset skin must GROW past the source footprint to meet the
324        // neighbour's offset (a pocket wall's source [5,15] → skin
325        // [3.5,16.5]); a source-sized trim leaves a gap no miter can bridge.
326        // The surplus at the face's convex ends is clipped by the imprints +
327        // on-skin filter. Convex-only faces keep their exact source-sized
328        // trim — extending them perturbs delicately-selected fragment
329        // landscapes for no benefit.
330        let miter = source_faces
331            .iter()
332            .find(|face| face.id == *face_id)
333            .map(|face| face_reflex_miter_tan(source, face))
334            .transpose()?
335            .flatten();
336        // The offsets of two faces joined at a reflex edge meet d·tan(θn/2)
337        // past the source rim — d only for a perpendicular join. Scale the
338        // extension to the worst sampled miter (×1.5 headroom so the true
339        // intersection lands strictly INSIDE the extended trim, never on its
340        // boundary where the arrangement drops boundary-coincident cuts) and
341        // cap it: a near-tangential join would ask for an unbounded trim.
342        let reflex_extension = miter.map(|worst_tan| {
343            (distance.abs() * worst_tan * 1.5)
344                .max(distance.abs())
345                .min(distance.abs() * 12.0)
346        });
347        if let Some(extension) = reflex_extension {
348            os_debug!("carrier for src face {face_id}: reflex-extended by {extension:.4}");
349        }
350        // OUTWARD: every retained carrier grows by |distance| across its
351        // sharp and opening-facing sides (the offsets of a convex junction
352        // meet past both source rims; a wall plane cuts the surplus), and
353        // by nothing across a smooth junction into a retained neighbour —
354        // see `outward_carrier_extension`. A reflex junction needs no
355        // outward growth at all (those offsets cross inside the trims).
356        let extension = if distance < 0.0 {
357            outward_carrier_extension(source, face, &source_faces, &opening_set, distance.abs())?
358        } else {
359            let mut inward = crate::CarrierExtension::uniform(reflex_extension.unwrap_or(0.0));
360            // An INWARD carrier that falls short of the planar opening it meets
361            // is grown until it crosses that plane, so the imprint cuts the
362            // skin there instead of leaving a rim for the ruled weld to cork
363            // below the opening (`fallshort_opening_reach`).
364            if let Some((at_v_max, reach)) =
365                fallshort_opening_reach(source, face, &source_faces, &opening_set, distance)?
366            {
367                // Past the plane by a quarter of the shell's own thickness, so
368                // the section is strictly inside the carrier's trim rather than
369                // on its boundary. Measured 2026-09-17 over the offset-shell
370                // suite: every fraction from 0.01 to 2.0 of |d| gives the same
371                // 73 passing members, while a margin sized in COINCIDENCE BANDS
372                // (1 to 32 of them, 2e-5 each here) breaks the sphere-under-
373                // frustum member by 9.4e-2 — the fragile margins are the ones
374                // far below the construction's own length.
375                let grown = reach + REACH_CLEARANCE * distance.abs();
376                if at_v_max {
377                    inward.v_max = inward.v_max.max(grown);
378                } else {
379                    inward.v_min = inward.v_min.max(grown);
380                }
381                os_debug!(
382                    "carrier for src face {face_id}: inward reach to its opening plane {reach:.6}                      at v_{} ",
383                    if at_v_max { "max" } else { "min" },
384                );
385            }
386            // A CURVED opening has no such construction, and the pipeline
387            // closes the cavity with whatever completion reaches for: measured
388            // 7.6% short on the hemisphere cup shelled through its dome.
389            if let Some((opening, gap)) =
390                offset_falls_short_of_curved_opening(source, face, &source_faces, &opening_set, distance)?
391            {
392                return Err(format!(
393                    "offset_shell: the offset skin of source face {face_id} stops {gap:.3e} short of \
394                     curved opening face {opening}; only a planar opening's skin is grown to meet it"
395                ));
396            }
397            inward
398        };
399        if distance < 0.0 {
400            os_debug!(
401                "carrier for src face {face_id}: outward extension u=({:.3},{:.3}) v=({:.3},{:.3})",
402                extension.u_min,
403                extension.u_max,
404                extension.v_min,
405                extension.v_max,
406            );
407        }
408        // CARVE: a support whose offset folds over PART of its trim keeps the
409        // regular part and drops the rest, instead of being built whole with
410        // the fold in it. The carrier is built over the CARVED source, so the
411        // trim it clones stops at the fold locus — and, because that trim no
412        // longer reaches past the offset's pinch, `offset_surface`'s apex-cone
413        // pinch retrim does not fire and the cloned pcurves still name the
414        // pointwise offset.
415        //
416        // A carve that cannot be made is not a licence to build the folded
417        // support anyway: the refusal is the answer, because a carrier with an
418        // inverted patch in it welds into a shell that validates and bounds the
419        // wrong solid.
420        let carved = carve_folded_support(source, face, distance)?;
421        let carrier_source = match &carved {
422            Some(carved) => {
423                os_debug!(
424                    "carving the fold off source face {face_id}: {:.1}% of its trim kept, \
425                     {} new boundary pcurve(s)",
426                    carved.kept_fraction * 100.0,
427                    carved.fold_boundary
428                );
429                carved_supports.insert(*face_id, carved.face.clone());
430                &carved.solid
431            }
432            None => source,
433        };
434        let mut carrier = carrier_solid_sided(carrier_source, *face_id, distance, &extension)?;
435        if (distance < 0.0 || reflex_extension.is_some()) && face.surface.is_affine()? {
436            // PADDED planes: the pad slides the plane's net while the trim's
437            // loops are cloned in uv, so an INTERIOR loop (a bore or boss rim
438            // in the face) is carried outward with the grown outline instead
439            // of following the neighbour's offset.
440            //   OUTWARD: a bore's rim grew (r=4.68 → 5.15) while the shrunk
441            //   offset bore (r=3.68) that must hole this plane fell inside the
442            //   enlarged void, so neither the imprint nor the orphan-rim weld
443            //   could cut it.
444            //   INWARD, reflex-extended: the same slide moves a REFLEX hole
445            //   rim the wrong way — a sphere sitting under a frustum's base
446            //   annulus (the user's 2026-09-07 document) had its r=8.3 rim
447            //   scaled to 9.22 while the shrunk offset sphere (r=7.3) crosses
448            //   the offset plane at r=7.23, inside the enlarged hole: the
449            //   pair imprint found nothing and the rim stayed one-use.
450            // Drop the interior loops (as the wall carriers do): the
451            // neighbour's carrier imprints — or its rim, welded in as a
452            // hole — cut the true opening, and the seeded selection drops
453            // the disk over it. A CONVEX interior rim on the same face (a
454            // through-bore in a pocket floor) is safe to drop too: its
455            // offset bore imprints at r+d and the ring inside is rejected by
456            // class (Out) or by the on-skin filter, no seed involved.
457            drop_wall_interior_loops(&mut carrier)?;
458        }
459        // The rim a shadowed support's removal VACATED in this carrier's trim:
460        // a slot narrower than 2|d| that runs out through this face leaves a
461        // notch its own skin has to close, because the dilation fills the slot.
462        // The source face keeps its notch; only the carrier is bridged.
463        if distance < 0.0 && !shadowed_supports.is_empty() {
464            let report = close_vacated_rims(
465                &mut carrier,
466                source_faces
467                    .iter()
468                    .find(|face| face.id == *face_id)
469                    .copied()
470                    .unwrap_or(face),
471                &source_faces,
472                shadowed_supports,
473            )?;
474            if report.closed > 0 {
475                os_debug!(
476                    "carrier for src face {face_id}: {} vacated rim run(s) bridged",
477                    report.closed
478                );
479            }
480            for declined in &report.declined {
481                os_debug!("carrier for src face {face_id}: vacated rim left alone — {declined}");
482                vacated_notes.push(format!("source face {face_id}: {declined}"));
483            }
484        }
485        carriers.push(Carrier {
486            solid: carrier,
487            source_face_id: *face_id,
488            kind: OffsetFaceRole::Offset,
489        });
490    }
491    // APEX-CAP carriers: a retained face whose DEGENERATE edge (an apex
492    // point, e.g. a conic crater's tip) offsets into a RING is an EXTERIOR
493    // cone offset — the parallel surface truncates at the ring and the exact
494    // rolling-ball offset closes it with a SPHERE of radius |distance| about
495    // the apex. Emit that sphere as an extra carrier: the ring imprint
496    // (sphere × offset frustum) splits it, the on-skin filter keeps exactly
497    // the cap sector (its points are |d| from the apex and ≥|d| from the
498    // rest of the face), and the ring becomes two-use.
499    let mut apex_cap_sources = HashSet::default();
500    let mut apex_cap_pairs: Vec<(usize, usize)> = Vec::new();
501    {
502        let retained_count = carriers.len();
503        for index in 0..retained_count {
504            // A CARVED support's trim is the carved one. Its coedges name edges
505            // that live only in the carved clone, so the `source.edges` lookup
506            // below finds nothing and the apex-cap lane skips the face — which
507            // is right: the carve already ended that carrier at the offset's own
508            // pinch, and there is no apex ring left to cap.
509            let carved_face = carved_supports.get(&carriers[index].source_face_id);
510            let source_face = carved_face
511                .or_else(|| source_by_id_lookup(&source_faces, carriers[index].source_face_id));
512            let Some(source_face) = source_face else {
513                continue;
514            };
515            let carrier_surface = carriers[index].solid.shells[0].faces[0].surface.clone();
516            for coedge in source_face
517                .loops
518                .iter()
519                .flat_map(|loop_record| &loop_record.coedges)
520            {
521                let Some(edge) = source
522                    .edges
523                    .iter()
524                    .find(|edge| edge.id == coedge.edge_id)
525                else {
526                    continue;
527                };
528                if !edge.degenerate {
529                    continue;
530                }
531                // Image of the degenerate edge on the offset surface.
532                let [p0, p1] = coedge.pcurve.domain()?;
533                let mut ring = Vec::new();
534                for sample in 0..=8 {
535                    let uv = coedge
536                        .pcurve
537                        .evaluate(p0 + (p1 - p0) * sample as f64 / 8.0)?;
538                    ring.push(carrier_surface.evaluate(uv.x, uv.y)?);
539                }
540                let spread = ring
541                    .iter()
542                    .map(|point| point.sub(ring[0]).length())
543                    .fold(0.0f64, f64::max);
544                if spread <= distance.abs() * 1e-2 {
545                    continue;
546                }
547                let apex = source
548                    .vertices
549                    .iter()
550                    .find(|vertex| vertex.id == edge.start_vertex_id)
551                    .map(|vertex| vertex.point)
552                    .ok_or_else(|| "offset_shell: apex vertex missing".to_string())?;
553                let centroid = ring
554                    .iter()
555                    .fold(Vec3::default(), |sum, point| sum.add(*point))
556                    .scale(1.0 / ring.len() as f64);
557                let axis = apex.sub(centroid);
558                let axis = if axis.length() > 1e-9 {
559                    axis.normalized()?
560                } else {
561                    Vec3::new(0.0, 0.0, 1.0)
562                };
563                os_debug!(
564                    "apex-cap carrier for src face {} at ({:.3},{:.3},{:.3}) r={:.3}",
565                    carriers[index].source_face_id,
566                    apex.x,
567                    apex.y,
568                    apex.z,
569                    distance.abs(),
570                );
571                apex_cap_sources.insert(index);
572                apex_cap_sources.insert(carriers.len());
573                apex_cap_pairs.push((index, carriers.len()));
574                carriers.push(Carrier {
575                    solid: crate::make_sphere_brep(apex, distance.abs(), axis)?,
576                    source_face_id: carriers[index].source_face_id,
577                    kind: OffsetFaceRole::Offset,
578                });
579            }
580        }
581    }
582    // A fold the carve's probe did not see (`outward_fold_the_carve_missed`):
583    // a band too thin for its grid is built whole, and the torus wedge grown by
584    // 1.001 then held the reflected lemon beyond its axis. Asked of every
585    // retained face the carve neither carved nor omitted, on every outward
586    // shell: a ruled wall is what first let the pipeline CLOSE such a shape,
587    // but the geometry is the trigger. Refused by name, the tangent onset
588    // included; a partial revolve of that kind is the revolved-wedge lane's
589    // question, and that lane runs in front of this pipeline.
590    if distance < 0.0 {
591        for face_id in &retained {
592            if carved_supports.contains_key(face_id)
593                || !carriers.iter().any(|carrier| carrier.source_face_id == *face_id)
594            {
595                continue;
596            }
597            let face = source_by_id_lookup(&source_faces, *face_id).unwrap();
598            if let Some(fold) = outward_fold_the_carve_missed(face, distance)? {
599                return Err(format!(
600                    "offset_shell: the outward offset of source face {face_id} folds where the carve \
601                     saw no fold (area factor {:.3e} at u={:.6}, v={:.6}); a fold band that thin is \
602                     not built",
603                    fold.factor, fold.u, fold.v
604                ));
605            }
606        }
607    }
608    // Wall carriers built as a RULED opening face extended along itself, by
609    // carrier index: the in-front guard reads their sides off the surface
610    // normal where it would read a plane's.
611    let mut ruled_walls = HashSet::default();
612    // OUTWARD through a CURVED opening. A ruled one — the cone a revolved
613    // straight profile edge sweeps, a cylinder — has its wall built as the
614    // opening face held in place and EXTENDED along itself, exactly as a plane
615    // is padded (`extended_ruled_wall`); the pad is the plane's, read off the
616    // same convex junctions. Built first, so the planar walls know which
617    // neighbours are ruled walls.
618    //
619    // Any other curved opening is refused by name. Its wall used to be the
620    // unpadded source face, which never reaches the grown offset: on a torus
621    // wedge whose chord revolves to a cone, the pair offset x cone cut 0
622    // pieces, the cone's one fragment was dropped as a void cross-section, and
623    // the result read "completion produced non-integral genus" with 12 open
624    // edges. No outward shell in the kernel suites or the case corpus closed
625    // through that wall (census, 2026-09-17).
626    let mut ruled_built = HashMap::<u64, BrepSolid>::default();
627    if distance < 0.0 {
628        for face_id in opening_face_ids {
629            let source_face = source_by_id_lookup(&source_faces, *face_id).unwrap();
630            if source_face.surface.is_affine()? {
631                continue;
632            }
633            if !ruled_opening(source_face)? {
634                return Err(format!(
635                    "offset_shell: opening face {face_id} is curved and not a ruled surface; an \
636                     outward wall is built only on a planar or ruled opening"
637                ));
638            }
639            let pad = outward_wall_pad(
640                source,
641                source_face,
642                &source_faces,
643                &opening_set,
644                distance.abs(),
645            )?;
646            let tolerance = 1e-7f64.max(crate::solid_scale(source) * 1e-9);
647            match extended_ruled_wall(source, source_face, pad, tolerance)? {
648                Ok(wall) => {
649                    os_debug!(
650                        "wall for opening face {face_id}: ruled, pad {pad:.4}, sides reach {:.4?}",
651                        wall.reached
652                    );
653                    ruled_built.insert(*face_id, wall.solid);
654                }
655                Err(reason) => {
656                    return Err(format!(
657                        "offset_shell: the outward wall of ruled opening face {face_id} cannot be \
658                         built: {reason}"
659                    ));
660                }
661            }
662        }
663    }
664    let ruled_openings = ruled_built
665        .keys()
666        .filter_map(|id| source_by_id_lookup(&source_faces, *id))
667        .collect::<Vec<_>>();
668    for face_id in opening_face_ids {
669        let source_face = source_faces
670            .iter()
671            .find(|face| face.id == *face_id)
672            .unwrap();
673        if let Some(wall) = ruled_built.remove(face_id) {
674            ruled_walls.insert(carriers.len());
675            carriers.push(Carrier {
676                solid: wall,
677                source_face_id: *face_id,
678                kind: OffsetFaceRole::Wall,
679            });
680            continue;
681        }
682        carriers.push(Carrier {
683            solid: if distance < 0.0 && source_face.surface.is_affine()? {
684                let pad = outward_wall_pad(
685                    source,
686                    source_face,
687                    &source_faces,
688                    &opening_set,
689                    distance.abs(),
690                )?;
691                // A plane meeting a RULED opening is padded past the grown
692                // outline, not onto it. Padded by exactly the pad, its trim's
693                // arc lands ON the grown offset's section wherever the join is
694                // perpendicular, and the ruled wall's section then ENDS on that
695                // coincident pair: on the torus wedge the cap shredded into 60
696                // slivers along the grown circle. The clearance is counted in
697                // the band that decides whether the strip beyond the grown
698                // outline is wall or void, so the strip always resolves as its
699                // own fragment and is dropped as void.
700                let pad = if ruled_openings
701                    .iter()
702                    .any(|ruled| source_faces_adjacent(source_face, ruled))
703                {
704                    pad + RULED_NEIGHBOUR_CLEARANCE_BANDS
705                        * offset_skin_band(crate::solid_scale(source), distance)
706                } else {
707                    pad
708                };
709                os_debug!("wall for opening face {face_id}: outward pad {pad:.4}");
710                // The wall is the opening's outline OFFSET by the pad in its
711                // own plane (`outline_offset.rs`). The pad used to SCALE that
712                // outline about the patch centre, which is the offset only for
713                // a rectangle filling its patch or a circle centred on it: an
714                // L-shaped opening's notch edges pass through the centre and
715                // did not move at all, so the notch faces' grown offsets
716                // crossed the plane outside the wall ("non-integral genus",
717                // `l-step-open-bottom` at d = −1.5 in the membrane census).
718                //
719                // An outline this module does not offset keeps the scaled wall,
720                // but only when that wall still COVERS the offset outline along
721                // every edge a retained face meets — which is what the sections
722                // have to land inside. Otherwise the shell refuses by name
723                // rather than assembling an open rim.
724                let mut scaled = carrier_solid(source, *face_id, 0.0, pad)?;
725                drop_wall_interior_loops(&mut scaled)?;
726                let mut wall = match offset_outline_wall(source, source_face, pad)? {
727                    Ok(outline) => {
728                        // Where the scaled wall already trims the offset
729                        // outline's own region — a rectangle filling its patch,
730                        // a circle centred on it — it is kept, so no shell that
731                        // was right before is rebuilt on a different patch.
732                        let same = walls_trim_the_same_region(
733                            &outline,
734                            &scaled,
735                            1e-9f64.max(crate::solid_scale(source) * 1e-11),
736                        )?;
737                        if same {
738                            os_debug!("wall for opening face {face_id}: scaled, which IS its outline offset");
739                            scaled
740                        } else {
741                            os_debug!("wall for opening face {face_id}: outline offset by {pad:.4}");
742                            outline
743                        }
744                    }
745                    Err(reason) => {
746                        if let Err(uncovered) = scaled_wall_covers_offset(
747                            source,
748                            source_face,
749                            &scaled,
750                            pad,
751                            &source_faces,
752                            &opening_set,
753                        )? {
754                            return Err(format!(
755                                "offset_shell: opening face {face_id}'s outline is not offset \
756                                 ({reason}), and its scaled outward wall does not cover the offset \
757                                 outline (a point of it lies {uncovered:.3e} outside)"
758                            ));
759                        }
760                        os_debug!(
761                            "wall for opening face {face_id}: scaled, which covers its offset ({reason})"
762                        );
763                        scaled
764                    }
765                };
766                // The pad extends the wall by STRETCHING the plane's 2x2 net
767                // while the trim pcurves are cloned in UV, so every loop
768                // scales about the patch centre by (w+2|d|)/w. For the OUTER
769                // loop of a full-domain rectangle that lands exactly on the
770                // grown outline — the intended wall extent. But an INTERIOR
771                // loop (a carve outline: a bore, gouge or crater rim in the
772                // opening face) is scaled OUTWARD too, and the enlarged hole
773                // then swallows both circles the wall must be cut by (the
774                // source carve rim from the wall x source imprint and the
775                // shrunk rim from the wall x offset-carrier imprint) — the
776                // imprints clip to nothing and the rims dangle one-use. Drop
777                // interior loops instead: the wall covers the carve mouth,
778                // the imprints cut the true rims, and selection (void-wall
779                // guard + on-skin filter) drops the fragments over the void.
780                drop_wall_interior_loops(&mut wall)?;
781                wall
782            } else {
783                standalone_face(source, *face_id)?
784            },
785            source_face_id: *face_id,
786            kind: OffsetFaceRole::Wall,
787        });
788    }
789    if carriers.len() >= SOURCE_OPERAND as usize {
790        return Err("offset_shell: too many carrier faces for current ABI".into());
791    }
792    // The characteristic length every tolerance below is derived from.  This
793    // was `max ‖vertex‖` — the distance from the WORLD ORIGIN — until audit
794    // slice 0: that form made every band widen as the part was moved away from
795    // the origin while ignoring the part's actual size, so the same shell
796    // solved to different tolerances depending only on where it was modelled.
797    // `solid_scale` is the bbox diagonal, floored at 1.0 exactly as the old
798    // fold was, so this changes ONE thing: placement-dependence.
799    let scale = crate::solid_scale(source);
800    crate::report_scale_migration("offset_shell", scale, || {
801        source
802            .vertices
803            .iter()
804            .map(|vertex| vertex.point.length())
805            .fold(1.0, f64::max)
806    });
807    let smooth = synchronize_smooth_offset_boundaries(&mut carriers, &source_faces, scale)?;
808    // Reflex-rim rebuilds run on BOTH attempts: the fallback for a broken
809    // extension is an honest refusal, but the fallback for a skipped reflex
810    // rebuild is a silently WRONG (membrane-capped) shell.
811    let reflex_rebuilt = rebuild_reflex_rim_carriers(
812        &mut carriers,
813        source,
814        &source_faces,
815        &smooth.pairs,
816        scale,
817        distance,
818    )?;
819    *reflex_rebuilds = reflex_rebuilt.len();
820    if extend_oblique_carriers {
821        let oblique_extended = extend_offset_carriers_past_open_hole_rims(
822            &mut carriers,
823            source,
824            &source_faces,
825            &opening_set,
826            &smooth.pairs,
827            scale,
828        )?;
829        let mut already_extended = oblique_extended.clone();
830        already_extended.extend(reflex_rebuilt.iter().copied());
831        let fallshort_extended = extend_fallshort_curved_carriers(
832            &mut carriers,
833            source,
834            &source_faces,
835            &opening_set,
836            &smooth.pairs,
837            &already_extended,
838            scale,
839            distance,
840        )?;
841        *extension_fired = !oblique_extended.is_empty() || fallshort_extended > 0;
842        os_debug!(
843            "extended {} oblique + {fallshort_extended} fall-short carriers past their opening planes",
844            oblique_extended.len(),
845        );
846    }
847    let tolerance = 1e-7f64.max(scale * 1e-9);
848    let pair_tolerance = (scale * 1e-8).max(2e-6);
849    let reach = distance.abs() * 4.0 + pair_tolerance;
850    let carrier_samples = carriers
851        .iter()
852        .map(|carrier| carrier_extent_points(&carrier.solid))
853        .collect::<Result<Vec<_>, _>>()?;
854    let carrier_bounds = carrier_samples
855        .iter()
856        .map(|samples| Bounds::from_points(samples))
857        .collect::<Option<Vec<_>>>()
858        .ok_or_else(|| "offset_shell: carrier has no boundary samples".to_string())?;
859    let source_by_id = source_faces
860        .iter()
861        .map(|face| (face.id, *face))
862        .collect::<HashMap<_, _>>();
863    let source_samples = source_faces
864        .iter()
865        .map(|face| {
866            let standalone = standalone_face(source, face.id)?;
867            Ok((face.id, edge_sample_points(&standalone)?))
868        })
869        .collect::<Result<HashMap<_, _>, String>>()?;
870    if debug_enabled() {
871        for (index, carrier) in carriers.iter().enumerate() {
872            let face = &carrier.solid.shells[0].faces[0];
873            let samples = &carrier_samples[index];
874            let bounds =
875                samples
876                    .iter()
877                    .fold((Vec3::default(), Vec3::default()), |(low, high), point| {
878                        (
879                            Vec3 {
880                                x: low.x.min(point.x),
881                                y: low.y.min(point.y),
882                                z: low.z.min(point.z),
883                            },
884                            Vec3 {
885                                x: high.x.max(point.x),
886                                y: high.y.max(point.y),
887                                z: high.z.max(point.z),
888                            },
889                        )
890                    });
891            let surface = &face.surface;
892            let rational = surface
893                .control_points
894                .iter()
895                .flatten()
896                .any(|point| (point.w - 1.0).abs() > 1e-12);
897            os_debug!(
898                "carrier[{index}] kind={:?} source_face={} loops={} deg=({},{}) net={}x{} rational={rational} bounds=({:.3},{:.3},{:.3})..({:.3},{:.3},{:.3})",
899                carrier.kind, carrier.source_face_id, face.loops.len(),
900                surface.degree_u, surface.degree_v,
901                surface.control_points.len(),
902                surface.control_points.first().map(|row| row.len()).unwrap_or(0),
903                bounds.0.x, bounds.0.y, bounds.0.z, bounds.1.x, bounds.1.y, bounds.1.z,
904            );
905        }
906        for (index, carrier) in carriers.iter().enumerate() {
907            if !matches!(carrier.kind, OffsetFaceRole::Offset) {
908                continue;
909            }
910            let source_face = source_by_id[&carrier.source_face_id];
911            let carrier_surface = &carrier.solid.shells[0].faces[0].surface;
912            let (ku, kv) = (
913                crate::KnotVector::new(
914                    source_face.surface.knots_u.clone(),
915                    source_face.surface.degree_u,
916                ),
917                crate::KnotVector::new(
918                    source_face.surface.knots_v.clone(),
919                    source_face.surface.degree_v,
920                ),
921            );
922            if let (Ok(ku), Ok(kv)) = (ku, kv) {
923                let [u0, u1] = ku.domain();
924                let [v0, v1] = kv.domain();
925                let mut worst = 0.0f64;
926                let mut worst_at = (0.0f64, 0.0f64);
927                for iu in 0..=24 {
928                    for iv in 0..=24 {
929                        let u = u0 + (u1 - u0) * iu as f64 / 24.0;
930                        let v = v0 + (v1 - v0) * iv as f64 / 24.0;
931                        let expected = face_offsets(source_face)
932                            .at(u, v, -distance)
933                            .map(|sample| sample.point);
934                        let actual = carrier_surface.evaluate(u, v);
935                        if let (Ok(expected), Ok(actual)) = (expected, actual) {
936                            let error = expected.sub(actual).length();
937                            if error > worst {
938                                worst = error;
939                                worst_at = (u, v);
940                            }
941                        }
942                    }
943                }
944                let mut normal_swing = 0.0f64;
945                let mut previous: Option<Vec3> = None;
946                for iu in 0..=48 {
947                    let u = u0 + (u1 - u0) * iu as f64 / 48.0;
948                    let v = (v0 + v1) / 2.0;
949                    if let Ok(normal) = face_normal(source_face, u, v) {
950                        if let Some(previous) = previous {
951                            normal_swing = normal_swing.max(previous.sub(normal).length());
952                        }
953                        previous = Some(normal);
954                    }
955                }
956                let weights = source_face
957                    .surface
958                    .control_points
959                    .iter()
960                    .flatten()
961                    .map(|point| point.w)
962                    .fold((f64::MAX, f64::MIN), |(low, high), w| {
963                        (low.min(w), high.max(w))
964                    });
965                os_debug!(
966                    "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={:?}",
967                    worst_at.0, worst_at.1,
968                    source_face.surface.control_points.len(),
969                    source_face.surface.control_points.first().map(|row| row.len()).unwrap_or(0),
970                    source_face.surface.degree_u, source_face.surface.degree_v,
971                    weights.0, weights.1,
972                    &source_face.surface.knots_u,
973                );
974            }
975        }
976        os_debug!("smooth pairs: {:?}", smooth.pairs);
977    }
978    let mut imprint = empty_imprint();
979    let mut next_piece_id = 1;
980    let mut next_vertex_id = 1;
981    for first in 0..carriers.len() {
982        for second in first + 1..carriers.len() {
983            let first_source = source_by_id[&carriers[first].source_face_id];
984            let second_source = source_by_id[&carriers[second].source_face_id];
985            if matches!(carriers[first].kind, OffsetFaceRole::Wall)
986                && matches!(carriers[second].kind, OffsetFaceRole::Wall)
987            {
988                // INWARD walls are the opening faces themselves: two openings
989                // never overlap and adjacent ones only touch along their
990                // shared edge, so there is nothing to imprint. OUTWARD walls
991                // are the opening planes EXTENDED by |distance|: the walls of
992                // two ADJACENT openings cross along the line of their shared
993                // source edge, and each wall ring must stop there (the sheet
994                // past that line lies in front of the other opening). Without
995                // the cut the wall × source chain below stays open on the
996                // shared-edge side (its neighbour there is an opening, not a
997                // retained face), the wall never fragments into its ring, and
998                // every source rim along both openings dangles one-use.
999                if distance > 0.0 || !source_faces_adjacent(first_source, second_source) {
1000                    continue;
1001                }
1002            }
1003            if smooth.pairs.contains(&(first, second)) {
1004                os_debug!("pair ({first},{second}) skipped: smooth");
1005                continue;
1006            }
1007            if !carrier_bounds[first].intersects(carrier_bounds[second], pair_tolerance) {
1008                os_debug!("pair ({first},{second}) skipped: bounds");
1009                continue;
1010            }
1011            if !source_faces_adjacent(first_source, second_source)
1012                && sample_separation(
1013                    &source_samples[&first_source.id],
1014                    &source_samples[&second_source.id],
1015                ) > reach
1016            {
1017                os_debug!("pair ({first},{second}) skipped: separation");
1018                continue;
1019            }
1020            let pair = match build_imprints(
1021                &carriers[first].solid,
1022                &carriers[second].solid,
1023                &ImprintOptions {
1024                    tolerance,
1025                    maximum_fit_points: 96,
1026                    // The GLOBAL interpolation lane. `local_fit: true` until
1027                    // 2026-09-13, which cost three orders on every smooth
1028                    // section: measured on the apex cone's base circle, the
1029                    // local lane needs 3,070 control points to reach 2.0e-5
1030                    // where the global one reaches 1.4e-8 with 384. What the
1031                    // local lane is for — a rim through a corner, where its
1032                    // monotonicity limiter holds a kink the global cubic rings
1033                    // across, 4.9x measured — is now the fit's own fallback:
1034                    // `fit_polyline` re-runs the other lane whenever the asked
1035                    // one cannot meet the tolerance and returns the better
1036                    // MEASURED curve, so this flag chooses which ladder is
1037                    // paid for first, never which curve is delivered.
1038                    local_fit: false,
1039                    fit_chunk_points: None,
1040                    // Offset carriers can meet in short, tightly curved
1041                    // branches. The general SSI default (diagonal / 15) is
1042                    // too coarse here and lets independently fitted branches
1043                    // miss a shared junction when thickness crosses one of
1044                    // those branches.
1045                    maximum_ssi_step: Some((scale * 0.0005).max(tolerance * 100.0)),
1046                },
1047            ) {
1048                Ok(pair) => pair,
1049                // A failed pair imprint (e.g. the marching SSI exhausting its
1050                // step budget on a long closed sphere/plane intersection) is
1051                // not fatal to the shell: the affected rim simply stays
1052                // unsplit and the rim-weld passes below get to close it. The
1053                // final watertightness gate still refuses anything the welds
1054                // cannot reach, so tolerating the miss only enlarges the
1055                // honest success set.
1056                Err(error) => {
1057                    os_debug!("pair ({first},{second}) imprint failed: {error}");
1058                    continue;
1059                }
1060            };
1061            let pieces_before = imprint.pieces.len();
1062            merge_pair_imprint(
1063                &mut imprint,
1064                pair,
1065                first as u8,
1066                second as u8,
1067                &mut next_piece_id,
1068                &mut next_vertex_id,
1069                tolerance,
1070                scale,
1071            );
1072            os_debug!(
1073                "pair ({first},{second}) src=({},{}) pieces+={}",
1074                carriers[first].source_face_id,
1075                carriers[second].source_face_id,
1076                imprint.pieces.len() - pieces_before,
1077            );
1078        }
1079    }
1080    if distance < 0.0 {
1081        // OUTWARD shells: the opening-wall carrier is the opening face's
1082        // plane EXTENDED by |distance|, so its trim carries only the GROWN
1083        // outline. Its inner boundary — where the wall ring stops at the
1084        // source solid — is the source outline, and the retained SOURCE faces
1085        // are not carriers, so no carrier×carrier pair ever imprints it.
1086        // Un-cut, the wall stays one whole-plane fragment covering the
1087        // opening void, and the source faces' rim edges dangle one-use.
1088        // Imprint each wall carrier against the retained source faces that
1089        // share an edge with its opening: the wall then fragments into the
1090        // ring (kept) and the opening hole (dropped by the void guard).
1091        for index in 0..carriers.len() {
1092            if !matches!(carriers[index].kind, OffsetFaceRole::Wall) {
1093                continue;
1094            }
1095            let opening = source_by_id[&carriers[index].source_face_id];
1096            for retained_id in &retained {
1097                let retained_face = source_by_id[retained_id];
1098                if !source_faces_adjacent(opening, retained_face) {
1099                    continue;
1100                }
1101                let neighbor = standalone_face(source, *retained_id)?;
1102                let pair = match build_imprints(
1103                    &carriers[index].solid,
1104                    &neighbor,
1105                    &ImprintOptions {
1106                        tolerance,
1107                        maximum_fit_points: 96,
1108                        // The global lane, as above.
1109                        local_fit: false,
1110                        fit_chunk_points: None,
1111                        maximum_ssi_step: Some((scale * 0.0005).max(tolerance * 100.0)),
1112                    },
1113                ) {
1114                    Ok(pair) => pair,
1115                    Err(error) => {
1116                        os_debug!(
1117                            "wall×source pair ({index},{retained_id}) imprint failed: {error}"
1118                        );
1119                        continue;
1120                    }
1121                };
1122                let pieces_before = imprint.pieces.len();
1123                merge_pair_imprint(
1124                    &mut imprint,
1125                    pair,
1126                    index as u8,
1127                    SOURCE_OPERAND,
1128                    &mut next_piece_id,
1129                    &mut next_vertex_id,
1130                    tolerance,
1131                    scale,
1132                );
1133                os_debug!(
1134                    "wall×source pair ({index},{retained_id}) pieces+={}",
1135                    imprint.pieces.len() - pieces_before,
1136                );
1137            }
1138        }
1139    }
1140    // APEX-CAP ring splits: the cap × cone section lies ON the cone
1141    // carrier's promoted ring edge (an overlap, not a crossing), so
1142    // `build_imprints` mints no edge splits for the cone side. Without them
1143    // the cone keeps ONE closed ring edge while the cap carries the section
1144    // as arcs — mismatched segmentation, both sides one-use. Record the arc
1145    // junctions as splits on the cone's coincident edge.
1146    for (cone_index, cap_index) in &apex_cap_pairs {
1147        let cap_face_id = carriers[*cap_index].solid.shells[0].faces[0].id;
1148        let piece_ids = imprint
1149            .by_face
1150            .iter()
1151            .find(|entry| entry.operand == *cap_index as u8 && entry.face_id == cap_face_id)
1152            .map(|entry| entry.piece_ids.clone())
1153            .unwrap_or_default();
1154        let coincidence_band = 2e-5f64.max(scale * 1e-7);
1155        for piece_id in piece_ids {
1156            let Some((curve, t0, t1)) = imprint
1157                .pieces
1158                .iter()
1159                .find(|piece| piece.id == piece_id)
1160                .map(|piece| (piece.curve.clone(), piece.t0, piece.t1))
1161            else {
1162                continue;
1163            };
1164            for endpoint in [curve.evaluate(t0)?, curve.evaluate(t1)?] {
1165                for edge in &carriers[*cone_index].solid.edges {
1166                    if edge.degenerate {
1167                        continue;
1168                    }
1169                    let projection = crate::project_point_to_curve(&edge.curve, endpoint)?;
1170                    if projection.distance > coincidence_band
1171                        || projection.u < edge.t0 + 1e-9
1172                        || projection.u > edge.t1 - 1e-9
1173                    {
1174                        continue;
1175                    }
1176                    let parameter = projection.u;
1177                    if let Some(existing) = imprint.edge_splits.iter_mut().find(|split| {
1178                        split.operand == *cone_index as u8 && split.edge_id == edge.id
1179                    }) {
1180                        if !existing
1181                            .parameters
1182                            .iter()
1183                            .any(|value| (*value - parameter).abs() <= 1e-8)
1184                        {
1185                            existing.parameters.push(parameter);
1186                        }
1187                    } else {
1188                        imprint.edge_splits.push(EdgeSplitRecord {
1189                            operand: *cone_index as u8,
1190                            edge_id: edge.id,
1191                            parameters: vec![parameter],
1192                        });
1193                    }
1194                    os_debug!(
1195                        "apex-cap ring split: cone carrier {cone_index} edge {} at t={parameter:.6}",
1196                        edge.id,
1197                    );
1198                }
1199            }
1200        }
1201    }
1202    if debug_enabled() {
1203        for piece in &imprint.pieces {
1204            let start = piece.curve.evaluate(piece.t0);
1205            let mid = piece.curve.evaluate((piece.t0 + piece.t1) * 0.5);
1206            let end = piece.curve.evaluate(piece.t1);
1207            if let (Ok(start), Ok(mid), Ok(end)) = (start, mid, end) {
1208                os_debug!(
1209                    "piece[{}] ({:.4},{:.4},{:.4})..({:.4},{:.4},{:.4})..({:.4},{:.4},{:.4})",
1210                    piece.id,
1211                    start.x,
1212                    start.y,
1213                    start.z,
1214                    mid.x,
1215                    mid.y,
1216                    mid.z,
1217                    end.x,
1218                    end.y,
1219                    end.z,
1220                );
1221            }
1222        }
1223    }
1224    synchronize_smooth_edge_splits(&mut imprint, &smooth.edge_pairs);
1225    // This decides whether an imprint is genuinely the carrier's existing
1226    // trim, not whether independently fitted curves can later be sewn. The
1227    // looser assembly tolerance can erase a short separating branch while it
1228    // is still departing a boundary.
1229    let boundary_coincidence_tolerance = 2e-5f64.max(scale * 1e-7);
1230    let piece_geometry = imprint
1231        .pieces
1232        .iter()
1233        .map(|piece| {
1234            (
1235                piece.id,
1236                FragmentEdgeGeometry {
1237                    curve: piece.curve.clone(),
1238                    t0: piece.t0,
1239                    t1: piece.t1,
1240                },
1241            )
1242        })
1243        .collect::<HashMap<_, _>>();
1244    for (index, carrier) in carriers.iter().enumerate() {
1245        if !matches!(carrier.kind, OffsetFaceRole::Offset) {
1246            continue;
1247        }
1248        let boundaries = carrier
1249            .solid
1250            .edges
1251            .iter()
1252            .map(|edge| FragmentEdgeGeometry {
1253                curve: edge.curve.clone(),
1254                t0: edge.t0,
1255                t1: edge.t1,
1256            })
1257            .collect::<Vec<_>>();
1258        if let Some(by_face) = imprint
1259            .by_face
1260            .iter_mut()
1261            .find(|entry| entry.operand == index as u8)
1262        {
1263            let before = by_face.piece_ids.clone();
1264            by_face.piece_ids.retain(|piece_id| {
1265                let piece = &piece_geometry[piece_id];
1266                !boundaries.iter().any(|boundary| {
1267                    fragment_edge_lies_on(piece, boundary, boundary_coincidence_tolerance)
1268                        .unwrap_or(false)
1269                })
1270            });
1271            if debug_enabled() && before.len() != by_face.piece_ids.len() {
1272                os_debug!(
1273                    "carrier[{index}] dropped boundary-coincident pieces: {:?} -> {:?}",
1274                    before,
1275                    by_face.piece_ids,
1276                );
1277            }
1278        }
1279    }
1280
1281    if debug_enabled() {
1282        for entry in &imprint.by_face {
1283            os_debug!(
1284                "by_face operand={} face={} pieces={:?}",
1285                entry.operand,
1286                entry.face_id,
1287                entry.piece_ids,
1288            );
1289        }
1290    }
1291    let mut split_carriers = Vec::new();
1292    let mut fragments_by_carrier = Vec::new();
1293    for (index, carrier) in carriers.iter().enumerate() {
1294        // Offset carriers keep their boundary un-split (their trims never
1295        // coincide with imprints — the boundary-coincidence filter drops such
1296        // pieces instead). An apex-cap ring breaks that assumption: the
1297        // frustum's ring is its TRIM boundary while the cap crosses it as TWO
1298        // imprint arcs — without splitting, the two sides segment differently
1299        // and both stay one-use. Split exactly the cap-affected carriers.
1300        let split = if matches!(carrier.kind, OffsetFaceRole::Offset)
1301            && !apex_cap_sources.contains(&index)
1302        {
1303            carrier.solid.clone()
1304        } else {
1305            apply_edge_splits(&carrier.solid, index as u8, &imprint)?
1306        };
1307        let fragments = fragment_solid(&split, index as u8, &imprint)?;
1308        os_debug!(
1309            "carrier[{index}] kind={:?} src={} fragments={}",
1310            carrier.kind,
1311            carrier.source_face_id,
1312            fragments.len(),
1313        );
1314        if debug_enabled() {
1315            for (fragment_index, fragment) in fragments.iter().enumerate() {
1316                let mut boundary_count = 0usize;
1317                let mut imprint_pieces = Vec::new();
1318                let mut derived_count = 0usize;
1319                for coedge in fragment
1320                    .loops
1321                    .iter()
1322                    .flat_map(|loop_record| &loop_record.coedges)
1323                {
1324                    match &coedge.source {
1325                        FragmentEdgeSource::Boundary { .. }
1326                        | FragmentEdgeSource::SharedBoundary { .. } => boundary_count += 1,
1327                        FragmentEdgeSource::Imprint { piece_id } => imprint_pieces.push(*piece_id),
1328                        FragmentEdgeSource::Derived { .. } => derived_count += 1,
1329                    }
1330                }
1331                os_debug!(
1332                    "  frag[{index}.{fragment_index}] test=({:.3},{:.3},{:.3}) uv=({:.3},{:.3}) boundary={boundary_count} derived={derived_count} pieces={imprint_pieces:?}",
1333                    fragment.test_point.x, fragment.test_point.y, fragment.test_point.z,
1334                    fragment.test_uv.x, fragment.test_uv.y,
1335                );
1336            }
1337        }
1338        split_carriers.push(split);
1339        fragments_by_carrier.push(fragments);
1340    }
1341    let mut assembly_sources = [(SOURCE_OPERAND, source)]
1342        .into_iter()
1343        .collect::<HashMap<_, _>>();
1344    for (index, carrier) in split_carriers.iter().enumerate() {
1345        assembly_sources.insert(index as u8, carrier);
1346    }
1347
1348    let source_edge_by_id = source
1349        .edges
1350        .iter()
1351        .map(|edge| (edge.id, edge))
1352        .collect::<HashMap<_, _>>();
1353    let retained_faces_with_edges = retained
1354        .iter()
1355        .map(|face_id| {
1356            let face = source_by_id[face_id];
1357            let edges = face
1358                .loops
1359                .iter()
1360                .flat_map(|loop_record| &loop_record.coedges)
1361                .filter_map(|coedge| source_edge_by_id.get(&coedge.edge_id).copied())
1362                .collect::<Vec<_>>();
1363            (face, edges)
1364        })
1365        .collect::<Vec<_>>();
1366    let offset_skin_tolerance = offset_skin_band(scale, distance);
1367    // OUTWARD shells: a wall fragment lying IN FRONT of another opening —
1368    // past that opening's plane on its void side, within the extent of its
1369    // (extended) wall carrier — is not material: an opening removes
1370    // everything in front of it. Such a fragment is the sheet of this wall
1371    // between the source outline and the grown outline on the far side of an
1372    // ADJACENT opening's shared edge (the x∈[−1,0] strip of an opened −Z
1373    // face's wall, in front of the opened −X face). It sits within |distance|
1374    // of a retained face's corner edge, so the void-cross-section guard reads
1375    // it as wall thickness; only the other opening's plane tells it apart.
1376    //
1377    // A RULED opening's wall is curved, so it has no one plane: its front is
1378    // read at the point's foot on the wall carrier, along the carrier's normal
1379    // turned to the opening face's outward side. On the torus wedge that is
1380    // what drops the start and end caps' strips beyond the extended chord,
1381    // which lie within |distance| of the torus and in front of the cone.
1382    let mut opening_planes: Vec<(usize, Vec3, Vec3)> = Vec::new();
1383    let mut opening_ruled: Vec<(usize, f64)> = Vec::new();
1384    if distance < 0.0 {
1385        for (index, carrier) in carriers.iter().enumerate() {
1386            if !matches!(carrier.kind, OffsetFaceRole::Wall) {
1387                continue;
1388            }
1389            let opening = source_by_id[&carrier.source_face_id];
1390            let [u0, u1] = opening.surface.domain_u()?;
1391            let [v0, v1] = opening.surface.domain_v()?;
1392            let (u, v) = ((u0 + u1) * 0.5, (v0 + v1) * 0.5);
1393            if ruled_walls.contains(&index) {
1394                let wall = &split_carriers[index].shells[0].faces[0];
1395                let probe = project_point_to_surface(&wall.surface, opening.surface.evaluate(u, v)?)?;
1396                let side = face_normal(wall, probe.u, probe.v)?.dot(face_normal(opening, u, v)?);
1397                opening_ruled.push((index, if side < 0.0 { -1.0 } else { 1.0 }));
1398                continue;
1399            }
1400            if !opening.surface.is_affine()? {
1401                continue;
1402            }
1403            opening_planes.push((
1404                index,
1405                opening.surface.evaluate(u, v)?,
1406                face_normal(opening, u, v)?,
1407            ));
1408        }
1409    }
1410    let in_front_of_other_opening = |wall_index: usize, point: Vec3| -> Result<bool, String> {
1411        let band = 2e-3f64.max(scale * 5e-5);
1412        for (index, plane_point, outward) in &opening_planes {
1413            if *index == wall_index || point.sub(*plane_point).dot(*outward) <= band {
1414                continue;
1415            }
1416            let face = &split_carriers[*index].shells[0].faces[0];
1417            let projection = project_point_to_surface(&face.surface, point)?;
1418            let uv = Vec2 {
1419                x: projection.u,
1420                y: projection.v,
1421            };
1422            if parameter_point_in_face(face, uv, 1e-8)? != PolygonClass::Outside {
1423                return Ok(true);
1424            }
1425        }
1426        for (index, side) in &opening_ruled {
1427            if *index == wall_index {
1428                continue;
1429            }
1430            let face = &split_carriers[*index].shells[0].faces[0];
1431            let projection = project_point_to_surface(&face.surface, point)?;
1432            let outward = face_normal(face, projection.u, projection.v)?.scale(*side);
1433            if point.sub(projection.point).dot(outward) <= band {
1434                continue;
1435            }
1436            let uv = Vec2 {
1437                x: projection.u,
1438                y: projection.v,
1439            };
1440            if parameter_point_in_face(face, uv, 1e-8)? != PolygonClass::Outside {
1441                return Ok(true);
1442            }
1443        }
1444        Ok(false)
1445    };
1446
1447    let mut chosen_offsets = Vec::new();
1448    let mut chosen_walls = Vec::new();
1449    let mut newly_shadowed = HashSet::<u64>::default();
1450    for (index, carrier) in carriers.iter().enumerate() {
1451        let raw_seeds = source_seeds(source, carrier.source_face_id)?;
1452        let mut seeds = Vec::with_capacity(raw_seeds.len());
1453        for raw_seed in raw_seeds {
1454            let seed = if matches!(carrier.kind, OffsetFaceRole::Offset) {
1455                offset_seed(
1456                    source_by_id[&carrier.source_face_id],
1457                    raw_seed,
1458                    &split_carriers[index].shells[0].faces[0].surface,
1459                    distance,
1460                    2e-3f64.max(scale * 5e-5),
1461                )?
1462                .unwrap_or(raw_seed)
1463            } else {
1464                raw_seed
1465            };
1466            if seed.sub(raw_seed).length() > 1e-9 {
1467                os_debug!(
1468                    "  seed[{index}] moved from ({:.4},{:.4}) to the offset image ({:.4},{:.4})",
1469                    raw_seed.x,
1470                    raw_seed.y,
1471                    seed.x,
1472                    seed.y
1473                );
1474            }
1475            seeds.push(seed);
1476        }
1477        let seed = seeds[0];
1478        if matches!(carrier.kind, OffsetFaceRole::Offset) {
1479            // Fragments whose test point sits at the full offset distance
1480            // from every retained source face are the true offset-skin
1481            // regions. Fragments closer to some other face are shadowed
1482            // pockets/strips that another carrier owns.
1483            let readings = fragments_by_carrier[index]
1484                .iter()
1485                .map(|fragment| {
1486                    offset_skin_reading(
1487                        fragment.test_point,
1488                        &retained_faces_with_edges,
1489                        distance,
1490                        offset_skin_tolerance,
1491                    )
1492                })
1493                .collect::<Vec<_>>();
1494            for (fragment, reading) in fragments_by_carrier[index].iter().zip(&readings) {
1495                if let SkinReading::Unmeasured { face, reason } = reading {
1496                    return Err(unmeasured_skin_refusal(fragment.test_point, *face, reason));
1497                }
1498            }
1499            // EVERY fragment measured nearer than the distance to some other
1500            // retained face: this support's offset is SHADOWED over its whole
1501            // extended carrier — the side walls of a slot narrower than 2|d|
1502            // grown outward, a pocket floor within 2d of the face under it.
1503            // It owns no skin. It used to switch the filter off and keep its
1504            // seeded fragment anyway, which built a closed, validating shell
1505            // with an inverted box inside it (+90 on a width-2 slot grown by
1506            // 1.5, with the 90 of material at its centre missing). Dropping
1507            // only its fragments is not enough: its carrier has already cut
1508            // its neighbours, and the top skin over that slot keeps a hole
1509            // nothing fills. So the pass is re-run with the support omitted
1510            // before the imprint, like a collapsed one. An apex-cap sphere
1511            // shares its cone's source id and is not judged here.
1512            //
1513            // Only the FIRST pass omits. A test point speaks for its fragment
1514            // because every other carrier's imprint bounds it; omitting a
1515            // carrier removes cuts, merges fragments and moves test points,
1516            // but changes no distance, so a support that reads shadowed only
1517            // AFTER an omission is reading a test point that no longer stands
1518            // for its fragment. Measured on two bosses 1 apart grown outward
1519            // by 1.5: once the facing boss walls were omitted, the plate's
1520            // grown top — one uncut fragment, mostly skin — read shadowed at
1521            // its single test point.
1522            //
1523            // "Every fragment" counts a fragment the selection would drop by
1524            // CLASS as not skin, as the selection does: the extended carrier's
1525            // surplus past a slot's end reads at least the distance from every
1526            // face, lies inside the source, and on a slot 1 wide grown outward
1527            // left the slot floor unjudged until the side walls were gone.
1528            // ADRIFT: a fragment whose test point is farther from its OWN face
1529            // than the distance, in the mitered metric, is not that face's skin
1530            // — it is inside the cavity, past where its neighbours' offsets cut
1531            // it. A rib, a pin or a divider thinner than 2d shelled inward
1532            // keeps such fragments, and the assembly then fails on them.
1533            let adrift = fragments_by_carrier[index]
1534                .iter()
1535                .map(|fragment| {
1536                    point_adrift_of_its_own_offset(
1537                        fragment.test_point,
1538                        carrier.source_face_id,
1539                        &retained_faces_with_edges,
1540                        distance,
1541                        offset_skin_tolerance,
1542                    )
1543                })
1544                .collect::<Vec<_>>();
1545            let mut skinless = readings
1546                .iter()
1547                .any(|reading| matches!(reading, SkinReading::Shadowed { .. }))
1548                || adrift.iter().any(|flag| *flag);
1549            for (fragment, reading) in fragments_by_carrier[index].iter().zip(&readings) {
1550                if !skinless {
1551                    break;
1552                }
1553                if matches!(reading, SkinReading::On)
1554                    && !adrift[fragments_by_carrier[index]
1555                        .iter()
1556                        .position(|other| std::ptr::eq(other, fragment))
1557                        .unwrap_or(0)]
1558                {
1559                    let class = classify_point(fragment.test_point, source, tolerance * 10.0)?.class;
1560                    skinless = (distance > 0.0 && class == PointClass::Out)
1561                        || (distance < 0.0 && class == PointClass::In);
1562                }
1563            }
1564            if skinless && !apex_cap_sources.contains(&index) {
1565                if !shadowed_supports.is_empty() {
1566                    let mut omitted = shadowed_supports.iter().copied().collect::<Vec<_>>();
1567                    omitted.sort_unstable();
1568                    return Err(format!(
1569                        "offset_shell: omitting the shadowed offsets of source faces {omitted:?} \
1570                         leaves the offset of source face {} shadowed at every one of its {} \
1571                         fragment test points, which no longer stand for their fragments once \
1572                         those carriers stop cutting it",
1573                        carrier.source_face_id,
1574                        readings.len()
1575                    ));
1576                }
1577                os_debug!(
1578                    "  select[{index}] src={} SHADOWED over all {} fragment(s): {:?}",
1579                    carrier.source_face_id,
1580                    readings.len(),
1581                    readings
1582                );
1583                newly_shadowed.insert(carrier.source_face_id);
1584                continue;
1585            }
1586            // Partly shadowed: keep a bounded sample of the shadowed test
1587            // points, so a refusal can say where two offsets cross.
1588            for (fragment, reading) in fragments_by_carrier[index].iter().zip(&readings) {
1589                if shadowed_points.len() >= MAXIMUM_CROSSING_READS {
1590                    break;
1591                }
1592                if matches!(reading, SkinReading::Shadowed { .. }) {
1593                    shadowed_points.push((fragment.test_point, carrier.source_face_id));
1594                }
1595            }
1596            let on_skin = readings
1597                .iter()
1598                .zip(&adrift)
1599                .map(|(reading, adrift)| matches!(reading, SkinReading::On) && !adrift)
1600                .collect::<Vec<_>>();
1601            let skin_filter_active = on_skin.iter().any(|flag| *flag);
1602            let mut classified = Vec::new();
1603            let mut viable = Vec::new();
1604            for (fragment_index, fragment) in fragments_by_carrier[index].iter().enumerate() {
1605                let class = classify_point(fragment.test_point, source, tolerance * 10.0)?.class;
1606                let excluded_by_class = (distance > 0.0 && class == PointClass::Out)
1607                    || (distance < 0.0 && class == PointClass::In);
1608                let contact = if excluded_by_class {
1609                    false
1610                } else {
1611                    distance > 0.0
1612                        && fragment_has_sustained_source_contact(
1613                            fragment,
1614                            &source_faces,
1615                            &assembly_sources,
1616                            &imprint,
1617                            2e-3f64.max(scale * 5e-5),
1618                        )?
1619                };
1620                os_debug!(
1621                    "  select[{index}.{fragment_index}] class={class:?} contact={contact} on_skin={} seed_in={:?} uv=({:.3},{:.3})",
1622                    on_skin[fragment_index],
1623                    parameter_point_in_face(&fragment_as_trim(fragment), seed, 1e-8),
1624                    fragment.test_uv.x, fragment.test_uv.y,
1625                );
1626                if excluded_by_class || (skin_filter_active && !on_skin[fragment_index]) {
1627                    continue;
1628                }
1629                classified.push(fragment.clone());
1630                if contact {
1631                    continue;
1632                }
1633                viable.push(fragment.clone());
1634            }
1635            // One skin per REGION of the source face (see `source_seeds`):
1636            // every region of a pinched face is offset like a face of its
1637            // own, and the selection below answers each region's seed. An
1638            // ordinary face has the one seed and the one answer it always had.
1639            let mut region_skins = Vec::new();
1640            for &seed in &seeds {
1641                os_debug!("  select[{index}] seed=({:.4},{:.4})", seed.x, seed.y);
1642                let seeded = viable
1643                    .iter()
1644                    .filter(|fragment| {
1645                        parameter_point_in_face(&fragment_as_trim(fragment), seed, 1e-8)
1646                            .is_ok_and(|class| class != PolygonClass::Outside)
1647                    })
1648                    .cloned()
1649                    .collect::<Vec<_>>();
1650                let seeded_classified = classified
1651                    .iter()
1652                    .filter(|fragment| {
1653                        parameter_point_in_face(&fragment_as_trim(fragment), seed, 1e-8)
1654                            .is_ok_and(|class| class != PolygonClass::Outside)
1655                    })
1656                    .cloned()
1657                    .collect::<Vec<_>>();
1658                let selected = if viable.is_empty() {
1659                    if !skin_filter_active {
1660                        // NOTHING on this carrier reads on-skin: every classified
1661                        // fragment's test point is measurably CLOSER than the
1662                        // offset distance to some retained face — a buried strip
1663                        // another carrier owns. Forcing the largest one in anyway
1664                        // plants a wrong skin patch that collides with the
1665                        // completion phase's reconstruction (3-use edges).
1666                        // Contribute nothing: `complete_opening_boundary_cycles`
1667                        // rebuilds the true skin from the carrier surface, and the
1668                        // watertight gate still refuses if it cannot.
1669                        None
1670                    } else {
1671                        let mut by_area = classified
1672                            .iter()
1673                            .cloned()
1674                            .map(|fragment| {
1675                                let area = parameter_space_area(&fragment_as_trim(&fragment))?.abs();
1676                                Ok((fragment, area))
1677                            })
1678                            .collect::<Result<Vec<_>, String>>()?;
1679                        by_area.sort_by(|a, b| b.1.total_cmp(&a.1));
1680                        by_area.into_iter().next().map(|entry| entry.0)
1681                    }
1682                } else if !seeded_classified.is_empty() {
1683                    let mut candidates = seeded_classified;
1684                    candidates.sort_by(|a, b| {
1685                        a.test_uv
1686                            .sub(seed)
1687                            .length()
1688                            .total_cmp(&b.test_uv.sub(seed).length())
1689                    });
1690                    candidates.into_iter().next()
1691                } else if viable.len() > 2 {
1692                    let mut by_area = viable
1693                        .iter()
1694                        .cloned()
1695                        .map(|fragment| {
1696                            let area = parameter_space_area(&fragment_as_trim(&fragment))?.abs();
1697                            Ok((fragment, area))
1698                        })
1699                        .collect::<Result<Vec<_>, String>>()?;
1700                    by_area.sort_by(|a, b| b.1.total_cmp(&a.1));
1701                    by_area.into_iter().next().map(|entry| entry.0)
1702                } else {
1703                    let mut candidates = if seeded.is_empty() { viable.clone() } else { seeded };
1704                    candidates.sort_by(|a, b| {
1705                        a.test_uv
1706                            .sub(seed)
1707                            .length()
1708                            .total_cmp(&b.test_uv.sub(seed).length())
1709                    });
1710                    candidates.into_iter().next()
1711                };
1712                if let Some(fragment) = &selected {
1713                    os_debug!(
1714                        "  select[{index}] src={} chosen test point departs its own face's offset \
1715                         distance by {:?}",
1716                        carrier.source_face_id,
1717                        own_offset_departure(
1718                            fragment.test_point,
1719                            carrier.source_face_id,
1720                            &retained_faces_with_edges,
1721                            distance
1722                        )
1723                    );
1724                    os_debug!(
1725                        "  select[{index}] src={} chosen test point departs in the MITER metric by {:?}",
1726                        carrier.source_face_id,
1727                        own_miter_departure(
1728                            fragment.test_point,
1729                            carrier.source_face_id,
1730                            &retained_faces_with_edges,
1731                            distance
1732                        )
1733                    );
1734                    if let Some((other, separation)) = coincident_offset_face(
1735                        fragment.test_point,
1736                        carrier.source_face_id,
1737                        &retained_faces_with_edges,
1738                        distance,
1739                        offset_skin_tolerance,
1740                    )? {
1741                        return Err(format!(
1742                            "offset_shell: the offsets of source faces {} and {other} coincide near \
1743                             ({:.4}, {:.4}, {:.4}) — the material between those faces is twice the \
1744                             shell distance thick (separation {separation:.6} against {:.6}, band \
1745                             {offset_skin_tolerance:.1e}), so the cavity between them has no \
1746                             thickness there; a cavity pinched to zero thickness is not supported",
1747                            carrier.source_face_id,
1748                            fragment.test_point.x,
1749                            fragment.test_point.y,
1750                            fragment.test_point.z,
1751                            distance.abs(),
1752                        ));
1753                    }
1754                }
1755                if let Some(fragment) = selected {
1756                    // A pinched face's seeds each find their own region; a
1757                    // fallback that ignores the seed can answer the same
1758                    // fragment twice, and one skin must enter once.
1759                    if !region_skins
1760                        .iter()
1761                        .any(|other: &FaceFragmentRecord| {
1762                            other.test_point.sub(fragment.test_point).length() <= 1e-12
1763                        })
1764                    {
1765                        region_skins.push(fragment);
1766                    }
1767                }
1768            }
1769            chosen_offsets.extend(region_skins);
1770        } else {
1771            // Keep arrangement order stable. Besides making the result
1772            // reproducible, this matches the reference kernel's Set insertion
1773            // order when the final manifold-wall guard admits fragments.
1774            let opening = source_by_id[&carrier.source_face_id];
1775            let wall_seeds = opening_wall_seeds(
1776                opening,
1777                &split_carriers[index].shells[0].faces[0],
1778                source,
1779                &opening_set,
1780                distance,
1781            )?;
1782            // The wall-seed exemptions below rest on "the coplanar-rim weld
1783            // cuts the void hole later" — which only ever happens on PLANAR
1784            // opening carriers. A curved carrier (e.g. the sphere face used
1785            // directly as the opening) keeps its un-split fragment forever:
1786            // exempting it would seal the opening with the source face itself
1787            // and fabricate a closed hollow solid. Curved carriers therefore
1788            // get the strict void guard.
1789            let carrier_planar =
1790                surface_is_planar(&split_carriers[index].shells[0].faces[0].surface, tolerance)
1791                    .unwrap_or(false);
1792            let mut selected_indices = Vec::new();
1793            for (fragment_index, fragment) in fragments_by_carrier[index].iter().enumerate() {
1794                if parameter_point_in_face(&fragment_as_trim(fragment), seed, 1e-8)?
1795                    == PolygonClass::Outside
1796                {
1797                    if in_front_of_other_opening(index, fragment.test_point)? {
1798                        os_debug!(
1799                            "  wall[{index}.{fragment_index}] skipped: in front of another \
1800                             opening at ({:.3},{:.3},{:.3})",
1801                            fragment.test_point.x,
1802                            fragment.test_point.y,
1803                            fragment.test_point.z,
1804                        );
1805                        continue;
1806                    }
1807                    // Wall = the material cross-section exposed at the
1808                    // opening: every point of a genuine wall fragment lies
1809                    // WITHIN the offset distance of some retained face (it is
1810                    // the thickness between that face and its offset skin). A
1811                    // fragment at ≥ distance from EVERY retained face — and
1812                    // containing no expected wall seed (an un-split cap
1813                    // fragment can span both the void AND the wall annulus;
1814                    // the coplanar-rim weld cuts its hole later) — is the
1815                    // core's own cross-section: a HOLE in the opening (e.g.
1816                    // the corner void where a carve's offset circle passes
1817                    // just inside the opening's corner). Welding it shut
1818                    // would fabricate a wall over the void.
1819                    if point_on_offset_skin(
1820                        fragment.test_point,
1821                        &retained_faces_with_edges,
1822                        distance,
1823                        offset_skin_tolerance,
1824                    )? && !(carrier_planar
1825                        && wall_seeds.iter().any(|wall_seed| {
1826                            parameter_point_in_face(&fragment_as_trim(fragment), *wall_seed, 1e-8)
1827                                .is_ok_and(|class| class != PolygonClass::Outside)
1828                        }))
1829                    {
1830                        os_debug!(
1831                            "  wall[{index}.{fragment_index}] skipped: void cross-section at \
1832                             ({:.3},{:.3},{:.3})",
1833                            fragment.test_point.x,
1834                            fragment.test_point.y,
1835                            fragment.test_point.z,
1836                        );
1837                        continue;
1838                    }
1839                    selected_indices.push(fragment_index);
1840                }
1841            }
1842            for wall_seed in wall_seeds {
1843                let fragments = &fragments_by_carrier[index];
1844                let nearest_containing = fragments
1845                    .iter()
1846                    .enumerate()
1847                    .filter(|(_, fragment)| {
1848                        parameter_point_in_face(&fragment_as_trim(fragment), wall_seed, 1e-8)
1849                            .is_ok_and(|class| class != PolygonClass::Outside)
1850                    })
1851                    .min_by(|(_, first), (_, second)| {
1852                        first
1853                            .test_uv
1854                            .sub(wall_seed)
1855                            .length()
1856                            .total_cmp(&second.test_uv.sub(wall_seed).length())
1857                    })
1858                    .map(|(fragment_index, _)| fragment_index);
1859                // Arrangement fitting can leave the seed just outside every
1860                // fragment by a small amount. Match the reference kernel's
1861                // geometric fallback instead of silently omitting the wall
1862                // fragment and leaving the assembled shell open.
1863                let nearest = if nearest_containing.is_some() {
1864                    nearest_containing
1865                } else {
1866                    let seed_point = split_carriers[index].shells[0].faces[0]
1867                        .surface
1868                        .evaluate(wall_seed.x, wall_seed.y)?;
1869                    fragments
1870                        .iter()
1871                        .enumerate()
1872                        .min_by(|(_, first), (_, second)| {
1873                            first
1874                                .test_point
1875                                .sub(seed_point)
1876                                .length()
1877                                .total_cmp(&second.test_point.sub(seed_point).length())
1878                        })
1879                        .map(|(fragment_index, _)| fragment_index)
1880                };
1881                if let Some(fragment_index) = nearest {
1882                    let candidate = &fragments_by_carrier[index][fragment_index];
1883                    if in_front_of_other_opening(index, candidate.test_point)? {
1884                        continue;
1885                    }
1886                    // Void-cross-section guard. On a PLANAR carrier it applies
1887                    // to the GEOMETRIC FALLBACK only: a fragment that
1888                    // genuinely contains this wall seed is wall content by
1889                    // construction (even when un-split it also spans void —
1890                    // the rim weld cuts the hole later), but a merely-nearest
1891                    // fragment must not resurrect a hole in the opening. On a
1892                    // CURVED carrier no later weld cuts the hole, so even a
1893                    // seed-containing fragment gets the strict guard.
1894                    if (nearest_containing.is_none() || !carrier_planar)
1895                        && point_on_offset_skin(
1896                            candidate.test_point,
1897                            &retained_faces_with_edges,
1898                            distance,
1899                            offset_skin_tolerance,
1900                        )?
1901                    {
1902                        os_debug!(
1903                            "  wall[{index}.{fragment_index}] seed-hit skipped: void \
1904                             cross-section (planar={carrier_planar}) at ({:.3},{:.3},{:.3})",
1905                            candidate.test_point.x,
1906                            candidate.test_point.y,
1907                            candidate.test_point.z,
1908                        );
1909                        continue;
1910                    }
1911                    let existing = chosen_offsets.iter().cloned().chain(
1912                        selected_indices
1913                            .iter()
1914                            .map(|selected| fragments_by_carrier[index][*selected].clone()),
1915                    );
1916                    if !selected_indices.contains(&fragment_index)
1917                        && !would_overuse_existing_boundary(
1918                            candidate,
1919                            existing,
1920                            &assembly_sources,
1921                            &imprint,
1922                            2e-3,
1923                        )?
1924                    {
1925                        selected_indices.push(fragment_index);
1926                    }
1927                }
1928            }
1929            for fragment_index in selected_indices.iter().copied() {
1930                chosen_walls.push(fragments_by_carrier[index][fragment_index].clone());
1931            }
1932        }
1933    }
1934    if debug_enabled() {
1935        for fragment in &chosen_offsets {
1936            os_debug!(
1937                "chosen offset: operand={} src={} test=({:.3},{:.3},{:.3})",
1938                fragment.operand,
1939                carriers[fragment.operand as usize].source_face_id,
1940                fragment.test_point.x,
1941                fragment.test_point.y,
1942                fragment.test_point.z,
1943            );
1944            for (loop_index, loop_record) in fragment.loops.iter().enumerate() {
1945                for coedge in &loop_record.coedges {
1946                    let surface = &fragment.surface;
1947                    let [c0, c1] = coedge.pcurve.domain().unwrap_or([0.0, 0.0]);
1948                    let uv0 = coedge.pcurve.evaluate(c0);
1949                    let uv1 = coedge.pcurve.evaluate(c1);
1950                    if let (Ok(uv0), Ok(uv1)) = (uv0, uv1) {
1951                        let p0 = surface.evaluate(uv0.x, uv0.y);
1952                        let p1 = surface.evaluate(uv1.x, uv1.y);
1953                        if let (Ok(p0), Ok(p1)) = (p0, p1) {
1954                            let kind = match &coedge.source {
1955                                FragmentEdgeSource::Boundary { edge_id, .. } => {
1956                                    format!("bnd:{edge_id}")
1957                                }
1958                                FragmentEdgeSource::SharedBoundary { edge_id, .. } => {
1959                                    format!("sbnd:{edge_id}")
1960                                }
1961                                FragmentEdgeSource::Imprint { piece_id } => {
1962                                    format!("imp:{piece_id}")
1963                                }
1964                                FragmentEdgeSource::Derived { .. } => "derived".to_string(),
1965                            };
1966                            os_debug!(
1967                                "    loop{loop_index} {kind} ({:.4},{:.4},{:.4})..({:.4},{:.4},{:.4})",
1968                                p0.x, p0.y, p0.z, p1.x, p1.y, p1.z,
1969                            );
1970                        }
1971                    }
1972                }
1973            }
1974        }
1975        for fragment in &chosen_walls {
1976            os_debug!(
1977                "chosen wall: operand={} src={} test=({:.3},{:.3},{:.3})",
1978                fragment.operand,
1979                carriers[fragment.operand as usize].source_face_id,
1980                fragment.test_point.x,
1981                fragment.test_point.y,
1982                fragment.test_point.z,
1983            );
1984        }
1985    }
1986    if !newly_shadowed.is_empty() {
1987        let mut omitted = shadowed_supports.clone();
1988        omitted.extend(newly_shadowed.iter().copied());
1989        os_debug!(
1990            "re-running without shadowed offset supports {:?} (omitted before: {:?})",
1991            newly_shadowed,
1992            shadowed_supports
1993        );
1994        // What this pass sampled belongs to carriers the next pass may not
1995        // build.
1996        shadowed_points.clear();
1997        return offset_shell_impl(
1998            source,
1999            opening_face_ids,
2000            distance,
2001            extend_oblique_carriers,
2002            extension_fired,
2003            reflex_rebuilds,
2004            &omitted,
2005            shadowed_points,
2006            omitted_supports,
2007            vacated_notes,
2008        );
2009    }
2010    if chosen_offsets.is_empty() && !shadowed_supports.is_empty() {
2011        let mut omitted = shadowed_supports.iter().copied().collect::<Vec<_>>();
2012        omitted.sort_unstable();
2013        return Err(format!(
2014            "offset_shell: no retained face keeps any offset skin once the shadowed offsets of \
2015             source faces {omitted:?} are omitted — the solid is nowhere thicker than twice the \
2016             shell distance, so there is no cavity to shell"
2017        ));
2018    }
2019    if chosen_offsets.is_empty() {
2020        return Err("offset_shell: carrier intersections produced no offset boundary".into());
2021    }
2022    // Opening-wall fragments can overlap at dense carrier junctions. The
2023    // seed-time guard above handles geometric containment; this final pass
2024    // mirrors the topology-level rule and counts exact fragment edge sources.
2025    let mut boundary_use_count = HashMap::<[i64; 9], usize>::default();
2026    for fragment in &chosen_offsets {
2027        for coedge in fragment
2028            .loops
2029            .iter()
2030            .flat_map(|loop_record| &loop_record.coedges)
2031        {
2032            let key = fragment_edge_segment_key(&coedge.source, &assembly_sources, &imprint)?;
2033            *boundary_use_count.entry(key).or_default() += 1;
2034        }
2035    }
2036    let mut manifold_walls = Vec::new();
2037    for fragment in chosen_walls {
2038        let keys = fragment
2039            .loops
2040            .iter()
2041            .flat_map(|loop_record| &loop_record.coedges)
2042            .map(|coedge| fragment_edge_segment_key(&coedge.source, &assembly_sources, &imprint))
2043            .collect::<Result<Vec<_>, _>>()?;
2044        if !keys
2045            .iter()
2046            .any(|key| boundary_use_count.get(key).copied().unwrap_or(0) >= 2)
2047        {
2048            for key in keys {
2049                *boundary_use_count.entry(key).or_default() += 1;
2050            }
2051            manifold_walls.push(fragment);
2052        }
2053    }
2054    os_debug!(
2055        "manifold walls kept: {} operands={:?}",
2056        manifold_walls.len(),
2057        manifold_walls
2058            .iter()
2059            .map(|fragment| fragment.operand)
2060            .collect::<Vec<_>>(),
2061    );
2062    let chosen_walls = manifold_walls;
2063
2064    let source_fragments = fragment_solid(source, SOURCE_OPERAND, &empty_imprint())?;
2065    let mut selected = source_fragments
2066        .into_iter()
2067        .filter(|fragment| retained.contains(&fragment.source_face_id))
2068        .collect::<Vec<_>>();
2069    let mut face_images = selected
2070        .iter()
2071        .map(|fragment| OffsetShellFaceImageRecord {
2072            role: OffsetFaceRole::Source,
2073            source_face_id: fragment.source_face_id,
2074        })
2075        .collect::<Vec<_>>();
2076    if distance < 0.0 {
2077        for fragment in &mut selected {
2078            flip_fragment(fragment)?;
2079        }
2080    }
2081    if distance > 0.0 {
2082        for fragment in &mut chosen_offsets {
2083            flip_fragment(fragment)?;
2084        }
2085    }
2086    face_images.extend(
2087        chosen_offsets
2088            .iter()
2089            .map(|fragment| OffsetShellFaceImageRecord {
2090                role: OffsetFaceRole::Offset,
2091                source_face_id: carriers[fragment.operand as usize].source_face_id,
2092            }),
2093    );
2094    face_images.extend(
2095        chosen_walls
2096            .iter()
2097            .map(|fragment| OffsetShellFaceImageRecord {
2098                role: OffsetFaceRole::Wall,
2099                source_face_id: carriers[fragment.operand as usize].source_face_id,
2100            }),
2101    );
2102    selected.extend(chosen_offsets);
2103    selected.extend(chosen_walls);
2104    let mut solid = assemble_open_fragments(
2105        selected,
2106        &assembly_sources,
2107        &imprint,
2108        2e-3f64.max(scale * 5e-5),
2109    )?;
2110    orient_open_solid_faces(&mut solid)?;
2111    let connector_images = complete_sharp_offset_connectors(
2112        &mut solid,
2113        source,
2114        &face_images,
2115        distance,
2116        2e-3f64.max(scale * 5e-5),
2117    )?;
2118    os_debug!(
2119        "sharp connector completion added {} faces",
2120        connector_images.len()
2121    );
2122    if !connector_images.is_empty() {
2123        // Wall fragments were arranged before the sharp seam was closed, so
2124        // their prospective inner boundary was an open chain. Rebuild the
2125        // wall from the now-closed source/offset cycles instead of retaining
2126        // that pre-connector fragment.
2127        for shell in &mut solid.shells {
2128            shell.faces.retain(|face| {
2129                !matches!(
2130                    face_images
2131                        .get(face.id.saturating_sub(1) as usize)
2132                        .map(|image| image.role),
2133                    Some(OffsetFaceRole::Wall)
2134                )
2135            });
2136        }
2137        solid.shells.retain(|shell| !shell.faces.is_empty());
2138    }
2139    face_images.extend(connector_images);
2140    orient_open_solid_faces(&mut solid)?;
2141    // Weld curved-face offset rims that the wall fragmentation left orphaned
2142    // into their coplanar opening cap (cylinder / straight-hole shells). This
2143    // is the seam-rim consistency step the offset pipeline previously lacked.
2144    let welded_rims = weld_coplanar_orphan_rims(&mut solid, 2e-3f64.max(scale * 5e-5))?;
2145    os_debug!("welded {welded_rims} coplanar orphan rims into opening caps");
2146    // A rim that is not a circle: a free-form or non-iso rim whose offset image
2147    // falls short of the opening. It runs after every earlier weld because it
2148    // only ever sees rims none of them closed.
2149    let rim_band = weld_free_form_rim_bands(
2150        &mut solid,
2151        &mut face_images,
2152        &carriers,
2153        source,
2154        2e-3f64.max(scale * 5e-5),
2155    )?;
2156    let rim_bands = rim_band.welded;
2157    os_debug!("welded {rim_bands} free-form rim bands");
2158    // Weld leftover coaxial coplanar rim PAIRS (a through-hole's exposed wall
2159    // thickness at each opening) into new planar annulus faces.
2160    let pair_rims =
2161        weld_coplanar_rim_pair_annuli(&mut solid, &mut face_images, 2e-3f64.max(scale * 5e-5))?;
2162    os_debug!("welded {pair_rims} coplanar rim pairs into annulus walls");
2163    if debug_enabled() {
2164        for (shell_index, shell) in solid.shells.iter().enumerate() {
2165            for face in &shell.faces {
2166                os_debug!(
2167                    "POSTWELD shell {} face {} same_sense={} loops={}",
2168                    shell_index,
2169                    face.id,
2170                    face.same_sense,
2171                    face.loops.len()
2172                );
2173                for (loop_index, loop_record) in face.loops.iter().enumerate() {
2174                    let walk = loop_record
2175                        .coedges
2176                        .iter()
2177                        .map(|coedge| {
2178                            let spin = (|| -> Result<f64, String> {
2179                                let [d0, d1] = coedge.pcurve.domain()?;
2180                                let a = coedge.pcurve.evaluate(d0 + (d1 - d0) * 0.45)?;
2181                                let b = coedge.pcurve.evaluate(d0 + (d1 - d0) * 0.55)?;
2182                                let pa = face.surface.evaluate(a.x, a.y)?;
2183                                let pb = face.surface.evaluate(b.x, b.y)?;
2184                                Ok(pa.cross(pb).z)
2185                            })()
2186                            .unwrap_or(f64::NAN);
2187                            format!(
2188                                "{}{}(spin{:+.0})",
2189                                if coedge.forward { "+" } else { "-" },
2190                                coedge.edge_id,
2191                                spin.signum()
2192                            )
2193                        })
2194                        .collect::<Vec<_>>();
2195                    os_debug!("    loop {} {:?}", loop_index, walk);
2196                }
2197            }
2198        }
2199    }
2200    let completion_carriers = carriers.iter().collect::<Vec<_>>();
2201    let completion_tolerance = 2e-3f64.max(scale * 5e-5);
2202    // Unify geometric duplicate arc records BEFORE completion: a ring that is
2203    // already covered by both its faces (frustum + apex cap) must not read as
2204    // an open boundary, or completion papers over it with duplicate faces.
2205    let duplicate_welds = weld_duplicate_one_use_arcs(&mut solid, completion_tolerance)?;
2206    os_debug!("welded {duplicate_welds} duplicate one-use boundary arcs");
2207    if debug_enabled() {
2208        let mut use_counts = HashMap::<u64, usize>::default();
2209        for coedge in solid
2210            .shells
2211            .iter()
2212            .flat_map(|shell| &shell.faces)
2213            .flat_map(|face| &face.loops)
2214            .flat_map(|loop_record| &loop_record.coedges)
2215        {
2216            *use_counts.entry(coedge.edge_id).or_default() += 1;
2217        }
2218        let open = use_counts.values().filter(|count| **count == 1).count();
2219        os_debug!(
2220            "assembled: faces={} open_edges={open}",
2221            solid
2222                .shells
2223                .iter()
2224                .map(|shell| shell.faces.len())
2225                .sum::<usize>()
2226        );
2227    }
2228    let completed_images = complete_opening_boundary_cycles(
2229        &mut solid,
2230        &completion_carriers,
2231        &face_images,
2232        completion_tolerance,
2233    )?;
2234    os_debug!("completion added {} faces", completed_images.len());
2235    face_images.extend(completed_images);
2236    let solid = merge_same_surface_faces_open(&solid, (1e-7f64).max(scale * 1e-9))?;
2237    let assembly_tolerance = 2e-3f64.max(scale * 5e-5);
2238    // No faceted fallback here: an offset shell must be made of real analytic
2239    // surfaces. Failing loudly beats silently returning a tessellated BREP
2240    // with destroyed face provenance.
2241    // A shell the rim band lane recognized but could not close fails here as it
2242    // always did; the refusal now carries the lane's reason.
2243    let mut solid = finalize_assembled_solid(solid, assembly_tolerance).map_err(|error| {
2244        let message = String::from(error);
2245        match &rim_band.decline {
2246            Some(reason) => format!("{message}; offset_shell: {reason}"),
2247            None => message,
2248        }
2249    })?;
2250    if rim_bands + pair_rims > 0 {
2251        // A rim-band or rim-pair weld joins independently-oriented skins;
2252        // put the whole finalized manifold on one normal convention so the
2253        // shell reports its exact wall volume (coplanar-only shells keep
2254        // their assembled sense).
2255        coheres_face_normals(&mut solid)?;
2256    }
2257    let solid = solid;
2258    face_images = solid
2259        .shells
2260        .iter()
2261        .flat_map(|shell| &shell.faces)
2262        .map(|face| {
2263            face_images
2264                .get(face.id.saturating_sub(1) as usize)
2265                .cloned()
2266                .ok_or_else(|| "offset_shell: merged face lost provenance".to_string())
2267        })
2268        .collect::<Result<Vec<_>, _>>()?;
2269    // A bore's end ring carries the bore wall's provenance whichever
2270    // construction built it (the opening's fragmentation or the rim-pair
2271    // weld), so its name does not depend on the path the rims took.
2272    let bore_rings = claim_bore_end_rings(&solid, &mut face_images)?;
2273    os_debug!("{bore_rings} bore end rings took the bore wall's provenance");
2274    // Honesty gate: a real rim left one-use is a hole in the shell that the
2275    // degenerate marking hides from `validate()` (degenerate edges are allowed
2276    // to be face-local). Refuse such a result instead of shipping a
2277    // non-watertight solid as valid. A rim is a CLOSED edge whose interior
2278    // sweeps measurably away from its seam vertex — a genuine circle, not a
2279    // legitimate pole point placeholder (which stays one-use by design).
2280    let mut rim_use_counts = HashMap::<u64, usize>::default();
2281    for coedge in solid
2282        .shells
2283        .iter()
2284        .flat_map(|shell| &shell.faces)
2285        .flat_map(|face| &face.loops)
2286        .flat_map(|loop_record| &loop_record.coedges)
2287    {
2288        *rim_use_counts.entry(coedge.edge_id).or_default() += 1;
2289    }
2290    if debug_enabled() {
2291        for (shell_index, shell) in solid.shells.iter().enumerate() {
2292            for face in &shell.faces {
2293                let role = face_images
2294                    .get(face.id.saturating_sub(1) as usize)
2295                    .map(|image| image.role);
2296                let c = face.surface.evaluate(0.5, 0.5).unwrap_or_default();
2297                os_debug!(
2298                    "DUMPFACE shell {} face {} affine={} role={:?} loops={} center=({:.3},{:.3},{:.3})",
2299                    shell_index, face.id, face.surface.is_affine().unwrap_or(false), role,
2300                    face.loops.len(), c.x, c.y, c.z
2301                );
2302                for (li, lp) in face.loops.iter().enumerate() {
2303                    let ids = lp.coedges.iter().map(|c| c.edge_id).collect::<Vec<_>>();
2304                    os_debug!("    loop {} edges {:?}", li, ids);
2305                }
2306            }
2307        }
2308        for edge in &solid.edges {
2309            let uses = rim_use_counts.get(&edge.id).copied().unwrap_or(0);
2310            let s = edge.curve.evaluate(edge.t0)?;
2311            let m = edge.curve.evaluate((edge.t0 + edge.t1) * 0.5)?;
2312            let q = edge.curve.evaluate(edge.t0 + (edge.t1 - edge.t0) * 0.25)?;
2313            os_debug!(
2314                "DUMPEDGE edge {} uses={} closed={} deg={} cpts={} cdeg={} knots={:?} start=({:.3},{:.3},{:.3}) q=({:.3},{:.3},{:.3}) mid=({:.3},{:.3},{:.3})",
2315                edge.id, uses, edge.start_vertex_id == edge.end_vertex_id, edge.degenerate,
2316                edge.curve.control_points.len(), edge.curve.degree, edge.curve.knots,
2317                s.x, s.y, s.z, q.x, q.y, q.z, m.x, m.y, m.z
2318            );
2319        }
2320    }
2321    for edge in &solid.edges {
2322        if rim_use_counts.get(&edge.id).copied().unwrap_or(0) != 1
2323            || edge.start_vertex_id != edge.end_vertex_id
2324        {
2325            continue;
2326        }
2327        let anchor = edge.curve.evaluate(edge.t0)?;
2328        let sweep_threshold = 1e-4f64.max(scale * 1e-6);
2329        let sweeps = [0.25, 0.5, 0.75].into_iter().any(|fraction| {
2330            edge.curve
2331                .evaluate(edge.t0 + (edge.t1 - edge.t0) * fraction)
2332                .map(|point| point.sub(anchor).length() > sweep_threshold)
2333                .unwrap_or(false)
2334        });
2335        if sweeps {
2336            if debug_enabled() {
2337                let rim_mid = edge.curve.evaluate((edge.t0 + edge.t1) * 0.5)?;
2338                os_debug!(
2339                    "PROBE orphan rim edge {} anchor=({:.4},{:.4},{:.4}) mid=({:.4},{:.4},{:.4})",
2340                    edge.id,
2341                    anchor.x,
2342                    anchor.y,
2343                    anchor.z,
2344                    rim_mid.x,
2345                    rim_mid.y,
2346                    rim_mid.z
2347                );
2348                for (shell_index, shell) in solid.shells.iter().enumerate() {
2349                    for face in &shell.faces {
2350                        let uses_rim = face
2351                            .loops
2352                            .iter()
2353                            .flat_map(|l| &l.coedges)
2354                            .any(|c| c.edge_id == edge.id);
2355                        let affine = face.surface.is_affine().unwrap_or(false);
2356                        let on = edge_on_surface(edge, &face.surface, 2e-3f64.max(scale * 5e-5))
2357                            .unwrap_or(false);
2358                        let proj = project_point_to_surface(&face.surface, rim_mid)?;
2359                        let contains = if on {
2360                            parameter_point_in_face(
2361                                face,
2362                                Vec2 {
2363                                    x: proj.u,
2364                                    y: proj.v,
2365                                },
2366                                2e-3f64.max(scale * 5e-5),
2367                            )? != PolygonClass::Outside
2368                        } else {
2369                            false
2370                        };
2371                        if on || uses_rim {
2372                            os_debug!(
2373                                "  face {} shell {} affine={} uses_rim={} on_surf={} proj_dist={:.5} contains={}",
2374                                face.id, shell_index, affine, uses_rim, on, proj.distance, contains
2375                            );
2376                        }
2377                    }
2378                }
2379            }
2380            return Err(format!(
2381                "offset_shell: unwelded rim leaves a non-watertight shell \
2382                 (one-use closed edge {} near ({:.3},{:.3},{:.3})); this \
2383                 curved-solid opening is not yet supported",
2384                edge.id, anchor.x, anchor.y, anchor.z
2385            ));
2386        }
2387    }
2388    // The shell's single exit. An offset skin that crosses another wall, or
2389    // folds through itself where the source turned tighter than the distance,
2390    // leaves a body that validates and measures — so it is asked here, and
2391    // repaired or refused by name rather than returned.
2392    let solid = crate::accept_sound(solid, "offsetShell")?;
2393    Ok(OffsetShellResultRecord { solid, face_images })
2394}
2395
2396/// Run offset shell with stable counters and validation diagnostics suitable
2397/// for automated regressions and UI presentation.
2398pub fn offset_shell_with_diagnostics(
2399    source: &BrepSolid,
2400    opening_face_ids: &[u64],
2401    distance: f64,
2402    tolerances: Option<KernelTolerances>,
2403) -> Result<KernelOutcome<OffsetShellResultRecord>, String> {
2404    let policy = tolerances.unwrap_or_else(|| KernelTolerances::for_solid(source, 1e-7));
2405    policy.check()?;
2406    let mut diagnostics = KernelDiagnostics::default();
2407    diagnostics.count_n(
2408        "collect.source_faces",
2409        source
2410            .shells
2411            .iter()
2412            .map(|shell| shell.faces.len() as u64)
2413            .sum(),
2414    );
2415    diagnostics.count_n("collect.opening_faces", opening_face_ids.len() as u64);
2416    diagnostics.measure_max("offset.distance", distance.abs());
2417    diagnostics.measure_max("tolerance.model", policy.model);
2418    // Tally every pcurve fit the shell makes (its own re-trims and any boolean
2419    // it runs) so `pcurve.unmet_floor` reports a trim that stopped at the
2420    // sample ceiling instead of passing it off as one that met the floor.
2421    let fit_scope = crate::PcurveFitScope::open();
2422    // Same for the polyline fits of its carrier×carrier sections, which is
2423    // where a marched rim's accuracy is decided (`geometry/fit.rs`).
2424    let polyline_scope = crate::PolylineFitScope::open();
2425    let result = offset_shell(source, opening_face_ids, distance)?;
2426    fit_scope.close().report_into(&mut diagnostics);
2427    polyline_scope.close().report_into(&mut diagnostics);
2428    diagnostics.count_n(
2429        "sew.output_faces",
2430        result
2431            .solid
2432            .shells
2433            .iter()
2434            .map(|shell| shell.faces.len() as u64)
2435            .sum(),
2436    );
2437    diagnostics.count_n("sew.face_images", result.face_images.len() as u64);
2438    let validation = result.solid.validate_detailed(&policy);
2439    diagnostics.measure_max("validate.max_pcurve_error", validation.max_pcurve_error);
2440    diagnostics.count_n("validate.issues", validation.issues.len() as u64);
2441    diagnostics.count_n(
2442        "validate.wire_warnings",
2443        validation.wire_warnings.len() as u64,
2444    );
2445    for warning in validation.wire_warnings {
2446        diagnostics.event(
2447            DiagnosticSeverity::Warning,
2448            KernelStage::Validate,
2449            "validate.uv_wire",
2450            warning.message,
2451        );
2452    }
2453    if !validation.issues.is_empty() {
2454        for issue in &validation.issues {
2455            diagnostics.event(
2456                DiagnosticSeverity::Error,
2457                KernelStage::Validate,
2458                "validate.brep",
2459                issue.message.clone(),
2460            );
2461        }
2462        return Err(format!(
2463            "offset_shell: invalid diagnostic result: {:?}",
2464            validation.issues
2465        ));
2466    }
2467    Ok(KernelOutcome {
2468        value: result,
2469        diagnostics,
2470    })
2471}