Skip to content

[DRAFT] Adds YAML files for 2026-10-C1 cohort rulesets and submission checks - #545

Merged
arekay-nv merged 7 commits into
feat/validation-modulefrom
feat/mlperf-endpoints-cohort
Oct 28, 2026
Merged

arekay-nv merged 7 commits into
feat/validation-modulefrom
feat/mlperf-endpoints-cohort

Conversation

@nv-alicheng

Copy link
Copy Markdown
Collaborator

What does this PR do?

Adds the first real cohort to the validation module, plus the small module change it needs to ship its
own catalog.

The cohort is 2026-10-C1, the round this cohort targets, exercised end-to-end against real
submission artifacts for that round
It lives in src/inference_endpoint/config/cohorts/2026-10-C1/:

File What it declares
cohort.yaml the manifest: the cohort's hint and its bundled ruleset directory
point.yaml — 25 checks per-run facts: disclosure completeness, cohort and seed-set membership, seed adoption and runtime match, seed spellings, concurrency and warmup shape, run duration, output-token and P90 presence, the §12 sample-count floors, accuracy presence
system.yaml — 3 checks the §4.5.2/Appendix E power declaration, its node-set list, and the MLC-estimate flag
pareto.yaml — 2 checks §5.6's point cap and §5.4's out-of-range points, folded once per pareto
valid_refs.yaml the field vocabulary: 61 typed leaves across the four scopes, with the allowlists and absent-state notes the rows rely on
ruleset/models.yaml, ruleset/datasets.yaml the cohort's own catalog: 9 models, 11 datasets
2026-10-C1.md provenance, the "Not yet expressible" table, and this version's rough edges

Every check is a declarative row naming the Endpoints Policy section it enforces, its severity, and
the fix a failing submission should apply. Rows exist only for what a row can decide — the
"Not yet expressible" table records what the dialect cannot say today (cross-point counts and
coverage, accuracy gates, Appendix E arithmetic, upload structure) with a reason for each.

The module change lets a cohort bundle its catalog as a ruleset/ directory (ruleset_dir in
cohort.yaml, read by Catalog.from_directory) instead of naming a packaged ruleset. The two
sources are mutually exclusive, the directory must live inside the cohort, and the stray-file check
admits the new name.

Writing the cohort against real artifacts, rather than fixtures, is what caught four declaration
mistakes synthetic data could not: cooling is a string ("liquid") rather than a block;
power_method lives inside node_sets[], not at the top level; link_to_model_transformation is an
explicit null on a typed leaf; and percentile blocks are keyed "90.0" while a row names 90.

Type of change

  • New feature

Related issues

None. Stacked on #544: this branch is based on feat/validation-module, and the decoding the cohort
relies on (numeric strings, differently spelled percentile keys) landed there. Retarget to main
once #544 merges.

Testing

  • Tests added/updated — cohort loading, the bundled-catalog path and the manifest refusals in
    tests/unit/validation/test_check.py, on top of the module's existing stub-cohort coverage.
  • All tests pass locally — uv run pytest tests/unit/validation tests/unit/config/test_regenerate_templates.py -q
    → 436 passed.
  • Manual testing completed — against real submission artifacts for this round:
    • python -m inference_endpoint.validation src/inference_endpoint/config/cohorts/2026-10-C1 <submission-root>
      → 291 findings, 0 failing, exit 0 (18 checks ran; the 12 that did not apply are disclosed as
      NEVER-RAN with their reason, not silently skipped).
    • The P90 row reads a bundle's "90.0" percentile key at every measurement point.
    • A copy of the same tree with a stringified concurrency reads it as its number, prints the
      coerced: note, and returns the identical 291 findings.
    • The reference submission checker on the same tree: 0 errors, 12 warnings (11 × steady-state
      basis §4.4, 1 × agentic inline accuracy §4.3) — both already in the cohort's
      "Not yet expressible" table.

Checklist

  • Code follows project style — ruff/ruff-format clean, prettier on the YAML and Markdown.
  • Pre-commit hooks pass
  • Documentation updated (if needed) — the cohort notes, plus README and DESIGN for the bundled
    catalog.

@nv-alicheng
nv-alicheng requested a review from a team October 23, 2026 15:26
@github-actions

Copy link
Copy Markdown

MLCommons CLA bot All contributors have signed the MLCommons CLA ✍️ ✅

@github-actions github-actions Bot added the size/very-large PR Review Policy: >1500 lines or >50 files label Oct 23, 2026
@nv-alicheng
nv-alicheng changed the base branch from main to feat/validation-module October 23, 2026 15:26
@nv-alicheng nv-alicheng changed the title Feat/mlperf endpoints cohort [DRAFT] Adds YAML files for 2026-10-C1 cohort rulesets and submission checks Oct 23, 2026
A cohort could name a packaged ruleset (`ruleset: mlperf-inference-v6.1`,
resolved through the registry). It can now carry its catalog beside its checks
instead: `cohort.yaml` gains `ruleset_dir`, naming a directory under the cohort
directory that `Catalog.from_directory` reads (`models.yaml` + `datasets.yaml`),
and the stray-file refusal admits that one directory. Declaring both sources is
refused -- which catalog the rows read must never be ambiguous -- and
`ruleset_dir` must be a relative path inside the cohort, so a cohort cannot aim
the checker at arbitrary directories.
The first full Endpoints cohort in the module's dialect: 29 checks across
point.yaml/pareto.yaml/system.yaml; a `valid_refs.yaml` declaring every fact a
row may name, with §8.3/§4.4/§6.1's vocabularies as allowlists (an
out-of-vocabulary value is refused at collect, so those rules need no rows);
and a bundled `ruleset/` catalog (`models.yaml` + `datasets.yaml`) carrying the
six §3.2 names, the legacy accuracy table and the §12 acceptance counts.

Provenance is cited per file: policy sections at `4ba8224dc746`, the rule
inventory from the submission-checker CLI (`messages.yaml` and its aggregate
models), the accuracy and floor tables from the same CLI, and the model-spec
pins -- marked provisional -- from the unverified bench-suite draft at
`3bd1d0b1`. `src/inference_endpoint/config/cohorts/2026-10-C1.md` lists what the
dialect cannot yet express (cross-point counts and coverage, per-curve
consistency, the accuracy gates' conditional rescaling, metric arithmetic, the
power model, upload structure) with the reason for each, and this version's
rough edges.
Writing the cohort against real artifacts, rather than fixtures, caught four
declaration and row mistakes:

- system_power.json carries `cooling` as a string ("liquid"), not a block, and
  its vocabulary lives per node set: the table declares the real Appendix E
  top-level shape, and the rows check the node-set list and the MLC-estimate
  flag rather than a top-level `power_method`.
- `link_to_model_transformation` is a string or an explicit null, and
  `type: str` refuses the null: it stays undeclared, with the "value or null"
  declaration form noted as a dialect gap.
- percentile blocks are keyed by spelling (`tpot.percentiles["90.0"]`), so the
  P90 row became a presence-and-non-empty check over the block, with the
  canonicalisation gap noted.
- the warmup log-retention row now gates on the warmup being performed
  (`duration_s > 0`), so a disabled warmup is not warned about.

The cohort reports no failing findings against a full bundle, and the reference
checker agrees on the same tree: its warnings are rules this cohort lists as not
yet expressible.
`Ref.resolve` now reads a numeric component against a key spelling the same
number, so the cohort asserts the P90 itself (`tpot.percentiles.90`) instead of
only that the percentile block is non-empty: a block keyed `"90.0"` is read, and
the row runs at every measurement point.
The catalog carried per-model accuracy targets and per-dataset run shapes but
nothing tying the two together, so a target had no subject: `aime25`'s
`unit_samples` could belong to any model, and the §15 gate's sample-weighted
mean had no declared member sets.

- `models.yaml` gains `accuracy_datasets`: the set(s) a model's accuracy phase
  runs, with the run shape per (model, set). gpt-oss-120b's §15 `exact_match`
  gate reads its three (aime25, gpqa, livecodebench); deepseek-r1's reads its
  one (deepseek_r1_accuracy). The legacy models carry `{}` rather than a guessed
  link: this round declares no accuracy sets for them.
- Agentic gates now name what they read: `inline` -> `agentic_combined`,
  `swebench` -> `swe_bench` with `mean_of_n: 4`, `osl` ->
  `output_sequence_lengths_full_run`.
- `datasets.yaml` loses the per-dataset run shapes (they live on the tie now),
  gains the two agentic sets, and drops cnn_dailymail's unsourced pair.
- The cohort notes record the tie's source and refine what an accuracy-gate row
  would still need: the join from the run's declared model to its tie.
…ve one

gpt-oss-120b's §15 gate is the cumulative sample-weighted mean over its three
sets, but a model may also have published thresholds per set. A tied set now
accepts its own `targets`, in the same `metric: { lower | band, factor }` form
as the model-level `accuracy_targets`: `accuracy_targets` stays the cumulative
gate, a set's `targets` gate that set's own score, so a model can carry both.

Only a published number goes there: no reference publishes per-set thresholds
for this round's models, so the form is documented (models.yaml header) and left
absent rather than guessed -- the same rule the legacy tie follows. The cohort
notes record it and the row-dialect work still needed to consume either
(the model-to-set join and the per-set lookup inside accuracy_results).
@nv-alicheng
nv-alicheng force-pushed the feat/mlperf-endpoints-cohort branch from 3d1732f to b4d95af Compare October 23, 2026 16:29
@github-actions github-actions Bot added size/large PR Review Policy: 501-1500 lines or 21-50 files and removed size/very-large PR Review Policy: >1500 lines or >50 files labels Oct 23, 2026
CI's mypy hook (skipped by the local commits for three pre-existing
macOS-typeshed errors) refused the cohort wiring:

  src/inference_endpoint/validation/__main__.py:100: error: Incompatible types
  in assignment (expression has type "Catalog | None", variable has type
  "Catalog")  [assignment]

The `ruleset_dir` branch assigned a `Catalog` first, so mypy had narrowed the
name before the packaged-ruleset fallback could assign `Catalog | None`. The
name is declared `Catalog | None` up front and assigned once per branch, which
leaves the module's mypy output clean (the only errors the hook still reports
are the three pre-existing Linux-only `sched_*affinity` ones).
@arekay-nv

Copy link
Copy Markdown
Collaborator

Merging this into #544 to make reviews easier.

@arekay-nv
arekay-nv merged commit 0c7c929 into feat/validation-module Oct 28, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/large PR Review Policy: 501-1500 lines or 21-50 files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants