Port of snaporca da8d011b87; parity holds (DesignPanel.cpp still exactly 32 divergent
lines). Verified independently on this fork's own rig: full ladder 126/126 against
BuildID 96c697a3, built from this tree.
Reviewing the DistanceX/Y fix for OTHER members of its class found three more live defects
on the constrain toolbar. All four share one root: a branch assumes every picked entity has
two endpoints, and the solver's refusal to resolve a role it cannot find is silent.
COINCIDENT had the identical closest-pair walk over {P0,p0},{P1,p1}. For two Points the
phantom (0,0) pair sits at distance 0, which is the smallest distance there is, so it
ALWAYS won: ptOf(Point,P1) -> 0, ref_ok fails (SketchSolver.cpp:185), constraint dropped.
Not sometimes -- every press.
HORIZONTAL/VERTICAL hardcoded ra=P0, rb=P1 with no type check. With a Point picked the
constraint is dropped by the same mechanism but still STORED: constraints goes 0 -> 1 after
the commit and nothing moves, so the Constraints list shows a dimension that can never do
anything. Worse than refusing -- the panel claims the sketch is constrained when it is not.
ANGLE computed p1-p0 on whatever was picked. On a circle that is (0,0)-centre, so two
circles pre-filled the field with the angle between their centre POSITION VECTORS (178.83
deg for two on the x axis), and accepting it emits SLVS_C_ANGLE on two circle prims.
Both branches now refuse with a message. entity_ends()/closest_ends() are file-scope and
shared by Coincident and DistanceX/Y, so there is one implementation instead of two that
drift.
Two smaller findings from the same review: infer_auto_constraints' roles_of omitted
EllipseArc while heal_coincidences' identical copy has it; and set_point(Circle, Center)
wrote e.center and not e.p0, breaking the "p0 mirrors centre" invariant for the duration of
a live drag.
New rungs D8 and D9, both RED against the shipped binary and green here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY
Design-tab scripts
Everything here supports the parametric Design tab (src/libslic3r/CAD/,
src/slic3r/GUI/CAD/). Nothing here is needed to build or run OrcaSlicer — these
are the development and verification tools for that one feature.
The verb in the name is the role:
build-… |
produce a binary |
start-… |
bring something up and leave it running |
run-… |
run a suite and report pass/fail |
check-… |
one specific assertion, usually driving a live app |
Verification
| Script | What it proves | Needs |
|---|---|---|
run-kernel-tests.sh |
The CAD kernel builds and the Catch2 [CadDocument] tags pass — every case builds a document, recomputes it and asserts on real geometry. Exit 0 is the verification contract. |
Docker only. No display. |
run-all-checks.sh |
Every check below, in one command. The gate before pushing a Design-tab change. | Docker + the GUI container |
check-sketch-engine.py |
A ladder of 2D sketches of increasing complexity, judged on loop count, closure and void attribution rather than on area. | Kernel only |
check-sketch-engine-corpus.py |
The same ladder graded against a systematic sample of real drawings instead of shapes we chose. | Kernel + corpus |
check-gui-sketching.py |
The same profiles drawn the way a person draws them — synthetic mouse gestures and typed values. | Headless GUI |
check-gui-context-menu.py |
That right-click is the pivot of the design gesture, and adapts to what was clicked. | Headless GUI |
check-mcp-sketch.py |
The sketch layer driven over the MCP socket, asserting what decides whether a profile is buildable. | Headless GUI + SNAPORCA_MCP |
run-kernel-tests.sh is the only one CI can run. The rest need a live
application with an OpenGL canvas and synthetic input, which hosted runners do not
have. The kernel suite itself is already in CI by an ordinary route: the cases are
registered in tests/libslic3r/CMakeLists.txt under if (SLIC3R_CAD), so they are
part of libslic3r_tests and run under ctest on every platform like any other
unit test. This script exists for the local loop, where it is a two-minute round
trip instead of a full application build.
Build and run
| Script | Purpose |
|---|---|
build-gui.sh |
Build the GUI binary in a throwaway container, writing into the build-cache volume the long-lived GUI container reads. |
build-gui-incremental.sh |
Incremental build against the deps-baked image, for a fast edit/compile loop. |
start-headless-gui.sh |
Bring the app up on a headless X display (Xvfb + a window manager), ready to drive or attach to over VNC. |
Two constraints that are not obvious and have each cost a session:
- Never build inside the GUI container. Its baked source tree silently reconfigures the shared build directory and this fork's targets vanish.
- A window manager is required. Without one, windows are never focused, and an unfocused GTK app ignores synthetic keys — which looks exactly like a code bug.
docs/rig_build_traps.md documents these and three more, with symptoms and exact
recovery commands. Read it before debugging a configure or link failure one of
these scripts reports.