SeaWolf-AI commited on
Commit
c689c36
·
verified ·
1 Parent(s): d4901b9

LEADBOARD 상금: 자격을 전 부문 제출로. 46부문 전체를 감당하는 예측기를 가린다

Browse files
Files changed (3) hide show
  1. app.py +26 -8
  2. i18n.js +8 -4
  3. index.html +3 -2
app.py CHANGED
@@ -50,8 +50,11 @@ PRIZE = {
50
  "amount_usd": 1000,
51
  "winners": 1,
52
  "closes": "2026-11-30",
53
- # 부문마다 지표가 달라 점수를 합산할 수 없다. 1위 부문 수를 센다.
54
- "rule": "most_first_places",
 
 
 
55
  }
56
 
57
 
@@ -312,9 +315,14 @@ def api_leaders():
312
  """
313
  def build():
314
  out = []
 
315
  for name, b in boards().items():
316
  rolled = ledger_read("leaderboard/%s.json" % name.lower(), {}) or {}
317
  ent = (rolled.get("entries") or [])
 
 
 
 
318
  top = ent[0] if ent else None
319
  nf = (b.get("noise_floor") or {}).get("sd_single")
320
  base = b.get("baselines") or {}
@@ -341,19 +349,29 @@ def api_leaders():
341
  "verified": bool(top.get("verified")), "leak": top.get("leak")}
342
  out.append(row)
343
  out.sort(key=lambda r: (r["leader"] is None, -(r["n_test"] or 0)))
344
- return out
345
- rows = cached("leaders", 60, build)
346
- # 수상 후보 집계. 주최측은 세지 않는다.
 
 
 
 
 
 
347
  tally = {}
348
  for r in rows:
349
  u = (r.get("leader") or {}).get("user")
350
  if u and not is_host(u):
351
  tally[u] = tally.get(u, 0) + 1
352
- standing = sorted(({"user": u, "firsts": n} for u, n in tally.items()),
353
- key=lambda x: -x["firsts"])
 
 
 
 
354
  return {"spec": SPEC, "n": len(rows), "rows": rows,
355
  "held": sum(1 for r in rows if r["leader"]),
356
- "prize": PRIZE, "standing": standing,
357
  "host_accounts": sorted(HOST_ACCOUNTS)}
358
 
359
 
 
50
  "amount_usd": 1000,
51
  "winners": 1,
52
  "closes": "2026-11-30",
53
+ # 🔴 자격은 **전 부문 제출**이다. 한 부문만 잘 맞히는 특화 모델이 아니라
54
+ # 46부문 전체를 감당하는 범용 예측기를 가리는 시험대이기 때문이다.
55
+ # 전 부문을 채운 사람들 중에서 1위 부문 수로 순위를 매긴다.
56
+ "rule": "all_boards_then_most_firsts",
57
+ "require_all_boards": True,
58
  }
59
 
60
 
 
315
  """
316
  def build():
317
  out = []
318
+ cover = {} # 누가 어느 부문에 제출했나. 자격 판정에 쓴다.
319
  for name, b in boards().items():
320
  rolled = ledger_read("leaderboard/%s.json" % name.lower(), {}) or {}
321
  ent = (rolled.get("entries") or [])
322
+ for e in ent:
323
+ u = e.get("user")
324
+ if u and not is_host(u):
325
+ cover.setdefault(u, set()).add(name)
326
  top = ent[0] if ent else None
327
  nf = (b.get("noise_floor") or {}).get("sd_single")
328
  base = b.get("baselines") or {}
 
349
  "verified": bool(top.get("verified")), "leak": top.get("leak")}
350
  out.append(row)
351
  out.sort(key=lambda r: (r["leader"] is None, -(r["n_test"] or 0)))
352
+ return {"rows": out, "cover": {u: sorted(s) for u, s in cover.items()}}
353
+
354
+ got = cached("leaders", 60, build)
355
+ rows, cover = got["rows"], got["cover"]
356
+ n_boards = len(rows)
357
+
358
+ # 수상 후보. 주최측은 세지 않는다.
359
+ # **자격 = 전 부문 제출.** 못 채운 사람도 표에는 올린다 - 몇 개 남았는지 보여야
360
+ # 채우러 온다. 감추면 왜 자기가 후보가 아닌지 알 수 없다.
361
  tally = {}
362
  for r in rows:
363
  u = (r.get("leader") or {}).get("user")
364
  if u and not is_host(u):
365
  tally[u] = tally.get(u, 0) + 1
366
+ standing = []
367
+ for u, bs in cover.items():
368
+ standing.append({"user": u, "firsts": tally.get(u, 0),
369
+ "submitted": len(bs), "missing": n_boards - len(bs),
370
+ "eligible": len(bs) >= n_boards})
371
+ standing.sort(key=lambda x: (not x["eligible"], -x["firsts"], -x["submitted"]))
372
  return {"spec": SPEC, "n": len(rows), "rows": rows,
373
  "held": sum(1 for r in rows if r["leader"]),
374
+ "prize": dict(PRIZE, n_boards=n_boards), "standing": standing,
375
  "host_accounts": sorted(HOST_ACCOUNTS)}
376
 
377
 
i18n.js CHANGED
@@ -29,8 +29,10 @@ ko: {
29
  leadersSome: (a, b) => `${b}개 부문 중 ${a}개에 선두가 있습니다.`,
30
  secBrowse: "분야", secBrowseLead: "분야를 선택하면 소속 부문의 순위표와 제출 창구로 이동합니다.",
31
  prizeH: "상금",
32
- prizeLead: (amt,close)=>`마감일에 <b>순위표 1위 부문을 가장 많이 보유한 한 분</b>에게 미화 ${amt}달러를 드립니다. 마감 ${close}.`,
33
- prizeRule: "부문마다 지표가 달라 점수를 합산할 수 없으므로, <b>1위 부문의 개수</b>로 셉니다. 동수이면 먼저 도달한 분이 우선합니다.",
 
 
34
  prizeHost: "주최측 계정(SeaWolf-AI 등)은 수상 대상이 아닙니다. 눈금 역할로 표에 남되 겨루지 않습니다.",
35
  prizeNone: "아직 수상 후보가 없습니다. 부문 하나에서 1위를 하면 이름이 여기 올라갑니다.",
36
  prizeStanding: "현재 후보",
@@ -233,8 +235,10 @@ en: {
233
  leadersSome: (a, b) => `${a} of ${b} boards have a leader.`,
234
  secBrowse: "Disciplines",
235
  prizeH: "Prize",
236
- prizeLead: (amt,close)=>`At the closing date, <b>the entrant holding the most first places</b> receives USD ${amt}. Closes ${close}.`,
237
- prizeRule: "Boards use different metrics, so scores cannot be summed. What counts is <b>the number of boards you lead</b>. Ties go to whoever got there first.",
 
 
238
  prizeHost: "Host accounts (SeaWolf-AI and others) are not eligible. They stay on the tables as a scale to read against, but they do not compete.",
239
  prizeNone: "No contenders yet. Take first place on any board and your name appears here.",
240
  prizeStanding: "Current contenders",
 
29
  leadersSome: (a, b) => `${b}개 부문 중 ${a}개에 선두가 있습니다.`,
30
  secBrowse: "분야", secBrowseLead: "분야를 선택하면 소속 부문의 순위표와 제출 창구로 이동합니다.",
31
  prizeH: "상금",
32
+ prizeLead: (amt,close)=>`마감일에 <b>한 분</b>에게 미화 ${amt}달러를 드립니다. 마감 ${close}.`,
33
+ prizeRule: (n)=>`<b>자격은 ${n}개 전 부문 제출입니다.</b> 한 부문만 잘 맞히는 모델이 아니라 전체를 감당하는 예측기를 가리는 자리이기 때문입니다. 전 부문을 채운 분들 중에서 <b>1위 부문의 개수</b>로 순위를 매기고, 동수이면 먼저 도달한 분이 우선합니다.`,
34
+ prizeElig: "자격 충족",
35
+ prizeMissing: (n)=>`${n}개 부문 남음`,
36
  prizeHost: "주최측 계정(SeaWolf-AI 등)은 수상 대상이 아닙니다. 눈금 역할로 표에 남되 겨루지 않습니다.",
37
  prizeNone: "아직 수상 후보가 없습니다. 부문 하나에서 1위를 하면 이름이 여기 올라갑니다.",
38
  prizeStanding: "현재 후보",
 
235
  leadersSome: (a, b) => `${a} of ${b} boards have a leader.`,
236
  secBrowse: "Disciplines",
237
  prizeH: "Prize",
238
+ prizeLead: (amt,close)=>`At the closing date <b>one entrant</b> receives USD ${amt}. Closes ${close}.`,
239
+ prizeRule: (n)=>`<b>To qualify you must submit to all ${n} boards.</b> This is a test bench for a predictor that handles the whole range, not one that wins a single board. Among those who cover every board, ranking is by <b>the number of boards you lead</b>, ties going to whoever got there first.`,
240
+ prizeElig: "qualified",
241
+ prizeMissing: (n)=>`${n} to go`,
242
  prizeHost: "Host accounts (SeaWolf-AI and others) are not eligible. They stay on the tables as a scale to read against, but they do not compete.",
243
  prizeNone: "No contenders yet. Take first place on any board and your name appears here.",
244
  prizeStanding: "Current contenders",
index.html CHANGED
@@ -434,9 +434,10 @@ function renderPrize(d){
434
  el.innerHTML=`<h2>${t.prizeH}</h2>
435
  <div class="amt">$${p.amount_usd.toLocaleString()} <small>USD</small></div>
436
  <p>${t.prizeLead(p.amount_usd.toLocaleString(), p.closes)}</p>
437
- <p>${t.prizeRule}</p>
438
  <div class="cand"><b>${t.prizeStanding}</b> — ${
439
- s.length? s.slice(0,5).map(x=>`${esc(x.user)} <span class="dim">(${t.prizeFirsts(x.firsts)})</span>`).join(" · ")
 
440
  : t.prizeNone}</div>
441
  <div class="fine">${t.prizeHost}</div>`;
442
  }
 
434
  el.innerHTML=`<h2>${t.prizeH}</h2>
435
  <div class="amt">$${p.amount_usd.toLocaleString()} <small>USD</small></div>
436
  <p>${t.prizeLead(p.amount_usd.toLocaleString(), p.closes)}</p>
437
+ <p>${t.prizeRule(p.n_boards)}</p>
438
  <div class="cand"><b>${t.prizeStanding}</b> — ${
439
+ s.length? s.slice(0,6).map(x=>`${esc(x.user)} <span class="dim">(${
440
+ x.eligible? t.prizeElig : t.prizeMissing(x.missing)} · ${t.prizeFirsts(x.firsts)})</span>`).join(" · ")
441
  : t.prizeNone}</div>
442
  <div class="fine">${t.prizeHost}</div>`;
443
  }