run-sweep: gate full-sweep PRs behind a sequential canary#1503
Conversation
28ecd9a to
78b51e3
Compare
Per PR #1503 test plan (T1 — canary success → fan-out runs with dedup). The minimaxm2.5-fp8-b200-vllm config has both single_node 1k1k and 8k1k scenarios, so canary-select has lowest-conc candidates to pick from. The master config image (vllm/vllm-openai:v0.21.0) is known-good, so the canary is expected to succeed and the fan-out should run against remaining-search-space-config (canary entry removed → no duplicate run).
Per PR #1503 test plan (T1 — canary success → fan-out runs with dedup). The minimaxm2.5-fp8-b200-vllm config has both single_node 1k1k and 8k1k scenarios, so canary-select has lowest-conc candidates to pick from. The master config image (vllm/vllm-openai:v0.21.0) is known-good, so the canary is expected to succeed and the fan-out should run against remaining-search-space-config (canary entry removed → no duplicate run).
65d7856 to
0c1a94d
Compare
Per PR #1503 test plan (T1 — canary success → fan-out runs with dedup). The minimaxm2.5-fp8-b200-vllm config has both single_node 1k1k and 8k1k scenarios, so canary-select has lowest-conc candidates to pick from. The master config image (vllm/vllm-openai:v0.21.0) is known-good, so the canary is expected to succeed and the fan-out should run against remaining-search-space-config (canary entry removed → no duplicate run).
9286ade to
de73181
Compare
When a PR carries `full-sweep-enabled` (and not `evals-only`), pick the lowest-conc single-node benchmark entry as a canary and run it before fanning out the full sweep. If the canary fails, the eight fan-out jobs are skipped to save cluster time on shared failures (bad image tag, removed CLI flag, etc.). Design choices: - Canary candidacy is restricted to single_node['1k1k' | '8k1k'] and excludes entries with run-eval: true, so the canary is always a pure benchmark smoke test using the existing single-node template. - The canary entry is removed from the regular fan-out's matrix (via remaining-search-space-config) only when the canary actually succeeded. On canary skip / cancel / canary-select failure, the regular fan-out falls back to the full search-space-config so coverage is preserved. - The fan-out gate blocks only on `canary-sweep.result == 'failure'` -- every other state (success, skipped, cancelled) proceeds, so a bug in the canary mechanism never blocks the rest of the sweep. - Non-full-sweep PRs, draft PRs, pushes to main, and the reuse path all behave identically to before via existing gates. The aggregated results_bmk artifact picks up both the canary's row and the regular fan-out's rows via the existing bmk_* glob -- each entry appears exactly once.
Previously the fan-out gate was `needs.canary-sweep.result != 'failure'`, which let `cancelled` (and any unknown future result) fall through. A cancelled canary then ran the FULL fan-out matrix — including the canary's own entry — without canary validation, the worst-case outcome. Replace with an explicit allowlist: (result == 'success' || result == 'skipped') - success: canary passed → fan-out runs with deduped (remaining) matrix - skipped: no canary candidate (multi-node-only / evals-only) → fan-out runs with full matrix (no canary to dedup against) - failure / cancelled / anything else: fan-out blocked The matrix-ternary `result == 'success' && remaining-search-space-config || full-search-space-config` already had the right shape and is untouched. Applies to all 8 fan-out jobs (single/multi-node 1k1k+8k1k, agentic, multi-node-agentic, evals, multi-node-evals).
…nary)
New label that triggers the full sweep without running the canary gate.
Acts as an escape hatch when:
- The canary is known to be flaky / unreliable for this config
- The user wants the full sweep without the canary delay
- The canary's chosen entry is not a representative smoke test
Behavior matrix:
sweep-enabled - trims to max(conc) per parallelism, with canary
full-sweep-enabled - full intermediate conc sweep, with canary
non-canary-full-sweep-enabled - full intermediate conc sweep, NO canary
How it works (no changes to existing label semantics):
- Setup gate triggers on any of the 3 labels (was: 2)
- canary-select gate still requires `full-sweep-enabled` (exact array match,
so `non-canary-full-sweep-enabled` does NOT match) → canary skips → all
fan-out jobs run on full search space via the `== 'skipped'` allowlist
- TRIM_CONC env is unchanged — only `sweep-enabled` enables trim, so the
new label correctly behaves as "full sweep"
- The reject-conflicting-labels step is now a 3-way exclusion: at most
one of {sweep-enabled, full-sweep-enabled, non-canary-full-sweep-enabled}
- The same gate updates apply to the comment-visualizer job
- Concurrency-group filter excludes the new label too so toggling it
uses the same `'active'` group key as the other sweep labels
2f6aa0c to
afb408b
Compare
|
see unofficial run visualizer at https://inferencex.semianalysis.com/inference?unofficialRun=26524225403 |
|
see unofficial run visualizer at https://inferencex.semianalysis.com/inference?unofficialRun=26525033406 |
Used by T6/T7 (cancellation-regression repro and !cancelled() fix verification, runs 26524225403 and 26525033406). Both tests are complete and recorded in the PR description; the entry is no longer needed.
|
see unofficial run visualizer at https://inferencex.semianalysis.com/inference?unofficialRun=26530059401 |
DO NOT MERGE. Verifies empty-canary-config path on HEAD's !cancelled() gate. Agentic-only config → canary-select returns [] → canary-sweep skipped via inner guard → agentic fan-out on full search space.
|
see unofficial run visualizer at https://inferencex.semianalysis.com/inference?unofficialRun=26531940666 |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d35e0b7. Configure here.
|
see unofficial run visualizer at https://inferencex.semianalysis.com/inference?unofficialRun=26531946908 |
DO NOT MERGE. Verifies canary success → fan-out + dedup path on HEAD's !cancelled() gate.
|
see unofficial run visualizer at https://inferencex.semianalysis.com/inference?unofficialRun=26539800671 |
AGENTS.md: list all three sweep labels in the table; clarify multi-label rejection. .github/workflows/README.md: reuse section accepts either full-sweep label; fail-closed wording covers both. KLAUD_DEBUG.md / klaud-pr-status-html.md: mention the new label alongside full-sweep-enabled.
Final cleanup. T8 redo (run 26530059401, commit 13272b9, success) is the reusable green sweep for /reuse-sweep-run.
Resolves conflicts with PR #1576 (trim-to-min). For the multi-conflicting-labels guardrail in run-sweep.yml and the matching prose in AGENTS.md, keep this branch's three-label structure (sweep-enabled / full-sweep-enabled / non-canary-full-sweep-enabled) and the canary-gate description for full-sweep-enabled, and update the sweep-enabled wording from "max(conc)" → "min(conc)" to match the new trim_conc behavior on main. utils/process_changelog.py auto-merged cleanly to the new lowest-`conc` implementation.

Summary
When a PR carries
full-sweep-enabled, pick the lowest-conc single-node benchmark entry as a canary and run it before fanning out the full sweep. If the canary fails, the eight fan-out jobs are skipped to save cluster time on shared failures (bad image tag, removed CLI flag, etc.).Design choices:
single_node['1k1k' | '8k1k']and excludes entries withrun-eval: true, so the canary is always a pure benchmark smoke test using the existing single-node template. For anevals-only: truechangelog entry, the generated benchmark matrices are empty and the canary skips naturally.remaining-search-space-config) only when the canary actually succeeded. On canary skip or canary-select failure, the regular fan-out falls back to the full search-space-config so coverage is preserved.canary-sweep.result == 'success' || == 'skipped'(allowlist, not!= 'failure'), so a cancelled canary also blocks fan-out — preventing the case where in-flight fan-out jobs continue after the user explicitly cancels the canary.!cancelled() && …, notalways() && ….always()is immune to workflow cancellation, so under the old gate any matrix entry whose runner had been assigned would launch and run to completion aftergh run cancel, and queued matrix entries kept picking up runners.!cancelled()evaluates false once the workflow is cancelled (by user, by concurrency, or upstream), so the queued matrix stops spawning and in-flight entries are cancelled along with the workflow.collect-resultsand the housekeeping jobs keepalways()on purpose so partial-result aggregation still runs on cancel.non-canary-full-sweep-enabledlabel runs the full sweep without the canary gate (escape hatch when the canary is flaky or unrepresentative). The three sweep labels are now mutually exclusive.utils/find_reusable_sweep_run.pyandutils/merge_with_reuse.shaccept eitherfull-sweep-enabledornon-canary-full-sweep-enabledas a "full sweep" for/reuse-sweep-runandmerge_with_reusepaths.The aggregated
results_bmkartifact picks up both the canary's row and the regular fan-out's rows via the existingbmk_*glob — each entry appears exactly once.Docker-tag-monitor research block split out to #1538.
Documentation for the new label and reuse behavior is included in
AGENTS.md,.github/workflows/README.md,KLAUD_DEBUG.md, and.claude/commands/klaud-pr-status-html.md.Test plan
T1/T2/T3/T6/T7/T8 are live Run Sweep runs on this branch, each triggered by a
synchronizeevent with a deliberately-chosen changelog target.gptoss-fp4-h100-vllmwas used for T1/T2/T6/T7/T8 (h100 has the shortest CI queue);kimik2.5-int4-h100-vllm(agentic-only) was used for T3. T5 is workflow-logic inspection; T9/T10 are local validation.T6 and T7 are the empirical bug-and-fix pair for the cancellation regression: T6 reproduces the bug on the old
always() &&gate, T7 verifies the fix on the new!cancelled() &&gate. They share the same procedure (let canary succeed →gh run cancelmid-fan-out) and differ only by the gate they ran against.T1 — Canary success → fan-out runs with dedup (run 26467367124)
canary-sweepran the lowest-conc 1k1k entry (tp=2, conc=4) and succeeded. Downstreamsingle-node-1k1kran againstremaining-search-space-config(the canary entry de-duped). Final tally: 41 success, 7 skipped, 0 failures.remove_onecorrectness and the(canary == success && remaining) || fullmatrix ternary.T2 — Canary failure → fan-out skipped (run 26471353341)
vllm/vllm-openai:nonexistent-tag-T2-canary-failure-test.canary-sweep.result == 'failure'; all 8 fan-out jobs (single-node 1k1k/8k1k, single-node agentic/eval, all multi-node variants) andcollect-resultscorrectly skipped via thesuccess || skippedallowlist.T3 — No canary candidate → fan-out on full search space (run 26471597565)
kimik2.5-int4-h100-vllm(agentic-only config; no fixed-seq-len entries → emptysingle_node['1k1k']and['8k1k']arrays).canary-selectsucceeded but returned[];canary-sweepskipped via the!= '' && != '[]'guard;agenticfan-out ran on the full search space (ternary fell throughcanary-sweep.result == 'success'); 1k1k/8k1k/eval/multi-node all correctly skipped because their matrices are empty for this config.!cancelled()gate:canary-sweepskipped and the agentic fan-out was admitted. The run is not counted as green validation because its downstream agentic benchmark jobs failed.T5 — Push to
main→ canary never firescanary-select.ifrequiresgithub.event_name == 'pull_request', so on apushevent it evaluates false →canary-sweepskipped → everysweep-*job runs via thesuccess || skippedallowlist on the full search-space-config. Identical to pre-PR push-to-main behavior.T6 — Workflow cancel mid-fan-out under old
always() &&gate (regression repro) (run 26524225403)d51965fe, fan-out gates werealways() && needs.setup.result == 'success' && …. Canary completed success attp=2, conc=4; once the fan-out matrix had 19 in_progress + 12 queued + 10 skipped/done jobs, rangh run cancel 26524225403.conclusion=success. The run never honored the cancel.always()gate ignores workflow cancellation — the reason for moving to!cancelled() && ….T7 — Workflow cancel mid-fan-out under new
!cancelled() &&gate (fix verification) (run 26525033406)e166509d, fan-out gates are now!cancelled() && …. Same procedure as T6 on the same canary entry (gptoss-fp4-h100-vllm,tp=2 conc=4): waited for canary to succeed and the fan-out matrix to reach 19 in_progress + 12 queued, then rangh run cancel 26525033406.!cancelled()actually fires on user-issuedgh run canceland blocks queued matrix entries from spawning new runners. Side-by-side with T6 this is the direct empirical receipt that thealways() → !cancelled()swap fixes the cancellation regression.T8 —
non-canary-full-sweep-enabledlabel → canary skipped, full fan-out under final gate (run 26530059401)13272b92, after the!cancelled()fix; swapped the PR label fromfull-sweep-enabledtonon-canary-full-sweep-enabled.canary-selectandcanary-sweepskipped; fan-out ran on the full search space; final tally: 40 success, 9 skipped, 0 failures. Theresults_bmkaggregate contains 28 rows, 28 unique rows.!cancelled()expression.T9 — Reuse path accepts both full-sweep labels (unit test,
utils/test_find_reusable_sweep_run.py)test_main_accepts_non_canary_full_sweep_label(PR carrying onlynon-canary-full-sweep-enabled→reuse-enabled=true) andtest_main_rejects_pr_with_neither_full_sweep_label(PR carrying neither label →RuntimeErrormentioning both label names). All 13 reuse tests pass.find_reusable_sweep_run.py/merge_with_reuse.shchange that lets a PR labeled with the new no-canary escape hatch still approve/reuse-sweep-runand merge viautils/merge_with_reuse.sh.T10 — Final local validation
actionlint .github/workflows/run-sweep.yml,bash -n utils/merge_with_reuse.sh, andpython -m pytest utils/test_find_reusable_sweep_run.py utils/test_validate_reusable_sweep_artifacts.py utils/matrix_logic/ -qsucceeded (166 passed).Follow-ups (separate PR)
Raised by the code reviewer and intentionally scoped out of this PR to keep it focused on the canary gate + cancellation fix + label-reuse plumbing:
collect-resultspredicate omitssweep-agentic/sweep-multi-node-agentic. Pre-existing bug, not introduced here — visible in T3 (run 26471597565) wherecollect-resultswasskippedeven though the agentic fan-out ran. Should be fixed by adding both job names to the OR-chain at.github/workflows/run-sweep.ymlaround line 524.The originally-listed docs follow-up (
non-canary-full-sweep-enablednot inAGENTS.md/ workflow README) has been folded into this PR (commite3f40988).Merge note
perf-changelog.yamlon this branch is identical tomainafter mergingorigin/mainto pick up PR #1569's new MI355X entries. This is now a workflow/docs-only PR:Run Sweepdoes not trigger on the current head viapull_request: paths: [perf-changelog.yaml], and a standard squash merge will not trigger the push-to-main sweep or result ingestion either. No/reuse-sweep-runapproval is needed for the final diff.For audit purposes, the post-fix T8 redo (run 26530059401, commit
13272b92) is green and its commit remains in this PR's history. It would be eligible reuse evidence only if a later revision reintroduced a realperf-changelog.yamlchange before merge.Note
Medium Risk
Changes core
run-sweep.ymlorchestration (canary gating, jobifconditions, new label matrix); mistakes could skip sweeps, duplicate work, or break merge-time artifact reuse.Overview
full-sweep-enabledPR sweeps now run a sequential single-node canary before the full matrix:canary-selectpicks the lowest-concurrency non-eval entry from1k1k/8k1k,canary-sweepruns it, and fan-out jobs wait for canary success or skip; on canary success, that entry is removed from the single-node1k1k/8k1kmatrices viaremaining-search-space-config.Fan-out job gates switch from
always()to!cancelled()so workflow cancel stops queued matrix jobs from spawning (fix for post-gh run cancelrunner pickup).Adds
non-canary-full-sweep-enabledfor full sweeps without the canary;sweep-enabled,full-sweep-enabled, andnon-canary-full-sweep-enabledare mutually exclusive. Reuse paths (find_reusable_sweep_run.py,merge_with_reuse.sh) and docs accept either full-sweep label for/reuse-sweep-run.Reviewed by Cursor Bugbot for commit ce6a610. Bugbot is set up for automated code reviews on this repo. Configure here.