Commit Graph
44 Commits
Author SHA1 Message Date
Karl Von Richter 8a6332be83 Fix face Extrude Join targets in assemblies (#1375)
A new face-based Extrude Join (and outward Press Pull) joins the picked face's body by default and stores that scope, so an edge-touching neighbour is no longer tried first or absorbed. Explicit targets and participants still win. Related to #226.
2026-10-15 08:33:48 -04:00
Giovanniandgvocale faeeff1c64 Blends: a curved seam where the edge chain runs on holds the contact on itself (#1291)
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 <[email protected]>
2026-10-15 01:19:51 -04:00
bherbruckandClaude Opus 5.5 5c2fa3e9ca Action matrix regressions of #1255: knuckle rounds, thin holes, a 45° flange hole, an axis after an edit (#1280)
* Action matrix regressions of #1255: knuckle rounds, thin holes, a 45° flange hole, an axis after an edit

- Curve blends: past the end of a curved edge the run of sections along the end
  tangent wrapped round the ring of centres; it is shortened while it still
  crosses the end face (the hinge knuckle's cap rounds at 0.728 mm).
- Boolean retry guard: each body's volume is measured finer than its smallest
  radius, and a volume out of bounds is measured again ten times finer before
  it refuses (a 0.133 mm drill measured -30272 mm³; a plastic part's coarse
  mesh was off by more than the slack).
- Sheet metal: a drill cap's certificate allows the evaluation noise its fitted
  tilt shows (a hole square to a 45° flange).
- Construction geometry on a named face uses the face found by name, not a
  second pick at its nearest point (an axis through a corner round after a
  parameter moved it).

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Retry guard: measure the target, tool and result at one tolerance

Measured at different tolerances, the chords' error on the faces they share
didn't cancel: a blind hole in a long D-profile bar measured 20 mm³ more than
the bar.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Action matrix baseline from this branch's full run: 37 actions pass again, none fewer

Blessed with cargo xtask action-matrix --from DIR --bless from the 16 shards of
run 38673859774.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-15 00:24:27 -04:00
bherbruckandClaude Opus 5.5 d73cd8a177 Robustness goldens: record seed 13 after #1164 (#1268)
#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 <[email protected]>
2026-10-14 21:18:54 -04:00
bherbruckandClaude Opus 5.5 c159a3e277 Action matrix: nightly shards cut by measured cost, a fresh baseline, and a determinism check (#1256)
* Action matrix: nightly shards cut by measured cost, heavy designs in slices, and a determinism check

The full matrix ran as four fixed quarters of the corpus and two of them hit the 60-minute
job limit. Now action_matrix_shard runs shard k of n (ACTION_MATRIX_SHARD=k/n), planned from
tests/action_matrix/costs.json: designs that take more than five minutes are split into slices,
and the pieces go largest first to the least loaded shard. The nightly runs 12 shards and uploads
each one's outcomes and timings; cargo xtask action-matrix --from DIR --bless records them in the
baseline and costs.json without running the matrix again. action_matrix_determinism runs a sample
twice and lists any action whose outcome changed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Action matrix: costs measured on runners, 10 shards, determinism on the lighter designs

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Action matrix: baseline and costs from a full run on main, 16 shards, timeouts listed

The baseline is regenerated from the 10 shards' results of a full run on 01b1b705
(cargo xtask action-matrix --from DIR --bless): 8 new designs, 302 actions that pass now,
names that changed, and 40 actions that passed before and fail now, each listed in #1255
(22 fillets refused since #949, 4 hinge blends since #1101, 9 on the loft cut, 5 single).
costs.json now holds every design's measured time, and the nightly runs 16 shards of about
17 minutes. An action that passes in the baseline and times out is listed but not judged,
and stays passing when blessed: two runs of the same build differed only on 10 actions that
took 50-84 s against the 90 s limit.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Action matrix: slice heavy designs by a hash of each action's name

Slicing by index gave some slices only fillets on oracle 41 (28 slices, a multiple of the
actions per edge), three times the planned time; two shards ran past their limit.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-14 21:18:11 -04:00
phanoob beb3ea01e7 Taper: the review of #1014 (spline sides follow their offset, no silent limits, face names kept) (#1204)
Taper: the review of #1014 (spline sides follow their offset, no silent limits, face names kept).
2026-10-14 17:55:58 -04:00
bherbruckandClaude Opus 5.5 563bcaff5b Refuse fillets and chamfers that run past their faces or cross each other (#1080) (#1124)
* Refuse fillets and chamfers that run past their faces or cross each other (#1080)

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Blend fit: chamfers keep their old acceptance of crossed loops; skip the volume bound along tangent chains

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Blend fit: one selection per check, a coarse volume pass first; record the refused oversize blends in the action matrix baseline

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-14 11:46:44 -04:00
Lasse Lian 6df69e9def Thin Extrude: walls of a set thickness along sketch curves (#721) (#991)
Thin Extrude builds walls of a set thickness along sketch curves, open chains and closed loops, with the wall centred, inside, outside or on both sides at two thicknesses. Saved under format 20 (thin on an Extrude); an extrude without thin saves as before. Closes #721.
2026-10-14 11:46:16 -04:00
bherbruckandClaude Opus 5.5 d019f2d5bf Straight edges stay one edge after cuts (#1049) (#1101)
* Straight edges stay one edge after cuts (#1049)

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Robustness goldens: cuts join straight edges along untouched walls (#1049)

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Robustness goldens note: what each changed seed shows when replayed on both builds

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-14 10:51:07 -04:00
32d3cf6877 Fillets and chamfers meeting at corners on curved faces: what #935 leaves (#854)
* 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 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bV2ntwLfUHV4JnCMPSyRi

---------

Co-authored-by: bherbruck <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-14 07:40:23 -04:00
bherbruckandClaude Opus 5.5 dfbf7dd6a8 fix: a lenient parameter boundary found across a seam is not used; record seed 81 (#1003)
#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 <[email protected]>
2026-10-14 04:56:39 -04:00
froglemonade2andfroglemonade2 3669d4b3d0 Cut a hole tangent inside a stepped boss (zero-thickness curved wall) (#986)
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 <[email protected]>
2026-10-14 03:55:06 -04:00
bherbruckandClaude Opus 5.5 18347b3d0d Boolean nudge: no sliver where a tool only touches a round side (#827, seen in #897) (#941)
* 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 #897
Fixes #827

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* 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 <[email protected]>

* 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 <[email protected]>

* Goldens on current main: seeds 31, 43 and 78 with the two-way nudge

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Keep the hinge and tangent-cut tests beside the #871 fillet test

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Goldens: seeds 33 and 91 as main's fillet changes build them

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Goldens: keep main's #950 record

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-14 02:55:37 -04:00
bherbruckandClaude Opus 5.5 6cb3025b72 Sheet metal: a hole drilled into a rim is a bore its panel keeps (#560) (#955)
A hole drilled along a panel, into its rim, has no place in the flat pattern
as a cut-out, so every such hole was refused. It is now kept as a bore of that
panel, in flat coordinates, and cut only from that panel's material when the
folded part and its flat pattern are built, so the sheet still unfolds and
folds back with it. A hole that would run into a bend, or cross a panel at an
angle, is still refused. The flat pattern lists the bores.

The action matrix worker takes ACTION_MATRIX_ONLY (just these actions) and
ACTION_MATRIX_UNFOLD (unfold and refold every sheet after each action) for
rechecking one group by hand.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-14 02:31:19 -04:00
bherbruckandClaude Opus 5.5 1ff16cc72b A hole on a face drills into the material, also in older designs (#950) (#952)
* 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 <[email protected]>

* 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 <[email protected]>

* 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 <[email protected]>

* 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 <[email protected]>

* Goldens: seeds 7, 21 and 85 drill their holes straight in (#950)

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-14 01:45:11 -04:00
bherbruckandClaude Opus 5.5 813bee8914 Fillet: refuse a result with openings in its surface (#871) (#949)
* Fillet: refuse a result with openings in its surface (#871)

A fillet on #871's part (radius 1 on a window's edges and on the sides of a
block 1.26 mm away) came back closed as topology with every face meshing, but
the rounds overlapped and the end faces' boundary loops crossed, so the model
showed holes. The constant-radius fillet now checks its result before taking it:
the body's mesh, welded within a millionth of its size, must have no edge
without as many triangles running the other way along it, except for cracks
within the mesh tolerance where fitted curves meet. A result that fails is
refused, so the corner build gets its try and the radius search treats it as
too large.

Body::open_mesh_edges is the check. Kernel tests cover the #871 part (refused
at radius 1, closed with a round on every edge at 0.5), and an engine test runs
the fillet from the report and leaves the part as it was. All 96 robustness
seeds build the same with and without it.

Fixes #871

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Check fillets for crossed face boundaries, not free mesh edges

Free edges in the mesh also come from cracks where fitted curves meet (corner
patches, rounds ending on curved edges), so the mesh test refused good fillets.
The check is now on the cause of #871: a planar face whose boundary loops cross
each other or themselves has no inside. Body::crossed_face_loops samples each
planar face's loops within 1/1000 of the size and counts proper crossings
(touching within a millionth doesn't count).

The pyramid apex blend and the loft fillets build again. Ten action-matrix fillets
stay refused, recorded in the baseline: r = 3 on the 2 mm rim of oracle 09's
shelled box (the round runs past the inner wall; the result was 240 mm3 lighter
than any round can make it), and the six seam-edge fillets on oracle 60's bolt
holes, whose boundary jumps across the hole.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-14 01:36:30 -04:00
bherbruckandClaude Opus 5.5 ea23401710 Sketch on every side wall of one sketch extruded up and down (#957)
* Name a side drawn on several sketch curves by all of them

An extrude named each side wall after the one sketch curve its profile
segment lies on. A wall along two coincident lines (squares drawn edge to
edge) or along collinear lines merged into one profile segment had no
single curve, so it was named from geometry and could not carry a sketch
attachment. One sketch extruded up and down and joined (the logo) refused
a sketch on every one of its side walls.

Such a side is now named by every curve it lies on, in sketch order: the
first is its name, the others aliases. The set is fixed by the sketch, so
the name is exact. The refusal message no longer blames merged faces.

Adds the reported logo design and a synthetic up-and-down join to the
action-matrix designs, and a regression test that sketches and extrudes on
every flat face, fresh and after save and reopen.

Fixes #954

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Action matrix: record the up-and-down join designs

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-14 01:00:04 -04:00
bherbruck ce902be66c Fillets and chamfers ending on a boss's pieced wall or beside it, on a face that runs along its seam twice, and loops the loop blend refuses (#926)
Fillets and chamfers ending on a boss's pieced wall or beside it, on a face that runs along its seam twice, and loops the loop blend refuses

- A straight edge whose end meets one curved surface in several faces (a cylinder a join left
  in pieces) ends on that surface: the section is cut where it crosses each seam, which is
  shortened there; where no seam is crossed (the wall missing inside the other body) the
  section lies on the bared surface and the rest of the side edge becomes a seam.
- Two end faces that aren't both planes meeting in lines: each face takes the section's points
  on it, cut where it crosses the edge between them. Not where an end face runs on smoothly
  from a side (an earlier round): the corner build takes those.
- Face boundaries close over several connector edges.
- A face on a periodic surface running along its seam twice (as a STEP file gives it) is
  rebuilt the same way (#691).
- A curved chain ending square on a face that runs on past its side extends that face's seam.
- A smooth chain stops before an edge between faces that meet smoothly.
- A loop the loop blend refuses for its shape is blended edge by edge; refusals about its size
  stand.
- Action matrix: ACTION_MATRIX_ACTIONS and ACTION_MATRIX_VALIDITY for quick local runs; the
  fillets and chamfers that pass now recorded.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 00:28:09 -04:00
bherbruckandClaude Opus 5.5 00fdcf3e72 fix: grid lines for split ruling edges only in display and export meshes; record the moved seeds (#961)
#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 <[email protected]>
2026-10-14 00:14:18 -04:00
bherbruckandClaude Opus 5.5 774a8b1d9a test: record the bracket example's action matrix after its fillet moved (#962)
#820 fixed examples/bracket.json's fillet pick, which lay far from every edge and rounded the outer corner instead of the inner one. This re-records examples/bracket only: its edges carry the fillet's new names, and three chamfers beside and across the inner fillet are refused (the blend is larger than the neighbouring faces).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 23:57:59 -04:00
Lasse Lianandlasselian a2c7396160 Fillets and chamfers where edges meet at corners on a curved wall or a knife-edge tip (#851) (#935)
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 <[email protected]>
2026-10-13 23:21:47 -04:00
bherbruck 7498e3b367 The model's body mesh comes from the reference mesher again (#940)
Fixes 20 action-matrix regressions from #805 and the seed 14 shell refusal (#897).
2026-10-13 22:37:11 -04:00
bherbruckandClaude Opus 5.5 78d9aa0153 Booleans: small tools in large bodies are traced at their own scale (#559) (#946)
A through-all hole's tool is twice the largest body long, and the boolean's tolerances
followed that length: a 6 mm hole through a 920 mm part was traced at nearly 1 mm, wider than
the hole, and the cut came out empty or failed. When every other strategy has failed, the
boolean is now asked again (unshifted, then once shifted) at tolerances scaled to where the
bodies meet: the overlap of their boxes and the thinner operand's thickness. Its result is
checked as the others are and held to the retry guard. It runs last, so whatever an earlier
strategy answered is kept as it was, and only for single-shell operands (bodies in several
pieces are retried a piece at a time, each with this pass of its own).

The sampled shortcut also gave up on a slender tool lying across its box (a long hole drilled at
an angle fills little of it): it now samples past the first 2000 points until enough land
inside, so a tool that misses a body leaves that body as it is. Bodies that had enough samples
in the first 2000 are sampled exactly as before.

Baseline: the 90 actions that newly pass, rechecked one by one with the final build.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 21:54:09 -04:00
bherbruckandClaude Opus 5.5 7c85970bfc Fillet and chamfer: refuse a smooth seam as having no corner to round (#936)
* 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 <[email protected]>

* Robustness goldens: seed 72's smooth-seam fillet is now a rejected pick, not unsupported

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 21:02:06 -04:00
bherbruck 0040ce6bf2 Robustness goldens: record the seeds the 13 October kernel merges changed (#898)
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.
2026-10-13 18:46:00 -04:00
bherbruck 3d3f9b626f Robustness goldens: record seed 0 after the tessellation plans (#870)
#805 and the goldens (#826) landed side by side, so seed 0 was recorded before the new meshing reached main.
2026-10-13 17:30:16 -04:00
bherbruckandClaude Opus 5.5 534393ed5a test: seeded goldens for the robustness seeds (#826)
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 <[email protected]>
2026-10-13 16:23:27 -04:00
Irakli KourtisandClaude Opus 5.5 17b4b9a32c Reference case for a fillet with a B-spline radius (#810)
Adds oracle case 81 (a box edge rounded at a clamped cubic B-spline radius) with analytic expected values, and passes spline fillets through recipes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 14:28:49 -04:00
bherbruckandClaude Opus 5.5 1a0100cdd9 test: record the action-matrix outcomes that changed on main (#781)
26 baseline actions that fail on main: 17 are the retry guard's refusals of geometry that used to delete a body or fill past an edge (#644), 9 vary between runs (#707). Load timeouts left as they were.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 12:37:05 -04:00
Irakli Kourtis 8cdefd4cd5 test: reference cases for variable, chord-length and tapered fillets (#776)
Four analytic reference cases for variable, to-zero, chord-length and taper-to-fit fillets, with the formulas in tools/oracle-analytic.
2026-10-13 12:35:16 -04:00
bherbruckandClaude Opus 5.5 a3dfbaa0b0 Booleans build the same body every time: face order no longer follows heap addresses (#748)
truck's face and edge IDs are their addresses, so walking maps keyed by them followed heap layout, and the ribbed lid's side-wall hole passed or failed by chance. The planar boolean's rebuild and glue now take truck's connected components in the shell's order, and the planar boolean's own maps are ordered. Healing's union-find keeps the lesser root and takes a run's ends in order of use. The face classification after an intersection orders each component's faces by the shell first. The lid now builds the same body on every run, with a test that builds it six times in one process. Its 0.5 mm side-wall holes, and one sensor enclosure hole of the same kind, now fail every time and are marked failing in the baseline.

Fixes #707.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 12:31:23 -04:00
bherbruckandClaude Opus 5.5 1e4387f3ea fix: cuts no longer split walls they don't touch (#670)
A cut built slab by slab (the exact prism boolean) sewed the result from horizontal
slabs and only joins merged the coplanar pieces back. So a floor vent cut through the
Raspberry Pi case split the long wall into strips at the ports' tops and bottoms
(87 faces instead of 79 at 32 mm), and at 24 mm the end opening split the end wall.

- Prism booleans merge coplanar neighbours for every operation (faces only: edges,
  curves and surfaces stay exact), keeping each face's construction source where all
  its pieces share it, Split Face lines and regularization protection. Painted or
  protected operands keep their authored pieces as before.
- The prism history now tells apart a wall's several edges with its caps (a wall
  with openings meets each opening's floor), so cuts beside existing openings keep
  exact history and faces keep their names.
- Tests: the Pi case's faces pinned after every feature at 24, at 24 changed to 32,
  and built at 32 (each outer side one face); random openings and bosses on a
  shelled case never split another side; every corpus design rebuilds a parameter
  edit like a fresh build and reverts exactly.
- Action matrix baseline: demo/pi-case re-blessed (fewer, merged faces; no
  regressions), demo/pi-case-0.8 recorded, and 88 new passes on
  regressions/lid_ribs_flush_with_window.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 10:14:52 -04:00
bherbruckandClaude Opus 5.5 17e42e7b94 Action matrix: mark the ribbed lid's side-wall hole as failing while it varies between runs (#708)
The ratchet has no flaky marker, so regressions/lid_ribs_flush_with_window Lid/F11:+y face.hole is marked as failing until the boolean is made deterministic (#707).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 09:56:43 -04:00
bherbruckandClaude Opus 5.5 5ef1dcba8e Sheet metal rims and holes, plastic features, lofts, raised pieces and merged walls take face attachments (#677)
Sheet metal rims and bend ends attach by name (<panel>:rim.<edge>, <flange>:rim.bend0/1), as do face profiles from sheet faces. A plain or counterbored Hole square to a panel is machined into the flat pattern. Boss, Lip, Rest and Snap Fit keep the body's history and name their own faces. Hole tools name their faces by the part they cut, and pattern copies as copies. A pattern's repeated fillets keep the body's history. Loft sides are named by their section curves. A piece Offset Face moved off its face's plane attaches by its own qualified name. Sides of a profile grown to overlap a flush body keep their sketch line's name, so walls a Join merged take a sketch (#681). Face sketch 75% -> 90%, offset plane 75% -> 90%, press-pull/extrude 64% -> 85% in the action matrix; baseline blessed.

Fixes #494, fixes #495, fixes #560, fixes #561, fixes #563, fixes #564, fixes #681.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 09:13:09 -04:00
bherbruckandClaude Opus 5.5 302dd7e343 README demo for 0.8: the Raspberry Pi 4 case again, with a rounded rim, engraved text and PETG (#671)
The `pi` story of examples/demo/enclosure_ui_mcp.py keeps the 0.6 flow and adds the rim
rounded in one pick (a tangent chain), "Pi 4" engraved in the floor in DejaVu Sans Bold, and a
PETG material defined in the design, with its mass in Properties, before the height change.
The 0.6 story stays as `pi-0.6` (it built demo/pi-case). The center rectangle now comes from
the Rectangle drop-down. The finished case is in the action matrix corpus as
demo/pi-case-0.8.

docs/screenshots/demo-0.8.gif (9.3 MB) and demo-0.8.mp4 (9.9 MB) replace the 0.6 files: 41 s
at 9x playback.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 08:23:27 -04:00
bherbruckandClaude Opus 5.5 29258767ce fix: refuse Boolean retries that change the part away from the tool (#616) (#644)
Joining ribs flush with a lid's window left a zero-thickness slit far from the rib (the planar fallback glued back only one of the faces its pieces shared) and displaced the tool on the other joins. Gluing now joins every shared face pair, coincident-face separation checks there is material behind a pushed face for every join, and any join or cut that needed a retry must be closed, keep volume monotonic and leave the part unchanged outside the tool's box, or it is refused with an error. Feature command replies carry the feature's warning.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 07:10:29 -04:00
bherbruckandClaude Opus 5.5 8be0f64f5a Fillet and chamfer of one edge ending on curved, slanted or several faces (#646)
A single edge's blend no longer needs a plane square to the edge at each end. Straight edges: each rail ends where it reaches the end face's surface, the side edges there are shortened or continued along their line or circle, and the blend ends where its cylinder or chamfer plane meets that surface (a fitted curve checked against both). A chamfer may end across two faces. Curved edges: at a slanted or curved end the rolling ball runs on past the end and the strip is cut back where it meets that face. A straight edge running smoothly into a bend or rounded corner is blended along its whole smooth chain. Rolling-ball fixes: smooth chains follow edges stored against their curve, the ball touches only the faces of the edges it rolls along, the seam normal at a joint comes from the face there, and each strip is fitted with neighbouring sections at its own spacing.

Action matrix: edge.fillet 83.6% -> 93.0%, edge.chamfer 82.6% -> 93.3% (697 new passes, no regressions); reference tests 76/76.

Fixes #556

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 06:43:13 -04:00
bherbruckandClaude Opus 5.5 bb60a95289 Through-all holes beside walls: a long thin tool keeps its outside out (#629)
Body::new no longer turns a long thin solid (a through-all hole's tool) inside out on the strength of a coarse mesh volume: it checks again on a fine mesh first. 79 more face.hole actions pass in the action matrix; the remaining no-result cuts stay under #559.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 05:39:48 -04:00
bherbruckandClaude Opus 5.5 6d5df4b9b3 Sketch on cut walls, chamfers, pattern copies, join-merged sides and split faces (#625)
A flat face that no construction certificate names on its own now attaches by its exact history name (a new lineage face certificate): cut walls and floors, chamfer faces, each pattern or mirror copy, side walls a Join merged, and the pieces a later feature split a face into. Construction certificates still come first; a seed keeps its certificate when it is patterned. Two flush extrudes of one outline joined end to end keep their exact history in the prism boolean. Face sketch 52% -> 71%, offset plane 52% -> 71%, press-pull/extrude from face 41% -> 60% in the action matrix; baseline blessed.

Fixes #491, fixes #492, fixes #493, fixes #557.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 05:26:29 -04:00
bherbruckandClaude Opus 5.5 2a434d59c3 Picks on a moved or pasted component build where it is shown (#558) (#610)
Construction axes, points and planes resolve their picks against the model as their component sees it (in the root, every placement, pasted instances too), and a Hole picked on another component's body cuts that body. components-arm 355 -> 502/594 and joints-hinge 304/390 -> 371/408 in the action matrix.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 04:12:24 -04:00
bherbruckandClaude Opus 5.5 736d9277b8 Action matrix: every ordinary action on every face, edge, vertex and body of the design corpus (#553)
apps/solidcraft-cli/tests/action_matrix.rs tries sketch, offset/angle/mid planes, press pull, extrude from a face, hole, draft, shell, fillet, chamfer, axes, points, planes, projection, move, copy, mirror and pattern on the final bodies of 104 designs (the old design files, the examples, the 76 reference recipes, the enclosure demos, the Pi case built through the UI, eight typical parts), through the commands and picks the desktop sends, each design in its own process, with an edit round on a sample of passes. tests/action_matrix/baseline.json is a ratchet: an action that passed there and fails now fails the test; newly passing ones are reported for cargo xtask action-matrix --bless. Every CI run checks a fixed sample; the nightly Action matrix job runs the whole matrix in four parts. 30,567 of 35,576 actions pass (85.9%); results and causes in docs/action-matrix.md, one ignored reproduction per open cause (#556-#568).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 02:41:17 -04:00
bherbruckandClaude Opus 5.5 57e6396fbb Tangent hole contacts split no faces, consistently (#307) (#364)
* Tangent hole contacts: every symmetric contact gives the same faces (#307)

Three things made the four symmetric contacts of reference case 42 differ:

- The 2D prism boolean's ray-parity test miscounted a ray grazing the bottom
  of a patterned hole, whose two halves are read back with centres a few ulps
  apart: one half counted the touch, the other missed it. The loop chaining
  then failed and those cuts fell back to the general boolean, which treats
  circles tangent within its tolerance as overlapping and splits the hole.
  The ray is now moved off vertices and arc extremes by far less than any
  modelling tolerance.
- The prism result's volume check used a coarser mesh than the operands, so
  a plate with many holes read too large and correct results were rejected.
- The merged topology did not join a hole's two pieces across the line where
  two tangent holes touch (four faces meet there).

Case 42 now gives 39 faces (33 holes, 6 planes); its expected.json pins it.

Fixes #307

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

* Kernel test: tangent hole pinch no longer splits the wall (#307)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-12 15:01:03 -04:00
bherbruckandClaude Opus 5.5 2ebceb6918 Sheet metal: sew the folded-material guard per piece so adjacent flanges cut (#296) (#355)
The guard that refuses machining through bends sewed every bend zone and
nonparallel panel into one solid. Two bends meeting at an open corner relief
share only an edge, so that sew failed with "nonmanifold edge contact" and any
cut on the base was refused. Sew and test each piece on its own instead.

Reference case 75-sm-bracket-holes now passes; its known_failure mark is removed.

Fixes #296


Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-12 14:27:40 -04:00
e12758ff91 Public reference tests: analytic and FreeCAD expected values (#310)
The oracle no longer uses Fusion measurements. tests/oracle/<case>/ now holds the 76 recipes
(our own format, with recorded measurements and tool-specific fields removed) and an
expected.json per case:

- 55 analytic cases: closed-form values from tools/oracle-analytic/ (stdlib Python, formulas
  in each case's "method").
- 21 FreeCAD cases: the same recipe built with FreeCAD's public scripting API by
  tools/freecad-oracle/ (an external program, not a dependency), with a reference.stl for 20.

solvecraft-cli oracle compares body count, volume, area, centre of mass, bbox, face counts
where the geometry fixes them, and, against reference.stl, the sampled Hausdorff distance and
the principal moments (spatial.rs from #301). cargo xtask oracle reads tests/oracle, writes
docs/oracle.md with the source of each value, and supports known_failure marks for tracked
bugs. CI runs it on every PR; a manual workflow regenerates the FreeCAD values. step-corpus,
seam normalisation and the through-all emulation, which only existed to compare with Fusion,
are removed.

75/76 pass; 75-sm-bracket-holes is a known failure (#296).


Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

Co-authored-by: bherbruck <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-12 10:43:43 -04:00