Skip to content

Add Buildkite CI pipeline (CPU jobs + manual-gated GPU suites) and remove PR test on GHA - #239

Merged
khluu merged 11 commits into
mainfrom
claude/hopeful-hamilton-h7zyas
Jun 16, 2026
Merged

Add Buildkite CI pipeline (CPU jobs + manual-gated GPU suites) and remove PR test on GHA#239
khluu merged 11 commits into
mainfrom
claude/hopeful-hamilton-h7zyas

Conversation

@khluu

@khluu khluu commented Jun 11, 2026

Copy link
Copy Markdown
Member

Summary

Buildkite port of vime CI, mirroring the jobs in .github/workflows/pr-test.yml.j2. GitHub Actions keeps running in parallel and stays authoritative until Buildkite proves itself.

  • .buildkite/pipeline.yml — always-on CPU steps (pre-commit, plugin-contracts, agent-adapter, unit), run on every PR and push to main.
  • .buildkite/gpu_suites.py — the run-ci-* GPU suites (short, vllm-config, megatron, precision, ckpt) behind a manual block-step gate (PR labels can't trigger Buildkite), generating one K8s pod per test on the mithril-h100-pool H100 queue.
  • .buildkite/README.md — one-time Buildkite setup and how to keep the test lists in sync with the GHA matrix.
  • Drops 4 orphaned test_arguments.py unit tests left behind by the sync: complete slime #1920, #1967, #1985 #232 arguments refactor.

gsm8k_async_short (80 GB OOM) and parallel_check (CP-invariance) are marked soft_fail pending follow-up.

Also deleted PR workflows on GHA

https://claude.ai/code/session_01BSqHKH1FafdRobA7ZeRzBQ

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a Buildkite pipeline configuration and generator script to port always-on CPU CI jobs from GitHub Actions to Buildkite. The review feedback suggests making the docker_command helper more robust by handling trailing spaces in extra_args and centrally passing GIT_CONFIG_PARAMETERS to avoid Git ownership errors. Consequently, the manual git config workaround in pre_commit_step and the trailing space in unit_step can be cleaned up. Additionally, a minor typo in the README documentation should be corrected.

Comment thread .buildkite/generate_pipeline.py Outdated
Comment on lines +76 to +83
def docker_command(image: str, script: str, extra_args: str = "") -> str:
"""`docker run` wrapper matching the GHA jobs' raw-docker style."""
return (
"docker run --rm --ipc=host --shm-size=4g "
f"{extra_args}"
f'-v "$PWD:{REPO_MOUNT}" -w {REPO_MOUNT} '
f"{image} bash -c {shlex.quote(script)}"
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The current implementation of docker_command is fragile because it directly concatenates extra_args without ensuring proper spacing. If a caller passes extra_args without a trailing space (e.g., "--network host"), it will result in a malformed command (e.g., --network host-v "$PWD:/workspace").

Additionally, running git commands inside containers (which run as root) on a workspace owned by the host's buildkite-agent user will trigger Git's "dubious ownership" error. Centrally passing GIT_CONFIG_PARAMETERS as an environment variable in docker_command solves this globally for all steps, eliminating the need for manual git config workarounds in individual steps.

def docker_command(image: str, script: str, extra_args: str = "") -> str:
    """`docker run` wrapper matching the GHA jobs' raw-docker style."""
    # Pass GIT_CONFIG_PARAMETERS to avoid "dubious ownership" errors since the container runs as root
    # while the workspace is owned by the host's buildkite-agent user.
    extra = f"{extra_args.strip()} " if extra_args.strip() else ""
    return (
        "docker run --rm --ipc=host --shm-size=4g "
        '-e GIT_CONFIG_PARAMETERS="\\'safe.directory=*\\'" '
        f"{extra}"
        f'-v "$PWD:{REPO_MOUNT}" -w {REPO_MOUNT} '
        f"{image} bash -c {shlex.quote(script)}"
    )

Comment thread .buildkite/generate_pipeline.py Outdated
Comment on lines +124 to +134
def pre_commit_step() -> dict:
script = "\n".join(
[
"set -euo pipefail",
# The checkout is owned by the host's buildkite-agent user; the
# container runs as root, so git refuses to touch it without this.
f"git config --global --add safe.directory {REPO_MOUNT}",
"pip install -q pre-commit",
"pre-commit run --all-files --show-diff-on-failure --color=always",
]
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Since safe.directory is now centrally handled via GIT_CONFIG_PARAMETERS in docker_command, we can clean up and simplify pre_commit_step by removing the manual git config workaround.

def pre_commit_step() -> dict: 
    script = "\n".join(
        [
            "set -euo pipefail",
            "pip install -q pre-commit",
            "pre-commit run --all-files --show-diff-on-failure --color=always",
        ]
    )
    return step(
        ":lint-roller: pre-commit",
        "pre-commit",
        CPU_QUEUE_SMALL,
        docker_command(PYTHON_IMAGE, script),
        timeout=15,
        gated=False,
    )

Comment thread .buildkite/generate_pipeline.py Outdated
Comment on lines +170 to +176
return step(
":pytest: unit & utils tests (in-image)",
"unit",
CPU_QUEUE_MEDIUM,
docker_command(CI_IMAGE, script, extra_args="--network host "),
timeout=45,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

With the updated docker_command handling trailing spaces robustly, we can remove the manual trailing space from the extra_args parameter here.

Suggested change
return step(
":pytest: unit & utils tests (in-image)",
"unit",
CPU_QUEUE_MEDIUM,
docker_command(CI_IMAGE, script, extra_args="--network host "),
timeout=45,
)
return step(
":pytest: unit & utils tests (in-image)",
"unit",
CPU_QUEUE_MEDIUM,
docker_command(CI_IMAGE, script, extra_args="--network host"),
timeout=45,
)

Comment thread .buildkite/README.md Outdated
| `agent-adapter` | `agent-adapter-test` | `small_cpu_queue_premerge` | PR / manual builds |
| `unit` | `e2e-test-unit` | `medium_cpu_queue_premerge` | PR / manual builds |

All non-gate steps `depend_on` the pre-commit gate, matching the GHA

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

There is a minor typo in the documentation. The Buildkite YAML key is depends_on (with an s), but the README refers to it as depend_on.

Suggested change
All non-gate steps `depend_on` the pre-commit gate, matching the GHA
All non-gate steps `depends_on` the pre-commit gate, matching the GHA

@khluu khluu changed the title Add Buildkite CI pipeline for always-on CPU jobs Add Buildkite CI pipeline (CPU jobs + manual-gated GPU suites) Jun 16, 2026
@aoshen02
aoshen02 force-pushed the claude/hopeful-hamilton-h7zyas branch from 055f361 to 5fbcdeb Compare June 16, 2026 02:32
@read-the-docs-community

read-the-docs-community Bot commented Jun 16, 2026

Copy link
Copy Markdown

@aoshen02

aoshen02 commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

shrink the max_batched_tokens to 2048 as it will oom in h100, it's slime's problem and will optimized in the future

@aoshen02
aoshen02 force-pushed the claude/hopeful-hamilton-h7zyas branch from b78da15 to fa6af9f Compare June 16, 2026 08:53
claude and others added 10 commits June 16, 2026 08:58
Port the always-on jobs from .github/workflows/pr-test.yml.j2 (pre-commit
gate, plugin contracts, agent adapter, in-image unit tests) to a single
dynamically generated Buildkite pipeline targeting the vLLM elastic-stack
CPU queues. GitHub Actions keeps running in parallel and stays
authoritative; GPU suites are not migrated yet.

https://claude.ai/code/session_01BSqHKH1FafdRobA7ZeRzBQ
Signed-off-by: aoshen02 <aoshen@inferact.ai>
Drop generate_pipeline.py in favor of a plain static .buildkite/pipeline.yml
defining the four always-on CPU steps directly (pre-commit gate, plugin
contracts, agent adapter, in-image unit tests). Simpler to read and review for
a first cut; the GHA workflow stays authoritative and GPU suites are still out
of scope.

Pass GIT_CONFIG_PARAMETERS into every container so git (in pre-commit) doesn't
abort with "dubious ownership" on the host-owned checkout, and fix the
depends_on typo in the README.

https://claude.ai/code/session_01BSqHKH1FafdRobA7ZeRzBQ
Signed-off-by: aoshen02 <aoshen@inferact.ai>
plugin-contracts failed in build #3 on tests/utils/test_hf_checkpoint_saver.py
(ModuleNotFoundError: safetensors): the dep list predated the slime sync in
#232 which added requests/ray/safetensors to the GHA template. Mirror it.

GitHub PR labels can't trigger Buildkite jobs, so expose the run-ci-* GPU
suites behind a block step instead: unblocking offers a multi-select of suites
(short / vllm-config / megatron / precision / ckpt) and gpu_suites.py uploads
one step per test with the same gpu_lock_exec + docker invocations and
per-test DEEPEP/FP8/EVAL env combos as the GHA jobs. blocked_state: passed
keeps the commit status green when the gate is left untouched. GPU steps
target a new vime-gpu agent queue (self-hosted hosts; see README).

https://claude.ai/code/session_01BSqHKH1FafdRobA7ZeRzBQ
Signed-off-by: aoshen02 <aoshen@inferact.ai>
Build #4's unblock test showed the CI cluster rejects uploads targeting a
nonexistent queue, and rather than minting a new queue, follow the pattern
vllm-omni already uses for mithril-h100-pool: each GPU job is a Kubernetes pod
(agent-stack-k8s kubernetes plugin) on an H100 SXM node with nvidia.com/gpu
limits (4 or 8), memory-backed /dev/shm, and /mnt/hf-cache mounted as HF_HOME.
vime tests hf-download their models, so the warm HF cache replaces the GHA
runners' /mnt/nvme0n1/vime_ci mounts; the docker-run wrapper goes away since
the pod runs the vime CI image directly.

Also pin GLOO/TP_SOCKET_IFNAME=lo in the plugin-contracts container:
test_metric_report_dist hung intermittently (build #4 timed out at 30 min)
because gloo can pick a non-loopback interface inside a bridge-network
container.

https://claude.ai/code/session_01BSqHKH1FafdRobA7ZeRzBQ
Signed-off-by: aoshen02 <aoshen@inferact.ai>
test_qwen3.5_0.8B_gsm8k_async_short OOMed in compute_log_probs on the mithril
pool's 80 GB H100s (build #6) with 7 GiB reserved-but-unallocated — the
allocator-fragmentation case PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
exists for. Scope it to this test's pod only (vLLM sleep-mode CuMemAllocator
can conflict with expandable segments) via verbatim pass-through of non-VIME
env overrides. The other short tests passed on H100 pods unchanged.

https://claude.ai/code/session_01BSqHKH1FafdRobA7ZeRzBQ
Signed-off-by: aoshen02 <aoshen@inferact.ai>
Builds #6/#7 isolated two test-level failures on the mithril 80 GB H100s,
neither a pipeline issue:
- gsm8k_async_short OOMs as tuned (67 GiB live on the actor GPU after
  expandable_segments eliminated fragmentation; its sync twin passes).
- parallel_check's CP=2 grad norm diverges ~4% from the same-node baseline
  recording, a topology-sensitive numerical invariance question.

Mark exactly these two soft_fail so they keep running and stay visible on
Buildkite without failing the build; their authoritative gate remains the
GHA label jobs.

https://claude.ai/code/session_01BSqHKH1FafdRobA7ZeRzBQ
Signed-off-by: aoshen02 <aoshen@inferact.ai>
Revert the soft_fail: per review, the gsm8k_async_short OOM and the
parallel_check CP-invariance divergence should stay visible as hard failures
on Buildkite until the underlying issues are fixed. Keep the diagnostic
comments and the test-scoped expandable_segments setting.

https://claude.ai/code/session_01BSqHKH1FafdRobA7ZeRzBQ
Signed-off-by: aoshen02 <aoshen@inferact.ai>
Re-apply b334784 (reverted in 0a98010): per the follow-up decision, mark
gsm8k_async_short and parallel_check soft_fail so they keep running visibly
on mithril without failing the build, with the GHA label jobs as their
authoritative gate until the OOM tuning and CP-invariance questions are
resolved.

https://claude.ai/code/session_01BSqHKH1FafdRobA7ZeRzBQ
Signed-off-by: aoshen02 <aoshen@inferact.ai>
Root cause: Qwen3.5's 248K vocab produces [T, 248320] fp32 logits tensors.
calculate_log_probs_and_entropy holds 5 copies simultaneously (2 clones +
2 intermediates + original). At max-tokens-per-gpu=9216, each copy is
~8.5 GB → 42.6 GB from logits alone, exceeding H100 80 GB with
activations and reserved pool fragmentation.

Fix: reduce max-tokens-per-gpu from 9216 to 2048. Peak drops from 117.6 GB
to 39.6 GB (measured on H200), well within H100's 80 GB. GSM8K's longest
sequence is ~1200 tokens, so 2048 still fits all samples.

Also removes gsm8k_async_short from SOFT_FAIL_ON_H100 (no longer needed)
and the expandable_segments workaround.

parallel_check remains soft-fail: ~11% flake rate on TP4+per-token-loss,
confirmed same behavior in slime (Megatron FP reduction-order issue).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: aoshen02 <aoshen@inferact.ai>
Signed-off-by: aoshen02 <aoshen@inferact.ai>
@aoshen02
aoshen02 force-pushed the claude/hopeful-hamilton-h7zyas branch from fa6af9f to 2f01009 Compare June 16, 2026 08:59
Signed-off-by: khluu <khluu000@gmail.com>
@khluu khluu changed the title Add Buildkite CI pipeline (CPU jobs + manual-gated GPU suites) Add Buildkite CI pipeline (CPU jobs + manual-gated GPU suites) and remove PR test on GHA Jun 16, 2026
@khluu
khluu merged commit 4a550b6 into main Jun 16, 2026
1 of 3 checks passed
@CalvinXKY
CalvinXKY deleted the claude/hopeful-hamilton-h7zyas branch June 16, 2026 11:33
@CalvinXKY
CalvinXKY restored the claude/hopeful-hamilton-h7zyas branch June 16, 2026 11:36
@aoshen02
aoshen02 deleted the claude/hopeful-hamilton-h7zyas branch June 23, 2026 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants