Fix issue #88: seven volumetric corpus mismatches, root-caused individually - #106
Merged
Conversation
…dually Rebuilt the v3.9 volumetric-comparison toolchain (real OpenSCAD oracle, Manifold, headless chiselcad_core) and bisected each of the seven files issue #88 flagged. All seven are real, distinct bugs, now fixed: - ifelse-tests.scad: cube()/square()'s positional `center` argument (`cube(2, true)`) was silently dropped by the parser. - primitive-inf-tests.scad: non-finite cube/sphere/cylinder dimensions were folded to 0 instead of rejected, sometimes producing a valid but wrong shape instead of empty geometry; a non-finite $fn also escaped its minimum-segment clamp via undefined int-cast behavior. - surface-simple.scad: surface()'s base was clamped to 0 instead of real OpenSCAD's `minHeight - 1`, `center` incorrectly re-centered Z, and the row-to-Y mapping was flipped relative to real OpenSCAD. - module-recursion.scad: rotate([x,y,z]) composed its three axis rotations in the reverse order from real OpenSCAD's X,Y,Z convention. - resize-tests.scad: resize()'s negative-newsize and auto= handling didn't match real OpenSCAD's actual algorithm. - intersection-tests.scad: an empty-geometry operand was silently dropped instead of nullifying the whole intersection(); excluded non-geometric statements (echo/assert) and '%'-backgrounded children from that rule so they're still just skipped. - cylinder-tests.scad: when both r and r1/r2 were given, r unconditionally overwrote both instead of only filling the unspecified slot. Re-verified against the live OpenSCAD oracle across the entire tests/data/scad/3D/features corpus (not just these seven files), which caught and fixed a regression the intersection() fix introduced in background-modifier2.scad. Filed issue #105 for a pre-existing, unrelated crash found during that sweep (linear_extrude-parameter-tests.scad). 9 new regression tests added; full chiselcad_tests suite passes (3679 assertions, 664 test cases). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PTiTkTcWUPE4ucANory5WA
particlesector
commented
Aug 12, 2026
particlesector
left a comment
Owner
Author
There was a problem hiding this comment.
Reviewed the diff (excluding docs/roadmap.md and fixtures). Each of the seven fixes is narrowly scoped, well-justified in comments, and backed by a targeted regression test:
Parser.cpp's positionaltrue/falsehandling is correctly confined toparseParamList(cube/sphere/cylinder/square/circle + discarded-params call sites), not the generic user-module-call path, so it can't misinterpret a custom module's positional bool arg ascenter.evalBoolean's new intersection-emptiness check correctly re-inspectsastModifiers(*child)directly to distinguish "genuinely empty child" from "disabled/backgrounded child," sinceevalNodealready consumes those modifiers before returning nullptr — no double-counting.MeshEvaluator::checkStatusnow discarding the manifold on error (not just the 7 named files) is the broadest behavioral change here, but it's covered by the described 72/73-file oracle resweep with no regressions, so it looks safe.
One minor note (non-blocking): the checkStatus change affects every call site (booleans, resize, primitives), not just the primitives touched by the issue's seven files — worth keeping an eye on if any downstream corpus file relied on a "degenerate but non-empty" manifold surviving a non-NoError status.
Nothing here blocks merging as far as I can tell.
Generated by Claude Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #88. Rebuilt the v3.9 volumetric-comparison toolchain (real OpenSCAD 2021.01 oracle, Manifold v3.5.2, headless
chiselcad_core,scad_to_stl/stl_diff— seetests/tools/README.md) and bisected each of the issue's seven untriaged corpus files individually. All seven turned out to be real, distinct bugs, and all seven are now fixed — each file'ssym_diff_volumeagainst the live oracle is at floating-point-noise level:ifelse-tests.scad(175% → exact):cube()/square()'s positionalcenterargument (cube(2, true)) was silently dropped by the parser — never anif/elsebug at all.primitive-inf-tests.scad(83% → exact): non-finite cube/sphere/cylinder dimensions were folded to0.0instead of rejected, so e.g.cylinder(r2=1/0)silently became a valid zero-radius cone instead of empty geometry; a non-finite$fnalso escaped its minimum-segment clamp via undefinedintcast behavior (empiricallyINT_MAXon this platform).surface-simple.scad(~82% → exact):surface()'s base was clamped to0instead of real OpenSCAD's actualminHeight - 1,center=incorrectly re-centered Z (real OpenSCAD only offsets X/Y), and the row-to-Y mapping was flipped relative to real OpenSCAD's own convention.module-recursion.scad(31% → exact):rotate([x,y,z])composed its three axis rotations in the reverse order from real OpenSCAD's X-then-Y-then-Z convention.resize-tests.scad(1.5% → exact):resize()'s negative-newsizeandauto=handling was a generalization that didn't match real OpenSCAD's actualgetResizeTransform()algorithm — rewritten as a verbatim port.intersection-tests.scad(6.4% → exact): a child that itself produced no geometry (e.g. barerender();) was silently dropped instead of nullifying the wholeintersection(); carved out non-geometric statements (echo()/assert()) and%-backgrounded children so they're still just skipped, not treated as empty operands.cylinder-tests.scad(13% → exact): when bothrandr1/r2were given,runconditionally overwrote both instead of only filling in the unspecified slot.Full root-cause narrative and verification details for each are in
docs/roadmap.md's new v3.14 section.Regression safety net
Re-verified against the live OpenSCAD oracle across the entire
tests/data/scad/3D/featurescorpus subdirectory (72 of 73 files — see below), not just the seven files this issue named. That wider sweep caught a real regression theintersection()fix introduced inbackground-modifier2.scad(a%-backgrounded child inside anintersection()was being treated as an empty operand instead of simply excluded from the main tree) before it landed — fixed in the same commit.Filed #105 for a pre-existing, unrelated crash found during that sweep (
linear_extrude-parameter-tests.scad— heap corruption, confirmed present before this PR's changes too via a clean worktree build of the base commit).Test plan
chiselcad_testssuite passes: 3679 assertions, 664 test cases (9 new regression tests added)tests/data/scad/3D/featurescorpus (72/73 files) re-verified against the oracle — no regressions, two additional pre-existing gaps (rotate-parameters,transform-tests) improved by the rotation-order fixGenerated by Claude Code