6.0 KiB
Test-selection — implementation state / handoff
Working notes for the diff-based CI test-selection system, so the work can be
resumed without re-deriving context. For how the system works / how to use it,
see TEST_SELECTION.md; this file is only about the state
of the implementation.
Last updated: 2026-06-18.
Status: complete & locally verified; in review on PR #8077
The system is implemented end-to-end and passes local checks. Opened as
deepspeedai/DeepSpeed#8077
(scoped to modal-torch-latest first; replicate to other workflows if accepted).
It has not yet run a live subset/deploy on modal, so the first real runs
should be watched.
Review fixes applied (Codex bot, PR #8077)
- P1 — run the selector from trusted code.
collect-testsnow restoresci/from the base branch before running the selector + self-tests, so a PR can't rewritetests_fetcher.pyto emitmode=noneand skip the Required check. (A PR'sci/changes still show in the diff and force a full run viaci/**.) Includes a bootstrap fallback: if base has notests_fetcher.pyyet, run all. - P1 — hidden-file artifact.
actions/upload-artifact@v4skips dot-prefixed paths by default;ci/.test_selection/is one. Addedinclude-hidden-files: truesodeploy's download doesn't fail.
Reminder: under
pull_request_target,deployrestoresci/from the base branch, so changes underci/*(the fetcher included) only take effect once merged. To validate the live behavior before merge, trigger via apull_request-based run or themodalCLI.
What was built
A diff-driven selector that, on a PR, runs only the tests/unit/v1 tests impacted
by the changed files, with a fail-safe fallback to the full suite. Driven by the
modal-torch-latest workflow.
Files
| File | State | Notes |
|---|---|---|
ci/tests_fetcher.py |
new/rewritten | Config-driven TestSelector class; import-graph selector. |
ci/test_tests_fetcher.py |
new | 12 stdlib self-tests over synthetic git repos. |
ci/torch_latest.py |
modified | Reads DS_TEST_LIST_FILE, runs pytest on the selected targets (falls back to full tests/unit/v1). |
.github/workflows/modal-torch-latest.yml |
rewritten | collect-tests (fetcher) gates deploy (modal). |
.github/workflows/TEST_SELECTION.md |
new | Full design + usage doc. |
.github/workflows/TEST_SELECTION_STATE.md |
new | This file. |
CONTRIBUTING.md |
modified | "Diff-based CI test selection" section + link. |
.gitignore |
modified | Ignores ci/.test_selection/. |
Key design decisions (and why)
- Always-runs Required job, selects instead of skips.
modal-torch-latestis a Required check, so path filters can't skip it.collect-testsdecidesall|subset|none;noneskipsdeploywhile still satisfying the Required status. deploytests PR code but restoresci/from base. Selection must reflect PR code, but the orchestration that holds modal/HF secrets must not be PR-controlled. (Security trade-off accepted earlier in the work.)- Opaque hub modules + curated run-all globs.
deepspeed,deepspeed.comm,deepspeed.acceleratorare opaque in the graph to stop universal fan-out; core hubs (deepspeed/__init__.py,runtime/engine.py,comm/**,accelerator/**, …) instead live in the run-all globs. (Coarseness fix accepted earlier.) - Fail-safe to
all, nevernone. Every uncertain case (no base, no merge-base, parse error, unexpected exception) widens to the full suite.
Improvements implemented in the latest pass (items #3–#11)
- #3 Degrade to
allon any selector error (top-level guard inmain()). - #4
DYNAMIC_EDGESmap for runtime/dynamic deps the AST can't see (seeded:deepspeed/module_inject/** → tests/unit/v1/moe/**). - #5 Deleted
.pyonly forcesallwhen a surviving file still imports it (dangling import); clean deletions no longer over-trigger. - #6 GitHub job summary (
$GITHUB_STEP_SUMMARY) with mode/reason/file list;reasonalso on$GITHUB_OUTPUT. - #7
--explainprints import chains from changed files to selected tests. - #8 Escape hatches documented in
CONTRIBUTING.md+TEST_SELECTION.md. - #9 Self-tests in
ci/test_tests_fetcher.py, also run incollect-tests. - #10 Robust merge-base: explicit check,
allif missing; workflow keepsfetch-depth: 0with rationale. - #11 Multi-workflow config:
WORKFLOWSregistry +WorkflowConfig+--workflowflag.
Verification done locally
python ci/tests_fetcher.pyself-tests: 12/12 pass (narrowing, shared importers, core/comm/fixture run-all, commit tag, docs-only → none, new test file, clean vs. dangling delete, dynamic edge, missing base).- Real-repo smoke:
--base,--explain,--workflowvalidation all behave. - Confirmed
$GITHUB_OUTPUT+$GITHUB_STEP_SUMMARYemission and the #3 error-fallback path directly. - No linter errors.
Re-run the core check any time:
python ci/test_tests_fetcher.py
python ci/tests_fetcher.py --base origin/master --explain
Open items / possible follow-ups
- Live validation: watch the first real PR; confirm
collect-testsartifact hand-off anddeploygating behave on Actions + modal. DYNAMIC_EDGESis minimal. Only one seeded edge. Expand as blind spots are found (tests that fail onmaster's full run but weren't selected on their PR are the signal).- Single workflow wired. The engine is config-driven (#11) but only
modal-torch-latestis registered/wired. Other GPU workflows could adopt it by adding aWorkflowConfigand mirroring thecollect-testsjob. - Run-all glob tuning. The core-hub list is a conservative first cut; revisit if it proves too coarse (full runs on minor edits) or too narrow (missed impact).
- No telemetry. Consider logging selection stats over time to tune globs/opaque-modules against real false-positive/negative rates.