Rig and CI: one kernel, solidcore

- CI: the "Native Linux tests (C++ SMLib)" job, Clippy's run with
  --features smlib and every SMLib fetch step go; the kernel rig and the
  fillet rig build the CLI without the feature, and the ladder gate runs
  without --kernel smlib.
- xtask kernel-cases has no --kernel any more (solidcore|smlib|both, and
  the side by side with the C++ kernel); passed, it is refused as --route
  is. A run keeps results.json and dumps/ in its output folder and writes
  docs/kernel-cases.md, the kernel's report.
- The per-area lists: each area's KNOWN_FAILING.solidcore becomes its
  KNOWN_FAILING, replacing the C++ kernel's list; the workflows, the
  README, the plan's self-test and xtask's help say so.
- tests/KNOWN_FAILING_TESTS.smlib, xtask's SMLIB_LIST and
  scripts/fetch-smlib.sh are deleted; PATHS-ALL drops the script.
- The CLI's kernel-cases names its kernel solidcore.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M41G8Nua7HvuFPZkmJ
This commit is contained in:
jyviko
2026-11-02 18:07:53 -05:00
parent aa87a149f8
commit 7d7203f9ed
52 changed files with 188 additions and 755 deletions
+1 -73
View File
@@ -470,13 +470,6 @@ jobs:
scope=(--workspace)
if [ "$FULL" != true ]; then scope=(); for p in $PACKAGES; do scope+=(-p "$p"); done; fi
cargo clippy "${scope[@]}" --all-targets --profile ci --locked -- -D warnings
# The C++ SMLib kernel is opt-in (`--features smlib`, off by default): lint the code and tests
# behind it too, on the crates that have any. Needs the prebuilt library.
- name: Fetch SMLib (crates/smlib/SMLIB_REV)
shell: bash
run: scripts/fetch-smlib.sh
- name: Clippy with the C++ SMLib kernel
run: cargo clippy -p solidcraft-smlib -p solidcraft-kernel -p solidcraft-cli --features solidcraft-cli/smlib --all-targets --profile ci --locked -- -D warnings
build-tests:
name: Build tests
@@ -635,69 +628,6 @@ jobs:
path: ${{ env.CARGO_TARGET_DIR || 'target' }}/nextest/ci/junit.xml
retention-days: 7
cpp-tests:
name: Native Linux tests (C++ SMLib)
# The tests that compare solidcore with the C++ SMLib kernel (parity tests, the C++ round trips,
# the C++ SSI corpus score, the model cache across kernels) are built only with the opt-in
# `smlib` feature, which every other job leaves off. They live in solidcraft-smlib,
# solidcraft-kernel and the CLI's model_cache; the other tests there run again here on
# solidcore, the default kernel either way, graded against the same list.
needs: changes
if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.native == 'true' }}
runs-on: blacksmith-16vcpu-ubuntu-2404
timeout-minutes: 60
env:
CARGO_INCREMENTAL: "0"
RUSTC_WRAPPER: sccache
SCCACHE_DIR: /home/runner/.cache/sccache
SCCACHE_CACHE_SIZE: 20G
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Size parallel compiles to the job's memory
run: scripts/ci/build-jobs.sh
- uses: dtolnay/rust-toolchain@stable
- name: Mount the compiler cache
uses: useblacksmith/stickydisk@3f6be1451e3cad893b778bc93495c80452a5da26 # v1.7.2
continue-on-error: true
with:
key: ${{ github.repository }}-sccache-cpp-tests
path: /home/runner/.cache/sccache
commit: ${{ github.ref == 'refs/heads/main' && 'on-change' || 'false' }}
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
key: native-cpp-tests
save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' }}
- name: Fetch SMLib (crates/smlib/SMLIB_REV)
shell: bash
run: scripts/fetch-smlib.sh
- name: Set up compiler cache
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
with:
version: v0.16.0
- uses: taiki-e/install-action@1168f6810a3cb30a3514bf5756a3b7f0422c6df8 # v2.87.28
with:
tool: cargo-nextest
- name: Run the tests with the C++ kernel built
env:
EVENT_NAME: ${{ github.event_name }}
run: |
# The pull request filter of Native Linux tests (default() in .config/nextest.toml);
# elsewhere everything but the random boolean property tests, as there.
base='default()'
if [ "$EVENT_NAME" != pull_request ]; then
base='not (package(solidcraft-kernel) & binary(boolean_props))'
fi
junit=${CARGO_TARGET_DIR:-target}/nextest/ci/junit.xml
rm -f "$junit"
status=0
cargo nextest run -p solidcraft-smlib -p solidcraft-kernel -p solidcraft-cli --features solidcraft-cli/smlib \
--cargo-profile ci --locked --profile ci --no-tests=pass --ignore-default-filter -E "($base) & (not package(=solidcraft-cli) | binary(=model_cache))" || status=$?
if [ "$status" -ne 0 ] && [ "$status" -ne 100 ]; then exit "$status"; fi
cargo xtask known-failing --junit "$junit"
- name: Compiler cache statistics
if: always()
run: sccache --show-stats
gpu-path-tests:
name: GPU path tests (${{ matrix.shard }}/4)
# The GPU path tracer's tests (about 108) compile their pipelines on lavapipe, one test at a
@@ -1055,7 +985,7 @@ jobs:
# commit's real run instead: the merge queue reads `ci` from the newest run of a commit, so a
# run without a passing `ci` would block a pull request that passed (#1850, #3182, #3252).
name: ci
needs: [changes, checks, quick-compile, clippy, build-tests, tests, cpp-tests, gpu-path-tests, doc-tests, oracle, windows-fxc, windows-startup, dependency-advisories, wasm]
needs: [changes, checks, quick-compile, clippy, build-tests, tests, gpu-path-tests, doc-tests, oracle, windows-fxc, windows-startup, dependency-advisories, wasm]
if: always() && (github.event_name != 'pull_request' || !github.event.pull_request.draft)
runs-on: blacksmith-2vcpu-ubuntu-2404
permissions:
@@ -1103,7 +1033,6 @@ jobs:
BUILD: ${{ needs.build-tests.result }}
EVENT_NAME: ${{ github.event_name }}
TESTS: ${{ needs.tests.result }}
CPP_TESTS: ${{ needs.cpp-tests.result }}
GPU_RUN: ${{ needs.changes.outputs.gpu }}
GPU: ${{ needs.gpu-path-tests.result }}
DOCS: ${{ needs.doc-tests.result }}
@@ -1128,7 +1057,6 @@ jobs:
test "$BUILD" = success
fi
test "$TESTS" = success
test "$CPP_TESTS" = success
fi
# The same output decides whether the GPU path tests run (their job's `if`).
if [ "$GPU_RUN" = true ]; then
+4 -6
View File
@@ -1,7 +1,7 @@
# The fillet rig as a regression gate: a pull request that touches fillet code (the paths below)
# runs every case in tests/kernel-cases/fillets/ on solidcore, through one release build of
# runs every case in tests/kernel-cases/fillets/ through one release build of
# solidcraft-cli, and fails on a regression (a case that fails and
# tests/kernel-cases/fillets/KNOWN_FAILING.solidcore does not list) or on a listed case that now passes
# tests/kernel-cases/fillets/KNOWN_FAILING does not list) or on a listed case that now passes
# (it is fixed: remove its line, so the list only shrinks). See tests/kernel-cases/README.md.
#
# GitHub filters a workflow by whole files, so the fillet parts of crates/doc/src/eval*.rs and
@@ -25,7 +25,6 @@ on:
# The rig itself: the grading, the runner and this workflow.
- "apps/solidcraft-cli/src/kernel_cases.rs"
- "xtask/src/kernel_cases.rs"
- "scripts/fetch-smlib.sh"
- ".github/workflows/fillet-rig.yml"
push:
branches: [main, develop]
@@ -42,7 +41,6 @@ on:
# The rig itself: the grading, the runner and this workflow.
- "apps/solidcraft-cli/src/kernel_cases.rs"
- "xtask/src/kernel_cases.rs"
- "scripts/fetch-smlib.sh"
- ".github/workflows/fillet-rig.yml"
workflow_dispatch:
@@ -90,13 +88,13 @@ jobs:
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
with:
version: v0.16.0
- name: Build the CLI (release, solidcore alone)
- name: Build the CLI (release)
run: cargo build --release --locked -p solidcraft-cli
- name: Run the fillet cases against the known-failing list
run: >-
cargo run -q --locked -p xtask -- kernel-cases --area fillets
--cli target/release/solidcraft-cli --out "$RUNNER_TEMP/fillet-rig"
--known-failing tests/kernel-cases/fillets/KNOWN_FAILING.solidcore
--known-failing tests/kernel-cases/fillets/KNOWN_FAILING
- name: Keep the results
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
+7 -14
View File
@@ -2,13 +2,13 @@
# changed files to the rig areas they can affect (scripts/ci/kernel_rig_plan.py): an area runs
# when a file its tests/kernel-cases/<area>/PATHS lists changes, or one of its cases; every area
# runs when the shared core in tests/kernel-cases/PATHS-ALL changes; the ladder runs whenever any
# area does. One job then builds solidcraft-cli once (release, SMLib prebuilt), checks that every
# area does. One job then builds solidcraft-cli once (release), checks that every
# registry command has a case or an exemption (tests/kernel-cases/EXEMPT), and hands the CLI to a
# matrix of shards as an artifact, one per selected area plus the ladder, in parallel, so the
# wall time is the build plus the slowest shard. See tests/kernel-cases/README.md.
#
# - An area, on solidcore, fails on a regression (a case that fails and its
# tests/kernel-cases/<area>/KNOWN_FAILING.solidcore does not list) or on a listed case that passes (it is fixed: remove its line in the same pull
# - An area fails on a regression (a case that fails and its tests/kernel-cases/<area>/KNOWN_FAILING
# does not list) or on a listed case that passes (it is fixed: remove its line in the same pull
# request, so the list only shrinks).
# - The ladder fails on any case whose status or counts differ from
# tests/kernel-cases/ladder/golden.json; a right change is re-recorded (`--record "why"`).
@@ -38,7 +38,6 @@ on:
- "apps/solidcraft-cli/src/kernel_cases.rs"
- "xtask/src/kernel_cases.rs"
- "xtask/src/kernel_ladder.rs"
- "scripts/fetch-smlib.sh"
- "scripts/ci/kernel_rig_plan.py"
- "scripts/ci/test_kernel_rig_plan.py"
- ".github/workflows/kernel-rig.yml"
@@ -58,7 +57,6 @@ on:
- "apps/solidcraft-cli/src/kernel_cases.rs"
- "xtask/src/kernel_cases.rs"
- "xtask/src/kernel_ladder.rs"
- "scripts/fetch-smlib.sh"
- "scripts/ci/kernel_rig_plan.py"
- "scripts/ci/test_kernel_rig_plan.py"
- ".github/workflows/kernel-rig.yml"
@@ -141,16 +139,13 @@ jobs:
with:
key: kernel-rig
save-if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop') }}
- name: Fetch SMLib (crates/smlib/SMLIB_REV)
shell: bash
run: scripts/fetch-smlib.sh
- name: Set up compiler cache
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
with:
version: v0.16.0
- name: Build the CLI (release, SMLib) and the rig's runner
- name: Build the CLI (release) and the rig's runner
run: |
cargo build --release --locked -p solidcraft-cli --features smlib
cargo build --release --locked -p solidcraft-cli
cargo build --locked -p xtask
# A tar keeps the executable bits, which an artifact drops. xtask finds the repository from
# the path it was built in (CARGO_MANIFEST_DIR), which is the same checkout path in every
@@ -199,11 +194,9 @@ jobs:
SHARD: ${{ matrix.shard }}
run: |
if [ "$SHARD" = ladder ]; then
# The golden is the C++ kernel's: solidcore differs on one case (shell under mitred
# rounds), so this shard stays on it until a solidcore golden is justified.
set -- --ladder --gate --kernel smlib
set -- --ladder --gate
else
set -- --area "$SHARD" --known-failing "tests/kernel-cases/$SHARD/KNOWN_FAILING.solidcore"
set -- --area "$SHARD" --known-failing "tests/kernel-cases/$SHARD/KNOWN_FAILING"
fi
target/debug/xtask kernel-cases "$@" --cli target/release/solidcraft-cli --out "$RUNNER_TEMP/kernel-rig"
- name: Keep the results
+2 -2
View File
@@ -9,9 +9,9 @@ use serde_json::{Value, json};
use crate::oracle::{ABS_FRAC, Checks, REL_TOL, totals, v3};
use crate::{read_json, recipe};
/// The kernel the cases run on: SMLib, the only one.
/// The kernel the cases run on: solidcore, the only one.
fn kernel() -> String {
"smlib".into()
"solidcore".into()
}
/// How many cases a chain of `base` recipes may go through (a ladder case builds on the one
-1
View File
@@ -118,7 +118,6 @@ class Real(unittest.TestCase):
for area, globs in {"PATHS-ALL": shared, **areas}.items():
if area != "PATHS-ALL":
self.assertTrue(os.path.isfile(os.path.join(ROOT, plan.CASES, area, "KNOWN_FAILING")), area)
self.assertTrue(os.path.isfile(os.path.join(ROOT, plan.CASES, area, "KNOWN_FAILING.solidcore")), area)
for g in globs:
with self.subTest(area=area, glob=g):
rx = plan.glob_regex(g)
-95
View File
@@ -1,95 +0,0 @@
#!/usr/bin/env bash
# Fetches SMLib for solidcraft-smlib (feature `native`), at the commit in crates/smlib/SMLIB_REV.
#
# scripts/fetch-smlib.sh [TARGET...] the prebuilt C API library for each Rust target (default:
# the host's), checked against crates/smlib/SMLIB_PREBUILT,
# into target/smlib-<rev12>-prebuilt/<target>; the sources
# for a target with no prebuilt library
# scripts/fetch-smlib.sh --source the sources (source/SMLib, source/SM_API, capi), into
# target/smlib-<rev12> or SOLIDCRAFT_SMLIB_DIR, to compile
# scripts/fetch-smlib.sh --pin writes SMLIB_PREBUILT from the release of SMLIB_REV
#
# The libraries are the release prebuilt-<rev> of tangency-labs/smlib (its prebuilt.yml).
# OpenCASCADE is not part of the fork.
set -euo pipefail
root="$(cd "$(dirname "$0")/.." && pwd)"
rev="$(tr -d '[:space:]' < "$root/crates/smlib/SMLIB_REV")"
pins="$root/crates/smlib/SMLIB_PREBUILT"
release="https://github.com/tangency-labs/smlib/releases/download/prebuilt-$rev"
sha256() {
if command -v sha256sum >/dev/null; then sha256sum "$1" | cut -d' ' -f1; else shasum -a 256 "$1" | cut -d' ' -f1; fi
}
fetch_source() {
local dest="${SOLIDCRAFT_SMLIB_DIR:-$root/target/smlib-${rev:0:12}}"
if [ -f "$dest/capi/include/smlib.h" ] && [ "$(git -C "$dest" rev-parse HEAD 2>/dev/null)" = "$rev" ]; then
echo "SMLib sources $rev already at $dest"
return
fi
rm -rf "$dest"
mkdir -p "$dest"
git -C "$dest" init -q
git -C "$dest" remote add origin https://github.com/tangency-labs/smlib.git
git -C "$dest" sparse-checkout set --no-cone /source/SMLib/ /source/SM_API/ /capi/ /LICENSE
git -C "$dest" fetch -q --depth 1 --filter=blob:none origin "$rev"
git -C "$dest" checkout -q FETCH_HEAD
echo "SMLib sources $rev at $dest"
}
fetch_prebuilt() {
local target="$1" want dest tmp
want="$(awk -v t="$target" '$1 == t { print $2 }' "$pins")"
if [ -z "$want" ]; then
echo "no prebuilt SMLib for $target: fetching the sources to compile"
fetch_source
return
fi
dest="$root/target/smlib-${rev:0:12}-prebuilt/$target"
if [ "$(cat "$dest/.sha256" 2>/dev/null)" = "$want" ]; then
echo "SMLib $rev for $target already at $dest"
return
fi
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' RETURN
curl -fsSL --retry 3 -o "$tmp/smlib.tar.gz" "$release/smlib-$target.tar.gz"
if [ "$(sha256 "$tmp/smlib.tar.gz")" != "$want" ]; then
echo "smlib-$target.tar.gz does not match its SHA-256 in crates/smlib/SMLIB_PREBUILT" >&2
exit 1
fi
tar -xzf "$tmp/smlib.tar.gz" -C "$tmp"
if [ "$(tr -d '[:space:]' < "$tmp/smlib-$target/REV")" != "$rev" ]; then
echo "smlib-$target.tar.gz was built from another commit than SMLIB_REV" >&2
exit 1
fi
rm -rf "$dest"
mkdir -p "$(dirname "$dest")"
mv "$tmp/smlib-$target" "$dest"
echo "$want" > "$dest/.sha256"
echo "SMLib $rev for $target at $dest"
}
case "${1:-}" in
--source)
fetch_source
;;
--pin)
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
curl -fsSL --retry 3 -o "$tmp/SHA256SUMS" "$release/SHA256SUMS"
{
echo "# Rust target, SHA-256 of smlib-<target>.tar.gz in the release prebuilt-<SMLIB_REV> of"
echo "# tangency-labs/smlib. Written by scripts/fetch-smlib.sh --pin; never edited by hand."
sed -E 's/^([0-9a-f]{64}) +smlib-(.*)\.tar\.gz$/\2 \1/' "$tmp/SHA256SUMS" | sort
} > "$pins"
echo "pinned $(grep -vc '^#' "$pins") prebuilt targets of $rev"
;;
*)
if [ $# -eq 0 ]; then
set -- "$(rustc -vV | sed -n 's/^host: //p')"
fi
for target in "$@"; do
fetch_prebuilt "$target"
done
;;
esac
+5 -3
View File
@@ -1,10 +1,12 @@
# The cargo tests that fail today on the default kernel, solidcore, one a line: `<test> <why it fails
# The cargo tests that fail today on the kernel, solidcore, one a line: `<test> <why it fails
# today>`, with the issue that tracks it when there is one. Sorted. `<test>` is nextest's
# `<binary id>::<test name>`, as the junit report names it. CI's test jobs (`cargo xtask known-failing`)
# fail on a test that fails and is not listed here, and on a listed test that passes: a fix removes its
# line in the same pull request. The tests stay un-ignored, so every run shows whether they still fail.
# `KNOWN_FAILING_TESTS.smlib` is the same list for the C++ kernel (SOLIDCRAFT_KERNEL=smlib, graded with
# --list). Refresh as that list's header says.
# Refresh: download the junit artifacts of develop's latest CI run, one directory each
# (`gh run download <run> -R tangency-labs/solidcraft -n <artifact> -D <dir>/<artifact>` for junit
# and junit-gpu-1..4), run `cargo xtask known-failing --junit <dir>`, then drop each FIXED line and
# add each REGRESSION line with its cause, from the test's failure message.
solidcraft-cli::action_matrix::action_matrix_sample 3 baseline actions fail, the same 3 as on C++: 2 shells (Bad Loop Orient on issue-616-lid-ribs; status 1001 on filleted-shelled-box), 1 fillet (SmSurfOfRevolution Test #7 on oblique_cut_of_cylinder)
solidcraft-cli::model_cache::a_later_round_after_opening_blends_the_saved_rounds_again the later r3 round at the r2 mitre builds solidcore's 10-face corner (7928.743041), the test wants SMLib f916a8d's setback corner (smlib#104), which solidcore ports in solidcore#2310: 15 faces, 7928.142563938
solidcraft-cli::naming_corpus::corpus_designs_name_alike_every_build_and_fail_where_a_reference_is_gone oracle/83-boundary-loop-thicken does not load: step 8, thicken status 1001, as on C++
-43
View File
@@ -1,43 +0,0 @@
# The cargo tests that fail today on the C++ kernel (SOLIDCRAFT_KERNEL=smlib), one a line: `<test> <why it fails today>`, with the issue that
# tracks it when there is one. Sorted. `<test>` is nextest's `<binary id>::<test name>`, as the
# junit report names it. CI's test jobs (`cargo xtask known-failing`) fail on a test that fails
# and is not listed here, and on a listed test that passes: a fix removes its line in the same
# pull request. The tests stay un-ignored, so every run shows whether they still fail.
# Refresh (after an SMLib pin bump): download the junit artifacts of develop's latest CI run, one
# directory each (`gh run download <run> -R tangency-labs/solidcraft -n <artifact> -D <dir>/<artifact>`
# for junit and junit-gpu-1..4), run `cargo xtask known-failing --junit <dir>`, then drop each
# FIXED line and add each REGRESSION line with its cause, from the test's failure message.
# Baseline: develop 38fd4a4f6 (CI run 41157648345, x86_64 Linux), after the SMLib eaa998a pin; SMLib lines as of f916a8d (smlib 5862ee223).
solidcraft-cli::action_matrix::action_matrix_sample 2 baseline actions fail on SMLib: 2 shells (Bad Loop Orient on issue-616-lid-ribs; status 1001 on filleted-shelled-box, shelled again open at an inner wall)
solidcraft-cli::naming_corpus::corpus_designs_name_alike_every_build_and_fail_where_a_reference_is_gone oracle/83-boundary-loop-thicken does not load: step 8, SMLib thicken status 1001
solidcraft-doc::eval::chain_tests::a_propagated_chain_that_cannot_build_says_how_to_blend_the_edge_alone the propagated chain now builds a round (9 faces), so there is no refusal to read, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-doc::eval::cost_tests::a_cut_leaves_bodies_it_cannot_reach_as_they_were main's mesh-based version (#10303) not taken; the exact replacement is to come
solidcraft-doc::eval::cost_tests::a_tap_marking_searches_only_the_bodies_near_it main's mesh-based version (#10303) not taken; the exact replacement is to come
solidcraft-doc::eval::cost_tests::a_tap_marking_still_searches_the_bodies_within_its_reach main's mesh-based version (#10303) not taken; the exact replacement is to come
solidcraft-engine::cmd::file::tests::each_format_has_an_export_command_of_its_own SMLib meshes a box's planar faces into 124 triangles, not 12 (the STL is 6284 bytes, the test counts 84 + 50 x 12)
solidcraft-engine::cmd::sketch_project::tests::intersection_curve_of_picked_faces_spans_the_whole_surface main's mesh-based version (#9107) not taken; the exact replacement is to come
solidcraft-engine::extent_tests::cut_to_the_far_side_of_a_curved_wall main's mesh-based version (#8634) not taken; the exact replacement is to come
solidcraft-engine::hole_face_tests::a_hole_wider_than_the_part_says_it_removes_all_of_it a 40 mm hole at (10, 10) touches the plate's edge y = 30 at one point; SMLib parts the plate there into 2 bodies, the test wants truck's 1
solidcraft-engine::measure_centre_tests::a_fillet_round_a_boss_reports_its_radius SMLib's round at the foot of a boss is not an analytic torus of minor radius 3, so no face of the body is (the test finds none to measure)
solidcraft-engine::tests::fillet_fit_taper_closes_to_a_point SMLib fillet status 1001 on the taper fit (radius 16 closing to 0)
solidcraft-engine::tests::mirror_placed::dragging_a_mirrored_part_meshes_its_copies_once on SMLib a copy of a copy drawn from its first copy's triangles (#10101) is triangulated differently from a fresh evaluation; the surface is the same. Dealt with in solidcore, where the mesher moves (docs/layers.md)
solidcraft-engine::tests::robustness::fillet_into_an_earlier_round R2 into the earlier round: volume 35923.387 against 35919.524, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-engine::tests::shell_tangent_chain_that_opens_every_face_explains_how_to_keep_walls SMLib shell status 1034 on a box with all 12 edges rounded (Ball corners since 5e8c9c1), opened at one face (tangency-labs/smlib#102)
solidcraft-kernel::blend::corner_tests::a_round_ending_in_an_earlier_round_matches_both_together SMLib fillet status 1001 on the round that ends in the earlier one
solidcraft-kernel::blend::corner_tests::corner_blends_hold_at_any_scale at 0.01x a picked edge runs on tangentially into an unblended edge and SMLib's result is not a closed solid (the smooth-vertex End, tangency-labs/smlib#81)
solidcraft-kernel::blend_corner::tests::a_round_next_to_a_round_of_another_radius the face count is 9, not the expected count, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::blend_corner::tests::issue2422_vertical_after_separate_bottom_rounds SMLib's check refuses the fillet: edge and vertex tolerance 0.97 against the body's 0.01 (#2422)
solidcraft-kernel::blend_smlib::tests::smooth_edges_and_unfinished_tangent_chains_are_refused_saying_why the smooth edge builds (volume 7957.723) where a refusal is expected, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::corner_g2::tests::a_concave_corner_takes_the_g2_patch_too the concave G2 corner's curvature jump clear of the corners is 5.5e-2, above the bound, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::corner_g2::tests::a_long_setback_keeps_the_g2_patch_inside_the_box at set backs 11 to 15 the G2 corner patch bulges 2.6e-6 to 1.33e-3 past the box (the explicit corner is in progress)
solidcraft-kernel::corner_g2::tests::curvature_rounds_meet_at_a_g2_corner the corner loop's fill misses its neighbours' curvature by 1.6e-3 (tolerance 1e-3), on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::corner_g2::tests::set_back_8_the_g2_corner_lies_between_the_hull_and_the_prisms set back 8: the G2 corner's distance check reads 0.0611, past its bound (volume 47370.642, in range), on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::corner_g2::tests::the_box_corner_g2_patch_is_a_closed_solid_curvature_continuous_to_its_neighbours the fitted G2 corner patch bulges 1.7e-5 past the box, which SMLib's exact tight box now sees (the explicit G2 corner builds it inside)
solidcraft-kernel::issue_851_tests::blend_the_arc_top_edge_and_the_top_front_edge removes 59.148 against 60.122, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::issue_851_tests::fillet_the_arc_top_edge_and_the_front_upright_at_the_arc removes 31.497 against 32.310, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::issue_851_tests::fillet_the_top_front_edge_and_the_front_left_upright removes 42.236 against 43.187, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::issue_851_tests::fillet_the_top_front_edge_and_the_front_upright_at_the_arc removes 41.341 against 42.146, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::smooth_edges::tests::a_seam_split_in_two_edges_is_drawn_whole the side seam is one edge ([24]), not split in two, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::tests::fillet_tabbed_plate_outer_loop_and_partial_selection_after_hole the partial selection runs on tangentially into an unblended edge and SMLib's result is not a closed solid (the smooth-vertex End, tangency-labs/smlib#81)
solidcraft-smlib::ops::tests::a_setback_corner_left_open_returns_its_hole the open corner returns holes of 9, 27 and 19 edges, not its one hole; SMLib's open_holes counts a seam edge its own face uses twice as free (fixed for v1.1.0-alpha.1)
solidcraft-smlib::ops::tests::fillet_takes_exactly_the_picked_edges one round on the picked edge gives 9 faces, not the expected count, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
+3 -5
View File
@@ -2,15 +2,13 @@
# (scripts/ci/kernel_rig_plan.py). One git pathspec glob a line, relative to the repository root:
# `*` stays within a folder, `**` crosses folders. Each area's own sources are in <area>/PATHS.
#
# SMLib: the bindings, the schema 4 record bridge and the pinned revision (SMLIB_REV,
# SMLIB_PREBUILT), and the script that fetches it.
# The kernel: solidcore's wrapper and the schema 4 record bridge.
crates/smlib/**
scripts/fetch-smlib.sh
# The geometry every body is made of: B-rep record, curves, surfaces, meshes.
crates/geom/**
# The kernel's core, which every case goes through: bodies, extrude/revolve/primitives, booleans
# and placements, the planar prisms, the SMLib sweeps and booleans, history and provenance, the
# native bridge to SMLib, tessellation, and what the grader measures (measure, validity, counts).
# and placements, the planar prisms, the sweeps and booleans, history and provenance, the
# native bridge to the kernel, tessellation, and what the grader measures (measure, validity, counts).
crates/kernel/Cargo.toml
crates/kernel/src/body.rs
crates/kernel/src/boolean_record.rs
+16 -34
View File
@@ -2,35 +2,23 @@
Every geometry case the old kernel (truck) got wrong, recorded in an issue, a pull request or a
crash report, is a use case here with its own right answer. The kernel, solidcore, is held to all
of them, as is the C++ SMLib kernel it was ported from when asked for. `cargo xtask kernel-cases`
runs them on solidcore; `--kernel smlib` runs them on C++ and writes
of them. `cargo xtask kernel-cases` runs them and writes
[`docs/kernel-cases.md`](../../docs/kernel-cases.md).
```sh
cargo xtask kernel-cases # every case, on solidcore
cargo xtask kernel-cases # every case
cargo xtask kernel-cases --cli target/release/solidcraft-cli --out /tmp/run # with a CLI already built
cargo xtask kernel-cases --kernel both --cli target/release/solidcraft-cli # SMLib and solidcore side by side
cargo run -p solidcraft-cli -- kernel-cases tests/kernel-cases/booleans/<id> # one case
```
The CLI builds with solidcore alone by default. The C++ SMLib kernel is opt-in at build time:
`--features smlib` links it (`scripts/fetch-smlib.sh` fetches the prebuilt library first), and
`--kernel smlib` or `both` without `--cli` builds the CLI that way. On a build without it, asking
for SMLib answers that this build doesn't include it. The run's output folder (`--out`, default `target/kernel-cases`)
The run's output folder (`--out`, default `target/kernel-cases`)
gets `results.json`, every case's full result, and `dumps/<area>-<case>/`: the inputs of each
SMLib call a case failed in, for replay (the CLI's `--dumps=DIR`, which the rig always passes).
`--validation MODE` runs the cases' features under that mode of SMLib's check
kernel call a case failed in, for replay (the CLI's `--dumps=DIR`, which the rig always passes).
`--validation MODE` runs the cases' features under that mode of the kernel's check
(`diagnostics.validation`): `each_feature` (the default: the bodies each feature keeps are checked
once), `each_step` (after every sweep, boolean and blend, as before) or `off`; the
`KNOWN_FAILING` lists are each_feature's.
`--kernel solidcore|smlib|both` (default `solidcore`) picks the backend each case's process runs on,
through `SOLIDCRAFT_KERNEL`. A `solidcore` run keeps its `results.json`, `dumps/` and `report.md`
in `<out>/solidcore/` and leaves `docs/kernel-cases.md`, which is the `smlib` run's, alone. `both` runs every case on each
backend, keeps `docs/kernel-cases.md` as the SMLib report and writes the two side by side to
[`docs/kernel-cases-backends.md`](../../docs/kernel-cases-backends.md) (cases that differ first)
and `<out>/backends.json`.
## Rules
- **The answer never comes from a kernel.** Not from truck's output, nor any commercial
@@ -138,21 +126,19 @@ the frozen truck-geometry PRs, a `kernel-paused` PR), for the report's coverage
Every area is a regression suite: each case is one small case of one issue, with its exact
answer. `.github/workflows/kernel-rig.yml` runs them, and the ladder, on pull requests (not
drafts). A plan job (`scripts/ci/kernel_rig_plan.py`) picks the areas from the changed files, one
job builds `solidcraft-cli` (release, `--features smlib`, for the ladder's `--kernel smlib`) and the rig's runner, and a matrix of shards, one per
job builds `solidcraft-cli` (release) and the rig's runner, and a matrix of shards, one per
selected area plus the ladder, runs them in parallel; the `kernel-rig` check passes when every
selected shard does (and when none was selected). Pushes to main and develop, merge groups, the
release gate (`release-gate.yml`) and a run by hand run every area. Each area's shard runs:
```sh
cargo xtask kernel-cases --area <area> --cli target/release/solidcraft-cli \
--known-failing tests/kernel-cases/<area>/KNOWN_FAILING.solidcore
--known-failing tests/kernel-cases/<area>/KNOWN_FAILING
```
The gate grades the kernel the run is on, so a list is one kernel's: `<area>/KNOWN_FAILING.solidcore`
for the default, `<area>/KNOWN_FAILING` with `--kernel smlib` (`--kernel both` is refused). Each lists
the cases of that area that fail today on it, sorted, one a line with its
`<area>/KNOWN_FAILING` lists the cases of that area that fail today, sorted, one a line with its
cause (`<case> <why it fails today>`; `#` starts a comment; the header names the baseline: the
develop commit and SMLib revision it was taken from). The gate fails on a **regression**, a
solidcore pin it was taken from). The gate fails on a **regression**, a
case that fails (or crashes, hangs, or is not supported yet) and is not listed, and on a
**fixed** case, one listed that passes. With `--known-failing` the run writes no report;
`docs/kernel-cases.md` stays the full run's.
@@ -160,7 +146,7 @@ case that fails (or crashes, hangs, or is not supported yet) and is not listed,
**Updating a list.** The pull request that changes an outcome changes the list in the same pull
request, so the list only shrinks and never goes stale:
- a fix (yours, or an SMLib pin bump): remove the line of each case the shard reports as
- a fix (yours, or a solidcore pin bump): remove the line of each case the shard reports as
`FIXED`;
- a new case that fails today: add its line, sorted, with the cause from its result
(`results.json` in the shard's `kernel-rig-results-<area>` artifact, or a local run);
@@ -175,9 +161,9 @@ target/release/solidcraft-cli --known-failing tests/kernel-cases/<area>/KNOWN_FA
(`*` within a folder, `**` across folders; `#` starts a comment): the engine command modules,
doc evaluation and kernel files its commands go through. Only the area's own files: never a
file `PATHS-ALL` covers, nor a whole crate (the self-test fails on either).
- `PATHS-ALL`: the shared core, whose change reruns every area: SMLib (`crates/smlib/**`, its pin
included) and `scripts/fetch-smlib.sh`, `crates/geom/**`, the kernel's core (bodies, extrude and
revolve, booleans, the SMLib bridge, tessellation, what the grader measures), timeline
- `PATHS-ALL`: the shared core, whose change reruns every area: the kernel's wrapper
(`crates/smlib/**`), `crates/geom/**`, the kernel's core (bodies, extrude and
revolve, booleans, the kernel bridge, tessellation, what the grader measures), timeline
evaluation, the solid feature commands, the grader, the runner and the workflow.
- A change under `<area>/` (a case, its `KNOWN_FAILING`, its `PATHS`) reruns that area.
- The ladder spans every operation: it runs whenever any area does, and on a change under
@@ -222,15 +208,11 @@ running part grows one tier at a time through `base`), so the last case carries
`method` gives the derivation).
```sh
cargo xtask kernel-cases --ladder --kernel smlib --cli target/release/solidcraft-cli
cargo xtask kernel-cases --ladder --kernel smlib --cli target/release/solidcraft-cli --gate
cargo xtask kernel-cases --ladder --kernel smlib --cli target/release/solidcraft-cli --record "why"
cargo xtask kernel-cases --ladder --cli target/release/solidcraft-cli
cargo xtask kernel-cases --ladder --cli target/release/solidcraft-cli --gate
cargo xtask kernel-cases --ladder --cli target/release/solidcraft-cli --record "why"
```
The golden is the C++ kernel's, so these say `--kernel smlib`. Without it a run is on solidcore and is
graded against the same golden; today that differs on one case,
`ladder/09-shells-and-offsets/010-shell-under-rounded-top`.
The ladder needs no known-failing list: the golden is the reference. Its shard in the kernel rig
gate runs with `--gate`, which fails on any case whose status or counts differ from the golden,
better or worse, and on a case with no golden; times are not compared there (they are the
+3 -4
View File
@@ -1,4 +1,3 @@
# The assemblies cases that fail today, one a line: `<case> <why it fails today>`. Sorted. A gate
# fails on a case that fails and is not listed here, and on a listed case that passes: a fix
# removes its line in the same pull request.
# Baseline: rig-cases-assemblies 45f69c0e5 with SMLib 60b1c6a, aarch64 Linux. None fail today.
# The assemblies cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The assemblies cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+3 -4
View File
@@ -1,4 +1,3 @@
# The booleans cases that fail today, one a line: `<case> <why it fails today>`. Sorted. The kernel
# rig gate (.github/workflows/kernel-rig.yml) fails on a case that fails and is not listed here,
# and on a listed case that passes: a fix removes its line in the same pull request.
# Baseline: develop 5ada4fc8a with SMLib 90aabff (the run on 60b1c6a, aarch64 Linux).
# The booleans cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The booleans cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,4 +1,3 @@
# The construction cases that fail today, one a line: `<case> <why it fails today>`. Sorted. A run
# with --known-failing fails on a case that fails and is not listed here, and on a listed case
# that passes: a fix removes its line in the same pull request.
# Baseline: rig-cases-construction-inspect 45f69c0e5 with SMLib 60b1c6a, aarch64 Linux.
# The construction cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The construction cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+3 -4
View File
@@ -1,4 +1,3 @@
# The continuity cases that fail today, one a line: `<case> <why it fails today>`. Sorted. The kernel
# rig gate (.github/workflows/kernel-rig.yml) fails on a case that fails and is not listed here,
# and on a listed case that passes: a fix removes its line in the same pull request.
# Baseline: not seeded yet; seeded from a develop run after the SMLib pin bump.
# The continuity cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The continuity cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+3 -4
View File
@@ -1,4 +1,3 @@
# The crashes cases that fail today, one a line: `<case> <why it fails today>`. Sorted. The kernel
# rig gate (.github/workflows/kernel-rig.yml) fails on a case that fails and is not listed here,
# and on a listed case that passes: a fix removes its line in the same pull request.
# Baseline: not seeded yet; seeded from a develop run after the SMLib pin bump.
# The crashes cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The crashes cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+37 -39
View File
@@ -1,39 +1,37 @@
# The fillet cases that fail today, one a line: `<case> <why it fails today>`. Sorted. The fillet
# rig gate (.github/workflows/fillet-rig.yml) fails on a case that fails and is not listed here,
# and on a listed case that passes: a fix removes its line in the same pull request.
# Baseline: develop 242bbc89f with the SMLib fixes of 2026-10-29 (integration-overnight + b78bd4a), aarch64 Linux.
1080-fillet-equal-slope-basin-1-mm-rim-loop-4 builds to the analytic volume (rel 5e-9), but the continuity check (g1 at every blend seam) takes in the mitre's creases, G0 by the mitre ruling: the case's continuity seams need the owner's word
1080-fillet-notched-block-top-outline-r8 a blend seam grades G0 where g1 is wanted, and the volume is 10320.299 against 10198.718, on SMLib v1.1.0-alpha (smlib #124, the End at a smooth vertex); passed on f916a8d. Whether the End's G0 there is by design or a defect is being established
1080-fillet-sloped-basin-1-mm-rim-r4-2-edges builds to the analytic volume (rel 6e-9), but the continuity check (g1 at every blend seam) takes in the mitre's creases, G0 by the mitre ruling: the case's continuity seams need the owner's word
1080-fillet-sloped-basin-1-mm-rim-r4-4-edges builds to the analytic volume (rel 3e-9), but the continuity check (g1 at every blend seam) takes in the mitre's creases, G0 by the mitre ruling: the case's continuity seams need the owner's word
1207-fillet-box-end-edge-into-unblended-round-partial-chain a blend seam grades G0 (1 of 5 seams) where g1 is wanted, at the end of the round's contact seam, on SMLib v1.1.0-alpha (smlib #124, the End at a smooth vertex); passed on f916a8d. Whether the End's G0 there is by design or a defect is being established
2893-chamfer-distance-and-angle-past-the-wall-refused refused for another reason: SMLib SM_ERR_INVALID_INPUT, not a check saying the angle runs past the wall
2893-chamfer-two-distances-elliptical-rim SMLib status 1001: the two arcs of the rim take their chamfer offsets each at its own midpoint, where the faces' angle differs (78.5 and 101.5 deg), and their chamfers do not meet at the tangent corners (held for the owner's ruling on unequal chamfers of a varying angle)
3369-fillet-edge-ends-on-tangent-seam two blend seams grade G0 (2 of 4) where g1 is wanted, at the end of the round's contact seam, on SMLib v1.1.0-alpha (smlib #124, the End at a smooth vertex); passed on f916a8d. Whether the End's G0 there is by design or a defect is being established
4782-fillet-bar-edge-wider-than-both-faces SMLib status 1001: a convex round past both its faces is not yet built by subtraction
5158-fillet-adjacent-plate-edges-as-thick-as-plate a blend seam grades G0 where g1 is wanted, and the volume is 1682.854 against 1681.904, on SMLib v1.1.0-alpha (smlib #124, the End at a smooth vertex); passed on f916a8d. Whether the End's G0 there is by design or a defect is being established
5158-fillet-round-just-past-a-10mm-face SMLib status 1001: the round passes 5e-6 under the box's top back edge, inside the body's tolerance (1e-5), and subtracting its removal region maps that edge to two of the region's faces (SmTopologyIntersector); 10.0001-10.04 open
851-fillet-arc-then-top-front SMLib status 1001: the top front edge's tangent chain (the edge, the arc round's end curve on the front face, the upright under it) rounded R2; along the end curve the R2 ball sits on the arc round's own centre circle, so that piece is the ball about (39.2538, -19, 8) touching front, top and wall (a torus of tube-centre radius 0), the three-edge rolling-ball corner; the same piece on a plane end arc builds (851-fillet-top-front-then-front-left-upright)
851-fillet-top-front-then-upright SMLib status 1001: the upright's tangent chain (the upright, the first round's end curve on the wall, the arc's top edge) rounded R2; along the end curve the R2 ball sits on the first round's axis, so that piece is the ball about (39.2538, -19, 8) touching front, top and wall (a torus of tube-centre radius 0), the three-edge rolling-ball corner; the upright alone builds, the upright with the end curve fails the same; the same piece on a plane end arc builds (851-fillet-top-front-then-front-left-upright)
9-fillet-corner-curvature-with-reduce-fit not supported yet: solid.fillet builds corner g2 with the exact fit only
9-fillet-corner-curvature-with-taper-fit not supported yet: solid.fillet builds corner g2 with the exact fit only
cov-fillet-g2-corner-beside-a-cylinder not supported yet: the curvature fillet builds its sections only between planar faces ("a picked edge is not on the face beside it" on the cylinder's arc)
cov-fillet-g2-five-edge-apex-corner refused: the default setback is shorter than where the rounds' contact lines meet (3.5056 mm from the apex); the corner should take a setback that works
cov-fillet-g2-four-edge-apex-corner refused: the default setback is shorter than where the rounds' contact lines meet (3.9027 mm from the apex); the corner should take a setback that works
cov-fillet-g2-mixed-corner not supported yet: SMLib sets back a corner only where its edges are all convex or all concave
cov-fillet-g2-oblique-three-edge-corner the G2 corner patch meets the new order-2 section's rounds only G1 at one face seam (its volume holds); the corner step rebuilds the patch
cov-fillet-g2-pocket-corner the G2 corner patch meets the new order-2 section's rounds only G1 at one face seam (its volume holds); the corner step rebuilds the patch
cov-fillet-turn-swept-boss-base-r1 not supported yet: solid.fillet has no `turn`; the corners are mitred (12508.9676, the Mitre case's volume)
cov-fillet-turn-swept-pocket-sharp-corner-refused-r1 not supported yet: solid.fillet has no `turn`, so the sharp concave corners are mitred, not refused
cov-junction-boss-tilt-20-root-round SMLib fillet status 1001 on a cylinder tilted 20 degrees into the plate (also before the blend rework)
cov-junction-tee-equal-round equal pipes' intersection is two plane ellipses crossing: their exact conic-pair rounds meet at the crossings in a corner the old corner code cannot join (built by the traced rounds before smlib#77); the corner step
cov-junction-y-junction-120-round refused: the faces between the three intersection curves narrow to nothing at the two triple points, so the room check trips; a three-edge concave corner (the corner step)
every-block-cylinder-tangent-concave-arc-r2-partial-chain a blend seam grades G0 where g1 is wanted, at the end of the round's contact seam, on SMLib v1.1.0-alpha (smlib #124, the End at a smooth vertex); passed on f916a8d. Whether the End's G0 there is by design or a defect is being established
every-box-corner-three-edges-r3-curvature-setback-3-5 not supported on SMLib v1.1.0-alpha (smlib #125: setbacks only at the Setback's corners, the old setback paths deleted); passed on f916a8d. Whether this is a refusal that should name a size or a corner the Setback should build is being established
every-fillet-after-fillet-curvature-front-then-side-r3-partial-chain a blend seam grades G0 where g2 is wanted, at the end of the round's contact seam, on SMLib v1.1.0-alpha (smlib #124, the End at a smooth vertex); passed on f916a8d. Whether the End's G0 there is by design or a defect is being established
report-drafted-peg-front-and-concave-rounds-together-r2 not supported yet: SMLib refuses the corner where the drafted front top edge runs tangent into the concave arc (on the cone) as of no kind its blend corners take
report-fillet-curvature-three-edges-at-bar-corner the G2 corner patch meets the new order-2 section's rounds only G1 at one face seam (its volume holds); the corner step rebuilds the patch
report-fillet-curvature-three-edges-at-bar-corner-solver-residues the G2 corner patch meets the new order-2 section's rounds only G1 at one face seam (its volume holds); the corner step rebuilds the patch
report-fillet-curvature-three-edges-at-bar-corner-solver-residues-outside-setback not supported on SMLib v1.1.0-alpha (smlib #125: setbacks only at the Setback's corners, the old setback paths deleted); passed on f916a8d. Whether this is a refusal that should name a size or a corner the Setback should build is being established
report-fillet-g2-corner-of-bar-running-into-cylinder not supported on SMLib v1.1.0-alpha (smlib #125: setbacks only at the Setback's corners, the old setback paths deleted); passed on f916a8d. Whether this is a refusal that should name a size or a corner the Setback should build is being established
report-fillet-g2-corner-of-bar-running-into-cylinder-outside-setback not supported on SMLib v1.1.0-alpha (smlib #125: setbacks only at the Setback's corners, the old setback paths deleted); passed on f916a8d. Whether this is a refusal that should name a size or a corner the Setback should build is being established
# The fillets cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
1080-fillet-equal-slope-basin-1-mm-rim-loop-4 [fail] continuity_order: got {'body': 'Slab', 'edges': 'blend', 'order': 'g0', want >= g1 at every blend seam
1080-fillet-sloped-basin-1-mm-rim-r4-2-edges [fail] continuity_order: got {'body': 'Slab', 'edges': 'blend', 'order': 'g0', want >= g1 at every blend seam
1080-fillet-sloped-basin-1-mm-rim-r4-4-edges [fail] continuity_order: got {'body': 'Slab', 'edges': 'blend', 'order': 'g0', want >= g1 at every blend seam
1207-fillet-bar-top-edge-after-boss-arc-round-r0-5 [fail] step 4 (solid.fillet): body `Arm`: the operation failed: SMLib fillet: SMLib's check refuses the result: 5 failed tests: SmBSplineCurve::Test #15 Bad Repeated CPts: BSplineCurve has Internal Coincident ControlPoints (causes
2893-chamfer-distance-and-angle-past-the-wall-refused [fail] refused, but not because "angle": step 2 (solid.chamfer): SMLib chamfer: operation: SMLib rejected the input (SM_ERR_INVALID_INPUT)
2893-chamfer-two-distances-elliptical-rim [fail] refused, but not because "not supported yet": step 3 (solid.chamfer): SMLib chamfer: operation: SMLib failed (status 1001) (tangent propagation blended the picked edges' tangent chain with them; with it off, tangent_chain:
4782-fillet-bar-edge-wider-than-both-faces [fail] continuity_order: got Box: no null seams want >= g1 at every blend seam
5158-fillet-round-just-past-a-10mm-face [fail] step 2 (solid.fillet): SMLib fillet: operation: SMLib failed (status 1001)
851-fillet-arc-then-top-front [fail] fillet status 1001, as on SMLib 5e8c9c1: with tangent_chain true since 21f00a917 the top front edge's chain takes the arc round's end curve, where the R2 ball sits on that round's centre circle (a torus of tube-centre radius 0, the three-edge rolling-ball corner)
851-fillet-top-front-then-upright [fail] fillet status 1001, as on SMLib 5e8c9c1: with tangent_chain true since 21f00a917 the upright's chain takes the first round's end curve, where the R2 ball sits on that round's axis (a torus of tube-centre radius 0, the three-edge rolling-ball corner)
9-fillet-corner-curvature-with-reduce-fit [unsupported] solid.fillet builds `corner: g2` with `fit: exact` only
9-fillet-corner-curvature-with-taper-fit [unsupported] solid.fillet builds `corner: g2` with `fit: exact` only
cov-fillet-g2-corner-beside-a-cylinder [fail] step 6 (solid.fillet): the open setback corner is not a closed solid, as on SMLib d01d7b0
cov-fillet-g2-five-edge-apex-corner [fail] step 12 (solid.fillet): invalid input: the setback must be more than 3.5056 mm at the corner (-0.000, 0.000, 30.000): the rounds' contact lines meet 3
cov-fillet-g2-four-edge-apex-corner [fail] step 11 (solid.fillet): invalid input: the setback must be more than 3.9027 mm at the corner (0.000, 0.000, 30.000): the rounds' contact lines meet 3.
cov-fillet-g2-mixed-corner [unsupported] refused as on SMLib d01d7b0: a G2 corner is set back only where every edge meeting it is rounded and all are convex or all concave
cov-fillet-g2-oblique-three-edge-corner [unsupported] refused on solidcore: its three edges meet at different wedge angles, and one curvature fillet takes the first edge's equal-area thumbweight for every edge (solidcore#2250, issuecomment-6563419897); SMLib d01d7b0 fails it too
cov-fillet-g2-pocket-corner [fail] continuity_order: G1 at one seam where the corner patch meets a contact face (g2 wanted), as on SMLib d01d7b0
cov-fillet-section-curvature-pipe-on-plate-r2 [fail] solidcore builds the order-2 section as SMLib d01d7b0 did (40302.5908, G2 on both seams); the case now grades SMLib 5e8c9c1's section, the round as its definition, G3 on the pipe and 40307.8856 (fork 4a10ed8 and 79db628, to be ported in solidcore#2273)
cov-fillet-turn-swept-boss-base-r1 [fail] as on SMLib: solid.fillet has no `turn`; the corners are mitred (12508.9675, the Mitre case's volume)
cov-fillet-turn-swept-pocket-sharp-corner-refused-r1 [fail] as on SMLib: solid.fillet has no `turn`, so the sharp concave corners are mitred, not refused
cov-junction-boss-tilt-20-root-round [fail] fillet status 1001 on a cylinder tilted 20 degrees into the plate, as on SMLib
cov-junction-boss-tilt-40-root-round [fail] fillet status 1001 on a cylinder tilted 40 degrees into the plate, as on SMLib
cov-junction-tee-equal-round [fail] the result is not a closed solid, as on SMLib: equal pipes' intersection is two plane ellipses crossing, a corner the old corner code cannot join (the corner step)
cov-junction-y-junction-120-round [unsupported] refused as on SMLib: the faces between the three intersection curves narrow to nothing at the two triple points, so the room check trips (the corner step)
report-drafted-peg-front-and-concave-rounds-together-r2 [unsupported] step 13 (solid.fillet): invalid input: not supported yet: the fillet meets a corner of this kind, which SMLib's blends do not handle yet (where its ed
report-fillet-concave-arc-and-front-top-edge-together-r5-solver-residues [fail] bbox.min: got [0.4892940775280783, 0.05636444090890084, 0.0] want [0.4892940775280783, 0.05792545052986289, 0.0]
report-fillet-concave-arc-and-front-top-edge-together-r7-solver-residues [fail] bbox.min: got [0.4892940775169876, 0.02441657049978923, 0.0] want [0.4892940775280783, 0.05792545052986289, 0.0]
report-fillet-curvature-three-edges-at-bar-corner [fail] continuity_order: G1 at one seam where the corner patch meets a contact face (g2 wanted), as on SMLib d01d7b0
report-fillet-curvature-three-edges-at-bar-corner-solver-residues [fail] continuity_order: G1 at one seam where the corner patch meets a contact face (g2 wanted), as on SMLib d01d7b0
report-peg-front-and-concave-chamfers-together-d2 [fail] step 13 (solid.chamfer): SMLib chamfer: operation: SMLib failed (status 1001)
report-peg-front-and-concave-rounds-together-r2 [fail] continuity_order: got {'body': 'Peg', 'edges': 'blend', 'order': 'g0', ' want >= g1 at every blend seam
report-peg-front-and-concave-rounds-together-r5 [fail] continuity_order: got {'body': 'Peg', 'edges': 'blend', 'order': 'g0', ' want >= g1 at every blend seam
report-peg-step-front-and-concave-rounds-together-r2 [fail] continuity_order: got {'body': 'Peg', 'edges': 'blend', 'order': 'g0', ' want >= g1 at every blend seam
@@ -1,37 +0,0 @@
# The fillets cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
1080-fillet-equal-slope-basin-1-mm-rim-loop-4 [fail] continuity_order: got {'body': 'Slab', 'edges': 'blend', 'order': 'g0', want >= g1 at every blend seam
1080-fillet-sloped-basin-1-mm-rim-r4-2-edges [fail] continuity_order: got {'body': 'Slab', 'edges': 'blend', 'order': 'g0', want >= g1 at every blend seam
1080-fillet-sloped-basin-1-mm-rim-r4-4-edges [fail] continuity_order: got {'body': 'Slab', 'edges': 'blend', 'order': 'g0', want >= g1 at every blend seam
1207-fillet-bar-top-edge-after-boss-arc-round-r0-5 [fail] step 4 (solid.fillet): body `Arm`: the operation failed: SMLib fillet: SMLib's check refuses the result: 5 failed tests: SmBSplineCurve::Test #15 Bad Repeated CPts: BSplineCurve has Internal Coincident ControlPoints (causes
2893-chamfer-distance-and-angle-past-the-wall-refused [fail] refused, but not because "angle": step 2 (solid.chamfer): SMLib chamfer: operation: SMLib rejected the input (SM_ERR_INVALID_INPUT)
2893-chamfer-two-distances-elliptical-rim [fail] refused, but not because "not supported yet": step 3 (solid.chamfer): SMLib chamfer: operation: SMLib failed (status 1001) (tangent propagation blended the picked edges' tangent chain with them; with it off, tangent_chain:
4782-fillet-bar-edge-wider-than-both-faces [fail] continuity_order: got Box: no null seams want >= g1 at every blend seam
5158-fillet-round-just-past-a-10mm-face [fail] step 2 (solid.fillet): SMLib fillet: operation: SMLib failed (status 1001)
851-fillet-arc-then-top-front [fail] fillet status 1001, as on SMLib 5e8c9c1 (see KNOWN_FAILING): with tangent_chain true since 21f00a917 the top front edge's chain takes the arc round's end curve, where the R2 ball sits on that round's centre circle (a torus of tube-centre radius 0, the three-edge rolling-ball corner)
851-fillet-top-front-then-upright [fail] fillet status 1001, as on SMLib 5e8c9c1 (see KNOWN_FAILING): with tangent_chain true since 21f00a917 the upright's chain takes the first round's end curve, where the R2 ball sits on that round's axis (a torus of tube-centre radius 0, the three-edge rolling-ball corner)
9-fillet-corner-curvature-with-reduce-fit [unsupported] solid.fillet builds `corner: g2` with `fit: exact` only
9-fillet-corner-curvature-with-taper-fit [unsupported] solid.fillet builds `corner: g2` with `fit: exact` only
cov-fillet-g2-corner-beside-a-cylinder [fail] step 6 (solid.fillet): the open setback corner is not a closed solid, as on SMLib d01d7b0
cov-fillet-g2-five-edge-apex-corner [fail] step 12 (solid.fillet): invalid input: the setback must be more than 3.5056 mm at the corner (-0.000, 0.000, 30.000): the rounds' contact lines meet 3
cov-fillet-g2-four-edge-apex-corner [fail] step 11 (solid.fillet): invalid input: the setback must be more than 3.9027 mm at the corner (0.000, 0.000, 30.000): the rounds' contact lines meet 3.
cov-fillet-g2-mixed-corner [unsupported] refused as on SMLib d01d7b0: a G2 corner is set back only where every edge meeting it is rounded and all are convex or all concave
cov-fillet-g2-oblique-three-edge-corner [unsupported] refused on solidcore: its three edges meet at different wedge angles, and one curvature fillet takes the first edge's equal-area thumbweight for every edge (solidcore#2250, issuecomment-6563419897); SMLib d01d7b0 fails it too (see KNOWN_FAILING)
cov-fillet-g2-pocket-corner [fail] continuity_order: G1 at one seam where the corner patch meets a contact face (g2 wanted), as on SMLib d01d7b0 (see KNOWN_FAILING)
cov-fillet-section-curvature-pipe-on-plate-r2 [fail] solidcore builds the order-2 section as SMLib d01d7b0 did (40302.5908, G2 on both seams); the case now grades SMLib 5e8c9c1's section, the round as its definition, G3 on the pipe and 40307.8856 (fork 4a10ed8 and 79db628, to be ported in solidcore#2273)
cov-fillet-turn-swept-boss-base-r1 [fail] as on SMLib: solid.fillet has no `turn`; the corners are mitred (12508.9675, the Mitre case's volume)
cov-fillet-turn-swept-pocket-sharp-corner-refused-r1 [fail] as on SMLib: solid.fillet has no `turn`, so the sharp concave corners are mitred, not refused
cov-junction-boss-tilt-20-root-round [fail] fillet status 1001 on a cylinder tilted 20 degrees into the plate, as on SMLib
cov-junction-boss-tilt-40-root-round [fail] fillet status 1001 on a cylinder tilted 40 degrees into the plate, as on SMLib
cov-junction-tee-equal-round [fail] the result is not a closed solid, as on SMLib: equal pipes' intersection is two plane ellipses crossing, a corner the old corner code cannot join (the corner step)
cov-junction-y-junction-120-round [unsupported] refused as on SMLib: the faces between the three intersection curves narrow to nothing at the two triple points, so the room check trips (the corner step)
report-drafted-peg-front-and-concave-rounds-together-r2 [unsupported] step 13 (solid.fillet): invalid input: not supported yet: the fillet meets a corner of this kind, which SMLib's blends do not handle yet (where its ed
report-fillet-concave-arc-and-front-top-edge-together-r5-solver-residues [fail] bbox.min: got [0.4892940775280783, 0.05636444090890084, 0.0] want [0.4892940775280783, 0.05792545052986289, 0.0]
report-fillet-concave-arc-and-front-top-edge-together-r7-solver-residues [fail] bbox.min: got [0.4892940775169876, 0.02441657049978923, 0.0] want [0.4892940775280783, 0.05792545052986289, 0.0]
report-fillet-curvature-three-edges-at-bar-corner [fail] continuity_order: G1 at one seam where the corner patch meets a contact face (g2 wanted), as on SMLib d01d7b0 (see KNOWN_FAILING)
report-fillet-curvature-three-edges-at-bar-corner-solver-residues [fail] continuity_order: G1 at one seam where the corner patch meets a contact face (g2 wanted), as on SMLib d01d7b0 (see KNOWN_FAILING)
report-peg-front-and-concave-chamfers-together-d2 [fail] step 13 (solid.chamfer): SMLib chamfer: operation: SMLib failed (status 1001)
report-peg-front-and-concave-rounds-together-r2 [fail] continuity_order: got {'body': 'Peg', 'edges': 'blend', 'order': 'g0', ' want >= g1 at every blend seam
report-peg-front-and-concave-rounds-together-r5 [fail] continuity_order: got {'body': 'Peg', 'edges': 'blend', 'order': 'g0', ' want >= g1 at every blend seam
report-peg-step-front-and-concave-rounds-together-r2 [fail] continuity_order: got {'body': 'Peg', 'edges': 'blend', 'order': 'g0', ' want >= g1 at every blend seam
+3 -4
View File
@@ -1,4 +1,3 @@
# The frames cases that fail today, one a line: `<case> <why it fails today>`. Sorted. A run with
# `--known-failing` fails on a case that fails and is not listed here, and on a listed case that
# passes: a fix removes its line in the same pull request.
# Baseline: rig-cases-solids-frames 45f69c0e5 with SMLib 60b1c6a, aarch64 Linux.
# The frames cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The frames cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+3 -4
View File
@@ -1,4 +1,3 @@
# The history cases that fail today, one a line: `<case> <why it fails today>`. Sorted. A gate on
# this area fails on a case that fails and is not listed here, and on a listed case that passes:
# a fix removes its line in the same pull request.
# Baseline: rig-cases-timeline-configurations 45f69c0e5 with SMLib 60b1c6a, aarch64 Linux.
# The history cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The history cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+3 -4
View File
@@ -1,4 +1,3 @@
# The import cases that fail today, one a line: `<case> <why it fails today>`. Sorted. The kernel
# rig gate (.github/workflows/kernel-rig.yml) fails on a case that fails and is not listed here,
# and on a listed case that passes: a fix removes its line in the same pull request.
# Baseline: develop 5ada4fc8a with SMLib 90aabff (the run on 60b1c6a, aarch64 Linux).
# The import cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The import cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+3 -4
View File
@@ -1,4 +1,3 @@
# The inspect cases that fail today, one a line: `<case> <why it fails today>`. Sorted. A run
# with --known-failing fails on a case that fails and is not listed here, and on a listed case
# that passes: a fix removes its line in the same pull request.
# Baseline: rig-cases-construction-inspect 45f69c0e5 with SMLib 60b1c6a, aarch64 Linux.
# The inspect cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The inspect cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+3 -4
View File
@@ -1,4 +1,3 @@
# The plastic cases that fail today, one a line: `<case> <why it fails today>`. Sorted. A gate on
# this area fails on a case that fails and is not listed here, and on a listed case that passes:
# a fix removes its line in the same pull request.
# Baseline: rig-cases-sheet-plastic 45f69c0e5 with SMLib 60b1c6a, aarch64 Linux: every case passes.
# The plastic cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The plastic cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+3 -4
View File
@@ -1,4 +1,3 @@
# The sheet-metal cases that fail today, one a line: `<case> <why it fails today>`. Sorted. The kernel
# rig gate (.github/workflows/kernel-rig.yml) fails on a case that fails and is not listed here,
# and on a listed case that passes: a fix removes its line in the same pull request.
# Baseline: not seeded yet; seeded from a develop run after the SMLib pin bump.
# The sheet-metal cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The sheet-metal cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+4 -5
View File
@@ -1,5 +1,4 @@
# The shell cases that fail today, one a line: `<case> <why it fails today>`. Sorted. The kernel
# rig gate (.github/workflows/kernel-rig.yml) fails on a case that fails and is not listed here,
# and on a listed case that passes: a fix removes its line in the same pull request.
# Baseline: 45f69c0e5 with SMLib 60b1c6a, aarch64 Linux.
cov-shell-again-open-at-an-inner-wall-of-a-shelled-box SMLib status 1001
# The shell cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
cov-shell-again-open-at-an-inner-wall-of-a-shelled-box [fail] step 9 (solid.shell): SMLib shell: operation: SMLib failed (status 1001)
@@ -1,4 +0,0 @@
# The shell cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
cov-shell-again-open-at-an-inner-wall-of-a-shelled-box [fail] step 9 (solid.shell): SMLib shell: operation: SMLib failed (status 1001)
+3 -4
View File
@@ -1,4 +1,3 @@
# The solids cases that fail today, one a line: `<case> <why it fails today>`. Sorted. A run with
# `--known-failing` fails on a case that fails and is not listed here, and on a listed case that
# passes: a fix removes its line in the same pull request.
# Baseline: rig-cases-solids-frames 45f69c0e5 with SMLib 60b1c6a, aarch64 Linux.
# The solids cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The solids cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+3 -5
View File
@@ -1,5 +1,3 @@
# The surfaces cases that fail today, one a line: `<case> <why it fails today>`. Sorted. Run as a
# regression gate (`cargo xtask kernel-cases --area surfaces --known-failing <this file>`), a case
# that fails and is not listed fails it, and so does a listed case that passes: a fix removes its
# line in the same pull request.
# Baseline: rig-cases-surfaces 45f69c0e5 with SMLib 60b1c6a, aarch64 Linux.
# The surfaces cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The surfaces cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+3 -4
View File
@@ -1,4 +1,3 @@
# The sweeps cases that fail today, one a line: `<case> <why it fails today>`. Sorted. The kernel
# rig gate (.github/workflows/kernel-rig.yml) fails on a case that fails and is not listed here,
# and on a listed case that passes: a fix removes its line in the same pull request.
# Baseline: not seeded yet; seeded from a develop run after the SMLib pin bump.
# The sweeps cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The sweeps cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,4 +1,3 @@
# The tessellation cases that fail today, one a line: `<case> <why it fails today>`. Sorted. The kernel
# rig gate (.github/workflows/kernel-rig.yml) fails on a case that fails and is not listed here,
# and on a listed case that passes: a fix removes its line in the same pull request.
# Baseline: not seeded yet; seeded from a develop run after the SMLib pin bump.
# The tessellation cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The tessellation cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+3 -4
View File
@@ -1,4 +1,3 @@
# The threads cases that fail today, one a line: `<case> <why it fails today>`. Sorted. The kernel
# rig gate (.github/workflows/kernel-rig.yml) fails on a case that fails and is not listed here,
# and on a listed case that passes: a fix removes its line in the same pull request.
# Baseline: develop 5ada4fc8a with SMLib 90aabff (the run on 60b1c6a, aarch64 Linux).
# The threads cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
@@ -1,3 +0,0 @@
# The threads cases that fail today on solidcore, one a line: `<case> <why it fails today>`. Sorted.
# The kernel rig gate fails on a case that fails and is not listed, and on a listed case that passes.
# Baseline: solidcore pin de85a3e00, tests/kernel-cases run by `cargo xtask kernel-cases`, x86_64 Linux.
+41 -249
View File
@@ -1,18 +1,12 @@
//! `cargo xtask kernel-cases`: the kernel regression rig. Runs every case in
//! `tests/kernel-cases/<area>/<id>/` through `solidcraft-cli kernel-cases` on solidcore, or the
//! C++ SMLib kernel when asked for, one process per case (so a crash or a hang is that case's result, not the run's), and writes
//! its report: results per case, coverage per area and per source, and the issues and PRs looked
//! at and skipped. Each case is graded against its own answer.
//! `tests/kernel-cases/<area>/<id>/` through `solidcraft-cli kernel-cases`, one process per case
//! (so a crash or a hang is that case's result, not the run's), and writes its report,
//! `docs/kernel-cases.md`: results per case, coverage per area and per source, and the issues and
//! PRs looked at and skipped. Each case is graded against its own answer.
//!
//! The run's output folder (`--out`, default `target/kernel-cases`) holds `results.json`, every
//! case's full result, and `dumps/<area>-<case>/`, the inputs of each SMLib call a case's run
//! case's full result, and `dumps/<area>-<case>/`, the inputs of each kernel call a case's run
//! failed in (`solidcraft-cli kernel-cases --dumps`), for replay.
//!
//! `--kernel solidcore|smlib|both` (default solidcore) picks the backend each case's process runs
//! on (`SOLIDCRAFT_KERNEL`). A solidcore run keeps its results, dumps and report in
//! `<out>/solidcore/`; an smlib run writes `docs/kernel-cases.md`; `both` runs every case on each,
//! keeps `docs/kernel-cases.md` as the SMLib report and writes the side by side to
//! `docs/kernel-cases-backends.md` and `<out>/backends.json`.
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
@@ -26,9 +20,6 @@ use crate::{cargo, root};
const DEFAULT_TIMEOUT_S: u64 = 180;
/// The backends `--kernel` may name, as `SOLIDCRAFT_KERNEL` takes them.
const BACKENDS: [&str; 2] = ["smlib", "solidcore"];
/// How many cases ended in each status.
type StatusCounts = BTreeMap<String, usize>;
@@ -37,10 +28,8 @@ pub(crate) struct Options {
area: Option<String>,
timeout: Duration,
pub(crate) jobs: usize,
/// The run's output folder: `results.json` and the SMLib dumps (`dumps/`).
/// The run's output folder: `results.json` and the kernel's dumps (`dumps/`).
out: PathBuf,
/// The backends each case runs on (`--kernel`, default solidcore alone).
pub(crate) kernels: Vec<&'static str>,
/// `--known-failing FILE`: run as a regression gate against that baseline (see [`gate`]).
known_failing: Option<PathBuf>,
/// `--validation MODE`: when SMLib's full check runs on the cases' features (each_step,
@@ -48,44 +37,24 @@ pub(crate) struct Options {
validation: Option<String>,
}
impl Options {
/// A backend's output folder: the run's own for SMLib, `<out>/<backend>/` for any other.
fn out_of(&self, kernel: &str) -> PathBuf {
match kernel {
"smlib" => self.out.clone(),
other => self.out.join(other),
}
}
}
/// The run's options; `out` is its output folder unless `--out` gives one.
pub(crate) fn options(rest: &[&str], out: &str) -> Result<Options, String> {
let arg = |name: &str| rest.iter().position(|a| *a == name).and_then(|i| rest.get(i + 1)).map(|s| s.to_string());
let secs = arg("--timeout").map(|t| t.parse::<u64>().map_err(|e| format!("--timeout: {e}"))).transpose()?.unwrap_or(DEFAULT_TIMEOUT_S);
let jobs = arg("--jobs").map(|j| j.parse::<usize>().map_err(|e| format!("--jobs: {e}"))).transpose()?.unwrap_or(4).clamp(1, 32);
let out = arg("--out").map_or_else(|| root().join(out), PathBuf::from);
let kernels = match arg("--kernel").as_deref() {
Some("smlib") => vec![BACKENDS[0]],
None | Some("solidcore") => vec![BACKENDS[1]],
Some("both") => BACKENDS.to_vec(),
Some(k) => return Err(format!("--kernel: unknown backend '{k}' (smlib, solidcore or both)")),
};
if rest.contains(&"--route") {
return Err("--route is gone: a run has one kernel, --kernel solidcore, smlib or both".into());
if rest.contains(&"--route") || rest.contains(&"--kernel") {
return Err("--route and --kernel are gone: the cases run on solidcore, the only kernel".into());
}
let known_failing = arg("--known-failing").map(|p| {
let p = PathBuf::from(p);
if p.is_absolute() { p } else { root().join(p) }
});
// A list is one kernel's: the gate grades the run's one kernel against it.
if known_failing.is_some() && kernels.len() != 1 {
return Err("--known-failing: a list is one kernel's, so not with --kernel both".into());
}
let validation = arg("--validation");
if let Some(v) = validation.as_deref().filter(|v| !["each_step", "each_feature", "off"].contains(v)) {
return Err(format!("--validation must be each_step, each_feature or off, not `{v}`"));
}
Ok(Options { cli: arg("--cli"), area: arg("--area"), timeout: Duration::from_secs(secs), jobs, out, kernels, known_failing, validation })
Ok(Options { cli: arg("--cli"), area: arg("--area"), timeout: Duration::from_secs(secs), jobs, out, known_failing, validation })
}
/// Every case's full result as JSON, into the run's output folder.
@@ -126,8 +95,8 @@ fn cases(dir: &Path, only: Option<&str>) -> Result<Vec<PathBuf>, String> {
/// One case, in its own process, killed after the timeout; `path` is the case's directory under
/// `tests/kernel-cases/`.
fn run_one(o: &Options, case: &Path, kernel: &str) -> Value {
let mut r = run_case(o, case, kernel);
fn run_one(o: &Options, case: &Path) -> Value {
let mut r = run_case(o, case);
let base = root().join("tests/kernel-cases");
r["path"] = json!(case.strip_prefix(&base).unwrap_or(case).to_string_lossy().replace('\\', "/"));
r
@@ -166,26 +135,19 @@ fn wait_draining(mut child: std::process::Child, timeout: Duration) -> Result<Op
Ok(Some(std::process::Output { status, stdout: join(stdout)?, stderr: join(stderr)? }))
}
/// The features `cargo run` builds the CLI with for a run on `kernels`: the C++ kernel is opt-in at
/// build time (`--features smlib`), so only a run that asks for it builds it. One build for the
/// whole run (`both` included), so the cases don't rebuild the CLI between kernels.
fn cli_features(kernels: &[&str]) -> &'static [&'static str] {
if kernels.contains(&"smlib") { &["--features", "smlib"] } else { &[] }
}
fn run_case(o: &Options, case: &Path, kernel: &str) -> Value {
fn run_case(o: &Options, case: &Path) -> Value {
let rel = case.strip_prefix(root()).unwrap_or(case).to_path_buf();
let mut cmd = match &o.cli {
Some(bin) => Command::new(bin),
None => {
let mut c = cargo();
c.args(["run", "-q", "--release", "-p", "solidcraft-cli"]).args(cli_features(&o.kernels)).arg("--");
c.args(["run", "-q", "--release", "-p", "solidcraft-cli", "--"]);
c
}
};
let mut dumps = std::ffi::OsString::from("--dumps=");
dumps.push(o.out_of(kernel).join("dumps"));
cmd.env("SOLIDCRAFT_KERNEL", kernel).current_dir(root()).args(["kernel-cases", "--json"]).arg(dumps);
dumps.push(o.out.join("dumps"));
cmd.current_dir(root()).args(["kernel-cases", "--json"]).arg(dumps);
if let Some(v) = &o.validation {
cmd.arg(format!("--validation={v}"));
}
@@ -222,27 +184,21 @@ fn run_case(o: &Options, case: &Path, kernel: &str) -> Value {
}
}
/// Every case on the run's one backend (the ladder's: it refuses `--kernel both`).
/// Every case, one job pool for them all; the results in order.
pub(crate) fn run_all(o: &Options, list: &[PathBuf]) -> Vec<Value> {
run_on(o, list, &o.kernels).into_iter().next().unwrap_or_default()
}
/// Every case on each backend, one job pool for all the runs; the results per backend, in order.
fn run_on(o: &Options, list: &[PathBuf], kernels: &[&str]) -> Vec<Vec<Value>> {
// Without --cli each case is `cargo run`: build the CLI once first, so the first cases don't
// spend their timeout compiling it (the C++ kernel's build most of all).
// spend their timeout compiling it.
if o.cli.is_none() {
let mut c = cargo();
c.args(["build", "-q", "--release", "-p", "solidcraft-cli"]).args(cli_features(kernels));
c.args(["build", "-q", "--release", "-p", "solidcraft-cli"]);
if let Err(e) = c.status().map_err(|e| e.to_string()).and_then(|s| if s.success() { Ok(()) } else { Err(s.to_string()) }) {
eprintln!("kernel-cases: building solidcraft-cli failed ({e}); each case will say why");
}
}
let jobs = list.len() * kernels.len();
let next = Arc::new(Mutex::new(0usize));
let results = Arc::new(Mutex::new(vec![Value::Null; jobs]));
let results = Arc::new(Mutex::new(vec![Value::Null; list.len()]));
std::thread::scope(|s| {
for _ in 0..o.jobs.min(jobs.max(1)) {
for _ in 0..o.jobs.min(list.len().max(1)) {
let (next, results) = (Arc::clone(&next), Arc::clone(&results));
s.spawn(move || {
loop {
@@ -252,15 +208,9 @@ fn run_on(o: &Options, list: &[PathBuf], kernels: &[&str]) -> Vec<Vec<Value>> {
*n += 1;
i
};
// Case by case, each on every backend in turn.
let (Some(case), Some(kernel)) = (list.get(i / kernels.len().max(1)), kernels.get(i % kernels.len().max(1))) else { return };
let r = run_one(o, case, kernel);
let tag = if kernels.len() > 1 { format!("{kernel:<10} ") } else { String::new() };
println!(
"{:<11} {tag}{}",
r["status"].as_str().unwrap_or("?").to_uppercase(),
case.strip_prefix(root()).unwrap_or(case).display()
);
let Some(case) = list.get(i) else { return };
let r = run_one(o, case);
println!("{:<11} {}", r["status"].as_str().unwrap_or("?").to_uppercase(), case.strip_prefix(root()).unwrap_or(case).display());
if let Ok(mut all) = results.lock()
&& let Some(slot) = all.get_mut(i)
{
@@ -270,8 +220,7 @@ fn run_on(o: &Options, list: &[PathBuf], kernels: &[&str]) -> Vec<Vec<Value>> {
});
}
});
let all = Arc::try_unwrap(results).ok().and_then(|m| m.into_inner().ok()).unwrap_or_default();
(0..kernels.len()).map(|k| all.iter().skip(k).step_by(kernels.len().max(1)).cloned().collect()).collect()
Arc::try_unwrap(results).ok().and_then(|m| m.into_inner().ok()).unwrap_or_default()
}
/// What went wrong in a result: its failed checks, then its error.
@@ -353,9 +302,8 @@ fn source_kinds(dir: &Path, cited: &BTreeMap<String, Vec<String>>) -> Result<Str
Ok(md)
}
/// The report of one backend's run into `to` (relative to the repository root, or absolute);
/// `kernel` is the backend's label, `env` what its processes were given.
fn write_report(dir: &Path, list: &[PathBuf], results: &[Value], kernel: &str, env: &str, to: &Path) -> Result<String, String> {
/// The run's report into `to` (relative to the repository root, or absolute).
fn write_report(dir: &Path, list: &[PathBuf], results: &[Value], to: &Path) -> Result<String, String> {
let key = |r: &Value| (r["area"].as_str().unwrap_or("").to_string(), r["case"].as_str().unwrap_or("").to_string());
let by_case: BTreeMap<(String, String), &Value> = results.iter().map(|r| (key(r), r)).collect();
// Coverage: per area, cases and their statuses; per source, its cases.
@@ -386,11 +334,8 @@ fn write_report(dir: &Path, list: &[PathBuf], results: &[Value], kernel: &str, e
);
}
let mut md = String::from(
"# Kernel regression rig\n\nGenerated by `cargo xtask kernel-cases`. Every geometry case the old kernel (truck) got wrong, as an issue, a PR or a crash report recorded it, is a use case in [`tests/kernel-cases/`](../tests/kernel-cases/) with its own right answer: numbers from analysis or a hand calculation (**analytic**) where the geometry has them, and otherwise the invariants (**invariants**): the operation succeeds, or refuses cleanly where that is the right answer; each body is one closed shell that passes the record's structure and geometry checks and SMLib's own check; the expected face, edge and vertex counts. Never a kernel's output, and never a commercial kernel's.\n\nThe cases run on SMLib, SolidCraft's kernel. A failing case stays failing until the kernel is fixed; there is no workaround on SolidCraft's side. A failed SMLib call leaves its inputs for replay in the run's output folder (`target/kernel-cases/dumps/<area>-<case>/`). See [`tests/kernel-cases/README.md`](../tests/kernel-cases/README.md) for the format. Every area is also a regression gate: CI's Kernel rig workflow runs them on every pull request that touches the kernel and fails on a case that fails and its area's `KNOWN_FAILING` (such as [`fillets/KNOWN_FAILING`](../tests/kernel-cases/fillets/KNOWN_FAILING)) does not list, or a listed case that passes.\n\n",
"# Kernel regression rig\n\nGenerated by `cargo xtask kernel-cases`. Every geometry case the old kernel (truck) got wrong, as an issue, a PR or a crash report recorded it, is a use case in [`tests/kernel-cases/`](../tests/kernel-cases/) with its own right answer: numbers from analysis or a hand calculation (**analytic**) where the geometry has them, and otherwise the invariants (**invariants**): the operation succeeds, or refuses cleanly where that is the right answer; each body is one closed shell that passes the record's structure and geometry checks and the kernel's own check; the expected face, edge and vertex counts. Never a kernel's output, and never a commercial kernel's.\n\nThe cases run on solidcore, SolidCraft's kernel. A failing case stays failing until the kernel is fixed; there is no workaround on SolidCraft's side. A failed kernel call leaves its inputs for replay in the run's output folder (`target/kernel-cases/dumps/<area>-<case>/`). See [`tests/kernel-cases/README.md`](../tests/kernel-cases/README.md) for the format. Every area is also a regression gate: CI's Kernel rig workflow runs them on every pull request that touches the kernel and fails on a case that fails and its area's `KNOWN_FAILING` (such as [`fillets/KNOWN_FAILING`](../tests/kernel-cases/fillets/KNOWN_FAILING)) does not list, or a listed case that passes.\n\n",
);
if kernel != "smlib" {
md += &format!("**This run: `{env}`.**\n\n");
}
md += "## Coverage\n\n| Area | Cases | Results |\n|---|---|---|\n";
for (area, (n, statuses)) in &areas {
md += &format!("| {area} | {n} | {} |\n", statuses.iter().map(|(s, c)| format!("{c} {s}")).collect::<Vec<_>>().join(", "));
@@ -441,92 +386,11 @@ fn write_report(dir: &Path, list: &[PathBuf], results: &[Value], kernel: &str, e
let shown = path.strip_prefix(root()).unwrap_or(&path).display().to_string();
std::fs::write(&path, md).map_err(|e| format!("{shown}: {e}"))?;
let pass = results.iter().filter(|r| r["status"] == "pass").count();
let on = if kernel == "smlib" { String::new() } else { format!(" on {kernel}") };
Ok(format!("kernel-cases: {pass}/{} pass{on} → {shown} ({skipped} skipped sources listed)", list.len()))
}
/// pass, fail, or other (crash, hang, not supported yet...), for the summary.
fn bucket(status: &str) -> &'static str {
match status {
"pass" => "pass",
"fail" => "fail",
_ => "other",
}
}
/// A result's commands' time (or, without one, its process's).
fn seconds(r: &Value) -> Option<f64> {
r["seconds"].as_f64().or_else(|| r["process_seconds"].as_f64())
}
/// The two backends side by side: per case (area, id) each one's status, time and what went wrong,
/// as JSON, and the Markdown report: a summary, then per area the cases that differ first.
fn side_by_side(smlib: &[Value], solidcore: &[Value]) -> (Value, String) {
let key = |r: &Value| (r["area"].as_str().unwrap_or("").to_string(), r["case"].as_str().unwrap_or("").to_string());
let mut pairs: BTreeMap<(String, String), [Option<&Value>; 2]> = BTreeMap::new();
for (k, rs) in [smlib, solidcore].iter().enumerate() {
for r in rs.iter().filter(|r| !r.is_null()) {
if let Some(slot) = pairs.entry(key(r)).or_default().get_mut(k) {
*slot = Some(r);
}
}
}
let status = |r: Option<&Value>| r.and_then(|r| r["status"].as_str()).unwrap_or("not run").to_string();
let mut rows = Vec::new();
let (mut counts, mut times, mut agree) = ([StatusCounts::new(), StatusCounts::new()], [0.0f64; 2], 0);
for ((area, case), runs) in &pairs {
let same = status(runs[0]) == status(runs[1]);
agree += usize::from(same);
let mut row = json!({"case": case, "area": area, "agree": same});
for (k, name) in BACKENDS.iter().enumerate() {
let r = runs[k];
*counts[k].entry(bucket(&status(r)).to_string()).or_default() += 1;
times[k] += r.and_then(seconds).unwrap_or(0.0);
let error = r.map(|r| notes(r).join("; ")).filter(|e| !e.is_empty());
row[*name] = json!({"status": status(r), "seconds": r.and_then(seconds), "error": error});
}
rows.push(row);
}
let differ = pairs.len() - agree;
let mut md = String::from(
"# Kernel regression rig: SMLib and solidcore\n\nGenerated by `cargo xtask kernel-cases --kernel both`: every case in [`tests/kernel-cases/`](../tests/kernel-cases/) run on each backend (`SOLIDCRAFT_KERNEL`), graded against its own answer. Times are the commands' own. [`kernel-cases.md`](kernel-cases.md) is the SMLib run in full.\n\n",
);
md += "## Summary\n\n| Backend | Pass | Fail | Other | Time (s) |\n|---|---|---|---|---|\n";
for (k, name) in BACKENDS.iter().enumerate() {
let n = |b: &str| counts[k].get(b).copied().unwrap_or(0);
md += &format!("| {name} | {} | {} | {} | {:.1} |\n", n("pass"), n("fail"), n("other"), times[k]);
}
md += &format!("\n{} cases: {agree} agree, {differ} differ.\n", pairs.len());
let side = |r: &Value| match r["seconds"].as_f64() {
Some(s) => format!("{} ({s:.2} s)", r["status"].as_str().unwrap_or("?")),
None => r["status"].as_str().unwrap_or("?").to_string(),
};
let mut by_area: BTreeMap<&str, Vec<&Value>> = BTreeMap::new();
for row in &rows {
by_area.entry(row["area"].as_str().unwrap_or("")).or_default().push(row);
}
for (area, mut list) in by_area {
list.sort_by_key(|r| (r["agree"].as_bool().unwrap_or(false), r["case"].as_str().unwrap_or("").to_string()));
md += &format!("\n## {area}\n\n| Case | {} | {} | |\n|---|---|---|---|\n", BACKENDS[0], BACKENDS[1]);
for r in list {
let mark = if r["agree"].as_bool().unwrap_or(false) { "" } else { "**differ**" };
md += &format!("| {} | {} | {} | {mark} |\n", r["case"].as_str().unwrap_or(""), side(&r["smlib"]), side(&r["solidcore"]));
}
}
let summary: Value = BACKENDS
.iter()
.enumerate()
.map(|(k, name)| (name.to_string(), json!({"counts": counts[k], "seconds": times[k]})))
.collect::<serde_json::Map<_, _>>()
.into();
(json!({"summary": summary, "agree": agree, "differ": differ, "cases": rows}), md)
Ok(format!("kernel-cases: {pass}/{} pass → {shown} ({skipped} skipped sources listed)", list.len()))
}
pub fn run(rest: &[&str]) -> Result<(), String> {
if rest.contains(&"--ladder") {
if options(rest, "target/kernel-ladder")?.kernels.len() != 1 {
return Err("--kernel: the ladder runs on one backend, smlib or solidcore".into());
}
return crate::kernel_ladder::run(rest);
}
let o = options(rest, "target/kernel-cases")?;
@@ -539,39 +403,19 @@ pub fn run(rest: &[&str]) -> Result<(), String> {
if list.is_empty() {
return Err(format!("no cases (recipe.json + expected.json) under {}", dir.display()));
}
let runs = run_on(&o, &list, &o.kernels);
for (kernel, results) in o.kernels.iter().zip(&runs) {
save_json(&o.out_of(kernel), "results.json", results)?;
}
let results = run_all(&o, &list);
save_results(&o, &results)?;
if let Some(file) = &o.known_failing {
// A gate run grades the run's one kernel against its baseline, and writes no report; its
// results.json is still saved above.
// A gate run grades the run against its baseline, and writes no report; its results.json
// is still saved above.
let text = std::fs::read_to_string(file).map_err(|e| format!("{}: {e}", file.display()))?;
let base = file.parent().unwrap_or(&dir);
let paths: Vec<String> = list.iter().map(|c| c.strip_prefix(base).unwrap_or(c).to_string_lossy().replace('\\', "/")).collect();
let graded = runs.first().ok_or("--known-failing: no run to grade")?;
let statuses: Vec<&str> = graded.iter().map(|r| r["status"].as_str().unwrap_or("?")).collect();
let statuses: Vec<&str> = results.iter().map(|r| r["status"].as_str().unwrap_or("?")).collect();
println!("{}", gate(&text, &paths, &statuses).map_err(|e| format!("{}: {e}", file.display()))?);
return Ok(());
}
for (kernel, results) in o.kernels.iter().zip(&runs) {
let out = o.out_of(kernel);
let to = if *kernel == "smlib" { PathBuf::from("docs/kernel-cases.md") } else { out.join("report.md") };
let env = format!("SOLIDCRAFT_KERNEL={kernel}");
println!("{}", write_report(&dir, &list, results, kernel, &env, &to)?);
}
if let [smlib, solidcore] = runs.as_slice() {
let (data, md) = side_by_side(smlib, solidcore);
let into = o.out.clone();
save_json(&into, "backends.json", &data)?;
std::fs::write(root().join("docs/kernel-cases-backends.md"), md).map_err(|e| format!("docs/kernel-cases-backends.md: {e}"))?;
println!(
"kernel-cases: {} agree, {} differ → docs/kernel-cases-backends.md, {}",
data["agree"],
data["differ"],
into.join("backends.json").display()
);
}
println!("{}", write_report(&dir, &list, &results, Path::new("docs/kernel-cases.md"))?);
Ok(())
}
@@ -790,67 +634,15 @@ mod tests {
assert!(t.elapsed() < Duration::from_secs(20));
}
/// `--route`, the old per-family run, and `--kernel`, the old choice of kernel, are no options:
/// passed anyway, they are refused rather than run as something else.
#[test]
fn side_by_side_counts_and_puts_differences_first() {
let r = |area: &str, case: &str, status: &str, s: f64| json!({"area": area, "case": case, "status": status, "seconds": s});
let smlib = [r("booleans", "a", "pass", 1.0), r("booleans", "b", "pass", 2.0), r("shell", "c", "crash", 0.5)];
let mut hang = json!({"area": "booleans", "case": "b", "status": "hang", "error": "no result after 180 s"});
hang["process_seconds"] = json!(180.0);
let solidcore = [r("booleans", "a", "pass", 0.5), hang, r("shell", "c", "fail", 1.5)];
let (data, md) = side_by_side(&smlib, &solidcore);
assert_eq!((data["agree"].as_u64(), data["differ"].as_u64()), (Some(1), Some(2)));
assert_eq!(data["summary"]["smlib"]["counts"], json!({"pass": 2, "other": 1}));
assert_eq!(data["summary"]["solidcore"]["counts"], json!({"pass": 1, "fail": 1, "other": 1}));
assert_eq!(data["summary"]["solidcore"]["seconds"].as_f64(), Some(182.0));
let b = data["cases"].as_array().and_then(|c| c.iter().find(|c| c["case"] == "b")).cloned().unwrap_or_default();
assert_eq!((b["solidcore"]["status"].as_str(), b["solidcore"]["error"].as_str()), (Some("hang"), Some("no result after 180 s")));
// In booleans, b (differs) comes before a (agrees).
let (pos_a, pos_b) = (md.find("| a |"), md.find("| b |"));
assert!(pos_b.is_some() && pos_a.is_some() && pos_b < pos_a, "{md}");
assert!(md.contains("| b | pass (2.00 s) | hang (180.00 s) | **differ** |"), "{md}");
assert!(md.contains("3 cases: 1 agree, 2 differ."), "{md}");
}
/// `--route`, the old per-family run, is no option: each case's process has one kernel. Passed
/// anyway, it is refused rather than run as something else.
#[test]
fn a_kernel_has_its_own_folder_and_route_is_refused() {
let o = options(&["--kernel", "both", "--out", "/r"], "x").unwrap();
assert_eq!((o.out_of("smlib"), o.out_of("solidcore")), (PathBuf::from("/r"), PathBuf::from("/r/solidcore")));
fn route_and_kernel_are_refused() {
assert!(options(&["--route", "boolean=solidcore"], "x").is_err());
assert!(options(&["--kernel", "both", "--route"], "x").is_err());
}
/// `--known-failing` follows the kernel given, solidcore by default: a list is one kernel's.
#[test]
fn the_gate_grades_the_kernel_given() {
for (args, kernel) in [
(&["--known-failing", "/k"][..], "solidcore"),
(&["--kernel", "solidcore", "--known-failing", "/k"], "solidcore"),
(&["--kernel", "smlib", "--known-failing", "/k"], "smlib"),
] {
let o = options(args, "x").unwrap();
assert_eq!((o.known_failing, o.kernels), (Some(PathBuf::from("/k")), vec![kernel]), "{args:?}");
}
assert!(options(&["--kernel", "both", "--known-failing", "/k"], "x").is_err());
}
/// With no `--kernel`, a run is on solidcore; the C++ kernel is asked for.
#[test]
fn the_rig_defaults_to_solidcore() {
assert_eq!(options(&[], "x").unwrap().kernels, ["solidcore"]);
assert_eq!(options(&["--kernel", "smlib"], "x").unwrap().kernels, ["smlib"]);
assert_eq!(options(&["--kernel", "both"], "x").unwrap().kernels, ["smlib", "solidcore"]);
}
/// Only a run that asks for the C++ kernel builds the CLI with it.
#[test]
fn the_cli_is_built_with_the_cpp_kernel_only_when_a_run_asks_for_it() {
let features = |args: &[&str]| cli_features(&options(args, "x").unwrap().kernels).to_vec();
assert!(features(&[]).is_empty());
assert!(features(&["--kernel", "solidcore"]).is_empty());
assert_eq!(features(&["--kernel", "smlib"]), ["--features", "smlib"]);
assert_eq!(features(&["--kernel", "both"]), ["--features", "smlib"]);
assert!(options(&["--kernel", "smlib"], "x").is_err());
assert!(options(&["--kernel", "solidcore", "--known-failing", "/k"], "x").is_err());
let o = options(&["--known-failing", "/k", "--out", "/r"], "x").unwrap();
assert_eq!((o.known_failing, o.out), (Some(PathBuf::from("/k")), PathBuf::from("/r")));
}
fn gate_on(text: &str, cases: &[(&str, &str)]) -> Result<String, String> {
+3 -3
View File
@@ -2,13 +2,13 @@
//!
//! `tests/kernel-cases/ladder/ladder.json` lists tiers in order of complexity and, per tier, its
//! cases in order (paths under `tests/kernel-cases/`, so a tier may also list rig cases from other
//! areas). Each case is a test like any rig case, graded against its own `expected.json`, on
//! `--kernel`'s one backend. The golden is SMLib's, so a gate or a record says `--kernel smlib`. On top, `tests/kernel-cases/ladder/golden.json` records per case the status, the
//! areas). Each case is a test like any rig case, graded against its own `expected.json`. On top,
//! `tests/kernel-cases/ladder/golden.json` records per case the status, the
//! commands' time and what was made (counts, volume, area): the run compares with it and flags
//! slowdowns and changes; cases run one at a time unless `--jobs` says otherwise, so the times are
//! not shared with other cases. `--record REASON` re-measures the golden and re-sorts each tier
//! by time, fastest first; both files are committed. The run's output folder (`--out`, default
//! `target/kernel-ladder`) holds `results.json` and the SMLib dumps, as the rig's does.
//! `target/kernel-ladder`) holds `results.json` and the kernel's dumps, as the rig's does.
//! `--gate` makes the run a regression gate instead of the report: it fails on any case whose
//! status or counts differ from the golden (times aside, which are the machine's).
//!
+6 -10
View File
@@ -1,7 +1,7 @@
//! `cargo xtask known-failing --junit PATH... [--list FILE]`: grades a nextest run (its junit
//! report) against the tests known to fail today on the default kernel,
//! `tests/KNOWN_FAILING_TESTS` (the C++ kernel's are `tests/KNOWN_FAILING_TESTS.smlib`, for a run
//! with `SOLIDCRAFT_KERNEL=smlib` and `--list`). CI's test jobs run it after nextest, in place of failing on any failed test. It fails on a test that failed
//! report) against the tests known to fail today,
//! `tests/KNOWN_FAILING_TESTS` (or `--list FILE`). CI's test jobs run it after nextest, in place of
//! failing on any failed test. It fails on a test that failed
//! and is not listed, and on a listed test that passed (fixed: its line comes off in the same
//! pull request); a listed test that did not run (a pull request tests only the packages it
//! touches) is neither. The list has the kernel rig's format (`kernel_cases::known_failing`):
@@ -16,8 +16,6 @@ use quick_xml::Reader;
use quick_xml::events::{BytesStart, Event};
pub const LIST: &str = "tests/KNOWN_FAILING_TESTS";
/// The same for the C++ kernel (`SOLIDCRAFT_KERNEL=smlib`), graded with `--list`.
pub const SMLIB_LIST: &str = "tests/KNOWN_FAILING_TESTS.smlib";
pub fn run(root: &Path, rest: &[&str]) -> Result<(), String> {
let mut reports = Vec::new();
@@ -63,11 +61,9 @@ fn add(all: &mut BTreeMap<String, bool>, xml: &str) -> Result<(), String> {
/// `cargo xtask lists`: the list is sorted, each test once, with a cause each.
pub fn check_list(root: &Path) -> Result<(), String> {
for list in [LIST, SMLIB_LIST] {
let file = root.join(list);
let text = std::fs::read_to_string(&file).map_err(|e| format!("{}: {e}", file.display()))?;
crate::kernel_cases::known_failing(&text).map_err(|e| format!("{list}: {e}"))?;
}
let file = root.join(LIST);
let text = std::fs::read_to_string(&file).map_err(|e| format!("{}: {e}", file.display()))?;
crate::kernel_cases::known_failing(&text).map_err(|e| format!("{LIST}: {e}"))?;
Ok(())
}
+2 -2
View File
@@ -42,10 +42,10 @@ pub const TABLE: &[(&str, Class)] = &[
("derive", Class::Standalone),
// the 3Dconnexion driver's client API on macOS (no workspace dependencies)
("3dx-client", Class::Standalone),
// the profiler: timed spans for every layer, SMLib's calls to commands (no workspace dependencies)
// the profiler: timed spans for every layer, the kernel's calls to commands (no workspace dependencies)
("profile", Class::Standalone),
("sketch", Class::Layer(1)),
// NVIDIA's SMLib behind its C API (kernel-smlib branch, ADR 0002); only the kernel uses it
// the B-rep kernel, solidcore (the Rust port of NVIDIA's SMLib, ADR 0002); only the kernel uses it
("smlib", Class::Layer(1)),
// STEP (ISO 10303) exchange structure and geometry, no modelling backend
("step", Class::Layer(1)),
+1 -1
View File
@@ -5,7 +5,7 @@
//!
//! - The message catalogs (`assets/locales/*.json`): one message per line, sorted by id, no
//! duplicate ids, as `serde_json` pretty-prints them.
//! - `tests/KNOWN_FAILING_TESTS` and `.smlib`: one test a line with its cause, sorted, each test once
//! - `tests/KNOWN_FAILING_TESTS`: one test a line with its cause, sorted, each test once
//! (checked only; `cargo xtask known-failing` reads it).
//! - Growing Rust lists: no written array lengths on more than ten lines of entries.
+8 -16
View File
@@ -49,29 +49,21 @@ commands:
replay the reference tests (tests/oracle/*/recipe.json), compare with each
case's expected.json and write docs/oracle.md (--cli: a solidcraft-cli
already built, instead of cargo run --release)
kernel-cases [--area AREA] [--cli BIN] [--timeout S] [--jobs N] [--out DIR] [--kernel K] [--route R] [--known-failing FILE] [--validation MODE] [--coverage]
kernel-cases [--area AREA] [--cli BIN] [--timeout S] [--jobs N] [--out DIR] [--known-failing FILE] [--validation MODE] [--coverage]
the kernel regression rig: run every case in tests/kernel-cases/<area>/<id>/ on
solidcore (one process each, killed after --timeout, default 180 s), grade it against
the case's own answer; DIR (default target/kernel-cases) gets results.json and
dumps/<area>-<case>/, the inputs of each failing SMLib call (--cli: a
solidcraft-cli already built);
--kernel solidcore|smlib|both (default solidcore) sets SOLIDCRAFT_KERNEL per case:
solidcore keeps results.json, dumps/ and report.md in DIR/solidcore/; smlib
writes docs/kernel-cases.md; both runs each case on each, and also writes the
side by side to docs/kernel-cases-backends.md and DIR/backends.json; smlib and
both need the C++ kernel, so without --cli they build the CLI with --features smlib
(a --cli built without it reports every case as unsupported)
the case's own answer and write docs/kernel-cases.md; DIR (default
target/kernel-cases) gets results.json and dumps/<area>-<case>/, the inputs of
each failing kernel call (--cli: a solidcraft-cli already built);
--known-failing FILE: a regression gate instead of the report: fails on a case
that fails and FILE does not list, and on a listed case that passes
(tests/kernel-cases/<area>/KNOWN_FAILING, CI's Kernel rig workflow); it grades
the run's kernel, so a list is one kernel's (KNOWN_FAILING.solidcore,
KNOWN_FAILING for --kernel smlib) and --kernel both is refused
--validation MODE: when SMLib's full check runs on the cases' features:
(tests/kernel-cases/<area>/KNOWN_FAILING, CI's Kernel rig workflow)
--validation MODE: when the kernel's full check runs on the cases' features:
each_step, each_feature (the default) or off (solidcraft-cli kernel-cases
--validation=MODE); with --ladder too
--ladder [--record REASON | --gate]: the complexity ladder instead
(tests/kernel-cases/ladder/ladder.json, tiers in order), graded and compared
with its timing golden (one case at a time unless --jobs), on --kernel's one backend, into
with its timing golden (one case at a time unless --jobs), into
docs/kernel-ladder.md (DIR default target/kernel-ladder); --record re-measures
the golden and re-sorts each tier by time; --gate fails on any case whose status
or counts differ from the golden, instead of the report
@@ -81,7 +73,7 @@ commands:
known-failing --junit PATH... [--list FILE]
grade a nextest run's junit report (a file, or every .xml under a directory)
against the tests known to fail today on the default kernel,
tests/KNOWN_FAILING_TESTS (FILE: .smlib is the C++ kernel's): fails
tests/KNOWN_FAILING_TESTS (or FILE): fails
on a test that failed and is not listed, and on a listed test that passed
(fixed: take its line off); a listed test that did not run is neither. CI's
test jobs run it after nextest