Skip to content

Add multi-dataset model run prediction uploads - #472

Merged
luke-e-schaefer merged 6 commits into
masterfrom
lukeschaefer/multi-dataset-model-runs
Aug 18, 2026
Merged

Add multi-dataset model run prediction uploads#472
luke-e-schaefer merged 6 commits into
masterfrom
lukeschaefer/multi-dataset-model-runs

Conversation

@luke-e-schaefer

@luke-e-schaefer luke-e-schaefer commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary — v0.20.0: multi-dataset model runs

Stacked on #467 (update-nuc-sdk-for-new-eval-stuff-pt1) — review that first; this PR's diff is only the 7 files below. The SDK-visible half of the scaleapi change that gives a model run a resolved set of datasets instead of one declared dataset.

The one new method

dataset_b.upload_predictions_for_model_run(run_id, predictions)

Posts to dataset/{dataset_id}/modelRun/{model_run_id}/uploadPredictions, adding dataset_b to the run's dataset set. That is what lets a single run be scored against a benchmark whose items span several datasets — previously create_benchmark_evaluation_v2 returned a 400 for exactly that case.

Same update / asynchronous / batch_size / file-batching / trained_slice_id arguments as upload_predictions, and it runs the same duplicate-id check.

What is deliberately not changed

Dataset.upload_predictions still cannot widen a run, and that's the point. It identifies the run by (dataset, model), so it finds the run already on this dataset or creates a new one. Widening got its own endpoint rather than loosening this one — mirroring the server, where the existing route kept its never-widen contract exactly as it was.

ModelRun.predict also stays on the old route. It's deprecated, and switching it would silently turn a stale dataset_id passed to get_model_run() into a widening upload. Its docstring now says it fails for multi-dataset runs and points at the new method.

Routing

PredictionUploader now accepts dataset_id together with model_run_id — previously an assertion rejected the pair — and picks the endpoint from which identifiers are present:

Arguments Route Can widen?
dataset_id + model_run_id dataset/{ds}/modelRun/{run}/uploadPredictions Yes
dataset_id + model_id dataset/{ds}/model/{model}/uploadPredictions No
model_run_id alone modelRun/{run}/predict No (deprecated)

The two pre-existing forms route exactly as before.

Access, and the sharp edge

Widening requires write on this dataset and on every dataset the run already covers. That's stricter than it looks necessary, for a reason worth knowing: a run is visible only to users who can read all of its datasets, so adding a dataset to a run can remove that run from a collaborator's view. The set also only ever grows — a later upload never drops a dataset, so it can't widen who can read the run.

Docstring corrections

Both are wrong as of the server change, not merely incomplete:

  • create_benchmark_evaluation_v2 / Benchmark.create_evaluation_v2 said the run's predictions "must cover items from the benchmark's datasets". The server enforced that with a 400; it no longer does. Coverage may be partial or empty, and uncovered members score as false negatives.
  • ModelRun.predict — see above.

Tests

tests/test_multi_dataset_model_runs.py — 9 mock-based tests pinning all three routes (the whole difference between them is the route), the async route, trained_slice_id forwarding, and that the new entry point runs the duplicate-id check rather than bypassing it.

Ran locally: 68 passed across the new file plus the benchmark / eval-v2 / preset / leaderboard suites. black and isort clean on the changed files. Diff is purely additive — no reformatting churn from a newer local black.

Server dependency: the new route ships with the multi-dataset model-run work in scaleapi (#154100). Unit tests pass regardless; live calls 404 until that deploys.

🤖 Generated with Claude Code

Greptile Summary

Adds multi-dataset model-run prediction uploads while preserving existing upload behavior.

  • Adds Dataset.upload_predictions_for_model_run with synchronous and asynchronous widening routes.
  • Refactors shared prediction-upload validation and dispatch into _upload_predictions.
  • Keeps deprecated ModelRun.predict on its existing endpoint and documents its multi-dataset limitation.
  • Updates benchmark-evaluation documentation, package version, changelog, and route-focused tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
nucleus/dataset.py Adds the public multi-dataset upload entry point and extracts common synchronous/asynchronous upload handling.
nucleus/annotation_uploader.py Extends prediction uploader routing to support explicit dataset-and-run uploads while validating identifier combinations.
nucleus/model_run.py Preserves the deprecated prediction route through an explicit override and documents its multi-dataset limitation.
tests/test_multi_dataset_model_runs.py Covers identifier validation, all upload routes, asynchronous routing, trained-slice forwarding, and duplicate-ID rejection.
nucleus/init.py Corrects benchmark-evaluation documentation to describe partial or empty model-run coverage.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Prediction upload] --> B{Identifiers supplied}
    B -->|dataset_id + model_run_id| C[dataset/:dataset/modelRun/:run/uploadPredictions]
    B -->|dataset_id + model_id| D[dataset/:dataset/model/:model/uploadPredictions]
    B -->|Deprecated ModelRun.predict| E[modelRun/:run/predict]
    C --> F[Existing run may gain dataset]
    D --> G[Resolve or create run for dataset and model]
    E --> H[Retain legacy single-dataset behavior]
Loading

Reviews (7): Last reviewed commit: "updatte" | Re-trigger Greptile

@luke-e-schaefer
luke-e-schaefer marked this pull request as ready for review August 3, 2026 16:01
Base automatically changed from update-nuc-sdk-for-new-eval-stuff-pt1 to master August 11, 2026 14:24
Stacks on update-nuc-sdk-for-new-eval-stuff-pt1 (#467). The SDK-visible half
of the scaleapi change that gives a model run a resolved *set* of datasets
instead of one declared dataset.

`Dataset.upload_predictions_for_model_run(model_run_id, predictions, ...)`
posts to the new `dataset/{dataset_id}/modelRun/{model_run_id}/uploadPredictions`
route, which adds this dataset to the run's set. That is what lets one run be
scored against a benchmark whose items span several datasets.

`upload_predictions` is untouched and still cannot widen a run — it identifies
the run by (dataset, model), so it finds the run already on this dataset or
creates a new one. Keeping the two separate mirrors the server, where the
existing route deliberately kept its never-widen contract and widening got its
own endpoint.

`PredictionUploader` now accepts `dataset_id` together with `model_run_id`
(previously an assertion rejected the pair) and routes on which identifiers are
present. The other two forms are unchanged.

Docstring corrections the server change makes necessary:

- `create_benchmark_evaluation_v2` and `Benchmark.create_evaluation_v2` said the
  run's predictions "must cover items from the benchmark's datasets". The server
  used to enforce that with a 400; it no longer does, and uncovered members
  score as false negatives.
- `ModelRun.predict` infers its dataset from the run, so it fails for a
  multi-dataset run. Noted, pointing at the new method. Left on the old route:
  it is deprecated, and switching it would silently turn a stale `dataset_id`
  passed to `get_model_run()` into a widening upload.

Verified: 9 new mock-based tests in tests/test_multi_dataset_model_runs.py
pinning all three routes plus the async route, trained_slice_id forwarding and
duplicate-id rejection. 68 tests pass across the eval/benchmark/preset/
leaderboard suites. black and isort clean on the changed files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@luke-e-schaefer
luke-e-schaefer force-pushed the lukeschaefer/multi-dataset-model-runs branch from f49543a to 8b7e8b5 Compare August 11, 2026 14:35
@luke-e-schaefer
luke-e-schaefer requested a review from a team August 17, 2026 17:06
@luke-e-schaefer luke-e-schaefer self-assigned this Aug 17, 2026

@jaypsiri jaypsiri left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

had a few comments/questions!

Comment thread nucleus/annotation_uploader.py Outdated
Comment thread nucleus/annotation_uploader.py Outdated
Comment thread nucleus/annotation_uploader.py Outdated
Comment thread nucleus/annotation_uploader.py Outdated
Comment thread nucleus/__init__.py
Comment thread nucleus/dataset.py
Comment thread nucleus/dataset.py
luke-e-schaefer and others added 4 commits August 18, 2026 13:55
Addresses jaypsiri's review feedback:
- Replace the three argument-validation asserts in PredictionUploader.__init__
  with explicit ValueError raises (asserts get stripped under python -O), and
  update the two tests that pinned AssertionError.
- Add the -> Union[Dict[str, Any], AsyncJob] return annotation to
  Dataset.upload_predictions_for_model_run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dataset-model-runs

# Conflicts:
#	CHANGELOG.md
#	pyproject.toml
Per jaypsiri: upload_predictions and upload_predictions_for_model_run were
near-identical — only the uploader construction and the async route differ; the
duplicate-id check and the sync/async dispatch were duplicated. Both now build
their uploader + async_route and delegate to a private _upload_predictions.
Behaviour is unchanged (the existing route/async/trained_slice tests still pass).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…id-routing

Per jaypsiri (#4): PredictionUploader now derives only the two uploadPredictions
endpoints from ids (dataset_id is required; model_id XOR model_run_id). The
deprecated modelRun/{run}/predict route is no longer one of its id-based forms.

ModelRun.predict — the sole consumer — keeps working by passing that route
explicitly via the new `route=` escape hatch (it has no model_id and must not
switch to the widening route). Its behavior is unchanged; it's still deprecated
and points at Dataset.upload_predictions_for_model_run.

Tests updated: model_run_id-alone now raises (dataset_id required); added
coverage for the explicit-route override.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@jaypsiri jaypsiri left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few nits on comment stuff but other than this lgtm!

Comment thread nucleus/model_run.py Outdated
Comment thread nucleus/model_run.py Outdated
@luke-e-schaefer
luke-e-schaefer merged commit 23a81b1 into master Aug 18, 2026
3 of 9 checks passed
@luke-e-schaefer
luke-e-schaefer deleted the lukeschaefer/multi-dataset-model-runs branch August 18, 2026 20:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants