No panics in the boolean's final assembly (the web build aborts on any panic: the Plastic Enclosure sample panicked 8 times and crashed the browser's start page); face pushes check their result and fall back to the general offset (a boss standing on a plate joins again with off-axis cylinder seams); offset errors name the face they can't move; docs/robustness.md with the before and after rates; caught panics counted per design in the robustness runs
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
ccde7a4837
commit
1bf377c14b
8 files changed
+182
-33
No files matched your search
@@ -0,0 +1,96 @@
|
||||
# Kernel robustness
|
||||
|
||||
Real users hit edge cases the Fusion oracle (docs/oracle.md) never sees: faces that coincide
|
||||
by accident, tangencies, seams lying where another body cuts, walls thinner than a shell. The
|
||||
robustness runs build random but realistic designs and check every step.
|
||||
|
||||
## How it runs
|
||||
|
||||
```
|
||||
solvecraft-cli fuzz --from 0 --count 1000 --jobs 8 --timeout 90 --out runs/ --report report.md
|
||||
solvecraft-cli fuzz-one <seed> --minimise # one design, cut down to the steps that matter
|
||||
```
|
||||
|
||||
- **Designs** (`crates/engine/src/fuzz.rs`): a seeded generator starts from a box, an extruded
|
||||
sketch profile closed by an arc (sometimes notched), or a revolved section (partial or full
|
||||
turns, sometimes touching the axis). It then adds up to eight steps: joins and cuts of
|
||||
boxes, cylinders and spheres, fillets and chamfers on random edges, shells, holes (simple,
|
||||
blind, drilled), and rectangular and circular patterns of the last feature. Placements snap
|
||||
to a 2.5 mm grid and often to the body's own faces, so coincident faces and tangencies come
|
||||
up all the time, as they do in real parts.
|
||||
- **Checks after every step:** the command succeeds; every body is a sound solid (each shell
|
||||
closed and consistently oriented, every face meshes, positive finite volume:
|
||||
`Body::validity`); the volume moves the right way (a cut never adds, a join never removes).
|
||||
- **Boolean identity** (`crates/kernel/src/fuzz.rs`): for two random primitives on the same
|
||||
grid (boxes, cylinders, spheres, tori), union, intersection and cut each give a sound solid
|
||||
and V(A∪B) + V(A∩B) = V(A) + V(B), V(A−B) = V(A) − V(A∩B), within 0.2 %.
|
||||
- Each seed runs in its own process with a time limit, so hangs and hard crashes are recorded
|
||||
too. A step the kernel refuses as **not supported yet** (a fillet between two curved faces,
|
||||
a shell thicker than a wall) is undone and counted separately, and the design goes on: those
|
||||
are known limitations, not failures. Booleans that fail count as failures even when their
|
||||
message says "not supported".
|
||||
- `cargo test` runs a fixed set of seeds that must stay clean
|
||||
(`crates/engine/src/tests/robustness.rs`), next to the minimised cases fixed so far.
|
||||
|
||||
## Results
|
||||
|
||||
1000 seeds (0–999), 8 processes on a heavily loaded machine (load average 60–80), 90 s per
|
||||
seed. A "timeout" there is mostly a design whose booleans are very slow (seed 20 finishes in
|
||||
2 min 8 s alone), not a hang. The "after" run had more of them: the machine was busier still
|
||||
(test suites ran alongside), and failing booleans now try more fallbacks before giving up;
|
||||
fewer designs fail outright (27.1 % against 36.3 %). Both figures are from before the last two
|
||||
fixes below (sound face pushes, no panics in the boolean's final assembly).
|
||||
|
||||
| Designs | before | after |
|
||||
|---|---|---|
|
||||
| clean | 49.8 % | 53.8 % |
|
||||
| failed | 36.3 % | 27.1 % |
|
||||
| invalid body | 0.7 % | 0.9 % |
|
||||
| volume the wrong way | 0.2 % | 0.2 % |
|
||||
| over 90 s | 13.0 % | 18.0 % |
|
||||
|
||||
| Boolean identity | before | after |
|
||||
|---|---|---|
|
||||
| holds | 85.4 % | 80.8 % |
|
||||
| a boolean failed | 1.6 % | 1.2 % |
|
||||
| not run (the design ran out of time) | 13.0 % | 18.0 % |
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Shell corners where a curved face meets another at an angle** (the biggest cause, 215 of
|
||||
the 363 failed designs before). Moving a vertex took one linear step, exact only for planes;
|
||||
a cylinder meeting a plane at an angle (a shallow arc side) landed off the moved surface.
|
||||
Now refined by Newton steps onto the moved surfaces.
|
||||
- **Shell edges that are neither lines nor arcs** (a hole's wall meeting a curved side): the
|
||||
edge is rebuilt through its moved points.
|
||||
- **Shells of bodies in several pieces** ("this shell is not connected"): one shell per piece.
|
||||
- **Cylinder seams on the grid.** A cylinder's seam lines lay on its frame's axes, exactly
|
||||
where faces placed on the same grid cut it, and booleans failed along the seam. Seams now
|
||||
start at an odd angle: cylinders tangent to box faces from inside or out, and crossing
|
||||
cylinders touching along a line, now work.
|
||||
- **Partial revolves of profiles touching the axis** (a quarter or half turn of a rectangle
|
||||
from the axis): the edge on the axis no longer sweeps a zero-area face, which every boolean
|
||||
attempt failed on.
|
||||
- **Booleans on bodies in several pieces** (a join that left two lumps): when the whole fails
|
||||
or comes out empty, a piece at a time.
|
||||
- **Pushing a face apart** (coincident faces) checks its result: the exact rebuild could leave a
|
||||
cylinder unsound, and then the general offset is used. A boss standing on a plate joins again.
|
||||
- **No panics in the boolean's final assembly.** Natively a panic inside the kernel is caught,
|
||||
but the web build aborts on any panic; the Plastic Enclosure sample panicked 8 times building
|
||||
its bosses and crashed the start page in the browser. The vendored shapeops now returns
|
||||
`None` instead, and a test builds every sample with a panic counter. The runs count caught
|
||||
panics per design ("Caught panics" in the report), since each one would crash the web build.
|
||||
|
||||
### Known limitations (counted as "not supported", with a clear message)
|
||||
|
||||
- A shell thicker than a wall or a step: the moved faces would cross and the cavity turn
|
||||
inside out. Fusion fills such places solid; we need a topology-changing offset.
|
||||
- Fillets and chamfers between two curved faces, or ending at faces that aren't planar.
|
||||
|
||||
### Still failing
|
||||
|
||||
- Partial unions of a cap and a face (a cylinder's end lying partly on a box face): pushing
|
||||
one face into the other adds material where they don't overlap.
|
||||
- Shells of partial annuli (a half ring) whose cavity truck's boolean rejects although the
|
||||
same cavity built another way cuts cleanly.
|
||||
- Very slow booleans on bodies with many patterned features.
|
||||
Reference in new issue
Block a user