Files
hao-ai-lab-FastVideo/docs/contributing/ci_architecture.md
T
alexzmsandmergify[bot] 0df1445d0d [ci] add GPU model loading tests for fastvideo.train (PR 4/9) (#1274)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2026-05-12 16:54:37 -07:00

334 lines
14 KiB
Markdown

# CI Architecture
## Overview
FastVideo uses a three-tier CI pipeline designed to keep feedback fast on every push while
protecting `main` through a full GPU regression suite before any merge.
```
PR push
│
├─► Tier 1: Pre-commit (~2 min)
│ GitHub Actions / ubuntu-latest
│ yapf, ruff, mypy, codespell, pymarkdown, actionlint, check-filenames
│
└─► Tier 2: Fastcheck (~10-20 min, path-filtered)
Buildkite / Modal GPU instances
Only runs tests for paths you changed
│ (developer comments /merge or maintainer adds 'ready' label)
▼
Tier 3: Full Suite (~60-90 min)
Buildkite / Modal GPU instances
All integration, SSIM, training, and performance tests
Runs on the PR branch directly
│
pass ──► Mergify auto-squash-merges to main, branch deleted
fail ──► fix the regression, push, and /merge again
```
---
## CI Tiers
### Tier 1: Pre-commit (every PR push)
| Attribute | Value |
|-----------|-------|
| Triggered by | Every push to any PR branch, plus pushes to `main` |
| Runs on | GitHub Actions, `ubuntu-latest` |
| Duration | ~2 minutes |
**Checks run** (from `.pre-commit-config.yaml`, stage: `manual`):
| Hook | What it checks |
|------|---------------|
| `yapf` | Python code formatting |
| `ruff` | Python linting and auto-fixable style issues |
| `codespell` | Spelling errors in code and docs |
| `pymarkdown` | Markdown formatting |
| `actionlint` | GitHub Actions workflow syntax |
| `mypy` | Static type checking (Python 3.10 target) |
| `check-filenames` | No spaces in tracked filenames |
A failure here means code style or type issues. Run `pre-commit run --all-files` locally to
replicate CI results before pushing.
---
### Tier 2: Fastcheck (path-filtered, every PR push)
| Attribute | Value |
|-----------|-------|
| Triggered by | Every push; the monorepo-diff plugin skips tests for unchanged paths |
| Runs on | Buildkite, Modal GPU instances |
| Duration | ~10-20 minutes per test (run in parallel) |
**Tests and their path triggers:**
| Buildkite label | `TEST_TYPE` | Triggers when you change |
|-----------------|-------------|--------------------------|
| Encoder Tests | `encoder` | `fastvideo/models/encoders/**`, `fastvideo/models/loader/**`, `fastvideo/tests/encoders/**`, `pyproject.toml`, `docker/Dockerfile.python3.12` |
| VAE Tests | `vae` | `fastvideo/models/vaes/**`, `fastvideo/models/loader/**`, `fastvideo/tests/vaes/**`, `pyproject.toml`, `docker/Dockerfile.python3.12` |
| Transformer Tests | `transformer` | `fastvideo/models/dits/**`, `fastvideo/models/loader/**`, `fastvideo/tests/transformers/**`, `fastvideo/layers/**`, `fastvideo/attention/**`, `pyproject.toml`, `docker/Dockerfile.python3.12` |
| Kernel Tests | `kernel_tests` | `fastvideo-kernel/**`, `pyproject.toml`, `docker/Dockerfile.python3.12` |
| Unit Tests | `unit_test` | `fastvideo/**`, `.buildkite/**`, `.github/**`, `pyproject.toml`, `docker/Dockerfile.python3.12` |
A Fastcheck failure means a component-level regression. Check the Buildkite build log for the
failing test's output.
---
### Tier 3: Full Test Suite (triggered by `ready` label)
| Attribute | Value |
|-----------|-------|
| Triggered by | Adding the `ready` label to the PR (via `/merge` command), or a `/test full` command |
| Runs on | Buildkite, Modal GPU instances |
| Duration | 60-90 minutes total (tests run in parallel, path-filtered) |
**Tests:**
| Buildkite label | `TEST_TYPE` | Timeout |
|-----------------|-------------|---------|
| SSIM Tests | `ssim` | 90 min |
| LoRA Inference Tests | `inference_lora` | 20 min |
| Training Tests | `training` | 15 min |
| Distillation DMD Tests | `distillation_dmd` | 15 min |
| Self-Forcing Tests | `self_forcing` | 15 min |
| LoRA Training Tests | `training_lora` | 15 min |
| Training Tests VSA | `training_vsa` | 15 min |
| Inference Tests VMoBA | `inference_vmoba` | 15 min |
| Performance Tests | `performance` | 30 min |
| API Server Tests | `api_server` | 30 min |
| Train Framework Tests | `train_framework` | 30 min |
If a Full Suite test fails, check the Buildkite build log for the failing step's output.
Fix the regression, push, and comment `/merge` again to re-trigger.
---
## Auto-merge Flow
Mergify prevents untested code from landing on `main` by gating squash-merge on the Full
Suite passing directly on the PR branch.
**How it works:**
1. A developer comments `/merge` on an approved PR (or a maintainer adds the `ready` label).
2. The `ready` label triggers `ci-trigger-full-suite.yml`, which calls the Buildkite API to
run the Full Suite on the PR branch itself.
3. While the Full Suite runs, Mergify also auto-rebases the PR branch against `main` if it
is behind and has no conflicts.
4. Once the Full Suite posts `full-suite-passed`, Mergify checks all **merge conditions**:
- `pre-commit` check is green
- `fastcheck-passed` check is green
- `full-suite-passed` check is green
- At least 1 approved review (`#approved-reviews-by>=1`)
- PR title starts with a valid `[type]` tag
- PR is not a draft
- No merge conflicts
5. If all conditions pass, Mergify squash-merges to `main` automatically. The branch is
deleted after merge.
6. If the Full Suite fails, the developer fixes the issue, pushes, and comments `/merge`
again to re-trigger.
**Merge conditions summary:**
| Condition | Meaning |
|-----------|---------|
| `check-success~=pre-commit` | Tier 1 pre-commit must be green |
| `check-success=fastcheck-passed` | Tier 2 Fastcheck must be green |
| `check-success=full-suite-passed` | Tier 3 Full Suite must be green |
| `#approved-reviews-by>=1` | At least one approved review |
| `title~=(?i)^\[(feat|bugfix|...)` | PR title has a valid type tag |
| `-draft` | PR is not in draft state |
| `-conflict` | No merge conflicts with base branch |
| `-closed` | PR is still open |
---
## Label System
Labels are applied automatically. You don't need to set them manually.
### Type Labels (from PR title prefix)
Applied by Mergify based on the `[tag]` at the start of the PR title.
| Label | Matched title prefix | Meaning |
|-------|---------------------|---------|
| `type: feat` | `[feat]` or `[feature]` | New feature or capability |
| `type: bugfix` | `[bugfix]` or `[fix]` | Bug fix |
| `type: refactor` | `[refactor]` | Code restructuring, no behavior change |
| `type: perf` | `[perf]` | Performance improvement |
| `type: ci` | `[ci]` | CI/CD or tooling changes |
| `type: docs` | `[doc]` or `[docs]` | Documentation only |
| `type: misc` | `[misc]` or `[chore]` | Housekeeping, dependency bumps |
| `type: new-model` | `[new-model]` | Adding a new model |
### Scope Labels (from changed files)
Applied by Mergify based on which paths you modified. Multiple scope labels can be added.
| Label | File paths that trigger it |
|-------|---------------------------|
| `scope: training` | `fastvideo/train/`, `fastvideo/training/`, `fastvideo/distillation/`, `examples/train/`, `examples/training/`, `examples/distill/` |
| `scope: inference` | `fastvideo/pipelines/basic/`, `fastvideo/pipelines/stages/`, `fastvideo/pipelines/samplers/`, `fastvideo/entrypoints/`, `fastvideo/worker/`, `fastvideo/api/sampling_param.py`, `fastvideo/configs/pipelines/`, `examples/inference/` |
| `scope: attention` | `fastvideo/attention/` |
| `scope: kernel` | `fastvideo-kernel/`, `csrc/` |
| `scope: data` | `fastvideo/dataset/`, `fastvideo/pipelines/preprocess/`, `examples/preprocessing/` |
| `scope: infra` | `.github/`, `.buildkite/`, `fastvideo/tests/`, `docker/` |
| `scope: distributed` | `fastvideo/distributed/` |
| `scope: docs` | `docs/` |
| `scope: ui` | `ui/` |
| `scope: model` | `fastvideo/models/`, `fastvideo/layers/`, `fastvideo/configs/models/` |
### Process Labels
| Label | Who sets it | Meaning |
|-------|-------------|---------|
| `ready` | Developer (`/merge` command) or maintainer | Triggers Full Suite and enables auto-merge |
| `needs-rebase` | Mergify (automatic) | PR has merge conflicts; rebase needed |
| `do-not-merge` | Maintainer | Blocks queue entry regardless of other conditions |
---
## PR Title Format
All PR titles targeting `main` must start with a bracketed type tag. This is enforced by a
Mergify merge protection rule and is required before a PR can be squash-merged.
**Format:**
```
[type] Short description
```
**Valid type tags:**
`feat`, `feature`, `bugfix`, `fix`, `refactor`, `perf`, `ci`, `doc`, `docs`, `misc`, `chore`,
`kernel`, `new-model`
**Valid examples:**
```
[feat] Add causal Wan pipeline
[bugfix] Fix VAE temporal tiling corruption
[refactor] Restructure training framework
[perf] Optimize FlashAttention kernel dispatch
[docs] Add inference guide for LoRA
[new-model] Port HunyuanVideo 1.5 to FastVideo
```
**Invalid examples (will block merge):**
```
Add causal Wan pipeline ← missing type tag
FEAT: Add pipeline ← wrong format
feat: Add pipeline ← square brackets required
```
If your title is invalid, Mergify posts a comment explaining the required format and the
merge protection check will remain failed until you update the title.
---
## Slash Commands
Slash commands let contributors and maintainers trigger CI actions directly from PR comments.
**Write permission to the repository is required.**
The command is recognized within a few seconds. The workflow reacts with a 🚀 emoji to confirm.
### `/merge`
```
/merge
```
Adds the `ready` label to the PR, which triggers the Full Suite on your PR branch and
enables Mergify to auto-squash-merge once all conditions pass.
The command first removes the `ready` label if it is already present, then re-adds it. This
ensures the `labeled` event fires and a fresh Full Suite build is started even on a re-try.
### `/test <name>`
```
/test <name>
```
Triggers a specific Buildkite test or suite on the current PR branch.
| Command | Runs | Maps to `TEST_TYPE` |
|---------|------|---------------------|
| `/test encoder` | Encoder Tests (Fastcheck) | `encoder` |
| `/test vae` | VAE Tests (Fastcheck) | `vae` |
| `/test transformer` | Transformer Tests (Fastcheck) | `transformer` |
| `/test kernel` | Kernel Tests (Fastcheck) | `kernel_tests` |
| `/test unit` | Unit Tests (Fastcheck) | `unit_test` |
| `/test ssim` | SSIM regression tests | `ssim` |
| `/test training` | Training pipeline tests | `training` |
| `/test lora-inference` | LoRA inference tests | `inference_lora` |
| `/test lora-training` | LoRA training tests | `training_lora` |
| `/test distillation` | DMD distillation tests | `distillation_dmd` |
| `/test self-forcing` | Self-Forcing tests | `self_forcing` |
| `/test vsa` | VSA training tests | `training_vsa` |
| `/test vmoba` | VMoBA inference tests | `inference_vmoba` |
| `/test performance` | Performance benchmarks | `performance` |
| `/test api` | API server integration tests | `api_server` |
| `/test train-framework` | `fastvideo.train` GPU model loading + per-method tests | `train_framework` |
| `/test full` | Entire Full Suite | all (with `TEST_SCOPE=full`) |
| `/test fastcheck` | Entire Fastcheck suite | fastcheck (with `TEST_SCOPE=fastcheck`) |
| `/test pre-commit` | Pre-commit checks on PR code | — (runs `ci-precommit.yml` via `workflow_call`) |
**Re-running failed tests:** When you use `/test <name>` to re-run a specific failed test,
the resulting Buildkite check uses the same name as the original (e.g., `/test encoder`
creates `buildkite/ci/microscope-encoder-tests`). This overwrites the failed check status.
Once all tests in a tier pass, the aggregate status (`fastcheck-passed` or
`full-suite-passed`) is automatically updated to `success` by the `ci-aggregate-status.yml`
workflow.
**How aggregate status refresh works:**
1. `/test <name>` triggers a Buildkite build with `TEST_SCOPE=direct`. The test step uses
the same label as its fastcheck/full-suite counterpart, so the resulting GitHub check
overwrites the original.
2. When the build completes, Buildkite's `notify` posts a `direct-test-completed` commit
status. This is the only signal that triggers the aggregate workflow — intermediate step
status updates do not trigger it.
3. `ci-aggregate-status.yml` fires, calls `getCombinedStatusForRef` to fetch the latest
status for every context on that commit (each context returns only its most recent
state), groups them by prefix (`microscope-*` → fastcheck, `test-tube-*`/`bar-chart-*`
→ full suite), and posts `fastcheck-passed: success` or `full-suite-passed: success` if
all entries in the group are `success`.
4. Tests that were never triggered (skipped by monorepo-diff) have no status entry and do
not block the aggregate.
---
## Auto Branch Cleanup
After a PR is squash-merged to `main`, Mergify automatically deletes the head branch.
Protected branches (`main`, `master`, `release/*`) are never deleted.
---
## Workflow File Reference
| Filename | Trigger | What it does |
|----------|---------|-------------|
| `ci-precommit.yml` | Every push / PR against `main` | Runs pre-commit hooks (yapf, ruff, mypy, codespell, pymarkdown, actionlint, check-filenames) |
| `ci-trigger-full-suite.yml` | `ready` label added to a PR | Calls Buildkite API to run Full Suite on the PR branch |
| `ci-slash-commands.yml` | PR comment starting with `/merge` or `/test` | Handles slash commands; adds `ready` label or triggers Buildkite |
| `ci-aggregate-status.yml` | Any Buildkite commit status update | Checks if all tests in a tier passed; updates `fastcheck-passed` or `full-suite-passed` |
| `community-issue-labeler.yml` | Issue opened or edited | Auto-labels issues by keyword matching against title and body |
| `community-welcome.yml` | First contribution | Posts a welcome comment for first-time contributors |
| `community-stale.yml` | Scheduled | Marks and closes stale issues and PRs |
| `infra-build-image.yml` | Manual (`workflow_dispatch`) | Builds Docker images for CI |
| `infra-docs.yml` | Changes to `docs/` merged to `main` | Builds and deploys documentation to GitHub Pages |
| `publish-fastvideo.yml` | Version bump | Publishes `fastvideo` package to PyPI |
| `publish-kernel.yml` | Version bump | Publishes `fastvideo-kernel` package to PyPI |
| `publish-comfyui.yml` | Version bump | Publishes ComfyUI node package to PyPI |