-
Notifications
You must be signed in to change notification settings - Fork 79
[ws1]: complete C1-C5/C8 gtest validation and GPU CI gates #305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
af4d9c2
70286fb
087156e
81ddd65
e857084
fca1656
362562e
b41c6f8
f1bfbc5
2e4a30a
596feb0
69455aa
91261d6
5c33dcd
83029c7
3b3e681
89312cd
15e25dd
fffed4b
79c7d4d
ecdaa4b
cce9e94
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,108 @@ | ||||||||||||||||||||
| # SPDX-License-Identifier: Apache-2.0 | ||||||||||||||||||||
| # WS1 single-op gtest + C8 four-judgment GPU gate (CUDA BF16 and Triton-on-CUDA BF16). | ||||||||||||||||||||
| # Uses the same RunPod orchestrator as gpu-ci.yml. Fails closed on C8 red cells | ||||||||||||||||||||
| # and on C3/C4 silent fallback. Hopper must have zero pending_hopper. | ||||||||||||||||||||
| # | ||||||||||||||||||||
| # Security: do not use pull_request_target. Fork PRs never see RunPod secrets. | ||||||||||||||||||||
| # Same-repo PRs, pushes to main, and maintainer workflow_dispatch are allowed. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| name: WS1-gtest-GPU | ||||||||||||||||||||
|
|
||||||||||||||||||||
| on: | ||||||||||||||||||||
| pull_request: | ||||||||||||||||||||
| branches: [ main ] | ||||||||||||||||||||
| paths: | ||||||||||||||||||||
| - "rl_engine/kernels/gtest/**" | ||||||||||||||||||||
| - "rl_engine/kernels/ops/**" | ||||||||||||||||||||
| - "rl_engine/testing/**" | ||||||||||||||||||||
| - "scripts/sweep_ws1_four_judgments.py" | ||||||||||||||||||||
| - "scripts/check_forward_invariance.py" | ||||||||||||||||||||
| - "scripts/check_gradient_invariance.py" | ||||||||||||||||||||
| - "scripts/ws1_candidate_evidence.py" | ||||||||||||||||||||
| - "tests/test_ws1_*.py" | ||||||||||||||||||||
| - "tests/test_forward_invariance.py" | ||||||||||||||||||||
| - "tests/test_gradient_invariance.py" | ||||||||||||||||||||
| - "tests/test_four_judgment_matrix.py" | ||||||||||||||||||||
| - "tests/test_triton_batch_invariant_attention.py" | ||||||||||||||||||||
| - "ci/run_ws1_gtest.sh" | ||||||||||||||||||||
| - "ci/run_gpu_ci.sh" | ||||||||||||||||||||
| - ".github/workflows/ws1-gtest-gpu.yml" | ||||||||||||||||||||
| push: | ||||||||||||||||||||
| branches: [ main ] | ||||||||||||||||||||
| paths: | ||||||||||||||||||||
| - "rl_engine/kernels/gtest/**" | ||||||||||||||||||||
| - "rl_engine/kernels/ops/**" | ||||||||||||||||||||
| - "rl_engine/testing/**" | ||||||||||||||||||||
| - "scripts/sweep_ws1_four_judgments.py" | ||||||||||||||||||||
| - "scripts/check_forward_invariance.py" | ||||||||||||||||||||
| - "scripts/check_gradient_invariance.py" | ||||||||||||||||||||
| - "scripts/ws1_candidate_evidence.py" | ||||||||||||||||||||
| - "tests/test_ws1_*.py" | ||||||||||||||||||||
| - "tests/test_forward_invariance.py" | ||||||||||||||||||||
| - "tests/test_gradient_invariance.py" | ||||||||||||||||||||
| - "tests/test_four_judgment_matrix.py" | ||||||||||||||||||||
| - "tests/test_triton_batch_invariant_attention.py" | ||||||||||||||||||||
| - "ci/run_ws1_gtest.sh" | ||||||||||||||||||||
| - "ci/run_gpu_ci.sh" | ||||||||||||||||||||
| - ".github/workflows/ws1-gtest-gpu.yml" | ||||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| concurrency: | ||||||||||||||||||||
| group: ws1-gtest-gpu-${{ github.ref }} | ||||||||||||||||||||
| cancel-in-progress: false | ||||||||||||||||||||
|
|
||||||||||||||||||||
| permissions: | ||||||||||||||||||||
| contents: read | ||||||||||||||||||||
|
|
||||||||||||||||||||
| jobs: | ||||||||||||||||||||
| ws1-gtest: | ||||||||||||||||||||
| if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository | ||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||
| timeout-minutes: 90 | ||||||||||||||||||||
| strategy: | ||||||||||||||||||||
| fail-fast: false | ||||||||||||||||||||
| matrix: | ||||||||||||||||||||
| include: | ||||||||||||||||||||
| - { gpu_id: "NVIDIA RTX A4000", target_sm: "8.6", name: "sm86-cuda-triton" } | ||||||||||||||||||||
| - { gpu_id: "NVIDIA H100 80GB HBM3", target_sm: "9.0", force_sm90: "1", name: "sm90-c8-execute" } | ||||||||||||||||||||
| steps: | ||||||||||||||||||||
| - name: Checkout the commit under test | ||||||||||||||||||||
| uses: actions/checkout@v4 | ||||||||||||||||||||
| with: | ||||||||||||||||||||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||||||||||||||||||||
|
Comment on lines
+69
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Set
🔒 Proposed hardening - name: Checkout the commit under test
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
+ persist-credentials: false📝 Committable suggestion
Suggested change
🧰 Tools🪛 zizmor (1.29.0)[warning] 59-62: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||||||||||||||||||||
| persist-credentials: false | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Install runpodctl | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| wget -qO runpodctl https://github.com/runpod/runpodctl/releases/latest/download/runpodctl-linux-amd64 | ||||||||||||||||||||
| chmod +x runpodctl | ||||||||||||||||||||
| sudo mv runpodctl /usr/local/bin/runpodctl | ||||||||||||||||||||
| - name: Configure runpodctl | ||||||||||||||||||||
| run: runpodctl config --apiKey "${{ secrets.RUNPOD_API_KEY }}" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Setup SSH key | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| mkdir -p ~/.ssh && chmod 700 ~/.ssh | ||||||||||||||||||||
| printf '%s\n' "${{ secrets.RUNPOD_SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519 | ||||||||||||||||||||
| chmod 600 ~/.ssh/id_ed25519 | ||||||||||||||||||||
| - name: Run WS1 CUDA/Triton gtest + C8 on RunPod | ||||||||||||||||||||
| env: | ||||||||||||||||||||
| RUNPOD_API_KEY: ${{ secrets.RUNPOD_API_KEY }} | ||||||||||||||||||||
| PR_REPO_URL: ${{ github.event.pull_request.head.repo.clone_url || github.event.repository.clone_url }} | ||||||||||||||||||||
| PR_SHA: ${{ github.event.pull_request.head.sha || github.sha }} | ||||||||||||||||||||
| GPU_ID: ${{ matrix.gpu_id }} | ||||||||||||||||||||
| GPU_COUNT: "1" | ||||||||||||||||||||
| TARGET_SM: ${{ matrix.target_sm }} | ||||||||||||||||||||
| KERNEL_ALIGN_FORCE_SM90: ${{ matrix.force_sm90 }} | ||||||||||||||||||||
| TEST_SUITE: ws1-gtest | ||||||||||||||||||||
| run: bash ci/run_gpu_ci.sh | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Upload C8 execute JSON | ||||||||||||||||||||
| if: always() | ||||||||||||||||||||
| uses: actions/upload-artifact@v4 | ||||||||||||||||||||
| with: | ||||||||||||||||||||
| name: ws1-c8-execute-${{ matrix.name }} | ||||||||||||||||||||
| path: artifacts/ws1-c8-ci.json | ||||||||||||||||||||
| if-no-files-found: error | ||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,77 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # SPDX-License-Identifier: Apache-2.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # WS1 single-op gtest + C8 four-judgment GPU gate. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Assumes an editable install and a CUDA device. Fails closed on red cells | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # and on silent fallback (C3/C4 already reject those). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ROOT="$(cd "$(dirname "$0")/.." && pwd)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cd "$ROOT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PY="${PY:-python3}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Keep the artifact outside the repo so `_git_identity()` is not dirtied by | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # the file we are in the process of writing. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| OUT="${WS1_C8_JSON:-${TMPDIR:-/tmp}/ws1-c8-ci.json}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export RL_KERNEL_REQUIRE_EXT="${RL_KERNEL_REQUIRE_EXT:-1}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "[ws1-gtest] interpreter=$PY out=$OUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$PY" -m pytest -q \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tests/test_ws1_gtest_gpu.py \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tests/test_triton_batch_invariant_attention.py \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tests/test_four_judgment_matrix.py \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tests/test_ws1_candidate_evidence.py \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tests/test_op_checks.py \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tests/test_elementwise_inventory.py | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "[ws1-gtest] C3/C4 CUDA + Triton smoke (silu)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$PY" scripts/check_forward_invariance.py \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --op silu --candidate cuda --backend-profile cuda_bf16 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$PY" scripts/check_gradient_invariance.py \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --op silu --candidate cuda --backend-profile cuda_bf16 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$PY" scripts/check_forward_invariance.py \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --op silu --candidate triton --backend-profile triton_cuda_bf16 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$PY" scripts/check_gradient_invariance.py \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --op silu --candidate triton --backend-profile triton_cuda_bf16 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HOPPER=0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if "$PY" -c "import torch,sys; sys.exit(0 if torch.cuda.is_available() and torch.cuda.get_device_capability(0)[0]==9 else 1)"; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HOPPER=1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "[ws1-gtest] C8 --execute hopper=$HOPPER" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ "$HOPPER" = 1 ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$PY" scripts/sweep_ws1_four_judgments.py --execute --json > "$OUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$PY" scripts/sweep_ws1_four_judgments.py --execute --json --allow-pending-hopper > "$OUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$PY" - "$OUT" <<'PY' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path = sys.argv[1] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| payload = json.load(open(path, encoding="utf-8")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| counts = payload.get("counts") or {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| red = int(counts.get("red", 0)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print(f"[ws1-gtest] C8 counts={counts} source={payload.get('git')}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if red: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise SystemExit(f"C8 has {red} red cells") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cells = payload.get("cells") or [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not cells: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise SystemExit("C8 artifact contains no cells") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if int(counts.get("green", 0)) == 0: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise SystemExit("C8 artifact has no green cells") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| required = [c for c in cells if c.get("op_name") != "pack" and c.get("status") == "green"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not required: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise SystemExit("C8 artifact has no green required cells") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for cell in required: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not cell.get("judgment", "").endswith("invariance"): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not cell.get("actual_backend_id") or not cell.get("actual_kernel_config_id"): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise SystemExit( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| f"invariance cell missing provenance: {cell.get('profile')} {cell.get('op_name')}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("[ws1-gtest] C8 gate passed") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+55
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win The verifier passes when the payload has no cells. Line 56 defaults 🛡️ Proposed fix counts = payload.get("counts") or {}
red = int(counts.get("red", 0))
print(f"[ws1-gtest] C8 counts={counts} source={payload.get('git')}")
if red:
raise SystemExit(f"C8 has {red} red cells")
cells = payload.get("cells") or []
+if not cells:
+ raise SystemExit("C8 artifact contains no cells")
+if int(counts.get("green", 0)) == 0:
+ raise SystemExit("C8 artifact has no green cells")
required = [c for c in cells if c.get("op_name") != "pack" and c.get("status") == "green"]
+if not required:
+ raise SystemExit("C8 artifact has no green required cells")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PY | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
The
pushpath filter is narrower than thepull_requestfilter.The
pull_requesttrigger watchesrl_engine/kernels/ops/**,scripts/check_forward_invariance.py,scripts/check_gradient_invariance.py,scripts/ws1_candidate_evidence.py, and the WS1 test modules. Thepushtrigger omits all of them. A merge tomainthat changes only operator implementations does not re-run the C8 gate, so a red cell can land undetected. Align both lists.🔧 Proposed alignment
push: branches: [ main ] paths: - "rl_engine/kernels/gtest/**" + - "rl_engine/kernels/ops/**" - "rl_engine/testing/**" - "scripts/sweep_ws1_four_judgments.py" + - "scripts/check_forward_invariance.py" + - "scripts/check_gradient_invariance.py" + - "scripts/ws1_candidate_evidence.py" + - "tests/test_ws1_*.py" + - "tests/test_forward_invariance.py" + - "tests/test_gradient_invariance.py" + - "tests/test_four_judgment_matrix.py" + - "tests/test_triton_batch_invariant_attention.py" - "ci/run_ws1_gtest.sh" + - "ci/run_gpu_ci.sh" - ".github/workflows/ws1-gtest-gpu.yml"📝 Committable suggestion
🤖 Prompt for AI Agents