311 Commits

Author SHA1 Message Date
jyviko 653c16e6f5 Native B-rep: a ball patch is its own surface kind, read from and written to SMLib's flat kind 6
SMLib's flat arrays now carry the corner of three equal rounds as `SURFACE_BALL_PATCH` (kind 6): its net as a NURBS face's block, with its sphere's centre and radius as its definition (ids 36 and 166). The record reads it as `ball_patch {center, radius}`, a label like the analytic kinds, with the net as its `nurbs`. A plain sphere with a form won't do: the net is not a piece of SMLib's sphere NURBS, so SMLib's `IsNurbSurfaceSphere` would refuse it.

Written back, a ball patch is kind 6 with the same definition, which SMLib takes once its net is certified on that sphere. Elsewhere:
- Offsets classify it as its sphere, so its offsets stay exact and collapse at the centre.
- Face kinds count it as a sphere: fillet_three_edges_at_a_corner's corner is now `sphere`, no longer `other`.
- STEP, which has no ball-patch entity, gets the net as the face's B-spline surface, pcurves included.
- Iso curves and SSI of the label are refused; the face's form is what evaluates.

Test: a_rounded_cubes_ball_patches_go_round_with_their_spheres. The cube's eight corners are ball patches about the corners pulled in by r. Points of each patch lie on its sphere to 1e-12. The patches are kind 6 again after import, with the same definitions bit for bit, and the closed-form volume holds.

Format: pending/ball-patch-faces.rs. Docs: docs/native-brep.md and the rig README's `surface_types` (`ball_patch`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M41G8Nua7HvuFPZkmJ
2026-11-02 15:44:41 -05:00
jyviko e6db7be0af Kernel tests: three rounds of different radii at a corner meet in SMLib's setback corner
Each round runs whole to its section square to its edge at its setback (the owner's rule, at
least 1.5 r, scaled to the least at which the G1 fill is certified convex), and the hole is the
setback split: one patch per round and the triangle in three quadrilaterals, 15 faces, G1.
Outside the box the sections span the body is the three strips', so its volume is theirs within
that box's. A later r3 round at the mitred corner makes the body all three at once make
(7928.142563938, 15 faces), as the engine and the model-cache tests have it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M41G8Nua7HvuFPZkmJ
2026-11-01 22:57:24 -05:00
jyviko 970446dec0 Kernel rig: a case's continuity can ask for an order per seam (seams: [{order, edges, exact}])
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M41G8Nua7HvuFPZkmJ
2026-11-01 20:03:30 -05:00
jyviko 780a0652d9 Kernel rig: a volume or area can be graded as a hand-derived range where analysis only bounds it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:33:29 -04:00
jyviko f3cf0c4f37 Model cache: a body made by rounds keeps them, so a later round blends them the same after opening
A design gave another body when opened from its model cache: the rounds a body was made of
lived only in memory, so a later round at their mitre was built sequentially (or refused, as
too large) after opening and blended with them when evaluated anew. The saved model now
records, per kernel body made by rounds, the body they were made on (a place in the bodies,
stored once though no state holds it) and the edges with their radii; reading it attaches
them back down each chain, and a thinned model keeps those bodies with the bodies made from
them. Model cache format 7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 19:19:30 -04:00
jyviko 709765fcae Model cache: a saved model records its body check mode and is adopted under it
Since the body check mode became part of the evaluation context (9acbcf924),
evaluate digests the context with the mode, but Model::adopt still took the
context without it and the default mode: the first evaluation after opening a
design from its saved model saw another context and recomputed every feature
(undoing_an_edit_after_opening_reuses_the_saved_results,
rolling_the_marker_back_keeps_results_after_cache_eviction). The saved model
now records the mode it was evaluated under (thinned ones too), adopt takes
it and digests the context as evaluate does, and a session opening a design
under another mode evaluates it again rather than showing that mode's results.
Model cache format 6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 15:19:33 -04:00
jyviko d3766865a0 Tests: old designs open and evaluate; what they rebuild to is today's
Tests that asserted an older design rebuilds as the build that saved it made it
now assert what still holds: it opens, is upgraded, evaluates, round trips and
names alike every time, and a feature that lost a reference asks for it again.

- naming corpus: two builds still name every face and edge alike and find the
  same faces with their stored names; a stored name that finds nothing must
  leave its feature failed (it asks to reselect), never a feature that builds.
  A sketch's face is found by its name as the sketch finds it.
- design corpus: the volumes, areas and bounds the saving builds recorded are
  no longer compared; a corpus design may fail only by a request to reselect,
  and undo leaves the features that failed on opening failed.
- fixed robustness seeds: no panic, valid bodies and volumes moving the right
  way; a step the kernel refuses is not a bug.
- a format 28 design's pieces and a format 13 design's extra bodies: marked as
  they open and named alike, without promising the numbers or names saved.
- action matrix baseline: the two corpus designs whose fillets, chamfer and
  offset face held names saved before format 14 re-recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 14:31:23 -04:00
jyviko ef37bd4459 doc: names saved before format 14 find nothing; their features ask to reselect
Face and edge names stored before format 14 were worked out from geometry and
open marked `?`. They were found among the names geometry gives today, as the
builds that saved them found them, pieces by the one nearest the pick. They
find nothing now: the feature holding one fails, asking for its reference to be
picked again, which stores its exact name. The legacy face and edge names a
body worked out for them are gone.

The tests that found such names as saved now assert the request to reselect:
a saved strip projection, a version 9 emboss on an annulus, a format 10 face
sketch and the corpus design named with numbered pieces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 14:31:23 -04:00
jyviko cfa6f38d6e doc, engine: a stored name finds its very face or edge, or its feature asks to reselect it
A face or edge name a feature stored finds only the face or edge it names: the
very name (or a synonym of that face), or the named piece told apart by the
faces around it. A face split into several pieces, merged into another face,
or left only as a face of the same stem is not the face that was picked, and a
name found on several bodies is told apart only by the body the reference's
point lies on. The fallbacks are gone: no piece nearest the pick, no merged
face, no edge at the picked point, no lost link that keeps its last geometry.
A feature whose stored reference finds nothing fails with DocError::Reselect:
blends, face points, sketch planes, sketch projection links, construction
references, hole reference edges, sheet bend edges and cylinder emboss.

The tests that asserted a fallback now assert the request to reselect: split
and removed fillet edges, a merged or rejoined face, a projected edge that was
split or is gone, a projection whose body went, saved strip projections after
wall coalescence, a fillet saved on a piece of a tapered side that is whole
now, a cut that starts from a piece that is no longer that piece, and a fillet
named on the lower of two stacked boxes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 14:31:23 -04:00
jyviko 1a93a39770 CLI: run and kernel-cases take the validation mode
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

solidcraft-cli run --validation MODE, kernel-cases --validation=MODE and
cargo xtask kernel-cases --validation MODE (with --ladder too), so the rig
runs under each mode.
2026-10-30 13:52:54 -04:00
jyviko 172c64cef8 Tests: the naming corpus checks that references resolve and builds agree
corpus_designs_rebuild_with_the_same_names_and_references compared every
corpus design with a text record of each body's face and edge counts and its
full name list, last written from truck's output (a55196e7a); 110 designs
differed only because SMLib keeps whole faces truck split in pieces. Those
counts and names are the kernel's, not an outcome.

The test, renamed corpus_designs_keep_their_references_and_name_alike_every_build,
now asserts invariants only, with no record:
- every design loads; one that does not is a failure naming the design and
  the step (oracle/83-boundary-loop-thicken: surface.thicken, SMLib status
  1001), not a record line;
- every name a design stores (fillet and chamfer edges, faces a feature
  picks, a sketch's face, sheet metal edges) finds a face or edge: none
  `gone`, no sketch face `lost`;
- two builds give the same name -> face map: each named face's area and
  centre and each named edge's length and middle (to 1e-6 of their size), and
  the same face or edge found for every stored name.
The design already exempt for unstable piece order
(regressions/closed_sweep_torus_cut) is still only printed for the second.

On develop it fails on two designs: oracle/83 above, and
regressions/cut_up_to_face_leaves_skin, whose Extrude13 face
`F47:top#[...]` finds nothing (the truck-era record had it `gone` too). All
159 designs name alike in both builds. The records in tests/naming/ are no
longer read; CONTRIBUTING no longer asks to re-record them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 07:12:24 -04:00
jyviko 74001e5325 Tests: check what each operation is for, not how many faces it makes
The kernel switch broke these tests only through their counts, which record how a kernel splits
faces rather than whether the result is right. Each now checks its intent:
- a fitted circle is the exact circle (centre, radius, a full turn), not "one segment";
- the tight bend sweeps a valid solid of Pappus' volume, πr²(40 + 5π/2), not a count of faces,
  edges and vertices;
- the Pi case keeps each outer side one face, stays valid after every feature and rebuilds the
  same topology at 32 whether built there or edited there, without a hard-coded table of totals;
- a certified paint stays on the wall's radius and covers as many faces after an edit, a copy
  and reopening as when it was painted;
- the offset sleeve and the extended strip are checked by their exact areas only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 04:32:50 -04:00
jyviko db757efc7c Tests: the pi case and the hole wall read as on green-truck-era-tests, so both branches agree
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:17:59 -04:00
jyviko 2debdd87ae Pi case test: each standoff is four faces, its walls one face each
The README demo's Raspberry Pi case stands four standoffs on its floor: Extrude2's ring of
radius 3 round a 1.25 hole, patterned by RectangularPattern1. Each is its outer wall, its inner
wall, its top and the floor inside it: four faces. The recorded counts were truck's, which made
each cylindrical wall two halves (six faces a standoff): 25 after feature 6, 43 after the
pattern, and 8 more than now at every step after it. On SMLib each wall is one face closed on
its seam, and the counts are 23, 35, 35, 47, 47, 51, 51, 55, 71 from feature 6 on (the feature
names show it: F6:side:c1, F6:side:c2, F6:top and the floor piece bounded by F6:side:c2 per
standoff). The outer sides stay one face each, and (b) and (c) still agree step by step.

Fixes cli rebuild_topology::pi_case_faces_per_step_at_both_heights.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:17:59 -04:00
jyviko 5c45570c91 Kernel rig: rustfmt; measured values in results are decimals, within tolerance; the ladder records 06/023 passing
The single results form compares a whole number exactly (a count). The construction and inspect
cases gave positions and volumes as whole numbers, which the form they were written for compared
within tolerance; they are decimals now. The NPT groove fix makes ladder 06/023 pass: its golden
entry is the passing run (51 faces, 8226.4042 mm3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:08:31 -04:00
jyviko 014a9eced5 Kernel rig: a flat_pattern field grades a sheet metal case's flat pattern
From the script's last sheet.flat_pattern result: the outline's size, its area less the
cut-outs', and the bend lines, each matched to its own one of the result's either way round.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:08:31 -04:00
jyviko 70f695c6ba Kernel rig: grade construction geometry and the numbers a command replies with
A case's construction field names construction points, axes and planes with the point, line or
plane each must be, and results reads values out of the commands' own replies by JSON pointer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:08:31 -04:00
jyviko bc3c9185cd Kernel rig: grade the kinds of a result's surfaces, its B-spline degrees and spans, and its free edges
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:08:31 -04:00
jyviko 235645db50 Kernel rig: the ellipse length's Simpson weights as a named step
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:08:31 -04:00
jyviko 45c9553262 Kernel rig: a case can check the files it writes and the commands' answers
A case's expected.json may name files written to $OUT (json, csv rows, or a DXF's
entity counts and curve lengths per layer) and a command's answer by step, each
matched as a part of what was made.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:08:31 -04:00
jyviko e0c7867b9b run_strict: the box's volume to 1e-9, as SMLib integrates it
allow_errors_writes_anyway_and_a_saved_design_keeps_failing compared the box's volume
with 4000.0 to the bit, which the old kernel's closed-form planar volume gave. SMLib
integrates mass properties numerically (relative accuracy 1e-4 asked for) and gives
the 20 x 20 x 10 box within a unit or two in the last place (3999.999999999999), the
correct answer to the precision the measure has. The test now checks 4000 mm³ to a
relative 1e-9.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 22:13:01 -04:00
jyviko 39bf63b16a Kernel rig: designed continuity cases, G0 to G4, that prove the measurement
A new `continuity` area: seams whose order is certain by construction, each graded
`exact` (reads its order and not the next) at picked edges with Continuity Analysis's
default stations and tolerances: a box's crease (g0), a chamfer in place of a round (g0),
an r5 round on planes (g1), and a profile closed by a g1, g2, g3 or g4 blend curve between
lines, extruded (g1 … g4). `continuity.edges` may now be a list of points, picked as
`inspect.continuity` picks them, and `continuity.exact` asks for the order and no more.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 21:22:17 -04:00
jyviko c37b0d2f02 Kernel rig: a case's expected continuity order at its blend seams
expected.json may give `continuity: {order: g0…g4, edges?: "blend" | "corner"}`: the
seams of each round, chamfer face or corner patch with the faces either side of the edge it
replaced, and of each corner patch with its rounds, are measured as Continuity Analysis
measures them (seam_diagnostics at its default 33 stations and default tolerances), and the
case fails naming the worst seam, its faces, the order it reaches and the next order's worst
value. The seams come from the faces' persistent names (doc::naming::blend_seams). The older
`{near, within_mm, …}` form is kept.

Every fillet-area case with a body gets its order: constant rounds and rolling corners g1,
curvature rounds g2, chamfers g0, the corner: g2 patch g2 at its seams.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 21:22:17 -04:00
jyviko 97721ad05f Fillet setbacks not past where the rounds meet are refused naming the least; the rig grades a refusal by its reason
A corner setback must reach past where the corner's rounds' contact lines
meet without one (smlib_blend_setback); short of it SMLib failed with its
own status (1001). The kernel now refuses it before SMLib runs, for the
rolling-ball corner (fillet_setback) and the curvature corner
(fillet_g2_corners) alike, naming the least: on each face at a corner of
planar faces and straight edges the two rails, r tan(psi/2) from their
edges, cross (d2 + d1 cos alpha) / sin alpha along an edge (r on faces
square to each other). Other corners stay SMLib's to refuse.

The rig's `refused` cases now name the reason (`refusal`, a part of the
message, required), so a failure for another reason no longer passes; a
`solid_or_refused` case may name one. Fillets: the setback cases and
783, 3435 pass; 1390, 896, 4782 past-a-full-round and the no-tangent-chain
case are refused for an unclear reason and fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 15:13:23 -04:00
jyviko 2fed39c85c Continuity Analysis measures G3 and G4; the dialogs offer what each construction builds
Each seam now also reports the jump of the curvature's arc-length derivative across it (G3)
and of its second derivative (G4), both from the faces' exact partials, and its order: the
highest one every station meets within the tolerances (two new tolerances, defaults in the
kernel). The verdict keeps its meaning (smooth is G2 or better). inspect.continuity replies
with the new metrics, each seam's order and a count per order; the viewport widens G3 and G4
seams, the legend and the marker labels name every order in words. The Patch, Blend and
Boundary rows offer the orders the kernel's Construction table says they build. G4's words
in en, ar, de, he, ja, ko and zh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 21:15:20 -04:00
jyviko 77bd85cabf cli: snapshot --quality coarse|normal|fine|ultra meshes the bodies at that display quality
As the app's Display Quality setting, set before the design opens so every display plan is
made at it; a level that isn't one is refused with the levels. For close-up reviews of
imported faces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 20:53:08 -04:00
jyviko 8fbb575a5e kernel-cases: a continuity check, and ladder 07/015 graded by it
expected.json `continuity`: over the tangent seams wholly within `within_mm`
of `near`, the curvature jump across them (exact surfaces, 65 stations a
seam) at most `curvature_jump_per_mm` clear (`clear_mm` along the seam) of the
vertices where two of them turn, where a neighbour's own G1 seam ends.

07/015, the box corner's three r5 rounds with corner: g2: one valid body of 10
faces within the box, its patch's twelve seams jumping at most 1e-3 per mm
clear of the hole's six corners by 1.2 mm (2.7e-4 measured; the ball corner
of 009 jumps 0.2). Its golden entry is the passing run's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 12:24:10 -04:00
jyviko fafd977b05 Profiler: the Profile operations preference switches recording at run time
- Graphics page: "Profile operations" (off by default) starts and stops the
  profiler when it changes; an agent's diagnostics.profile in between stands,
  and SOLIDCRAFT_PROFILE=1 is not undone by the default at start-up.
- The desktop app reads SOLIDCRAFT_PROFILE at start-up.
- Labels in en, ar, de, he, ja, ko, zh. The pending-messages test compares
  right-to-left pending text in display order, as the catalogs give it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 11:40:49 -04:00
jyviko 9cd655259d Profiler: commands, feature evaluation, io; diagnostics.profile; CLI --profile
- Session::execute is a command span; Model::evaluate and each feature computed
  (by its type) are spans; io's import, export and design read/write too; the
  STEP reader's topology, pcurves and solid record.
- diagnostics.profile (contract + output schema): report, start/stop, reset,
  Chrome trace file.
- A STEP/IGES import's reply carries its own profile while recording.
- Every app compiles the profiler in by default (feature `profile`);
  SOLIDCRAFT_PROFILE=1 starts it.
- solidcraft-cli run/eval/bench-open --profile print the table on stderr,
  --profile-out writes the trace; run --profile works on designs and STEP files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 11:40:49 -04:00
jyviko 4e26dc6402 The command line and the web app link SMLib by default too
As the desktop app: SMLib is the only kernel, so a build without it models nothing. The web
app links the prebuilt wasm archive, so it needs no wasi-sdk.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HoZgkCdAVrscuw2kjQTWDs
2026-10-27 02:28:53 -04:00
jyviko e476aba94f SMLib in the browser: built with wasi-sdk for wasm32-unknown-unknown
On the web target the smlib build compiles SMLib for wasm32-wasip1 with wasi-sdk's clang
(WASI_SDK_PATH), with wasm exceptions in the exnref encoding that wasi-sdk's libc++ and Rust
use, and links wasi-sdk's libc++, libc++abi, libunwind and libc. The WASI calls libc makes are
defined in ffi.rs: stdout and stderr go to the log, the clocks are the page's (the C API times
every call), and there is no file system or environment. solidcraft-web gets an smlib
feature, off until CI has wasi-sdk.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HoZgkCdAVrscuw2kjQTWDs
2026-10-27 02:28:53 -04:00
jyviko bc15221fa3 The desktop app links SMLib by default
SMLib is the only kernel, so a desktop build without it models nothing. The app gets the
smlib feature the CLI has, on by default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HoZgkCdAVrscuw2kjQTWDs
2026-10-27 02:28:53 -04:00
jyviko 9138e87040 Rebase onto main: what the merged code needs to build together
The branch rebased onto main keeps each of its commits; where both sides
changed the same code, these are the pieces neither side's commit had.

- Cargo: one [features] table in the CLI's manifest (two met in the merge).
- geom: a NURBS surface's `closed` set once in a placed copy (both sides
  added it).
- kernel: the whole-face extrude tools (#2040) work around truck's boolean
  on truck types, which left the workspace with the SMLib kernel; the
  module, its tests and the doc crate's tool and tests go. The display
  planner's flat fill (tess/fallback.rs) has no caller with the schema 4
  mesher, and the tessellator's seam and uv modules are the branch's. A
  body's boundary tolerance from a STEP file belongs to the truck body the
  schema 4 record replaced: `with_boundary_tol` goes. `unmeshed_faces`
  counts the coarse mesh as the branch does. A loft's section re-split
  passes the lead's perimeter shares to main's `resample` (a circle breaks
  there when the matched corners do not go round in order). Main's tests of
  the mesh-based measure (the SMLib kernel measures exactly) and of the
  IGES preprocessor name (no such field on the branch's import record) go.
- doc: a feature result carries no boolean diagnostics on the branch, so
  the model cache neither writes nor reads them, and a pattern copy's miss
  test runs the intersect as it is. A placed body's worker result is a
  Result: a body taken from the previous placement is Ok. A thread's
  clipboard remap takes main's arguments, the tapped catalogue names a
  metric size by ThreadForm::Metric, and main's tests unwrap the placing
  calls that return their error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 02:28:53 -04:00
jyviko 369c897d85 kernel, cli: clippy and the cli tests build again
prism.rs's sheet regions import Surface and Vec3 only where they are built (the smlib feature),
so the kernel without it has no unused imports; the cli's tests that measure meshes at their own
tolerance depend on solidcraft-kernel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
2026-10-27 02:28:51 -04:00
jyviko 9a79588575 doc, engine, ui: placing the model returns its error; placements are checked where they are set
doc: world_state, world_state_reusing, state_in_frame_at, state_in_frame, face_point_state,
face_point_names and construction_state return Result. A body that could not be placed, a
frame that could not be inverted, a sketch plane or thread axis that did not survive the
placement, or a failed placing worker used to leave things where they were without a word;
now the call fails with what could not be placed. is_placement is the one test of an
occurrence's placement (finite, a rotation that does not mirror, a translation within
1e9 mm). Opening a design names every occurrence that fails it; add_occurrence refuses
one; a joint solution that would place an occurrence outside one is not applied and the
joints placing it report it.

engine: Session::world_state returns Result and keeps a failure in its cache as it keeps a
placed model. bounds, home_camera, open_sketch_plane, the scene builders, the world
previews, frames::to_local and auto_operation pass the error on; helpers answering "not
found" take the placed model from their caller. Commands setting a placement check it
(valid_position, exploded view, fastener at a point, STEP insert matrix).

ui: panels, picks and hovers read the session's placed model through
open_meshing::session_world; a model that cannot be placed shows no placed bodies, and the
viewport says why across its bottom. Pictures and the control channel report the error.

cli, mcp: snapshots, renders, benches and the oracle report the error; the kernel-case rig
records it as the case's failure. Tests read the new Results with unwrap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
2026-10-27 02:28:51 -04:00
jyviko af4e97b648 cli: the rig and the oracle reach MeshTolerance through the engine
solidcraft-cli depends on the engine, not the kernel: solidcraft_kernel::MeshTolerance did not
resolve; it is solidcraft_engine::kernel::MeshTolerance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
2026-10-27 02:28:50 -04:00
jyviko 712caf8bf4 engine: no boolean retries to report; overlaps are SMLib's exact intersection
The kernel has no boolean retries now, nor their diagnostics
(capture_boolean_diagnostics, BooleanDiagnostics, BooleanStrategy), nor the near-coaxial
crescent (coaxial_overlap, coaxial_candidate, with_attempt_budget). What read them goes:

- doc: FeatureResult and the evaluation cache carry no boolean diagnostics, and no "Boolean
  retry" warning; the saved model no longer writes them (an older file's are ignored);
- engine: timeline.inspect / feature inspection drop `boolean_diagnostics`; fuzz runs and
  the CLI fuzz summary drop their retry counts;
- inspect.interference: each pair is the bodies' Intersect, measured; the near-coaxial
  crescent, the by-piece intersection of bodies in several pieces and the unverified notes
  go (the command's doc no longer lists near_coaxial);
- inspect.clearance: an overlap is the bodies' Intersect, measured near its region; the pin
  tries, the cut-down copies of large bodies (clipped, narrowed), the union cross-check
  (union_disagrees, contradicted) and the malformed-part check (plausible) go, and the
  measure near the origin passes its move's error on.

Tests: the retry test and the unit tests of the deleted checks are removed; the barrel join
test (tests/boolean_diagnostics.rs, now tests/barrel_join.rs) keeps its geometry checks;
the pin-in-bushing test expects the filleted case measured; assertions on empty diagnostics
and on near_coaxial are dropped; the corpus fixtures lose the diagnostics key and the one
retry warning.

(not built: base in progress)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
2026-10-27 02:28:50 -04:00
jyviko 1ecf00b5ac engine: feature replies carry no boolean diagnostics
doc's FeatureResult has no boolean_diagnostics any more (truck's Boolean
retry reports, gone with truck; SMLib's boolean has no retries). The
timeline.inspect and doc.inspect replies drop the key.

Tests of the removed reports: tests/boolean_diagnostics.rs is deleted (it
checked truck's retry events and their survival through the cache, undo and
reopen); the assertions that a feature's report had no events go from
features_more_tests, patterns_tests, hole_face_tests and tests/rim_cut (the
rest of each test stays). The CLI corpus's expected replies
(move-bodies, issue-489-stacked-join, issue-616-lid-ribs) drop the key; the
issue-616 one listed a planar_fallback event. docs/robustness.md: its
section on retries becomes one on SMLib's booleans, which have none.

Left to the blends work: engine fuzz.rs (its retry-event counts) and
clearance/interference (capture_boolean_diagnostics, coaxial_overlap,
with_attempt_budget).

Not built: base in progress (kernel-smlib/no-truck 66ab6b7f does not build).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
2026-10-27 02:28:49 -04:00
jyviko 001c62ab16 kernel-cases: the rig runs SMLib only and keeps each run's SMLib dumps
SMLib is the only kernel now. cargo xtask kernel-cases ran every case once
per kernel asked for (--kernel default|smlib|both), setting
SOLIDCRAFT_KERNEL per run, and wrote a column per kernel; solidcraft-cli no
longer reads that variable.

The rig and the ladder run each case once, through solidcraft-cli built with
--features smlib (cargo run passes it), and report one result per case:
--kernel and the env var are gone. Each run has an output folder (--out,
default target/kernel-cases, target/kernel-ladder for the ladder) holding
results.json (every case's full result, which --results used to write on
request) and dumps/<area>-<case>/: every case runs with
solidcraft-cli kernel-cases --dumps=<out>/dumps, so a failed SMLib call
leaves its inputs for replay.

The ladder's golden holds one entry per case: golden.json is the last
recording's smlib entries, which predate SMLib running every case (its
reason says so); record it again after the first SMLib-only run.

docs/kernel-cases.md (until the next run regenerates it),
tests/kernel-cases/README.md, docs/kernel-smlib-sweeps-shell.md (its truck
column and comparisons dropped), xtask's and solidcraft-cli's usage text:
one kernel. Nothing was run.

clippy -p xtask --all-targets: clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
2026-10-27 02:28:49 -04:00
jyviko beebf22032 kernel-cases: --dumps=DIR leaves each failing SMLib call's inputs for replay
A rig case whose SMLib call fails left nothing to replay it from: nothing called
solidcraft_smlib::set_dump_dir. `solidcraft-cli kernel-cases --dumps=DIR` now points SMLib's
dump folder at DIR/<area>-<case> before each case runs, so a failing call leaves its
arguments and B-reps there (smlib_brep_read reads them back into a scratch C program), and
turns it off after the run. Off without the flag. The kernel exposes it as
smlib_dump_dir, beside smlib_built (the CLI reaches SMLib only through the kernel).

(not built: base in progress)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
2026-10-27 02:28:49 -04:00
jyviko 166ebe2ee9 The truck crates leave the workspace; the rig and threads run on SMLib alone
truck-modeling, -topology, -shapeops, -stepio and the vendored truck-geometry, -meshalgo,
-shapeops, -stepio and matext4cgmath (with their attribution rows and vendor notes) are removed.
The kernel-cases runner has one kernel, SMLib, and no build-mismatch check; a modelled thread is
cut by SMLib's exact screw-swept groove (the faceted groove path is gone).

(not built: base in progress)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
2026-10-27 02:28:49 -04:00
jyviko 42997a62ed WIP kernel: Body::mesh(&MeshTolerance) as the one mesher (does not build yet)
Body::mesh / mesh_plan / mesh_of and MeshTolerance (chord, display, display_of, export_of)
replace tessellate, tessellate_with, display_mesh*, display_plan*, reference_display_mesh_angular;
every caller in kernel, doc, engine, io, ui-egui, gpu and the CLI renamed mechanically; the
truck-mesher fallback, mesh_shells*, refined* removed; Body::new orients from the planner;
truck-meshalgo dropped from Cargo.toml with the tests of its hooks. Still to fix: trait imports
in tess/*, splitface/lumps/preview/step_in/boolean_record meshalgo uses, measure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
2026-10-27 02:28:47 -04:00
jyviko e1a2571696 kernel-cases: SOLIDCRAFT_KERNEL=truck grades as the default kernel
The kernel accepts `truck` (as well as unset) for its truck backend, and
`boolean_kernel()` reports that backend as `default`. The rig compared
the raw setting with that name, so a run with SOLIDCRAFT_KERNEL=truck
reported every case as "this build runs booleans on the default kernel,
not truck" instead of grading it. The rig now names unset, empty and
`truck` alike as `default`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
2026-10-27 02:28:47 -04:00
jyviko d672cfa013 kernel: one switch, SOLIDCRAFT_KERNEL, picks the kernel for every operation
All operations move to SMLib at once, so the selector is no longer the booleans' own:
`SOLIDCRAFT_KERNEL=smlib|truck` (read once, unset is truck, the same refusals for an unknown
value or SMLib in a build without it) is answered by `solidcraft_kernel::backend()`
(crates/kernel/src/backend.rs), which every operation's dispatch calls. The boolean's SMLib path
moves to smlib_boolean.rs. The regression rig's kernel check (`boolean_kernel`) now answers from
the switch, and the rig and CLI set SOLIDCRAFT_KERNEL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWhMwdqJYQKQq8RCLSL1LT
2026-10-27 02:28:47 -04:00
bherbruck 8cb976b9b2 kernel-cases: watertight checks the display mesh, welding vertices by distance
Two faults made simple curved solids look open (#818's blind hole: 80 open edges, a stadium
slot: 52):
- It meshed with `refine`, the measuring mesh, which splits triangles across curved faces on
  their own and leaves T-junctions on the edges they share with neighbours. It now checks the
  display mesh, whose faces share each edge's points.
- It matched vertices by rounding to a 1e-6 mm grid, which splits points a rounding error apart
  across a cell boundary. It now joins vertices closer than `tolerance.weld_mm` (default 1e-4 mm).
Both cases now have 0 open edges, also with the weld at 1e-6 mm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 02:28:46 -04:00
bherbruck 58ce14f45f kernel-cases: count ranges, a watertight mesh check, and per-case timeouts
For the history areas' cases (threads, tessellation):
- A count may be an inclusive range `[min, max]`, where the geometry only bounds it (a modelled
  thread's faces).
- `"watertight": true` meshes each body (chord tolerance `tolerance.mesh_mm`, default 0.01 mm)
  and requires no open and no over-shared edges, with vertices matched by position.
- `"timeout_s"` gives a case longer than the run's timeout, at most 30 min.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 02:28:46 -04:00
jyviko 35ebc816ba kernel-cases: a missing capability's message is the case's own text
The report already says "not supported yet" for the status; the error repeated it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWhMwdqJYQKQq8RCLSL1LT
2026-10-27 02:28:46 -04:00
jyviko bf0761f6b9 kernel-cases: base recipes, missing capabilities, and the commands' own time
What the complexity ladder needs from the rig's case runner, kept in the one runner:

- A script may name a `base` case directory: that case's commands (and its own base's, up to
  32 deep) run first, so a ladder case starts from the previous tier's finished part without
  copying its commands. `$CASE` is each recipe's own directory; `$OUT` is the running case's
  scratch directory, in its bases too.
- `missing` in expected.json reports the case as not supported yet without running it: a
  capability with no command or parameter (multi-start threads, fillet setbacks) stays visible
  instead of being faked with a stand-in.
- Each result carries `seconds` (the commands' own time, without process start or grading) and
  `measured` (body count, face/edge/vertex counts, volume, area), for the ladder's golden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWhMwdqJYQKQq8RCLSL1LT
2026-10-27 02:28:45 -04:00
bherbruck c24b066d25 kernel-cases: an outcome for geometry with no single manifold answer
`"outcome": "solid_or_refused"` takes a clean refusal, or else grades the result as usual. Two
bodies that touch along a circle only (#168, #3841) have no one-solid union: a refusal or the two
bodies left apart are both right; fusing them is wrong. The two cases said opposite things
(two bodies, a refusal) and now agree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 02:28:45 -04:00
bherbruck 678a70da2c kernel-cases: shells as a graded count, no SMLib verdict where it can't take the record, $OUT
- `"shells": N` in expected.json grades the total number of shells: a body with a sealed void
  holds two, and some joins keep several lumps in one body. Those cases (#3175, #3455, #3526,
  #3730) are graded on validity again instead of being marked not valid.
- When SMLib's record conversion says "not supported yet" (revolved surfaces, traced intersection
  curves), its check gives no verdict. That's shown but not graded, since it isn't a fault of the
  body. solidcraft_kernel::SmlibCheck carries the three outcomes.
- `$OUT` in a recipe is a scratch directory outside the repository, for files a case writes. The
  two STEP-export crash cases write there instead of /tmp.
- cargo xtask kernel-cases --results FILE keeps every result as JSON.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 02:28:45 -04:00