LennartPurucker Claude Opus 5 commited on
Commit
17d9c9b
·
1 Parent(s): 9b53220

Overview table gets a row per variant, and its cost columns follow the row

Browse files

The cross-subset overview picked each column's value independently, taking the
extremum per model. For the two cost columns that meant the minimum, which is
always the default variant, while the model cell was labelled with whichever
variant led on the selected metric. A row reading "RealMLP (tuned + ensembled)"
quoted the default's fit time: 10.06 against 2950.72, roughly 200x low, because
tuning fits 200 configurations where the default fits one. 20 of 39 model rows
were affected, by 6.8x to 902x.

Rows are now keyed by (model, variant), so default, tuned and tuned + ensembled
each get their own line and a row's cost is the cost of the run it scores. That
removes the mismatch by construction, and puts the price of tuning on the page.

"One per model" collapses each method to its best variant, decided by the
leading column. It sits in the overview's own row and feeds only that table,
and is named after the win-rate matrix's button so the two read as one control.

The upstream artifacts were correct throughout: the full leaderboard table
(72,992 time values) and pareto_front_points.csv (67,232) both agree with
website_leaderboard.csv per (model, variant), and api.py works per record.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Files changed (4) hide show
  1. main.py +11 -2
  2. pages.py +33 -5
  3. views.py +79 -36
  4. website_texts.py +10 -1
main.py CHANGED
@@ -45,6 +45,11 @@ def _choice_hints() -> dict[str, str]:
45
  hints[label] = notes[key]
46
 
47
  hints["🤖 Models"] = "Always on: TabArena is a model benchmark first."
 
 
 
 
 
48
  hints["Include imputed models"] = PROTOCOL_NOTES["imputed"]
49
  hints["TabArena-Lite (single split)"] = PROTOCOL_NOTES["lite"]
50
  # A category with no entrant yet says so, matching the disabled state the page renders.
@@ -332,7 +337,8 @@ CSS = """
332
  the chips themselves. `main.taStampTitles` moves each one into a native `title`, so it shows
333
  on hover instead, and the ? badge is what says the text is there at all. */
334
  .ta-controls span[data-testid="block-info"] { display: none !important; }
335
- .ta-controlrow .ta-catchip label::after {
 
336
  content: "?";
337
  flex: 0 0 auto;
338
  width: 14px;
@@ -346,7 +352,8 @@ CSS = """
346
  line-height: 12px;
347
  text-align: center;
348
  }
349
- .ta-controlrow .ta-catchip label:hover::after { opacity: 0.85; }
 
350
  /* Chip-bar buttons carry a tooltip too; a dotted underline hints at it without a badge on
351
  every chip, which at five per row would be louder than the chips. */
352
  .ta-controls .tab-buttons button[title] { text-decoration: underline dotted #ffffff40 1px; text-underline-offset: 3px; }
@@ -1818,6 +1825,8 @@ function taStampTitles() {
1818
  };
1819
  document.querySelectorAll(".ta-controls .ta-catchip label").forEach(stamp);
1820
  document.querySelectorAll(".ta-controls .tab-buttons button").forEach(stamp);
 
 
1821
 
1822
  // The row caption is a CSS ::before, which cannot hold a title, so it goes on the element
1823
  // the caption is drawn on. A chip inside has its own title, and the nearest one wins, so
 
45
  hints[label] = notes[key]
46
 
47
  hints["🤖 Models"] = "Always on: TabArena is a model benchmark first."
48
+ hints["One per model"] = (
49
+ "Keep only each model's best-performing variant, one row per model — as the win-rate "
50
+ "matrix does. With it off, every variant gets its own row, so you can read what "
51
+ "tuning bought."
52
+ )
53
  hints["Include imputed models"] = PROTOCOL_NOTES["imputed"]
54
  hints["TabArena-Lite (single split)"] = PROTOCOL_NOTES["lite"]
55
  # A category with no entrant yet says so, matching the disabled state the page renders.
 
337
  the chips themselves. `main.taStampTitles` moves each one into a native `title`, so it shows
338
  on hover instead, and the ? badge is what says the text is there at all. */
339
  .ta-controls span[data-testid="block-info"] { display: none !important; }
340
+ .ta-controlrow .ta-catchip label::after,
341
+ .metric-select .ta-catchip label::after {
342
  content: "?";
343
  flex: 0 0 auto;
344
  width: 14px;
 
352
  line-height: 12px;
353
  text-align: center;
354
  }
355
+ .ta-controlrow .ta-catchip label:hover::after,
356
+ .metric-select .ta-catchip label:hover::after { opacity: 0.85; }
357
  /* Chip-bar buttons carry a tooltip too; a dotted underline hints at it without a badge on
358
  every chip, which at five per row would be louder than the chips. */
359
  .ta-controls .tab-buttons button[title] { text-decoration: underline dotted #ffffff40 1px; text-underline-offset: 3px; }
 
1825
  };
1826
  document.querySelectorAll(".ta-controls .ta-catchip label").forEach(stamp);
1827
  document.querySelectorAll(".ta-controls .tab-buttons button").forEach(stamp);
1828
+ // The overview's own toggle sits outside the control card but explains itself the same way.
1829
+ document.querySelectorAll(".metric-select .ta-catchip label").forEach(stamp);
1830
 
1831
  // The row caption is a CSS ::before, which cannot hold a title, so it goes on the element
1832
  // the caption is drawn on. A chip inside has its own title, and the nearest one wins, so
pages.py CHANGED
@@ -359,9 +359,10 @@ def render_internal_page(page: LeaderboardPage) -> None:
359
  gr.HTML(
360
  '<div class="ta-section-head" id="ta-overview-section">'
361
  "<h2>🔭 Performance across leaderboards</h2>"
362
- '<p class="ta-section-sub">Best result per method across every task and dataset-size subset. '
363
  "The quickest way to spot the ones that are strong everywhere against those that shine on "
364
- "one subset.</p>"
 
365
  "</div>"
366
  )
367
  with gr.Row(elem_classes="metric-select"):
@@ -375,16 +376,43 @@ def render_internal_page(page: LeaderboardPage) -> None:
375
  min_width=200,
376
  )
377
  metric_tldr = gr.Markdown(OVERVIEW_METRIC_TLDR["Elo"], elem_classes="metric-tldr")
 
 
 
 
 
 
 
 
 
 
 
 
378
  overview_metric.change(
379
  lambda m: OVERVIEW_METRIC_TLDR.get(m, ""), overview_metric, metric_tldr, api_visibility="private"
380
  )
381
 
382
  # The overview follows the selectors too: the column each one points at leads its group and
383
  # is tinted, so the reader's own view is where their eye already is.
384
- @gr.render(inputs=[overview_metric, entrants_state, tasks_state, datasets_state, care_state])
385
- def _render_overview(metric, entrants, tasks, datasets, care):
 
 
 
 
 
 
 
 
 
386
  make_cross_subset_overview(
387
- page.data_root, metric, entrants=entrants, tasks=tasks, datasets=datasets, care=care
 
 
 
 
 
 
388
  )
389
 
390
  # The "I care about" metric drives the overview's own selector, so the two cannot disagree
 
359
  gr.HTML(
360
  '<div class="ta-section-head" id="ta-overview-section">'
361
  "<h2>🔭 Performance across leaderboards</h2>"
362
+ '<p class="ta-section-sub">Every method variant across every task and dataset-size subset. '
363
  "The quickest way to spot the ones that are strong everywhere against those that shine on "
364
+ "one subset, and to see what tuning buys. <i>One per model</i> collapses each method to its "
365
+ "best variant.</p>"
366
  "</div>"
367
  )
368
  with gr.Row(elem_classes="metric-select"):
 
376
  min_width=200,
377
  )
378
  metric_tldr = gr.Markdown(OVERVIEW_METRIC_TLDR["Elo"], elem_classes="metric-tldr")
379
+ # Lives here rather than in the control card because it only decides which rows this one
380
+ # table has. Same collapse the win-rate matrix offers and named the same, so the two read
381
+ # as one control. Off by default: how much tuning buys a model is one of the things this
382
+ # table is for.
383
+ overview_one_per_model = gr.Checkbox(
384
+ value=False,
385
+ label="One per model",
386
+ container=False,
387
+ scale=0,
388
+ min_width=180,
389
+ elem_classes=["ta-catchip"],
390
+ )
391
  overview_metric.change(
392
  lambda m: OVERVIEW_METRIC_TLDR.get(m, ""), overview_metric, metric_tldr, api_visibility="private"
393
  )
394
 
395
  # The overview follows the selectors too: the column each one points at leads its group and
396
  # is tinted, so the reader's own view is where their eye already is.
397
+ @gr.render(
398
+ inputs=[
399
+ overview_metric,
400
+ entrants_state,
401
+ tasks_state,
402
+ datasets_state,
403
+ care_state,
404
+ overview_one_per_model,
405
+ ]
406
+ )
407
+ def _render_overview(metric, entrants, tasks, datasets, care, one_per_model):
408
  make_cross_subset_overview(
409
+ page.data_root,
410
+ metric,
411
+ entrants=entrants,
412
+ tasks=tasks,
413
+ datasets=datasets,
414
+ care=care,
415
+ one_per_model=one_per_model,
416
  )
417
 
418
  # The "I care about" metric drives the overview's own selector, so the two cannot disagree
views.py CHANGED
@@ -997,8 +997,15 @@ _GROUP_TITLE = {"cost": "What it costs", "task": "By Task", "size": "By Dataset
997
  # Size definitions are reused from DATASET_SIZE_NOTE so they can't drift from the subset blurbs.
998
  _COLUMN_TOOLTIPS: dict[str, str] = {
999
  "Overall": "All tasks across every dataset size. This is the headline ranking.",
1000
- "Fit (s/1K)": "Median seconds to train per 1000 rows, across all datasets. Lower is better.",
1001
- "Infer (s/1K)": "Median seconds to predict per 1000 rows, across all datasets. Lower is better.",
 
 
 
 
 
 
 
1002
  "Class.": "Classification tasks only (binary + multiclass).",
1003
  "Regr.": "Regression tasks only.",
1004
  "Binary": "Binary classification tasks only.",
@@ -1046,26 +1053,30 @@ def _selected_overview_columns(tasks: str, datasets: str, care: str) -> list[str
1046
  return [c for c in wanted if c]
1047
 
1048
 
1049
- def _subset_best(df: pd.DataFrame, column: str, higher_is_better: bool) -> pd.DataFrame:
1050
- """Best variant per model in a subset for `column`.
 
 
 
1051
 
1052
  Systems stay in. Which entrants compete is decided by the pool the reader selected, and
1053
  the overview reports the numbers computed for that pool, so dropping a competitor here
1054
  would show a field the numbers were not computed against.
1055
  """
1056
- df = df.copy()
1057
- df = df.dropna(subset=[column])
1058
  parsed = df["Model"].map(parse_model)
1059
  df["base"] = [p[0] for p in parsed]
1060
  df["variant"] = [p[1] for p in parsed]
1061
  df["url"] = [p[2] for p in parsed]
1062
  df["imputed"] = df["Imputed"].astype(bool) if "Imputed" in df.columns else False
1063
  df["verified"] = df["Verified"] if "Verified" in df.columns else ""
1064
- grouped = df.groupby("base")[column]
1065
- best = df.loc[grouped.idxmax() if higher_is_better else grouped.idxmin()]
1066
- return best[
1067
- ["base", "TypeName", "Type", "variant", "url", column, "verified", "imputed"]
1068
- ].rename(columns={column: "val"})
 
 
1069
 
1070
 
1071
  def _overview_th(label: str, *, rowspan: int | None = None, selected: bool = False) -> str:
@@ -1227,8 +1238,14 @@ def make_cross_subset_overview(
1227
  tasks: str = "all",
1228
  datasets: str = "all",
1229
  care: str = "quality",
 
1230
  ) -> gr.HTML:
1231
- """Heatmap of the best `metric` per method (rows) and subset (columns), within one pool.
 
 
 
 
 
1232
 
1233
  `entrants` selects the pool. Every column is read from that pool's artifacts, so the whole
1234
  grid is one consistent field of competitors.
@@ -1243,29 +1260,50 @@ def make_cross_subset_overview(
1243
  metric = "Elo"
1244
  column, higher_is_better, fmt = _OVERVIEW_METRIC_SPECS[metric]
1245
 
1246
- val_by_col: dict[str, dict[str, float]] = {}
1247
- imp_by_col: dict[str, dict[str, bool]] = {}
1248
- meta: dict[str, dict] = {}
1249
  present: list[tuple[str, str]] = [] # (label, group)
1250
 
 
 
1251
  for label, group, subset, value_column in _OVERVIEW_COLUMNS:
1252
  subset = replace(subset, entrants=entrants)
1253
  path = Path(data_root) / subset.rel_path / "website_leaderboard.csv"
1254
  if not path.exists():
1255
  continue
1256
- # A cost column reports its own metric; a subset column reports the selected one.
1257
- col, col_higher_better = (column, higher_is_better)
1258
- if value_column is not None:
1259
- col, col_higher_better, _ = _FIXED_COLUMN_SPECS[label]
1260
- if col not in load_leaderboard_csv(str(path.resolve())).columns:
1261
- continue
1262
- best = _subset_best(load_leaderboard_csv(str(path.resolve())), col, col_higher_better)
1263
- val_by_col[label] = dict(zip(best["base"], best["val"]))
1264
- imp_by_col[label] = dict(zip(best["base"], best["imputed"]))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1265
  present.append((label, group))
1266
- for _, row in best.iterrows():
1267
  meta.setdefault(
1268
- row["base"],
1269
  {
1270
  "type_name": row["TypeName"],
1271
  "emoji": row["Type"],
@@ -1293,8 +1331,8 @@ def make_cross_subset_overview(
1293
 
1294
  sort_label = present[0][0]
1295
  worst_sort = float("-inf") if higher_is_better else float("inf")
1296
- bases = sorted(
1297
- meta, key=lambda b: val_by_col[sort_label].get(b, worst_sort), reverse=higher_is_better
1298
  )
1299
 
1300
  rank_by_col, bounds = {}, {}
@@ -1322,10 +1360,10 @@ def make_cross_subset_overview(
1322
 
1323
  # -- Body
1324
  body = []
1325
- for base in bases:
1326
- m = meta[base]
1327
  color = model_type_color.get(m["type_name"], "#9e9e9e")
1328
- name = html.escape(base)
1329
  if m["variant"]:
1330
  name += f' <span class="ta-variant">({html.escape(m["variant"])})</span>'
1331
  if m.get("verified") == "✔️":
@@ -1343,7 +1381,7 @@ def make_cross_subset_overview(
1343
  f'<td class="ta-model-cell">{name_html}</td>',
1344
  ]
1345
  for label, _ in present:
1346
- val = val_by_col[label].get(base)
1347
  if val is None:
1348
  cells.append('<td class="ta-na">–</td>')
1349
  continue
@@ -1357,10 +1395,10 @@ def make_cross_subset_overview(
1357
  else:
1358
  frac_best = (val - lo) / (hi - lo) if col_higher_better else (hi - val) / (hi - lo)
1359
  bg = _interp_color(1 - frac_best)
1360
- medal = _MEDALS.get(rank_by_col[label].get(base), "")
1361
  imp = (
1362
  '<sup class="ta-imp" title="Score is (partly) imputed">*</sup>'
1363
- if imp_by_col[label].get(base)
1364
  else ""
1365
  )
1366
  sel = " ta-col-sel" if label in highlighted else ""
@@ -1372,10 +1410,15 @@ def make_cross_subset_overview(
1372
  body.append(f"<tr>{''.join(cells)}</tr>")
1373
 
1374
  direction = "Higher is better" if higher_is_better else "Lower is better"
 
 
 
 
 
1375
  caption = (
1376
- f'<div class="ta-cap">Best <b>{html.escape(metric)}</b> per model across subsets '
1377
  f"(with imputation, all repeats). {direction}; 🥇🥈🥉 mark the top 3 in each column. "
1378
- "Each model shows its best-performing variant.</div>"
1379
  '<div class="ta-cap ta-cap-legend">✔️ = verified implementation &nbsp;·&nbsp; '
1380
  '<span class="ta-imp">*</span> = (partly) imputed score &nbsp;·&nbsp; '
1381
  "💡 Click any <u>underlined</u> model name (↗) to open its paper or code.</div>"
 
997
  # Size definitions are reused from DATASET_SIZE_NOTE so they can't drift from the subset blurbs.
998
  _COLUMN_TOOLTIPS: dict[str, str] = {
999
  "Overall": "All tasks across every dataset size. This is the headline ranking.",
1000
+ "Fit (s/1K)": (
1001
+ "Median seconds to train per 1000 rows, across all datasets, for the variant shown. "
1002
+ "Tuning fits 200 configurations, so a tuned variant costs far more than its default. "
1003
+ "Lower is better."
1004
+ ),
1005
+ "Infer (s/1K)": (
1006
+ "Median seconds to predict per 1000 rows, across all datasets, for the variant shown. "
1007
+ "Lower is better."
1008
+ ),
1009
  "Class.": "Classification tasks only (binary + multiclass).",
1010
  "Regr.": "Regression tasks only.",
1011
  "Binary": "Binary classification tasks only.",
 
1053
  return [c for c in wanted if c]
1054
 
1055
 
1056
+ _SUBSET_FIELDS = ["base", "TypeName", "Type", "variant", "url", "verified", "imputed"]
1057
+
1058
+
1059
+ def _subset_rows(df: pd.DataFrame, column: str) -> pd.DataFrame:
1060
+ """A subset's rows, `Model` split into base/variant/url and `column` renamed to `val`.
1061
 
1062
  Systems stay in. Which entrants compete is decided by the pool the reader selected, and
1063
  the overview reports the numbers computed for that pool, so dropping a competitor here
1064
  would show a field the numbers were not computed against.
1065
  """
1066
+ df = df.dropna(subset=[column]).copy()
 
1067
  parsed = df["Model"].map(parse_model)
1068
  df["base"] = [p[0] for p in parsed]
1069
  df["variant"] = [p[1] for p in parsed]
1070
  df["url"] = [p[2] for p in parsed]
1071
  df["imputed"] = df["Imputed"].astype(bool) if "Imputed" in df.columns else False
1072
  df["verified"] = df["Verified"] if "Verified" in df.columns else ""
1073
+ return df.rename(columns={column: "val"})[[*_SUBSET_FIELDS, "val"]]
1074
+
1075
+
1076
+ def _subset_best(rows: pd.DataFrame, higher_is_better: bool) -> pd.DataFrame:
1077
+ """Best-performing variant per model, one row each."""
1078
+ grouped = rows.groupby("base")["val"]
1079
+ return rows.loc[grouped.idxmax() if higher_is_better else grouped.idxmin()]
1080
 
1081
 
1082
  def _overview_th(label: str, *, rowspan: int | None = None, selected: bool = False) -> str:
 
1238
  tasks: str = "all",
1239
  datasets: str = "all",
1240
  care: str = "quality",
1241
+ one_per_model: bool = False,
1242
  ) -> gr.HTML:
1243
+ """Heatmap of `metric` per entrant (rows) and subset (columns), within one pool.
1244
+
1245
+ A row is one model *variant* — default, tuned, or tuned + ensembled — so its quality and its
1246
+ cost are always the same run's. With `one_per_model` only each model's best-performing
1247
+ variant is kept, decided by the leading column, as the win-rate matrix's button of the same
1248
+ name does.
1249
 
1250
  `entrants` selects the pool. Every column is read from that pool's artifacts, so the whole
1251
  grid is one consistent field of competitors.
 
1260
  metric = "Elo"
1261
  column, higher_is_better, fmt = _OVERVIEW_METRIC_SPECS[metric]
1262
 
1263
+ val_by_col: dict[str, dict[tuple[str, str], float]] = {}
1264
+ imp_by_col: dict[str, dict[tuple[str, str], bool]] = {}
1265
+ meta: dict[tuple[str, str], dict] = {}
1266
  present: list[tuple[str, str]] = [] # (label, group)
1267
 
1268
+ # Read every column first. A cost column reports its own metric, the rest the selected one.
1269
+ loaded: list[tuple[str, str, pd.DataFrame]] = []
1270
  for label, group, subset, value_column in _OVERVIEW_COLUMNS:
1271
  subset = replace(subset, entrants=entrants)
1272
  path = Path(data_root) / subset.rel_path / "website_leaderboard.csv"
1273
  if not path.exists():
1274
  continue
1275
+ df = load_leaderboard_csv(str(path.resolve()))
1276
+ col = _FIXED_COLUMN_SPECS[label][0] if value_column is not None else column
1277
+ if col not in df.columns:
1278
+ continue
1279
+ rows = _subset_rows(df, col)
1280
+ if not rows.empty:
1281
+ loaded.append((label, group, rows))
1282
+
1283
+ if not loaded:
1284
+ return gr.HTML("<p>No overview data available.</p>")
1285
+
1286
+ # The leading column decides which variant stands for each model, so the kept row is the one
1287
+ # the reader is ranking by.
1288
+ keep = None
1289
+ if one_per_model:
1290
+ lead = next((r for lbl, _, r in loaded if lbl not in _FIXED_COLUMN_SPECS), loaded[0][2])
1291
+ best = _subset_best(lead, higher_is_better)
1292
+ keep = set(zip(best["base"], best["variant"]))
1293
+
1294
+ for label, group, rows in loaded:
1295
+ keys = list(zip(rows["base"], rows["variant"]))
1296
+ if keep is not None:
1297
+ rows = rows[[k in keep for k in keys]]
1298
+ keys = [k for k in keys if k in keep]
1299
+ if rows.empty:
1300
+ continue
1301
+ val_by_col[label] = dict(zip(keys, rows["val"]))
1302
+ imp_by_col[label] = dict(zip(keys, rows["imputed"]))
1303
  present.append((label, group))
1304
+ for key, (_, row) in zip(keys, rows.iterrows()):
1305
  meta.setdefault(
1306
+ key,
1307
  {
1308
  "type_name": row["TypeName"],
1309
  "emoji": row["Type"],
 
1331
 
1332
  sort_label = present[0][0]
1333
  worst_sort = float("-inf") if higher_is_better else float("inf")
1334
+ entries = sorted(
1335
+ meta, key=lambda k: val_by_col[sort_label].get(k, worst_sort), reverse=higher_is_better
1336
  )
1337
 
1338
  rank_by_col, bounds = {}, {}
 
1360
 
1361
  # -- Body
1362
  body = []
1363
+ for key in entries:
1364
+ m = meta[key]
1365
  color = model_type_color.get(m["type_name"], "#9e9e9e")
1366
+ name = html.escape(key[0])
1367
  if m["variant"]:
1368
  name += f' <span class="ta-variant">({html.escape(m["variant"])})</span>'
1369
  if m.get("verified") == "✔️":
 
1381
  f'<td class="ta-model-cell">{name_html}</td>',
1382
  ]
1383
  for label, _ in present:
1384
+ val = val_by_col[label].get(key)
1385
  if val is None:
1386
  cells.append('<td class="ta-na">–</td>')
1387
  continue
 
1395
  else:
1396
  frac_best = (val - lo) / (hi - lo) if col_higher_better else (hi - val) / (hi - lo)
1397
  bg = _interp_color(1 - frac_best)
1398
+ medal = _MEDALS.get(rank_by_col[label].get(key), "")
1399
  imp = (
1400
  '<sup class="ta-imp" title="Score is (partly) imputed">*</sup>'
1401
+ if imp_by_col[label].get(key)
1402
  else ""
1403
  )
1404
  sel = " ta-col-sel" if label in highlighted else ""
 
1410
  body.append(f"<tr>{''.join(cells)}</tr>")
1411
 
1412
  direction = "Higher is better" if higher_is_better else "Lower is better"
1413
+ scope = (
1414
+ "Each model shows its best-performing variant."
1415
+ if one_per_model
1416
+ else "One row per model variant, so a row's cost is the cost of the run it scores."
1417
+ )
1418
  caption = (
1419
+ f'<div class="ta-cap"><b>{html.escape(metric)}</b> per entrant across subsets '
1420
  f"(with imputation, all repeats). {direction}; 🥇🥈🥉 mark the top 3 in each column. "
1421
+ f"{scope}</div>"
1422
  '<div class="ta-cap ta-cap-legend">✔️ = verified implementation &nbsp;·&nbsp; '
1423
  '<span class="ta-imp">*</span> = (partly) imputed score &nbsp;·&nbsp; '
1424
  "💡 Click any <u>underlined</u> model name (↗) to open its paper or code.</div>"
website_texts.py CHANGED
@@ -643,10 +643,19 @@ YOUR_BENCHMARK_LINKS = [
643
  ]
644
 
645
  VERSION_HISTORY_BUTTON_TEXT = """
646
- **Current Version: TabArena-v0.1.8.1**
647
 
648
  The following details updates to the leaderboard (date format is YYYY/MM/DD):
649
 
 
 
 
 
 
 
 
 
 
650
  * 2026/08/10-v0.1.8.1:
651
  * Updated verified model: ChimeraBoost, now at version 0.30.0.
652
  * 2026/08/06-v0.1.8:
 
643
  ]
644
 
645
  VERSION_HISTORY_BUTTON_TEXT = """
646
+ **Current Version: TabArena-v0.1.8.2**
647
 
648
  The following details updates to the leaderboard (date format is YYYY/MM/DD):
649
 
650
+ * 2026/08/17-v0.1.8.2:
651
+ * The *Performance across leaderboards* table now has a row per model variant, so default,
652
+ tuned and tuned + ensembled each get their own line and the cost of tuning is on the page.
653
+ Its new *One per model* toggle collapses each method to its best variant, as the win-rate
654
+ matrix's button of the same name does.
655
+ * Fixed the *Fit (s/1K)* and *Infer (s/1K)* columns of that table, which reported the cheapest
656
+ variant of each model rather than the variant on the row. A row labelled
657
+ *(tuned + ensembled)* showed its default's fit time, roughly 200x too low, because tuning
658
+ fits 200 configurations where the default fits one.
659
  * 2026/08/10-v0.1.8.1:
660
  * Updated verified model: ChimeraBoost, now at version 0.30.0.
661
  * 2026/08/06-v0.1.8: