Commit Graph

14 Commits

Author SHA1 Message Date
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 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 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 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
bherbruck c87bb72f0f kernel-cases: coverage by kind of source, and the ring join of #2357
- tests/kernel-cases/sources.json gives each looked-at number's kind: an open or closed issue, a
  merged PR, one of the frozen truck-geometry PRs, a kernel-paused PR. The report's coverage by
  source counts how many of each were looked at, became cases or were skipped.
- crashes/2357: one join of a ring of 90 overlapping cylinder segments. The right answer is one
  closed ring body. The old kernel still panics in its intersection curves and runs past the
  timeout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 02:28:46 -04:00
jyviko 248fee75b9 ladder: every ladder run measures one case at a time
Runs are compared with the golden's times, so a run sharing the machine between cases flags
slowdowns that are only contention (seen with --jobs 4: four cases two to ten times slower).
--jobs still overrides 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 208c39461e ladder: cargo xtask kernel-cases --ladder, the complexity ladder's runner
The ladder orders kernel operations by complexity instead of by random goldens: a manifest
(tests/kernel-cases/ladder/ladder.json) lists tiers in order and each tier's cases in order;
every case is graded against its own answer like any rig case, and a golden
(tests/kernel-cases/ladder/golden.json) records per case and kernel the status, the commands'
time and what the kernel made. A run compares with the golden and flags slowdowns (over twice the
time and 0.25 s more), status changes and changed counts. `--record REASON` re-measures one case
at a time, rewrites the golden with its reason and sorts each tier by the first kernel's time.

The report, docs/kernel-ladder.md, gives per tier and kernel the counts per status and the
frontier: the first case in ladder order the kernel fails. It reuses the rig's process-per-case
runner, timeout and cells; results now carry their path under tests/kernel-cases/ so cases from
other areas can be listed in a tier. The README documents `base`, `missing` and the ladder.

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
bherbruck 7bb74d1c6b kernel-cases: an smlib feature for the CLI, and no grading of a kernel the build isn't running
- solidcraft-cli and solidcraft-engine forward an `smlib` feature to solidcraft-kernel/smlib, so
  `cargo build -p solidcraft-cli --features smlib` gives the rig SMLib's check.
- solidcraft_kernel::boolean_kernel() says which kernel this process runs booleans on.
  `default` until the SMLib switch (SOLIDCRAFT_BOOLEANS=smlib) lands and answers there. An smlib
  run on a build without the switch reports "not supported yet" instead of grading the default
  kernel under SMLib's name.
- An area may keep its skipped list in parts (skipped-<part>.json).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 02:28:45 -04:00
bherbruck 732fd2ace2 kernel-cases: a regression rig that grades each kernel against the case's own answer
Every geometry case the old kernel got wrong becomes tests/kernel-cases/<area>/<id>/: an
engine script or oracle recipe, and expected.json with the right answer, from analysis or a
hand calculation, or else the invariants. Never a kernel's output.

- solidcraft-cli kernel-cases <dir>...: runs a case and grades it. The checks are the outcome
  (succeeds, or refuses cleanly), the body count, and one closed shell per body that passes the
  record's structure and geometry checks and, with SMLib built, SMLib's check(All). Counts,
  volume, area, centroid and box are graded where the case gives them. Each run is pass, fail,
  not supported yet or crash.
- cargo xtask kernel-cases [--kernel default|smlib|both]: one process per case, so a native crash
  or a hang (--timeout) is that case's result. It writes docs/kernel-cases.md: coverage per area
  and source, results per kernel, and the sources looked at and skipped (<area>/skipped.json).
- solidcraft_kernel::validity and smlib_built, which the rig's checks use.

tests/kernel-cases/README.md gives the format.

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