From 13d5eac891f4f1468addb18d6d522a642af88418 Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Fri, 28 Aug 2026 19:34:03 +0200 Subject: [PATCH] Move the Design-tab scripts into scripts/CAD/ and name them by role Requested by SoftFever on PR #15238: ten of these had accumulated loose in scripts/ next to ~20 unrelated upstream ones, with names that only meant something to whoever wrote them. They now sit in scripts/CAD/, mirroring the src/libslic3r/CAD/ and src/slic3r/GUI/CAD/ split, and the verb in the name is the role: build- produces a binary, start- brings something up, run- runs a suite, check- asserts one thing against a live app. kernel-test.sh -> CAD/run-kernel-tests.sh ladder-all.sh -> CAD/run-all-checks.sh sketch-ladder.py -> CAD/check-sketch-engine.py ladder-corpus.py -> CAD/check-sketch-engine-corpus.py gui-ladder.py -> CAD/check-gui-sketching.py offer-ladder.py -> CAD/check-gui-context-menu.py mcp-sketch-smoke.py -> CAD/check-mcp-sketch.py rig-build.sh -> CAD/build-gui.sh docker-iter-build.sh -> CAD/build-gui-incremental.sh gui-session.sh -> CAD/start-headless-gui.sh "Ladder" was the worst of them: it named the shape of the test (rungs of increasing difficulty) rather than what the test proves, so nothing in the directory listing told you which one needed a GPU and which was pure kernel. Every reference rewritten -- the docs, the cross-calls between the scripts, Dockerfile.deps, and the container-side /OrcaSlicer/scripts paths. The three shell scripts resolve REPO relative to themselves and now sit one level deeper, so that walk went from /.. to /../.. . The copies these push into a container's /tmp were renamed to match, or the container would have kept the old names alive. Two runtime paths deliberately NOT renamed. /tmp/orca-rig-build.lock is a cross-fork contract -- both forks take the same lock so two concurrent builds serialise instead of OOMing the box, and renaming it on one side silently removes that guard. /tmp/gui-session.log is a runtime artefact, not a script. Added scripts/CAD/README.md: what each script proves, what it needs, and the two constraints that have each cost a session (never build inside the GUI container; a window manager is required or synthetic keys are ignored). On CI, which was the other half of the request: the kernel suite is already there and always has been. The cases are registered in tests/libslic3r/CMakeLists.txt under if (SLIC3R_CAD), which defaults ON and no workflow turns off, so they build into libslic3r_tests and run under ctest on every platform via unit_tests.yml -- like any other unit test, needing no new job. They have simply never been seen to run, because the workflows on this PR are still awaiting maintainer approval. run-kernel-tests.sh is the local loop over the same cases, and it is the only script here CI could run: the other six need an OpenGL canvas and synthetic input. Verified: scripts/CAD/run-kernel-tests.sh from its new location, all tests passed, 2562 assertions in 190 test cases. --- docs/design_tab_pr_description.md | 2 +- docs/rig_build_traps.md | 28 +++++----- docs/ux/mockups/gen_offer_table.py | 2 +- scripts/CAD/README.md | 53 +++++++++++++++++++ .../build-gui-incremental.sh} | 12 ++--- scripts/{rig-build.sh => CAD/build-gui.sh} | 12 ++--- .../check-gui-context-menu.py} | 10 ++-- .../check-gui-sketching.py} | 6 +-- .../check-mcp-sketch.py} | 2 +- .../check-sketch-engine-corpus.py} | 2 +- .../check-sketch-engine.py} | 2 +- .../{ladder-all.sh => CAD/run-all-checks.sh} | 20 +++---- .../run-kernel-tests.sh} | 20 +++---- .../start-headless-gui.sh} | 6 +-- scripts/Dockerfile.deps | 4 +- tests/libslic3r/test_caddocument.cpp | 2 +- 16 files changed, 118 insertions(+), 65 deletions(-) create mode 100644 scripts/CAD/README.md rename scripts/{docker-iter-build.sh => CAD/build-gui-incremental.sh} (92%) rename scripts/{rig-build.sh => CAD/build-gui.sh} (91%) rename scripts/{offer-ladder.py => CAD/check-gui-context-menu.py} (99%) rename scripts/{gui-ladder.py => CAD/check-gui-sketching.py} (99%) rename scripts/{mcp-sketch-smoke.py => CAD/check-mcp-sketch.py} (98%) rename scripts/{ladder-corpus.py => CAD/check-sketch-engine-corpus.py} (99%) rename scripts/{sketch-ladder.py => CAD/check-sketch-engine.py} (99%) rename scripts/{ladder-all.sh => CAD/run-all-checks.sh} (72%) rename scripts/{kernel-test.sh => CAD/run-kernel-tests.sh} (91%) rename scripts/{gui-session.sh => CAD/start-headless-gui.sh} (96%) diff --git a/docs/design_tab_pr_description.md b/docs/design_tab_pr_description.md index deea21d6fc..a6d67f0e7c 100644 --- a/docs/design_tab_pr_description.md +++ b/docs/design_tab_pr_description.md @@ -46,7 +46,7 @@ is new code. The negotiable surface is the 37 modified files. 205 `TEST_CASE` blocks across 6 new test source files. This counts assertions written, not assertions passed — a run needs a build. -`scripts/kernel-test.sh` is the headless verification contract: it builds only +`scripts/CAD/run-kernel-tests.sh` is the headless verification contract: it builds only `libslic3r_tests` (not the GUI app), needs no display, and exit 0 means the CAD suite passed. It now runs with **no exclusions** — both cases that used to be quarantined (the circle-line tangency solver abort and the internal-thread reference) are fixed. diff --git a/docs/rig_build_traps.md b/docs/rig_build_traps.md index 02d1db54a4..ac7829a1a8 100644 --- a/docs/rig_build_traps.md +++ b/docs/rig_build_traps.md @@ -3,16 +3,16 @@ The build rig is two long-lived containers, `snaporca-gui` and `orcacad-gui`, one per fork. Each mounts only its fork's build volume (`snaporca_buildcache` / `orcacad_buildcache`) at `/OrcaSlicer/build`, its fork's `resources/`, and a shots directory — nothing else. They run the -binary; they do not build it. Rebuild with `scripts/rig-build.sh`. +binary; they do not build it. Rebuild with `scripts/CAD/build-gui.sh`. | fork repo | project() | deps image | build volume | GUI container | binary | |---|---|---|---|---|---| | `snaporca` | `Snapmaker_Orca` | `snaporca-deps` | `snaporca_buildcache` | `snaporca-gui` | `snapmaker-orca` | | `orca_cad` | `OrcaSlicer` | `orcacad-deps` | `orcacad_buildcache` | `orcacad-gui` | `orca-slicer` | -`scripts/rig-build.sh` exists alongside `scripts/docker-iter-build.sh` for one reason: it does a +`scripts/CAD/build-gui.sh` exists alongside `scripts/CAD/build-gui-incremental.sh` for one reason: it does a target-only `ninja` into the volume the GUI rig launches from, so a session can test a single -change without a full repackage, whereas `docker-iter-build.sh` runs the full packaged build. +change without a full repackage, whereas `build-gui-incremental.sh` runs the full packaged build. Both start a throwaway container from the deps image with the live repo mounted over the baked tree — never build inside the GUI container (Trap 1). @@ -32,7 +32,7 @@ reports an unknown target, and `orca-slicer` / `OrcaSlicer` have been replaced b `snaporca-deps`, so even on the mainline fork the baked tree is the other fork's. A `cmake .` there reconfigures the shared build dir under the wrong project name. -**Fix.** Build only via `scripts/rig-build.sh`, which starts a throwaway container from the deps +**Fix.** Build only via `scripts/CAD/build-gui.sh`, which starts a throwaway container from the deps image with the live repo mounted over the baked tree — `src`, `resources`, `cmake`, `deps_src`, `localization`, `CMakeLists.txt`, `version.inc` — and writes into the same volume the rig launches from. @@ -66,7 +66,7 @@ fork's root `CMakeLists.txt`, near line 948). **Cause.** The deps image predates that requirement. Only the mainline (`orca_cad`) fork has `deps_src/pybind11` and the requirement; snaporca has neither. -**Fix.** Mount `deps_src` over the baked tree — `scripts/rig-build.sh` does. Corollary: mounting a +**Fix.** Mount `deps_src` over the baked tree — `scripts/CAD/build-gui.sh` does. Corollary: mounting a snaporca tree into an `orcacad-deps` build reproduces this error exactly. --- @@ -83,7 +83,7 @@ its own configure, while the consumer in the root `CMakeLists.txt` (`if (NOT OCC after the `TKFillet TKOffset` prepend (`src/libslic3r/CMakeLists.txt:599`) therefore links the previous list and drops `TKBool`/`TKOffset`. -**Fix.** Configure twice. `scripts/rig-build.sh` runs `cmake .` twice for exactly this reason; if +**Fix.** Configure twice. `scripts/CAD/build-gui.sh` runs `cmake .` twice for exactly this reason; if you ever configure by hand, run it twice. --- @@ -100,7 +100,7 @@ snaporca, 319/320 in orca_cad). Every `#ifdef SLIC3R_CAD` block therefore compil option still reads ON. **Fix.** Always mount the live `CMakeLists.txt` and `cmake/` — never inherit them from the image. -This is why `scripts/docker-iter-build.sh`, `scripts/kernel-test.sh` and `scripts/rig-build.sh` +This is why `scripts/CAD/build-gui-incremental.sh`, `scripts/CAD/run-kernel-tests.sh` and `scripts/CAD/build-gui.sh` all mount both. --- @@ -109,18 +109,18 @@ all mount both. `ninja ` writes `/OrcaSlicer/build/src/Release/`; only `build_linux.sh` additionally packages to `/OrcaSlicer/build/package/bin/`. `orca_cad`'s -`scripts/gui-session.sh` defaults `BIN` to `src/Release/orca-slicer`, but snaporca's defaults to +`scripts/CAD/start-headless-gui.sh` defaults `BIN` to `src/Release/orca-slicer`, but snaporca's defaults to `package/bin/snapmaker-orca`. So after a target-only rebuild on snaporca, launching -`gui-session.sh` with its default runs the **stale packaged** binary — the change under test is +`start-headless-gui.sh` with its default runs the **stale packaged** binary — the change under test is invisible and the session hunts a phantom. Pass `BIN` explicitly: - docker exec -e BIN=/OrcaSlicer/build/src/Release/snapmaker-orca snaporca-gui /OrcaSlicer/scripts/gui-session.sh + docker exec -e BIN=/OrcaSlicer/build/src/Release/snapmaker-orca snaporca-gui /OrcaSlicer/scripts/CAD/start-headless-gui.sh -`scripts/rig-build.sh` prints the correct line for the current fork when it finishes. +`scripts/CAD/build-gui.sh` prints the correct line for the current fork when it finishes. Note also that the GUI containers do **not** mount `scripts/`: `/OrcaSlicer/scripts` inside them -is the baked copy, so a local edit to `gui-session.sh` has no effect until you -`docker cp scripts/gui-session.sh :/OrcaSlicer/scripts/`. +is the baked copy, so a local edit to `start-headless-gui.sh` has no effect until you +`docker cp scripts/CAD/start-headless-gui.sh :/OrcaSlicer/scripts/`. --- @@ -144,7 +144,7 @@ a real fault in your code gets past the version banner. Compare ## Trap 7 — a single-instance app plus a path-matched `pkill` -`gui-session.sh` used to kill by `"$BIN"`, while its own `app_pid()` matched by BASENAME. Launch +`start-headless-gui.sh` used to kill by `"$BIN"`, while its own `app_pid()` matched by BASENAME. Launch with a `BIN` that differs from the running instance's path and the old process survives, keeps the single-instance lock, and the new one exits seconds after loading fonts — then `status` reports the *stale* pid as a healthy session. Fixed by killing on the basename; `status` now also diff --git a/docs/ux/mockups/gen_offer_table.py b/docs/ux/mockups/gen_offer_table.py index e56c626a3e..503bf26007 100644 --- a/docs/ux/mockups/gen_offer_table.py +++ b/docs/ux/mockups/gen_offer_table.py @@ -144,7 +144,7 @@ def main(): text = "\n".join(lines) # --check: prove the checked-in header IS what this generator produces, and change nothing. # The header calls itself GENERATED and was hand-edited anyway; a claim like that is only - # worth having if something enforces it, so ladder-all.sh runs this on every gate. + # worth having if something enforces it, so run-all-checks.sh runs this on every gate. if "--check" in sys.argv: have = open(OUT, encoding="utf-8").read() if os.path.exists(OUT) else "" if have == text: diff --git a/scripts/CAD/README.md b/scripts/CAD/README.md new file mode 100644 index 0000000000..d881b6f1db --- /dev/null +++ b/scripts/CAD/README.md @@ -0,0 +1,53 @@ +# 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. diff --git a/scripts/docker-iter-build.sh b/scripts/CAD/build-gui-incremental.sh similarity index 92% rename from scripts/docker-iter-build.sh rename to scripts/CAD/build-gui-incremental.sh index 9b3d33dca1..1b6d2f2b0b 100755 --- a/scripts/docker-iter-build.sh +++ b/scripts/CAD/build-gui-incremental.sh @@ -9,8 +9,8 @@ # Result: edit -> rebuild in seconds-to-minutes instead of a full Docker rebuild. # # Usage (run on the build host, e.g. behemoth, from anywhere): -# scripts/docker-iter-build.sh -# IMAGE=orcacad-deps scripts/docker-iter-build.sh +# scripts/CAD/build-gui-incremental.sh +# IMAGE=orcacad-deps scripts/CAD/build-gui-incremental.sh # # On success the binary is inside the persistent volume at # /OrcaSlicer/build/package/bin/orca-slicer (copy it out with a follow-up @@ -18,8 +18,8 @@ # Rig build traps already paid for once each (stale project, NLopt cache, pybind11, OCCT_LIBS, SLIC3R_CAD gate): docs/rig_build_traps.md set -euo pipefail -REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -# orcacad-deps, NOT snaporca-deps: see the note in kernel-test.sh — the wrong image +REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# orcacad-deps, NOT snaporca-deps: see the note in run-kernel-tests.sh — the wrong image # fails at CMake configure, not at link time. IMAGE="${IMAGE:-orcacad-deps}" BUILD_VOL="${BUILD_VOL:-orcacad_buildcache}" @@ -42,10 +42,10 @@ echo "REPO=$REPO IMAGE=$IMAGE BUILD_VOL=$BUILD_VOL" # ---- OOM guard (2026-08-21) ------------------------------------------------------------- # Two of these builds ran at once on 2026-08-21, each with ninja -j$(nproc)=16: ~36 cc1plus # holding 42 GB of a 62 GB box -> global OOM at 21:05, a 2h28m kill storm, ssh unreachable, -# lightdm destroyed. Neither build produced a single object. scripts/rig-build.sh grew the +# lightdm destroyed. Neither build produced a single object. scripts/CAD/build-gui.sh grew the # bounds first; every script that starts a compile needs the same three, or the guard is only # as strong as the script you happened not to use. -# flock — the lock path is SHARED with rig-build.sh and the other fork on purpose, so +# flock — the lock path is SHARED with build-gui.sh and the other fork on purpose, so # concurrent builds serialise instead of summing. # -j — bounded parallelism; ~1.17 GB per cc1plus was the measured average. # --memory — the actual guarantee: a runaway build dies in its own cgroup instead of taking diff --git a/scripts/rig-build.sh b/scripts/CAD/build-gui.sh similarity index 91% rename from scripts/rig-build.sh rename to scripts/CAD/build-gui.sh index 72e9fc3ace..1858ef5dc7 100755 --- a/scripts/rig-build.sh +++ b/scripts/CAD/build-gui.sh @@ -9,11 +9,11 @@ # Read that file before debugging a configure or link failure this script reports. # # Usage: -# scripts/rig-build.sh # configure + build the fork's GUI target -# DRY_RUN=1 scripts/rig-build.sh # print the resolved fork identity and exit, no container +# scripts/CAD/build-gui.sh # configure + build the fork's GUI target +# DRY_RUN=1 scripts/CAD/build-gui.sh # print the resolved fork identity and exit, no container set -euo pipefail -REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" # Fork identity is DERIVED from the repo, never hardcoded, so this file is byte-identical in # both forks and cannot be mirrored into the wrong one. Pointing a fork at the other fork's @@ -53,7 +53,7 @@ LOCK=/tmp/orca-rig-build.lock exec 9>"$LOCK" if ! flock -n 9; then - echo "another fork's rig-build holds $LOCK — waiting (this is the OOM guard, not a hang)" + echo "another fork's build-gui holds $LOCK — waiting (this is the OOM guard, not a hang)" flock 9 fi @@ -90,9 +90,9 @@ docker run --rm \ exit \$rc " || rc=$? -# A target-only build writes src/Release/, but this fork's gui-session.sh may default BIN to the +# A target-only build writes src/Release/, but this fork's start-headless-gui.sh may default BIN to the # PACKAGED path that only build_linux.sh refreshes — launching with the default would then run a # stale binary. Pass BIN explicitly. See docs/rig_build_traps.md. echo "=== launch the rig on the binary just built ===" -echo " docker exec -e BIN=/OrcaSlicer/build/src/Release/$BIN ${PREFIX}-gui /OrcaSlicer/scripts/gui-session.sh" +echo " docker exec -e BIN=/OrcaSlicer/build/src/Release/$BIN ${PREFIX}-gui /OrcaSlicer/scripts/CAD/start-headless-gui.sh" exit "$rc" diff --git a/scripts/offer-ladder.py b/scripts/CAD/check-gui-context-menu.py similarity index 99% rename from scripts/offer-ladder.py rename to scripts/CAD/check-gui-context-menu.py index 7a6738521f..cb16bd6fb6 100644 --- a/scripts/offer-ladder.py +++ b/scripts/CAD/check-gui-context-menu.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """The OFFER ladder: prove that right-click is the pivot, and that it adapts to what was clicked. -The gesture ladder (scripts/gui-ladder.py) proved the TARGET — a complex closed profile, precise +The gesture ladder (scripts/CAD/check-gui-sketching.py) proved the TARGET — a complex closed profile, precise in vertices, lengths, arcs and symmetry, with its voids correctly attributed. It proved it by arming every tool with a letter key. That leaves the goal's own MECHANISM untested: the design logic pivots on right-click, and the verbs offered are supposed to adapt to the element under the @@ -20,7 +20,7 @@ This ladder drives the menu. Nothing here is asserted from pixels: Run inside the rig container, with the app launched under SNAPORCA_KEYTRACE=1: - docker exec snaporca-gui python3 /OrcaSlicer/scripts/offer-ladder.py [rung ...] + docker exec snaporca-gui python3 /OrcaSlicer/scripts/CAD/check-gui-context-menu.py [rung ...] """ import importlib.util import math @@ -34,7 +34,7 @@ HERE = os.path.dirname(os.path.abspath(__file__)) # The gesture ladder owns the hand and the eye: the homography per sketch, the window lookup by # class, the synthetic click, the typed value, the socket. Importing it is the only way those # stay one implementation — a second copy would drift the first time a rig detail moved. -_spec = importlib.util.spec_from_file_location("gui_ladder", os.path.join(HERE, "gui-ladder.py")) +_spec = importlib.util.spec_from_file_location("gui_ladder", os.path.join(HERE, "check-gui-sketching.py")) G = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(G) @@ -617,7 +617,7 @@ def clicked(X, Y): def fresh_sketch(tool): """Enter a sketch from a KNOWN empty state, whatever the previous rung or run left behind. - gui-ladder's enter_sketch dismisses the old session with keys, and a key is exactly what an + check-gui-sketching's enter_sketch dismisses the old session with keys, and a key is exactly what an open value field swallows — so a session that should have been cancelled survives, the four calibration probes land in it on top of whatever was already there, and the run dies with "calibration expected 4 points, got 7". Cancelling through the socket cannot be swallowed: @@ -1196,7 +1196,7 @@ RUNGS = {"kinds": rung_kinds, "vocabulary": rung_vocabulary, def main(): if not os.path.exists(LOG): - G.die(f"no {LOG} — launch the app through scripts/gui-session.sh") + G.die(f"no {LOG} — launch the app through scripts/CAD/start-headless-gui.sh") if "[OFFER]" not in open(LOG, errors="replace").read()[-400000:]: print(f"note: no [OFFER] lines in {LOG} yet — the app must run with SNAPORCA_KEYTRACE=1") want = sys.argv[1:] or list(RUNGS) diff --git a/scripts/gui-ladder.py b/scripts/CAD/check-gui-sketching.py similarity index 99% rename from scripts/gui-ladder.py rename to scripts/CAD/check-gui-sketching.py index 1e6547f8f9..dcb49c06e5 100644 --- a/scripts/gui-ladder.py +++ b/scripts/CAD/check-gui-sketching.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """A ladder of sketches drawn the way a person draws them: mouse gestures and typed values. -WHY THIS EXISTS, next to scripts/sketch-ladder.py. That ladder proves the ENGINE — it feeds +WHY THIS EXISTS, next to scripts/CAD/check-sketch-engine.py. That ladder proves the ENGINE — it feeds geometry through the MCP socket's add_entities_scripted and grades what comes back. The socket path skips everything the goal actually rests on: gesture state, the auto-edit queue, snapping, inference at gesture tolerance, and the right-click offer. A ladder that only drives the socket @@ -11,8 +11,8 @@ here ONLY as an instrument, never as an author. Runs INSIDE the headless rig container (Xvfb :10 + openbox + the app with SNAPORCA_MCP set): - docker cp scripts/gui-ladder.py snaporca-gui:/tmp/ && \ - docker exec snaporca-gui python3 /tmp/gui-ladder.py [rung ...] + docker cp scripts/CAD/check-gui-sketching.py snaporca-gui:/tmp/ && \ + docker exec snaporca-gui python3 /tmp/check-gui-sketching.py [rung ...] With no arguments every rung runs. Exit 0 = every property held. """ diff --git a/scripts/mcp-sketch-smoke.py b/scripts/CAD/check-mcp-sketch.py similarity index 98% rename from scripts/mcp-sketch-smoke.py rename to scripts/CAD/check-mcp-sketch.py index c68cf90780..b0d7ea70e3 100755 --- a/scripts/mcp-sketch-smoke.py +++ b/scripts/CAD/check-mcp-sketch.py @@ -9,7 +9,7 @@ loop: build a known profile, ask the app what it thinks it has, compare against RUN IT AGAINST A RUNNING APP: SNAPORCA_MCP=/tmp/mcp.sock # launch with the socket enabled - python3 scripts/mcp-sketch-smoke.py [socket] # default /tmp/mcp.sock + python3 scripts/CAD/check-mcp-sketch.py [socket] # default /tmp/mcp.sock Exit 0 = every assertion held. Anything else prints the first mismatch and stops. """ diff --git a/scripts/ladder-corpus.py b/scripts/CAD/check-sketch-engine-corpus.py similarity index 99% rename from scripts/ladder-corpus.py rename to scripts/CAD/check-sketch-engine-corpus.py index e39b77103e..d9237ca2d0 100644 --- a/scripts/ladder-corpus.py +++ b/scripts/CAD/check-sketch-engine-corpus.py @@ -20,7 +20,7 @@ agree, and that the engine's own operations preserve what they promise. MIRROR a real closed profile, mirrored, is still exactly one closed loop OFFSET a real closed profile, offset, is still closed -Usage: ladder-corpus.py [--sample N] [--corpus DIR] +Usage: check-sketch-engine-corpus.py [--sample N] [--corpus DIR] """ import argparse diff --git a/scripts/sketch-ladder.py b/scripts/CAD/check-sketch-engine.py similarity index 99% rename from scripts/sketch-ladder.py rename to scripts/CAD/check-sketch-engine.py index e901829f78..2a2ec9d7c9 100755 --- a/scripts/sketch-ladder.py +++ b/scripts/CAD/check-sketch-engine.py @@ -16,7 +16,7 @@ Every rung asserts those. Area appears only as a cross-check, never as the verdi Entirely 2D: sketch entities only, no extrude, revolve or any solid feature. SNAPORCA_MCP=/tmp/mcp.sock - python3 scripts/sketch-ladder.py [socket] + python3 scripts/CAD/check-sketch-engine.py [socket] Exit 0 = every rung held. Otherwise the first broken property is named and the run stops. """ diff --git a/scripts/ladder-all.sh b/scripts/CAD/run-all-checks.sh similarity index 72% rename from scripts/ladder-all.sh rename to scripts/CAD/run-all-checks.sh index 40a50bc0b9..1cb56b8a3c 100755 --- a/scripts/ladder-all.sh +++ b/scripts/CAD/run-all-checks.sh @@ -6,12 +6,12 @@ # run this, read the last line, and do not push a red one. The kernel suite is the only part CI # can carry, and it already does. # -# scripts/ladder-all.sh # kernel + engine + corpus (every 20th) + gestures + offer -# FULL=1 scripts/ladder-all.sh # corpus over ALL 997 sheets (~25 min) -# SKIP_GUI=1 scripts/ladder-all.sh # kernel only, for a machine with no rig +# scripts/CAD/run-all-checks.sh # kernel + engine + corpus (every 20th) + gestures + offer +# FULL=1 scripts/CAD/run-all-checks.sh # corpus over ALL 997 sheets (~25 min) +# SKIP_GUI=1 scripts/CAD/run-all-checks.sh # kernel only, for a machine with no rig # # The rig container is expected to be up with the app running and SNAPORCA_MCP set; bring it up -# with scripts/gui-session.sh inside it. The corpus lives at /corpus in that container. +# with scripts/CAD/start-headless-gui.sh inside it. The corpus lives at /corpus in that container. set -uo pipefail cd "$(dirname "$0")/.." || exit 1 @@ -43,17 +43,17 @@ run_in_rig() { # copy the script in fresh, then run it ther # 92-row array, so the last verb was unreachable (snaporca-z8rs, snaporca-ziam). step "offer table matches the atlas" python3 docs/ux/mockups/gen_offer_table.py --check -step "kernel suite" scripts/kernel-test.sh --vol "${KVOL:-snaporca_kerneltest}" +step "kernel suite" scripts/CAD/run-kernel-tests.sh --vol "${KVOL:-snaporca_kerneltest}" if [ -z "${SKIP_GUI:-}" ]; then step "engine ladder (rungs 1-8, scripted geometry)" \ - run_in_rig scripts/sketch-ladder.py /tmp/sketch-ladder.py + run_in_rig scripts/CAD/check-sketch-engine.py /tmp/check-sketch-engine.py step "corpus rung (real drawings, every ${STEP}th)" \ - run_in_rig scripts/ladder-corpus.py /tmp/ladder-corpus.py --corpus "$CORPUS" --step "$STEP" + run_in_rig scripts/CAD/check-sketch-engine-corpus.py /tmp/check-sketch-engine-corpus.py --corpus "$CORPUS" --step "$STEP" step "corpus scale rung (the heaviest sheets)" \ - run_in_rig scripts/ladder-corpus.py /tmp/ladder-corpus.py --corpus "$CORPUS" --scale + run_in_rig scripts/CAD/check-sketch-engine-corpus.py /tmp/check-sketch-engine-corpus.py --corpus "$CORPUS" --scale step "gesture ladder (mouse and keyboard)" \ - run_in_rig scripts/gui-ladder.py /tmp/gui-ladder.py + run_in_rig scripts/CAD/check-gui-sketching.py /tmp/check-gui-sketching.py # The offer ladder needs TWO extra things the others do not: the app must have been launched # with SNAPORCA_KEYTRACE=1 (its [OFFER] lines are the whole instrument), and it reads the # generated offer table to predict what each selection should show — which is not in the @@ -61,7 +61,7 @@ if [ -z "${SKIP_GUI:-}" ]; then # run_in_rig puts the script, is one of the paths the ladder looks in. docker cp src/slic3r/GUI/CAD/DesignOffer.hpp "$C:/tmp/DesignOffer.hpp" >/dev/null step "offer ladder (right-click, the menu, the verbs behind it)" \ - run_in_rig scripts/offer-ladder.py /tmp/offer-ladder.py + run_in_rig scripts/CAD/check-gui-context-menu.py /tmp/check-gui-context-menu.py fi echo diff --git a/scripts/kernel-test.sh b/scripts/CAD/run-kernel-tests.sh similarity index 91% rename from scripts/kernel-test.sh rename to scripts/CAD/run-kernel-tests.sh index 19a4bcb6f2..f8c8b18153 100755 --- a/scripts/kernel-test.sh +++ b/scripts/CAD/run-kernel-tests.sh @@ -7,10 +7,10 @@ # CadDocument, recompute()s it and asserts on geometry. # # Usage: -# scripts/kernel-test.sh # [CadDocument] tags, default volume -# scripts/kernel-test.sh --tags '[CadDocument],[Sketch]' -# scripts/kernel-test.sh --vol wt_mirror # private build cache (parallel workers) -# scripts/kernel-test.sh --host tommaso@100.103.234.2 # build on a remote host +# scripts/CAD/run-kernel-tests.sh # [CadDocument] tags, default volume +# scripts/CAD/run-kernel-tests.sh --tags '[CadDocument],[Sketch]' +# scripts/CAD/run-kernel-tests.sh --vol wt_mirror # private build cache (parallel workers) +# scripts/CAD/run-kernel-tests.sh --host tommaso@100.103.234.2 # build on a remote host # # Parallel workers MUST pass a distinct --vol: two builds sharing one cache corrupt # each other. A new volume pays one full build; runs after that are incremental. @@ -22,14 +22,14 @@ # Rig build traps already paid for once each (stale project, NLopt cache, pybind11, OCCT_LIBS, SLIC3R_CAD gate): docs/rig_build_traps.md set -euo pipefail -REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" # orcacad-deps, NOT snaporca-deps: this fork is mainline-based and needs Eigen 5.0.1, # CGAL 5.6.3, wx 3.3.2 and Python 3.12 Development.Embed, none of which snaporca-deps has. # With the wrong image CMake dies at configure, which is exactly why this fork went # M1-M8 without ever compiling (see commit 1633005bba). IMAGE="${IMAGE:-orcacad-deps}" # Must NOT default to snaporca_buildcache: that is the other fork's volume, and pointing -# this fork at it makes the two silently trade build artefacts. docker-iter-build.sh had the +# this fork at it makes the two silently trade build artefacts. build-gui-incremental.sh had the # identical defect and was fixed to orcacad_buildcache; this script was missed. VOL="${BUILD_VOL:-orcacad_kerneltest}" # No exclusions. Both cases that used to be quarantined now run: the solver SIGABRT on @@ -64,7 +64,7 @@ if [[ -n "$HOST" ]]; then "$REPO/src" "$REPO/tests" "$REPO/resources" "$REPO/cmake" "$REPO/scripts" \ "$REPO/CMakeLists.txt" \ "$HOST:$REMOTE/" - exec ssh "$HOST" "cd $REMOTE && scripts/kernel-test.sh --vol '$VOL' --tags '$TAGS' --image '$IMAGE'" + exec ssh "$HOST" "cd $REMOTE && scripts/CAD/run-kernel-tests.sh --vol '$VOL' --tags '$TAGS' --image '$IMAGE'" fi if ! docker image inspect "$IMAGE" >/dev/null 2>&1; then @@ -84,17 +84,17 @@ if ! docker volume inspect "$VOL" >/dev/null 2>&1; then docker volume create "$VOL" >/dev/null fi -# tests/ is mounted too -- unlike docker-iter-build.sh, this script exists precisely to +# tests/ is mounted too -- unlike build-gui-incremental.sh, this script exists precisely to # compile tests being edited. CMakeLists.txt and cmake/ carry the SLIC3R_CAD gate; taking # them from the baked image instead leaves the gate off and the CAD symbols vanish. # ---- OOM guard (2026-08-21) ------------------------------------------------------------- # Two of these builds ran at once on 2026-08-21, each with ninja -j$(nproc)=16: ~36 cc1plus # holding 42 GB of a 62 GB box -> global OOM at 21:05, a 2h28m kill storm, ssh unreachable, -# lightdm destroyed. Neither build produced a single object. scripts/rig-build.sh grew the +# lightdm destroyed. Neither build produced a single object. scripts/CAD/build-gui.sh grew the # bounds first; every script that starts a compile needs the same three, or the guard is only # as strong as the script you happened not to use. -# flock — the lock path is SHARED with rig-build.sh and the other fork on purpose, so +# flock — the lock path is SHARED with build-gui.sh and the other fork on purpose, so # concurrent builds serialise instead of summing. # -j — bounded parallelism; ~1.17 GB per cc1plus was the measured average. # --memory — the actual guarantee: a runaway build dies in its own cgroup instead of taking diff --git a/scripts/gui-session.sh b/scripts/CAD/start-headless-gui.sh similarity index 96% rename from scripts/gui-session.sh rename to scripts/CAD/start-headless-gui.sh index f784195d4c..b8f4719c2c 100755 --- a/scripts/gui-session.sh +++ b/scripts/CAD/start-headless-gui.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash # Bring the headless GUI up on a VNC-served X display, ready to drive or to attach Remmina to. # -# Runs INSIDE the long-lived GUI container (see the header of scripts/docker-iter-build.sh for how +# Runs INSIDE the long-lived GUI container (see the header of scripts/CAD/build-gui-incremental.sh for how # that container is created). Idempotent: safe to re-run to recover a session whose app died. # -# docker exec /OrcaSlicer/scripts/gui-session.sh # launch + settle -# docker exec /OrcaSlicer/scripts/gui-session.sh --status # report, change nothing +# docker exec /OrcaSlicer/scripts/CAD/start-headless-gui.sh # launch + settle +# docker exec /OrcaSlicer/scripts/CAD/start-headless-gui.sh --status # report, change nothing # # WHY THIS EXISTS. Dismissing the first-run dialogs by computing the titlebar close box from # `xdotool getwindowgeometry --shell` and clicking it went wrong whenever the dialog had already diff --git a/scripts/Dockerfile.deps b/scripts/Dockerfile.deps index 8d87df70de..f0ca4e4735 100644 --- a/scripts/Dockerfile.deps +++ b/scripts/Dockerfile.deps @@ -2,7 +2,7 @@ # Identical system+pinned-dependency setup to scripts/Dockerfile, but STOPS after # `build_linux.sh -dr` (no slicer/AppImage build). Produces an image with the pinned # deps baked at /OrcaSlicer/deps/build/destdir, so the slicer can be rebuilt -# incrementally via scripts/docker-iter-build.sh without re-running the long deps build. +# incrementally via scripts/CAD/build-gui-incremental.sh without re-running the long deps build. # # Build once (rebuild only when deps/ changes, e.g. OCCT module flags): # docker build -t snaporca-deps -f scripts/Dockerfile.deps . @@ -82,7 +82,7 @@ RUN ln -sfn /OrcaSlicer/deps/build/OrcaSlicer_dep /OrcaSlicer/deps/build/destdir # The rig's GUI runtime. This used to arrive for free because orcacad-deps was layered on # snaporca-deps; that lineage is Trap 1 in docs/rig_build_traps.md (a baked project(Snapmaker_Orca) # tree) and building from this Dockerfile is what removes it — along with the X stack the rig -# needs. scripts/gui-session.sh requires Xvfb and openbox (without a window manager `xdotool +# needs. scripts/CAD/start-headless-gui.sh requires Xvfb and openbox (without a window manager `xdotool # windowactivate` aborts with "windowmanager claims not to support..."), drives the UI with # xdotool, and captures to /shots with scrot/ImageMagick. Same set snaporca-deps carries. RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ diff --git a/tests/libslic3r/test_caddocument.cpp b/tests/libslic3r/test_caddocument.cpp index ff861bb2b9..2746ce655e 100644 --- a/tests/libslic3r/test_caddocument.cpp +++ b/tests/libslic3r/test_caddocument.cpp @@ -4005,7 +4005,7 @@ TEST_CASE("golden recipe v1 still deserialises", "[CadDocument]") // A failure BELOW this point means the on-disk serialization format changed: some field // in CadFeature::save/load was reordered, retyped, or removed. Fields may only ever be // APPENDED at the end of both lists. Do NOT regenerate the fixture to make this pass -- - // fix the field order instead. See scripts/kernel-test.sh and the [.regen] case. + // fix the field order instead. See scripts/CAD/run-kernel-tests.sh and the [.regen] case. // Field-by-field assertions against expected values. // Every field set to a distinctive non-default literal must be checked here.