Skip to content

[DRAFT] feat: add generalized Kaggle Community Benchmarks adapter#191

Draft
mrshu wants to merge 1 commit into
evaleval:mainfrom
mrshu:mrshu/kaggle-benchmarks-adapter
Draft

[DRAFT] feat: add generalized Kaggle Community Benchmarks adapter#191
mrshu wants to merge 1 commit into
evaleval:mainfrom
mrshu:mrshu/kaggle-benchmarks-adapter

Conversation

@mrshu

@mrshu mrshu commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Previously the only Kaggle ingestion was a single hardcoded script (utils/global-mmlu-lite) bound to one benchmark and one metric path. This commit adds a generalized adapter that converts any Kaggle Community Benchmark leaderboard into the EvalEval schema (v0.2.2), either for explicit owner/slug targets or by discovering and converting every published benchmark. A full run converts 996/1017 benchmarks into about 13.7k schema-valid records, which would make Kaggle the second-largest source in the datastore.

Discovery uses Kaggle's unauthenticated internal RPC (benchmarks.BenchmarkService/ListBenchmarks) with the anonymous XSRF cookie/header handshake, because no official package, sitemap, or public endpoint can enumerate community benchmarks. Per-benchmark leaderboards are read from the public REST endpoint
(/api/v1/benchmarks/{owner}/{slug}/leaderboard). Both APIs are undocumented for consumers, so the response shapes the adapter relies on are pinned by validation and tests rather than an upstream contract.

Schema mapping is deliberately conservative about what Kaggle actually exposes:

  • Numeric results in [0, 1] become bounded continuous metrics; boolean results become binary. Numeric values outside [0, 1] have an unknown scale (Kaggle does not publish metric bounds) and are left untyped rather than given fabricated [0, 1] bounds; COUNTS-typed metrics are never bounded even when a value happens to fall in [0, 1].
  • Confidence intervals are emitted as [score - ci, score + ci] because Kaggle's confidenceInterval is a symmetric half-width ("confidence radius"), matching the sibling utils/hle adapter.
  • Each result carries its Kaggle evaluationDate as evaluation_timestamp when present (about 70% of results).
  • On the discovery path, benchmark scoring config enriches each record: lower_is_better from sortOrder, metric_kind from aggregationType (only PERCENTAGE_PASSED -> pass_rate; generic reductions like AVERAGE/SUM are intentionally not metric families), metric_unit from displayType, with benchmark_id/aggregation_type/display_type recorded in source_metadata.additional_details. The targeted --benchmark path has no access to this metadata, so those fields fall back to defaults there (a documented limitation).

Bulk runs are built to fail loudly rather than silently lose data: a fetch failure is distinguished from an empty leaderboard, discovery truncation and per-benchmark conversion errors are isolated and surfaced, and the process exits non-zero when any benchmark could not be fetched, converted, or discovered, so a partial run is never reported as a clean success.

  • Add utils/kaggle/adapter.py with --benchmark owner/slug (repeatable), --all, --limit, and --output-dir; targets are de-duplicated by (owner, slug), preferring the metadata-carrying entry
  • Resolve the leaderboard owner as the organization slug when org-owned, else the creating user's username; owner-qualify evaluation_id
  • Write to the standard data/{benchmark}/{developer}/{model}/{uuid}.json layout via the shared helpers (make_model_info, make_source_metadata, save_evaluation_log)
  • Add tests/test_kaggle_adapter.py: 31 network-free tests covering result-type handling, CI bracketing, metadata enrichment, discovery pagination/filtering, the failure-vs-empty contract, dedup, and the non-zero-exit path
  • Document usage, the discovery/bounds behavior, and the targeted-path limitation in utils/README.md; retain the global-mmlu-lite adapter for backwards compatibility

Previously the only Kaggle ingestion was a single hardcoded script
(utils/global-mmlu-lite) bound to one benchmark and one metric path. This
commit adds a generalized adapter that converts any Kaggle Community
Benchmark leaderboard into the EvalEval schema (v0.2.2), either for
explicit owner/slug targets or by discovering and converting every
published benchmark. A full run converts ~996/1017 benchmarks into
~13.7k schema-valid records, which would make Kaggle the second-largest
source in the datastore.

Discovery uses Kaggle's unauthenticated internal RPC
(benchmarks.BenchmarkService/ListBenchmarks) with the anonymous XSRF
cookie/header handshake, because no official package, sitemap, or public
endpoint can enumerate community benchmarks. Per-benchmark leaderboards
are read from the public REST endpoint
(/api/v1/benchmarks/{owner}/{slug}/leaderboard). Both APIs are
undocumented for consumers, so the response shapes the adapter relies on
are pinned by validation and tests rather than an upstream contract.

Schema mapping is deliberately conservative about what Kaggle actually
exposes:

- Numeric results in [0, 1] become bounded `continuous` metrics; boolean
  results become `binary`. Numeric values outside [0, 1] have an unknown
  scale (Kaggle does not publish metric bounds) and are left untyped
  rather than given fabricated [0, 1] bounds; `COUNTS`-typed metrics are
  never bounded even when a value happens to fall in [0, 1].
- Confidence intervals are emitted as `[score - ci, score + ci]` because
  Kaggle's `confidenceInterval` is a symmetric half-width ("confidence
  radius"), matching the sibling utils/hle adapter.
- Each result carries its Kaggle `evaluationDate` as
  `evaluation_timestamp` when present (~70% of results).
- On the discovery path, benchmark scoring config enriches each record:
  `lower_is_better` from `sortOrder`, `metric_kind` from `aggregationType`
  (only `PERCENTAGE_PASSED -> pass_rate`; generic reductions like
  AVERAGE/SUM are intentionally not metric families), `metric_unit` from
  `displayType`, with `benchmark_id`/`aggregation_type`/`display_type`
  recorded in `source_metadata.additional_details`. The targeted
  `--benchmark` path has no access to this metadata, so those fields fall
  back to defaults there (a documented limitation).

Bulk runs are built to fail loudly rather than silently lose data: a
fetch failure is distinguished from an empty leaderboard, discovery
truncation and per-benchmark conversion errors are isolated and surfaced,
and the process exits non-zero when any benchmark could not be fetched,
converted, or discovered, so a partial run is never reported as a clean
success.

- Add `utils/kaggle/adapter.py` with `--benchmark owner/slug`
  (repeatable), `--all`, `--limit`, and `--output-dir`; targets are
  de-duplicated by (owner, slug), preferring the metadata-carrying entry
- Resolve the leaderboard owner as the organization slug when org-owned,
  else the creating user's username; owner-qualify `evaluation_id`
- Write to the standard data/{benchmark}/{developer}/{model}/{uuid}.json
  layout via the shared helpers (make_model_info, make_source_metadata,
  save_evaluation_log)
- Add `tests/test_kaggle_adapter.py`: 31 network-free tests covering
  result-type handling, CI bracketing, metadata enrichment, discovery
  pagination/filtering, the failure-vs-empty contract, dedup, and the
  non-zero-exit path
- Document usage, the discovery/bounds behavior, and the targeted-path
  limitation in utils/README.md; retain the global-mmlu-lite adapter for
  backwards compatibility
@mrshu mrshu marked this pull request as draft June 21, 2026 21:24
@mrshu mrshu changed the title feat: add generalized Kaggle Community Benchmarks adapter [DRAFT] feat: add generalized Kaggle Community Benchmarks adapter Jun 21, 2026
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.

1 participant