ci: make CUDA conditional lane GPU-capable

This commit is contained in:
Joseph Magly
2026-08-16 09:23:22 -04:00
parent baf5331730
commit fa233fd8c9
4 changed files with 42 additions and 5 deletions
+9
View File
@@ -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
+11 -4
View File
@@ -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",
+10 -1
View File
@@ -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
```
+12
View File
@@ -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 = {