Skip to content

srt-slurm: resolve CONFIG_FILE recipe selectors in launchers and the matrix - #3390

Open
cquil11 wants to merge 2 commits into
mainfrom
ix/srt-recipe-selector-tooling
Open

cquil11 wants to merge 2 commits into
mainfrom
ix/srt-recipe-selector-tooling

Conversation

@cquil11

@cquil11 cquil11 commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Base of a two-PR stack. The recipe consolidation that uses this tooling is stacked on top: #3391.

Why

Master entries can already point at one variant of an override-format srt-slurm recipe (recipe.yaml:zip_override_x[i]), and srtctl handles that natively. Three InferenceX consumers did not:

  1. Launchers read recipes as text before srtctl runs. Power-lane detection is an awk over top-level telemetry:. launch_b200-nscale-slurm.sh / launch_h100-dgxc-slurm.sh sed-patch name, max_attempts and dist-timeout. In an override file those keys sit indented under base:, so these checks silently stop matching.
  2. Node-count scheduling gave up on any file with base: and fell back to the master-topology estimate. That breaks the invariant that nodes:N is exact.
  3. Recipe fingerprints and curve identity hash the CONFIG_FILE string. Moving a recipe into a variants file would change every fingerprint and break history and Klaud baseline matching, even when the recipe is byte-identical.

What

  • infx/srt_slurm/recipe_selector.py: resolves exactly one variant (base, override_<name>, zip_override_<group>[i]) using srtctl's rules (deep merge, null deletes, zip slicing and broadcast, auto-naming). It rejects group and glob selectors, because one matrix row is one job. It is tested against the pinned srtctl generate_override_configs.
  • materialize_srt_configs in runners/slurm_utils.sh, called right after slurm_utils.sh is sourced in all six srt-slurm launchers. For a selector CONFIG_FILE / EVAL_CONFIG_FILE, it writes <file>.<selector>.resolved.yaml beside the source and points the variable at it. Every later step (power detection, patches, apply_srt_recipe) then sees a standalone recipe. Flat recipes pass through untouched with no new dependency. The selector path uses uv run --with pyyaml because not every login node's system python3 has PyYAML (h100's does not).
  • recipe_node_count reads the selected variant.
  • recipe_fingerprint and _matrix_curve_key map any NAME=<value> setting listed in benchmarks/multi_node/srt-slurm-recipe-identities.yaml back to the flat recipe it replaced. The map is empty in this PR.
  • Docs: "Variants of one recipe" in docs/configuration-procedures.md (+ _zh).

Behavior change on main

I diffed the full multi-node matrix (full-sweep --multi-node, both default and --all-evals) between main and this branch. 457 of 459 rows are identical. The two differences are eval rows of the existing dsr1/sglang/b200-fp4/8k1k/disagg-stp-mtp-variants.yaml entries. Their node-count moves from the master estimate to the recipe's actual allocation:

Selector Before After
:override_stp_maxtpt_7p2d 6 9
:zip_override_stp_lowlat[2] 6 7

Their fingerprints change with the node count. Those same entries also start receiving the b200-nscale name / max_attempts: 720 patches that every flat recipe on that launcher already gets. The GLM-5.2 selector entries have no telemetry block, so the power lane is unaffected.

Testing

  • utils/test_recipe_selector.py:
    • parity with srtctl across base, override and zip selectors (null deletion, list-of-list, broadcast, auto-name)
    • hand-computed expansion
    • the materialize CLI and its error path
    • materialize_srt_configs run through bash with a stubbed uv
    • node count for selectors
    • fingerprint identity for CONFIG_FILE and EVAL_CONFIG_FILE
  • pytest utils/ runners/: 1711 passed locally. Skipped only suites needing deps not installed locally (codeowners, torch).
  • ruff check / ruff format --check infx: clean.
  • Not GPU-run. No recipe content changes here, and no perf-changelog.yaml entry.

…trix

Master entries can already select one variant of an override-format recipe
(recipe.yaml:zip_override_x[i]), but three consumers only understood flat
files:

- Launchers read the recipe as text for power detection and name/health-check
  patches. materialize_srt_configs now writes the selected variant beside its
  source and points CONFIG_FILE / EVAL_CONFIG_FILE at the flat copy, so every
  later step sees a standalone recipe. Flat recipes pass through untouched.
- recipe_node_count now reads the selected variant instead of falling back to
  the master-topology estimate.
- recipe_fingerprint and curve identity map selector CONFIG_FILEs listed in
  srt-slurm-recipe-identities.yaml back to the flat recipe they replaced, so
  consolidating recipes keeps history and Klaud baselines intact.

Expansion mirrors srtctl's generate_override_configs and is tested against it.
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the contribution!

  • Review: If this PR changes files owned by someone other than a repository admin or @SemiAnalysisAI/core, ask one eligible CODEOWNER to complete the latest PR_REVIEW_CHECKLIST.md before contacting a core maintainer on Slack. Follow the template exactly, including As a PR reviewer and CODEOWNER, I have reviewed this and have, so sign-off verification triggers.
  • PR verification: Sweeps only run on labeled PRs. Add full-sweep-fail-fast (strongly recommended); use full-sweep-enabled only when matrix jobs should continue after a failure.
  • After merging: PR authors must ensure all GitHub Actions jobs pass. Transient failures often pass on rerun; see how to rerun failed jobs.
中文

感谢你的贡献!

  • **审阅:**如果 PR 修改的文件归属于仓库管理员及 @SemiAnalysisAI/core 之外的 CODEOWNER,请先联系一位有资格的 CODEOWNER 填写最新的 PR_REVIEW_CHECKLIST.md,再通过 Slack 联系核心维护者。必须严格遵循模板,并保留 As a PR reviewer and CODEOWNER, I have reviewed this and have,才能触发签核验证。
  • **PR 验证:**扫描仅在带有标签的 PR 上运行。强烈建议添加 full-sweep-fail-fast;仅当需要矩阵任务在失败后继续运行时才使用 full-sweep-enabled。
  • **合并后:**PR 作者必须确保所有 GitHub Actions 任务通过。临时性失败通常可以通过重新运行恢复;参见重新运行失败任务的说明。

@claude claude 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.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Comment thread infx/matrix/generate.py
Comment on lines +248 to +253
if split_config_file(config_file)[1] is None and "base" in yaml.safe_load(
recipe_path.read_text()
):
# Without a selector srtctl submits every variant, which has no single
# node count. The master topology supplies the estimate.
return None

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.

🟡 (optional) For an override-format srt-slurm recipe referenced without a selector (a plain CONFIG_FILE, e.g. recipes/x/disagg.yaml), recipe_node_count now returns None before ever checking recipe.get("schema") != 2, so a recipe missing schema: 2 silently falls back to the master-topology node-count estimate instead of raising. On main, the schema check ran unconditionally before the base/override check, so a malformed override recipe always raised ValueError("srt-slurm recipes must declare schema: 2"). Fix: keep the schema validation on the fast-return base-without-selector path too, e.g. by loading the raw dict once and validating schema before deciding whether to return None.

Why this was flagged

Trigger: a checked-in override-format recipe (contains top-level base:) that is missing schema: 2, referenced by a master CONFIG_FILE with no :selector suffix, reaching infx/matrix/generate.py:recipe_node_count via infx/matrix/plan.py's matrix generation. The new early-return at generate.py:248-253 checks only split_config_file(config_file)[1] is None and "base" in raw and returns None, skipping the recipe.get("schema") != 2 check at line 255 entirely for this path. On main the schema check ran first and unconditionally, so this malformed recipe would raise ValueError and fail matrix generation loudly; now it is silently treated as unknown/estimate-only with no error, hiding an authoring mistake until runtime job submission.

Verification: nit. The ordering change is real and as described. Base ran recipe = yaml.safe_load(...); if recipe.get("schema") != 2: raise ...; if "base" in recipe: return None, so a malformed override recipe (top-level base: but no top-level schema: 2) raised. The new code (infx/matrix/generate.py:248-253) short-circuits first: `if split_config_file(config_file)[1] is None and "base" in… | nit.…

Comment thread runners/slurm_utils.sh
local name value
for name in CONFIG_FILE EVAL_CONFIG_FILE; do
value="${!name}"
[[ "$value" == *:* ]] || continue

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.

🟣 Pre-existing (partial fix): materialize_srt_configs() only rewrites CONFIG_FILE when it contains a colon selector, so an override-format recipe referenced with no selector still reaches launchers as raw text with base:-nested keys, exactly the bug this PR sets out to fix. configs/nvidia-master.yaml:2536 sets CONFIG_FILE=recipes/dsr1/sglang/gb200-fp8/8k1k/disagg-tp8-stp-variants.yaml with no :selector, yet that recipe has base: and a 3-way zip_override_lowlat: (file lines 2-117, 118-132). materialize_srt_configs's [[ "$value" == *:* ]] guard (slurm_utils.sh:19) skips it, so runners/launch_gb200-nv.sh:489 sed -i "s/^name:.*/.../" "$CONFIG_PATH" still can't match the indented name: at line 3 of that recipe, same as on main. …

Why this was flagged

…Fix: also materialize/flag override-format CONFIG_FILE values that lack a selector (or reject them) so the launcher-text-parsing checks this PR fixes for selector paths are not silently skipped for this real production entry.

Trigger: configs/nvidia-master.yaml:2536 CONFIG_FILE has no :selector, dispatched through the gb200-nv launcher. materialize_srt_configs (runners/slurm_utils.sh:15-27) requires a colon in the value (line 19) before calling the selector module, so this value is left untouched. runners/launch_gb200-nv.sh:473-489 then treats the raw multi-variant file as flat: CONFIG_PATH equals the source file, and sed -i "s/^name:.*/.../" "$CONFIG_PATH" cannot match the recipe's name: (nested 2-space under base: at recipe line 3), so the job-name patch silently no-ops just as it did before this PR. The PR's own description names this exact class of launcher bug as motivation; its fix (materialize_srt_configs) does not cover CONFIG_FILE values without a selector, so this production row keeps the original failure mode.

Verification: pre-existing. The mechanism is real and reachable, but the base branch already fails identically by the same route; the PR's new code is a no-op on this path. Chain verified: - runners/slurm_utils.sh:19 [[ "$value" == *:* ]] || continue — materialize_srt_configs only rewrites CONFIG_FILE/EVAL_CONFIG_FILE that contain a colon selector; a bare override-format reference is skipped unchanged. -…

@functionstackx

Copy link
Copy Markdown
Collaborator

Sorry, over the weekend, there was 2 major refactors to clean up the technical debt accumalated over the past 11 months of moving at the speed of light. We don't see any major refactors in the forthseeable future besides cleaning up AMD multinode AgentX pile of bash. As much, due to the refactors, u would need to ask your agent to rebase from remote main@latest. Thank you in advance for ur understanding

@adibarra

Copy link
Copy Markdown
Collaborator

Heads-up: #3576 (merged) replaced the bash launchers with a Python launcher, so this PR will conflict when you merge main, and the sweep won't start until that's resolved. Please merge main and move your launcher changes over to configs/runners.yaml / infx/launch/. Apologies for the churn, and thanks for your understanding as we wrap up the repo-wide refactoring push.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants