Skip to content

Commit ce6a610

Browse files
committed
Merge origin/main into sweep-canary-gate
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.
2 parents 142c925 + 99acc90 commit ce6a610

3 files changed

Lines changed: 9 additions & 9 deletions

File tree

.github/workflows/run-sweep.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ jobs:
9595
(contains(github.event.pull_request.labels.*.name, 'full-sweep-enabled') && contains(github.event.pull_request.labels.*.name, 'non-canary-full-sweep-enabled'))
9696
)
9797
run: |
98-
echo "::error::PR has multiple conflicting sweep labels. Pick exactly one of: 'sweep-enabled' (trims to max(conc) per parallelism config), 'full-sweep-enabled' (full intermediate concurrency sweep, with canary gate), or 'non-canary-full-sweep-enabled' (full sweep, no canary gate)."
98+
echo "::error::PR has multiple conflicting sweep labels. Pick exactly one of: 'sweep-enabled' (trims to min(conc) per parallelism config), 'full-sweep-enabled' (full intermediate concurrency sweep, with canary gate), or 'non-canary-full-sweep-enabled' (full sweep, no canary gate)."
9999
exit 1
100100
101101
- name: Checkout code

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ Git: conventional commit messages. `[skip-sweep]` in commit message skips benchm
6161

6262
PRs do not run the sweep automatically - `run-sweep.yml` is gated on a label. Pick exactly one; setting multiple sweep labels is rejected by the workflow's `setup` job.
6363

64-
- `sweep-enabled` - runs the sweep with `--trim-conc` (each parallelism config reduced to its single highest concurrency). Default for most PRs.
64+
- `sweep-enabled` - runs the sweep with `--trim-conc` (each parallelism config reduced to its single lowest concurrency). Default for most PRs.
6565
- `full-sweep-enabled` - runs the full intermediate concurrency sweep behind a sequential single-node canary gate. Use when intermediate points matter (e.g. a recipe change shifts the throughput/latency curve, not just its endpoints).
6666
- `non-canary-full-sweep-enabled` - runs the full intermediate concurrency sweep without the canary gate. Use when the canary is flaky or not representative of the affected configuration.
6767

6868
**The sweep does not trigger while the PR has merge conflicts.** Even with `sweep-enabled`, `full-sweep-enabled`, or `non-canary-full-sweep-enabled` applied, the `run-sweep.yml` workflow will not start until the PR cleanly merges into main — a stale claude/* or update-* branch with a `perf-changelog.yaml` conflict (the common case) will sit in NO_SWEEP / NO_SUCCESS until rebased. Resolution recipe is documented in `KLAUD_DEBUG.md §1.1`: `git merge origin/main`, then `git checkout origin/main -- perf-changelog.yaml`, then re-append the PR's own changelog entry at the tail. Don't 3-way merge `perf-changelog.yaml`; whitespace edits silently re-trigger the deletion check.
6969

70-
Push-to-main always runs the full untrimmed sweep unless `[skip-sweep]` is in the commit message. Trim logic lives in `trim_conc()` in `utils/process_changelog.py`: single-node entries are grouped by every non-`conc` field and only the highest-`conc` entry per group is kept; multi-node entries have their `conc` list collapsed to `[max(conc)]`.
70+
Push-to-main always runs the full untrimmed sweep unless `[skip-sweep]` is in the commit message. Trim logic lives in `trim_conc()` in `utils/process_changelog.py`: single-node entries are grouped by every non-`conc` field and only the lowest-`conc` entry per group is kept; multi-node entries have their `conc` list collapsed to `[min(conc)]`.
7171

7272
## Common Tasks
7373

utils/process_changelog.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,22 @@ def get_added_lines(base_ref: str, head_ref: str, filepath: str) -> str:
4242

4343

4444
def trim_conc(entries: list[dict]) -> list[dict]:
45-
"""Trim each parallelism config's concurrency sweep to its highest point.
45+
"""Trim each parallelism config's concurrency sweep to its lowest point.
4646
4747
Non-full-sweep PRs only need a single concurrency point per parallelism
4848
config to validate a change runs end-to-end, so the shared cluster stays
4949
clear. Push-to-main and ``full-sweep-enabled`` PRs skip this reduction.
5050
51-
The retained value is the maximum configured concurrency — independent of
51+
The retained value is the minimum configured concurrency — independent of
5252
the source ordering of ``conc-list`` / ``conc-start``.
5353
5454
Input comes from ``json.loads(subprocess.stdout)`` so ``conc`` is always
5555
``int`` (single-node) or ``list`` (multi-node); other single-node fields
5656
are hashable scalars.
5757
5858
- Single-node entries: group by every other field and keep only the entry
59-
with the highest ``conc`` per group.
60-
- Multi-node entries: trim the ``conc`` list in place to ``[max(conc)]``.
59+
with the lowest ``conc`` per group.
60+
- Multi-node entries: trim the ``conc`` list in place to ``[min(conc)]``.
6161
"""
6262
groups: dict[tuple, list[int]] = {}
6363
out: list[dict] = []
@@ -66,7 +66,7 @@ def trim_conc(entries: list[dict]) -> list[dict]:
6666
if entry.get("prefill") is not None:
6767
conc = entry.get("conc")
6868
if isinstance(conc, list) and len(conc) > 1:
69-
entry = {**entry, "conc": [max(conc)]}
69+
entry = {**entry, "conc": [min(conc)]}
7070
out.append(entry)
7171
continue
7272

@@ -77,7 +77,7 @@ def trim_conc(entries: list[dict]) -> list[dict]:
7777
drop: set[int] = set()
7878
for idxs in groups.values():
7979
if len(idxs) > 1:
80-
keep = max(idxs, key=lambda i: out[i]["conc"])
80+
keep = min(idxs, key=lambda i: out[i]["conc"])
8181
drop.update(i for i in idxs if i != keep)
8282
return [e for i, e in enumerate(out) if i not in drop]
8383

0 commit comments

Comments
 (0)