From fa233fd8c97d2a1463141535f2a288b264abe93b Mon Sep 17 00:00:00 2001 From: Joseph Magly <1159087+jmagly@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:23:22 -0400 Subject: [PATCH] ci: make CUDA conditional lane GPU-capable --- .github/workflows/conditional-tests.yml | 9 +++++++++ ci/conditional-test-policy.json | 15 +++++++++++---- docs/conditional-testing.md | 11 ++++++++++- tests/test_conditional_gate_scripts.py | 12 ++++++++++++ 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/.github/workflows/conditional-tests.yml b/.github/workflows/conditional-tests.yml index 8cd1856..16442b8 100644 --- a/.github/workflows/conditional-tests.yml +++ b/.github/workflows/conditional-tests.yml @@ -240,6 +240,15 @@ jobs: python -m pip install "uv==${UV_VERSION}" UV_PROJECT_ENVIRONMENT="$CONDITIONAL_ENV" \ uv sync --locked --no-default-groups --extra dev --no-editable + CUDA_TORCH_VERSION="$("$CONDITIONAL_ENV/bin/python" -c \ + 'import torch; print(torch.__version__.split("+", 1)[0])')" + UV_TORCH_BACKEND=cu130 uv pip install \ + --python "$CONDITIONAL_ENV/bin/python" \ + --reinstall-package torch \ + "torch==$CUDA_TORCH_VERSION" + "$CONDITIONAL_ENV/bin/python" -c \ + 'import torch; assert torch.version.cuda is not None, torch.__version__' + uv pip check --python "$CONDITIONAL_ENV/bin/python" - name: Run CUDA placement and operation probe run: >- "$CONDITIONAL_ENV/bin/python" scripts/run_conditional_gate.py cuda-runtime diff --git a/ci/conditional-test-policy.json b/ci/conditional-test-policy.json index ac1aa3e..2312d65 100644 --- a/ci/conditional-test-policy.json +++ b/ci/conditional-test-policy.json @@ -12,12 +12,19 @@ "trust_remote_code": false, "cache": "GitHub Actions cache keyed by repository, revision, runner OS, and Python version", "timeout_minutes": 20 + }, + "cuda_torch": { + "version_source": "Exact base version from the locked CPU Torch package", + "backend": "cu130", + "index": "https://download.pytorch.org/whl/cu130", + "installer": "uv pip with UV_TORCH_BACKEND=cu130", + "rationale": "Mandatory Linux CI stays CPU-only; the selected CUDA lane replaces only Torch with the same-version official CUDA build and verifies dependency consistency" } }, "environment_waivers": [ { "gate": "cuda-runtime", - "reason": "No dedicated CUDA runner is confirmed; the enable variable is unset and the current maintainer token cannot enumerate repository runners.", + "reason": "Titan has a verified RTX 4090 and Gitea GPU runner, but no GitHub self-hosted CUDA runner is registered or selectable for this workflow.", "issue": "https://github.com/elder-plinius/OBLITERATUS/issues/110", "opened": "2026-08-16", "expires": "2026-09-15", @@ -25,7 +32,7 @@ }, { "gate": "bitsandbytes-runtime", - "reason": "No dedicated CUDA and bitsandbytes runner is confirmed; the enable variable is unset and the current maintainer token cannot enumerate repository runners.", + "reason": "Titan has a verified RTX 4090 and Gitea GPU runner, but no GitHub self-hosted CUDA and bitsandbytes runner is registered or selectable for this workflow.", "issue": "https://github.com/elder-plinius/OBLITERATUS/issues/110", "opened": "2026-08-16", "expires": "2026-09-15", @@ -33,7 +40,7 @@ }, { "gate": "mps-runtime", - "reason": "No Apple Silicon MPS runner is confirmed; the enable variable is unset and the current maintainer token cannot enumerate repository runners.", + "reason": "Mutsu is a verified 16 GB Apple M4 builder, but no GitHub self-hosted MPS runner is registered or selectable for this workflow.", "issue": "https://github.com/elder-plinius/OBLITERATUS/issues/110", "opened": "2026-08-16", "expires": "2026-09-15", @@ -41,7 +48,7 @@ }, { "gate": "mlx-runtime", - "reason": "No Apple Silicon MLX runner is confirmed; the enable variable is unset and the current maintainer token cannot enumerate repository runners.", + "reason": "Mutsu is a verified 16 GB Apple M4 builder, but no GitHub self-hosted MLX runner is registered or selectable for this workflow.", "issue": "https://github.com/elder-plinius/OBLITERATUS/issues/110", "opened": "2026-08-16", "expires": "2026-09-15", diff --git a/docs/conditional-testing.md b/docs/conditional-testing.md index f5ed57d..974cd90 100644 --- a/docs/conditional-testing.md +++ b/docs/conditional-testing.md @@ -55,12 +55,21 @@ Set the repository variable `ENABLE_CUDA_GATE=true` for scheduled/release eviden or select CUDA during manual dispatch. The gate verifies CUDA discovery, automatic selection, dtype selection, tensor placement, matrix multiplication, bitsandbytes availability, NF4 quantization, dequantization, shape, placement, and finite output. -The expected cost is below 20 self-hosted runner-minutes. +The expected cost is below 20 self-hosted runner-minutes. Mandatory Linux CI +deliberately locks CPU-only Torch. The selected CUDA job reads that exact locked +base version, replaces only Torch with the same-version official `cu130` build, +asserts a CUDA build was installed, and runs `uv pip check` before executing the +probes. For an operator run on the labeled machine: ```bash uv sync --locked --extra dev +CUDA_TORCH_VERSION="$(.venv/bin/python -c \ + 'import torch; print(torch.__version__.split("+", 1)[0])')" +UV_TORCH_BACKEND=cu130 uv pip install --python .venv/bin/python \ + --reinstall-package torch "torch==$CUDA_TORCH_VERSION" +uv pip check --python .venv/bin/python uv run --extra dev python scripts/run_conditional_gate.py cuda-runtime uv run --extra dev python scripts/run_conditional_gate.py bitsandbytes-runtime ``` diff --git a/tests/test_conditional_gate_scripts.py b/tests/test_conditional_gate_scripts.py index 54a1c8d..0dc1f34 100644 --- a/tests/test_conditional_gate_scripts.py +++ b/tests/test_conditional_gate_scripts.py @@ -37,6 +37,18 @@ def test_committed_conditional_policy_is_complete(): ) == [] +def test_cuda_job_replaces_locked_cpu_torch_with_same_version_cuda_build(): + workflow = (ROOT / ".github" / "workflows" / "conditional-tests.yml").read_text() + cuda_job = workflow.split(" cuda:\n", maxsplit=1)[1].split(" mps:\n", maxsplit=1)[0] + + assert "torch.__version__.split" in cuda_job + assert "UV_TORCH_BACKEND=cu130 uv pip install" in cuda_job + assert "--reinstall-package torch" in cuda_job + assert '"torch==$CUDA_TORCH_VERSION"' in cuda_job + assert "assert torch.version.cuda is not None" in cuda_job + assert 'uv pip check --python "$CONDITIONAL_ENV/bin/python"' in cuda_job + + def test_policy_rejects_unknown_cpu_exclusion_gate(tmp_path): policy = json.loads((ROOT / "ci" / "conditional-test-policy.json").read_text()) quality = {