Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
1db280d
chore(release): 3.8.0
AregGevorgyan Aug 12, 2026
d139a46
fix(cuda): a vacuous sanitizer gate and two capability overclaims
AregGevorgyan Aug 12, 2026
99ac342
fix(cuda): reach every GPU from Python, and a racecheck gate that pri…
AregGevorgyan Aug 12, 2026
917a4b5
fix: the remaining silent errors, and five gates that could not fail
AregGevorgyan Aug 12, 2026
661f677
Merge remote-tracking branch 'origin/cuda/3.8-hardware-fixes' into re…
AregGevorgyan Aug 12, 2026
4225654
ci: three nightly shards were passing without running anything
AregGevorgyan Aug 12, 2026
c26cc5a
ci: do not prefix `cargo afl system-config` with sudo, and add AFL fa…
AregGevorgyan Aug 12, 2026
dd10b95
ci: cover release branches, and stop scheduling a job that has no runner
AregGevorgyan Aug 12, 2026
9b2467e
ci: make the three broken shards actually run
AregGevorgyan Aug 12, 2026
08975a6
ci: resolve the fuzz binary instead of assuming its path
AregGevorgyan Aug 12, 2026
8c45932
ci: move AddressSanitizer out of the PR path and into nightly
AregGevorgyan Aug 12, 2026
c0a371b
ci: valgrind now runs, and gates on real leaks rather than possible ones
AregGevorgyan Aug 12, 2026
3ad9e8c
ci: bring AddressSanitizer back to PRs, as a parallel job
AregGevorgyan Aug 12, 2026
ab4e946
ci: Tier 1b on PRs, and scope valgrind to the FFI boundary
AregGevorgyan Aug 12, 2026
4130506
fix: refuse where nothing can be certified; make declines observable
AregGevorgyan Aug 12, 2026
591626e
fix(simplify): record expansion declines on the parallel path too
AregGevorgyan Aug 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/alkahest-semver-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ name: semver-check
on:
pull_request:
branches: [main]
# `release/**` is included because a release branch accumulates merges that
# would otherwise reach a tag with no CI at all: `pull_request` runs did not
# fire for a PR based on `release/3.8.0`, and push only covered `main`, so
# everything merged there was verified by local gates alone.
push:
branches: [main]
branches: [main, 'release/**']

env:
CARGO_TERM_COLOR: always
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/ci-cross.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ name: ci-cross
on:
pull_request:
branches: [main]
# `release/**` is included because a release branch accumulates merges that
# would otherwise reach a tag with no CI at all: `pull_request` runs did not
# fire for a PR based on `release/3.8.0`, and push only covered `main`, so
# everything merged there was verified by local gates alone.
push:
branches: [main]
branches: [main, 'release/**']

env:
CARGO_TERM_COLOR: always
Expand Down
273 changes: 253 additions & 20 deletions .github/workflows/ci.yml

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion .github/workflows/codspeed.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
name: CodSpeed

on:
# `release/**` is included because a release branch accumulates merges that
# would otherwise reach a tag with no CI at all: `pull_request` runs did not
# fire for a PR based on `release/3.8.0`, and push only covered `main`, so
# everything merged there was verified by local gates alone.
push:
branches: [main]
branches: [main, 'release/**']
pull_request:

# Benchmarks must be reproducible — no parallel jobs touching the same runner.
Expand Down
71 changes: 65 additions & 6 deletions .github/workflows/cuda_nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@
# Runs memcheck and racecheck on CUDA tests. Requires self-hosted GPU runner.
name: CUDA Nightly (compute-sanitizer)

# NOT SCHEDULED. This job targets `[self-hosted, gpu-3090]`, and no such runner
# is registered — a scheduled run does not fail, it queues forever, so the
# schedule produced a permanently pending job on `main` and no signal either
# way. `workflow_dispatch` is kept so it can be run the moment a GPU runner
# exists, and the file is kept because it is the specification for running
# these suites: an agent on a GPU box follows it step for step.
#
# Until a runner is registered, the CUDA surface is verified by hand on GPU
# hardware. As of 3.8.0 that run passed: 17 Rust CUDA tests, 17/17 in
# `tests/test_cuda.py`, memcheck and racecheck clean, and GPU/CPU agreement
# within 0-2 ulp checked against numpy's own ufuncs (not `numpy_eval`, which
# shares the Cranelift backend and is therefore not an independent oracle).
on:
schedule:
- cron: '0 2 * * *' # 02:00 UTC daily
workflow_dispatch:

jobs:
Expand All @@ -29,20 +39,69 @@ jobs:
ALKAHEST_GPU_TESTS: "1"
run: cargo test --features cuda,groebner-cuda --no-fail-fast

# The Python surface of the CUDA feature had never been built by any CI
# job: this workflow ran `cargo` only. That is how `ak.compile_cuda` came
# to raise AttributeError on a build whose own capabilities() advertised
# `cuda: true`, and survived three releases — the Rust tests all passed
# the entire time, because the gap was in the re-export, not the kernel.
- name: Install Python
uses: actions/setup-python@v6
with:
python-version: "3.11"

- uses: astral-sh/setup-uv@v6

- name: Create venv and install Python tooling
run: |
uv sync --no-install-project --group dev
echo "$PWD/.venv/bin" >> $GITHUB_PATH
echo "VIRTUAL_ENV=$PWD/.venv" >> $GITHUB_ENV

- name: maturin develop (cuda + groebner-cuda)
run: maturin develop --manifest-path alkahest-py/Cargo.toml --features "groebner egraph cuda groebner-cuda"

# ALKAHEST_GPU_TESTS=1 makes the device probe assert rather than skip, so
# a missing or broken GPU fails here instead of quietly reporting green.
- name: pytest (CUDA surface)
env:
ALKAHEST_GPU_TESTS: "1"
run: pytest tests/test_cuda.py -v

# The capability contract is only falsifiable on a build that has the
# feature; on every other runner these assertions are vacuously true.
- name: Capability contract on a real CUDA build
run: pytest tests/test_agent_contract.py -v

# Both sanitizer steps are scoped to the two integration targets that
# actually launch kernels. Wrapping the whole `cargo test` instead drags
# rustdoc's doc-test runner under the sanitizer, where it segfaults
# (SIGSEGV, exit 139) *after* the CUDA suites have passed but *before*
# the summary is printed — so racecheck produced no RACECHECK SUMMARY at
# all, and with `continue-on-error: true` that looked like a pass.
# Scoping costs no coverage: the only GPU work in the workspace lives in
# these two targets. The in-`src` unit tests reach `compile_cuda` for PTX
# generation only, and `compute_groebner_basis_gpu(.., None)` takes the
# `reduce_cpu` path, so neither issues a CUDA API call.
- name: Run compute-sanitizer memcheck
env:
ALKAHEST_GPU_TESTS: "1"
run: |
compute-sanitizer --tool memcheck \
cargo test --features cuda,groebner-cuda --no-fail-fast
# --target-processes all is load-bearing: the default is
# application-only, which instruments `cargo` — a process that makes
# no CUDA calls whatsoever. Without it this step emits a banner, no
# ERROR SUMMARY, and a green tick while checking nothing.
compute-sanitizer --target-processes all --tool memcheck \
cargo test --features cuda,groebner-cuda --no-fail-fast \
--test nvptx_gpu --test groebner_cuda
continue-on-error: false

- name: Run compute-sanitizer racecheck
env:
ALKAHEST_GPU_TESTS: "1"
run: |
compute-sanitizer --tool racecheck \
cargo test --features cuda,groebner-cuda
compute-sanitizer --target-processes all --tool racecheck \
cargo test --features cuda,groebner-cuda \
--test nvptx_gpu --test groebner_cuda
Comment on lines 98 to +104

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

file=".github/workflows/cuda_nightly.yml"
printf '%s\n' '--- workflow context ---'
sed -n '1,125p' "$file"

printf '%s\n' '--- all continue-on-error entries ---'
rg -n -C 3 'continue-on-error|racecheck|compute-sanitizer|ALKAHEST_GPU_TESTS' "$file"

printf '%s\n' '--- workflow metadata ---'
git diff --stat
git status --short

Repository: alkahest-cas/alkahest

Length of output: 8942


Make racecheck failures fail the workflow.

Set continue-on-error: false. Otherwise, racecheck failures and sanitizer startup failures can pass silently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/cuda_nightly.yml around lines 98 - 104, Ensure the “Run
compute-sanitizer racecheck” workflow step explicitly sets continue-on-error to
false so racecheck and sanitizer startup failures fail the workflow.

continue-on-error: true # racecheck may have false positives

- name: Upload sanitizer logs
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ name: docs

on:
workflow_dispatch:
# `release/**` is included because a release branch accumulates merges that
# would otherwise reach a tag with no CI at all: `pull_request` runs did not
# fire for a PR based on `release/3.8.0`, and push only covered `main`, so
# everything merged there was verified by local gates alone.
push:
branches: [main]
branches: [main, 'release/**']
paths:
- 'docs/**'
- 'python/alkahest/**'
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/release-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ jobs:
print(ak.simplify_egraph(x + 0).value)
assert hasattr(ak, 'solve'), 'expected groebner APIs in default wheel'
f = ak.capabilities()["features"]
# `numpy` and `groebner_cuda` are deliberately absent (contract v3):
# neither named anything a Python caller could reach.
assert f == {
"egraph": True, "groebner": True, "jit": False,
"cranelift": True, "llvm_jit": False, "cranelift_jit": True,
"parallel": False, "numpy": False, "cuda": False,
"groebner_cuda": False,
"parallel": False, "cuda": False,
}
assert ak.jit_is_available(), "expected Cranelift JIT in default wheel"
print('default wheel ok (groebner + cranelift)')
Expand Down
Loading
Loading