Skip to main content

brep_kernel/csg/imprint/
driver.rs

1use crate::{KernelRefusal, KernelStage, OrRefuse, RefusalClass, MAX_FIT_STATIONS};
2
3/// The degree a marched section is interpolated at (2026-09-27). The march
4/// puts every station on both carriers; the fit decides how far the curve
5/// strays BETWEEN them, and a cubic's O(h^4) there left `BadBoolean`'s
6/// sphere×bore rim 2.5e-7 off the bore with a mean bias of −1.2e-8 that both
7/// trims inherited (+1.14e-6 on the solid). A quintic through the same
8/// stations reads 8.5e-9 and +6e-11 with the same knots and control-point
9/// count. More stations bought the same accuracy on 2026-09-26 and were
10/// reverted for their cost: the watertight tessellator samples every interior
11/// knot, so every scan downstream scales with station count, and a degree does
12/// not add knots. `BREP_SECTION_FIT_DEGREE=3` restores the cubic. The gate on
13/// the mid-span refinement, as a multiple of the fit tolerance (2026-09-27): a
14/// marched section whose unrefined fit misses a carrier between stations by
15/// more than this is UNDERSAMPLED — the 20° cylinder crossing of
16/// `fillet-skew-cylinder-seam-split-20deg` sits 4e-5..8e-5 off, 470 times the
17/// tolerance, at any degree — and only such a section is given true
18/// intersection points until its mid-spans hold. Refining every section cost
19/// more downstream than it returned (the tessellator samples every knot).
20/// `BREP_SECTION_REFINE_GATE` sets the multiple (`on` for
21/// [`SECTION_REFINE_GATE`]). OFF BY DEFAULT: at k = 100 the sequential
22/// blend/direct_edit/imprint/boolean lib set costs +64 % and
23/// `oblique_multi_rim_cone_cap_tearing_push_refuses` goes red; k = 1000 costs
24/// +32 % and leaves the skew union +5.3e-4 off. This global switch stays off.
25/// Independently, a pair of grazing crossings on one trim edge requests a
26/// fit-floor check for that face pair below: those two nearby junctions and
27/// the intervening cap must survive the fit.
28fn section_refine_gate() -> Option<f64> {
29    static GATE: std::sync::OnceLock<Option<f64>> = std::sync::OnceLock::new();
30    *GATE.get_or_init(|| match std::env::var("BREP_SECTION_REFINE_GATE") {
31        Ok(value) if value == "on" => Some(SECTION_REFINE_GATE),
32        Ok(value) => value.parse::<f64>().ok().filter(|gate| *gate >= 0.0),
33        Err(_) => None,
34    })
35}
36
37/// Why a section goes to [`refine_section_against_carriers`].
38#[derive(Clone, Copy, Debug, PartialEq)]
39pub(super) enum SectionRefineRoute {
40    /// `BREP_SECTION_REFINE_GATE`: every section, at the variable's multiple.
41    Global,
42    /// A recovered fit reproduces its march points; check it between them.
43    Recovered,
44    /// A pair of grazing crossings on one trim edge.
45    Grazing,
46    /// The standing fit missed the tolerance it was asked for. The polyline
47    /// deviation can overstate the carrier miss (a band-raised floor reads the
48    /// input's noise), so the refiner's own carrier measure decides: a section
49    /// whose mid-spans already hold the gate leaves at round 0 as `BelowGate`,
50    /// unchanged. Measured 2026-10-04: the StationCeiling fits it reaches ship
51    /// 4.7e-5 to 2.1e-4 off the true section; the refiner brings them to
52    /// 1e-8..3e-8.
53    UnmetRequest,
54    /// A standing fit that MET its request on no other route, whose kept
55    /// stations all lie on both carriers within the fit tolerance, but whose
56    /// curve stands further off the carriers BETWEEN them than the local gate
57    /// ([`carrier_miss_route`]). The polyline it met is the march's chords; an
58    /// interpolant through consistent stations can still ring between them.
59    /// Measured 2026-10-04 (08356963b, 94 cases): 23 of 285 fast-path sections,
60    /// 13 distinct pairs, read their mid-spans up to 6.03e-6 off while every
61    /// kept station read within 1e-7; fixture 28 t217 pair 118x474 read 1.59e-6
62    /// between stations 1.8e-9 off.
63    CarrierMiss,
64}
65
66/// The carrier-miss route for a fit that met its request on no other route:
67/// refine at the local gate when its mid-spans miss the carriers by more than
68/// the fit tolerance WHILE every kept station is within it. Stations off a
69/// carrier are the input's (moving them is the reserved relocation ruling),
70/// so such a section keeps the fast path and is not reported as refined. An
71/// unreadable reading (NaN) never routes.
72pub(super) fn carrier_miss_route(station_upper: f64, midspan_upper: f64, fit_tolerance: f64) -> Option<(f64, SectionRefineRoute)> {
73    (station_upper.is_finite() && midspan_upper.is_finite() && station_upper <= fit_tolerance && midspan_upper > fit_tolerance)
74        .then_some((1.0, SectionRefineRoute::CarrierMiss))
75}
76
77/// The carrier readings [`carrier_miss_route`] decides on: the worst of both
78/// carriers over EVERY point of the section's run (the march's original
79/// stations, kept or dropped by the fit, so a fit through consistent kept
80/// stations cannot hide an inconsistent dropped one), and at the fit's
81/// mid-spans. Projector distances, so upper readings; NaN as soon as any is
82/// unreadable. The mid-span read is the route's TRIGGER, not a bound on the
83/// curve's maximum; [`knot_interior_carrier_upper`] is the finer read.
84pub(super) fn fast_path_carrier_readings(fit: &PolylineFit, run: &[Vec3], first: &NurbsSurface, second: &NurbsSurface) -> (f64, f64) {
85    let read = |surface: &NurbsSurface, point: Vec3| project_point_to_surface(surface, point).map_or(f64::NAN, |projection| projection.distance);
86    let mut station = 0.0f64;
87    for point in run {
88        let (a, b) = (read(first, *point), read(second, *point));
89        station = if a.is_nan() || b.is_nan() || station.is_nan() { f64::NAN } else { station.max(a).max(b) };
90    }
91    (station, midspan_carrier_upper(fit, first, second))
92}
93
94/// The worst of BOTH carriers at the fit's mid-spans, each carrier read on its
95/// own and checked finite BEFORE any max (`f64::max` would drop a NaN from one
96/// carrier and pass the other's reading): NaN as soon as either is unreadable.
97pub(super) fn midspan_carrier_upper(fit: &PolylineFit, first: &NurbsSurface, second: &NurbsSurface) -> f64 {
98    let read = |surface: &NurbsSurface, point: Vec3| project_point_to_surface(surface, point).map_or(f64::NAN, |projection| projection.distance);
99    let mut worst = 0.0f64;
100    for span in 0..fit.parameters.len().saturating_sub(1) {
101        let mid = 0.5 * (fit.parameters[span] + fit.parameters[span + 1]);
102        let (a, b) = match fit.curve.evaluate(mid) {
103            Ok(point) => (read(first, point), read(second, point)),
104            Err(_) => (f64::NAN, f64::NAN),
105        };
106        if !(a.is_finite() && b.is_finite()) || worst.is_nan() {
107            return f64::NAN;
108        }
109        worst = worst.max(a).max(b);
110    }
111    worst
112}
113
114/// The curve's worst distance from both carriers at the quarter points of
115/// every one of its own knot spans (its native pieces, where an interpolant
116/// is extremal between knots), NaN as soon as any read is unreadable. Sampled
117/// and projector-based: an upper reading at its points, not a certified
118/// maximum of the curve.
119pub(super) fn knot_interior_carrier_upper(curve: &NurbsCurve, first: &NurbsSurface, second: &NurbsSurface) -> f64 {
120    let read = |surface: &NurbsSurface, point: Vec3| project_point_to_surface(surface, point).map_or(f64::NAN, |projection| projection.distance);
121    let Ok([t0, t1]) = curve.domain() else { return f64::NAN };
122    let mut knots: Vec<f64> = curve.knots.iter().copied().filter(|knot| *knot >= t0 && *knot <= t1).collect();
123    knots.dedup();
124    let mut worst = 0.0f64;
125    for pair in knots.windows(2) {
126        if pair[1] <= pair[0] {
127            continue;
128        }
129        for fraction in [0.25, 0.5, 0.75] {
130            let value = match curve.evaluate(pair[0] + (pair[1] - pair[0]) * fraction) {
131                Ok(point) => {
132                    let (a, b) = (read(first, point), read(second, point));
133                    if a.is_finite() && b.is_finite() { a.max(b) } else { f64::NAN }
134                }
135                Err(_) => f64::NAN,
136            };
137            worst = if worst.is_nan() || !value.is_finite() { f64::NAN } else { worst.max(value) };
138        }
139    }
140    worst
141}
142
143/// The refine route and its gate (a multiple of the fit tolerance) for one
144/// section, or `None` for the fast path.
145///
146/// A standing fit that MET its request takes exactly the routes that existed
147/// before: the global gate alone when set, else a recovered fit, else a grazing
148/// pair (read lazily, only when the first two do not apply), else nothing — it
149/// goes straight to `process_curve`, untouched.
150///
151/// A fit that MISSED its request is always refined, at the local gate 1, or at
152/// a tighter global gate. A looser global gate does not mask the miss: seam 60
153/// was a recovered fit missing its 1e-7 request, and `BREP_SECTION_REFINE_GATE`
154/// above 1 used to let it through. Its route stays `UnmetRequest` under any
155/// global gate, so its cost reads apart from the global gate's.
156pub(super) fn section_refine_route(
157    global: Option<f64>,
158    recovered: bool,
159    grazing: impl FnOnce() -> bool,
160    met_requested: bool,
161) -> Option<(f64, SectionRefineRoute)> {
162    if !met_requested {
163        return Some((global.map_or(1.0, |gate| gate.min(1.0)), SectionRefineRoute::UnmetRequest));
164    }
165    global
166        .map(|gate| (gate, SectionRefineRoute::Global))
167        .or_else(|| recovered.then_some((1.0, SectionRefineRoute::Recovered)))
168        .or_else(|| grazing().then_some((1.0, SectionRefineRoute::Grazing)))
169}
170
171/// The multiple `BREP_SECTION_REFINE_GATE=on` uses: the smallest measured
172/// that trips the skew union's undersampled sections and leaves fixture 22 as
173/// it was (k = 10 flips it).
174const SECTION_REFINE_GATE: f64 = 100.0;
175
176/// The axis-aligned box of a curve's control points (rational ones read at
177/// their Cartesian position), grown by `margin` on every side: a box the
178/// curve cannot leave, since a NURBS curve with positive weights lies in its
179/// control hull.
180pub(super) fn control_hull_box(curve: &NurbsCurve, margin: f64) -> [Vec3; 2] {
181    let mut low = Vec3::new(f64::INFINITY, f64::INFINITY, f64::INFINITY);
182    let mut high = Vec3::new(f64::NEG_INFINITY, f64::NEG_INFINITY, f64::NEG_INFINITY);
183    for control in &curve.control_points {
184        let w = if control.w.abs() > 1e-300 { control.w } else { 1.0 };
185        let point = Vec3::new(control.x / w, control.y / w, control.z / w);
186        low = Vec3::new(low.x.min(point.x), low.y.min(point.y), low.z.min(point.z));
187        high = Vec3::new(high.x.max(point.x), high.y.max(point.y), high.z.max(point.z));
188    }
189    [
190        Vec3::new(low.x - margin, low.y - margin, low.z - margin),
191        Vec3::new(high.x + margin, high.y + margin, high.z + margin),
192    ]
193}
194
195/// Whether two closed boxes share a point.
196pub(super) fn boxes_overlap(a: &[Vec3; 2], b: &[Vec3; 2]) -> bool {
197    a[0].x <= b[1].x && b[0].x <= a[1].x && a[0].y <= b[1].y && b[0].y <= a[1].y && a[0].z <= b[1].z && b[0].z <= a[1].z
198}
199
200/// A clipped run's END span can be a sliver: the clip endpoint lands beside a
201/// march station, a spacing ratio to the run's median of 0.011 on
202/// `anotherBooleanFail`, and a global interpolant rings next to such a jump —
203/// the mid-spans near the ends miss their carriers by 1e-3, and bisecting them
204/// only makes the spacing more uneven (2026-09-27). The reduced witness
205/// (`imprint/tests.rs` `sliver_end_evening`) says what makes the jump ring: a
206/// sliver end ON both carriers fits to 3e-8, while the same end 2.7e-4 off
207/// the torus — the vendor's edge curves sit that far off the tori they
208/// bound, and the run's end is solved on such an edge — rings at 2e-3 with
209/// the interior at 3e-13 (2026-09-30). Below
210/// `SLIVER_END_FRACTION` of the median spacing the station beside the
211/// endpoint is RE-SOLVED at the middle of the merged gap as a fresh
212/// intersection point (the default, `BREP_SECTION_SLIVER_END=resolve`) or
213/// dropped (`drop`); `off` restores the unevened fit for a before/after
214/// reading. Returns how many ends were evened.
215///
216/// ON BY DEFAULT since 2026-09-30 (lane K6), behind the measurement in
217/// [`even_sliver_ends_measured`]: only a section whose fit shows the ringing signature
218/// ([`ringing_signature`]) is evened, and the evened fit stands only where it reads closer to
219/// the carriers by [`SLIVER_END_GAIN`]. The ringing is what a marched section carries into the
220/// result: on `anotherBooleanFail` the sphere sections leave the analytic vendor torus by
221/// 3.1e-3 within 1% of their span (measured against the STEP file's own `TOROIDAL_SURFACE`,
222/// not the projector), the cut torus faces depart from their edges by 2.6e-4 and the result
223/// shell's vector-area closure reads 1.88e-4 against a 3.83e-5 bar. Evened, the sections sit
224/// 5e-8 off, the shell closes at 1.7e-6 and the boolean takes 2.3 s instead of 9.1 s. The
225/// 2026-09-27 shelving reason was three fixture-25 exact-value pins moving under a blanket
226/// `resolve`; a blanket default also refused fixture 28's reversed subtract and broke fixture
227/// 26's idempotence, which is why the signature gates it. Fixture 25's sections do not show
228/// the signature at the shipped contrast and its pins stand.
229fn even_sliver_ends(
230    section: &mut Vec<Vec3>,
231    first: &NurbsSurface,
232    second: &NurbsSurface,
233    tolerance: f64,
234) -> Result<usize, String> {
235    static MODE: std::sync::OnceLock<String> = std::sync::OnceLock::new();
236    let mode = MODE.get_or_init(|| {
237        std::env::var("BREP_SECTION_SLIVER_END").unwrap_or_else(|_| "resolve".to_string())
238    });
239    if !(mode == "drop" || mode == "resolve") {
240        return Ok(0);
241    }
242    let mut evened = 0;
243    // One sliver at a time: each removal changes the spans it sits between.
244    for _ in 0..SLIVER_END_ROUNDS {
245        let count = section.len();
246        if count < 6 {
247            break;
248        }
249        let mut chords: Vec<f64> = section.windows(2).map(|pair| pair[1].sub(pair[0]).length()).collect();
250        let lengths = chords.clone();
251        chords.sort_by(f64::total_cmp);
252        let median = chords[chords.len() / 2];
253        let spans = lengths.len();
254        let near_ends = [0, 1, 2, spans - 3, spans - 2, spans - 1];
255        let Some(&sliver) = near_ends
256            .iter()
257            .filter(|&&span| lengths[span] < sliver_end_fraction() * median)
258            .min_by(|a, b| lengths[**a].total_cmp(&lengths[**b]))
259        else {
260            break;
261        };
262        // The sliver's bounding stations are `sliver` and `sliver + 1`; a run
263        // endpoint is never moved. Of the interior ones, remove the one whose
264        // removal leaves the shorter merged span.
265        let mut candidates = Vec::new();
266        for station in [sliver, sliver + 1] {
267            if station == 0 || station == count - 1 {
268                continue;
269            }
270            let merged = section[station + 1].sub(section[station - 1]).length();
271            candidates.push((station, merged));
272        }
273        let Some(&(station, _)) = candidates.iter().min_by(|a, b| a.1.total_cmp(&b.1)) else {
274            break;
275        };
276        if mode == "resolve" {
277            let (before, after) = (section[station - 1], section[station + 1]);
278            let seed = before.add(after).scale(0.5);
279            let reach = 0.5 * after.sub(before).length();
280            match crate::surface_surface_intersection::refine_to_intersection(first, second, seed, tolerance, reach)? {
281                Some(point) => section[station] = point,
282                None => {
283                    section.remove(station);
284                }
285            }
286        } else {
287            section.remove(station);
288        }
289        evened += 1;
290    }
291    Ok(evened)
292}
293
294/// At 0.25 six of `anotherBooleanFail`'s eight sections stay NoProgress
295/// (worst miss 2.7e-4); at 0.5 all eight are evened and fall below the
296/// refinement gate (worst miss 2.8e-3 -> 5.4e-8).
297const SLIVER_END_FRACTION: f64 = 0.5;
298
299/// How many sliver spans one section may lose, at most, over both ends. Every
300/// `anotherBooleanFail` section reaches this cap (the march lands several
301/// closely spaced stations beside each clip end), and the evened fits read
302/// 2.2e-8..5.4e-8 against the carriers under it; whether a higher cap would
303/// read differently was not measured (lane K6, 2026-09-30).
304const SLIVER_END_ROUNDS: usize = 4;
305
306/// `BREP_SECTION_SLIVER_FRACTION` overrides [`SLIVER_END_FRACTION`] for the
307/// measurement that picks it.
308fn sliver_end_fraction() -> f64 {
309    static FRACTION: std::sync::OnceLock<f64> = std::sync::OnceLock::new();
310    *FRACTION.get_or_init(|| {
311        std::env::var("BREP_SECTION_SLIVER_FRACTION")
312            .ok()
313            .and_then(|value| value.parse::<f64>().ok())
314            .filter(|fraction| *fraction > 0.0 && *fraction < 1.0)
315            .unwrap_or(SLIVER_END_FRACTION)
316    })
317}
318
319fn section_fit_degree() -> usize {
320    static DEGREE: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
321    *DEGREE.get_or_init(|| {
322        std::env::var("BREP_SECTION_FIT_DEGREE")
323            .ok()
324            .and_then(|value| value.parse::<usize>().ok())
325            .filter(|degree| (1..=7).contains(degree))
326            .unwrap_or(5)
327    })
328}
329
330/// `BREP_SPAN_BUDGET`, read once: unset leaves [`ImprintOptions::span_budget`]
331/// in charge; `off` forces none; `fit` is the pair's `intersection_fit` at the
332/// operands' scale; a number is an absolute budget.
333#[derive(Clone, Copy, Debug, PartialEq)]
334enum SpanBudgetSwitch {
335    Unset,
336    Off,
337    Fit,
338    Absolute(f64),
339}
340
341fn span_budget_switch() -> SpanBudgetSwitch {
342    static SWITCH: std::sync::OnceLock<SpanBudgetSwitch> = std::sync::OnceLock::new();
343    *SWITCH.get_or_init(|| match std::env::var("BREP_SPAN_BUDGET") {
344        Ok(value) if value == "fit" => SpanBudgetSwitch::Fit,
345        Ok(value) if value == "off" || value == "0" => SpanBudgetSwitch::Off,
346        Ok(value) => value
347            .parse::<f64>()
348            .ok()
349            .filter(|budget| *budget > 0.0)
350            .map_or(SpanBudgetSwitch::Unset, SpanBudgetSwitch::Absolute),
351        Err(_) => SpanBudgetSwitch::Unset,
352    })
353}
354
355/// The span budget every march of this imprint carries: the option under
356/// its environment override. `fit` is what the catalogue names as the
357/// budget a lane may carry, the imprint's `intersection_fit`
358/// (`KernelTolerances::for_scale`), never the corrector's `tolerance`.
359pub(super) fn span_budget(options: &ImprintOptions, scale: f64) -> Option<f64> {
360    match span_budget_switch() {
361        SpanBudgetSwitch::Unset => options.span_budget,
362        SpanBudgetSwitch::Off => None,
363        SpanBudgetSwitch::Fit => Some(crate::KernelTolerances::for_scale(scale, options.tolerance).intersection_fit),
364        SpanBudgetSwitch::Absolute(budget) => Some(budget),
365    }
366}
367
368/// [`ImprintOptions::hermite_sections`] under its environment override.
369fn hermite_sections(options: &ImprintOptions) -> bool {
370    match std::env::var("BREP_HERMITE_SECTIONS").as_deref() {
371        Ok("0") => false,
372        Ok(_) => true,
373        Err(_) => options.hermite_sections,
374    }
375}
376
377/// [`ImprintOptions::exact_iso_pcurves`] under its environment override
378/// (`BREP_EXACT_ISO_PCURVES`: `0`/`off`, `check`, anything else on).
379#[derive(Clone, Copy, Debug, PartialEq, Eq)]
380pub(super) enum ExactIsoPcurves {
381    Off,
382    On,
383    /// The fit lane runs; the exact pcurve is built beside it and compared
384    /// (`ImprintBuilder::exact_pcurve_check`).
385    Check,
386}
387
388fn exact_iso_pcurves(options: &ImprintOptions) -> ExactIsoPcurves {
389    match std::env::var("BREP_EXACT_ISO_PCURVES").as_deref() {
390        Ok("0") | Ok("off") => ExactIsoPcurves::Off,
391        Ok("check") => ExactIsoPcurves::Check,
392        Ok(_) => ExactIsoPcurves::On,
393        Err(_) if options.exact_iso_pcurves => ExactIsoPcurves::On,
394        Err(_) => ExactIsoPcurves::Off,
395    }
396}
397
398thread_local! {
399    /// Set by `build_imprints_impl` as it returns, read by the boolean
400    /// right after ([`take_rescue_firings`]) into
401    /// `intersect.march_swap_rescue` and `intersect.clip_swap_rescue`; a
402    /// thread-local rather than a field so the shared record's eight
403    /// literals stay as they are.
404    static RESCUE_FIRINGS: std::cell::Cell<(u64, u64)> = const { std::cell::Cell::new((0, 0)) };
405}
406
407/// `(march-order swap rescues, clip-order swap rescues)` of the last imprint
408/// built on this thread, cleared by the read.
409pub(crate) fn take_rescue_firings() -> (u64, u64) {
410    RESCUE_FIRINGS.with(|cell| cell.replace((0, 0)))
411}
412
413/// [`ImprintOptions::march_starts`] under its environment override, as
414/// `(ordered_starts, consume_starts, tree_seeds)` for every march this
415/// imprint runs. `BREP_MARCH_STARTS`: `0`/`off`; `order` (A3's ordering
416/// alone); `snap` (the ordering with run-through starts consumed); `tree`
417/// (A4 alone); `order+tree`; anything else all three.
418fn march_starts(options: &ImprintOptions) -> (bool, bool, bool) {
419    match std::env::var("BREP_MARCH_STARTS").as_deref() {
420        Ok("0") | Ok("off") => (false, false, false),
421        Ok("order") => (true, false, false),
422        Ok("snap") => (true, true, false),
423        Ok("tree") => (false, false, true),
424        Ok("order+tree") => (true, false, true),
425        Ok(_) => (true, true, true),
426        Err(_) => (options.march_starts, options.march_starts, options.march_starts),
427    }
428}
429
430/// `BREP_SPAN_CENSUS=<file>`: one line per clipped section, appended, so a
431/// corpus replay can be read for station growth and refine-route firings
432/// under a budget. `BREP_CENSUS_LABEL` names the run on every line.
433fn span_census(line: impl FnOnce() -> String) {
434    if let Ok(path) = std::env::var("BREP_SPAN_CENSUS") {
435        use std::io::Write;
436        if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open(path) {
437            let label = std::env::var("BREP_CENSUS_LABEL").unwrap_or_default();
438            let _ = writeln!(file, "span-budget census: label {label} {}", line());
439        }
440    }
441}
442
443/// A marched section is held to the fit tolerance against the CARRIERS, not
444/// only against the polyline it was fitted through (2026-09-26). The march
445/// refines every station onto both surfaces to `tolerance * 0.01`, but the
446/// cubic interpolant between stations is measured by `fit_polyline` against the
447/// polyline's own chords, which are further from the true curve than the
448/// interpolant is — so a systematic bias of the interpolant (2.8e-8 mean,
449/// 4.7e-7 worst, inside the bore on `BadBoolean`'s sphere/bore rim at 135
450/// stations) passed every check the fit could make, and both trims inherited it
451/// (+1.14e-6 on the solid's volume, against two independent readings agreeing
452/// to 1e-8). The check below evaluates the fitted curve at every mid-span,
453/// measures it against both carriers, and where it misses `fit tolerance *
454/// SECTION_MIDSPAN_FRACTION` inserts a TRUE intersection point there and
455/// refits. The interpolant's bias falls as h^4, so one round usually suffices.
456/// A round that neither halves the worst miss nor lowers the count of spans
457/// missing is not in that regime — a carrier's C0 crease puts a corner in the
458/// section (fixture 25's pierce solid), where every round only doubles the
459/// stations — so that round is discarded and the loop stops. It is also capped
460/// in rounds and stations, and names how it left.
461/// `BREP_SECTION_REFINE_GATE=off` switches it off, for the before/after reading
462/// and nothing else.
463pub(super) const SECTION_MIDSPAN_FRACTION: f64 = 0.1;
464const SECTION_MIDSPAN_ROUNDS: usize = 4;
465/// A round earns another if it cuts the worst mid-span miss by this factor
466/// (h^4 promises 16 for a halved spacing) OR lowers the count of spans
467/// missing: near the floor a few isolated spans hold the worst while the count
468/// falls, and on a corner the count GROWS round on round.
469const SECTION_MIDSPAN_PROGRESS: f64 = 0.5;
470
471/// Squared distance from `point` to the segment `from`-`to`.
472fn distance_to_segment_sq(point: Vec3, from: Vec3, to: Vec3) -> f64 {
473    let d = to.sub(from);
474    let l2 = d.dot(d);
475    let t = if l2 > 0.0 { (point.sub(from).dot(d) / l2).clamp(0.0, 1.0) } else { 0.0 };
476    let q = from.add(d.scale(t));
477    point.sub(q).dot(point.sub(q))
478}
479
480/// How a mid-span refinement left (`SECTION_MIDSPAN_*`), for the pair trace.
481#[derive(Clone, Copy, Debug, PartialEq)]
482pub(super) enum MidspanExit {
483    /// Every mid-span within the floor of both carriers.
484    Converged,
485    /// The unrefined fit's worst mid-span is within the gate: the section is
486    /// sampled well enough that its degree carries it, and stations would
487    /// cost more downstream than they return.
488    BelowGate,
489    /// Some mid-span still misses and no inserted point could improve it
490    /// (the Newton failed, wandered off the span, or landed on a station
491    /// already present).
492    Stalled,
493    /// A round neither halved the worst miss nor lowered the count of spans
494    /// missing: not the h^4 regime, so the section has a corner the
495    /// interpolant cannot follow. That round's fit is discarded.
496    NoProgress,
497    RoundBudget,
498    StationCeiling,
499}
500
501/// Measure `fit` at every mid-span against both carriers; return the worst
502/// distance, the count of spans that miss `floor` and, for each of them the
503/// Newton could place, the refined intersection point to insert (with the
504/// span's index).
505fn midspan_misses(
506    fit: &PolylineFit,
507    first: &NurbsSurface,
508    second: &NurbsSurface,
509    floor: f64,
510    tolerance: f64,
511) -> Result<(f64, usize, Vec<(usize, Vec3)>), String> {
512    let mut worst = 0.0f64;
513    let mut missing = 0usize;
514    let mut inserts = Vec::new();
515    for span in 0..fit.parameters.len().saturating_sub(1) {
516        let mid = 0.5 * (fit.parameters[span] + fit.parameters[span + 1]);
517        let point = fit.curve.evaluate(mid)?;
518        let off = project_point_to_surface(first, point)?
519            .distance
520            .max(project_point_to_surface(second, point)?.distance);
521        worst = worst.max(off);
522        if off <= floor {
523            continue;
524        }
525        missing += 1;
526        // The refined point must stay on THIS span: half its chord is the reach.
527        let reach = 0.5 * fit.kept[span + 1].sub(fit.kept[span]).length();
528        if let Some(refined) = crate::surface_surface_intersection::refine_to_intersection(
529            first, second, point, tolerance, reach,
530        )? {
531            inserts.push((span, refined));
532        }
533    }
534    Ok((worst, missing, inserts))
535}
536
537/// Every mid-span miss of `fit` against both carriers, measured and nothing
538/// else: what [`even_sliver_ends_measured`] reads before and after evening.
539/// It refines nothing, so a section without a sliver end pays only the
540/// projections.
541fn midspan_misses_only(fit: &PolylineFit, first: &NurbsSurface, second: &NurbsSurface) -> Result<Vec<f64>, String> {
542    let mut misses = Vec::with_capacity(fit.parameters.len());
543    for span in 0..fit.parameters.len().saturating_sub(1) {
544        let mid = 0.5 * (fit.parameters[span] + fit.parameters[span + 1]);
545        let point = fit.curve.evaluate(mid)?;
546        let off = project_point_to_surface(first, point)?
547            .distance
548            .max(project_point_to_surface(second, point)?.distance);
549        misses.push(off);
550    }
551    Ok(misses)
552}
553
554/// The signature of a global interpolant ringing on a sliver end span: the
555/// worst mid-span miss sits in one of the [`SLIVER_END_SPANS`] spans at either
556/// end, is over the fit `floor`, AND stands [`SLIVER_RING_CONTRAST`] times
557/// above the median of the interior spans. A section sampled too coarsely for the carriers misses
558/// everywhere at once and does not show this; a section with fewer than two
559/// interior spans offers no evidence either way. Returns the end-span worst
560/// and the interior median when the signature is present.
561fn ringing_signature(misses: &[f64], floor: f64) -> Option<(f64, f64)> {
562    let spans = misses.len();
563    if spans < 2 * SLIVER_END_SPANS + 2 {
564        return None;
565    }
566    let ends = misses[..SLIVER_END_SPANS]
567        .iter()
568        .chain(&misses[spans - SLIVER_END_SPANS..])
569        .copied()
570        .fold(0.0f64, f64::max);
571    let mut interior: Vec<f64> = misses[SLIVER_END_SPANS..spans - SLIVER_END_SPANS].to_vec();
572    interior.sort_by(f64::total_cmp);
573    let median = interior[interior.len() / 2];
574    let worst = misses.iter().copied().fold(0.0f64, f64::max);
575    // Below the fit floor there is nothing to even: a 1e-8 miss on a planar
576    // section passed the contrast on fixture 26 and flipped its idempotence
577    // reading while changing nothing a bar could see.
578    (ends > floor.max(sliver_min_miss()) && ends >= worst && ends > sliver_ring_contrast() * median.max(f64::MIN_POSITIVE))
579        .then_some((ends, median))
580}
581
582/// How many spans at each end of a section [`even_sliver_ends`] may even —
583/// the same three it inspects — and where [`ringing_signature`] looks.
584const SLIVER_END_SPANS: usize = 3;
585
586/// The ringing signature's contrast: the end spans' worst mid-span miss over
587/// the interior spans' median. A converged march leaves its interior at
588/// 1e-9 and a sliver end rings at 1e-4..1e-3, so the ratio is 1e5 and up:
589/// `anotherBooleanFail`'s eight sections read 1.3e5..2.2e6 (interior
590/// 6e-10..2.6e-9, ends 1.6e-4..2.8e-3). A section whose interior itself
591/// misses is under-sampled rather than ringing, and evening its end moves a
592/// junction the assembler then cannot repair: fixture 28's pair 822×118
593/// (interior 1.5e-6, ends 1.4e-3, contrast 930) refused the reversed
594/// subtract whenever it was evened, while its pairs 474×118 (1.7e4) and
595/// 842×118 (1.4e5) are evened and build. Fixture 25's two sections read
596/// 2.2e3 and 5.9e3 (interior 2e-8) and keep their stations and their pins.
597/// 3e4 sits at least 4× from the nearest reading on either side
598/// (2026-09-30).
599const SLIVER_RING_CONTRAST: f64 = 3.0e4;
600
601/// `BREP_SECTION_SLIVER_CONTRAST` overrides [`SLIVER_RING_CONTRAST`] for the
602/// measurement that picks it.
603fn sliver_ring_contrast() -> f64 {
604    static CONTRAST: std::sync::OnceLock<f64> = std::sync::OnceLock::new();
605    *CONTRAST.get_or_init(|| {
606        std::env::var("BREP_SECTION_SLIVER_CONTRAST")
607            .ok()
608            .and_then(|value| value.parse::<f64>().ok())
609            .filter(|contrast| *contrast >= 1.0)
610            .unwrap_or(SLIVER_RING_CONTRAST)
611    })
612}
613
614/// `BREP_SECTION_SLIVER_MIN_MISS` raises the absolute floor under the end
615/// spans' worst miss, for measurement only (the shipped floor is the fit
616/// tolerance).
617fn sliver_min_miss() -> f64 {
618    static MIN: std::sync::OnceLock<f64> = std::sync::OnceLock::new();
619    *MIN.get_or_init(|| {
620        std::env::var("BREP_SECTION_SLIVER_MIN_MISS")
621            .ok()
622            .and_then(|value| value.parse::<f64>().ok())
623            .filter(|miss| *miss >= 0.0)
624            .unwrap_or(0.0)
625    })
626}
627
628/// How a sliver-end evening left, for the census line.
629#[derive(Clone, Copy, Debug, PartialEq)]
630pub(super) enum SliverEvening {
631    /// No end span was shorter than the fraction, or the hatch is `off`.
632    NoSliver,
633    /// A sliver end exists but the unevened fit does not show the ringing
634    /// signature ([`ringing_signature`]): its stations stand.
635    NotRinging { slivers: usize, worst: f64 },
636    /// The evened section's fit reads at least [`SLIVER_END_GAIN`] times
637    /// closer to the carriers at its worst mid-span: the evened fit stands.
638    Accepted { slivers: usize, before: f64, after: f64, interior: f64 },
639    /// Evening did not earn its keep: the unevened fit stands, the stations
640    /// untouched.
641    Rejected { slivers: usize, before: f64, after: f64, interior: f64 },
642}
643
644/// A sliver-end evening must earn its keep: the evened fit stands only when
645/// its worst mid-span miss against both carriers falls by at least this
646/// factor. Measured on 2026-09-30 against the blanket default: `resolve` on
647/// every section that HAS a sliver end refused the reversed subtract of
648/// fixture 28 (`march_swap_rescue_recovers_reversed_subtract_t217`, an open
649/// loop) and made fixture 26's union read differently before and after
650/// operand splitting, while on `anotherBooleanFail` (2.8e-3 → 5e-8) and
651/// fixture 25 (2.0e-5 / 3.4e-5 → 9.2e-7) it cut the miss by 20× to 5e4×. A
652/// section whose evened fit is not clearly better keeps its stations.
653const SLIVER_END_GAIN: f64 = 2.0;
654
655/// [`even_sliver_ends`] with the measurement that decides whether it stands:
656/// fit the section as marched; if its mid-spans show the ringing signature
657/// ([`ringing_signature`]), even its sliver ends, fit again, and keep the
658/// evened fit only when its worst mid-span wins by [`SLIVER_END_GAIN`].
659/// Returns the section, its fit, the recovery flag of the fit that stands and
660/// the outcome.
661pub(super) fn even_sliver_ends_measured(
662    section: Vec<Vec3>,
663    first: &NurbsSurface,
664    second: &NurbsSurface,
665    tolerance: f64,
666    fit_tolerance: f64,
667    maximum_fit_points: usize,
668    local_fit: bool,
669) -> Result<(Vec<Vec3>, PolylineFit, bool, SliverEvening), String> {
670    let (fit, recovered) = crate::fit::fit_polyline_of_degree_with_recovery(
671        &section,
672        fit_tolerance,
673        maximum_fit_points,
674        local_fit,
675        section_fit_degree(),
676    )?;
677    let mut evened = section.clone();
678    let slivers = even_sliver_ends(&mut evened, first, second, tolerance)?;
679    if slivers == 0 {
680        return Ok((section, fit, recovered, SliverEvening::NoSliver));
681    }
682    let misses = midspan_misses_only(&fit, first, second)?;
683    let Some((before, interior)) = ringing_signature(&misses, fit_tolerance) else {
684        let worst = misses.iter().copied().fold(0.0f64, f64::max);
685        return Ok((section, fit, recovered, SliverEvening::NotRinging { slivers, worst }));
686    };
687    let (evened_fit, evened_recovered) = crate::fit::fit_polyline_of_degree_with_recovery(
688        &evened,
689        fit_tolerance,
690        maximum_fit_points,
691        local_fit,
692        section_fit_degree(),
693    )?;
694    let after_misses = midspan_misses_only(&evened_fit, first, second)?;
695    let after = after_misses.iter().copied().fold(0.0f64, f64::max);
696    if let Ok(path) = std::env::var("BREP_SECTION_SLIVER_CENSUS") {
697        use std::io::Write;
698        if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open(path) {
699            let chords = |points: &[Vec3]| points.windows(2).map(|pair| format!("{:.4e}", pair[1].sub(pair[0]).length())).collect::<Vec<_>>().join(" ");
700            let fmt = |values: &[f64]| values.iter().map(|value| format!("{value:.2e}")).collect::<Vec<_>>().join(" ");
701            let _ = writeln!(file, "sliver-end detail: stations {} -> {} kept {} -> {}", section.len(), evened.len(), fit.kept.len(), evened_fit.kept.len());
702            let _ = writeln!(file, "sliver-end detail: chords before: {}", chords(&section));
703            let _ = writeln!(file, "sliver-end detail: chords after:  {}", chords(&evened));
704            let _ = writeln!(file, "sliver-end detail: misses before: {}", fmt(&misses));
705            let _ = writeln!(file, "sliver-end detail: misses after:  {}", fmt(&after_misses));
706            let _ = writeln!(file, "sliver-end detail: ends before: {:?} {:?}", section[0], section[section.len() - 1]);
707            let _ = writeln!(file, "sliver-end detail: ends after:  {:?} {:?}", evened[0], evened[evened.len() - 1]);
708        }
709    }
710    if after * SLIVER_END_GAIN <= before {
711        Ok((evened, evened_fit, evened_recovered, SliverEvening::Accepted { slivers, before, after, interior }))
712    } else {
713        Ok((section, fit, recovered, SliverEvening::Rejected { slivers, before, after, interior }))
714    }
715}
716
717/// Refit `section` until its mid-spans sit within `floor` of both carriers,
718/// inserting true intersection points where they do not. Returns the fit that
719/// stands, the worst mid-span miss it still carries, the unrefined fit's worst
720/// (what the gate read), the rounds spent and the exit.
721/// Keep the single best measured refiner state (root grant 2026-10-04,
722/// accepted-representative sections only): replaced when `worst` is finite and
723/// no larger than the kept one (ties go to the later state). An unreadable
724/// reading is never kept. At most one snapshot is held.
725pub(super) fn keep_best_state<S>(best: &mut Option<(S, f64)>, state: impl FnOnce() -> S, worst: f64) {
726    if worst.is_finite() && best.as_ref().is_none_or(|(_, kept)| worst <= *kept) {
727        *best = Some((state(), worst));
728    }
729}
730
731/// The rollback a budget-type exit (RoundBudget, StationCeiling, Stalled)
732/// takes: on a section where an ACCEPTED representative round ran, the kept
733/// best state when its COMMON reading is strictly lower than the current
734/// state's common reading on the same instrument (both carriers, finite, at the
735/// fit's mid-spans and its own knot-span quarter points). Otherwise `None`:
736/// the exit returns the current state exactly as before, with nothing cloned.
737/// An unreadable current reading never rolls back (it is not hidden).
738pub(super) fn take_rollback<S>(best: &mut Option<(S, f64)>, current_common: f64, representative_ran: bool) -> Option<(S, f64)> {
739    let lower = matches!(best, Some((_, kept)) if representative_ran && current_common.is_finite() && *kept < current_common);
740    if lower { best.take() } else { None }
741}
742
743/// Which fit a refinement RETURNED: a receipt for controls, deciding nothing.
744#[derive(Clone, Copy, Debug, PartialEq)]
745pub(super) enum RefinedFitSource {
746    /// The standing fit the caller passed in.
747    Standing,
748    /// The original full refit of the run, made directly (`full-unmatched`,
749    /// or the retry after an unreadable representative or a seeded stall).
750    FullRefit,
751    /// The seeded (forced-station) call and its own path: a `Fallback` path
752    /// IS the original full refit.
753    Seeded(crate::fit::SeededPath),
754    /// The representative candidate call and its own path: a `Fallback` path
755    /// IS the original full refit.
756    Representatives(crate::fit::SeededPath),
757    /// The best measured state the budget-exit rollback restored.
758    Rollback,
759}
760
761/// The refiner's receipt: whether the run took the representative route at
762/// all, and which fit it returned (None on an error return). Production
763/// callers discard it; only controls read it.
764#[allow(dead_code)]
765#[derive(Clone, Copy, Debug, Default, PartialEq)]
766pub(super) struct RefineReceipt {
767    pub original_consistent: bool,
768    pub returned: Option<RefinedFitSource>,
769}
770
771pub(super) fn refine_section_against_carriers(
772    section: &mut Vec<Vec3>,
773    fit: PolylineFit,
774    first: &NurbsSurface,
775    second: &NurbsSurface,
776    fit_tolerance: f64,
777    tolerance: f64,
778    local_fit: bool,
779    gate: f64,
780) -> Result<(PolylineFit, f64, f64, usize, MidspanExit), String> {
781    // `BREP_SECTION_REPRESENTATIVES=0` restores the seeded path everywhere for
782    // an attribution A/B only; read here, once per call, as before.
783    let representatives = std::env::var("BREP_SECTION_REPRESENTATIVES").as_deref() != Ok("0");
784    refine_section_against_carriers_with(section, fit, first, second, fit_tolerance, tolerance, local_fit, gate, representatives, &mut RefineReceipt::default())
785}
786
787/// [`refine_section_against_carriers`] with the representative switch passed
788/// in (the env hatch's value, so a control can take the seeded route without
789/// touching the process environment) and a receipt of the fit returned.
790#[allow(clippy::too_many_arguments)]
791pub(super) fn refine_section_against_carriers_with(
792    section: &mut Vec<Vec3>,
793    fit: PolylineFit,
794    first: &NurbsSurface,
795    second: &NurbsSurface,
796    fit_tolerance: f64,
797    tolerance: f64,
798    local_fit: bool,
799    gate: f64,
800    representatives: bool,
801    receipt: &mut RefineReceipt,
802) -> Result<(PolylineFit, f64, f64, usize, MidspanExit), String> {
803    // A reused receipt starts clean, so an error return leaves `returned`
804    // None as documented, never a previous call's value.
805    *receipt = RefineReceipt::default();
806    // Which fit `fit` currently is, and which fit `previous` holds.
807    let mut fit_source = RefinedFitSource::Standing;
808    let mut previous_source = RefinedFitSource::Standing;
809    let floor = fit_tolerance * SECTION_MIDSPAN_FRACTION;
810    let mut unrefined = f64::NAN;
811    let mut fit = fit;
812    let mut rounds = 0usize;
813    let mut previous: Option<(PolylineFit, f64, usize)> = None;
814    // Every true intersection point inserted so far: the residual-driven bend
815    // witnesses, which the refit must keep as stations.
816    let mut inserted_points: Vec<Vec3> = Vec::new();
817    // `BREP_SECTION_REFINE_CENSUS`: one `section-refine round:` line per round,
818    // bound to its section by the run's head and tail, so a stall can be read
819    // round by round (debug only; nothing below reads it).
820    let round_census = std::env::var("BREP_SECTION_REFINE_CENSUS").ok();
821    let (head, tail) = (section[0], section[section.len() - 1]);
822    // Whether EVERY original point of the run lies on both carriers within the
823    // fit tolerance (projector upper readings, NaN = no): only such a run takes
824    // the refiner-specific representative candidate below. A run with any
825    // point off a carrier keeps the existing seeded path exactly (moving or
826    // discounting input points is the reserved relocation ruling).
827    // `representatives` false (the `BREP_SECTION_REPRESENTATIVES=0` hatch)
828    // restores the seeded path everywhere for an attribution A/B only.
829    let original_consistent = representatives
830        && section.iter().all(|point| {
831            let a = project_point_to_surface(first, *point).map_or(f64::NAN, |projection| projection.distance);
832            let b = project_point_to_surface(second, *point).map_or(f64::NAN, |projection| projection.distance);
833            a.is_finite() && b.is_finite() && a <= fit_tolerance && b <= fit_tolerance
834        });
835    receipt.original_consistent = original_consistent;
836    let mut refit_path = String::from("standing");
837    let mut refit_seeds = 0usize;
838    let mut refit_seeds_kept = 0usize;
839    let mut refit_seeds_outside_pool = 0usize;
840    let mut refit_pool = 0usize;
841    let mut refit_pool_discarded = 0usize;
842    let mut refit_pool_floor = f64::NAN;
843    let mut refit_seed_min_chord = f64::NAN;
844    // Trace only: what the closest seed pair is made of (kept station or
845    // refiner insert at each end), to place the near pair upstream.
846    let mut refit_seed_min_pair = "n/a";
847    // Trace only: every seed the full refit's pool rejects, by ORIGIN (a march
848    // station of the run, or a refiner insert) and by REASON (dropped by
849    // `station_pool`'s simplification, or kept by it and then conditioned
850    // away as a near-duplicate): [march simplified, march conditioned,
851    // insert simplified, insert conditioned].
852    let mut refit_rejected = [0usize; 4];
853    // Fits made for the round being judged (2 when its seeded fit stalled and
854    // the full refit was tried as well), and that retry's own cost.
855    let mut refit_trials = 1usize;
856    let mut retry_ms = 0.0f64;
857    // Whether the fit judged this round is an ACCEPTED seeded fit (not merely
858    // a seeded call: a seeded call that fell back already IS the full refit).
859    let mut seeded_refit = false;
860    // Whether the fit judged this round is an ACCEPTED representative
861    // candidate, and what that candidate call spent (its own interpolations
862    // and whether it ended on the full refit), kept apart from the fit's
863    // report, which on a fallback must stay the full refit's to the bit.
864    let mut representative_fit = false;
865    let mut refit_cost = crate::fit::RepresentativeCost::default();
866    // Whether an ACCEPTED representative round ran on this section, and the one
867    // best measured (fit, section) state kept for its budget exits.
868    let mut representative_ran = false;
869    let mut best_state: Option<((PolylineFit, Vec<Vec3>), f64)> = None;
870    loop {
871        // On an accepted representative candidate a read or refinement ERROR is
872        // not a refusal: the section takes the original full refit of the same
873        // run instead, as an unreadable read does below.
874        let (mut worst, missing, inserts) = match midspan_misses(&fit, first, second, floor, tolerance) {
875            Ok(reading) => reading,
876            Err(_) if representative_fit => {
877                representative_fit = false;
878                seeded_refit = false;
879                let maximum_points = section.len().min(MAX_FIT_STATIONS);
880                fit = fit_polyline_of_degree(section, fit_tolerance, maximum_points, local_fit, section_fit_degree())?;
881                fit_source = RefinedFitSource::FullRefit;
882                refit_path = String::from("full-after-unreadable-representative");
883                refit_trials += 1;
884                refit_cost.full_refit = true;
885                continue;
886            }
887            Err(error) => return Err(error),
888        };
889        // An ACCEPTED representative candidate is judged on more than its
890        // mid-spans: both carriers must read finite at every mid-span and at
891        // the quarter points of the curve's own knot spans, and its worst is
892        // the worse of the two reads (sampled, projector upper readings; the
893        // carrier target is unchanged). An unreadable read never passes: the
894        // section takes the original full refit of the same run instead.
895        if representative_fit {
896            let interior = knot_interior_carrier_upper(&fit.curve, first, second);
897            let midspans = midspan_carrier_upper(&fit, first, second);
898            if interior.is_finite() && midspans.is_finite() {
899                worst = worst.max(interior).max(midspans);
900            } else {
901                representative_fit = false;
902                seeded_refit = false;
903                let maximum_points = section.len().min(MAX_FIT_STATIONS);
904                fit = fit_polyline_of_degree(section, fit_tolerance, maximum_points, local_fit, section_fit_degree())?;
905                fit_source = RefinedFitSource::FullRefit;
906                refit_path = String::from("full-after-unreadable-representative");
907                refit_trials += 1;
908                refit_cost.full_refit = true;
909                continue;
910            }
911        }
912        if let Some(path) = &round_census {
913            use std::io::Write;
914            if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open(path) {
915                let _ = writeln!(
916                    file,
917                    "section-refine round: head ({:.9}, {:.9}, {:.9}) tail ({:.9}, {:.9}, {:.9}) round {rounds} fit {refit_path} trials {refit_trials} retry_ms {retry_ms:.3} kept {} seeds {refit_seeds} seeds_kept {refit_seeds_kept} seeds_outside_pool {refit_seeds_outside_pool} seed_min_chord {refit_seed_min_chord:.3e} seed_min_pair {refit_seed_min_pair} rejected_march_simplified {} rejected_march_conditioned {} rejected_insert_simplified {} rejected_insert_conditioned {} pool {refit_pool} pool_discarded {refit_pool_discarded} pool_floor {refit_pool_floor:.3e} exit {:?} deviation {:.3e} floor {:.3e} run {} worst {:.3e} missing {} inserts_offered {} representatives {} witnesses {} candidate_fits {} candidate_full_refit {} candidate_end_offsets {:.3e}/{:.3e} seed_role {}",
918                    head.x, head.y, head.z, tail.x, tail.y, tail.z,
919                    fit.kept.len(),
920                    refit_rejected[0], refit_rejected[1], refit_rejected[2], refit_rejected[3], fit.report.exit, fit.report.deviation, fit.report.floor, section.len(), worst, missing, inserts.len(),
921                    refit_cost.representatives, refit_cost.witnesses, refit_cost.candidate_fits, refit_cost.full_refit,
922                    refit_cost.start_offset, refit_cost.end_offset,
923                    // On the representative path the seeds counted above are
924                    // WITNESSES (not forced); on the seeded path they are forced.
925                    if original_consistent { "witness" } else { "forced" }
926                );
927                // Trace only: where the full refit's band-raised floor comes
928                // from on THIS run, and whether the run's own points are on
929                // the carriers (input-consistent) or not. The band is
930                // `dropped_band`'s reading (largest distance of a point the
931                // pool drops from the segment between its surviving
932                // neighbours); its point is classified as simplified away or
933                // conditioned away, with its carrier distance and its gap to
934                // the nearest run neighbour. Projector distances are upper
935                // readings.
936                let pool = crate::fit::polyline_station_pool(section, fit_tolerance);
937                let simplified = crate::fit::simplify_polyline_indices(section, fit_tolerance);
938                let mut band = (0.0f64, usize::MAX);
939                for pair in pool.windows(2) {
940                    for index in pair[0] + 1..pair[1] {
941                        let off = distance_to_segment_sq(section[index], section[pair[0]], section[pair[1]]).sqrt();
942                        if off > band.0 {
943                            band = (off, index);
944                        }
945                    }
946                }
947                let carrier = |point: Vec3| -> f64 {
948                    let a = project_point_to_surface(first, point).map_or(f64::NAN, |projection| projection.distance);
949                    let b = project_point_to_surface(second, point).map_or(f64::NAN, |projection| projection.distance);
950                    if a.is_nan() || b.is_nan() { f64::NAN } else { a.max(b) }
951                };
952                let mut run_carrier = 0.0f64;
953                for point in section.iter() {
954                    let off = carrier(*point);
955                    run_carrier = if off.is_nan() || run_carrier.is_nan() { f64::NAN } else { run_carrier.max(off) };
956                }
957                let (kind, band_carrier, gap) = if band.1 == usize::MAX {
958                    ("none", f64::NAN, f64::NAN)
959                } else {
960                    let index = band.1;
961                    let kind = if simplified.binary_search(&index).is_ok() { "conditioned" } else { "simplified" };
962                    let mut gap = f64::INFINITY;
963                    if index > 0 {
964                        gap = gap.min(section[index].sub(section[index - 1]).length());
965                    }
966                    if index + 1 < section.len() {
967                        gap = gap.min(section[index + 1].sub(section[index]).length());
968                    }
969                    (kind, carrier(section[index]), gap)
970                };
971                let _ = writeln!(
972                    file,
973                    "section-refine band: head ({:.9}, {:.9}, {:.9}) tail ({:.9}, {:.9}, {:.9}) round {rounds} run {} pool {} tolerance {:.3e} band {:.3e} band_index {} of {} band_kind {kind} band_point_carrier_upper {band_carrier:.3e} band_point_gap {gap:.3e} run_carrier_upper {run_carrier:.3e}",
974                    head.x, head.y, head.z, tail.x, tail.y, tail.z,
975                    section.len(), pool.len(), fit_tolerance, band.0,
976                    if band.1 == usize::MAX { -1 } else { band.1 as i64 }, section.len()
977                );
978            }
979        }
980        if rounds == 0 {
981            unrefined = worst;
982        }
983        // The rollback path's COMMON reading, only once an accepted
984        // representative round has run and only on a run the refit can hold
985        // (<= MAX_FIT_STATIONS): both carriers, finite, at the fit's mid-spans
986        // and its own knot-span quarter points, for EVERY state compared
987        // (representative, standing or full alike). One snapshot, the fit and
988        // the run it was measured on as one coherent pair: its payload is one
989        // PolylineFit and at most MAX_FIT_STATIONS points. Off this path
990        // nothing is read or cloned.
991        let mut current_common = f64::NAN;
992        if representative_ran && section.len() <= MAX_FIT_STATIONS {
993            let interior = knot_interior_carrier_upper(&fit.curve, first, second);
994            let midspans = midspan_carrier_upper(&fit, first, second);
995            current_common = if interior.is_finite() && midspans.is_finite() { interior.max(midspans) } else { f64::NAN };
996            keep_best_state(&mut best_state, || (fit.clone(), section.clone()), current_common);
997        }
998        if worst <= floor {
999            receipt.returned = Some(fit_source);
1000            return Ok((fit, worst, unrefined, rounds, MidspanExit::Converged));
1001        }
1002        if rounds == 0 && worst <= gate {
1003            receipt.returned = Some(fit_source);
1004            return Ok((fit, worst, unrefined, rounds, MidspanExit::BelowGate));
1005        }
1006        if let Some((earlier, earlier_worst, earlier_missing)) = previous.take() {
1007            // A round that did not earn its keep is discarded whole: the fit
1008            // of the last round that did stands (on a corner, the unrefined
1009            // fit), not whichever of the two happens to read a smaller max.
1010            if worst > earlier_worst * SECTION_MIDSPAN_PROGRESS && missing >= earlier_missing {
1011                // A SEEDED round that did not earn its keep is refitted once
1012                // with the original full refit of the same denser run, and
1013                // that is judged against the same earlier round before the
1014                // section stops. The seeded fit keeps fewer stations; on the
1015                // helmet's 2036x3009 section that gave back the whole of the
1016                // full refit's gain (6.335e-6 stood where 5.596e-7 was
1017                // reached). The full refit is the round the refiner made
1018                // before the seeded entry existed; only a round that fails
1019                // both ends the section, exactly as before.
1020                if seeded_refit {
1021                    seeded_refit = false;
1022                    let maximum_points = section.len().min(MAX_FIT_STATIONS);
1023                    let retry_started = round_census.is_some().then(Instant::now);
1024                    fit = fit_polyline_of_degree(section, fit_tolerance, maximum_points, local_fit, section_fit_degree())?;
1025                    fit_source = RefinedFitSource::FullRefit;
1026                    // Trace: one more fit for the SAME round, its cost, and no
1027                    // seed counters carried over from the rejected seeded fit.
1028                    refit_path = String::from("full-after-seeded-stall");
1029                    // Every fit this round made: the candidate's (or the seeded
1030                    // call's one) plus this retry.
1031                    refit_trials += 1;
1032                    retry_ms = retry_started.map_or(0.0, |started| started.elapsed().as_secs_f64() * 1e3);
1033                    refit_seeds = 0;
1034                    refit_seeds_kept = 0;
1035                    refit_seeds_outside_pool = 0;
1036                    refit_seed_min_chord = f64::NAN;
1037                    refit_seed_min_pair = "n/a";
1038                    refit_rejected = [0; 4];
1039                    representative_fit = false;
1040                    // Keep the candidate's own counts; the retry is the full refit.
1041                    refit_cost.full_refit = true;
1042                    previous = Some((earlier, earlier_worst, earlier_missing));
1043                    continue;
1044                }
1045                receipt.returned = Some(previous_source);
1046                return Ok((earlier, earlier_worst, unrefined, rounds, MidspanExit::NoProgress));
1047            }
1048        }
1049        if inserts.is_empty() {
1050            if let Some(((kept_fit, kept_run), kept_common)) = take_rollback(&mut best_state, current_common, representative_ran) {
1051                *section = kept_run;
1052                receipt.returned = Some(RefinedFitSource::Rollback);
1053                return Ok((kept_fit, kept_common, unrefined, rounds, MidspanExit::Stalled));
1054            }
1055            receipt.returned = Some(fit_source);
1056            return Ok((fit, worst, unrefined, rounds, MidspanExit::Stalled));
1057        }
1058        if rounds >= SECTION_MIDSPAN_ROUNDS {
1059            if let Some(((kept_fit, kept_run), kept_common)) = take_rollback(&mut best_state, current_common, representative_ran) {
1060                *section = kept_run;
1061                receipt.returned = Some(RefinedFitSource::Rollback);
1062                return Ok((kept_fit, kept_common, unrefined, rounds, MidspanExit::RoundBudget));
1063            }
1064            receipt.returned = Some(fit_source);
1065            return Ok((fit, worst, unrefined, rounds, MidspanExit::RoundBudget));
1066        }
1067        if section.len() + inserts.len() > MAX_FIT_STATIONS {
1068            if let Some(((kept_fit, kept_run), kept_common)) = take_rollback(&mut best_state, current_common, representative_ran) {
1069                *section = kept_run;
1070                receipt.returned = Some(RefinedFitSource::Rollback);
1071                return Ok((kept_fit, kept_common, unrefined, rounds, MidspanExit::StationCeiling));
1072            }
1073            receipt.returned = Some(fit_source);
1074            return Ok((fit, worst, unrefined, rounds, MidspanExit::StationCeiling));
1075        }
1076        // Insert each refined point into the run between its span's stations,
1077        // on the nearest segment of the run there. Positions are located
1078        // against the run BEFORE any insertion of this round, then applied
1079        // from the back so earlier indices stay valid. The kept stations are
1080        // found by a FORWARD search from the previous one: a closed section
1081        // ends on its first station, and a search from the start would put
1082        // the last span's far end at index 0 and skip that span forever.
1083        let station_index = |point: Vec3, from: usize| -> Option<usize> {
1084            section[from..]
1085                .iter()
1086                .position(|p| p.sub(point).length() <= 1e-15 * (1.0 + point.length()))
1087                .map(|offset| from + offset)
1088        };
1089        let mut placed: Vec<(usize, Vec3)> = Vec::new();
1090        for (span, point) in inserts {
1091            let Some(lo) = station_index(fit.kept[span], 0) else {
1092                continue;
1093            };
1094            let Some(hi) = station_index(fit.kept[span + 1], lo + 1) else {
1095                continue;
1096            };
1097            if hi <= lo {
1098                continue;
1099            }
1100            if section[lo..=hi].iter().any(|p| p.sub(point).length() <= floor) {
1101                continue; // already a station: inserting it again refines nothing
1102            }
1103            let mut best = (lo, f64::INFINITY);
1104            for index in lo..hi {
1105                let d2 = distance_to_segment_sq(point, section[index], section[index + 1]);
1106                if d2 < best.1 {
1107                    best = (index, d2);
1108                }
1109            }
1110            placed.push((best.0 + 1, point));
1111        }
1112        if placed.is_empty() {
1113            if let Some(((kept_fit, kept_run), kept_common)) = take_rollback(&mut best_state, current_common, representative_ran) {
1114                *section = kept_run;
1115                receipt.returned = Some(RefinedFitSource::Rollback);
1116                return Ok((kept_fit, kept_common, unrefined, rounds, MidspanExit::Stalled));
1117            }
1118            receipt.returned = Some(fit_source);
1119            return Ok((fit, worst, unrefined, rounds, MidspanExit::Stalled));
1120        }
1121        placed.sort_by(|a, b| b.0.cmp(&a.0));
1122        for (at, point) in placed {
1123            section.insert(at, point);
1124            inserted_points.push(point);
1125        }
1126        // The refit keeps the stations the current fit kept and every point
1127        // inserted so far as SEEDS, and grows only where it is measured to
1128        // miss (`fit_polyline_seeded_with_path`). It is no longer the whole denser run
1129        // from the run's own count: that interpolated every march station the
1130        // standing fit had dropped as well, 3x the controls on the skew-cylinder
1131        // loop for the same carrier floor. The ceiling is the one the full refit
1132        // derives from the same `maximum_points`, and a seeded fit that cannot
1133        // meet the floor, or cannot be read, IS the full refit. The carrier
1134        // measure above still decides every round.
1135        let same = |a: &Vec3, b: &Vec3| a.x.to_bits() == b.x.to_bits() && a.y.to_bits() == b.y.to_bits() && a.z.to_bits() == b.z.to_bits();
1136        let mut seeds = Vec::with_capacity(fit.kept.len() + inserted_points.len());
1137        // The previous fit's kept stations alone: the representative candidate's
1138        // starting set (inserts are its witnesses, not forced stations).
1139        let mut kept_seeds = Vec::with_capacity(fit.kept.len());
1140        // The refiner's own inserted true-carrier points: the representative
1141        // candidate's TIGHT witnesses, held to this refiner's carrier floor.
1142        let mut insert_indices = Vec::with_capacity(inserted_points.len());
1143        let mut next_kept = 0usize;
1144        for (index, point) in section.iter().enumerate() {
1145            // The kept stations are a subsequence of the run, in run order
1146            // (insertion only adds points), so a closed run's two equal ends
1147            // each match their own station.
1148            // An inserted point is a tight witness whether or not the previous
1149            // fit also kept it as a station (membership is independent).
1150            let inserted = inserted_points.iter().any(|candidate| same(point, candidate));
1151            if inserted {
1152                insert_indices.push(index);
1153            }
1154            if next_kept < fit.kept.len() && same(point, &fit.kept[next_kept]) {
1155                seeds.push(index);
1156                kept_seeds.push(index);
1157                next_kept += 1;
1158            } else if inserted {
1159                seeds.push(index);
1160            }
1161        }
1162        let maximum_points = section.len().min(MAX_FIT_STATIONS);
1163        // Every standing station must be found as a seed; if the pass missed
1164        // one, the seeded refit would silently lose it, so the section takes the
1165        // original full refit instead.
1166        refit_trials = 1;
1167        retry_ms = 0.0;
1168        let refit_source;
1169        let refit = if next_kept == fit.kept.len() {
1170            let (refit, path) = if original_consistent {
1171                let (refit, path, cost) = crate::fit::fit_polyline_representatives_with_witnesses(
1172                    section,
1173                    &kept_seeds,
1174                    &insert_indices,
1175                    floor,
1176                    fit_tolerance,
1177                    maximum_points,
1178                    local_fit,
1179                    section_fit_degree(),
1180                )?;
1181                // MIXED UNITS, named as such: the candidate's own
1182                // `fit_station_set` interpolations plus one per call of the
1183                // full refit `fit_polyline_of_degree`, which may itself run
1184                // several ladder and recovery interpolations that are NOT
1185                // counted here. Whole-job cost is the matched timing.
1186                refit_cost = cost;
1187                refit_trials = cost.candidate_fits + usize::from(cost.full_refit);
1188                (refit, path)
1189            } else {
1190                refit_cost = crate::fit::RepresentativeCost::default();
1191                crate::fit::fit_polyline_seeded_with_path(
1192                    section,
1193                    &seeds,
1194                    fit_tolerance,
1195                    maximum_points,
1196                    local_fit,
1197                    section_fit_degree(),
1198                )?
1199            };
1200            // Only an ACCEPTED seeded fit can be retried in full: a fallback
1201            // already is the full refit, and retrying it would repeat it.
1202            seeded_refit = matches!(path, crate::fit::SeededPath::Accepted { .. });
1203            representative_fit = original_consistent && seeded_refit;
1204            refit_source = if original_consistent { RefinedFitSource::Representatives(path) } else { RefinedFitSource::Seeded(path) };
1205            representative_ran |= representative_fit;
1206            if round_census.is_some() {
1207                refit_path = if original_consistent { format!("representatives-call:{path:?}") } else { format!("seeded-call:{path:?}") };
1208            }
1209            refit
1210        } else {
1211            seeded_refit = false;
1212            representative_fit = false;
1213            refit_cost = crate::fit::RepresentativeCost::default();
1214            refit_path = String::from("full-unmatched");
1215            refit_source = RefinedFitSource::FullRefit;
1216            fit_polyline_of_degree(section, fit_tolerance, maximum_points, local_fit, section_fit_degree())?
1217        };
1218        if round_census.is_some() {
1219            // Trace only: how many seeds the refit kept. This does NOT tell an
1220            // accepted seeded fit from the fallback (a full refit can keep
1221            // every seed too); the returned `SeededPath`, traced as `fit`, does.
1222            refit_seeds = seeds.len();
1223            refit_seeds_kept = seeds.iter().filter(|&&index| refit.kept.iter().any(|kept| same(kept, &section[index]))).count();
1224            // Seeds the full refit's pool would NOT interpolate (simplified
1225            // or conditioned away): forced stations only the seeded fit keeps.
1226            let pool = crate::fit::polyline_station_pool(section, fit_tolerance);
1227            refit_pool = pool.len();
1228            refit_pool_discarded = section.len() - pool.len();
1229            refit_pool_floor = crate::fit::polyline_station_pool_floor(section, fit_tolerance);
1230            refit_seeds_outside_pool = seeds.iter().filter(|index| !pool.contains(index)).count();
1231            // Seeds are in run order; the closest consecutive pair is what a
1232            // near-duplicate conditioning floor would act on.
1233            refit_seed_min_chord = seeds
1234                .windows(2)
1235                .map(|pair| section[pair[1]].sub(section[pair[0]]).length())
1236                .fold(f64::INFINITY, f64::min);
1237            let is_insert = |index: usize| inserted_points.iter().any(|inserted| same(inserted, &section[index]));
1238            refit_seed_min_pair = seeds
1239                .windows(2)
1240                .min_by(|a, b| {
1241                    section[a[1]].sub(section[a[0]]).length().total_cmp(&section[b[1]].sub(section[b[0]]).length())
1242                })
1243                .map_or("n/a", |pair| match (is_insert(pair[0]), is_insert(pair[1])) {
1244                    (false, false) => "station-station",
1245                    (false, true) => "station-insert",
1246                    (true, false) => "insert-station",
1247                    (true, true) => "insert-insert",
1248                });
1249            // Every rejected seed, classified. `station_pool` starts from this
1250            // same simplification, so a non-member that is not in it was
1251            // simplified away, and one that is in it was conditioned away.
1252            let simplified = crate::fit::simplify_polyline_indices(section, fit_tolerance);
1253            refit_rejected = [0; 4];
1254            for &index in seeds.iter().filter(|index| !pool.contains(index)) {
1255                let conditioned = simplified.binary_search(&index).is_ok();
1256                refit_rejected[2 * usize::from(is_insert(index)) + usize::from(conditioned)] += 1;
1257            }
1258        }
1259        previous = Some((std::mem::replace(&mut fit, refit), worst, missing));
1260        previous_source = std::mem::replace(&mut fit_source, refit_source);
1261        rounds += 1;
1262    }
1263}
1264use super::*;
1265use super::gate_census::{census_pair, fit_census_enabled};
1266
1267pub fn build_imprints(
1268    solid_a: &BrepSolid,
1269    solid_b: &BrepSolid,
1270    options: &ImprintOptions,
1271) -> Result<ImprintResultRecord, KernelRefusal> {
1272    build_imprints_impl(solid_a, solid_b, options, false, super::pcurve_cache::enabled())
1273}
1274
1275/// Imprint temporary open offset sheets. A section riding one sheet's trim
1276/// still cuts the other sheet when no boundary copy supplied that section.
1277pub(crate) fn build_carrier_imprints(
1278    solid_a: &BrepSolid,
1279    solid_b: &BrepSolid,
1280    options: &ImprintOptions,
1281) -> Result<ImprintResultRecord, KernelRefusal> {
1282    build_imprints_impl(solid_a, solid_b, options, true, super::pcurve_cache::enabled())
1283}
1284
1285pub(super) fn build_imprints_impl(
1286    solid_a: &BrepSolid,
1287    solid_b: &BrepSolid,
1288    options: &ImprintOptions,
1289    open_carriers: bool,
1290    pcurve_cache: bool,
1291) -> Result<ImprintResultRecord, KernelRefusal> {
1292    let _pcurve_cache = super::pcurve_cache::FitCacheScope::open(pcurve_cache);
1293    let mut section_evidence = false;
1294    let edges = edge_map(solid_a, solid_b);
1295    let mut builder = ImprintBuilder {
1296        open_carriers,
1297        edges,
1298        tolerance: options.tolerance,
1299        barrier_edges: HashSet::default(),
1300        overlap_ridden_edges: HashSet::default(),
1301        scale: solid_scale(solid_a).max(solid_scale(solid_b)),
1302        vertices: Vec::new(),
1303        vertex_radii: HashMap::default(),
1304        vertex_sources: HashMap::default(),
1305        pieces: Vec::new(),
1306        by_face: HashMap::default(),
1307        edge_splits: HashMap::default(),
1308        marched_pieces: HashSet::default(),
1309        emitted_pcurves: HashSet::default(),
1310        exact_pcurve_check: false,
1311        next_id: 1,
1312    };
1313    let hermite_lane = hermite_sections(options);
1314    let exact_iso = exact_iso_pcurves(options);
1315    let (ordered_starts, consume_starts, tree_seeds) = march_starts(options);
1316    builder.exact_pcurve_check = exact_iso == ExactIsoPcurves::Check;
1317    // The Hermite lane needs the march's span test; with no budget asked for
1318    // it carries the one the catalogue names, the pair's `intersection_fit`.
1319    let march_span_budget = span_budget(options, builder.scale)
1320        .or_else(|| hermite_lane.then(|| crate::KernelTolerances::for_scale(builder.scale, options.tolerance).intersection_fit));
1321    let mut first_faces = faces(solid_a, 0);
1322    let mut second_faces = faces(solid_b, 1);
1323    // Per-face trim-window carriers, computed once: tighter BVH bounds, and
1324    // the seed/march stages walk the window instead of the full carrier
1325    // (identical geometry and parameterization inside the window).
1326    //
1327    // A window LIFTED across a closed direction's seam (`restricted_carrier`)
1328    // is the exception to "same parameterization": it is the trim's frame, a
1329    // period off the carrier's on one side. Its face carries it as its
1330    // `chart`, and every uv the imprint reads for that face — the clip's
1331    // containment, the sections' pcurves, a seed's normal — is read there.
1332    let first_restricted: Vec<Option<MarchWindow>> = first_faces
1333        .iter()
1334        .map(|tagged| restricted_carrier(tagged.face))
1335        .collect();
1336    let second_restricted: Vec<Option<MarchWindow>> = second_faces
1337        .iter()
1338        .map(|tagged| restricted_carrier(tagged.face))
1339        .collect();
1340    for (tagged, window) in first_faces.iter_mut().zip(&first_restricted) {
1341        tagged.lifted = window.as_ref().filter(|window| window.lifted).map(|window| &window.surface);
1342    }
1343    for (tagged, window) in second_faces.iter_mut().zip(&second_restricted) {
1344        tagged.lifted = window.as_ref().filter(|window| window.lifted).map(|window| &window.surface);
1345    }
1346    let first_faces = first_faces;
1347    let second_faces = second_faces;
1348    // The lifted charts, by key, for the post-passes that rebuild a pcurve
1349    // after the mint (junction canonicalization, the origin dissolve, the
1350    // truncation bridge). A face absent here is read on its own carrier.
1351    let charts: FaceCharts<'_> = first_faces
1352        .iter()
1353        .chain(second_faces.iter())
1354        .filter_map(|tagged| tagged.lifted.map(|surface| (tagged.key(), surface)))
1355        .collect();
1356    let first_bounds = first_faces
1357        .iter()
1358        .zip(&first_restricted)
1359        .map(|(tagged, restricted)| {
1360            face_bounds(
1361                tagged.face,
1362                restricted.as_ref().map(|window| &window.surface),
1363                &builder.edges,
1364                tagged.operand,
1365                options.tolerance,
1366            )
1367        })
1368        .collect::<Result<Vec<_>, _>>()?;
1369    let second_bounds = second_faces
1370        .iter()
1371        .zip(&second_restricted)
1372        .map(|(tagged, restricted)| {
1373            face_bounds(
1374                tagged.face,
1375                restricted.as_ref().map(|window| &window.surface),
1376                &builder.edges,
1377                tagged.operand,
1378                options.tolerance,
1379            )
1380        })
1381        .collect::<Result<Vec<_>, _>>()?;
1382    let second_bvh = Bvh::build(&second_bounds);
1383    // Per-face classifier data and edge lists/subcurves, computed once and
1384    // reused across every pair the face participates in.
1385    let first_classify = first_faces
1386        .iter()
1387        .map(|tagged| SurfaceClassifyData::build(&tagged.face.surface, options.tolerance))
1388        .collect::<Result<Vec<_>, _>>().or_refuse(KernelStage::Intersect, "csg.imprint.driver")?;
1389    let second_classify = second_faces
1390        .iter()
1391        .map(|tagged| SurfaceClassifyData::build(&tagged.face.surface, options.tolerance))
1392        .collect::<Result<Vec<_>, _>>().or_refuse(KernelStage::Intersect, "csg.imprint.driver")?;
1393    let mut face_edge_lists: HashMap<FaceKey, Vec<&EdgeRecord>> = HashMap::default();
1394    for tagged in first_faces.iter().chain(second_faces.iter()) {
1395        face_edge_lists.insert(tagged.key(), face_edges(*tagged, &builder.edges)?);
1396    }
1397    let mut subcurves: HashMap<(u8, u64), NurbsCurve> = HashMap::default();
1398    for (&key, edge) in &builder.edges {
1399        if !edge.degenerate {
1400            // Failures fall through: the use sites recompute and surface the
1401            // original error exactly where the uncached code did.
1402            if let Ok(curve) = edge_subcurve(edge) {
1403                subcurves.insert(key, curve);
1404            }
1405        }
1406    }
1407    let cached_subcurve = |operand: u8, edge: &EdgeRecord| -> Result<NurbsCurve, KernelRefusal> {
1408        match subcurves.get(&(operand, edge.id)) {
1409            Some(curve) => Ok(curve.clone()),
1410            None => edge_subcurve(edge),
1411        }
1412    };
1413    let mut profile = ImprintProfile::new();
1414    let mut march_swap_rescues = 0_u64;
1415    let mut clip_swap_rescues = 0_u64;
1416    // `imprint.fits`: the pcurve fits the pairs record, read through a nested
1417    // scope that folds into the operation's own ledger on close.
1418    let pairs_fits = profile.enabled.then(crate::PcurveFitScope::open);
1419    let mut tangent_nodes: Vec<Vec3> = Vec::new();
1420    let mut tangent_sections: Vec<TangentSectionRecord> = Vec::new();
1421    // Planar tangent runs to IMPRINT once every pair has minted its pieces
1422    // (`ImprintOptions::tangent_curve_imprint`): (section index, run, pair).
1423    let mut tangent_imprint_candidates: Vec<(usize, Vec<Vec3>, TaggedFace<'_>, TaggedFace<'_>)> = Vec::new();
1424    let mut cosurface_pairs: Vec<(FaceKey, FaceKey)> = Vec::new();
1425    let mut deferred_boundary_spans = Vec::new();
1426    let mut paired = Vec::new();
1427    for (first_index, first) in first_faces.iter().enumerate() {
1428        let first = *first;
1429        paired.clear();
1430        second_bvh.overlapping(
1431            first_bounds[first_index],
1432            options.tolerance * 100.0,
1433            &mut paired,
1434        );
1435        paired.sort_unstable();
1436        let debug_pairs = std::env::var("BREP_DEBUG_PAIRS").is_ok();
1437        if debug_pairs {
1438            eprintln!(
1439                "bvh first_face={} -> {} candidate pairs {:?}",
1440                first.face.id,
1441                paired.len(),
1442                paired
1443                    .iter()
1444                    .map(|&index| second_faces[index].face.id)
1445                    .collect::<Vec<_>>()
1446            );
1447        }
1448        for &second_index in &paired {
1449            let second = second_faces[second_index];
1450            profile.pairs += 1;
1451            // Set when this pair's section passes through an isolated TANGENT
1452            // NODE inside both trims (see the classification below). The march
1453            // is attempted anyway — that is the whole point — but a marcher
1454            // that cannot get through a node must refuse in the tangent-node
1455            // class naming the node, not leak its own step-budget message.
1456            let mut tangent_node: Option<Vec3> = None;
1457            let mut lap_start = None;
1458            profile.lap(&mut lap_start);
1459            let pair_classification = classify_surface_pair_cached(
1460                &first.face.surface,
1461                &first_classify[first_index],
1462                &second.face.surface,
1463                &second_classify[second_index],
1464                options.tolerance,
1465                PAIR_ANGULAR_TOLERANCE,
1466            ).or_refuse(KernelStage::Intersect, "csg.imprint.driver")?;
1467            profile.classify += profile.lap(&mut lap_start);
1468            if pair_classification.relation == SurfacePairRelation::Disjoint {
1469                if debug_pairs {
1470                    eprintln!(
1471                        "pair {}x{}: DISJOINT-cull sep={:.4e}",
1472                        first.face.id, second.face.id, pair_classification.minimum_separation
1473                    );
1474                }
1475                continue;
1476            }
1477            // Coincident carriers are never marched: their true intersection
1478            // is a 2D region, not a curve, so anything the marcher traces on
1479            // them is noise ("similar faces we do not intersect" — Golovanov
1480            // §6.2).  The sampled classification catches coincident pairs
1481            // the strict reconstruction test misses (partial overlaps,
1482            // differing parameterizations); both route to the boundary-curve
1483            // exchange below.
1484            let is_cosurface = pair_classification.relation == SurfacePairRelation::Cosurface
1485                || cosurface_pair(&first.face.surface, &second.face.surface, options.tolerance)?;
1486            profile.cosurface += profile.lap(&mut lap_start);
1487            if is_cosurface {
1488                if debug_pairs {
1489                    eprintln!("pair {}x{}: cosurface", first.face.id, second.face.id);
1490                }
1491                cosurface_pairs.push((first.key(), second.key()));
1492                for edge in &face_edge_lists[&second.key()] {
1493                    if !edge.degenerate {
1494                        builder.process_curve(
1495                            cached_subcurve(second.operand, edge)?,
1496                            first,
1497                            second,
1498                            &[first],
1499                            &[first],
1500                            false,
1501                            None,
1502                        )?;
1503                    }
1504                }
1505                for edge in &face_edge_lists[&first.key()] {
1506                    if !edge.degenerate {
1507                        builder.process_curve(
1508                            cached_subcurve(first.operand, edge)?,
1509                            first,
1510                            second,
1511                            &[second],
1512                            &[second],
1513                            false,
1514                            None,
1515                        )?;
1516                    }
1517                }
1518                profile.process_curve += profile.lap(&mut lap_start);
1519                continue;
1520            }
1521
1522            // Exact lanes discard sections riding an ordinary trim boundary:
1523            // that face already owns the edge, but the other face still needs
1524            // the overlapping span as a cut. Keep the existing whole-edge
1525            // exchange order, and append missing partial spans after all pairs
1526            // have run so duplicate sections retain their established IDs and
1527            // fragment names. Seams are retained by the exact lane itself.
1528            let planar_iso = planar_iso_section(
1529                &first.face.surface,
1530                &second.face.surface,
1531                options.tolerance,
1532            )?;
1533            profile.planar_iso += profile.lap(&mut lap_start);
1534            let analytic = crate::intersect_analytic_pair(
1535                &first.face.surface,
1536                &second.face.surface,
1537                options.tolerance,
1538            );
1539            profile.analytic += profile.lap(&mut lap_start);
1540            let exact_section = planar_iso.is_some() || analytic.is_some();
1541
1542            for (source, target) in [(first, second), (second, first)] {
1543                for edge in &face_edge_lists[&source.key()] {
1544                    if edge.degenerate {
1545                        continue;
1546                    }
1547                    let curve = cached_subcurve(source.operand, edge)?;
1548                    let spans = curve_spans_on_face(
1549                        curve.clone(), target.face, &face_edge_lists[&target.key()],
1550                        options.tolerance, exact_section,
1551                    )?;
1552                    let seam = source.face.loops.iter().flat_map(|loop_record| &loop_record.coedges)
1553                        .filter(|coedge| coedge.edge_id == edge.id).count() >= 2;
1554                    if spans.is_empty() && exact_section && !seam {
1555                        for span in curve_spans_on_face(
1556                            curve, target.face, &face_edge_lists[&target.key()],
1557                            options.tolerance, false,
1558                        )? {
1559                            deferred_boundary_spans.push((span, first, second, target));
1560                        }
1561                    }
1562                    for span in spans {
1563                        builder.process_curve(span, first, second, &[target], &[target], false, None)?;
1564                    }
1565                }
1566            }
1567            profile.lies_on += profile.lap(&mut lap_start);
1568            // CENSUS ONLY (`BREP_FIT_CENSUS=1`): the lane this pair takes under
1569            // the count-keyed and the geometry-keyed gates, and — when it is
1570            // marched here and answered exactly there — the point-set comparison
1571            // of the two, printed when `pair_census` is dropped. `imprint/gate_census.rs`.
1572            let mut pair_census = if fit_census_enabled() {
1573                census_pair(first, second, options.tolerance)?
1574            } else {
1575                None
1576            };
1577            if let Some(IsoSection { curve, pcurves }) = planar_iso {
1578                if debug_pairs {
1579                    eprintln!("pair {}x{}: planar_iso", first.face.id, second.face.id);
1580                }
1581                // Slice 1: the exact pcurves ride along with the curve when
1582                // the lane is on (or checked). A face read in a lifted chart
1583                // declines: the iso line is in the carrier's own frame, and
1584                // the lifted chart's period is not the carrier's.
1585                let exact_pcurves = match (exact_iso, pcurves) {
1586                    (ExactIsoPcurves::Off, _) => None,
1587                    (_, Some(pcurves)) if first.lifted.is_none() && second.lifted.is_none() => {
1588                        profile.exact_iso_sections += 1;
1589                        Some(pcurves)
1590                    }
1591                    _ => {
1592                        profile.exact_iso_declined += 1;
1593                        None
1594                    }
1595                };
1596                let lane_fits = profile.enabled.then(crate::PcurveFitScope::open);
1597                builder.process_curve(
1598                    curve,
1599                    first,
1600                    second,
1601                    &[first, second],
1602                    &[first, second],
1603                    true,
1604                    exact_pcurves,
1605                )?;
1606                if let Some(scope) = lane_fits {
1607                    profile.exact_lane_fits += scope.close().fits;
1608                }
1609                profile.process_curve += profile.lap(&mut lap_start);
1610                continue;
1611            }
1612
1613            // Recognized analytic pairs produce their exact intersection
1614            // curves (lines, circles, ellipses) directly — no marching, no
1615            // polyline fitting, no chord-sag drift. An empty result is a
1616            // proof of non-intersection and also skips the marcher. (Read
1617            // above, with the planar-iso curve.)
1618            if let Some(curves) = analytic {
1619                if debug_pairs {
1620                    eprintln!(
1621                        "pair {}x{}: analytic x{}",
1622                        first.face.id,
1623                        second.face.id,
1624                        curves.len()
1625                    );
1626                }
1627                // TANGENT-CURVE LANE. An exact lane's "provably empty" is a
1628                // proof about TRANSVERSE curves: a plane at exactly the
1629                // cylinder's radius from its axis has no generatrix pair, and
1630                // the pair would be dropped here without a word while the
1631                // carriers touch along a whole line. Where the classification
1632                // read the pair as near-tangent, the lane looks for the
1633                // extended contact and records it typed.
1634                if curves.is_empty()
1635                    && options.tangent_curve_lane
1636                    && pair_classification.relation == SurfacePairRelation::NearTangent
1637                {
1638                    if let Some((mut section, run)) = tangent_curve_section(
1639                        first, second, options, &first_faces, &second_faces, &face_edge_lists, debug_pairs,
1640                    )? {
1641                        if options.tangent_curve_imprint && section.planar && run.len() >= 2 {
1642                            tangent_imprint_candidates.push((tangent_sections.len(), run, first, second));
1643                        }
1644                        tangent_sections.push(section);
1645                    }
1646                }
1647                let lane_fits = profile.enabled.then(crate::PcurveFitScope::open);
1648                for curve in curves {
1649                    builder.process_curve(
1650                        curve,
1651                        first,
1652                        second,
1653                        &[first, second],
1654                        &[first, second],
1655                        true,
1656                        None,
1657                    )?;
1658                }
1659                if let Some(scope) = lane_fits {
1660                    profile.exact_lane_fits += scope.close().fits;
1661                }
1662                profile.process_curve += profile.lap(&mut lap_start);
1663                continue;
1664            }
1665
1666            // A pair whose every touching sample is TANGENTIAL cannot
1667            // contain a transverse intersection curve: the marcher would
1668            // walk the tangency band's noise, which neither closes nor
1669            // reaches a boundary (the distance-0 glue-extrude runaway).
1670            // Shared topology at a tangential contact comes from the
1671            // boundary-curve exchange above ("similar faces we do not
1672            // intersect" extended to tangential contacts — Golovanov §6.2;
1673            // where surfaces CROSS through a tangency, off-line samples
1674            // have non-parallel normals and the pair still marches).
1675            if pair_classification.relation == SurfacePairRelation::NearTangent
1676                && pair_classification.tangential_only
1677            {
1678                // The coarse 5×5 classifier can flag `tangential_only` off an
1679                // incidental tangential KISS between two curved carriers and
1680                // miss the transverse loop where they actually cross (two
1681                // overlapping tori: their tubes cross while their inner walls
1682                // just touch). Before honouring the skip, a GATED supplemental
1683                // detector (denser two-sided seeding, tangency-band seeds
1684                // rejected, trace-exhaustion swallowed, transverse-only
1685                // branches) checks whether a genuine transverse curve of
1686                // meaningful length lies inside BOTH trims.
1687                //
1688                // Such a pair's intersection is SINGULAR where a tangency
1689                // sits on it, and what the imprint can do about that depends
1690                // entirely on the SHAPE of the tangency — see
1691                // `imprint/tangent_contact.rs`. An isolated NODE (two branches
1692                // crossing, as every equal-radius pair produces) is already
1693                // assembled correctly by the ordinary march plus the 2D
1694                // arrangement's pinch carving; an EXTENDED contact along a
1695                // whole curve has no section to imprint at all and tears the
1696                // shell. Both are classified below and only the second is
1697                // refused. Skipping either silently would DROP the
1698                // intersection (torus∪torus double-counts; torus−torus removes
1699                // nothing — the two structural bugs the semantic oracle
1700                // found), so nothing here ever falls through quietly.
1701                let first_march = first_restricted[first_index]
1702                    .as_ref()
1703                    .map(|window| &window.surface)
1704                    .unwrap_or(&first.face.surface);
1705                let second_march = second_restricted[second_index]
1706                    .as_ref()
1707                    .map(|window| &window.surface)
1708                    .unwrap_or(&second.face.surface);
1709                let supplemental = intersect_surfaces_supplemental(
1710                    first_march,
1711                    second_march,
1712                    &SurfaceIntersectionOptions {
1713                        tolerance: options.tolerance,
1714                        maximum_step: options.maximum_ssi_step,
1715                        span_budget: march_span_budget,
1716                        ..Default::default()
1717                    },
1718                ).or_refuse(KernelStage::Intersect, "csg.imprint.driver")?;
1719                let mut dropped_length = 0.0f64;
1720                let mut clipped: Vec<Vec<Vec3>> = Vec::new();
1721                for branch in &supplemental {
1722                    for run in clip_branch_to_trims(&branch.points, first, second)? {
1723                        if run.len() < 2 {
1724                            continue;
1725                        }
1726                        let length: f64 = run
1727                            .windows(2)
1728                            .map(|pair| pair[1].sub(pair[0]).length())
1729                            .sum();
1730                        dropped_length = dropped_length.max(length);
1731                        clipped.push(run);
1732                    }
1733                }
1734                if dropped_length <= options.tolerance * 100.0 {
1735                    if debug_pairs {
1736                        eprintln!(
1737                            "pair {}x{}: tangential-only contact, march skipped",
1738                            first.face.id, second.face.id
1739                        );
1740                    }
1741                    // TANGENT-CURVE LANE: the skip is right for a transverse
1742                    // march, which has nothing to walk here, but the contact
1743                    // may still be a CURVE inside both trims (the same
1744                    // generatrix on a carrier no exact lane recognises).
1745                    // Recognise and record it, typed, rather than lose it.
1746                    if options.tangent_curve_lane {
1747                        if let Some((mut section, run)) = tangent_curve_section(
1748                            first, second, options, &first_faces, &second_faces, &face_edge_lists, debug_pairs,
1749                        )? {
1750                            if options.tangent_curve_imprint && section.planar && run.len() >= 2 {
1751                                tangent_imprint_candidates.push((tangent_sections.len(), run, first, second));
1752                            }
1753                            tangent_sections.push(section);
1754                        }
1755                    }
1756                    continue;
1757                }
1758                // A transverse curve EXISTS. What would make it unimprintable is
1759                // a tangent NODE on it — and the node need not lie inside the
1760                // trims. Two equal-radius pipe arms are tangent to each other
1761                // where their axes' common perpendicular leaves the junction,
1762                // and a joint ball wider than the arms trims that crotch off
1763                // both faces; what is left inside the trims is an ordinary
1764                // crossing. So the question is not "does a transverse curve
1765                // exist" but "does the curve INSIDE BOTH TRIMS reach a
1766                // tangency". Only the latter is the checkerboard case.
1767                let mut tangency_inside_trims = false;
1768                let mut tangency_witness = Vec3::default();
1769                'clipped: for run in &clipped {
1770                    for (index, &point) in run.iter().enumerate() {
1771                        if pair_normals_parallel_at(first, second, point)? {
1772                            tangency_inside_trims = true;
1773                            tangency_witness = point;
1774                            if debug_pairs {
1775                                eprintln!(
1776                                    "pair {}x{}: TANGENCY at run index {}/{} ({:.6},{:.6},{:.6}) dropped_len={:.4e}",
1777                                    first.face.id, second.face.id, index, run.len(),
1778                                    point.x, point.y, point.z, dropped_length
1779                                );
1780                            }
1781                            break 'clipped;
1782                        }
1783                    }
1784                }
1785                if tangency_inside_trims {
1786                    // WHAT SHAPE is the tangency? The witness is only a marched
1787                    // sample within the transverse-seed angular gate, so it is
1788                    // REFINED onto the contact before being classified — at the
1789                    // raw witness a G1 cylinder/torus join and a genuine
1790                    // equal-radius node are eighteen-fold apart, which would be
1791                    // a band; at the refined contact they are thirty orders
1792                    // apart, which is a rank question. See
1793                    // `imprint/tangent_contact.rs`.
1794                    let contact = classify_tangent_contact(
1795                        &first.face.surface,
1796                        &second.face.surface,
1797                        tangency_witness,
1798                        options.tolerance,
1799                    )?;
1800                    if debug_pairs {
1801                        eprintln!(
1802                            "pair {}x{}: contact classification {:?}",
1803                            first.face.id, second.face.id, contact
1804                        );
1805                    }
1806                    match contact {
1807                        // An isolated node: the section is a curve everywhere
1808                        // but that one point, so the ordinary march below runs
1809                        // and the 2D arrangement carves the pinch on both
1810                        // faces. `tangent_node` records it so a march that
1811                        // cannot get through still refuses in THIS class rather
1812                        // than leaking the marcher's own message.
1813                        Some(contact) if contact.is_isolated_node() => {
1814                            tangent_node = Some(contact.point);
1815                            tangent_nodes.push(contact.point);
1816                        }
1817                        // An extended contact (rank-deficient) or a witness we
1818                        // could not refine onto any contact at all (None — so
1819                        // nothing is proven and the pre-classification refusal
1820                        // stands). Neither has a section curve the imprint can
1821                        // represent.
1822                        other => {
1823                            let shape = match other {
1824                                Some(contact) => contact.describe(),
1825                                None => format!(
1826                                    "the tangency near ({:.6},{:.6},{:.6}) could not be refined \
1827                                     onto a contact, so its shape is unproven",
1828                                    tangency_witness.x, tangency_witness.y, tangency_witness.z
1829                                ),
1830                            };
1831                            return Err(KernelRefusal::new(
1832                                RefusalClass::TangentNodeSingularity,
1833                                KernelStage::Intersect,
1834                                format!(
1835                                    "boolean: unsupported singular/tangent-node surface intersection \
1836                                     between faces {} and {}: {shape}",
1837                                    first.face.id, second.face.id
1838                                ),
1839                            ));
1840                        }
1841                    }
1842                }
1843                if debug_pairs && tangent_node.is_none() {
1844                    // Transverse the whole way inside both trims: the coarse
1845                    // 5x5 classifier only saw the tangency the trims cut away.
1846                    eprintln!(
1847                        "pair {}x{}: classified tangential-only, but the curve inside both \
1848                         trims is transverse ({dropped_length:.4}) — marching",
1849                        first.face.id, second.face.id
1850                    );
1851                }
1852            }
1853
1854            // The trim-window carriers: same surface and parameterization
1855            // over the window, so hit (u, v) values remain valid on the
1856            // originals; out-of-window intersections could never survive
1857            // clip_branch_to_trims and are not walked at all.
1858            let first_march = first_restricted[first_index]
1859                .as_ref()
1860                .map(|window| &window.surface)
1861                .unwrap_or(&first.face.surface);
1862            let second_march = second_restricted[second_index]
1863                .as_ref()
1864                .map(|window| &window.surface)
1865                .unwrap_or(&second.face.surface);
1866            let mut seed_points = Vec::new();
1867            // Smallest |edge_tangent · surface_normal| over accepted seeds — the
1868            // local grazing measure at the trim crossings (near 0 = the edge
1869            // pierces the other surface tangentially). Gates the near-tangent
1870            // clip-order rescue below to genuinely grazing pairs.
1871            let mut min_seed_tangency = f64::INFINITY;
1872            // Two grazing crossings of one trim edge bound a real, narrow
1873            // interval. It cannot tolerate a section fit that misses either
1874            // crossing, even when a coarse whole-model distance looks small.
1875            let mut paired_grazing_crossings = false;
1876            for (face, other_march, other) in
1877                [(first, second_march, second), (second, first_march, first)]
1878            {
1879                for edge in &face_edge_lists[&face.key()] {
1880                    if edge.degenerate {
1881                        continue;
1882                    }
1883                    let mut grazing_crossings: Vec<Vec3> = Vec::new();
1884                    for hit in intersect_curve_surface(&edge.curve, other_march, options.tolerance).or_refuse(KernelStage::Intersect, "intersect_curve_surface")?
1885                    {
1886                        if hit.t < edge.t0 - 1e-9 || hit.t > edge.t1 + 1e-9 {
1887                            continue;
1888                        }
1889                        let derivative = edge.curve.derivatives(hit.t, 1).or_refuse(KernelStage::Intersect, "derivatives")?[1];
1890                        // A STATIONARY POINT on the edge curve is not a reason
1891                        // to refuse the boolean. An involute flank starts at
1892                        // the base circle with an exactly zero tangent, so a
1893                        // gear tooth's profile carries one cusp per flank, and
1894                        // a hit landing on that parameter used to propagate
1895                        // "Vec3.normalized: zero-length vector" out of the
1896                        // whole union (the 2026-09-14 herringbone report: the
1897                        // second tooth band's z=0 cap edge meets the first
1898                        // band's flank exactly at the cusp). The direction is
1899                        // still defined as the one-sided limit, so read it from
1900                        // just inside the edge's own range; an edge with no
1901                        // direction at all simply contributes no seed, exactly
1902                        // as a hit whose face normal is unavailable already
1903                        // does two lines below. Seeds are marcher hints, so a
1904                        // dropped one costs a hint, never an answer.
1905                        // Escape hatch for tamper-verification:
1906                        // BREP_CUSP_TANGENT_RESCUE=0 restores the refusal.
1907                        let tangent = match derivative.normalized() {
1908                            Ok(tangent) => tangent,
1909                            Err(error) => {
1910                                if std::env::var("BREP_CUSP_TANGENT_RESCUE").as_deref() == Ok("0") {
1911                                    return Err(error)
1912                                        .or_refuse(KernelStage::Intersect, "normalized");
1913                                }
1914                                match edge.curve.stationary_tangent_rescue(hit.t, edge.t0, edge.t1)
1915                                {
1916                                    Some(tangent) => tangent,
1917                                    None => continue,
1918                                }
1919                            }
1920                        };
1921                        // `hit` was solved on the other face's MARCH WINDOW, so
1922                        // its uv is in that face's chart — a period off the
1923                        // carrier's where the window is lifted, and `normal`
1924                        // clamps a parameter past its domain.
1925                        let normal = match other.chart().normal(hit.u, hit.v) {
1926                            Ok(normal) => normal,
1927                            Err(_) => continue,
1928                        };
1929                        if debug_pairs {
1930                            eprintln!(
1931                                "pair {}x{}: seed edge {} t={:.6} p=({:.5},{:.5},{:.5}) |tan.n|={:.4} {}",
1932                                first.face.id,
1933                                second.face.id,
1934                                edge.id,
1935                                hit.t,
1936                                hit.point.x,
1937                                hit.point.y,
1938                                hit.point.z,
1939                                tangent.dot(normal).abs(),
1940                                if tangent.dot(normal).abs() >= 0.1 { "ACCEPT" } else { "reject" }
1941                            );
1942                        }
1943                        if tangent.dot(normal).abs() >= 0.1 {
1944                            seed_points.push(hit.point);
1945                            min_seed_tangency = min_seed_tangency.min(tangent.dot(normal).abs());
1946                            section_evidence = true;
1947                        } else {
1948                            if grazing_crossings.iter().any(|point| {
1949                                point.sub(hit.point).length() > assembler_weld(options.tolerance)
1950                            }) {
1951                                paired_grazing_crossings = true;
1952                            }
1953                            grazing_crossings.push(hit.point);
1954                        }
1955                    }
1956                }
1957            }
1958            profile.seeds += profile.lap(&mut lap_start);
1959            profile.marched_pairs += 1;
1960            if debug_pairs {
1961                eprintln!(
1962                    "pair {}x{}: marching (relation {:?})...",
1963                    first.face.id, second.face.id, pair_classification.relation
1964                );
1965            }
1966            let marched = intersect_surfaces(
1967                first_march,
1968                second_march,
1969                &SurfaceIntersectionOptions {
1970                    tolerance: options.tolerance,
1971                    maximum_step: march_maximum_step(
1972                        &pair_classification,
1973                        options.maximum_ssi_step,
1974                        builder.scale,
1975                    ),
1976                    seed_points: seed_points.clone(),
1977                    span_budget: march_span_budget,
1978                    ordered_starts,
1979                    consume_starts,
1980                    tree_seeds,
1981                    ..Default::default()
1982                },
1983            );
1984            // A pair carrying a tangent node keeps its OWN refusal class when
1985            // the march fails: the node is why the trace cannot close, and the
1986            // equal-radius torus pair depends on being told so rather than on
1987            // reading a step-budget message it cannot act on.
1988            let marched = match (marched, tangent_node) {
1989                (Err(error), Some(node)) => {
1990                    return Err(KernelRefusal::new(
1991                        RefusalClass::TangentNodeSingularity,
1992                        KernelStage::Intersect,
1993                        format!(
1994                            "boolean: unsupported singular/tangent-node surface intersection \
1995                             between faces {} and {}: the section through the tangent node at \
1996                             ({:.6},{:.6},{:.6}) could not be marched ({error})",
1997                            first.face.id, second.face.id, node.x, node.y, node.z
1998                        ),
1999                    ));
2000                }
2001                (marched, _) => marched,
2002            };
2003            let mut branches = marched
2004            .map_err(|error| {
2005                format!(
2006                    "{error} (marching faces {} and {})",
2007                    first.face.id, second.face.id
2008                )
2009            }).or_refuse(KernelStage::Intersect, "csg.imprint.driver")?;
2010            profile.march += profile.lap(&mut lap_start);
2011            let rescue_started = profile.enabled.then(Instant::now);
2012            // MARCH-ORDER SWAP RESCUE (hatch BREP_MARCH_SWAP_RESCUE=0).
2013            // `intersect_surfaces` is not order-symmetric: the coupled Newton
2014            // trace can fail to start/continue from a valid seed when the two
2015            // surfaces are presented in one operand order yet succeed in the
2016            // other. This is the sole reason t217's `subtract(sphere, step)`
2017            // fails while every other op passes — pair 118x842 (sphere-first)
2018            // marches ZERO branches, while 842x118 (step-first, the working
2019            // a\b order) marches the section from the IDENTICAL accepted pierce
2020            // seeds. When the forward order returns no branch AND an accepted
2021            // transverse pierce seed exists (so a real section provably crosses
2022            // both trims), retry the march with the surfaces swapped — i.e.
2023            // reproduce the exact call the working operand order makes for this
2024            // pair (measured: seed_only alone does NOT recover it — the section
2025            // is found from an auto-grid start, not from the near-tangent pierce
2026            // seeds, which the seed normal-cross gate rejects). The returned
2027            // branch points are 3D and therefore order-independent, so no
2028            // parameter remap is needed; they flow through the identical clip /
2029            // process_curve gates below, which drop any out-of-trim or
2030            // sub-length run exactly as today. The rescue only ever runs when
2031            // the forward order found NOTHING, so it cannot alter a pair that
2032            // already marched.
2033            if branches.is_empty()
2034                && !seed_points.is_empty()
2035                && pair_classification.relation == SurfacePairRelation::Candidate
2036                && std::env::var("BREP_MARCH_SWAP_RESCUE").as_deref() != Ok("0")
2037            {
2038                // FAIL-SOFT: the forward order already returned Ok(empty); a
2039                // swapped-march error (trace-exhaustion is a real error class —
2040                // `intersect_surfaces_supplemental` swallows it for exactly this
2041                // reason) must NOT convert that graceful empty into a hard error.
2042                // On Err, keep the (empty) forward result and carry on.
2043                let swapped = intersect_surfaces(
2044                    second_march,
2045                    first_march,
2046                    &SurfaceIntersectionOptions {
2047                        tolerance: options.tolerance,
2048                        maximum_step: march_maximum_step(
2049                            &pair_classification,
2050                            options.maximum_ssi_step,
2051                            builder.scale,
2052                        ),
2053                        seed_points: seed_points.clone(),
2054                        span_budget: march_span_budget,
2055                        ordered_starts,
2056                        consume_starts,
2057                        tree_seeds,
2058                        ..Default::default()
2059                    },
2060                )
2061                .unwrap_or_default();
2062                if debug_pairs {
2063                    eprintln!(
2064                        "pair {}x{}: MARCH-SWAP RESCUE attempt -> {} branches, pts {:?}",
2065                        first.face.id,
2066                        second.face.id,
2067                        swapped.len(),
2068                        swapped.iter().map(|b| b.points.len()).collect::<Vec<_>>()
2069                    );
2070                }
2071                if !swapped.is_empty() {
2072                    branches = swapped;
2073                    march_swap_rescues += 1;
2074                }
2075            }
2076            // NEAR-TANGENT CLIP-ORDER RESCUE (hatch BREP_MARCH_SWAP_CLIP_RESCUE=0).
2077            // Companion to the empty-branch MARCH-SWAP RESCUE above:
2078            // `intersect_surfaces` is order-asymmetric not only in WHETHER it
2079            // marches, but in the exact sample positions of the section
2080            // polyline. On a NEAR-TANGENT graze, `clip_branch_to_trims`
2081            // classifies those samples against the mutual trims, and a sample
2082            // landing just past the near-tangent boundary is dropped as a
2083            // false-Outside that TRUNCATES the clipped section. The two operand
2084            // orders drop DIFFERENT near-tangent tail samples, so one order
2085            // yields a section ~0.1-0.2mm shorter at ONE endpoint (t660: b\a's
2086            // step-first order clips pairs 223x105/399x105 ~0.22/0.14mm short of
2087            // the section a\b's cyl-first order keeps, stranding edge 173
2088            // one-use). Near-tangent clip errors are almost exclusively
2089            // false-Outside (a point truly outside a trim rarely projects to an
2090            // in-trim uv), so the order with the LONGER clipped section suffered
2091            // fewer drops and is the more complete one. When the swapped order
2092            // marches the SAME branch structure with a meaningfully longer
2093            // clipped total, adopt its branches (3D points, so they flow through
2094            // the identical clip/process_curve gates below). Gated to Candidate
2095            // pairs (the near-tangent/ambiguous class; clean Transverse
2096            // crossings clip identically in both orders and never differ) with
2097            // an accepted GRAZING pierce seed (min |tan·n| < 0.5 — a real
2098            // section provably crosses, and does so near-tangentially, the only
2099            // regime where the clip wobbles; this also bounds the extra march to
2100            // grazing pairs), and requires a >0.1%-of-length margin so
2101            // raw-sampling jitter (t660: 0.02%) cannot flip a clean pair.
2102            // Fail-soft: any swapped-march or comparison-clip error keeps the
2103            // forward result.
2104            if !branches.is_empty()
2105                && !seed_points.is_empty()
2106                && min_seed_tangency < 0.5
2107                && pair_classification.relation == SurfacePairRelation::Candidate
2108                && std::env::var("BREP_MARCH_SWAP_CLIP_RESCUE").as_deref() != Ok("0")
2109            {
2110                let swapped = intersect_surfaces(
2111                    second_march,
2112                    first_march,
2113                    &SurfaceIntersectionOptions {
2114                        tolerance: options.tolerance,
2115                        maximum_step: march_maximum_step(
2116                            &pair_classification,
2117                            options.maximum_ssi_step,
2118                            builder.scale,
2119                        ),
2120                        seed_points: seed_points.clone(),
2121                        span_budget: march_span_budget,
2122                        ordered_starts,
2123                        consume_starts,
2124                        tree_seeds,
2125                        ..Default::default()
2126                    },
2127                )
2128                .unwrap_or_default();
2129                // Only a swap that reproduces the SAME branch count — a
2130                // refined-endpoint variant of the same section, not a different
2131                // branch decomposition (guards against adopting a spurious
2132                // extra branch as "longer").
2133                if !swapped.is_empty() && swapped.len() == branches.len() {
2134                    let totals = (|| -> Result<(f64, f64), KernelRefusal> {
2135                        let mut fwd = 0.0;
2136                        for b in &branches {
2137                            let refined = insert_seed_points_into_branch(
2138                                &b.points,
2139                                &seed_points,
2140                                options.tolerance,
2141                            );
2142                            for run in clip_branch_to_trims(&refined, first, second)? {
2143                                fwd += run
2144                                    .windows(2)
2145                                    .map(|p| p[1].sub(p[0]).length())
2146                                    .sum::<f64>();
2147                            }
2148                        }
2149                        let mut swp = 0.0;
2150                        for b in &swapped {
2151                            let refined = insert_seed_points_into_branch(
2152                                &b.points,
2153                                &seed_points,
2154                                options.tolerance,
2155                            );
2156                            for run in clip_branch_to_trims(&refined, first, second)? {
2157                                swp += run
2158                                    .windows(2)
2159                                    .map(|p| p[1].sub(p[0]).length())
2160                                    .sum::<f64>();
2161                            }
2162                        }
2163                        Ok((fwd, swp))
2164                    })();
2165                    if let Ok((fwd_clip, swp_clip)) = totals {
2166                        let margin = fwd_clip.max(swp_clip) * 1.0e-3;
2167                        let adopt = swp_clip > fwd_clip + margin;
2168                        if debug_pairs {
2169                            eprintln!(
2170                                "pair {}x{}: CLIP-SWAP RESCUE fwd_clip={:.6} swp_clip={:.6} margin={:.6}{}",
2171                                first.face.id,
2172                                second.face.id,
2173                                fwd_clip,
2174                                swp_clip,
2175                                margin,
2176                                if adopt { " ADOPT" } else { "" }
2177                            );
2178                        }
2179                        if adopt {
2180                            branches = swapped;
2181                            clip_swap_rescues += 1;
2182                        }
2183                    }
2184                }
2185            }
2186            if let Some(started) = rescue_started {
2187                profile.rescue_march += started.elapsed();
2188            }
2189            if branches.iter().any(|branch| branch.points.len() >= 2) {
2190                section_evidence = true;
2191            }
2192            if debug_pairs {
2193                eprintln!(
2194                    "pair {}x{}: MARCH {} branches, pts {:?}",
2195                    first.face.id,
2196                    second.face.id,
2197                    branches.len(),
2198                    branches.iter().map(|b| b.points.len()).collect::<Vec<_>>()
2199                );
2200            }
2201            for branch in branches {
2202                // The pierce seeds are the section's exact trim-crossing
2203                // points — insert them so no trim interval shorter than the
2204                // march step is invisible to the point-classification clip.
2205                let refined_points =
2206                    insert_seed_points_into_branch(&branch.points, &seed_points, options.tolerance);
2207                let clip_started = profile.enabled.then(Instant::now);
2208                let runs = clip_branch_to_trims(&refined_points, first, second)?;
2209                if debug_pairs {
2210                    let dups = |points: &[Vec3]| points.windows(2).enumerate().filter(|(_, pair)| pair[1].sub(pair[0]).length() <= options.tolerance).map(|(i, pair)| format!("{i}:{:.2e}", pair[1].sub(pair[0]).length())).collect::<Vec<_>>();
2211                    eprintln!(
2212                        "pair {}x{}: DUPS branch {:?} seeded {:?} runs {:?} seeds {} branch_pts {} seeded_pts {}",
2213                        first.face.id, second.face.id, dups(&branch.points), dups(&refined_points), runs.iter().map(|run| dups(run)).collect::<Vec<_>>(), seed_points.len(), branch.points.len(), refined_points.len()
2214                    );
2215                }
2216                if let Some(started) = clip_started {
2217                    profile.clip += started.elapsed();
2218                }
2219                for run in runs {
2220                    if debug_pairs {
2221                        eprintln!(
2222                            "pair {}x{}: clip run len_pts={} length={:.4e}",
2223                            first.face.id,
2224                            second.face.id,
2225                            run.len(),
2226                            run.windows(2)
2227                                .map(|pair| pair[1].sub(pair[0]).length())
2228                                .sum::<f64>()
2229                        );
2230                    }
2231                    if run.len() < 2 {
2232                        continue;
2233                    }
2234                    let length: f64 = run
2235                        .windows(2)
2236                        .map(|pair| pair[1].sub(pair[0]).length())
2237                        .sum();
2238                    if length <= options.tolerance * 100.0 {
2239                        continue;
2240                    }
2241                    let shared_started = profile.enabled.then(Instant::now);
2242                    let follows_shared = branch_follows_shared_boundary(
2243                        &run,
2244                        first,
2245                        second,
2246                        &builder.edges,
2247                        options.tolerance,
2248                        builder.scale,
2249                    )?;
2250                    if let Some(started) = shared_started {
2251                        profile.shared_boundary += started.elapsed();
2252                    }
2253                    if follows_shared {
2254                        if debug_pairs {
2255                            eprintln!(
2256                                "pair {}x{}: run dropped (follows shared boundary)",
2257                                first.face.id, second.face.id
2258                            );
2259                        }
2260                        continue;
2261                    }
2262                    if let Some(census) = pair_census.as_mut() {
2263                        census.record_stations(&run);
2264                    }
2265                    let pieces_before = builder.pieces.len();
2266                    let chunk_points = options.fit_chunk_points.unwrap_or(run.len()).max(2);
2267                    let mut start = 0;
2268                    while start + 1 < run.len() {
2269                        let end = (start + chunk_points - 1).min(run.len() - 1);
2270                        // HERMITE EMISSION (`imprint/hermite.rs`): with the lane on
2271                        // and every span of this run within the budget, the section
2272                        // is the march's own cubic Hermite with its two parameter
2273                        // Hermites, and the fit lane below is skipped.
2274                        let hermite_started = profile.enabled.then(Instant::now);
2275                        let hermite: Option<Result<super::hermite::HermiteSection, super::hermite::HermiteDecline>> = if hermite_lane {
2276                            Some(match march_span_budget {
2277                                Some(budget) => super::hermite::hermite_section(&run[start..=end], &branch, first_march, second_march, budget)
2278                                    .or_refuse(KernelStage::Intersect, "csg.imprint.driver.hermite")?,
2279                                None => Err(super::hermite::HermiteDecline::NoTangents),
2280                            })
2281                        } else {
2282                            None
2283                        };
2284                        if let Some(started) = hermite_started {
2285                            profile.hermite += started.elapsed();
2286                        }
2287                        let (section_curve, exact_pcurves) = match hermite {
2288                            Some(Ok(emitted)) => {
2289                                profile.hermite_runs += 1;
2290                                span_census(|| {
2291                                    format!(
2292                                        "pair {}x{} budget {} branch_stations {} run_stations {} kept {} span_deviation {:.3e} tangents true route None met_requested true lane hermite inserted {}",
2293                                        first.face.id,
2294                                        second.face.id,
2295                                        march_span_budget.map_or("none".to_string(), |budget| format!("{budget:.3e}")),
2296                                        branch.points.len(),
2297                                        emitted.stations,
2298                                        emitted.stations,
2299                                        emitted.deviation,
2300                                        emitted.inserted,
2301                                    )
2302                                });
2303                                (emitted.curve, Some([emitted.pcurve_a, emitted.pcurve_b]))
2304                            }
2305                            other => {
2306                        let hermite_decline = other.map(|lane| lane.err());
2307                        profile.fit_runs += 1;
2308                        let fit_started = profile.enabled.then(Instant::now);
2309                        let fit_tolerance = options.tolerance.max(1e-7);
2310                        let (mut section, mut fit, recovered, evening) = even_sliver_ends_measured(
2311                            run[start..=end].to_vec(),
2312                            &first.face.surface,
2313                            &second.face.surface,
2314                            options.tolerance,
2315                            fit_tolerance,
2316                            options.maximum_fit_points,
2317                            options.local_fit,
2318                        )
2319                        .or_refuse(KernelStage::Intersect, "csg.imprint.driver.sliver_end")?;
2320                        if evening != SliverEvening::NoSliver {
2321                            if let Ok(path) = std::env::var("BREP_SECTION_SLIVER_CENSUS") {
2322                                use std::io::Write;
2323                                if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open(path) {
2324                                    let _ = writeln!(file, "sliver-end census: pair {}x{} {evening:?} stations {}", first.face.id, second.face.id, section.len());
2325                                }
2326                            }
2327                        }
2328                        // A recovered fit may reproduce every march point yet
2329                        // still wander off the carriers between sparse stations.
2330                        // Measure it against both supports before accepting that
2331                        // recovery, and use the existing bounded SSI refiner.
2332                        let met_requested = fit.report.met_requested_tolerance();
2333                        let refine_route = section_refine_route(
2334                            section_refine_gate(),
2335                            recovered,
2336                            || {
2337                                paired_grazing_crossings
2338                                    && std::env::var("BREP_GRAZE_SECTION_REFINE").as_deref() != Ok("0")
2339                            },
2340                            met_requested,
2341                        )
2342                        .or_else(|| {
2343                            // `BREP_SECTION_CARRIER_MISS=0` restores the fast path
2344                            // for an attribution A/B only (default on).
2345                            if std::env::var("BREP_SECTION_CARRIER_MISS").as_deref() == Ok("0") {
2346                                return None;
2347                            }
2348                            let (station_upper, midspan_upper) =
2349                                fast_path_carrier_readings(&fit, &section, &first.face.surface, &second.face.surface);
2350                            carrier_miss_route(station_upper, midspan_upper, fit_tolerance)
2351                        });
2352                        if let Some((gate, route)) = refine_route {
2353                            let stations_before = fit.kept.len();
2354                            let refine_census = std::env::var("BREP_SECTION_REFINE_CENSUS").ok();
2355                            let (census_head, census_tail) = (section[0], section[section.len() - 1]);
2356                            let refine_started = refine_census.is_some().then(Instant::now);
2357                            // The wrapper's own two lines, inlined so the receipt
2358                            // can be read (behaviour identical to
2359                            // `refine_section_against_carriers`).
2360                            let representatives = std::env::var("BREP_SECTION_REPRESENTATIVES").as_deref() != Ok("0");
2361                            let mut receipt = RefineReceipt::default();
2362                            let (refined, worst, unrefined, rounds, exit) = refine_section_against_carriers_with(
2363                                &mut section,
2364                                fit,
2365                                &first.face.surface,
2366                                &second.face.surface,
2367                                fit_tolerance,
2368                                options.tolerance,
2369                                options.local_fit,
2370                                gate * fit_tolerance,
2371                                representatives,
2372                                &mut receipt,
2373                            ).or_refuse(KernelStage::Intersect, "csg.imprint.driver.midspan")?;
2374                            let _ = &receipt;
2375                            // `BREP_SECTION_REFINE_CENSUS=<file>`: one line per section,
2376                            // appended, so a corpus replay (whose children's stderr is
2377                            // captured) can be read for trip counts and growth.
2378                            // The route, whether the standing fit met its request, and
2379                            // the refiner's own wall time close the line, so a run can
2380                            // total the UNMET-REQUEST route's cost apart from the
2381                            // global gate's (which reads every section).
2382                            if let Some(path) = refine_census {
2383                                use std::io::Write;
2384                                if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open(path) {
2385                                    let _ = writeln!(
2386                                        file,
2387                                        "section-refine census: pair {}x{} exit {:?} rounds {} stations {} -> {} unrefined {:.3e} worst {:.3e} route {:?} met_requested {} ms {:.3} head ({:.9}, {:.9}, {:.9}) tail ({:.9}, {:.9}, {:.9})",
2388                                        first.face.id, second.face.id, exit, rounds, stations_before, refined.kept.len(), unrefined, worst,
2389                                        route, met_requested, refine_started.map_or(0.0, |started| started.elapsed().as_secs_f64() * 1e3),
2390                                        census_head.x, census_head.y, census_head.z, census_tail.x, census_tail.y, census_tail.z
2391                                    );
2392                                }
2393                            }
2394                            if debug_pairs && (rounds > 0 || !matches!(exit, MidspanExit::Converged | MidspanExit::BelowGate)) {
2395                                eprintln!(
2396                                    "pair {}x{}: mid-span refinement {:?} after {} round(s): {} stations, worst {:.3e}",
2397                                    first.face.id, second.face.id, exit, rounds, section.len(), worst
2398                                );
2399                            }
2400                            fit = refined;
2401                        }
2402                        span_census(|| {
2403                            format!(
2404                                "pair {}x{} budget {} branch_stations {} run_stations {} kept {} span_deviation {} tangents {} route {:?} met_requested {} lane fit hermite {}",
2405                                first.face.id,
2406                                second.face.id,
2407                                march_span_budget.map_or("none".to_string(), |budget| format!("{budget:.3e}")),
2408                                branch.points.len(),
2409                                section.len(),
2410                                fit.kept.len(),
2411                                branch.span_deviation.map_or("none".to_string(), |deviation| format!("{deviation:.3e}")),
2412                                branch.tangents.is_some(),
2413                                refine_route.map(|(_, route)| route),
2414                                met_requested,
2415                                hermite_decline.map_or("off".to_string(), |decline| decline.map_or("none".to_string(), |decline| format!("{decline:?}"))),
2416                            )
2417                        });
2418                        // `BREP_SECTION_OVERSHOOT_CENSUS=<file>` (debug only; nothing
2419                        // reads it): EVERY section's final fit, on any route, is read
2420                        // against both carriers at its kept stations and at its
2421                        // mid-spans, so a fit that stands further off the carriers
2422                        // between its stations than at them (fixture 28 t217: 5.07e-4
2423                        // shipped against a 1.32e-4 worst station) is counted, not
2424                        // guessed. Projector distances are upper readings; the line
2425                        // says so by its field names.
2426                        {
2427                            if let Ok(path) = std::env::var("BREP_SECTION_OVERSHOOT_CENSUS") {
2428                                // An unreadable station makes the whole reading NaN
2429                                // (f64::max would silently drop it).
2430                                let read = |surface: &NurbsSurface, point: Vec3| {
2431                                    project_point_to_surface(surface, point).map_or(f64::NAN, |projection| projection.distance)
2432                                };
2433                                let mut station_worst = 0.0f64;
2434                                for point in &fit.kept {
2435                                    let (a, b) = (read(&first.face.surface, *point), read(&second.face.surface, *point));
2436                                    station_worst = if a.is_nan() || b.is_nan() || station_worst.is_nan() { f64::NAN } else { station_worst.max(a).max(b) };
2437                                }
2438                                let (run_worst, _) = fast_path_carrier_readings(&fit, &section, &first.face.surface, &second.face.surface);
2439                                let interior_worst = knot_interior_carrier_upper(&fit.curve, &first.face.surface, &second.face.surface);
2440                                let misses = midspan_misses_only(&fit, &first.face.surface, &second.face.surface).unwrap_or_default();
2441                                let (worst_span, midspan_worst) = misses
2442                                    .iter()
2443                                    .copied()
2444                                    .enumerate()
2445                                    .fold((usize::MAX, 0.0f64), |best, (span, miss)| if miss > best.1 { (span, miss) } else { best });
2446                                let line = format!(
2447                                    "section-overshoot census: pair {}x{} route {:?} kept {} spans_read {} station_upper {:.3e} midspan_upper {:.3e} worst_span {} fit_tolerance {:.1e} ratio {:.3} run {} run_upper {run_worst:.3e} knot_interior_upper {interior_worst:.3e} head ({:.9}, {:.9}, {:.9}) tail ({:.9}, {:.9}, {:.9})\n",
2448                                    first.face.id, second.face.id, refine_route.map(|(_, route)| route), fit.kept.len(), misses.len(), station_worst, midspan_worst,
2449                                    if worst_span == usize::MAX { -1 } else { worst_span as i64 }, fit_tolerance,
2450                                    midspan_worst / station_worst.max(fit_tolerance),
2451                                    section.len(),
2452                                    section[0].x, section[0].y, section[0].z,
2453                                    section[section.len() - 1].x, section[section.len() - 1].y, section[section.len() - 1].z
2454                                );
2455                                use std::io::Write;
2456                                if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open(path) {
2457                                    let _ = file.write_all(line.as_bytes());
2458                                }
2459                            }
2460                        }
2461                        if let Some(started) = fit_started {
2462                            profile.fit += started.elapsed();
2463                        }
2464                        if let Some(census) = pair_census.as_mut() {
2465                            census.record_fit(&fit);
2466                        }
2467                        (fit.curve, None)
2468                            }
2469                        };
2470                        let process_started = profile.enabled.then(Instant::now);
2471                        builder.process_curve(
2472                            section_curve,
2473                            first,
2474                            second,
2475                            &[first, second],
2476                            &[first, second],
2477                            true,
2478                            exact_pcurves,
2479                        )?;
2480                        if let Some(started) = process_started {
2481                            profile.process += started.elapsed();
2482                        }
2483                        start = end;
2484                    }
2485                    for piece in &builder.pieces[pieces_before..] {
2486                        builder.marched_pieces.insert(piece.id);
2487                    }
2488                    if debug_pairs {
2489                        eprintln!(
2490                            "pair {}x{}: run -> {} pieces",
2491                            first.face.id,
2492                            second.face.id,
2493                            builder.pieces.len() - pieces_before
2494                        );
2495                    }
2496                }
2497            }
2498            profile.clip_and_fit += profile.lap(&mut lap_start);
2499        }
2500    }
2501    for (span, first, second, target) in deferred_boundary_spans {
2502        builder.process_curve(span, first, second, &[target], &[target], false, None)?;
2503    }
2504    if let Some(scope) = pairs_fits {
2505        profile.pairs_fits = scope.close().fits;
2506    }
2507    profile.report();
2508    // SELF-TOUCH SPLIT: a face whose loops touch at an edge interior (a hole
2509    // tangent to a fillet setback) gets a vertex minted at the touch on BOTH
2510    // edges, so the fragment arrangement's pinch resolution assembles — see
2511    // `imprint/self_touch.rs`. Escape hatch: BREP_SELF_TOUCH_SPLIT=0.
2512    let mut tail_lap: Option<Instant> = None;
2513    // Beside each stage's time, the pcurve fits it recorded (a nested
2514    // `PcurveFitScope` per stage, folded into the operation's ledger).
2515    let mut tail_fits: Option<crate::PcurveFitScope> = None;
2516    let mut tail_ms = Vec::<(&str, f64, u64)>::new();
2517    let mut lap = |name: &'static str,
2518                   started: &mut Option<Instant>,
2519                   fits: &mut Option<crate::PcurveFitScope>,
2520                   tail_ms: &mut Vec<(&str, f64, u64)>| {
2521        if profile.enabled {
2522            let now = Instant::now();
2523            let recorded = fits.take().map_or(0, |scope| scope.close().fits);
2524            if let Some(previous) = *started {
2525                tail_ms.push((name, (now - previous).as_secs_f64() * 1_000.0, recorded));
2526            }
2527            *started = Some(now);
2528            *fits = Some(crate::PcurveFitScope::open());
2529        }
2530    };
2531    lap("pairs", &mut tail_lap, &mut tail_fits, &mut tail_ms);
2532    if std::env::var("BREP_SELF_TOUCH_SPLIT").as_deref() != Ok("0") {
2533        builder.split_self_touching_loops(&first_faces, &face_edge_lists, &cached_subcurve)?;
2534        builder.split_self_touching_loops(&second_faces, &face_edge_lists, &cached_subcurve)?;
2535    }
2536    // PIECE-ENDPOINT EXCHANGE post-pass: with every pair's process_curve
2537    // done, the piece set is final for the ridden-edge class — imprint each
2538    // open riding piece's junction endpoints onto the ridden edges (see the
2539    // method doc; hatch BREP_OVERLAP_PIECE_ENDPOINT_SPLIT=0).
2540    builder.exchange_piece_endpoint_junctions()?;
2541    // TANGENT-SECTION IMPRINT (`ImprintOptions::tangent_curve_imprint`), after
2542    // every pair: whether a run splits a face is read against the face's trim
2543    // AND the pieces the other pairs minted on it, so the runs are minted
2544    // once the piece set is complete (the through-bore's contact ends on the
2545    // bore's cap circles, which the box's top and bottom minted).
2546    for (index, run, first, second) in std::mem::take(&mut tangent_imprint_candidates) {
2547        let closed = tangent_sections[index].closed;
2548        tangent_sections[index].piece_ids = imprint_tangent_run(
2549            &mut builder,
2550            &run,
2551            closed,
2552            first,
2553            second,
2554            &face_edge_lists,
2555            options,
2556            std::env::var("BREP_DEBUG_PAIRS").is_ok(),
2557        )?;
2558    }
2559    // TANGENT-SECTION T-JUNCTIONS (`ImprintOptions::tangent_curve_imprint`):
2560    // an imprinted contact ends on operand edges, which `process_curve` split,
2561    // and on earlier SECTIONS of the same carrier, which nothing splits — the
2562    // through-bore's contact line ends on the two cap circles the box's top
2563    // and bottom minted on the bore. Split those pieces at the contact's end
2564    // vertices so both faces of each circle carry the vertex the bore's
2565    // arrangement needs there (see `split_pieces_at_tangent_ends`).
2566    if tangent_sections.iter().any(|section| !section.piece_ids.is_empty()) {
2567        split_pieces_at_tangent_ends(
2568            &mut builder,
2569            &tangent_sections,
2570            &first_faces,
2571            &second_faces,
2572            options,
2573            std::env::var("BREP_DEBUG_PAIRS").is_ok(),
2574        )?;
2575    }
2576    lap("self_touch", &mut tail_lap, &mut tail_fits, &mut tail_ms);
2577    let mut edge_splits = builder
2578        .edge_splits
2579        .into_iter()
2580        .map(|((operand, edge_id), mut parameters)| {
2581            parameters.sort_by(f64::total_cmp);
2582            EdgeSplitRecord {
2583                operand,
2584                edge_id,
2585                parameters,
2586            }
2587        })
2588        .collect::<Vec<_>>();
2589    edge_splits.sort_by_key(|record| (record.operand, record.edge_id));
2590    let mut by_face = builder
2591        .by_face
2592        .into_iter()
2593        .map(|(face, piece_ids)| FaceImprints {
2594            operand: face.operand,
2595            face_id: face.face_id,
2596            piece_ids,
2597        })
2598        .collect::<Vec<_>>();
2599    by_face.sort_by_key(|record| (record.operand, record.face_id));
2600    let section_evidence = section_evidence || !builder.pieces.is_empty();
2601    let marched_pieces = std::mem::take(&mut builder.marched_pieces);
2602    let mut emitted_pcurves = std::mem::take(&mut builder.emitted_pcurves);
2603    let junction_evidence = JunctionEvidence {
2604        radii: std::mem::take(&mut builder.vertex_radii),
2605        sources: std::mem::take(&mut builder.vertex_sources),
2606    };
2607    let mut result = ImprintResultRecord {
2608        tangent_nodes,
2609        tangent_sections,
2610        vertices: builder.vertices,
2611        pieces: builder.pieces,
2612        by_face,
2613        edge_splits,
2614        barrier_edges: builder.barrier_edges.into_iter().collect(),
2615        section_evidence,
2616        cosurface_pairs,
2617    };
2618    RESCUE_FIRINGS.with(|cell| cell.set((march_swap_rescues, clip_swap_rescues)));
2619    if profile.enabled {
2620        eprintln!("imprint.rescues march_swap={march_swap_rescues} clip_swap={clip_swap_rescues}");
2621    }
2622    // COINCIDENT-PIECE MERGE (problemInbox equator-tangent, and the generic
2623    // one-circle-from-many-pairs class): the SAME section curve can be minted
2624    // by several pairs — a cosurface boundary-edge copy (the cylinder cap
2625    // ring lying ON the inscribed sphere) AND the cap-plane's analytic
2626    // section ring are one circle minted twice, each carrying only its own
2627    // pair's supports/pcurves. Assembly then builds duplicate edges that
2628    // cannot both be two-use → one-use strands. Merge pieces whose curves
2629    // coincide along their whole span (bidirectional max deviation within
2630    // the weld band): keep the first, union the supports/pcurves/by_face
2631    // registrations of the rest into it. Escape hatch:
2632    // BREP_COINCIDENT_PIECE_MERGE=0.
2633    lap("collect", &mut tail_lap, &mut tail_fits, &mut tail_ms);
2634    if std::env::var("BREP_COINCIDENT_PIECE_MERGE").as_deref() != Ok("0") {
2635        let weld = assembler_weld(options.tolerance).max(options.tolerance * 10.0);
2636        // Two pieces that coincide along their WHOLE spans (deviation within
2637        // the weld both ways) also have matching end points, up to direction
2638        // and a weld or two of overhang, so a piece whose ends are nowhere
2639        // near the other's needs no 33-station projection sweep. The sweep is
2640        // what made this pass quadratic in wall time: 630 pieces cost 3.2 s
2641        // of a 3.8 s imprint on the 2026-09-12 mesh-import report, all of it
2642        // rejecting pairs an end-point look already rules out.
2643        let mut ends: Vec<[Vec3; 2]> = Vec::with_capacity(result.pieces.len());
2644        for piece in &result.pieces {
2645            let [d0, d1] = piece.curve.domain().or_refuse(KernelStage::Intersect, "domain")?;
2646            ends.push([
2647                piece.curve.evaluate(d0).or_refuse(KernelStage::Intersect, "evaluate")?,
2648                piece.curve.evaluate(d1).or_refuse(KernelStage::Intersect, "evaluate")?,
2649            ]);
2650        }
2651        let end_band = 4.0 * weld;
2652        // CONTROL-HULL CULL (2026-10-10): the plate minus 36 cylinders mints 72
2653        // CLOSED rings, every one of which took the full sweep against every other —
2654        // 2 556 pairs, 230 of the imprint's 288 ms — although rings 16 units apart
2655        // cannot coincide. A NURBS curve lies in the convex hull of its control
2656        // points, so two curves within `weld` of each other along their whole spans
2657        // have control boxes that overlap once each is grown by `weld`; a pair whose
2658        // boxes do not is skipped before any projection. Exact, so the merged set is
2659        // the one the sweep alone found. `BREP_COINCIDENT_MERGE_BOX=0` restores the
2660        // unculled sweep for a before/after reading.
2661        let box_cull = std::env::var("BREP_COINCIDENT_MERGE_BOX").as_deref() != Ok("0");
2662        let mut boxes: Vec<[Vec3; 2]> = Vec::with_capacity(result.pieces.len());
2663        for piece in &result.pieces {
2664            boxes.push(control_hull_box(&piece.curve, weld));
2665        }
2666        // A CLOSED piece (a full ring) has no end points to speak of: two
2667        // rings of the same circle seamed at different azimuths coincide
2668        // along their whole spans while their domain ends sit anywhere on
2669        // the ring, so a closed piece always takes the full sweep.
2670        let ends_match = |a: &[Vec3; 2], b: &[Vec3; 2]| -> bool {
2671            let near = |p: Vec3, q: Vec3| p.sub(q).length() <= end_band;
2672            near(a[0], a[1])
2673                || near(b[0], b[1])
2674                || (near(a[0], b[0]) && near(a[1], b[1]))
2675                || (near(a[0], b[1]) && near(a[1], b[0]))
2676        };
2677        let mut removed: Vec<u64> = Vec::new();
2678        let mut index = 0;
2679        while index < result.pieces.len() {
2680            let mut other = index + 1;
2681            while other < result.pieces.len() {
2682                let coincide = (!box_cull || boxes_overlap(&boxes[index], &boxes[other]))
2683                    && ends_match(&ends[index], &ends[other])
2684                    && {
2685                        let a = &result.pieces[index];
2686                        let b = &result.pieces[other];
2687                        max_curve_deviation(&a.curve, &b.curve)? <= weld
2688                            && max_curve_deviation(&b.curve, &a.curve)? <= weld
2689                    };
2690                if coincide {
2691                    let absorbed = result.pieces.remove(other);
2692                    ends.remove(other);
2693                    boxes.remove(other);
2694                    removed.push(absorbed.id);
2695                    let keeper = &mut result.pieces[index];
2696                    for pcurve in absorbed.pcurves {
2697                        if !keeper
2698                            .pcurves
2699                            .iter()
2700                            .any(|existing| {
2701                                existing.operand == pcurve.operand
2702                                    && existing.face_id == pcurve.face_id
2703                            })
2704                        {
2705                            let key = FaceKey { operand: pcurve.operand, face_id: pcurve.face_id };
2706                            if emitted_pcurves.remove(&(absorbed.id, key)) {
2707                                emitted_pcurves.insert((keeper.id, key));
2708                            }
2709                            keeper.pcurves.push(pcurve);
2710                        }
2711                    }
2712                    let keeper_id = keeper.id;
2713                    for record in &mut result.by_face {
2714                        if let Some(position) =
2715                            record.piece_ids.iter().position(|&id| id == absorbed.id)
2716                        {
2717                            if record.piece_ids.contains(&keeper_id) {
2718                                record.piece_ids.remove(position);
2719                            } else {
2720                                record.piece_ids[position] = keeper_id;
2721                            }
2722                        }
2723                    }
2724                } else {
2725                    other += 1;
2726                }
2727            }
2728            index += 1;
2729        }
2730        if !removed.is_empty() && std::env::var("BREP_DEBUG_BOOL").is_ok() {
2731            eprintln!("coincident-piece merge: absorbed {:?}", removed);
2732        }
2733    }
2734    // Rescue near-tangent SSI truncations BEFORE canonicalization so the added
2735    // bridge pieces' endpoints (existing crossing/stub vertices) fold into the
2736    // same junction merges as every other section.
2737    lap("coincident_merge", &mut tail_lap, &mut tail_fits, &mut tail_ms);
2738    extend_truncated_sections(
2739        &mut result,
2740        &face_edge_lists,
2741        solid_a,
2742        solid_b,
2743        &charts,
2744        options.tolerance,
2745    )?;
2746    lap("extend_truncated", &mut tail_lap, &mut tail_fits, &mut tail_ms);
2747    canonicalize_imprint_junctions(
2748        &mut result,
2749        solid_a,
2750        solid_b,
2751        &charts,
2752        options.tolerance,
2753        &emitted_pcurves,
2754        &junction_evidence,
2755        junction_combine_mode(options),
2756    )?;
2757    lap("canonicalize", &mut tail_lap, &mut tail_fits, &mut tail_ms);
2758    // ONE RIM, ONE EDGE: with vertex identity final, dissolve the section
2759    // vertices that no operand edge passes through — the marcher's own
2760    // parameterization origin, which `process_curve` cannot tell from a
2761    // junction because it sees one pair at a time. See the method doc.
2762    let dissolved = dissolve_section_origin_vertices(
2763        &mut result,
2764        &marched_pieces,
2765        solid_a,
2766        solid_b,
2767        &charts,
2768        options.tolerance,
2769    )?;
2770    if dissolved > 0 && std::env::var("BREP_DEBUG_BOOL").is_ok() {
2771        eprintln!("origin-dissolve: {dissolved} parameterization vertex/vertices removed");
2772    }
2773    lap("origin_dissolve", &mut tail_lap, &mut tail_fits, &mut tail_ms);
2774    // B2: reuse an existing boundary edge as the shared section edge wherever a
2775    // section coincides with one along its whole span (vertices are final after
2776    // canonicalization; `face_edge_lists` holds each face's boundary edges on
2777    // the healed operands). Runs here so both operands reference ONE edge.
2778    reuse_boundary_section_edges(
2779        &mut result,
2780        &face_edge_lists,
2781        solid_a,
2782        solid_b,
2783        options.tolerance,
2784    )?;
2785    // Capstone step 1 — instrumentation only, zero behavior change: report
2786    // every (section piece × boundary edge) contact where the piece runs
2787    // within the scale-derived band of the edge over a real span. Measuring
2788    // the bands here first validates the graze-contact model on the
2789    // acceptance suite before step 2's common-block machinery replaces a
2790    // grazed overlap with a shared edge.
2791    lap("reuse_boundary", &mut tail_lap, &mut tail_fits, &mut tail_ms);
2792    report_graze_contacts(&result, &face_edge_lists, solid_a, solid_b, options.tolerance)?;
2793    if profile.enabled {
2794        if let Some(scope) = tail_fits.take() {
2795            scope.close();
2796        }
2797        let line = tail_ms
2798            .iter()
2799            .map(|(name, ms, _)| format!("{name}={ms:.2}"))
2800            .collect::<Vec<_>>()
2801            .join(" ");
2802        eprintln!("imprint.stages {line}");
2803        let fits = tail_ms
2804            .iter()
2805            .map(|(name, _, fits)| format!("{name}={fits}"))
2806            .collect::<Vec<_>>()
2807            .join(" ");
2808        eprintln!("imprint.stage_fits {fits}");
2809    }
2810    Ok(result)
2811}
2812
2813/// Debug-only graze-contact survey (`BREP_DEBUG_GRAZE=1`): for each section
2814/// piece and each boundary edge of its support faces, sample the piece and
2815/// measure distance to the edge; report contacts whose in-band span exceeds
2816/// both the weld scale and 4× the minimum deviation (span-wise proximity, not
2817/// a point touch). `band_cap` reuses the residual-merge `sep_cap` ceiling —
2818/// measured, never grown. The output is the raw material for capstone step 2
2819/// (partial-span common-block): which contacts exist, their spans, and their
2820/// measured bands.
2821fn report_graze_contacts(
2822    result: &ImprintResultRecord,
2823    face_edge_lists: &HashMap<FaceKey, Vec<&EdgeRecord>>,
2824    solid_a: &BrepSolid,
2825    solid_b: &BrepSolid,
2826    tolerance: f64,
2827) -> Result<(), KernelRefusal> {
2828    if std::env::var("BREP_DEBUG_GRAZE").as_deref() != Ok("1") {
2829        return Ok(());
2830    }
2831    let raw_extent = raw_solid_extent(solid_a).max(raw_solid_extent(solid_b));
2832    let (_, band_cap) = residual_merge_bands(raw_extent, tolerance);
2833    const SAMPLES: usize = 17;
2834    for piece in &result.pieces {
2835        let [t0, t1] = [piece.t0, piece.t1];
2836        if !(t1 > t0) {
2837            continue;
2838        }
2839        for key in piece.support_faces {
2840            let Some(edges) = face_edge_lists.get(&key) else {
2841                continue;
2842            };
2843            for edge in edges {
2844                if edge.degenerate {
2845                    continue;
2846                }
2847                let mut in_band = 0usize;
2848                let mut min_dev = f64::INFINITY;
2849                let mut max_dev_in_band = 0.0f64;
2850                let mut span = 0.0f64;
2851                let mut prev: Option<(bool, Vec3)> = None;
2852                for k in 0..SAMPLES {
2853                    let t = t0 + (t1 - t0) * k as f64 / (SAMPLES - 1) as f64;
2854                    let point = piece.curve.evaluate(t).or_refuse(KernelStage::Intersect, "evaluate")?;
2855                    let deviation = project_point_to_curve(&edge.curve, point).or_refuse(KernelStage::Intersect, "project_point_to_curve")?.distance;
2856                    min_dev = min_dev.min(deviation);
2857                    let inside = deviation <= band_cap;
2858                    if inside {
2859                        in_band += 1;
2860                        max_dev_in_band = max_dev_in_band.max(deviation);
2861                        if let Some((true, prev_point)) = prev {
2862                            span += point.sub(prev_point).length();
2863                        }
2864                    }
2865                    prev = Some((inside, point));
2866                }
2867                // Span-wise contact: several consecutive samples in band and a
2868                // span that dwarfs the closest-approach (not a transversal
2869                // crossing, which dips in and out at one sample).
2870                if in_band >= 3 && span > (4.0 * min_dev).max(assembler_weld(tolerance)) {
2871                    eprintln!(
2872                        "graze: piece {} sup=[{}:{},{}:{}] ~ edge {}:{} span={:.3e} band=[{:.3e},{:.3e}] samples_in_band={}/{}",
2873                        piece.id,
2874                        piece.support_faces[0].operand,
2875                        piece.support_faces[0].face_id,
2876                        piece.support_faces[1].operand,
2877                        piece.support_faces[1].face_id,
2878                        key.operand,
2879                        edge.id,
2880                        span,
2881                        min_dev,
2882                        max_dev_in_band,
2883                        in_band,
2884                        SAMPLES
2885                    );
2886                }
2887            }
2888        }
2889    }
2890    Ok(())
2891}
2892
2893/// Are the two carriers TANGENT (normals parallel) where they both pass through
2894/// `point`?
2895///
2896/// The test the tangential-only refusal above needs: a point on the marched
2897/// intersection is a TANGENT NODE when the two surface normals there are
2898/// parallel. The threshold is the transversality bound the supplemental
2899/// detector already accepts seeds by (`TRANSVERSE_SEED_CROSS`), not the far
2900/// tighter pair-classifier bound — a node the march merely passes CLOSE to
2901/// still poisons the assembly, so this errs toward calling a pair singular.
2902/// The tangent-curve lane's recognition of one pair: find the pair's
2903/// tangential contact without a witness, keep only an EXTENDED one (a node or
2904/// a point contact is the existing paths' business), and with one planar
2905/// carrier march it along the null direction of `II_a − II_b` and clip the
2906/// curve to both trims. `None` when there is no extended contact, or its trace
2907/// has no run inside both trims (a contact on the carriers' extensions
2908/// imprints nothing, exactly as today).
2909///
2910/// The section is RECORDED, not imprinted: a tangent edge whose two sides
2911/// both survive is a four-coedge incidence the assembler cannot represent
2912/// (the pinch gate in `csg/boolean/mod.rs` names the subtract case), and a
2913/// tangent edge only one side of which survives dissolves into its face.
2914/// What the record buys is the boolean's attribution: a refusal whose faces
2915/// the contact involves names the contact instead of the arrangement's own
2916/// symptom. The involved faces are the two carriers' and every face sharing
2917/// an edge a run end lies on (`TangentSectionRecord::faces`).
2918#[allow(clippy::too_many_arguments)]
2919fn tangent_curve_section(
2920    first: TaggedFace<'_>,
2921    second: TaggedFace<'_>,
2922    options: &ImprintOptions,
2923    first_faces: &[TaggedFace<'_>],
2924    second_faces: &[TaggedFace<'_>],
2925    face_edge_lists: &HashMap<FaceKey, Vec<&EdgeRecord>>,
2926    debug_pairs: bool,
2927) -> Result<Option<(TangentSectionRecord, Vec<Vec3>)>, KernelRefusal> {
2928    let Some(contact) =
2929        crate::find_tangent_contact(&first.face.surface, &second.face.surface, options.tolerance)
2930            .or_refuse(KernelStage::Intersect, "find_tangent_contact")?
2931    else {
2932        return Ok(None);
2933    };
2934    if debug_pairs {
2935        eprintln!(
2936            "pair {}x{}: tangent-curve lane contact {:?}",
2937            first.face.id, second.face.id, contact
2938        );
2939    }
2940    if !contact.is_extended() {
2941        return Ok(None);
2942    }
2943    let is_plane = |face: TaggedFace<'_>| {
2944        matches!(face.face.surface.analytic(), Some(crate::AnalyticSurface::Plane { .. }))
2945    };
2946    let planar = is_plane(first) || is_plane(second);
2947    if !planar {
2948        // The curved/curved branch: recognised and named, not traced.
2949        return Ok(Some((
2950            TangentSectionRecord {
2951                first: first.key(),
2952                second: second.key(),
2953                start: contact.point,
2954                end: contact.point,
2955                length: 0.0,
2956                closed: false,
2957                stations: 0,
2958                planar: false,
2959                faces: vec![first.key(), second.key()],
2960                piece_ids: Vec::new(),
2961            },
2962            Vec::new(),
2963        )));
2964    }
2965    let Some(curve) = crate::trace_tangent_curve(
2966        &first.face.surface,
2967        &second.face.surface,
2968        &contact,
2969        &SurfaceIntersectionOptions {
2970            tolerance: options.tolerance,
2971            maximum_step: options.maximum_ssi_step,
2972            ..Default::default()
2973        },
2974    )
2975    .or_refuse(KernelStage::Intersect, "trace_tangent_curve")?
2976    else {
2977        return Ok(None);
2978    };
2979    let mut longest: Option<Vec<Vec3>> = None;
2980    let mut longest_length = 0.0f64;
2981    for run in clip_branch_to_trims(&curve.points, first, second)? {
2982        if run.len() < 2 {
2983            continue;
2984        }
2985        let length: f64 = run.windows(2).map(|pair| pair[1].sub(pair[0]).length()).sum();
2986        if length > longest_length {
2987            longest_length = length;
2988            longest = Some(run);
2989        }
2990    }
2991    let Some(run) = longest else {
2992        return Ok(None);
2993    };
2994    if longest_length <= options.tolerance * 100.0 {
2995        return Ok(None);
2996    }
2997    if debug_pairs {
2998        eprintln!(
2999            "pair {}x{}: tangent-curve lane traced {} stations, run of {} inside both trims, length {:.6}, closed {}",
3000            first.face.id, second.face.id, curve.points.len(), run.len(), longest_length, curve.closed
3001        );
3002    }
3003    let closed = curve.closed && run.len() == curve.points.len();
3004    // The faces the contact involves: the carriers' own, and across every
3005    // edge of theirs that a run end lies on, the faces sharing that edge.
3006    let mut faces = vec![first.key(), second.key()];
3007    if !closed {
3008        let band = options.tolerance * 100.0;
3009        for end in [run[0], run[run.len() - 1]] {
3010            for face in [first, second] {
3011                let Some(edges) = face_edge_lists.get(&face.key()) else {
3012                    continue;
3013                };
3014                for edge in edges {
3015                    if edge.degenerate {
3016                        continue;
3017                    }
3018                    let Ok(projection) = project_point_to_curve(&edge.curve, end) else {
3019                        continue;
3020                    };
3021                    if projection.distance > band {
3022                        continue;
3023                    }
3024                    let siblings = if face.operand == first.operand { first_faces } else { second_faces };
3025                    for sibling in siblings {
3026                        let shares = sibling
3027                            .face
3028                            .loops
3029                            .iter()
3030                            .flat_map(|loop_record| &loop_record.coedges)
3031                            .any(|coedge| coedge.edge_id == edge.id);
3032                        if shares && !faces.contains(&sibling.key()) {
3033                            faces.push(sibling.key());
3034                        }
3035                    }
3036                }
3037            }
3038        }
3039    }
3040    if debug_pairs {
3041        eprintln!(
3042            "pair {}x{}: tangent-curve lane involves faces {:?}",
3043            first.face.id, second.face.id, faces
3044        );
3045    }
3046    Ok(Some((
3047        TangentSectionRecord {
3048            first: first.key(),
3049            second: second.key(),
3050            start: run[0],
3051            end: run[run.len() - 1],
3052            length: longest_length,
3053            closed,
3054            stations: run.len(),
3055            planar: true,
3056            faces,
3057            piece_ids: Vec::new(),
3058        },
3059        run,
3060    )))
3061}
3062
3063/// Imprint a traced tangent run ([`ImprintOptions::tangent_curve_imprint`]):
3064/// the run's stations become a section curve — the exact line through its
3065/// ends when they are collinear (a plane's contact with a cylinder or cone is
3066/// a generatrix), the marched lane's polyline fit otherwise (a torus parallel)
3067/// — and `process_curve` mints it on both carriers exactly as it mints a
3068/// transverse section: pieces with pcurves on each face, the operand edges the
3069/// ends lie on split there. Returns the ids of the pieces minted, in order.
3070///
3071/// Only a run that SPLITS both faces is minted: a closed run, or one each of
3072/// whose ends lies, on each carrier, on that face's trim or on a section
3073/// piece already minted on it (the through-bore's contact ends on the wall's
3074/// top and bottom edges and, on the bore, on the circles the box's top and
3075/// bottom cut there). A run with an end inside a face — the blind pocket's
3076/// contact ends on the bore's cap rings but inside the wall, where both of
3077/// its sides are one face — would be a slit, and a slit is not a boundary:
3078/// measured with the slit minted, the wall's four edges came out one-use and
3079/// the pocket refused `NonIntegralGenus`. Such a contact stays recorded only,
3080/// as before.
3081#[allow(clippy::too_many_arguments)]
3082fn imprint_tangent_run(
3083    builder: &mut ImprintBuilder<'_>,
3084    run: &[Vec3],
3085    closed: bool,
3086    first: TaggedFace<'_>,
3087    second: TaggedFace<'_>,
3088    face_edge_lists: &HashMap<FaceKey, Vec<&EdgeRecord>>,
3089    options: &ImprintOptions,
3090    debug: bool,
3091) -> Result<Vec<u64>, KernelRefusal> {
3092    if run.len() < 2 {
3093        return Ok(Vec::new());
3094    }
3095    if !closed {
3096        let band = options.tolerance * 100.0;
3097        let within = |curve: &NurbsCurve, t0: f64, t1: f64, point: Vec3| -> bool {
3098            project_point_to_curve(curve, point)
3099                .map(|projection| {
3100                    projection.distance <= band
3101                        && projection.u >= t0.min(t1) - 1e-9
3102                        && projection.u <= t0.max(t1) + 1e-9
3103                })
3104                .unwrap_or(false)
3105        };
3106        let on_boundary = |face: TaggedFace<'_>, point: Vec3| -> bool {
3107            let on_trim = face_edge_lists
3108                .get(&face.key())
3109                .map(|edges| {
3110                    edges
3111                        .iter()
3112                        .any(|edge| !edge.degenerate && within(&edge.curve, edge.t0, edge.t1, point))
3113                })
3114                .unwrap_or(false);
3115            on_trim
3116                || builder
3117                    .pieces
3118                    .iter()
3119                    .any(|piece| piece.support_faces.contains(&face.key()) && within(&piece.curve, piece.t0, piece.t1, point))
3120        };
3121        let ends = [run[0], run[run.len() - 1]];
3122        for face in [first, second] {
3123            if !ends.iter().all(|end| on_boundary(face, *end)) {
3124                if debug {
3125                    eprintln!(
3126                        "pair {}x{}: tangent-curve lane run not imprinted: an end lies inside face {}:{}'s trim (a slit)",
3127                        first.face.id, second.face.id, face.operand, face.face.id
3128                    );
3129                }
3130                return Ok(Vec::new());
3131            }
3132        }
3133    }
3134    let start = run[0];
3135    let end = run[run.len() - 1];
3136    let chord = end.sub(start);
3137    let chord_length = chord.length();
3138    let fit_tolerance = options.tolerance.max(1e-7);
3139    let collinear = chord_length > fit_tolerance && {
3140        let direction = chord.scale(1.0 / chord_length);
3141        run.iter().all(|station| {
3142            let offset = station.sub(start);
3143            offset.sub(direction.scale(offset.dot(direction))).length() <= 10.0 * fit_tolerance
3144        })
3145    };
3146    let curve = if collinear {
3147        crate::make_line(start, end).or_refuse(KernelStage::Intersect, "make_line")?
3148    } else {
3149        fit_polyline_of_degree(
3150            run,
3151            fit_tolerance,
3152            run.len().min(MAX_FIT_STATIONS),
3153            options.local_fit,
3154            section_fit_degree(),
3155        )
3156        .or_refuse(KernelStage::Intersect, "fit_polyline_of_degree")?
3157        .curve
3158    };
3159    let before = builder.pieces.len();
3160    builder.process_curve(curve, first, second, &[first, second], &[first, second], true, None)?;
3161    let ids: Vec<u64> = builder.pieces[before..].iter().map(|piece| piece.id).collect();
3162    if debug {
3163        eprintln!(
3164            "pair {}x{}: tangent-curve lane imprinted the run as {} ({} piece(s) {:?})",
3165            first.face.id,
3166            second.face.id,
3167            if collinear { "a line" } else { "a fitted section" },
3168            ids.len(),
3169            ids
3170        );
3171    }
3172    Ok(ids)
3173}
3174
3175/// Split every piece an imprinted tangent section ENDS ON, at that end
3176/// (`ImprintOptions::tangent_curve_imprint`). A tangent run is clipped to both
3177/// trims, so its ends lie on operand edges — split by `process_curve` — or on
3178/// the trim of the OTHER carrier's neighbours, where they also lie on the
3179/// sections those neighbours minted on this carrier: the through-bore's
3180/// contact line ends on the circles the box's top and bottom cut on the bore,
3181/// at a point no edge pierce put a vertex on (the box edge grazes the bore
3182/// there, and a grazing pierce is deliberately not a junction). Without the
3183/// vertex, the bore's arrangement would split the circle where the line
3184/// meets it while the cap's arrangement keeps the circle whole — one closed
3185/// edge against two arcs, one-use at assembly. The piece is split here, at
3186/// the imprint, so every face it is minted on sees the vertex: the halves
3187/// take the tangent end's vertex id, the pcurves are split with the curve
3188/// where they were emitted on its knots and rebuilt on the face's chart
3189/// otherwise, and the piece's face lists and lane sets follow the halves. A
3190/// piece that resolves to an operand edge (`shared_edge`) is left as it is:
3191/// that edge's own split is the exchange pass's.
3192fn split_pieces_at_tangent_ends(
3193    builder: &mut ImprintBuilder<'_>,
3194    sections: &[TangentSectionRecord],
3195    first_faces: &[TaggedFace<'_>],
3196    second_faces: &[TaggedFace<'_>],
3197    options: &ImprintOptions,
3198    debug: bool,
3199) -> Result<(), KernelRefusal> {
3200    let tangent_ids: HashSet<u64> = sections.iter().flat_map(|section| section.piece_ids.iter().copied()).collect();
3201    if tangent_ids.is_empty() {
3202        return Ok(());
3203    }
3204    let overlap_limit = options.tolerance.max(1e-5);
3205    let vertex_points: HashMap<u64, Vec3> =
3206        builder.vertices.iter().map(|vertex| (vertex.id, vertex.point)).collect();
3207    // (end vertex, its point, the tangent piece's supports)
3208    let mut ends: Vec<(u64, Vec3, [FaceKey; 2])> = Vec::new();
3209    for piece in builder.pieces.iter().filter(|piece| tangent_ids.contains(&piece.id)) {
3210        for vertex_id in [piece.start_vertex_id, piece.end_vertex_id] {
3211            if let Some(point) = vertex_points.get(&vertex_id) {
3212                if !ends.iter().any(|(id, _, _)| *id == vertex_id) {
3213                    ends.push((vertex_id, *point, piece.support_faces));
3214                }
3215            }
3216        }
3217    }
3218    let face_of = |key: FaceKey| {
3219        first_faces
3220            .iter()
3221            .chain(second_faces)
3222            .copied()
3223            .find(|face| face.key() == key)
3224    };
3225    let mut index = 0;
3226    while index < builder.pieces.len() {
3227        let piece = &builder.pieces[index];
3228        if tangent_ids.contains(&piece.id) || piece.shared_edge.is_some() || !(piece.t1 > piece.t0) {
3229            index += 1;
3230            continue;
3231        }
3232        let mut split: Option<(u64, f64, Vec3)> = None;
3233        for (vertex_id, point, supports) in &ends {
3234            if *vertex_id == piece.start_vertex_id || *vertex_id == piece.end_vertex_id {
3235                continue;
3236            }
3237            if !supports.iter().any(|support| piece.support_faces.contains(support)) {
3238                continue;
3239            }
3240            let projection = project_point_to_curve(&piece.curve, *point)
3241                .or_refuse(KernelStage::Intersect, "project_point_to_curve")?;
3242            if projection.distance > overlap_limit {
3243                continue;
3244            }
3245            let span = piece.t1 - piece.t0;
3246            let margin = (span * KNOT_IDENTITY_TOL).max(2e-9);
3247            if projection.u <= piece.t0 + margin || projection.u >= piece.t1 - margin {
3248                continue;
3249            }
3250            // Interior in PARAMETER but at an END in space: a closed piece's
3251            // origin seen from the far side of its domain.
3252            if projection.point.sub(vertex_points[&piece.start_vertex_id]).length() <= overlap_limit
3253                || projection.point.sub(vertex_points[&piece.end_vertex_id]).length() <= overlap_limit
3254            {
3255                continue;
3256            }
3257            split = Some((*vertex_id, projection.u, *point));
3258            break;
3259        }
3260        let Some((vertex_id, parameter, point)) = split else {
3261            index += 1;
3262            continue;
3263        };
3264        let piece = builder.pieces.remove(index);
3265        let (left, right) = piece.curve.split(parameter).or_refuse(KernelStage::Intersect, "split")?;
3266        let [left_t0, _] = left.domain().or_refuse(KernelStage::Intersect, "domain")?;
3267        let [_, right_t1] = right.domain().or_refuse(KernelStage::Intersect, "domain")?;
3268        let start_point = vertex_points[&piece.start_vertex_id];
3269        let end_point = vertex_points[&piece.end_vertex_id];
3270        let left = snap_curve_ends(&left, start_point, point)?;
3271        let right = snap_curve_ends(&right, point, end_point)?;
3272        let left_id = builder.next_id;
3273        let right_id = builder.next_id + 1;
3274        builder.next_id += 2;
3275        let mut left_pcurves = Vec::with_capacity(piece.pcurves.len());
3276        let mut right_pcurves = Vec::with_capacity(piece.pcurves.len());
3277        for face_pcurve in &piece.pcurves {
3278            let key = FaceKey { operand: face_pcurve.operand, face_id: face_pcurve.face_id };
3279            let emitted = builder.emitted_pcurves.remove(&(piece.id, key));
3280            let halves = if emitted {
3281                match face_pcurve.pcurve.split(parameter) {
3282                    Ok((a, b)) => {
3283                        builder.emitted_pcurves.insert((left_id, key));
3284                        builder.emitted_pcurves.insert((right_id, key));
3285                        Some((a, b))
3286                    }
3287                    Err(_) => None,
3288                }
3289            } else {
3290                None
3291            };
3292            let (a, b) = match halves {
3293                Some(halves) => halves,
3294                None => {
3295                    let Some(face) = face_of(key) else {
3296                        return Err(KernelRefusal::internal(
3297                            KernelStage::Intersect,
3298                            "imprint.tangent_split",
3299                            format!("tangent-section split: piece {} has a pcurve on an unknown face {key:?}", piece.id),
3300                        ));
3301                    };
3302                    (
3303                        build_pcurve_on_surface_marched(face.chart(), &left)
3304                            .or_refuse(KernelStage::Intersect, "build_pcurve_on_surface_marched")?,
3305                        build_pcurve_on_surface_marched(face.chart(), &right)
3306                            .or_refuse(KernelStage::Intersect, "build_pcurve_on_surface_marched")?,
3307                    )
3308                }
3309            };
3310            left_pcurves.push(FacePcurve { operand: key.operand, face_id: key.face_id, pcurve: a });
3311            right_pcurves.push(FacePcurve { operand: key.operand, face_id: key.face_id, pcurve: b });
3312        }
3313        if builder.marched_pieces.remove(&piece.id) {
3314            builder.marched_pieces.insert(left_id);
3315            builder.marched_pieces.insert(right_id);
3316        }
3317        for ids in builder.by_face.values_mut() {
3318            if let Some(slot) = ids.iter().position(|id| *id == piece.id) {
3319                ids[slot] = left_id;
3320                ids.insert(slot + 1, right_id);
3321            }
3322        }
3323        if debug {
3324            eprintln!(
3325                "tangent-curve lane: piece {} split at vertex {} (t={parameter:.6}) into pieces {left_id} and {right_id}",
3326                piece.id, vertex_id
3327            );
3328        }
3329        builder.pieces.insert(
3330            index,
3331            ImprintPieceRecord {
3332                id: left_id,
3333                curve: left,
3334                t0: left_t0,
3335                t1: parameter,
3336                start_vertex_id: piece.start_vertex_id,
3337                end_vertex_id: vertex_id,
3338                pcurves: left_pcurves,
3339                support_faces: piece.support_faces,
3340                shared_edge: None,
3341            },
3342        );
3343        builder.pieces.insert(
3344            index + 1,
3345            ImprintPieceRecord {
3346                id: right_id,
3347                curve: right,
3348                t0: parameter,
3349                t1: right_t1,
3350                start_vertex_id: vertex_id,
3351                end_vertex_id: piece.end_vertex_id,
3352                pcurves: right_pcurves,
3353                support_faces: piece.support_faces,
3354                shared_edge: None,
3355            },
3356        );
3357        // Re-examine the halves: a run may end on the same piece twice.
3358    }
3359    Ok(())
3360}
3361
3362fn pair_normals_parallel_at(
3363    first: TaggedFace<'_>,
3364    second: TaggedFace<'_>,
3365    point: Vec3,
3366) -> Result<bool, KernelRefusal> {
3367    let mut normals = [Vec3::default(); 2];
3368    for (slot, face) in normals.iter_mut().zip([first, second]) {
3369        let projection = project_point_to_surface(&face.face.surface, point)
3370            .or_refuse(KernelStage::Intersect, "project_point_to_surface")?;
3371        let Ok(normal) = face.face.surface.normal(projection.u, projection.v) else {
3372            // A pole/singular parameter point cannot witness transversality;
3373            // treat it as tangential so the pair stays refused.
3374            return Ok(true);
3375        };
3376        *slot = normal;
3377    }
3378    Ok(normals[0].cross(normals[1]).length() <= crate::TRANSVERSE_SEED_CROSS)
3379}