Skip to main content
This guide is for contributors landing small features and fixes. It answers three things: how to add a test to CI and be sure it actually runs, how to read a red check and decide whether it’s your change or the infrastructure, and how to report a machine issue or a flaky test. You never edit the CI workflow YAML to add a test — read on.

Add a test to CI

CI selection is driven by a one-line declaration at the top of each test file, not by the workflow. To add a test you drop a test_*.py file in the right place and declare it; the runner discovers it automatically. CPU / pure-Python tests go under tests/fast/. No declaration needed — every test_*.py there is auto-registered as a CPU test and runs on every PR. GPU tests go under tests/e2e/ (or tests/fast-gpu/ for small single-file GPU tests) and need exactly one top-level declaration:
Pick the suite by the hardware your test needs. The simplest reliable choice is to copy the suite= of an existing test most like yours.

Verify it definitely runs

A test that isn’t picked up fails silently — it just never appears, and CI stays green. Confirm pickup before you rely on it:
  1. Locally, from the repo root, list the plan for your suite (no GPU needed):
    Your file must appear under Enabled N test(s). Add --nightly when verifying a nightly=True registration. This command also validates registration across all tests — if any discovered file is missing its declaration, it errors here.
  2. On the PR, open the matching stage job and read the Resolve suite plan step — it prints the same plan, so you can confirm your file is listed in the real environment.
If your file does not show up, check, in order:
  • It’s named test_*.py and lives under tests/fast, tests/fast-gpu, tests/e2e, or tests/ci (the only discovered roots).
  • It has exactly one top-level register_*_ci(...) call (GPU tests only; not inside a function, not import-aliased).
  • The suite= string is one of the suites in the table (a typo’d suite has no job and never runs).

Will it run on my PR?

labels gates which PRs trigger your test within its eligible cadence. GPU registrations require at least one domain label:
  • labels=["megatron"] → runs only when the PR carries the GitHub label run-ci-megatron (the run-ci- prefix is added on the PR side). This keeps the heavy GPU matrix off unrelated PRs.
Cadence is independent of labels: nightly=True excludes a registration from regular cadence, while nightly, weekly, and release runs include both ordinary and nightly=True registrations. So if your test is gated and you don’t see it run, add the matching run-ci-<label> label to your PR. To force the full suite regardless of labels, a maintainer can add run-ci-all. Valid labels live in tests/ci/labels.py; using one outside that list is a hard error at collection time.

First PR from a fork: CI waits for approval

Until your first PR merges, GitHub holds every CI run of your fork PR behind a maintainer’s “Approve and run” — after every push. There is no separate trust flag: any run-ci-* label a maintainer adds (the same labels that select tests) also approves the held runs, for that push and each one after. Removing the labels restores manual approval.

When CI fails: yours or the infra?

Open the failing job and read the log first. Most failures fall cleanly into one of two buckets. Likely your change — fix it locally before re-running: Likely infrastructure, not your fault — re-run the job once first (transient issues clear on retry); if it reproduces, report it: Rule of thumb: if the failure is in code or tests your PR didn’t touch, and a re-run behaves differently, it’s infra or flakiness — not yours.

Report a machine / infra issue

When a re-run still shows an infra signal from the table above, open a GitHub Issue labeled ci-infra. Include:
  • The failing job URL (the Actions page for that job).
  • The runner name (runner_name, shown at the top of the job log).
  • The suite / stage (e.g. stage-c-4-gpu-h200) and the step that failed.
  • A short log snippet of the error (the infra signal line).
  • What you already tried (e.g. “re-ran twice, same ENOSPC”).
A maintainer maps the runner to its host and fixes the machine; you don’t need runner access. For a fast sanity check before filing, you can ask in the #miles-rl channel of the SGLang Slack, but the GitHub Issue is the tracked record.

Report a flaky test

A test is flaky when it fails non-deterministically — it passes on a re-run with no code change, usually on a numeric/accuracy/timing assertion. PR CI runs each test once, so a flake will fail your check; re-run the job to confirm the failure isn’t your change. Report a test that flakes repeatedly so a maintainer can stabilize or quarantine it. Open a GitHub Issue labeled flaky with:
  • The test file path (e.g. tests/e2e/megatron/test_x.py).
  • The assertion that failed (the AssertionError line).
  • Run URLs for both a passing and a failing run, if you have them.
To unblock other PRs, a maintainer may temporarily set disabled="<reason + issue link>" on the test’s register_*_ci(...) — that reports it as skipped (not deleted) until the flake is fixed. Don’t disable a test in your own feature PR unless a maintainer asks.