Split out of #3341 so that fix's green is not read as covering this.
#3341 was one specific defect: the parity ray-cast in point_inside used a segment sized to the OTHER operand's extent, so the endpoint could land inside the target, miss the exit crossing, and delete a face. That is fixed, and against an analytic oracle the predicate now agrees on 4,000,000 queries where main was wrong 8947 times.
A separate family of tears survives it.
Measurement
A sweep of 60000 random box pairs, run before and after the #3341 fix, across Difference, Union and Intersection, over touching / disjoint / overlapping / rotated configurations. "Torn" means the boolean result has a non-zero directed-edge imbalance when both operands went in closed.
- Disjoint pairs tear at 0.16% on main across all three ops and go to exactly 0 with the fix. That family is closed.
- 96 of 60000 pairs still tear with the fix, concentrated in:
- overlapping pairs: 0.16 to 0.28%
- rotated (non-axis-aligned) pairs: 0.08 to 0.38%
- touching pairs under Union: 0.10%
The fix never creates a tear: its torn set is a strict subset of main's in every cell measured.
Why it is a distinct defect
38 of the 96 were drilled into. 37 of 38 show flipped = 0 — no classification verdict changed between the pre-fix and post-fix predicate. So these tears are not caused by the parity endpoint at all; they were there before #3341 and are untouched by it.
That points at the arrangement or retriangulation stage rather than at classification, but which stage is unproven — nobody has traced one of these to a line yet.
Why it matters
This is the same failure shape as #3341: two closed operands in, a non-watertight shell out. It is the mechanism behind the torn thin IfcCovering layers reported in the #3219 investigation (198 and 662 edges of degree != 2), which survived every cap-gate variant tried and survived setting the flush-cap pad to zero.
ClippingProcessor::validate_mesh (rust/geometry/src/csg/mod.rs) checks only NaN, Inf and index bounds, so none of this is caught at the boundary. Note that enforcing closed-in/closed-out there is measured to be actively harmful (4 suite failures, watertightness up to 8.6x worse, #1007 reopened, +114% volume on 841_house #3698 via the #635 AABB fallback, 114 census regressions) — it should become an observation column, not a gate. Tracked separately.
Suggested start
Take one rotated overlapping pair from the sweep, confirm both operands are closed going in, and bisect the pipeline the way #3341 was bisected: operands in, boolean() out, then consolidate_coplanar. #3341 turned out to be upstream of consolidation; this one may not be.
Split out of #3341 so that fix's green is not read as covering this.
#3341 was one specific defect: the parity ray-cast in
point_insideused a segment sized to the OTHER operand's extent, so the endpoint could land inside the target, miss the exit crossing, and delete a face. That is fixed, and against an analytic oracle the predicate now agrees on 4,000,000 queries where main was wrong 8947 times.A separate family of tears survives it.
Measurement
A sweep of 60000 random box pairs, run before and after the #3341 fix, across Difference, Union and Intersection, over touching / disjoint / overlapping / rotated configurations. "Torn" means the boolean result has a non-zero directed-edge imbalance when both operands went in closed.
The fix never creates a tear: its torn set is a strict subset of main's in every cell measured.
Why it is a distinct defect
38 of the 96 were drilled into. 37 of 38 show
flipped = 0— no classification verdict changed between the pre-fix and post-fix predicate. So these tears are not caused by the parity endpoint at all; they were there before #3341 and are untouched by it.That points at the arrangement or retriangulation stage rather than at classification, but which stage is unproven — nobody has traced one of these to a line yet.
Why it matters
This is the same failure shape as #3341: two closed operands in, a non-watertight shell out. It is the mechanism behind the torn thin
IfcCoveringlayers reported in the #3219 investigation (198 and 662 edges of degree != 2), which survived every cap-gate variant tried and survived setting the flush-cap pad to zero.ClippingProcessor::validate_mesh(rust/geometry/src/csg/mod.rs) checks only NaN, Inf and index bounds, so none of this is caught at the boundary. Note that enforcing closed-in/closed-out there is measured to be actively harmful (4 suite failures, watertightness up to 8.6x worse, #1007 reopened, +114% volume on841_house#3698 via the #635 AABB fallback, 114 census regressions) — it should become an observation column, not a gate. Tracked separately.Suggested start
Take one rotated overlapping pair from the sweep, confirm both operands are closed going in, and bisect the pipeline the way #3341 was bisected: operands in,
boolean()out, thenconsolidate_coplanar. #3341 turned out to be upstream of consolidation; this one may not be.