* ci: repair local nextest scheduling and Windows fixtures
* test: refresh MSVC robustness references and isolate GNU policy
Integrate the Windows reference records from #3361 and the target-environment
selection and recording policy from #4159. Keep shared records and comparison
tolerances intact, and retain seed 36 as an existing failure tracked by #3583.
Co-authored-by: Ray <raykholo@users.noreply.github.com>
Co-authored-by: chris <christopher.nourse@gmail.com>
* test: make CI subprocess and revolve fixtures deterministic
---------
Co-authored-by: Ray <raykholo@users.noreply.github.com>
Co-authored-by: chris <christopher.nourse@gmail.com>
* Chamfer: a cutter that would reach into a nearby wall is not used
A straight chamfer's cutter reaches several times the chamfer's size out
from its edge, and further on a larger part. On a pin standing in a socket,
that far side lands inside the socket's walls, and the cut took bites out
of them. A cutter whose far side is inside the part is now refused, as one
whose ends are, and the chamfer is built locally instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Robustness goldens: seed 9 re-recorded for the chamfer cutter check
A chamfer in seed 9 was refused because its result changed more of the
part than a chamfer can. With its cutter refused, it now builds locally.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Measure: a body whose meshes leave a gap keeps its volume wherever it is
A part ring cut by solid.combine (two prisms through its ends, a notch
through its chamfer) measured 992.03 mm3 at the origin, 999.17 moved
100 mm and 1063.48 moved 1000 mm; it encloses 993.92. The reference
mesher leaves a crack where the notch meets the chamfer's cone: the
volume beside it is left out, and the divergence-theorem sums, taken
about the world origin, close the crack by a cone to the origin, so the
error grows with the body's distance from it.
A closed surface's area vectors sum to zero. When the picked meshes'
sum could move the volume by more than 1e-5 within the body's size, and
the display plan (which shares every edge's nodes between its faces) is
closed, the body is measured on the plan, about its box centre. Every
other body measures exactly as before.
Tests: the cut ring at the origin and moved by up to 10000 mm, against a
grid quadrature of the cut; a revolved ring of cones and cylinders moved
100/1000/10000 mm along each axis (1e-6); a cylinder and a frustum far
from the origin against hand values. Robustness seed 64 moves by 1.4e-6
and is recorded.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Measure: a gap the display plan can't close is measured about the box's centre
When the meshes leave a gap and the display plan isn't closed either, the
sums used to fall back to the origin-based volume, which drifts with the
body's distance from the origin (7 % at 1000 mm for the part ring). The
per-face sums are now taken about the fine mesh's box centre, which closes
the gap by a cone to a point inside the body; over a closed mesh nothing
changes. The gap decision moves into gap_closed, and a unit test with a
cube left open by hand covers closed vs open meshes, the closed plan, and
the fallback with an open plan or none.
Seeds 14, 20, 40, 55 and 61 end with such a body and are recorded with
ROBUSTNESS_GOLDENS_BLESS (volumes move by -0.51 %, +0.16 %, +1.9e-4,
+9.0e-5 and -1.5e-5; steps, outcomes and counts unchanged).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Record robustness seed 86 after measuring bodies whose meshes leave a gap
Seed 86 was added on main by #2387 after this branch's goldens were recorded. Its last
body leaves a gap in its meshes, so the measure change here moves its volume by -0.27 %
and its area by +0.13 %; steps, outcome and counts are unchanged. Seed 86 passes
unchanged on main 57d21013. Every other seed matches on the merged branch.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* measure: take the display plan only where it agrees with the sums to within what the gap could move
A closed display plan meshed less finely than the sums differs from them by its own chord error,
which can be larger than anything the gap explains: an imported part with small blends measured
0.03 % low on its plan. The plan is now taken only where the two differ by at most what the
gap's area could move the volume within the body's size; otherwise the sums about the box's
centre stand.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* measure: sum a mesh left open about its box's centre only, without the display plan
The closed display plan meshes some faces of an imported B-spline part
more coarsely than the sums do, so a body and its boolean pieces no
longer add up: clearance's union cross-check then refused a 17.3 mm3
overlap between two such parts (the pieces implied 20.5). Summing about
the box's centre alone keeps the gap closed by a cone to a point inside
the body and stays consistent with the pieces. Seeds 64 and 86 are
re-recorded with the reason.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* measure: placement tests in the area's test files
The ring and frustum tests join measure.rs's tests, and the cut ring
joins measure_centre_tests.rs (AGENTS.md: a regression test goes into
the existing test file for its area). The goldens note for seeds 14, 20,
40, 55 and 61 describes the centre-only sums.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* measure: keep the origin for a body left open on purpose
A surface, or a cup whose lid is still a separate sheet, has no volume of
its own. Measured about its box's centre, two such bodies stopped
comparing once the centre moved (a crowned lid rises), which broke the
patch crown test. Only a mesh with a small crack is measured about the
centre now.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Aac7mP9rthK3WsPpPRvCsF
* Robustness goldens: keep main's notes, one note for this change's seeds
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Aac7mP9rthK3WsPpPRvCsF
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Tessellation: trimmed faces of display meshes stay on their surfaces
Display meshes triangulate a trimmed face in parameters scaled by the
surface's speed along each, so a strip stretched along one parameter is
not fanned across, and every boundary segment stays a constraint: one that
crosses another is split where they meet. Boolean meshes keep truck's way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
* Tessellation: one boundary rule for every mesh; drop the #1648 retry
A boundary segment that crosses one already added is split where they
meet in Boolean meshes too, which keeps a pinched face (#1648) whole
without the snap-and-retry. Faces whose segments all go in mesh as
before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
* Robustness goldens: seeds 1, 23, 55, 64 and 86 re-recorded on current main for #1653
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWhMwdqJYQKQq8RCLSL1LT
* Thread preview test: wait for the stale fit error to clear before the next preview
After switching back from M6x1.3 to M8x1.3, wait_feature_preview stopped at the M6 error still on
screen when the new preview started a few frames later (seen on Linux CI with #1653's meshing).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWhMwdqJYQKQq8RCLSL1LT
* Robustness goldens: the slow seeds 14, 20 and 40 re-recorded for #1653 from the merge queue
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWhMwdqJYQKQq8RCLSL1LT
---------
Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
truck placed a face that no intersection divides (every face of a shell
that meets nothing of the other) by counting the faces a ray crosses,
taking each face's surface as stored. A revolved body's reversed faces
counted the wrong way, and an inward shell (a void, a cut's inverted
tool) was read as a solid: a cut beside a sealed void came out empty,
refused or, with a tool whose bounding box covers the target, taken with
the body gone. Intersections of such bodies came out empty as well.
In an AND the crossings now count as each face is oriented, and an
inward shell holds what lies outside it. An OR keeps truck's count.
The corrected cut let a folded offset through: an arc edge next to a
face it meets tangentially had its ends moved past its middle, and the
arc went the long way round (robustness seed 73's shell). The offset
refuses an arc whose middle crossed its chord, as it does a straight
edge that turned round.
Goldens: seeds 0, 45 and 77 had a cut refused as empty that now takes
what it should; their volumes are checked by hand in the PR.
A face pinched to a point, where its boundary touches itself or another of its loops within
TOLERANCE (a sphere touching a box's edge leaves one on the box), had a constraint refused by the
CDT, and the fallback cut across the face: it came out with no triangles or without those at the
pinch. When a constraint is refused, the vendored truck-meshalgo now puts every boundary point
within TOLERANCE of a segment into it (at most 8192) and triangulates the face again. Faces whose
segments all go in mesh as before.
The regression tests live in crates/kernel/src/thin_face_tests.rs, and the #1648 property test in
boolean_props.rs is no longer ignored. Robustness seeds 20 and 55 are recorded with their Linux
values.
Co-authored-by: MateuszSychXpl <151755914+MateuszSychXpl@users.noreply.github.com>
#2247 changed 16 robustness seeds (bodies N -> 1, and some seeds then build
different steps; seed 54's new shell fails on #2247's parent too). Recorded
on Linux.
Designs saved before #2247 that combined a split-off piece by name (tools
Posts, Posts (1)) failed on the missing piece and left both posts off the
case. A combine now skips a missing `X (n)` when `X` is a tool too or the
join's target, with a warning. Format note for the meaning change.
#2064 (multi-profile extrusion) merges coplanar faces the boolean used to
leave split. Seeds 67 and 94 change face/edge counts at the same volume;
seed 13 has four fewer edges before its random fillet, which then picks
different edges by index. Every step still passes the validity and
volume-direction checks. Pull request CI runs every 8th seed only, so
main's full run was the first to see these.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#853 recorded seeds 13, 71 and 94 with the face and edge counts its own branch built
(40/101, 19/50, 27/63). With main's kernel they still build as they did before #853
(41/103, 20/52, 26/61), so every full goldens run has failed since it landed. This
records them again; #853's seed 20 change and the other 93 seeds are unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Main's CI has failed since 14:47 on `robustness_goldens::all_3`: seed 55 (a
filleted box cut by spheres and patterned) used to end with an invalid body and
now passes the validity check, and its volume moved by 1.3e-5 relative.
The outcome changed between 2ae21143 (main's last green run) and 7f9074d6,
where the kernel meshing change is #1670 (twisted ruled faces divided to the
chord tolerance). The volume changed between 8a055afd and 31b2ddc0, where
#1753 changed truck-meshalgo's triangulation (the faces of an edge share its
points exactly). The kernel's validity and volume checks measure those meshes.
Pull requests run every 8th seed, so only main's full run saw seed 55.
Only seed 55 is recorded, with the values main's CI printed on Linux.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
Seed 31: #1581 refuses a fillet selection with an earlier round's smooth seam instead of re-rounding another nearby edge. Seed 83: #1316 was recorded before its branch took in #1495, whose shell keeps the wall beside a concave edge.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Chamfer: refuse a result that grew a convex edge's part (or shrank a concave one's)
A chamfer of a curved edge that runs off a face it skims (robustness seed 57's
ball rim) built a part bigger than before. Checked from the two faces' normals
at the edge; rounds and unclear angles are left to the wedge bound.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Action matrix: the sheet metal tray's relief corners refuse a 0.25 mm chamfer
Each is a 2.5 mm concave edge (the corner of a corner relief, between two
planes at right angles): a chamfer there fills at most 0.25²/2 × 2.5 = 0.08
mm³. What was built took 0.95 mm³ away; the chamfer guard now refuses it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Robustness goldens: seed 57's wrong-way chamfer is now refused (#1390)
On main with #391, seed 57's chamfer grew the part; this refuses it, so the run goes on
to its later steps and ends ok.
---------
Co-authored-by: Phanoob <phanoob@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
A point within the point tolerance of a boundary curve's end is that end in the boolean, whatever its parameter, so text cuts no longer leave unmatched sliver vertices (#391). Robustness goldens re-recorded for seeds 0, 34, 39, 41 and 57 with reasons.
A round or chamfer whose edge chain runs on across a curved seam (the end circle of a lofted tube whose axis bends) is now built: the section solve keeps its contact on the seam through a plane taken afresh at the seam's nearest point at each step. Straight seams are unchanged. Robustness seed 41 is re-recorded: its second fillet, refused before, now builds. Fixes#1213.
Co-authored-by: gvocale <gvocale@users.noreply.github.com>
#1164 joins a body that sits flush on a rounded rim into it. In seed 13 the
rectangular pattern's second box (x 5..7.5) sits flush on the half-ring's top
face with a 27 mm2 contact patch. It used to stay a separate shell (one body,
three shells); now it joins the ring (area -54 mm2, twice the patch). The
fillet edge and hole position the generator picks next come from the new
geometry, so the end state differs: 3 bodies, 2647.95 mm3 (was 4, 2300.91).
Every step stays a sound solid, and no other seed moves.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Straight edges stay one edge after cuts (#1049)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Robustness goldens: cuts join straight edges along untouched walls (#1049)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fmt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Robustness goldens note: what each changed seed shows when replayed on both builds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Fillets and chamfers meeting at corners on curved faces, on top of #935
What #935 and #926 leave of #851 and the matrix:
- Corner build for blends meeting on faces of any surface (curvecorner.rs):
the knife-edge tip's round with the arc's or the back edge's, edges
picked in any order, a round ending in an earlier round of its radius
(as a feature of its own), and chamfers meeting at the arc's corner.
Its end curves are fitted by chord length: a uniform parameter
through points clustered at the ends doubled back on itself there,
and the display planner refused the face.
- A straight edge ending at a curved face (the back edge into the
knife-edge tip): rolled, or cut by the face in the planar corner
build (blend_corner.rs).
- A rolling ball turning about a rounded corner of its own radius
(a pivot: a piece of sphere or cone).
- Seams that are an earlier blend's straight contact (fitted curves)
count as straight.
- No spline across a joint where the strip's curvature jumps (a line
into a small round): each strip ends on the joint's section.
- Sections at a chain's vertices on the faces of the edge from it
alone.
- Every new fillet path passes #949's check for openings.
Tests measure volumes through the display plan, as #935's do.
Action matrix: 51 more fillets and chamfers pass (sweep, tangent arc
chain, sheet-metal hem, bracket holes), none fewer. Robustness seed 33
recorded (its last fillet builds differently; display and measured
volumes now agree).
Co-Authored-By: bherbruck <brennen.herbruck@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015bV2ntwLfUHV4JnCMPSyRi
* Corner blend tests: scale, seed 33's volumes, tighter engine bounds
From the review of #854:
- seed_33_display_plan_and_measure_agree: seed 33's bodies measure
the same through the display plan and the measure (2e-5), which the
golden's re-record rests on.
- the_arc_rounded_after_the_back_edge_matches_both_together: the order
that still leaves 0.05 mm³ at the tip, as an ignored test.
- corner_blends_hold_at_any_scale: the cases this branch adds on the
#851 part, at 0.01x and 100x, take off what they take at full size
times k³ (within 5e-6, checked to 1e-4).
- The engine tests on the part as drawn measure through the display
plan; bounds are about twice what each reads (2e-4 to 3e-3), and the
front corner's sets are checked against the kernel's CSG grid.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015bV2ntwLfUHV4JnCMPSyRi
---------
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#970's lenient retry of a face's parameter boundary searches the whole surface as a last resort; on robustness seed 20 it found an edge's points across a cylinder's seam, half a turn apart, and the Cut failed. A lenient boundary whose points jump half the parameter range or more is refused, and the face is left undivided as before (#970's elbows step at most a fifth of the range). Seed 81's volume moved by 0.1 mm3 with #952's hole direction; recorded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Touching sews now split 4-use straight edges on extruded walls (along their rulings), not only on planes. Faces round such an edge are ordered by the way they leave it and, where they leave it tangent, by their curvature. Sheets bound the material wedges as before, except where that would make a face touch itself (a hole touching the outline from inside); edges ending there pair the empty wedges instead, so each loop gets its own vertex. Coincident faces are still refused, plain sew still refuses vertex contact, and shell_groups is unchanged.
A Ø10 hole tangent inside a stepped Ø40/Ø20 boss now cuts exactly instead of failing with "wire is not simple". Robustness seeds 42 and 51 are recorded: their touching hole patterns in stepped bodies now cut exactly instead of by a tool nudge.
Co-authored-by: froglemonade2 <froglemonade2@users.noreply.github.com>
* Boolean nudge tried both ways: no sliver where a cut's end touches a round side (#897, #827)
Robustness seed 14 cuts a cylinder whose end lies exactly on the apex of the
plate's arc side. Since the display tessellation plans (#805) the generator sees
the arc's true extent, so the cut's base lands on -10 instead of -10.000000000000002
and the end is tangent to the arc. The direct boolean fails there and the
last-resort tool nudge pushed the end into the arc, leaving a planar sliver a
tenth of a millimetre wide; shell then picked that sliver and refused it. The
13 October merges were not the cause (the bisect lands on #805).
The nudge is now tried both ways and the simpler result (fewer faces) is kept,
so the opposite nudge parts the touching faces instead. The same change joins
the hinge barrel in #827, whose top lies tangent to the lid's underside where
the mounting leaf ends. Each result still passes the same checks as before.
Goldens: seeds 14, 26 and 85 now build to the end, 31 and 78 come out with
fewer faces. Seeds 6, 43 and 73 still stop at shell: their joins now succeed and
shell reaches corners it can't offset (a cusp where a box face touches an arc,
coplanar faces facing opposite ways), which is unchanged.
Fixes#897Fixes#827
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Nudge the other way only when the first nudge fails or leaves a sliver
Trying both nudges and keeping the one with fewer faces could prefer a result
that keeps two pieces joined by a hair over one that separates them (the
centred coplanar revolve cut). The opposite nudge now runs only when the first
one failed or left a face narrower than 1/200 of the part, and it is taken
when it works with fewer of those.
Goldens re-recorded on current main: seeds 14, 26 and 85 build to the end,
31 and 78 with fewer faces. The other changed seeds are main's own since its
last full record, identical with and without this change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Nudge the other way only for slivers the nudge made
On the sensor enclosure's lid the first nudge left thin faces the operands
already had (thin walls, small rounds), so the opposite nudge ran a second
boolean for nothing and the press/pull took 79 s against main's 55 s. The
opposite nudge now runs only when the first one failed or left more slivers
than the operands brought; the press/pull test takes 36 s against 42 s on main
(same machine, one after the other).
Goldens re-recorded on top of #940.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Goldens on current main: seeds 31, 43 and 78 with the two-way nudge
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Keep the hinge and tangent-cut tests beside the #871 fillet test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Goldens: seeds 33 and 91 as main's fillet changes build them
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Goldens: keep main's #950 record
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Hole matrix: placement, types, extents, edits and 0.9.0 designs, with today's failures listed
Each case checks the drill goes into the material, the bore sits on its axis, a blind hole stops
where it should, the removed volume against its analytic value, the face count and that every
body is still one closed valid solid. Failing cases are listed in tests/hole_matrix/known_failures.txt
as a ratchet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* A hole on a face drills into the material, also in older designs (#950)
Without a direction, solid.hole took the direction from any face whose infinite plane passed
within ten tolerances of the point, the last one found winning: the far side of a thin plate or a
face of another body at the same height could set it, and the wrong direction was saved. It now
uses the face nearest the point, against its outward normal (exact for planes, cylinders and
spheres, so holes on curved faces work without a direction). When a design is evaluated, a face
hole whose saved direction leaves the face it starts on is mirrored into it, so designs saved
with the wrong direction drill into the part.
Fixes#950.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Hole at a point on no face (a planar face's centroid outside it) keeps the plane it lies in
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Record the hole direction fix in the goldens and the action matrix baseline (#950)
Seeds 7, 21, 81 and 85 drill their holes straight into their faces now. In the action matrix,
holes on four faces that used to go the wrong way now build, and two whose correct direction
meets a cut the kernel refuses are marked failing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Goldens: seeds 7, 21 and 85 drill their holes straight in (#950)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#921's grid lines through the vertices that split a ruling edge also went into the meshes Boolean operations intersect, which changed seven robustness seeds (seed 2's sphere cut failed). Deflection::rulings now asks for them only in the kernel's own tessellation (display, export, measurement). The seeds #936 (rejected instead of unsupported), #946 (26 and 85 build, others fail differently) and #921's display side (about 1e-6) moved are recorded with their reasons.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rolling-ball blends now handle knife edges, where the two faces have opposite normals; an edge that runs out along an end face tangent to one side; and rounds that end in an earlier round on curved faces, picked together or one after another. The three edges at a vertex of smooth faces, rounded to one radius, end in a piece of sphere. When the given order of up to four edges is refused, or leaves a face boundary off its surface, other orders are tried.
Closes#851.
Co-authored-by: lasselian <22126420+lasselian@users.noreply.github.com>
* Fillet and chamfer: refuse a smooth seam as having no corner to round
Picking the seams where R10 rounds run into the faces beside them, and asking for an R1
fillet there, failed with "not supported yet: blending a smooth edge (... both faces next
to the edge must be planar)". That reads like a missing feature, but the faces meet
tangentially at those edges and there is nothing to round.
An edge whose two faces are tangent along it is now refused as an invalid pick that names
the edge and asks for the sharp edges.
Fixes#896.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Robustness goldens: seed 72's smooth-seam fillet is now a rejected pick, not unsupported
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Main has failed the full robustness goldens since #838, #839, #841, #855 and #856 landed together. Records the eleven seeds that now build differently (2, 6, 14, 22, 36, 43, 50, 63, 71, 73, 94), with a note. Shell now refusing seed 14, which used to build, is tracked in #897.
tests/robustness/goldens.json records what each of seeds 0-95 builds: its steps, how it ended (ok, or the kind and the start of the error it was refused with) and, for the design it left, the bodies' total volume and area (within a relative 1e-6) and their face, edge and shell counts. tests::robustness_goldens fails on any change; ROBUSTNESS_GOLDENS_BLESS="why" records one, with the reason and the seeds it moved. Pull requests that touch crates/kernel run every 8th seed; pushes to main and the nightly run every seed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>