karlexmarin Claude Opus 4.7 (1M context) commited on
Commit
7c80934
·
1 Parent(s): 6378efa

v0.8.0 Benchmark Saturation Detector — anti-bullshit pack #6

Browse files

New 📈 Saturation mode: pick a benchmark, get top-3 frontier scores,
spread, mean, and a verdict (saturated / near-saturated / discriminative)
plus recommended replacements. Addresses the explicit "MMLU is saturated,
what now?" pain documented in arxiv 2508.15361 and 2026 leaderboards.

Data sources:
- Live: DemandSphere AI Frontier Model Tracker (CC BY-NC 4.0) — 66 models,
weekly updates, no auth, no rate limit
- Fallback: baked snapshot data/saturation_kb.json (15 benchmarks, 5 papers
cited, last fetch 2026-05-05)

Validation (research-physics, pre-registered 2026-05-07):
- 3 clean pass (MATH/HLE/SWE-bench)
- 3 borderline (GPQA/HumanEval rule sensitivity ±1pp)
- 1 falsified (AIME 2025 saturated faster than expected — itself a useful
tool output: tells users "AIME 2025 already at 96-100%, switch to HLE")
Shipped with explicit threshold-sensitivity disclaimer.

Coverage: MMLU/MMLU-Pro/GPQA-Diamond/SWE-bench-Verified/HumanEval/
LiveCodeBench-Pro/MATH/AIME-2025/HLE/ARC-AGI-2/HellaSwag/GSM8K +
multimodal: MMMU/MMMU-Pro/VisScience.

i18n × 4 langs (EN/ES/FR/ZH) — 36 keys per lang. Help modal section,
inventory card entry, and task-tile button under "Trust a benchmark score".

Files: data/saturation_kb.json + js/saturation_detector.js (new);
index.html + js/main.js + js/i18n.js (modified).

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

Files changed (5) hide show
  1. data/saturation_kb.json +285 -0
  2. index.html +29 -0
  3. js/i18n.js +144 -0
  4. js/main.js +175 -1
  5. js/saturation_detector.js +212 -0
data/saturation_kb.json ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "0.8.0",
3
+ "fetched_at": "2026-05-05",
4
+ "compiled_at": "2026-05-07",
5
+ "primary_source": {
6
+ "name": "DemandSphere AI Frontier Model Tracker",
7
+ "url": "https://www.demandsphere.com/research/demandsphere-radar/ai-frontier-model-tracker/",
8
+ "api": "https://www.demandsphere.com/research/demandsphere-radar/ai-frontier-model-tracker/api.json",
9
+ "license": "CC BY-NC 4.0",
10
+ "attribution_required": true,
11
+ "model_count": 66,
12
+ "last_updated": "2026-05-05"
13
+ },
14
+ "secondary_sources": [
15
+ {
16
+ "name": "HuggingFace Open LLM Leaderboard v3",
17
+ "url": "https://huggingface.co/spaces/open-llm-leaderboard/open_llm_leaderboard",
18
+ "use": "Open-weight historical baseline; dataset open-llm-leaderboard/contents (4580 models, 6 benchmarks)"
19
+ },
20
+ {
21
+ "name": "Public benchmark consensus (2026 community)",
22
+ "use": "MMLU/HellaSwag/GSM8K saturation status from survey arxiv 2508.15361 + multiple leaderboards"
23
+ }
24
+ ],
25
+ "classification_rule": {
26
+ "saturated": "top-3 spread ≤ 2pp AND mean(top-3) ≥ 90%",
27
+ "near_saturated": "top-3 spread ≤ 5pp AND mean(top-3) ≥ 80% (and not saturated)",
28
+ "discriminative": "top-3 spread > 5pp OR mean(top-3) < 80%",
29
+ "sparse_data": "fewer than 3 frontier models report this benchmark publicly"
30
+ },
31
+ "honest_disclaimer": "Threshold-sensitive: a benchmark with spread 5.0pp classifies as near_saturated; 5.1pp classifies as discriminative. Verdicts within ±1pp of cutoffs should be read as 'borderline'. Pre-registered validation 2026-05-07 against 7 benchmarks: 3 clean pass, 3 borderline, 1 falsified (AIME 2025 saturated faster than expected). Tool is descriptive of public scores at fetch date — not predictive of future. Always cross-check before strategic decisions.",
32
+ "benchmarks": {
33
+ "MMLU": {
34
+ "key": "mmlu",
35
+ "category": "general_knowledge",
36
+ "description": "Massive Multitask Language Understanding — 57 subjects, 4-way multiple choice.",
37
+ "year_introduced": 2020,
38
+ "top_3": [
39
+ {"model": "GPT-5.5", "score": 92.4},
40
+ {"model": "(other frontier models no longer report — DemandSphere lists N/A)", "score": null},
41
+ {"model": "(historically all 88-94% range)", "score": null}
42
+ ],
43
+ "spread_pp": null,
44
+ "mean_top3": null,
45
+ "classification": "saturated",
46
+ "classification_basis": "consensus + DemandSphere stopped tracking N/A for many frontier models, plus survey 2508.15361 confirms 88-94% top range cluster.",
47
+ "recommendations": ["MMLU-Pro", "GPQA Diamond", "HLE"],
48
+ "note": "MMLU was useful 2020-2023. By 2024 it stopped discriminating frontier models. Many leaderboards have dropped it. Use MMLU-Pro for general 7B-70B; GPQA/HLE for frontier."
49
+ },
50
+ "MMLU-Pro": {
51
+ "key": "mmlu_pro",
52
+ "category": "general_knowledge",
53
+ "description": "Harder, 10-way multiple choice version of MMLU. Reasoning-heavier.",
54
+ "year_introduced": 2024,
55
+ "top_3": [
56
+ {"model": "(top frontier 2026)", "score": 88.0, "approximate": true},
57
+ {"model": "(rank-2)", "score": 86.0, "approximate": true},
58
+ {"model": "(rank-3)", "score": 83.0, "approximate": true}
59
+ ],
60
+ "spread_pp": 5.0,
61
+ "mean_top3": 85.7,
62
+ "classification": "near_saturated",
63
+ "classification_basis": "Survey + leaderboard consensus 'near-saturated 83-90%' as of 2026.",
64
+ "recommendations": ["GPQA Diamond", "HLE", "ARC-AGI 2"],
65
+ "note": "Approximate top-3 — not in DemandSphere primary set. Confirm via HF Open LLM Leaderboard v3 for current numbers."
66
+ },
67
+ "GPQA-Diamond": {
68
+ "key": "gpqa",
69
+ "category": "scientific_reasoning",
70
+ "description": "Graduate-level Google-Proof Q&A — PhD-level science questions designed to be uncontaminable by web search.",
71
+ "year_introduced": 2023,
72
+ "top_3": [
73
+ {"model": "Claude Opus 4.7", "score": 94.2},
74
+ {"model": "DeepSeek V4 Pro", "score": 90.1},
75
+ {"model": "Qwen3.5", "score": 88.4}
76
+ ],
77
+ "spread_pp": 5.8,
78
+ "mean_top3": 90.9,
79
+ "classification": "discriminative",
80
+ "classification_basis": "spread 5.8pp > 5pp cutoff. Borderline near-saturated. Trend: tightening; will likely cross into near-saturated in 2026 H2.",
81
+ "recommendations": ["HLE", "ARC-AGI 2"],
82
+ "note": "Borderline. Still useful for 2026, but watch top-3 cluster — when spread drops below 3pp, switch up."
83
+ },
84
+ "SWE-bench-Verified": {
85
+ "key": "swe",
86
+ "category": "coding_agentic",
87
+ "description": "Real GitHub issues + tests. Agent must produce a patch that passes the project's tests.",
88
+ "year_introduced": 2024,
89
+ "top_3": [
90
+ {"model": "GPT-5.5", "score": 88.7},
91
+ {"model": "Claude Opus 4.7", "score": 87.6},
92
+ {"model": "Qwen3.6-Plus", "score": 78.8}
93
+ ],
94
+ "spread_pp": 9.9,
95
+ "mean_top3": 85.0,
96
+ "classification": "discriminative",
97
+ "classification_basis": "spread 9.9pp >> 5pp. Strong differentiation between top-2 and rank-3.",
98
+ "recommendations": ["SWE-bench-Verified (still useful)", "SWE-bench-Pro for harder split"],
99
+ "note": "Vendor self-report risk: many SWE-bench scores are vendor-published; cross-check with [SWE-bench Verified leaderboard](https://llm-stats.com/benchmarks/swe-bench-verified) which lists 89 self-reported vs 0 verified."
100
+ },
101
+ "HumanEval": {
102
+ "key": "he",
103
+ "category": "coding_basic",
104
+ "description": "164 Python programming problems with unit tests. Standard since 2021.",
105
+ "year_introduced": 2021,
106
+ "top_3": [
107
+ {"model": "xAI Grok 4.1", "score": 97.0},
108
+ {"model": "Claude Opus 4.6", "score": 96.0},
109
+ {"model": "Claude Opus 4.5", "score": 93.5}
110
+ ],
111
+ "spread_pp": 3.5,
112
+ "mean_top3": 95.5,
113
+ "classification": "near_saturated",
114
+ "classification_basis": "spread 3.5pp ≤ 5pp, mean ≥ 90%. Multiple frontier models 95%+.",
115
+ "recommendations": ["LiveCodeBench Pro", "SWE-bench Verified", "HumanEval+ (extended)"],
116
+ "note": "HumanEval has been considered effectively saturated since 2024. Heavy contamination risk: original problems are in many crawls."
117
+ },
118
+ "LiveCodeBench-Pro": {
119
+ "key": "lcb",
120
+ "category": "coding_contamination_resistant",
121
+ "description": "Continuously refreshed competitive programming problems — designed against contamination.",
122
+ "year_introduced": 2024,
123
+ "top_3": [
124
+ {"model": "DeepSeek V4 Pro", "score": 93.5},
125
+ {"model": "Claude Opus 4.6", "score": 76.0},
126
+ {"model": "(rank-3 sparse)", "score": null}
127
+ ],
128
+ "spread_pp": null,
129
+ "mean_top3": null,
130
+ "classification": "sparse_data",
131
+ "classification_basis": "Only 2 frontier models report in DemandSphere set. More data needed.",
132
+ "recommendations": ["Use this benchmark; few alternatives at this contamination resistance"],
133
+ "note": "Top-1 (DeepSeek V4 Pro 93.5) suspiciously high vs rank-2 (76.0) — possible chat-template or test-set version mismatch. Verify reproducibility before quoting."
134
+ },
135
+ "MATH": {
136
+ "key": "math",
137
+ "category": "math_reasoning",
138
+ "description": "Competition-style math problems (algebra, geometry, prealgebra, etc).",
139
+ "year_introduced": 2021,
140
+ "top_3": [
141
+ {"model": "o4-mini", "score": 97.4},
142
+ {"model": "o3", "score": 97.3},
143
+ {"model": "DeepSeek R1", "score": 97.3}
144
+ ],
145
+ "spread_pp": 0.1,
146
+ "mean_top3": 97.3,
147
+ "classification": "saturated",
148
+ "classification_basis": "spread 0.1pp ≤ 2pp, mean 97.3 ≥ 90%. Reasoning models cluster at top.",
149
+ "recommendations": ["AIME (was harder, now also saturating)", "PutnamBench", "FrontierMath", "Math Olympiad benchmarks"],
150
+ "note": "MATH was the harder math benchmark for years. Saturated by reasoning models in 2024-2025."
151
+ },
152
+ "AIME-2025": {
153
+ "key": "aime",
154
+ "category": "math_reasoning",
155
+ "description": "American Invitational Math Examination 2025 problems — 15 short-answer integer problems.",
156
+ "year_introduced": 2025,
157
+ "top_3": [
158
+ {"model": "GPT-5.4", "score": 100.0},
159
+ {"model": "Gemini 3.1 Flash Lite", "score": 99.7},
160
+ {"model": "Llama 4 Maverick", "score": 96.1}
161
+ ],
162
+ "spread_pp": 3.9,
163
+ "mean_top3": 98.6,
164
+ "classification": "near_saturated",
165
+ "classification_basis": "spread 3.9pp ≤ 5pp, mean 98.6 ≥ 90%. Frontier perfect or near-perfect.",
166
+ "recommendations": ["FrontierMath", "PutnamBench", "Math Olympiad 2026", "HLE"],
167
+ "note": "🚨 AIME 2025 saturated FASTER than expected (within ~6 months of release). This was the falsified pre-registered case in 2026-05-07 validation. Use as cautionary tale for any newly-released math bench."
168
+ },
169
+ "HLE": {
170
+ "key": "hle",
171
+ "category": "frontier_reasoning",
172
+ "description": "Humanity's Last Exam — designed by Center for AI Safety + Scale AI as the hardest standardized eval. Multidomain, expert-curated.",
173
+ "year_introduced": 2025,
174
+ "top_3": [
175
+ {"model": "Muse Spark", "score": 50.2},
176
+ {"model": "Gemini 3.1 Pro", "score": 41.0},
177
+ {"model": "DeepSeek V4 Pro", "score": 37.7}
178
+ ],
179
+ "spread_pp": 12.5,
180
+ "mean_top3": 43.0,
181
+ "classification": "discriminative",
182
+ "classification_basis": "spread 12.5pp >> 5pp, mean 43.0 << 80%. Top model only at 50% — large headroom.",
183
+ "recommendations": ["HLE is currently the strongest frontier discriminator. Use it."],
184
+ "note": "Released specifically to address saturation. As of 2026-05, no model has cracked 60%. Expected useful lifespan: 2-3 years."
185
+ },
186
+ "ARC-AGI-2": {
187
+ "key": "arc_agi_2",
188
+ "category": "abstract_reasoning",
189
+ "description": "Abstraction and Reasoning Corpus v2 — visual pattern puzzles designed against pretraining contamination.",
190
+ "year_introduced": 2024,
191
+ "top_3": [
192
+ {"model": "(top frontier 2026)", "score": 30.0, "approximate": true},
193
+ {"model": "(rank-2)", "score": 28.0, "approximate": true},
194
+ {"model": "(rank-3)", "score": 25.0, "approximate": true}
195
+ ],
196
+ "spread_pp": 5.0,
197
+ "mean_top3": 27.7,
198
+ "classification": "discriminative",
199
+ "classification_basis": "Mean << 80%. Massive headroom. (Approximate — not in DemandSphere primary set.)",
200
+ "recommendations": ["ARC-AGI 2 itself remains discriminative for years to come."],
201
+ "note": "Approximate scores — confirm via official ARC-AGI leaderboard. Tool should display 'approximate' badge."
202
+ },
203
+ "HellaSwag": {
204
+ "key": "hellaswag",
205
+ "category": "commonsense_reasoning",
206
+ "description": "Sentence-completion commonsense benchmark.",
207
+ "year_introduced": 2019,
208
+ "top_3": [
209
+ {"model": "(historically all 95%+)", "score": null}
210
+ ],
211
+ "spread_pp": null,
212
+ "mean_top3": null,
213
+ "classification": "saturated",
214
+ "classification_basis": "Saturated since 2023; most frontier leaderboards have dropped tracking it.",
215
+ "recommendations": ["WinoGrande-Hard", "BIG-Bench Hard (BBH)", "PIQA-extended"],
216
+ "note": "Useful only as a regression check on small models (<3B)."
217
+ },
218
+ "GSM8K": {
219
+ "key": "gsm8k",
220
+ "category": "math_grade_school",
221
+ "description": "Grade-school word problems requiring multi-step arithmetic.",
222
+ "year_introduced": 2021,
223
+ "top_3": [
224
+ {"model": "(historically all 95%+)", "score": null}
225
+ ],
226
+ "spread_pp": null,
227
+ "mean_top3": null,
228
+ "classification": "saturated",
229
+ "classification_basis": "Most frontier models 95%+ since 2024. Heavy contamination evidence.",
230
+ "recommendations": ["MATH (also saturating)", "AIME (now also saturated)", "FrontierMath"],
231
+ "note": "Contaminated. Top scores reflect memorization more than reasoning."
232
+ },
233
+ "MMMU": {
234
+ "key": "mmmu_vlm",
235
+ "category": "multimodal_reasoning",
236
+ "description": "Massive Multi-discipline Multimodal Understanding & Reasoning — expert-level cross-domain VLM benchmark.",
237
+ "year_introduced": 2023,
238
+ "top_3": [
239
+ {"model": "Qwen3.6 Plus", "score": 86.0},
240
+ {"model": "GPT-5.1", "score": 85.4},
241
+ {"model": "GPT-5.1 Instant", "score": 85.4}
242
+ ],
243
+ "spread_pp": 0.6,
244
+ "mean_top3": 85.6,
245
+ "classification": "near_saturated",
246
+ "classification_basis": "spread 0.6pp ≤ 2pp; mean 85.6% < 90% but ≥ 80% → near_saturated. Approaching human expert 88.6% (Apr 2026 data).",
247
+ "recommendations": ["MMMU-Pro", "VisScience", "ARC-AGI 2 (multimodal extension when available)"],
248
+ "note": "VLM-only. Source: llm-stats.com MMMU leaderboard 2026-04. Top models within 0.3pp of human expert performance — expect full saturation by 2026-Q4."
249
+ },
250
+ "MMMU-Pro": {
251
+ "key": "mmmu_pro",
252
+ "category": "multimodal_reasoning",
253
+ "description": "Harder MMMU variant with 10-way MC + augmented questions to resist contamination.",
254
+ "year_introduced": 2024,
255
+ "top_3": [
256
+ {"model": "GPT-5.4 Pro", "score": 94.0},
257
+ {"model": "Claude Mythos Preview", "score": 92.7},
258
+ {"model": "Gemini 3.1 Pro", "score": 83.9}
259
+ ],
260
+ "spread_pp": 10.1,
261
+ "mean_top3": 90.2,
262
+ "classification": "discriminative",
263
+ "classification_basis": "spread 10.1pp >> 5pp → discriminative. NOTE: alternate llm-stats reading (GPT-5.5 88.3 / Gemini 3.1 Pro 88.2 / Gemini 3 Flash 87.6) gives spread 0.7pp → near_saturated. Methodology variance is real.",
264
+ "recommendations": ["VisScience", "ARC-AGI 2", "(measure your own holdout)"],
265
+ "note": "Two public leaderboards disagree by ~6pp on top model — chat-template / sampling differences likely. Cross-check before quoting."
266
+ },
267
+ "VisScience": {
268
+ "key": "visscience",
269
+ "category": "multimodal_reasoning",
270
+ "description": "K-12 science multimodal benchmark — 3000 questions across math, physics, chemistry; 5 difficulty levels.",
271
+ "year_introduced": 2024,
272
+ "top_3": [
273
+ {"model": "Claude 3.5 Sonnet (math)", "score": 53.4},
274
+ {"model": "Gemini-1.5-Pro (chemistry)", "score": 47.0},
275
+ {"model": "GPT-4o (physics)", "score": 38.2}
276
+ ],
277
+ "spread_pp": 15.2,
278
+ "mean_top3": 46.2,
279
+ "classification": "discriminative",
280
+ "classification_basis": "spread 15.2pp >> 5pp; mean 46.2% << 80%. Massive headroom; subject-specific leaders differ. 25 MLLMs evaluated.",
281
+ "recommendations": ["VisScience itself remains discriminative for years."],
282
+ "note": "Top-3 here picks BEST model per subject (math/chem/physics). Composite leaderboard not published — subject splits more informative. Closed-source MLLMs generally outperform open-source."
283
+ }
284
+ }
285
+ }
index.html CHANGED
@@ -213,6 +213,9 @@
213
  <p><strong data-i18n="help.v07.niah.title">🔍 NIAH → Reasoning Gap</strong></p>
214
  <p data-i18n="help.v07.niah.body">RULER paper (NVIDIA 2024) shows that long-context models often pass NIAH (needle retrieval) but fail multi-hop reasoning at the same context. Tool predicts both pass rates from architecture (γ_Padé + d_horizon + arch pressure: small d_head, GQA, SWA), reports the gap, and finds your model's "safe reasoning context" where reasoning stays ≥65%. Sweep mode shows the curve across 1k/4k/16k/64k/T_train. <em>Use case</em>: before deploying at the claimed context, find out whether the model will actually reason there or just retrieve.</p>
215
 
 
 
 
216
  <h3 data-i18n="help.audit.title">The audit chain</h3>
217
  <p data-i18n="help.audit.body">Every result shows the full <strong>Computation Chain</strong> — each formula step with its inputs,
218
  output, and interpretation. Click any step to expand. Cite section numbers (§26.1, §19.1, etc.) refer
@@ -321,6 +324,7 @@
321
  <li data-i18n="inv.v07.quant"><strong>⚖️ Quant</strong> — predict γ shift + ΔPPL for any (model × quant scheme) combo</li>
322
  <li data-i18n="inv.v07.drift"><strong>🔀 Drift</strong> — bug or noise? Predict max admissible gap between two evals</li>
323
  <li data-i18n="inv.v07.niah"><strong>🔍 NIAH→Reason</strong> — does your "128k context" actually reason there, or just retrieve?</li>
 
324
  </ul>
325
  </details>
326
  </div>
@@ -378,6 +382,7 @@
378
  <button data-mode-link="contam" data-i18n="modes.contam">🧪 Contamination</button>
379
  <button data-mode-link="drift" data-i18n="modes.drift">🔀 Drift</button>
380
  <button data-mode-link="arena" data-i18n="modes.arena">🎯 Arena CI</button>
 
381
  </div>
382
  </div>
383
  <div class="task-tile">
@@ -444,6 +449,7 @@
444
  <button class="mode-btn" data-mode="quant" role="tab" aria-selected="false" data-i18n="modes.quant">⚖️ Quant</button>
445
  <button class="mode-btn" data-mode="drift" role="tab" aria-selected="false" data-i18n="modes.drift">🔀 Drift</button>
446
  <button class="mode-btn" data-mode="niah" role="tab" aria-selected="false" data-i18n="modes.niah">🔍 NIAH→Reason</button>
 
447
  </div>
448
  <p id="mode-desc" class="recipe-desc" data-i18n="modes.desc">
449
  <strong>Quickest start</strong>: paste any HuggingFace model id (e.g. <code>meta-llama/Meta-Llama-3-8B</code>),
@@ -968,6 +974,29 @@
968
  <div id="niah-output" style="margin-top: 1em;"></div>
969
  </section>
970
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
971
  <!-- Recipe selector (mode=recipe) -->
972
  <section id="recipe-section" style="display:none;">
973
  <h2 data-i18n="recipe.title">📋 Recipe</h2>
 
213
  <p><strong data-i18n="help.v07.niah.title">🔍 NIAH → Reasoning Gap</strong></p>
214
  <p data-i18n="help.v07.niah.body">RULER paper (NVIDIA 2024) shows that long-context models often pass NIAH (needle retrieval) but fail multi-hop reasoning at the same context. Tool predicts both pass rates from architecture (γ_Padé + d_horizon + arch pressure: small d_head, GQA, SWA), reports the gap, and finds your model's "safe reasoning context" where reasoning stays ≥65%. Sweep mode shows the curve across 1k/4k/16k/64k/T_train. <em>Use case</em>: before deploying at the claimed context, find out whether the model will actually reason there or just retrieve.</p>
215
 
216
+ <p><strong data-i18n="help.v08.saturation.title">📈 Benchmark Saturation Detector</strong></p>
217
+ <p data-i18n="help.v08.saturation.body">MMLU is saturated (top 88-94%), AIME 2025 saturated within months of release, HumanEval near-saturated. Pick any benchmark and the tool returns top-3 frontier scores, spread, mean, and a verdict — saturated / near-saturated / discriminative — plus a recommended replacement (e.g. MMLU → MMLU-Pro / GPQA / HLE). Live fetch from DemandSphere AI Frontier Tracker (CC BY-NC 4.0) when reachable; baked 2026-05-05 snapshot when not. <em>Use case</em>: before you cite '92% on MMLU' or design an eval, check whether the benchmark still discriminates anything.</p>
218
+
219
  <h3 data-i18n="help.audit.title">The audit chain</h3>
220
  <p data-i18n="help.audit.body">Every result shows the full <strong>Computation Chain</strong> — each formula step with its inputs,
221
  output, and interpretation. Click any step to expand. Cite section numbers (§26.1, §19.1, etc.) refer
 
324
  <li data-i18n="inv.v07.quant"><strong>⚖️ Quant</strong> — predict γ shift + ΔPPL for any (model × quant scheme) combo</li>
325
  <li data-i18n="inv.v07.drift"><strong>🔀 Drift</strong> — bug or noise? Predict max admissible gap between two evals</li>
326
  <li data-i18n="inv.v07.niah"><strong>🔍 NIAH→Reason</strong> — does your "128k context" actually reason there, or just retrieve?</li>
327
+ <li data-i18n="inv.v08.saturation"><strong>📈 Saturation</strong> — is your benchmark still useful, or are all frontier models tied at the top?</li>
328
  </ul>
329
  </details>
330
  </div>
 
382
  <button data-mode-link="contam" data-i18n="modes.contam">🧪 Contamination</button>
383
  <button data-mode-link="drift" data-i18n="modes.drift">🔀 Drift</button>
384
  <button data-mode-link="arena" data-i18n="modes.arena">🎯 Arena CI</button>
385
+ <button data-mode-link="saturation" data-i18n="modes.saturation">📈 Saturation</button>
386
  </div>
387
  </div>
388
  <div class="task-tile">
 
449
  <button class="mode-btn" data-mode="quant" role="tab" aria-selected="false" data-i18n="modes.quant">⚖️ Quant</button>
450
  <button class="mode-btn" data-mode="drift" role="tab" aria-selected="false" data-i18n="modes.drift">🔀 Drift</button>
451
  <button class="mode-btn" data-mode="niah" role="tab" aria-selected="false" data-i18n="modes.niah">🔍 NIAH→Reason</button>
452
+ <button class="mode-btn" data-mode="saturation" role="tab" aria-selected="false" data-i18n="modes.saturation">📈 Saturation</button>
453
  </div>
454
  <p id="mode-desc" class="recipe-desc" data-i18n="modes.desc">
455
  <strong>Quickest start</strong>: paste any HuggingFace model id (e.g. <code>meta-llama/Meta-Llama-3-8B</code>),
 
974
  <div id="niah-output" style="margin-top: 1em;"></div>
975
  </section>
976
 
977
+ <!-- Benchmark Saturation Detector (v0.8.0 anti-bullshit pack #6) -->
978
+ <section id="saturation-section" style="display:none;">
979
+ <h2><span data-i18n="saturation.title">📈 Benchmark Saturation Detector</span>
980
+ <span class="info"><span class="tooltip" data-i18n="saturation.tip">
981
+ MMLU is saturated (88-94% all frontier models). Reporting "92% on MMLU" is now meaningless. This tool tells you which benchmarks still discriminate frontier models, which are saturated, and what to use instead. Data: DemandSphere AI Frontier Tracker (CC BY-NC 4.0) refreshed 2026-05.
982
+ </span></span>
983
+ </h2>
984
+ <p class="recipe-desc" data-i18n="saturation.desc">
985
+ <strong>Is your benchmark still useful?</strong> Pick a benchmark to see top-3 frontier scores, spread, and a verdict (saturated / near-saturated / discriminative) plus recommended replacements.
986
+ </p>
987
+ <div class="form-row">
988
+ <label for="saturation-select" data-i18n="saturation.select_label">Benchmark:</label>
989
+ <select id="saturation-select"></select>
990
+ <button type="button" id="saturation-run-btn" data-i18n="saturation.run_btn">📈 Classify</button>
991
+ <button type="button" id="saturation-all-btn" class="secondary" data-i18n="saturation.all_btn">📊 Show all</button>
992
+ </div>
993
+ <p id="saturation-status" class="recipe-desc" style="font-size:0.92em;"></p>
994
+ <div id="saturation-output" style="margin-top: 1em;"></div>
995
+ <p class="subtle" style="font-size:0.82em; margin-top:1em;" data-i18n="saturation.attribution">
996
+ Data: DemandSphere AI Frontier Model Tracker (CC BY-NC 4.0) · HF Open LLM Leaderboard v3 (open-weight historical) · last fetch 2026-05-05.
997
+ </p>
998
+ </section>
999
+
1000
  <!-- Recipe selector (mode=recipe) -->
1001
  <section id="recipe-section" style="display:none;">
1002
  <h2 data-i18n="recipe.title">📋 Recipe</h2>
js/i18n.js CHANGED
@@ -421,6 +421,8 @@ export const TRANSLATIONS = {
421
  // v0.7.6 — anti-bullshit pack #7: NIAH → reasoning gap predictor
422
  "modes.niah": "🔍 NIAH→Reason",
423
  "mode_desc.niah": "Predicts NIAH (retrieval) and multi-hop reasoning pass rates at any context. Solves: long-context models often pass NIAH but fail reasoning at the same context (RULER paper).",
 
 
424
  "niah.title": "🔍 NIAH → Reasoning Gap",
425
  "niah.tip": "NIAH (Needle in a Haystack) tests retrieval: 'find this fact in long text'. Multi-hop reasoning tests inference: 'combine facts X+Y at the start with fact Z at the end'. RULER paper (NVIDIA 2024) shows long-context models often pass NIAH but fail reasoning at the same context. This tool predicts both pass rates from architecture alone.",
426
  "niah.desc": "<strong>Your model claims 128k context. Will it actually reason at 64k, or just retrieve?</strong> Paste an HF model id and a target eval context — tool predicts NIAH and multi-hop reasoning pass rates, the gap, and a 'safe context' where reasoning stays ≥65%.",
@@ -465,6 +467,40 @@ export const TRANSLATIONS = {
465
  "niah.status.fetched": "✅ Config fetched for {modelId}. Set T_eval and click Predict (or Sweep contexts).",
466
  "niah.status.done": "✅ {verdict} — NIAH {niah}% · reasoning {reasoning}%",
467
  "niah.status.sweep_done": "✅ Swept {n} context lengths.",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
 
469
  // v0.7.7 — Task tiles (UX restructure: 14 modes grouped by user intent)
470
  "tiles.title": "🎯 What do you want to do?",
@@ -1329,6 +1365,8 @@ export const TRANSLATIONS = {
1329
  // v0.7.6 — anti-bullshit pack #7: NIAH → predictor de gap de reasoning
1330
  "modes.niah": "🔍 NIAH→Reason",
1331
  "mode_desc.niah": "Predice tasas de pass de NIAH (retrieval) y reasoning multi-hop a cualquier contexto. Resuelve: modelos long-context pasan NIAH pero fallan reasoning al mismo contexto (paper RULER).",
 
 
1332
  "niah.title": "🔍 Gap NIAH → Reasoning",
1333
  "niah.tip": "NIAH (Needle in a Haystack) testea retrieval: 'encuentra este hecho en texto largo'. Reasoning multi-hop testea inferencia: 'combina hechos X+Y del principio con hecho Z del final'. El paper RULER (NVIDIA 2024) muestra que modelos long-context a menudo pasan NIAH pero fallan reasoning al mismo contexto. Esta herramienta predice ambas tasas desde la arquitectura sola.",
1334
  "niah.desc": "<strong>Tu modelo dice 128k de contexto. ¿Razonará realmente a 64k, o solo encontrará?</strong> Pega un model id HF y un contexto objetivo — la herramienta predice tasas de pass NIAH y reasoning multi-hop, el gap, y un 'contexto seguro' donde reasoning se mantiene ≥65%.",
@@ -1373,6 +1411,40 @@ export const TRANSLATIONS = {
1373
  "niah.status.fetched": "✅ Config obtenido para {modelId}. Pon T_eval y click Predecir (o Barrer contextos).",
1374
  "niah.status.done": "✅ {verdict} — NIAH {niah}% · reasoning {reasoning}%",
1375
  "niah.status.sweep_done": "✅ Barridos {n} largos de contexto.",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1376
 
1377
  // v0.7.7 — Tiles de tareas (UX restructure: 14 modos agrupados por intención)
1378
  "tiles.title": "🎯 ¿Qué quieres hacer?",
@@ -2101,6 +2173,8 @@ export const TRANSLATIONS = {
2101
  // v0.7.6 — anti-bullshit pack #7: prédicteur de gap NIAH → reasoning
2102
  "modes.niah": "🔍 NIAH→Reason",
2103
  "mode_desc.niah": "Prédit les taux de réussite NIAH (retrieval) et reasoning multi-hop à n'importe quel contexte. Résout : les modèles long-context passent souvent NIAH mais échouent au reasoning au même contexte (paper RULER).",
 
 
2104
  "niah.title": "🔍 Gap NIAH → Reasoning",
2105
  "niah.tip": "NIAH (Needle in a Haystack) teste le retrieval : 'trouve ce fait dans un long texte'. Le reasoning multi-hop teste l'inférence : 'combine les faits X+Y au début avec le fait Z à la fin'. Le paper RULER (NVIDIA 2024) montre que les modèles long-context passent souvent NIAH mais échouent au reasoning au même contexte. Cet outil prédit les deux taux à partir de la seule architecture.",
2106
  "niah.desc": "<strong>Votre modèle revendique 128k de contexte. Va-t-il vraiment raisonner à 64k, ou seulement retrouver ?</strong> Collez un model id HF et un contexte cible — l'outil prédit les taux de réussite NIAH et reasoning multi-hop, le gap, et un 'contexte sûr' où le reasoning reste ≥65%.",
@@ -2145,6 +2219,40 @@ export const TRANSLATIONS = {
2145
  "niah.status.fetched": "✅ Config récupéré pour {modelId}. Réglez T_eval et cliquez Prédire (ou Balayer les contextes).",
2146
  "niah.status.done": "✅ {verdict} — NIAH {niah}% · reasoning {reasoning}%",
2147
  "niah.status.sweep_done": "✅ Balayé {n} longueurs de contexte.",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2148
 
2149
  // v0.7.7 — Tuiles de tâches (refonte UX : 14 modes regroupés par intention)
2150
  "tiles.title": "🎯 Que voulez-vous faire ?",
@@ -2873,6 +2981,8 @@ export const TRANSLATIONS = {
2873
  // v0.7.6 — anti-bullshit pack #7: NIAH → reasoning gap 预测器
2874
  "modes.niah": "🔍 NIAH→Reason",
2875
  "mode_desc.niah": "在任意上下文下预测 NIAH(检索)与多跳 reasoning 通过率。解决:长上下文模型常常通过 NIAH 但在同一上下文上 reasoning 失败(RULER 论文)。",
 
 
2876
  "niah.title": "🔍 NIAH → Reasoning Gap",
2877
  "niah.tip": "NIAH(Needle in a Haystack)测试检索:\"在长文本中找到这个事实\"。多跳 reasoning 测试推理:\"把开头的事实 X+Y 与结尾的事实 Z 结合\"。RULER 论文(NVIDIA 2024)显示长上下文模型经常通过 NIAH 但在相同上下文上 reasoning 失败。本工具仅根据架构预测两种通过率。",
2878
  "niah.desc": "<strong>你的模型声称 128k 上下文。它在 64k 是真的能 reasoning,还是只能检索?</strong>粘贴 HF 模型 id 和目标 eval 上下文 — 工具预测 NIAH 与多跳 reasoning 通过率、gap,以及 reasoning 保持 ≥65% 的 \"安全上下文\"。",
@@ -2917,6 +3027,40 @@ export const TRANSLATIONS = {
2917
  "niah.status.fetched": "✅ 已获取 {modelId} 的 config。设置 T_eval 并点击预测(或扫描上下文)。",
2918
  "niah.status.done": "✅ {verdict} — NIAH {niah}% · reasoning {reasoning}%",
2919
  "niah.status.sweep_done": "✅ 已扫描 {n} 个上下文长度。",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2920
 
2921
  // v0.7.7 — 任务卡片(UX 重构:按用户意图分组的 14 个模式)
2922
  "tiles.title": "🎯 你想做什么?",
 
421
  // v0.7.6 — anti-bullshit pack #7: NIAH → reasoning gap predictor
422
  "modes.niah": "🔍 NIAH→Reason",
423
  "mode_desc.niah": "Predicts NIAH (retrieval) and multi-hop reasoning pass rates at any context. Solves: long-context models often pass NIAH but fail reasoning at the same context (RULER paper).",
424
+ "modes.saturation": "📈 Saturation",
425
+ "mode_desc.saturation": "Tells you whether a benchmark still discriminates frontier models or has saturated (e.g. MMLU 88-94% top, AIME 2025 already 96-100%). Returns top-3 + verdict + recommended replacements.",
426
  "niah.title": "🔍 NIAH → Reasoning Gap",
427
  "niah.tip": "NIAH (Needle in a Haystack) tests retrieval: 'find this fact in long text'. Multi-hop reasoning tests inference: 'combine facts X+Y at the start with fact Z at the end'. RULER paper (NVIDIA 2024) shows long-context models often pass NIAH but fail reasoning at the same context. This tool predicts both pass rates from architecture alone.",
428
  "niah.desc": "<strong>Your model claims 128k context. Will it actually reason at 64k, or just retrieve?</strong> Paste an HF model id and a target eval context — tool predicts NIAH and multi-hop reasoning pass rates, the gap, and a 'safe context' where reasoning stays ≥65%.",
 
467
  "niah.status.fetched": "✅ Config fetched for {modelId}. Set T_eval and click Predict (or Sweep contexts).",
468
  "niah.status.done": "✅ {verdict} — NIAH {niah}% · reasoning {reasoning}%",
469
  "niah.status.sweep_done": "✅ Swept {n} context lengths.",
470
+ "saturation.title": "📈 Benchmark Saturation Detector",
471
+ "saturation.tip": "MMLU is saturated (88-94% all frontier models). Reporting '92% on MMLU' is now meaningless. This tool tells you which benchmarks still discriminate frontier models, which are saturated, and what to use instead. Data: DemandSphere AI Frontier Tracker (CC BY-NC 4.0) refreshed 2026-05.",
472
+ "saturation.desc": "<strong>Is your benchmark still useful?</strong> Pick a benchmark to see top-3 frontier scores, spread, and a verdict (saturated / near-saturated / discriminative) plus recommended replacements.",
473
+ "saturation.select_label": "Benchmark:",
474
+ "saturation.select.all": "— show all benchmarks —",
475
+ "saturation.run_btn": "📈 Classify",
476
+ "saturation.all_btn": "📊 Show all",
477
+ "saturation.col.spread": "Top-3 spread",
478
+ "saturation.col.mean": "Top-3 mean",
479
+ "saturation.col.n": "Models",
480
+ "saturation.col.bench": "Benchmark",
481
+ "saturation.col.verdict": "Verdict",
482
+ "saturation.col.reco": "Top reco",
483
+ "saturation.col.model": "Model",
484
+ "saturation.col.score": "Score",
485
+ "saturation.section.top3": "Top-3 frontier scores",
486
+ "saturation.section.recommendations": "Recommended alternatives",
487
+ "saturation.section.note": "Notes",
488
+ "saturation.section.all": "All tracked benchmarks",
489
+ "saturation.verdict.saturated": "🚨 SATURATED",
490
+ "saturation.verdict.near_saturated": "⚠ NEAR SATURATED",
491
+ "saturation.verdict.discriminative": "✅ DISCRIMINATIVE",
492
+ "saturation.verdict.sparse_data": "ℹ SPARSE DATA",
493
+ "saturation.borderline": "Borderline — within ±1pp of a threshold cutoff. Treat verdict as 'check carefully'.",
494
+ "saturation.unknown": "Unknown benchmark.",
495
+ "saturation.attribution": "Data: DemandSphere AI Frontier Model Tracker (CC BY-NC 4.0) · HF Open LLM Leaderboard v3 (open-weight historical) · last fetch 2026-05-05.",
496
+ "saturation.status.live": "✅ Live data loaded — {count} models.",
497
+ "saturation.status.baked": "ℹ Using baked snapshot (live fetch unavailable).",
498
+ "saturation.status.kb_fail": "⚠ Could not load saturation KB.",
499
+ "saturation.status.done": "✅ {name} — {verdict}",
500
+ "saturation.status.all_done": "✅ Classified {n} benchmarks.",
501
+ "help.v08.saturation.title": "📈 Benchmark Saturation Detector",
502
+ "help.v08.saturation.body": "MMLU is saturated (88-94% top), AIME 2025 saturated within months of release, HumanEval near-saturated. Pick any benchmark and the tool returns top-3 frontier scores, spread, mean, and a verdict — saturated / near-saturated / discriminative — plus a recommended replacement (e.g. MMLU → MMLU-Pro / GPQA / HLE). Live fetch from DemandSphere AI Frontier Tracker (CC BY-NC 4.0) when reachable; baked 2026-05-05 snapshot when not. <em>Use case</em>: before you cite '92% on MMLU' or design an eval, check whether the benchmark still discriminates anything.",
503
+ "inv.v08.saturation": "<strong>📈 Saturation</strong> — is your benchmark still useful, or are all frontier models tied at the top?",
504
 
505
  // v0.7.7 — Task tiles (UX restructure: 14 modes grouped by user intent)
506
  "tiles.title": "🎯 What do you want to do?",
 
1365
  // v0.7.6 — anti-bullshit pack #7: NIAH → predictor de gap de reasoning
1366
  "modes.niah": "🔍 NIAH→Reason",
1367
  "mode_desc.niah": "Predice tasas de pass de NIAH (retrieval) y reasoning multi-hop a cualquier contexto. Resuelve: modelos long-context pasan NIAH pero fallan reasoning al mismo contexto (paper RULER).",
1368
+ "modes.saturation": "📈 Saturación",
1369
+ "mode_desc.saturation": "Te dice si un benchmark sigue discriminando frontier models o ya está saturado (ej. MMLU 88-94% top, AIME 2025 ya 96-100%). Devuelve top-3 + veredicto + reemplazos recomendados.",
1370
  "niah.title": "🔍 Gap NIAH → Reasoning",
1371
  "niah.tip": "NIAH (Needle in a Haystack) testea retrieval: 'encuentra este hecho en texto largo'. Reasoning multi-hop testea inferencia: 'combina hechos X+Y del principio con hecho Z del final'. El paper RULER (NVIDIA 2024) muestra que modelos long-context a menudo pasan NIAH pero fallan reasoning al mismo contexto. Esta herramienta predice ambas tasas desde la arquitectura sola.",
1372
  "niah.desc": "<strong>Tu modelo dice 128k de contexto. ¿Razonará realmente a 64k, o solo encontrará?</strong> Pega un model id HF y un contexto objetivo — la herramienta predice tasas de pass NIAH y reasoning multi-hop, el gap, y un 'contexto seguro' donde reasoning se mantiene ≥65%.",
 
1411
  "niah.status.fetched": "✅ Config obtenido para {modelId}. Pon T_eval y click Predecir (o Barrer contextos).",
1412
  "niah.status.done": "✅ {verdict} — NIAH {niah}% · reasoning {reasoning}%",
1413
  "niah.status.sweep_done": "✅ Barridos {n} largos de contexto.",
1414
+ "saturation.title": "📈 Detector de saturación de benchmarks",
1415
+ "saturation.tip": "MMLU está saturado (88-94% en todos los frontier). Reportar '92% en MMLU' ya no significa nada. Esta herramienta te dice qué benchmarks aún discriminan frontier models, cuáles están saturados, y qué usar en su lugar. Datos: DemandSphere AI Frontier Tracker (CC BY-NC 4.0) refrescado 2026-05.",
1416
+ "saturation.desc": "<strong>¿Sigue siendo útil tu benchmark?</strong> Elige un benchmark para ver top-3 frontier scores, spread, y un veredicto (saturated / near-saturated / discriminative) + reemplazos recomendados.",
1417
+ "saturation.select_label": "Benchmark:",
1418
+ "saturation.select.all": "— mostrar todos los benchmarks —",
1419
+ "saturation.run_btn": "📈 Clasificar",
1420
+ "saturation.all_btn": "📊 Mostrar todos",
1421
+ "saturation.col.spread": "Spread top-3",
1422
+ "saturation.col.mean": "Media top-3",
1423
+ "saturation.col.n": "Modelos",
1424
+ "saturation.col.bench": "Benchmark",
1425
+ "saturation.col.verdict": "Veredicto",
1426
+ "saturation.col.reco": "Mejor reco",
1427
+ "saturation.col.model": "Modelo",
1428
+ "saturation.col.score": "Score",
1429
+ "saturation.section.top3": "Top-3 frontier scores",
1430
+ "saturation.section.recommendations": "Alternativas recomendadas",
1431
+ "saturation.section.note": "Notas",
1432
+ "saturation.section.all": "Todos los benchmarks rastreados",
1433
+ "saturation.verdict.saturated": "🚨 SATURADO",
1434
+ "saturation.verdict.near_saturated": "⚠ CASI SATURADO",
1435
+ "saturation.verdict.discriminative": "✅ DISCRIMINATIVO",
1436
+ "saturation.verdict.sparse_data": "ℹ DATOS ESCASOS",
1437
+ "saturation.borderline": "Borderline — dentro de ±1pp de un umbral. Trata el veredicto como 'verifica con cuidado'.",
1438
+ "saturation.unknown": "Benchmark desconocido.",
1439
+ "saturation.attribution": "Datos: DemandSphere AI Frontier Model Tracker (CC BY-NC 4.0) · HF Open LLM Leaderboard v3 (histórico open-weight) · último fetch 2026-05-05.",
1440
+ "saturation.status.live": "✅ Datos en vivo cargados — {count} modelos.",
1441
+ "saturation.status.baked": "ℹ Usando snapshot baked (fetch en vivo no disponible).",
1442
+ "saturation.status.kb_fail": "⚠ No se pudo cargar el KB de saturación.",
1443
+ "saturation.status.done": "✅ {name} — {verdict}",
1444
+ "saturation.status.all_done": "✅ Clasificados {n} benchmarks.",
1445
+ "help.v08.saturation.title": "📈 Detector de saturación de benchmarks",
1446
+ "help.v08.saturation.body": "MMLU está saturado (top 88-94%), AIME 2025 saturó a los pocos meses de salir, HumanEval near-saturated. Elige cualquier benchmark y la herramienta retorna top-3 frontier scores, spread, media, y un veredicto — saturated / near-saturated / discriminative — más un reemplazo recomendado (ej. MMLU → MMLU-Pro / GPQA / HLE). Fetch en vivo desde DemandSphere AI Frontier Tracker (CC BY-NC 4.0) cuando llega; snapshot baked 2026-05-05 cuando no. <em>Caso de uso</em>: antes de citar '92% en MMLU' o diseñar una eval, verifica si el benchmark aún discrimina algo.",
1447
+ "inv.v08.saturation": "<strong>📈 Saturation</strong> — ¿sigue siendo útil tu benchmark, o están todos los frontiers empatados arriba?",
1448
 
1449
  // v0.7.7 — Tiles de tareas (UX restructure: 14 modos agrupados por intención)
1450
  "tiles.title": "🎯 ¿Qué quieres hacer?",
 
2173
  // v0.7.6 — anti-bullshit pack #7: prédicteur de gap NIAH → reasoning
2174
  "modes.niah": "🔍 NIAH→Reason",
2175
  "mode_desc.niah": "Prédit les taux de réussite NIAH (retrieval) et reasoning multi-hop à n'importe quel contexte. Résout : les modèles long-context passent souvent NIAH mais échouent au reasoning au même contexte (paper RULER).",
2176
+ "modes.saturation": "📈 Saturation",
2177
+ "mode_desc.saturation": "Indique si un benchmark discrimine encore les frontier models ou s'il est saturé (ex. MMLU 88-94% top, AIME 2025 déjà 96-100%). Retourne top-3 + verdict + remplacements recommandés.",
2178
  "niah.title": "🔍 Gap NIAH → Reasoning",
2179
  "niah.tip": "NIAH (Needle in a Haystack) teste le retrieval : 'trouve ce fait dans un long texte'. Le reasoning multi-hop teste l'inférence : 'combine les faits X+Y au début avec le fait Z à la fin'. Le paper RULER (NVIDIA 2024) montre que les modèles long-context passent souvent NIAH mais échouent au reasoning au même contexte. Cet outil prédit les deux taux à partir de la seule architecture.",
2180
  "niah.desc": "<strong>Votre modèle revendique 128k de contexte. Va-t-il vraiment raisonner à 64k, ou seulement retrouver ?</strong> Collez un model id HF et un contexte cible — l'outil prédit les taux de réussite NIAH et reasoning multi-hop, le gap, et un 'contexte sûr' où le reasoning reste ≥65%.",
 
2219
  "niah.status.fetched": "✅ Config récupéré pour {modelId}. Réglez T_eval et cliquez Prédire (ou Balayer les contextes).",
2220
  "niah.status.done": "✅ {verdict} — NIAH {niah}% · reasoning {reasoning}%",
2221
  "niah.status.sweep_done": "✅ Balayé {n} longueurs de contexte.",
2222
+ "saturation.title": "📈 Détecteur de saturation des benchmarks",
2223
+ "saturation.tip": "MMLU est saturé (88-94% sur tous les frontier models). Annoncer '92% sur MMLU' n'a plus de sens. Cet outil vous dit quels benchmarks discriminent encore les frontier models, lesquels sont saturés, et quoi utiliser à la place. Données : DemandSphere AI Frontier Tracker (CC BY-NC 4.0) rafraîchi 2026-05.",
2224
+ "saturation.desc": "<strong>Votre benchmark est-il encore utile ?</strong> Choisissez un benchmark pour voir top-3 frontier scores, spread, et un verdict (saturated / near-saturated / discriminative) + remplacements recommandés.",
2225
+ "saturation.select_label": "Benchmark :",
2226
+ "saturation.select.all": "— afficher tous les benchmarks —",
2227
+ "saturation.run_btn": "📈 Classer",
2228
+ "saturation.all_btn": "📊 Afficher tout",
2229
+ "saturation.col.spread": "Écart top-3",
2230
+ "saturation.col.mean": "Moyenne top-3",
2231
+ "saturation.col.n": "Modèles",
2232
+ "saturation.col.bench": "Benchmark",
2233
+ "saturation.col.verdict": "Verdict",
2234
+ "saturation.col.reco": "Reco principale",
2235
+ "saturation.col.model": "Modèle",
2236
+ "saturation.col.score": "Score",
2237
+ "saturation.section.top3": "Top-3 frontier scores",
2238
+ "saturation.section.recommendations": "Alternatives recommandées",
2239
+ "saturation.section.note": "Notes",
2240
+ "saturation.section.all": "Tous les benchmarks suivis",
2241
+ "saturation.verdict.saturated": "🚨 SATURÉ",
2242
+ "saturation.verdict.near_saturated": "⚠ PRESQUE SATURÉ",
2243
+ "saturation.verdict.discriminative": "✅ DISCRIMINATIF",
2244
+ "saturation.verdict.sparse_data": "ℹ DONNÉES RARES",
2245
+ "saturation.borderline": "Borderline — à ±1pp d'un seuil de coupure. Traitez le verdict comme 'à vérifier soigneusement'.",
2246
+ "saturation.unknown": "Benchmark inconnu.",
2247
+ "saturation.attribution": "Données : DemandSphere AI Frontier Model Tracker (CC BY-NC 4.0) · HF Open LLM Leaderboard v3 (historique open-weight) · dernier fetch 2026-05-05.",
2248
+ "saturation.status.live": "✅ Données en direct chargées — {count} modèles.",
2249
+ "saturation.status.baked": "ℹ Utilisation du snapshot baked (fetch en direct indisponible).",
2250
+ "saturation.status.kb_fail": "⚠ Impossible de charger le KB de saturation.",
2251
+ "saturation.status.done": "✅ {name} — {verdict}",
2252
+ "saturation.status.all_done": "✅ {n} benchmarks classés.",
2253
+ "help.v08.saturation.title": "📈 Détecteur de saturation des benchmarks",
2254
+ "help.v08.saturation.body": "MMLU est saturé (top 88-94%), AIME 2025 saturé en quelques mois après sa sortie, HumanEval presque saturé. Choisissez un benchmark et l'outil retourne top-3 frontier scores, spread, moyenne, et un verdict — saturated / near-saturated / discriminative — plus un remplacement recommandé (ex. MMLU → MMLU-Pro / GPQA / HLE). Fetch en direct depuis DemandSphere AI Frontier Tracker (CC BY-NC 4.0) si accessible ; snapshot baked 2026-05-05 sinon. <em>Cas d'usage</em> : avant de citer '92% sur MMLU' ou de concevoir une eval, vérifiez si le benchmark discrimine encore quelque chose.",
2255
+ "inv.v08.saturation": "<strong>📈 Saturation</strong> — votre benchmark est-il encore utile, ou tous les frontiers sont-ils à égalité au sommet ?",
2256
 
2257
  // v0.7.7 — Tuiles de tâches (refonte UX : 14 modes regroupés par intention)
2258
  "tiles.title": "🎯 Que voulez-vous faire ?",
 
2981
  // v0.7.6 — anti-bullshit pack #7: NIAH → reasoning gap 预测器
2982
  "modes.niah": "🔍 NIAH→Reason",
2983
  "mode_desc.niah": "在任意上下文下预测 NIAH(检索)与多跳 reasoning 通过率。解决:长上下文模型常常通过 NIAH 但在同一上下文上 reasoning 失败(RULER 论文)。",
2984
+ "modes.saturation": "📈 饱和度",
2985
+ "mode_desc.saturation": "告诉你某个 benchmark 是否仍能区分 frontier 模型,或者已经饱和(例如 MMLU 88-94% 顶部,AIME 2025 已经 96-100%)。返回 top-3 + 判定 + 推荐替代品。",
2986
  "niah.title": "🔍 NIAH → Reasoning Gap",
2987
  "niah.tip": "NIAH(Needle in a Haystack)测试检索:\"在长文本中找到这个事实\"。多跳 reasoning 测试推理:\"把开头的事实 X+Y 与结尾的事实 Z 结合\"。RULER 论文(NVIDIA 2024)显示长上下文模型经常通过 NIAH 但在相同上下文上 reasoning 失败。本工具仅根据架构预测两种通过率。",
2988
  "niah.desc": "<strong>你的模型声称 128k 上下文。它在 64k 是真的能 reasoning,还是只能检索?</strong>粘贴 HF 模型 id 和目标 eval 上下文 — 工具预测 NIAH 与多跳 reasoning 通过率、gap,以及 reasoning 保持 ≥65% 的 \"安全上下文\"。",
 
3027
  "niah.status.fetched": "✅ 已获取 {modelId} 的 config。设置 T_eval 并点击预测(或扫描上下文)。",
3028
  "niah.status.done": "✅ {verdict} — NIAH {niah}% · reasoning {reasoning}%",
3029
  "niah.status.sweep_done": "✅ 已扫描 {n} 个上下文长度。",
3030
+ "saturation.title": "📈 Benchmark 饱和度检测器",
3031
+ "saturation.tip": "MMLU 已饱和(所有 frontier 模型 88-94%)。报告\"92% on MMLU\"现在毫无意义。本工具告诉你哪些 benchmark 仍能区分 frontier 模型,哪些已饱和,以及替代方案。数据:DemandSphere AI Frontier Tracker(CC BY-NC 4.0),2026-05 刷新。",
3032
+ "saturation.desc": "<strong>你的 benchmark 还有用吗?</strong>选一个 benchmark 查看 top-3 frontier 分数、spread 与判定(saturated / near-saturated / discriminative),并给出推荐替代品。",
3033
+ "saturation.select_label": "Benchmark:",
3034
+ "saturation.select.all": "— 显示所有 benchmark —",
3035
+ "saturation.run_btn": "📈 分类",
3036
+ "saturation.all_btn": "📊 显示全部",
3037
+ "saturation.col.spread": "Top-3 spread",
3038
+ "saturation.col.mean": "Top-3 平均",
3039
+ "saturation.col.n": "模型数",
3040
+ "saturation.col.bench": "Benchmark",
3041
+ "saturation.col.verdict": "判定",
3042
+ "saturation.col.reco": "首选替代",
3043
+ "saturation.col.model": "模型",
3044
+ "saturation.col.score": "分数",
3045
+ "saturation.section.top3": "Top-3 frontier 分数",
3046
+ "saturation.section.recommendations": "推荐替代品",
3047
+ "saturation.section.note": "备注",
3048
+ "saturation.section.all": "所有跟踪的 benchmark",
3049
+ "saturation.verdict.saturated": "🚨 已饱和",
3050
+ "saturation.verdict.near_saturated": "⚠ 接近饱和",
3051
+ "saturation.verdict.discriminative": "✅ 仍可区分",
3052
+ "saturation.verdict.sparse_data": "ℹ 数据稀疏",
3053
+ "saturation.borderline": "边缘 — 在阈值切点的 ±1pp 内。判定视为\"需仔细核对\"。",
3054
+ "saturation.unknown": "未知 benchmark。",
3055
+ "saturation.attribution": "数据:DemandSphere AI Frontier Model Tracker(CC BY-NC 4.0)· HF Open LLM Leaderboard v3(开源权重历史)· 最近一次 fetch 2026-05-05。",
3056
+ "saturation.status.live": "✅ 实时数据已加载 — {count} 个模型。",
3057
+ "saturation.status.baked": "ℹ 使用 baked 快照(实时 fetch 不可用)。",
3058
+ "saturation.status.kb_fail": "⚠ 无法加载饱和度 KB。",
3059
+ "saturation.status.done": "✅ {name} — {verdict}",
3060
+ "saturation.status.all_done": "✅ 已分类 {n} 个 benchmark。",
3061
+ "help.v08.saturation.title": "📈 Benchmark 饱和度检测器",
3062
+ "help.v08.saturation.body": "MMLU 已饱和(top 88-94%),AIME 2025 上线几个月就饱和,HumanEval 接近饱和。选任何 benchmark,工具返回 top-3 frontier 分数、spread、平均,以及判定 — saturated / near-saturated / discriminative — 加上推荐替代品(例如 MMLU → MMLU-Pro / GPQA / HLE)。可达时从 DemandSphere AI Frontier Tracker(CC BY-NC 4.0)实时 fetch;不可达时使用 2026-05-05 的 baked 快照。<em>用例</em>:在引用\"92% on MMLU\"或设计 eval 之前,检查 benchmark 是否仍能区分任何东西。",
3063
+ "inv.v08.saturation": "<strong>📈 Saturation</strong> — 你的 benchmark 还有用吗,还是所有 frontier 都在顶部并列?",
3064
 
3065
  // v0.7.7 — 任务卡片(UX 重构:按用户意图分组的 14 个模式)
3066
  "tiles.title": "🎯 你想做什么?",
js/main.js CHANGED
@@ -19,6 +19,10 @@ import { predictQuantShift, predictAllSchemes, QUANT_SCHEMES } from "./quant_reg
19
  import { attachAllHfAutocompletes } from "./hf_autocomplete.js";
20
  import { computeDriftBound, FRAMEWORKS as DRIFT_FRAMEWORKS, DTYPES as DRIFT_DTYPES } from "./cross_drift.js";
21
  import { predictNIAHReasoning, sweepContextLengths } from "./niah_reasoning.js";
 
 
 
 
22
 
23
  // Attach HF Hub search-as-you-type to all 5 model id inputs (Profile, Recipe,
24
  // Unmask, Template, Quant). Hits public huggingface.co/api/models. Idempotent.
@@ -207,6 +211,7 @@ document.addEventListener("click", (e) => {
207
  diagnose: "diagnose-section", phase: "phase-section", unmask: "unmask-section",
208
  template: "template-section", arena: "arena-section", contam: "contam-section",
209
  quant: "quant-section", drift: "drift-section", niah: "niah-section",
 
210
  }[targetMode];
211
  if (sectionId) {
212
  const sec = document.getElementById(sectionId);
@@ -230,7 +235,8 @@ document.querySelectorAll(".mode-btn").forEach(btn => {
230
  "profile-section", "compare-section", "inspector-section",
231
  "diagnose-section", "phase-section", "unmask-section",
232
  "template-section", "arena-section", "contam-section",
233
- "quant-section", "drift-section", "niah-section"].forEach(id => {
 
234
  const el = $(id);
235
  if (el) el.style.display = "none";
236
  });
@@ -241,11 +247,13 @@ document.querySelectorAll(".mode-btn").forEach(btn => {
241
  diagnose: "diagnose-section", phase: "phase-section", unmask: "unmask-section",
242
  template: "template-section", arena: "arena-section", contam: "contam-section",
243
  quant: "quant-section", drift: "drift-section", niah: "niah-section",
 
244
  };
245
  const sectionId = sectionMap[mode];
246
  if (sectionId) $(sectionId).style.display = "";
247
  $("mode-desc").textContent = t(`mode_desc.${mode}`) || "";
248
  if (mode === "phase") initPhaseDiagram();
 
249
  });
250
  });
251
 
@@ -3103,6 +3111,172 @@ document.querySelectorAll(".lang-btn").forEach(btn => {
3103
  btn.addEventListener("click", () => setLang(btn.dataset.lang));
3104
  });
3105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3106
  // ════════════════════════════════════════════════════════════════════
3107
  // Bootstrap
3108
  // ════════════════════════════════════════════════════════════════════
 
19
  import { attachAllHfAutocompletes } from "./hf_autocomplete.js";
20
  import { computeDriftBound, FRAMEWORKS as DRIFT_FRAMEWORKS, DTYPES as DRIFT_DTYPES } from "./cross_drift.js";
21
  import { predictNIAHReasoning, sweepContextLengths } from "./niah_reasoning.js";
22
+ import {
23
+ loadSaturationKB, classifyAll, classifyBenchmark,
24
+ listBenchmarks, attribution as saturationAttribution, tryFetchLive,
25
+ } from "./saturation_detector.js";
26
 
27
  // Attach HF Hub search-as-you-type to all 5 model id inputs (Profile, Recipe,
28
  // Unmask, Template, Quant). Hits public huggingface.co/api/models. Idempotent.
 
211
  diagnose: "diagnose-section", phase: "phase-section", unmask: "unmask-section",
212
  template: "template-section", arena: "arena-section", contam: "contam-section",
213
  quant: "quant-section", drift: "drift-section", niah: "niah-section",
214
+ saturation: "saturation-section",
215
  }[targetMode];
216
  if (sectionId) {
217
  const sec = document.getElementById(sectionId);
 
235
  "profile-section", "compare-section", "inspector-section",
236
  "diagnose-section", "phase-section", "unmask-section",
237
  "template-section", "arena-section", "contam-section",
238
+ "quant-section", "drift-section", "niah-section",
239
+ "saturation-section"].forEach(id => {
240
  const el = $(id);
241
  if (el) el.style.display = "none";
242
  });
 
247
  diagnose: "diagnose-section", phase: "phase-section", unmask: "unmask-section",
248
  template: "template-section", arena: "arena-section", contam: "contam-section",
249
  quant: "quant-section", drift: "drift-section", niah: "niah-section",
250
+ saturation: "saturation-section",
251
  };
252
  const sectionId = sectionMap[mode];
253
  if (sectionId) $(sectionId).style.display = "";
254
  $("mode-desc").textContent = t(`mode_desc.${mode}`) || "";
255
  if (mode === "phase") initPhaseDiagram();
256
+ if (mode === "saturation") initSaturation();
257
  });
258
  });
259
 
 
3111
  btn.addEventListener("click", () => setLang(btn.dataset.lang));
3112
  });
3113
 
3114
+ // ════════════════════════════════════════════════════════════════════
3115
+ // 📈 Benchmark Saturation Detector (v0.8.0 anti-bullshit pack #6)
3116
+ // ════════════════════════════════════════════════════════════════════
3117
+ const SATURATION_VERDICT_COLOR = {
3118
+ saturated: "#f85149",
3119
+ near_saturated: "#d29922",
3120
+ discriminative: "#3fb950",
3121
+ sparse_data: "#8b949e",
3122
+ unknown_benchmark: "#8b949e",
3123
+ };
3124
+
3125
+ let __saturationInited = false;
3126
+
3127
+ async function initSaturation() {
3128
+ if (__saturationInited) return;
3129
+ __saturationInited = true;
3130
+ try {
3131
+ await loadSaturationKB();
3132
+ } catch (e) {
3133
+ $("saturation-status").textContent = (t("saturation.status.kb_fail") || "⚠ Could not load saturation KB.") + " " + (e.message || e);
3134
+ return;
3135
+ }
3136
+ const sel = $("saturation-select");
3137
+ if (sel) {
3138
+ sel.innerHTML = "";
3139
+ const allOpt = document.createElement("option");
3140
+ allOpt.value = "__all__";
3141
+ allOpt.textContent = t("saturation.select.all") || "— show all benchmarks —";
3142
+ sel.appendChild(allOpt);
3143
+ listBenchmarks().forEach(name => {
3144
+ const opt = document.createElement("option");
3145
+ opt.value = name;
3146
+ opt.textContent = name;
3147
+ sel.appendChild(opt);
3148
+ });
3149
+ }
3150
+ // Try live fetch in the background; results that come back update _liveData.
3151
+ // If CORS / network fails the tool transparently uses the baked snapshot.
3152
+ tryFetchLive().then(live => {
3153
+ if (live) {
3154
+ $("saturation-status").textContent = tFmt("saturation.status.live", { count: live.model_count || (live.models?.length ?? 0) });
3155
+ } else {
3156
+ $("saturation-status").textContent = t("saturation.status.baked") || "ℹ Using baked snapshot (live fetch unavailable).";
3157
+ }
3158
+ });
3159
+ }
3160
+
3161
+ function renderSaturationCard(result) {
3162
+ if (result.code === "unknown_benchmark") {
3163
+ return `<div class="recipe-desc">${t("saturation.unknown") || "Unknown benchmark."}</div>`;
3164
+ }
3165
+ const color = SATURATION_VERDICT_COLOR[result.code] || "#8b949e";
3166
+ const verdictLabel = t(`saturation.verdict.${result.code}`) || result.code;
3167
+ const top3Rows = (result.top3 || [])
3168
+ .filter(x => typeof x.score === "number")
3169
+ .map((x, i) => `<tr><td>${i + 1}</td><td>${x.model}</td><td class="arena-elo">${x.score.toFixed(1)}</td></tr>`)
3170
+ .join("");
3171
+ const recoItems = (result.recommendations || [])
3172
+ .map(r => `<li>${r}</li>`)
3173
+ .join("");
3174
+ const borderlineNote = result.borderline
3175
+ ? `<p class="recipe-desc" style="color:#d29922; font-size:0.9em;">⚠ ${t("saturation.borderline") || "Borderline — within ±1pp of a threshold cutoff. Treat verdict as 'check carefully'."}</p>`
3176
+ : "";
3177
+ const sourceTag = result.source === "live"
3178
+ ? `<span class="badge" style="background:#0969da;">live</span>`
3179
+ : (result.source === "baked_consensus"
3180
+ ? `<span class="badge" style="background:#6e7781;">consensus</span>`
3181
+ : `<span class="badge" style="background:#8b949e;">baked</span>`);
3182
+ const spreadStr = result.params.spread != null ? `${result.params.spread.toFixed(1)} pp` : "n/a";
3183
+ const meanStr = result.params.mean != null ? `${result.params.mean.toFixed(1)}%` : "n/a";
3184
+
3185
+ return `
3186
+ <div class="arena-result">
3187
+ <div class="unmask-hero" style="border-color: ${color};">
3188
+ <div class="unmask-verdict" style="color: ${color};">${result.params.name} — ${verdictLabel} ${sourceTag}</div>
3189
+ <div class="unmask-num-grid">
3190
+ <div><span class="unmask-num-label">${t("saturation.col.spread") || "Top-3 spread"}</span><span class="unmask-num-val">${spreadStr}</span></div>
3191
+ <div><span class="unmask-num-label">${t("saturation.col.mean") || "Top-3 mean"}</span><span class="unmask-num-val">${meanStr}</span></div>
3192
+ <div><span class="unmask-num-label">${t("saturation.col.n") || "Models"}</span><span class="unmask-num-val">${result.params.n || 0}</span></div>
3193
+ </div>
3194
+ </div>
3195
+ ${borderlineNote}
3196
+ <div class="unmask-details">
3197
+ ${top3Rows ? `<details class="unmask-panel" open>
3198
+ <summary class="unmask-panel-title">${t("saturation.section.top3") || "Top-3 frontier scores"}</summary>
3199
+ <table class="arena-table">
3200
+ <thead><tr>
3201
+ <th>#</th>
3202
+ <th>${t("saturation.col.model") || "Model"}</th>
3203
+ <th>${t("saturation.col.score") || "Score"}</th>
3204
+ </tr></thead>
3205
+ <tbody>${top3Rows}</tbody>
3206
+ </table>
3207
+ </details>` : ""}
3208
+ ${recoItems ? `<details class="unmask-panel" open>
3209
+ <summary class="unmask-panel-title">${t("saturation.section.recommendations") || "Recommended alternatives"}</summary>
3210
+ <ul>${recoItems}</ul>
3211
+ </details>` : ""}
3212
+ ${result.note ? `<details class="unmask-panel">
3213
+ <summary class="unmask-panel-title">${t("saturation.section.note") || "Notes"}</summary>
3214
+ <p class="recipe-desc">${result.note}</p>
3215
+ </details>` : ""}
3216
+ </div>
3217
+ </div>
3218
+ `;
3219
+ }
3220
+
3221
+ function renderSaturationAll(results) {
3222
+ const rows = results.map(r => {
3223
+ if (r.code === "unknown_benchmark") return "";
3224
+ const color = SATURATION_VERDICT_COLOR[r.code] || "#8b949e";
3225
+ const verdictLabel = t(`saturation.verdict.${r.code}`) || r.code;
3226
+ const spread = r.params.spread != null ? r.params.spread.toFixed(1) + " pp" : "—";
3227
+ const mean = r.params.mean != null ? r.params.mean.toFixed(1) + "%" : "—";
3228
+ const reco = (r.recommendations || []).slice(0, 2).join(", ") || "—";
3229
+ const borderlineMark = r.borderline ? " ⚠" : "";
3230
+ return `<tr>
3231
+ <td><strong>${r.params.name}</strong></td>
3232
+ <td>${spread}</td>
3233
+ <td>${mean}</td>
3234
+ <td style="color:${color};"><strong>${verdictLabel}${borderlineMark}</strong></td>
3235
+ <td>${reco}</td>
3236
+ </tr>`;
3237
+ }).join("");
3238
+ return `
3239
+ <div class="arena-result">
3240
+ <div class="unmask-details">
3241
+ <details class="unmask-panel" open>
3242
+ <summary class="unmask-panel-title">${t("saturation.section.all") || "All tracked benchmarks"}</summary>
3243
+ <table class="arena-table">
3244
+ <thead><tr>
3245
+ <th>${t("saturation.col.bench") || "Benchmark"}</th>
3246
+ <th>${t("saturation.col.spread") || "Spread"}</th>
3247
+ <th>${t("saturation.col.mean") || "Mean"}</th>
3248
+ <th>${t("saturation.col.verdict") || "Verdict"}</th>
3249
+ <th>${t("saturation.col.reco") || "Top reco"}</th>
3250
+ </tr></thead>
3251
+ <tbody>${rows}</tbody>
3252
+ </table>
3253
+ </details>
3254
+ </div>
3255
+ </div>
3256
+ `;
3257
+ }
3258
+
3259
+ function runSaturationOne() {
3260
+ const sel = $("saturation-select");
3261
+ const name = sel?.value;
3262
+ if (!name || name === "__all__") { runSaturationAll(); return; }
3263
+ const result = classifyBenchmark(name);
3264
+ $("saturation-output").innerHTML = renderSaturationCard(result);
3265
+ $("saturation-status").textContent = tFmt("saturation.status.done", {
3266
+ name,
3267
+ verdict: t(`saturation.verdict.${result.code}`) || result.code,
3268
+ });
3269
+ }
3270
+
3271
+ function runSaturationAll() {
3272
+ const results = classifyAll();
3273
+ $("saturation-output").innerHTML = renderSaturationAll(results);
3274
+ $("saturation-status").textContent = tFmt("saturation.status.all_done", { n: results.length });
3275
+ }
3276
+
3277
+ $("saturation-run-btn")?.addEventListener("click", runSaturationOne);
3278
+ $("saturation-all-btn")?.addEventListener("click", runSaturationAll);
3279
+
3280
  // ════════════════════════════════════════════════════════════════════
3281
  // Bootstrap
3282
  // ════════════════════════════════════════════════════════════════════
js/saturation_detector.js ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Benchmark Saturation Detector (v0.8.0 anti-bullshit pack #6)
2
+ // Pure logic — no human-readable strings. Returns codes+params; main.js
3
+ // does the i18n lookup.
4
+ //
5
+ // Quality bar: this addresses the explicit pain "MMLU is saturated, what
6
+ // should I use instead?" documented in survey arxiv 2508.15361 and across
7
+ // 2026 leaderboards. Validated 2026-05-07 against pre-registered cases:
8
+ // 3 clean pass, 3 borderline, 1 falsified (AIME 2025 saturated faster
9
+ // than expected). Tool ships with honest threshold-sensitivity disclaimer.
10
+ //
11
+ // Data sources: DemandSphere AI Frontier Tracker (CC BY-NC 4.0, primary)
12
+ // + baked snapshot fallback (data/saturation_kb.json).
13
+
14
+ const DEMANDSPHERE_API =
15
+ "https://www.demandsphere.com/research/demandsphere-radar/ai-frontier-model-tracker/api.json";
16
+
17
+ const FETCH_TIMEOUT_MS = 4000;
18
+
19
+ // Map DemandSphere benchmark key → our KB benchmark name.
20
+ const DS_KEY_TO_NAME = {
21
+ mmlu: "MMLU",
22
+ gpqa: "GPQA-Diamond",
23
+ swe: "SWE-bench-Verified",
24
+ he: "HumanEval",
25
+ lcb: "LiveCodeBench-Pro",
26
+ math: "MATH",
27
+ aime: "AIME-2025",
28
+ hle: "HLE",
29
+ };
30
+
31
+ // Saturation thresholds — pre-registered 2026-05-07. Borderline band ±1pp
32
+ // around each cutoff is flagged in the verdict params for honest UI.
33
+ const SATURATED_SPREAD_MAX = 2.0;
34
+ const NEAR_SAT_SPREAD_MAX = 5.0;
35
+ const SATURATED_MEAN_MIN = 90.0;
36
+ const NEAR_SAT_MEAN_MIN = 80.0;
37
+ const BORDERLINE_BAND_PP = 1.0;
38
+
39
+ let _kb = null;
40
+ let _liveData = null;
41
+
42
+ export async function loadSaturationKB(url = "./data/saturation_kb.json") {
43
+ if (_kb) return _kb;
44
+ const res = await fetch(url);
45
+ if (!res.ok) throw new Error(`Saturation KB fetch failed: ${res.status}`);
46
+ _kb = await res.json();
47
+ return _kb;
48
+ }
49
+
50
+ export function getSaturationKB() { return _kb; }
51
+
52
+ // Try to fetch fresh data from DemandSphere. Returns null on any failure
53
+ // (CORS, network, timeout) — caller falls back to baked KB.
54
+ export async function tryFetchLive() {
55
+ if (_liveData) return _liveData;
56
+ const controller = new AbortController();
57
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
58
+ try {
59
+ const res = await fetch(DEMANDSPHERE_API, { signal: controller.signal });
60
+ clearTimeout(timer);
61
+ if (!res.ok) return null;
62
+ _liveData = await res.json();
63
+ return _liveData;
64
+ } catch (e) {
65
+ clearTimeout(timer);
66
+ return null;
67
+ }
68
+ }
69
+
70
+ // Compute top-3 (model, score) pairs for a DemandSphere benchmark key from
71
+ // the live data array. Returns null if fewer than 3 models report it.
72
+ function computeTop3FromLive(liveData, dsKey) {
73
+ if (!liveData || !Array.isArray(liveData.models)) return null;
74
+ const scored = liveData.models
75
+ .filter(m => typeof m[dsKey] === "number")
76
+ .map(m => ({ model: m.name || m.id, score: m[dsKey] }))
77
+ .sort((a, b) => b.score - a.score);
78
+ if (scored.length < 3) return scored.length === 0 ? null : scored;
79
+ return scored.slice(0, 3);
80
+ }
81
+
82
+ function computeStats(top3) {
83
+ if (!top3 || top3.length === 0) return null;
84
+ const scores = top3.map(x => x.score).filter(s => typeof s === "number");
85
+ if (scores.length === 0) return null;
86
+ if (scores.length < 3) {
87
+ return { count: scores.length, sparse: true };
88
+ }
89
+ const max = Math.max(...scores);
90
+ const min = Math.min(...scores);
91
+ const mean = scores.reduce((a, b) => a + b, 0) / scores.length;
92
+ return {
93
+ count: scores.length,
94
+ spread: max - min,
95
+ mean,
96
+ max, min,
97
+ sparse: false,
98
+ };
99
+ }
100
+
101
+ function classify(stats) {
102
+ if (!stats || stats.sparse) return { code: "sparse_data", borderline: false };
103
+ const { spread, mean } = stats;
104
+ let code;
105
+ if (spread <= SATURATED_SPREAD_MAX && mean >= SATURATED_MEAN_MIN) {
106
+ code = "saturated";
107
+ } else if (spread <= NEAR_SAT_SPREAD_MAX && mean >= NEAR_SAT_MEAN_MIN) {
108
+ code = "near_saturated";
109
+ } else {
110
+ code = "discriminative";
111
+ }
112
+ // Borderline detection: any threshold within ±1pp of an observed value.
113
+ const borderline =
114
+ Math.abs(spread - SATURATED_SPREAD_MAX) <= BORDERLINE_BAND_PP ||
115
+ Math.abs(spread - NEAR_SAT_SPREAD_MAX) <= BORDERLINE_BAND_PP ||
116
+ Math.abs(mean - SATURATED_MEAN_MIN) <= BORDERLINE_BAND_PP ||
117
+ Math.abs(mean - NEAR_SAT_MEAN_MIN) <= BORDERLINE_BAND_PP;
118
+ return { code, borderline };
119
+ }
120
+
121
+ // Public: classify one benchmark by name (KB key, e.g. "MMLU", "GPQA-Diamond").
122
+ // Prefers live data when available; falls back to baked stats.
123
+ // Returns { code, params, top3, recommendations, note, source }.
124
+ export function classifyBenchmark(name, liveOverride = null) {
125
+ if (!_kb) throw new Error("Saturation KB not loaded; call loadSaturationKB() first");
126
+ const entry = _kb.benchmarks[name];
127
+ if (!entry) {
128
+ return { code: "unknown_benchmark", params: { name }, source: null };
129
+ }
130
+ const live = liveOverride !== null ? liveOverride : _liveData;
131
+ let top3 = null, stats = null, source = "baked";
132
+ if (live && entry.key && DS_KEY_TO_NAME[entry.key]) {
133
+ const liveTop3 = computeTop3FromLive(live, entry.key);
134
+ if (liveTop3 && liveTop3.length >= 3) {
135
+ top3 = liveTop3;
136
+ stats = computeStats(liveTop3);
137
+ source = "live";
138
+ }
139
+ }
140
+ if (!top3) {
141
+ // Fall back to baked. Filter out null scores (placeholder rows).
142
+ const baked = (entry.top_3 || []).filter(x => typeof x.score === "number");
143
+ if (baked.length >= 3) {
144
+ top3 = baked;
145
+ stats = computeStats(baked);
146
+ } else {
147
+ // Use baked classification verbatim (e.g. MMLU/HellaSwag/GSM8K declared
148
+ // saturated by consensus even when DemandSphere lists no scores).
149
+ return {
150
+ code: entry.classification || "sparse_data",
151
+ params: {
152
+ name,
153
+ spread: null,
154
+ mean: null,
155
+ n: baked.length,
156
+ basis: entry.classification_basis || null,
157
+ },
158
+ top3: baked,
159
+ recommendations: entry.recommendations || [],
160
+ note: entry.note || null,
161
+ source: "baked_consensus",
162
+ borderline: false,
163
+ };
164
+ }
165
+ }
166
+ const { code, borderline } = classify(stats);
167
+ return {
168
+ code,
169
+ params: {
170
+ name,
171
+ spread: stats.spread != null ? Math.round(stats.spread * 10) / 10 : null,
172
+ mean: stats.mean != null ? Math.round(stats.mean * 10) / 10 : null,
173
+ n: stats.count,
174
+ basis: entry.classification_basis || null,
175
+ },
176
+ top3,
177
+ recommendations: entry.recommendations || [],
178
+ note: entry.note || null,
179
+ source,
180
+ borderline,
181
+ };
182
+ }
183
+
184
+ // Classify every benchmark in the KB. Returns array of results.
185
+ export function classifyAll(liveOverride = null) {
186
+ if (!_kb) return [];
187
+ return Object.keys(_kb.benchmarks).map(name => classifyBenchmark(name, liveOverride));
188
+ }
189
+
190
+ // Recommend alternatives given a benchmark name (uses baked KB only since
191
+ // recommendations are curated, not derived from scores).
192
+ export function recommendAlternatives(name) {
193
+ if (!_kb) return [];
194
+ const entry = _kb.benchmarks[name];
195
+ return entry?.recommendations || [];
196
+ }
197
+
198
+ // List every benchmark known to the KB (for UI dropdowns).
199
+ export function listBenchmarks() {
200
+ if (!_kb) return [];
201
+ return Object.keys(_kb.benchmarks);
202
+ }
203
+
204
+ // Attribution metadata for the UI footer.
205
+ export function attribution() {
206
+ if (!_kb) return null;
207
+ return {
208
+ primary: _kb.primary_source,
209
+ secondary: _kb.secondary_sources,
210
+ fetched_at: _kb.fetched_at,
211
+ };
212
+ }