Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions .github/codeowner-signoff-verify-prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ You are an automated merge-gate auditor for InferenceX.
A CODEOWNER (`${SIGNOFF_AUTHOR}`) just posted the reviewer
sign-off checklist (as a ${SIGNOFF_KIND}) that marks
PR #${PR_NUMBER} as ready to merge. Your job is to
INDEPENDENTLY verify the checks below (0-10). Do not trust the reviewer's checkmarks.
INDEPENDENTLY verify the checks below (0-12). Do not trust the reviewer's checkmarks.
Re-derive every conclusion from CODEOWNERS, CI runs, the PR diff, the master
configs, and the linked recipe yourself. Be rigorous and specific. The checks encode
the merge standard in `docs/PR_REVIEW_CHECKLIST.md`. Read it in the checked-out
Expand Down Expand Up @@ -359,8 +359,38 @@ Verify BOTH:
unless the sign-off documents a sanctioned exception.
- N/A if the PR has no agentic speculative-decoding changes (state that in one line).

## Check 12 — Append-only changes only add new points to an unchanged curve
APPLICABILITY: this check applies when any new `perf-changelog.yaml` entry contains
`append-only: true`. If none does, report N/A.
- Confirm every new changelog entry in the sweep is append-only; mixed regular and
append-only entries are not allowed.
- Inspect the complete PR diff without using a file allowlist. Supporting code,
benchmark scripts, launchers, helpers, and other files may change. Their path alone
is never a reason to fail; determine whether each benchmark-affecting change is
behaviorally isolated to the appended points.
- For every selected config, compare the generated matrix at the PR base and head.
Treat the complete base matrix as an immutable subset of the head matrix: every
existing point must remain present with the same image and complete recipe. The
head may add concurrency points or entirely new recipe variants, such as a new
tensor-parallelism value, inside the selected existing config/scenario. Every
addition must retain the target visual curve's one non-null image.
- Trace the selected config and generated runtime values through every affected file
into the changed behavior. The behavior must be reachable only for the corresponding
newly appended points. PASS when the controlling condition is uniquely satisfied by
those points. FAIL an unguarded/shared setup change, a condition also satisfied by an
existing point, or any case where exclusivity cannot be proven from the diff.
- FAIL if any existing point or recipe is rerun, removed, or modified. New configs and
scenarios are out of scope, but new generated recipe variants inside the selected
existing config/scenario are allowed. Other benchmark-affecting changes are permitted
only under the behavioral-isolation rule above.
- Treat the repository's append-only matrix validation as supporting evidence, but
verify the diff independently and name the offending field/path when failing. Each
config revision is rendered with its own generator, validation code, and runner
metadata, but this does not mechanically prove that launcher or benchmark-script
changes are isolated at runtime.

## Verdict and output
Decide PASS only if Checks 0-11 ALL pass. A check reported as `N/A` counts as a pass.
Decide PASS only if Checks 0-12 ALL pass. A check reported as `N/A` counts as a pass.
Keep the `N/A — <reason>` row so the reviewer sees it was considered. Post EXACTLY ONE summary comment on
PR #${PR_NUMBER} using `gh pr comment`. Start the comment with
the hidden marker so reruns are identifiable:
Expand All @@ -386,7 +416,7 @@ single terse line. Rules:
restating the checklist, no hedging ("if X then maybe Y"). Make the call. Link the
run/recipe instead of describing it.

- If everything is to standard: post the verdict header + the twelve one-line rows
- If everything is to standard: post the verdict header + the thirteen one-line rows
- If anything is NOT to standard: the verdict header must be immediately followed by a
line that @-mentions the sign-off author as `@${SIGNOFF_AUTHOR}`
with the blocking summary. Then the per-check lines, each failing one led by its root
Expand Down
13 changes: 11 additions & 2 deletions .github/workflows/benchmark-multinode-tmpl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ on:
exp-name:
required: true
type: string
recipe-fingerprint:
description: "Deterministic generated-recipe identity"
required: false
type: string
default: ''
isl:
required: true
type: string
Expand Down Expand Up @@ -217,6 +222,7 @@ env:
# once; sbatch/srun inherit this env so the token reaches the workers.
HF_TOKEN: ${{ secrets.INFERENCEX_OFFICIAL_RO_HF_TOKEN }}
EXP_NAME: ${{ inputs.exp-name }}
RECIPE_FINGERPRINT: ${{ inputs.recipe-fingerprint }}
IMAGE: ${{ inputs.image }}
MODEL_PREFIX: ${{ inputs.model-prefix }}
MODEL: ${{ inputs.model }}
Expand Down Expand Up @@ -336,10 +342,13 @@ jobs:
env:
RUNNER_NAME: ${{ runner.name }}
RUNNER_TYPE: ${{ inputs.runner }}
# Hash uniquely on all prefill/decode parallelism fields, worker counts, serving mode, concurrency, and runner.
RESULT_FILENAME: ${{ env.EXP_NAME }}_${{ env.PRECISION }}_${{ env.FRAMEWORK }}_prefill-tp${{ env.PREFILL_TP }}-pp${{ env.PREFILL_PP_SIZE }}-dcp${{ env.PREFILL_DCP_SIZE }}-pcp${{ env.PREFILL_PCP_SIZE }}-ep${{ env.PREFILL_EP }}-dp${{ env.PREFILL_DP_ATTN }}-nw${{ env.PREFILL_NUM_WORKERS }}_decode-tp${{ env.DECODE_TP }}-pp${{ env.DECODE_PP_SIZE }}-dcp${{ env.DECODE_DCP_SIZE }}-pcp${{ env.DECODE_PCP_SIZE }}-ep${{ env.DECODE_EP }}-dp${{ env.DECODE_DP_ATTN }}-nw${{ env.DECODE_NUM_WORKERS }}_disagg-${{ env.DISAGG }}_spec-${{ env.SPEC_DECODING }}_conc${{ join(fromJson(inputs.conc-list), 'x') }}_${{ runner.name }}
RESULT_FILENAME_BASE: ${{ env.EXP_NAME }}_${{ env.PRECISION }}_${{ env.FRAMEWORK }}_prefill-tp${{ env.PREFILL_TP }}-pp${{ env.PREFILL_PP_SIZE }}-dcp${{ env.PREFILL_DCP_SIZE }}-pcp${{ env.PREFILL_PCP_SIZE }}-ep${{ env.PREFILL_EP }}-dp${{ env.PREFILL_DP_ATTN }}-nw${{ env.PREFILL_NUM_WORKERS }}_decode-tp${{ env.DECODE_TP }}-pp${{ env.DECODE_PP_SIZE }}-dcp${{ env.DECODE_DCP_SIZE }}-pcp${{ env.DECODE_PCP_SIZE }}-ep${{ env.DECODE_EP }}-dp${{ env.DECODE_DP_ATTN }}-nw${{ env.DECODE_NUM_WORKERS }}_disagg-${{ env.DISAGG }}_spec-${{ env.SPEC_DECODING }}_conc${{ join(fromJson(inputs.conc-list), 'x') }}_${{ runner.name }}
run: |
set -x
export RESULT_FILENAME="$RESULT_FILENAME_BASE"
if [ -n "$RECIPE_FINGERPRINT" ]; then
export RESULT_FILENAME="${RESULT_FILENAME}_recipe-${RECIPE_FINGERPRINT:0:16}"
fi
# Export RESULT_FILENAME early so it's available for artifact uploads even if cancelled
echo "RESULT_FILENAME=${RESULT_FILENAME}" >> "$GITHUB_ENV"

Expand Down
15 changes: 12 additions & 3 deletions .github/workflows/benchmark-tmpl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ on:
exp-name:
required: true
type: string
recipe-fingerprint:
description: "Deterministic generated-recipe identity"
required: false
type: string
default: ''
isl:
required: true
type: string
Expand Down Expand Up @@ -154,6 +159,7 @@ env:
HF_TOKEN: ${{ secrets.INFERENCEX_OFFICIAL_RO_HF_TOKEN }}
HF_HUB_CACHE: '/mnt/hf_hub_cache/'
EXP_NAME: ${{ inputs.exp-name }}
RECIPE_FINGERPRINT: ${{ inputs.recipe-fingerprint }}
MODEL: ${{ inputs.model }}
MODEL_PREFIX: ${{ inputs.model-prefix }}
ISL: ${{ inputs.isl }}
Expand Down Expand Up @@ -269,17 +275,20 @@ jobs:
env:
RUNNER_NAME: ${{ runner.name }}
RUNNER_TYPE: ${{ inputs.runner }}
# Hash uniquely on {EXP_NAME}_{PRECISION}_{FRAMEWORK}_tp{}-pp{}-dcp{}-pcp{}-ep{}-dpa{}_disagg-{}_spec-{}_conc{}_{runner}
RESULT_FILENAME: ${{ env.EXP_NAME }}_${{ env.PRECISION }}_${{ env.FRAMEWORK }}_tp${{ env.TP }}-pp${{ env.PP_SIZE }}-dcp${{ env.DCP_SIZE }}-pcp${{ env.PCP_SIZE }}-ep${{ env.EP_SIZE }}-dpa${{ env.DP_ATTENTION }}_disagg-${{ env.DISAGG }}_spec-${{ env.SPEC_DECODING }}_conc${{ env.CONC }}_${{ runner.name }}
RESULT_FILENAME_BASE: ${{ env.EXP_NAME }}_${{ env.PRECISION }}_${{ env.FRAMEWORK }}_tp${{ env.TP }}-pp${{ env.PP_SIZE }}-dcp${{ env.DCP_SIZE }}-pcp${{ env.PCP_SIZE }}-ep${{ env.EP_SIZE }}-dpa${{ env.DP_ATTENTION }}_disagg-${{ env.DISAGG }}_spec-${{ env.SPEC_DECODING }}_conc${{ env.CONC }}_${{ runner.name }}
# Suppress per-job eval markdown from being appended to the step summary.
# We'll publish a single combined eval table in the collection job instead.
GITHUB_STEP_SUMMARY: ''
run: |
export RESULT_FILENAME="$RESULT_FILENAME_BASE"
if [ -n "$RECIPE_FINGERPRINT" ]; then
export RESULT_FILENAME="${RESULT_FILENAME}_recipe-${RECIPE_FINGERPRINT:0:16}"
fi
export GPU_COUNT=$((TP * PP_SIZE * PCP_SIZE))
echo "GPU_COUNT=${GPU_COUNT}" >> "$GITHUB_ENV"

# Export RESULT_FILENAME early so it's available for artifact uploads even if cancelled
echo "RESULT_FILENAME=${RESULT_FILENAME}" >> $GITHUB_ENV
echo "RESULT_FILENAME=${RESULT_FILENAME}" >> "$GITHUB_ENV"

bash ./runners/launch_${RUNNER_NAME%%_*}.sh

Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/claude-pr-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ jobs:
- This is a 🔴 **BLOCKING** issue
- Comment: "New `perf-changelog.yaml` entries must be appended to the END of the file. The file is read chronologically (oldest at top, newest at bottom), so inserting in the middle or prepending breaks the ordering. Please move the new entry(ies) to the bottom of the file."

### Append-only Perf Changelog Safety:
When a new `perf-changelog.yaml` entry contains `append-only: true`, verify the complete PR diff before approving it:
- Do not use a file allowlist. Supporting code, benchmark scripts, launchers, helpers, and other files may change. Inspect the complete diff and judge whether each benchmark-affecting change is behaviorally isolated to the appended points.
- Every newly added changelog entry must contain `append-only: true`; append-only and regular entries may not be mixed.
- Treat the generated base matrix as an immutable subset of the generated head matrix. Every existing point must remain present with the same image and complete recipe. Additions may include new concurrency values or entirely new recipe variants (for example, a new tensor-parallelism value) inside the selected existing config/scenario, but they must retain the existing visual curve's single non-null image.
- Benchmark or launch logic may change only when every changed behavior is on a control-flow path uniquely gated to the corresponding newly appended points. Trace the selected config and generated runtime values through every affected file into the condition. Confirm the path cannot be reached by any existing point. Unguarded/shared setup changes, or a branch also used by an existing concurrency/config/scenario, are blocking.
- No existing point, recipe variant, config, or scenario may be removed or replaced. New configs and scenarios are out of scope for append-only mode; new generated variants inside the selected existing config/scenario are allowed.
- Eval modifiers (`evals-only`, `all-evals`, `eval-min-prefill-ep`) are not allowed.
If any condition fails, report a 🔴 **BLOCKING** issue. Never reject a change merely because of its file path; reject it when its benchmark effect is not exclusive to the appended points or the exclusivity cannot be proven from the diff.

## Terminology:
- **STP (Single Token Prediction)**: Standard autoregressive decoding — one token per forward pass. No speculative decoding or MTP. Benchmarks labeled "STP only" use vanilla decoding.
- **MTP (Multi-Token Prediction)**: Predicts multiple tokens per forward pass using speculative decoding (e.g., EAGLE, NEXTN).
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ jobs:

See `docs/configuration-procedures.md` → "Update an image" and "Append the changelog safely" for entry format and rules. Required whenever you change image tags, env vars, or perf-affecting params in `configs/*-master.yaml` or `benchmarks/*.sh`. Use `XXX` as the PR-link placeholder until the PR exists.

If an entry uses `append-only: true`, require the generated base matrix to remain an immutable subset of the generated head matrix. New concurrency values or new recipe variants may be added inside a selected existing config/scenario, but no existing generated point may be removed or modified, and every addition must retain the target visual curve's single non-null image. Do not enforce a file allowlist: supporting code, benchmark scripts, launchers, helpers, and other files may change when their benchmark effect is exclusive to the corresponding newly appended points. All added changelog entries must be append-only, and eval modifiers are forbidden. Trace behavior through the complete diff; unguarded changes or paths reachable by an existing point are blocking.

## Spawning Additional Workers:
You CAN spawn additional Claude workers by commenting "@claude" with a specific task.

Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ jobs:
router: ${{ matrix.config.router && toJson(matrix.config.router) || '' }}
kv-p2p-transfer: ${{ matrix.config['kv-p2p-transfer'] || '' }}
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
conc-list: ${{ toJson(matrix.config.conc) }}
spec-decoding: ${{ matrix.config.spec-decoding }}
disagg: ${{ matrix.config.disagg }}
Expand Down Expand Up @@ -351,6 +352,7 @@ jobs:
router: ${{ matrix.config.router && toJson(matrix.config.router) || '' }}
kv-p2p-transfer: ${{ matrix.config['kv-p2p-transfer'] || '' }}
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
conc-list: ${{ toJson(matrix.config.conc) }}
spec-decoding: ${{ matrix.config.spec-decoding }}
disagg: ${{ matrix.config.disagg }}
Expand Down Expand Up @@ -391,6 +393,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
runner: ${{ matrix.config.runner }}
priority: ${{ matrix.config.priority }}
queue-token: ${{ matrix.config['queue-token'] }}
Expand Down Expand Up @@ -435,6 +438,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
runner: ${{ matrix.config.runner }}
priority: ${{ matrix.config.priority }}
queue-token: ${{ matrix.config['queue-token'] }}
Expand Down Expand Up @@ -476,6 +480,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
isl: '0'
osl: '0'
max-model-len: '0'
Expand Down Expand Up @@ -532,6 +537,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
isl: '0'
osl: '0'
max-model-len: '0'
Expand Down Expand Up @@ -591,6 +597,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
isl: ${{ matrix.config.isl }}
osl: ${{ matrix.config.osl }}
max-model-len: ${{ matrix.config.max-model-len }}
Expand Down Expand Up @@ -629,6 +636,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
isl: ${{ matrix.config.isl }}
osl: ${{ matrix.config.osl }}
max-model-len: ${{ matrix.config.max-model-len }}
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/run-sweep.yml
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
isl: ${{ matrix.config.isl }}
osl: ${{ matrix.config.osl }}
max-model-len: ${{ matrix.config.max-model-len }}
Expand Down Expand Up @@ -469,6 +470,7 @@ jobs:
router: ${{ matrix.config.router && toJson(matrix.config.router) || '' }}
kv-p2p-transfer: ${{ matrix.config['kv-p2p-transfer'] || '' }}
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
conc-list: ${{ toJson(matrix.config.conc) }}
spec-decoding: ${{ matrix.config.spec-decoding }}
disagg: ${{ matrix.config.disagg }}
Expand Down Expand Up @@ -533,6 +535,7 @@ jobs:
secrets: inherit
with: &single-node-inputs
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
isl: ${{ matrix.config.isl }}
osl: ${{ matrix.config.osl }}
max-model-len: ${{ matrix.config.max-model-len }}
Expand Down Expand Up @@ -597,6 +600,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
runner: ${{ matrix.config.runner }}
priority: ${{ matrix.config.priority }}
queue-token: ${{ matrix.config['queue-token'] }}
Expand Down Expand Up @@ -648,6 +652,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
isl: '0'
osl: '0'
max-model-len: '0'
Expand Down Expand Up @@ -713,6 +718,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
isl: ${{ matrix.config.isl }}
osl: ${{ matrix.config.osl }}
max-model-len: ${{ matrix.config.max-model-len }}
Expand Down Expand Up @@ -762,6 +768,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
runner: ${{ matrix.config.runner }}
priority: ${{ matrix.config.priority }}
queue-token: ${{ matrix.config['queue-token'] }}
Expand Down Expand Up @@ -814,6 +821,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
isl: ${{ matrix.config.isl }}
osl: ${{ matrix.config.osl }}
max-model-len: ${{ matrix.config.max-model-len }}
Expand Down Expand Up @@ -879,6 +887,7 @@ jobs:
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
recipe-fingerprint: ${{ matrix.config['recipe-fingerprint'] || '' }}
isl: '0'
osl: '0'
max-model-len: '0'
Expand Down
Loading