josefchen commited on
Commit
f0c6805
·
verified ·
1 Parent(s): 6aec8cd

Publish the arXiv-linked v1.3 leaderboard

Browse files

Embeds the bound stability analysis, exposes the 342 optimizer-facing reward maps while keeping the 84-task transfer split out of the reward endpoint, and links the canonical arXiv record.

README.md CHANGED
@@ -83,15 +83,18 @@ The Space exposes four named endpoints:
83
  |---|---|
84
  | `/score_completion` | Score one completion on one official task |
85
  | `/score_submission` | Score a complete JSON or JSONL artifact supplied as text |
86
- | `/training_reward` | Query one of 426 anchor-disjoint development reward maps |
87
  | `/score_uploaded_submission` | Score an uploaded artifact and return a report |
88
 
89
  Use **Use via API** in the running Space for generated Python, JavaScript, and curl clients. For
90
  high-throughput RL, use the local deterministic reward function. The linked dataset includes
91
  ready-to-load SFT, DPO, and GRPO views plus runnable LoRA recipes for Hugging Face Jobs.
92
 
 
 
 
93
  [Dataset and lab kit](https://huggingface.co/datasets/josefchen/flavourbench)   
94
- [Paper](https://github.com/josefchen/flavourbench/blob/main/paper/build/flavourbench.pdf)   
95
  [Source](https://github.com/josefchen/flavourbench)
96
 
97
  Josef Chen, Independent Researcher<br>
@@ -101,6 +104,11 @@ Erim Hayretci, Imperial College London
101
  @article{chen2026flavourbench,
102
  title = {FlavourBench: Ranking Frontier Language Models with Executable Culinary Ground Truth},
103
  author = {Chen, Josef and Hayretci, Erim},
104
- year = {2026}
 
 
 
 
 
105
  }
106
  ```
 
83
  |---|---|
84
  | `/score_completion` | Score one completion on one official task |
85
  | `/score_submission` | Score a complete JSON or JSONL artifact supplied as text |
86
+ | `/training_reward` | Query one of 342 anchor-disjoint train/validation reward maps |
87
  | `/score_uploaded_submission` | Score an uploaded artifact and return a report |
88
 
89
  Use **Use via API** in the running Space for generated Python, JavaScript, and curl clients. For
90
  high-throughput RL, use the local deterministic reward function. The linked dataset includes
91
  ready-to-load SFT, DPO, and GRPO views plus runnable LoRA recipes for Hugging Face Jobs.
92
 
93
+ The [prospective reward-transfer protocol](https://github.com/josefchen/flavourbench/blob/main/docs/reward-transfer-study.md)
94
+ defines the 84-task transfer split, seeds, six confirmatory contrasts, and multiplicity control.
95
+
96
  [Dataset and lab kit](https://huggingface.co/datasets/josefchen/flavourbench)&nbsp;&nbsp;&nbsp;
97
+ [Paper](https://arxiv.org/abs/2608.20574)&nbsp;&nbsp;&nbsp;
98
  [Source](https://github.com/josefchen/flavourbench)
99
 
100
  Josef Chen, Independent Researcher<br>
 
104
  @article{chen2026flavourbench,
105
  title = {FlavourBench: Ranking Frontier Language Models with Executable Culinary Ground Truth},
106
  author = {Chen, Josef and Hayretci, Erim},
107
+ journal = {arXiv preprint arXiv:2608.20574},
108
+ year = {2026},
109
+ eprint = {2608.20574},
110
+ archivePrefix = {arXiv},
111
+ primaryClass = {cs.CL},
112
+ url = {https://arxiv.org/abs/2608.20574}
113
  }
114
  ```
app.py CHANGED
@@ -30,7 +30,7 @@ BUNDLE_PATH = Path(
30
 
31
  RUST = "#A83D34"
32
  INK = "#161817"
33
- PAPER_URL = "https://github.com/josefchen/flavourbench/blob/main/paper/build/flavourbench.pdf"
34
  DATASET_URL = "https://huggingface.co/datasets/josefchen/flavourbench"
35
  SOURCE_URL = "https://github.com/josefchen/flavourbench"
36
  DATASET_RESULTS_URL = (
@@ -1140,6 +1140,7 @@ MODELS = BUNDLE["models"]
1140
  TASKS = BUNDLE["tasks"]
1141
  LAB_TASKS = BUNDLE.get("lab_tasks", [])
1142
  PAIRWISE = BUNDLE["pairwise_comparisons"]
 
1143
  MODEL_COUNT = len(MODELS)
1144
  TASK_COUNT = len(TASKS)
1145
  PAIR_COUNT = len(PAIRWISE)
@@ -1658,6 +1659,23 @@ def _insights_html() -> str:
1658
  "mean_difference", float(DISPLAY_MODELS[0]["flavourbench_score"]) - chance
1659
  )
1660
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1661
  return f"""
1662
  <div class="fb-insight-layout">
1663
  <section>
@@ -1675,6 +1693,29 @@ def _insights_html() -> str:
1675
  </div>
1676
  </aside>
1677
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1678
  <section class="fb-family-insight">
1679
  <h3>Where the leading labs differ</h3>
1680
  <p>Scores are out of 100. Red marks each column leader.</p>
@@ -2417,8 +2458,9 @@ and GRPO recipes in the source repository. The full publication contract is in t
2417
  sign flips, Holm correction, exact tests against a random legal choice, bootstrap rank intervals,
2418
  and an independently compiled second panel.</p>
2419
  <h3>Training boundary</h3>
2420
- <p>The 426 SFT, DPO, and GRPO development maps use anchors that do not occur in
2421
- the {TASK_COUNT}-task leaderboard. Training cannot query the official test reward maps by accident.</p>
 
2422
  <aside class="fb-evidence">
2423
  <strong>Content-addressed release</strong><br>
2424
  <span class="fb-hash">{BUNDLE["release_artifact_sha256"]}</span><br><br>
@@ -2467,7 +2509,7 @@ pytest -q tests/lab_cli_test.py tests/hf_lab_space_api_test.py
2467
  <span>Erim Hayretci, Imperial College London</span>
2468
  </div>
2469
  <nav class="fb-footer-links" aria-label="Project resources">
2470
- <a href="https://github.com/josefchen/flavourbench/blob/main/paper/build/flavourbench.pdf">Paper</a>
2471
  <a href="https://huggingface.co/datasets/josefchen/flavourbench">Dataset</a>
2472
  <a href="https://github.com/josefchen/flavourbench">Source</a>
2473
  </nav>
 
30
 
31
  RUST = "#A83D34"
32
  INK = "#161817"
33
+ PAPER_URL = "https://arxiv.org/abs/2608.20574"
34
  DATASET_URL = "https://huggingface.co/datasets/josefchen/flavourbench"
35
  SOURCE_URL = "https://github.com/josefchen/flavourbench"
36
  DATASET_RESULTS_URL = (
 
1140
  TASKS = BUNDLE["tasks"]
1141
  LAB_TASKS = BUNDLE.get("lab_tasks", [])
1142
  PAIRWISE = BUNDLE["pairwise_comparisons"]
1143
+ STABILITY = BUNDLE["stability_analysis"]
1144
  MODEL_COUNT = len(MODELS)
1145
  TASK_COUNT = len(TASKS)
1146
  PAIR_COUNT = len(PAIRWISE)
 
1659
  "mean_difference", float(DISPLAY_MODELS[0]["flavourbench_score"]) - chance
1660
  )
1661
  )
1662
+ stability_rows = []
1663
+ for row in STABILITY["task_count_stability"]:
1664
+ rank = row["metrics"]["rank_spearman"]
1665
+ top_five = row["metrics"]["top_5_overlap"]
1666
+ leader = row["metrics"]["top_1_preserved"]
1667
+ stability_rows.append(
1668
+ "<tr>"
1669
+ f"<td>{int(row['tasks'])}</td>"
1670
+ f"<td>{float(rank['median']):.3f}</td>"
1671
+ f"<td>{float(rank['p2_5']):.3f}–{float(rank['p97_5']):.3f}</td>"
1672
+ f"<td>{float(top_five['median']) * 100:.0f}%</td>"
1673
+ f"<td>{float(leader['mean']) * 100:.1f}%</td>"
1674
+ "</tr>"
1675
+ )
1676
+ variance = STABILITY["variance_partition"]
1677
+ generalizability = float(variance["relative_decision_generalizability_at_534_tasks"])
1678
+ tasks_for_g_90 = int(variance["estimated_balanced_tasks_for_relative_g_0_90"])
1679
  return f"""
1680
  <div class="fb-insight-layout">
1681
  <section>
 
1693
  </div>
1694
  </aside>
1695
  </div>
1696
+ <section class="fb-family-insight">
1697
+ <h3>Why 534 tasks?</h3>
1698
+ <p>The crossed design's descriptive relative-decision generalizability is
1699
+ <strong>{generalizability:.3f}</strong>; the same variance model estimates
1700
+ <strong>{tasks_for_g_90}</strong> balanced tasks for 0.90. The table below repeatedly takes
1701
+ score-blind, balanced subsets and compares them with the complete point order.</p>
1702
+ <div class="fb-table-wrap">
1703
+ <table class="fb-table">
1704
+ <caption>5,000 family-by-panel stratified subsets at each non-complete task count</caption>
1705
+ <thead><tr>
1706
+ <th scope="col">Tasks</th>
1707
+ <th scope="col">Median rank ρ</th>
1708
+ <th scope="col">Empirical 95%</th>
1709
+ <th scope="col">Top-five overlap</th>
1710
+ <th scope="col">Point leader kept</th>
1711
+ </tr></thead>
1712
+ <tbody>{"".join(stability_rows)}</tbody>
1713
+ </table>
1714
+ </div>
1715
+ <p class="fb-resolution-note">This is a precision diagnostic relative to the complete
1716
+ release, not a post-hoc power claim. The point leader remains unstable in smaller subsets;
1717
+ the simultaneous score bands and rank intervals remain the inferential result.</p>
1718
+ </section>
1719
  <section class="fb-family-insight">
1720
  <h3>Where the leading labs differ</h3>
1721
  <p>Scores are out of 100. Red marks each column leader.</p>
 
2458
  sign flips, Holm correction, exact tests against a random legal choice, bootstrap rank intervals,
2459
  and an independently compiled second panel.</p>
2460
  <h3>Training boundary</h3>
2461
+ <p>The 342 optimizer-facing SFT, DPO, and GRPO maps use anchors that do not
2462
+ occur in the 84-task transfer split or the {TASK_COUNT}-task leaderboard.
2463
+ Training cannot query either evaluation map through the reward endpoint.</p>
2464
  <aside class="fb-evidence">
2465
  <strong>Content-addressed release</strong><br>
2466
  <span class="fb-hash">{BUNDLE["release_artifact_sha256"]}</span><br><br>
 
2509
  <span>Erim Hayretci, Imperial College London</span>
2510
  </div>
2511
  <nav class="fb-footer-links" aria-label="Project resources">
2512
+ <a href="https://arxiv.org/abs/2608.20574">Paper</a>
2513
  <a href="https://huggingface.co/datasets/josefchen/flavourbench">Dataset</a>
2514
  <a href="https://github.com/josefchen/flavourbench">Source</a>
2515
  </nav>
build_complete_core_space_bundle.py CHANGED
@@ -11,6 +11,9 @@ from typing import Any
11
  HERE = Path(__file__).resolve().parent
12
  DEFAULT_DATASET = HERE.parent / "dataset" / "data-complete-core"
13
  DEFAULT_LAB_DATASET = HERE.parent / "dataset" / "data-lab"
 
 
 
14
  DEFAULT_OUTPUT = HERE / "data-complete-core" / "flavourbench-complete-core-space.json"
15
 
16
 
@@ -53,7 +56,12 @@ def _jsonl(path: Path, *, expected_sha256: str, expected_rows: int) -> list[dict
53
  return rows
54
 
55
 
56
- def build_bundle(*, dataset_directory: Path, lab_dataset_directory: Path) -> dict[str, Any]:
 
 
 
 
 
57
  manifest = _load(dataset_directory / "DATA_MANIFEST.json")
58
  if (
59
  not _semantic_valid(manifest)
@@ -92,8 +100,8 @@ def build_bundle(*, dataset_directory: Path, lab_dataset_directory: Path) -> dic
92
  lab_manifest = _load(lab_dataset_directory / "DATA_MANIFEST.json")
93
  if (
94
  not _semantic_valid(lab_manifest)
95
- or lab_manifest.get("schema_version") != "flavourbench-lab-dataset-v1"
96
- or lab_manifest.get("status") != "development_reward_maps_not_official_test"
97
  ):
98
  raise CompleteCoreSpaceBuildError("lab dataset manifest failed verification")
99
  lab_records = {str(row["name"]): row for row in lab_manifest["files"]}
@@ -107,14 +115,21 @@ def build_bundle(*, dataset_directory: Path, lab_dataset_directory: Path) -> dic
107
  )
108
 
109
  lab_tasks = [*lab_rows("train_tasks.jsonl"), *lab_rows("validation_tasks.jsonl")]
 
 
 
 
 
 
 
110
  official_ids = {str(row["task_id"]) for row in tasks}
111
  official_anchors = {str(row["anchor_ingredient"]) for row in tasks}
112
  lab_ids = {str(row["task_id"]) for row in lab_tasks}
113
  lab_anchors = {str(row["anchor_ingredient"]) for row in lab_tasks}
114
  if (
115
- len(lab_tasks) != 426
116
- or len(lab_ids) != 426
117
- or len(lab_anchors) != 426
118
  or lab_ids & official_ids
119
  or lab_anchors & official_anchors
120
  ):
@@ -160,9 +175,11 @@ def build_bundle(*, dataset_directory: Path, lab_dataset_directory: Path) -> dic
160
  "task_count": len(lab_tasks),
161
  "train_tasks": int(lab_manifest["counts"]["train_tasks"]),
162
  "validation_tasks": int(lab_manifest["counts"]["validation_tasks"]),
 
163
  "official_anchor_overlap": 0,
164
  },
165
  "lab_tasks": lab_tasks,
 
166
  "primary_observations": compact_observations,
167
  "pairwise_comparisons": pairwise,
168
  }
@@ -199,12 +216,14 @@ def main() -> None:
199
  parser = argparse.ArgumentParser(description="Build the final FlavourBench Space bundle")
200
  parser.add_argument("--dataset-directory", type=Path, default=DEFAULT_DATASET)
201
  parser.add_argument("--lab-dataset-directory", type=Path, default=DEFAULT_LAB_DATASET)
 
202
  parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT)
203
  parser.add_argument("--check", action="store_true")
204
  args = parser.parse_args()
205
  bundle = build_bundle(
206
  dataset_directory=args.dataset_directory,
207
  lab_dataset_directory=args.lab_dataset_directory,
 
208
  )
209
  payload = _bytes(bundle)
210
  if args.check:
 
11
  HERE = Path(__file__).resolve().parent
12
  DEFAULT_DATASET = HERE.parent / "dataset" / "data-complete-core"
13
  DEFAULT_LAB_DATASET = HERE.parent / "dataset" / "data-lab"
14
+ DEFAULT_STABILITY = (
15
+ HERE.parents[1] / "paper/generated/complete-core/complete-core-stability-analysis.json"
16
+ )
17
  DEFAULT_OUTPUT = HERE / "data-complete-core" / "flavourbench-complete-core-space.json"
18
 
19
 
 
56
  return rows
57
 
58
 
59
+ def build_bundle(
60
+ *,
61
+ dataset_directory: Path,
62
+ lab_dataset_directory: Path,
63
+ stability_path: Path = DEFAULT_STABILITY,
64
+ ) -> dict[str, Any]:
65
  manifest = _load(dataset_directory / "DATA_MANIFEST.json")
66
  if (
67
  not _semantic_valid(manifest)
 
100
  lab_manifest = _load(lab_dataset_directory / "DATA_MANIFEST.json")
101
  if (
102
  not _semantic_valid(lab_manifest)
103
+ or lab_manifest.get("schema_version") != "flavourbench-lab-dataset-v2"
104
+ or lab_manifest.get("status") != "preregistered_transfer_maps_not_official_leaderboard_test"
105
  ):
106
  raise CompleteCoreSpaceBuildError("lab dataset manifest failed verification")
107
  lab_records = {str(row["name"]): row for row in lab_manifest["files"]}
 
115
  )
116
 
117
  lab_tasks = [*lab_rows("train_tasks.jsonl"), *lab_rows("validation_tasks.jsonl")]
118
+ stability = _load(stability_path)
119
+ if (
120
+ not _semantic_valid(stability)
121
+ or stability.get("schema_version") != "flavourbench-task-count-stability-v1"
122
+ or stability.get("status") != "retrospective_precision_and_stability_analysis"
123
+ ):
124
+ raise CompleteCoreSpaceBuildError("task-count stability analysis failed verification")
125
  official_ids = {str(row["task_id"]) for row in tasks}
126
  official_anchors = {str(row["anchor_ingredient"]) for row in tasks}
127
  lab_ids = {str(row["task_id"]) for row in lab_tasks}
128
  lab_anchors = {str(row["anchor_ingredient"]) for row in lab_tasks}
129
  if (
130
+ len(lab_tasks) != 342
131
+ or len(lab_ids) != 342
132
+ or len(lab_anchors) != 342
133
  or lab_ids & official_ids
134
  or lab_anchors & official_anchors
135
  ):
 
175
  "task_count": len(lab_tasks),
176
  "train_tasks": int(lab_manifest["counts"]["train_tasks"]),
177
  "validation_tasks": int(lab_manifest["counts"]["validation_tasks"]),
178
+ "evaluation_tasks": int(lab_manifest["counts"]["evaluation_tasks"]),
179
  "official_anchor_overlap": 0,
180
  },
181
  "lab_tasks": lab_tasks,
182
+ "stability_analysis": stability,
183
  "primary_observations": compact_observations,
184
  "pairwise_comparisons": pairwise,
185
  }
 
216
  parser = argparse.ArgumentParser(description="Build the final FlavourBench Space bundle")
217
  parser.add_argument("--dataset-directory", type=Path, default=DEFAULT_DATASET)
218
  parser.add_argument("--lab-dataset-directory", type=Path, default=DEFAULT_LAB_DATASET)
219
+ parser.add_argument("--stability", type=Path, default=DEFAULT_STABILITY)
220
  parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT)
221
  parser.add_argument("--check", action="store_true")
222
  args = parser.parse_args()
223
  bundle = build_bundle(
224
  dataset_directory=args.dataset_directory,
225
  lab_dataset_directory=args.lab_dataset_directory,
226
+ stability_path=args.stability,
227
  )
228
  payload = _bytes(bundle)
229
  if args.check:
data-complete-core/flavourbench-complete-core-space.json CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:026299fa7f98e2410033533ccc3e25ccd4b9df3281bb8fa34d2fcbf0678f8290
3
- size 14662246
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7bb9959b2a73d1c5ef2cafe064805ec874b5f4fa91c05b1d005e4b6e22e4d1ff
3
+ size 14353273