Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>Thin Channel · Second Loop</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com" /> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> | |
| <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@1,700&family=Inter:wght@400;500;700;800&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet" /> | |
| <script src="https://cdn.plot.ly/plotly-2.35.2.min.js" charset="utf-8"></script> | |
| <style> | |
| :root{ | |
| --bg:#000000; --bg-card:#0A0A0A; --bg-elev:#141414; | |
| --border:#1F1F1F; --border-strong:#2A2A2A; | |
| --text:#FFFFFF; --text-mute:#A8A8A8; --text-dim:#6B6B6B; | |
| --gold:#D4AF37; --gold-hi:#E8C84A; | |
| --red:#FF2A2A; --green:#1FD160; | |
| --mono:'JetBrains Mono',ui-monospace,monospace; | |
| --serif:'Playfair Display',serif; | |
| --sans:'Inter',system-ui,sans-serif; | |
| } | |
| *{box-sizing:border-box;} | |
| html,body{margin:0;background:var(--bg);color:var(--text);font-family:var(--sans);} | |
| .wrap{max-width:1180px;margin:0 auto;padding:22px 24px 64px 24px;} | |
| a{color:var(--gold);text-decoration:none;border-bottom:1px dotted var(--gold);} | |
| a:hover{color:var(--gold-hi);} | |
| /* ---------- header ---------- */ | |
| .head{border:1px solid var(--border-strong);border-radius:14px; | |
| padding:26px 30px 22px 30px;background:linear-gradient(180deg,#0A0A0A 0%,#050505 100%);} | |
| .head-top{display:flex;align-items:flex-start;justify-content:space-between;gap:24px; | |
| padding-bottom:16px;border-bottom:1px solid var(--border);margin-bottom:16px;} | |
| .head-brand{display:flex;align-items:center;gap:16px;} | |
| .head-icon{width:52px;height:52px;border:1px solid var(--border-strong);border-radius:12px; | |
| display:flex;align-items:center;justify-content:center; | |
| background:radial-gradient(60% 60% at 50% 40%,#1A1A1A 0%,#050505 100%);} | |
| .head-title{font-family:var(--serif);font-style:italic;font-weight:700;font-size:34px; | |
| color:var(--text);line-height:1;margin:2px 0 7px 0;} | |
| .head-subtitle{font-family:var(--mono);font-size:11.5px;letter-spacing:.14em; | |
| color:var(--text-mute);text-transform:uppercase;} | |
| .head-right{text-align:right;white-space:nowrap;} | |
| .submitted-label{font-family:var(--mono);font-size:10px;letter-spacing:.22em; | |
| color:var(--text-dim);text-transform:uppercase;display:block;margin-bottom:4px;} | |
| .submitted-name{font-family:var(--serif);font-style:italic;font-weight:700;font-size:20px;color:var(--text);} | |
| .status-pill{display:inline-flex;align-items:center;gap:6px;margin-top:10px;padding:5px 12px; | |
| border-radius:999px;background:rgba(31,209,96,.08);border:1px solid rgba(31,209,96,.5); | |
| font-family:var(--mono);font-size:10px;letter-spacing:.18em;color:var(--green);text-transform:uppercase;} | |
| .status-dot{width:7px;height:7px;border-radius:50%;background:var(--green);} | |
| .head-meta{display:grid;grid-template-columns:repeat(4,1fr);gap:12px 24px;} | |
| .head-meta .item{display:flex;flex-direction:column;gap:3px;} | |
| .head-meta .k{font-family:var(--mono);font-size:9.5px;letter-spacing:.2em;color:var(--text-dim);text-transform:uppercase;} | |
| .head-meta .v{font-family:var(--sans);font-size:13.5px;font-weight:700;color:var(--text);} | |
| /* ---------- three honest badges ---------- */ | |
| .badges{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:18px 0 4px 0;} | |
| .badge{background:var(--bg-card);border:1px solid var(--border-strong);border-radius:12px;padding:16px 20px;} | |
| .badge .label{font-family:var(--mono);font-size:9.5px;letter-spacing:.2em;color:var(--text-dim); | |
| text-transform:uppercase;margin-bottom:8px;} | |
| .badge .value{font-family:var(--serif);font-style:italic;font-weight:700;font-size:26px;color:var(--text);} | |
| .badge .sub{font-family:var(--mono);font-size:10px;letter-spacing:.1em;color:var(--text-mute); | |
| text-transform:uppercase;margin-top:4px;} | |
| .badge.green{border-color:rgba(31,209,96,.5);} | |
| .badge.red{border-color:rgba(255,42,42,.5);} | |
| /* ---------- exhibit (the museum lever) ---------- */ | |
| .exhibit{margin-top:18px;border:1px solid var(--border-strong);border-radius:14px; | |
| background:var(--bg-card);padding:22px 24px 26px 24px;} | |
| .exhibit-title{font-family:var(--serif);font-style:italic;font-weight:700;font-size:22px;margin:0 0 2px 0;} | |
| .exhibit-lede{font-family:var(--mono);font-size:11px;letter-spacing:.1em;color:var(--text-mute); | |
| text-transform:uppercase;margin-bottom:18px;} | |
| .exhibit-grid{display:grid;grid-template-columns:1fr 300px;gap:22px;align-items:stretch;} | |
| #chart{width:100%;height:430px;} | |
| .readout{border:1px solid var(--border-strong);border-radius:12px;background:#050505; | |
| padding:20px 22px;display:flex;flex-direction:column;gap:2px;transition:border-color 160ms ease;} | |
| .readout.collapsed{border-color:rgba(255,42,42,.6);background:rgba(255,42,42,.04);} | |
| .readout .ro-label{font-family:var(--mono);font-size:9.5px;letter-spacing:.2em;color:var(--text-dim);text-transform:uppercase;} | |
| .readout .ro-name{font-family:var(--serif);font-style:italic;font-weight:700;font-size:30px;line-height:1.05;margin:4px 0 2px 0;} | |
| .readout .ro-period{font-family:var(--mono);font-size:10.5px;letter-spacing:.08em;color:var(--text-mute);text-transform:uppercase;} | |
| .ro-brier-label{font-family:var(--mono);font-size:9.5px;letter-spacing:.2em;color:var(--text-dim); | |
| text-transform:uppercase;margin-top:20px;} | |
| .ro-brier{font-family:var(--serif);font-style:italic;font-weight:700;font-size:56px;line-height:1; | |
| color:var(--green);transition:color 160ms ease;} | |
| .readout.collapsed .ro-brier{color:var(--red);} | |
| .ro-tag{align-self:flex-start;margin-top:6px;padding:4px 10px;border-radius:999px; | |
| font-family:var(--mono);font-size:9.5px;letter-spacing:.18em;text-transform:uppercase; | |
| background:rgba(255,42,42,.1);border:1px solid rgba(255,42,42,.55);color:var(--red); | |
| visibility:hidden;} | |
| .readout.collapsed .ro-tag{visibility:visible;} | |
| .ro-aux{margin-top:18px;border-top:1px solid var(--border);padding-top:14px;display:flex;flex-direction:column;gap:9px;} | |
| .ro-aux .row{display:flex;align-items:baseline;justify-content:space-between;gap:10px;} | |
| .ro-aux .rk{font-family:var(--mono);font-size:10px;letter-spacing:.06em;color:var(--text-dim);text-transform:uppercase;} | |
| .ro-aux .rv{font-family:var(--mono);font-size:13px;font-weight:700;} | |
| .rv.gold{color:var(--gold);} .rv.red{color:var(--red);} .rv.green{color:var(--green);} .rv.mute{color:var(--text-mute);} | |
| /* ---------- slider (the lever) ---------- */ | |
| .lever{margin-top:24px;} | |
| .lever-head{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:14px;} | |
| .lever-head .t{font-family:var(--mono);font-size:11px;letter-spacing:.18em;color:var(--text);text-transform:uppercase;} | |
| .lever-head .h{font-family:var(--mono);font-size:10px;letter-spacing:.1em;color:var(--text-dim);text-transform:uppercase;} | |
| .slider-area{position:relative;padding:0 4px;} | |
| input[type=range].lever-input{ | |
| -webkit-appearance:none;appearance:none;width:100%;height:6px;border-radius:999px;margin:0; | |
| background:linear-gradient(90deg,var(--green) 0%,var(--gold) 78%,var(--red) 100%); | |
| outline:none;cursor:pointer;} | |
| input[type=range].lever-input::-webkit-slider-thumb{ | |
| -webkit-appearance:none;appearance:none;width:26px;height:26px;border-radius:50%; | |
| background:#0A0A0A;border:2px solid var(--gold);box-shadow:0 0 0 4px rgba(212,175,55,.18); | |
| cursor:grab;margin-top:-10px;transition:border-color 120ms ease,box-shadow 120ms ease;} | |
| input[type=range].lever-input::-webkit-slider-thumb:active{cursor:grabbing;} | |
| input[type=range].lever-input::-moz-range-thumb{width:26px;height:26px;border-radius:50%; | |
| background:#0A0A0A;border:2px solid var(--gold);box-shadow:0 0 0 4px rgba(212,175,55,.18);cursor:grab;} | |
| input[type=range].lever-input::-moz-range-track{height:6px;border-radius:999px;background:transparent;} | |
| input[type=range].lever-input.at-never::-webkit-slider-thumb{border-color:var(--red);box-shadow:0 0 0 4px rgba(255,42,42,.22);} | |
| input[type=range].lever-input.at-never::-moz-range-thumb{border-color:var(--red);box-shadow:0 0 0 4px rgba(255,42,42,.22);} | |
| input[type=range].lever-input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 4px rgba(212,175,55,.20),0 0 0 7px var(--gold-hi);} | |
| input[type=range].lever-input:focus-visible::-moz-range-thumb{box-shadow:0 0 0 4px rgba(212,175,55,.20),0 0 0 7px var(--gold-hi);} | |
| .ticks{position:relative;height:10px;margin-top:9px;} | |
| .tick{position:absolute;top:0;width:1px;height:6px;background:var(--border-strong);transform:translateX(-50%);} | |
| .tick.on{background:var(--gold);height:9px;} | |
| .ticklabels{position:relative;height:30px;margin-top:2px;} | |
| .tlabel{position:absolute;top:0;font-family:var(--mono);font-size:9.5px;letter-spacing:.02em; | |
| color:var(--text-dim);white-space:nowrap;line-height:1.15;text-align:center;cursor:pointer; | |
| transition:color 120ms ease;} | |
| .tlabel.on{color:var(--text);font-weight:700;} | |
| .tlabel.never.on{color:var(--red);} | |
| .lever-foot{margin-top:18px;display:flex;justify-content:space-between; | |
| font-family:var(--mono);font-size:10px;letter-spacing:.12em;color:var(--text-dim);text-transform:uppercase;} | |
| /* ---------- ablation strip ---------- */ | |
| .ablations{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:22px 0;} | |
| .abl{background:var(--bg-card);border:1px solid var(--border-strong);border-radius:12px;padding:18px 20px;text-align:center;} | |
| .abl .key{font-family:var(--mono);font-size:10px;letter-spacing:.16em;color:var(--text-dim);text-transform:uppercase;margin-bottom:8px;} | |
| .abl .val{font-family:var(--serif);font-style:italic;font-weight:700;font-size:30px;color:var(--text);} | |
| .abl .lbl{font-family:var(--mono);font-size:10px;letter-spacing:.1em;color:var(--text-mute);text-transform:uppercase;margin-top:4px;} | |
| .abl.acc .val{color:var(--green);} | |
| /* ---------- data table ---------- */ | |
| .table-wrap{background:var(--bg-card);border:1px solid var(--border-strong);border-radius:14px;padding:20px 22px;} | |
| .table-cap{font-family:var(--mono);font-size:10px;letter-spacing:.18em;color:var(--text-dim); | |
| text-transform:uppercase;margin-bottom:12px;} | |
| .schedule-table{width:100%;border-collapse:collapse;font-family:var(--mono);font-size:13px;} | |
| .schedule-table th{font-family:var(--mono);font-size:9.5px;letter-spacing:.18em;color:var(--text-dim); | |
| text-transform:uppercase;text-align:right;padding:8px 12px;border-bottom:1px solid var(--border-strong);} | |
| .schedule-table th:first-child{text-align:left;} | |
| .schedule-table td{padding:9px 12px;border-bottom:1px solid var(--border);text-align:right;} | |
| .schedule-table tr{cursor:pointer;} | |
| .schedule-table tr.active{background:rgba(212,175,55,.07);} | |
| .td-name{text-align:left!important;font-family:var(--serif);font-style:italic;font-weight:700;font-size:15px;color:var(--text);} | |
| .td-mute{color:var(--text-mute);} | |
| .td-c{color:var(--green);font-weight:700;} .td-b{color:var(--gold);font-weight:700;} .td-a{color:var(--red);font-weight:700;opacity:.78;} | |
| .never-row{background:rgba(255,42,42,.06);} | |
| .never-row .td-c{color:var(--red)!important;} | |
| /* ---------- about ---------- */ | |
| .foot{margin-top:24px;padding:22px 24px;border:1px solid var(--border);border-radius:12px;background:var(--bg-card);} | |
| .foot .ftitle{font-family:var(--mono);font-size:10px;letter-spacing:.2em;color:var(--text-dim);text-transform:uppercase;margin-bottom:10px;} | |
| .foot .body{font-family:var(--sans);font-size:13px;color:var(--text-mute);line-height:1.62;} | |
| .foot code{font-family:var(--mono);font-size:12px;color:var(--text);background:var(--bg-elev); | |
| padding:1px 5px;border-radius:4px;border:1px solid var(--border);} | |
| .attrib{margin-top:14px;padding-top:14px;border-top:1px solid var(--border); | |
| font-family:var(--mono);font-size:11px;letter-spacing:.04em;color:var(--text-dim);line-height:1.7;} | |
| @media(max-width:860px){ | |
| .exhibit-grid{grid-template-columns:1fr;} | |
| .head-meta{grid-template-columns:repeat(2,1fr);} | |
| .badges,.ablations{grid-template-columns:1fr;} | |
| .head-top{flex-direction:column;} | |
| .head-right{text-align:left;} | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <main class="wrap"> | |
| <!-- HEADER --> | |
| <header class="head"> | |
| <div class="head-top"> | |
| <div class="head-brand"> | |
| <div class="head-icon"> | |
| <svg width="28" height="28" viewBox="0 0 28 28" fill="none" aria-hidden="true"> | |
| <rect x="3.5" y="3.5" width="21" height="21" rx="4" stroke="#2A2A2A"/> | |
| <line x1="14" y1="5.5" x2="14" y2="22.5" stroke="#D4AF37" stroke-width="1.6"/> | |
| <circle cx="14" cy="9" r="1.3" fill="#1FD160"/> | |
| <circle cx="14" cy="14" r="1.3" fill="#1FD160"/> | |
| <circle cx="14" cy="19" r="1.3" fill="#1FD160"/> | |
| </svg> | |
| </div> | |
| <div> | |
| <div class="head-title">Thin Channel</div> | |
| <div class="head-subtitle">How rarely external truth can arrive before calibration collapses</div> | |
| </div> | |
| </div> | |
| <div class="head-right"> | |
| <span class="submitted-label">Submitted by</span> | |
| <div class="submitted-name" id="author">—</div> | |
| <div class="status-pill"><span class="status-dot"></span>Static demo · no live model</div> | |
| </div> | |
| </div> | |
| <div class="head-meta"> | |
| <div class="item"><span class="k">Subject model</span><span class="v">Qwen2.5-3B-Instruct (frozen)</span></div> | |
| <div class="item"><span class="k">Dataset</span><span class="v" id="m-dataset">ForecastBench</span></div> | |
| <div class="item"><span class="k">Hold-out</span><span class="v" id="m-holdout">N = 330</span></div> | |
| <div class="item"><span class="k">Calibration</span><span class="v">per-topic Beta · K = 10</span></div> | |
| </div> | |
| </header> | |
| <!-- THREE HONEST BADGES --> | |
| <section class="badges"> | |
| <div class="badge green"> | |
| <div class="label">Corridor — any finite schedule</div> | |
| <div class="value" id="b-corridor">0.205–0.220</div> | |
| <div class="sub">Brier on hold-out</div> | |
| </div> | |
| <div class="badge red"> | |
| <div class="label">Never — no signal</div> | |
| <div class="value" id="b-never">0.298</div> | |
| <div class="sub">collapses to raw 3B</div> | |
| </div> | |
| <div class="badge"> | |
| <div class="label">Cliff direction</div> | |
| <div class="value">Binary</div> | |
| <div class="sub">channel = volume, not frequency</div> | |
| </div> | |
| </section> | |
| <!-- EXHIBIT: the museum lever --> | |
| <section class="exhibit"> | |
| <div class="exhibit-title">How often does the system get to check reality?</div> | |
| <div class="exhibit-lede">Move the lever from “every day” to “never” and watch the Brier curve</div> | |
| <div class="exhibit-grid"> | |
| <div id="chart"></div> | |
| <div class="readout" id="readout"> | |
| <div class="ro-label">Current check interval</div> | |
| <div class="ro-name" id="ro-name">day</div> | |
| <div class="ro-period" id="ro-period">every 1 day · 1316 outcomes seen</div> | |
| <div class="ro-brier-label">Brier on hold-out · lower is better</div> | |
| <div class="ro-brier" id="ro-brier">0.205</div> | |
| <div class="ro-tag" id="ro-tag">Collapse — back to raw 3B</div> | |
| <div class="ro-aux"> | |
| <div class="row"><span class="rk">(b) base-rate only</span><span class="rv gold" id="ro-b">0.210</span></div> | |
| <div class="row"><span class="rk">(a) raw 3B only</span><span class="rv red" id="ro-a">0.298</span></div> | |
| <div class="row"><span class="rk">improvement vs raw 3B</span><span class="rv" id="ro-delta">−0.093</span></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="lever"> | |
| <div class="lever-head"> | |
| <span class="t">The lever — reveal schedule</span> | |
| <span class="h">← more often · less often →</span> | |
| </div> | |
| <div class="slider-area"> | |
| <input id="slider" class="lever-input" type="range" min="0" max="10" step="1" value="0" | |
| aria-label="How often the system checks reality" /> | |
| <div class="ticks" id="ticks"></div> | |
| <div class="ticklabels" id="ticklabels"></div> | |
| </div> | |
| <div class="lever-foot"> | |
| <span>Daily contact</span> | |
| <span>One annual debrief</span> | |
| <span>Never</span> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- ABLATION STRIP --> | |
| <section class="ablations"> | |
| <div class="abl"> | |
| <div class="key">(a) raw 3B only</div> | |
| <div class="val" id="abl-a">0.298</div> | |
| <div class="lbl">useless as a forecaster</div> | |
| </div> | |
| <div class="abl acc"> | |
| <div class="key">(b) topic base-rate only</div> | |
| <div class="val" id="abl-b">0.189</div> | |
| <div class="lbl">no model needed</div> | |
| </div> | |
| <div class="abl acc"> | |
| <div class="key">(c) mix (a + b)</div> | |
| <div class="val" id="abl-c">0.189</div> | |
| <div class="lbl">c − b = <span id="abl-d">−0.0001</span></div> | |
| </div> | |
| </section> | |
| <!-- DATA TABLE --> | |
| <section class="table-wrap"> | |
| <div class="table-cap">All 11 schedules — verbatim from the run (click a row to move the lever)</div> | |
| <table class="schedule-table"> | |
| <thead><tr> | |
| <th>Frequency</th><th>Period</th><th>Revealed</th> | |
| <th>(c) mix</th><th>(b) base only</th><th>(a) raw 3B</th> | |
| </tr></thead> | |
| <tbody id="tbody"></tbody> | |
| </table> | |
| </section> | |
| <!-- ABOUT --> | |
| <footer class="foot"> | |
| <div class="ftitle">About this demo</div> | |
| <div class="body"> | |
| 1,646 resolved binary forecasting questions are streamed through a simulated calendar: | |
| a frozen Qwen2.5-3B-Instruct emits a raw <i>P(YES)</i> at each question’s freeze date, | |
| the true outcome is hidden and revealed only on a schedule, and a per-topic Beta | |
| calibration (9 topics, K = 10) consumes each revealed outcome. The same stream is run | |
| independently through 11 reveal schedules, from “every day” to “never”. The metric is | |
| Brier score on the held-out last 20% (N = 330); lower is better. | |
| The result is a binary cliff: every finite schedule holds the corridor at | |
| <b id="t-corridor">0.205–0.220</b>, while zero contact collapses to | |
| <b id="t-never">0.298</b> — bit-for-bit the raw 3B level. | |
| <br/><br/> | |
| Read the honest caveat alongside it: the raw 3B is useless as a forecaster on its own | |
| (Brier <span id="t-wide">0.354</span> on a wide baseline, worse than “always NO”). The (c) ≈ (b) ablation shows | |
| the entire calibration gain comes from picking up <b>per-topic base rates</b>, not from | |
| the model learning to predict the future. What the lever measures is the rate at which | |
| unforgeable signal accumulates — not forecasting skill. | |
| <br/><br/> | |
| No live model runs in this Space. Every number, the curve and the table are verbatim | |
| outputs of the original experimental run, bundled into <code>data.json</code>. Full code, | |
| raw per-schedule results and methodology: | |
| <a id="repo-link" href="https://github.com/SergheiBrinza/thin-channel" target="_blank" rel="noopener">github.com/SergheiBrinza/thin-channel</a>. | |
| </div> | |
| <div class="attrib" id="attrib"> | |
| Dataset: ForecastBench (Karger, Bastani, Yueh-Han, Jacobs, Halawi, Zhang & Tetlock, | |
| <i>ForecastBench: A Dynamic Benchmark of AI Forecasting Capabilities</i>, ICLR 2025, | |
| arXiv:2409.19839), licensed CC BY-SA 4.0 — source: | |
| <a href="https://huggingface.co/datasets/forecastingresearch/forecastbench-datasets" target="_blank" rel="noopener">forecastingresearch/forecastbench-datasets</a>. | |
| No raw market questions or per-question outcomes are redistributed here — only aggregate | |
| Brier results. Demo code: MIT. | |
| </div> | |
| </footer> | |
| </main> | |
| <script> | |
| const COL={bg:'#000000',card:'#0A0A0A',border:'#1F1F1F',borderS:'#2A2A2A', | |
| text:'#FFFFFF',mute:'#A8A8A8',dim:'#6B6B6B',gold:'#D4AF37',red:'#FF2A2A',green:'#1FD160'}; | |
| const f3=v=>v.toFixed(3); | |
| const signed=v=>(v>0?'+':v<0?'−':'')+Math.abs(v).toFixed(3); | |
| const signed4=v=>(v>0?'+':v<0?'−':'')+Math.abs(v).toFixed(4); | |
| let S=[], NAMES=[], FINAL=[], BASE=[], RAW=[], REVEAL=[], FLOOR=0, CORR_MIN=0, CORR_MAX=0, cur=0; | |
| const PLOT_MARGIN={l:54,r:18,t:14,b:30}; | |
| fetch('data.json').then(r=>r.json()).then(D=>{ | |
| const meta=D.meta||{}; | |
| S=D.schedules; | |
| NAMES=S.map(s=>s.name); | |
| FINAL=S.map(s=>s.holdout_brier_final); | |
| BASE=S.map(s=>s.holdout_brier_base_only); | |
| RAW=S.map(s=>s.holdout_brier_raw); | |
| REVEAL=S.map(s=>Math.round(s.total_revealed)); | |
| const finite=S.filter(s=>s.period_days!==null); | |
| CORR_MIN=Math.min(...finite.map(s=>s.holdout_brier_final)); | |
| CORR_MAX=Math.max(...finite.map(s=>s.holdout_brier_final)); | |
| FLOOR=Math.min(...finite.map(s=>s.holdout_brier_base_only)); | |
| // header / badges / about — all driven by data | |
| document.getElementById('author').textContent=meta.author||'—'; | |
| document.getElementById('m-dataset').textContent=meta.dataset_short||'ForecastBench'; | |
| document.getElementById('m-holdout').textContent='N = '+(meta.n_holdout||330); | |
| const corrTxt=f3(CORR_MIN)+'–'+f3(CORR_MAX); | |
| document.getElementById('b-corridor').textContent=corrTxt; | |
| document.getElementById('t-corridor').textContent=corrTxt; | |
| const neverV=S.find(s=>s.period_days===null).holdout_brier_final; | |
| document.getElementById('b-never').textContent=f3(neverV); | |
| document.getElementById('t-never').textContent=f3(neverV); | |
| const repo=meta.repo||'https://github.com/SergheiBrinza/thin-channel'; | |
| const rl=document.getElementById('repo-link'); rl.href=repo; | |
| rl.textContent=repo.replace(/^https?:\/\//,''); | |
| const abl=D.ablations||{}; | |
| document.getElementById('abl-a').textContent=f3(abl.brier_a_raw); | |
| document.getElementById('abl-b').textContent=f3(abl.brier_b_base_only); | |
| document.getElementById('abl-c').textContent=f3(abl.brier_c_mix); | |
| document.getElementById('abl-d').textContent=signed4(abl.delta_c_vs_b); | |
| if(D.wide_baseline_overall&&typeof D.wide_baseline_overall.brier==='number'){ | |
| const tw=document.getElementById('t-wide'); if(tw) tw.textContent=f3(D.wide_baseline_overall.brier); | |
| } | |
| buildTicks(); | |
| buildTable(); | |
| drawChart(); | |
| // optional deep-link / screenshot preset: ?i=10 | |
| const q=new URLSearchParams(location.search); | |
| const i=parseInt(q.get('i'),10); | |
| const start=(Number.isFinite(i)&&i>=0&&i<=10)?i:0; | |
| document.getElementById('slider').value=start; | |
| document.getElementById('slider').addEventListener('input',e=>setPos(+e.target.value)); | |
| setPos(start); | |
| }).catch(err=>{ | |
| console.error('thin-channel: could not load data.json —', err); | |
| const ex=document.querySelector('.exhibit'); | |
| if(ex){ | |
| const b=document.createElement('div'); | |
| b.style.cssText='border:1px solid rgba(255,42,42,.5);background:rgba(255,42,42,.06);'+ | |
| 'color:#FF2A2A;font-family:var(--mono);font-size:12px;letter-spacing:.04em;'+ | |
| 'padding:14px 16px;border-radius:10px;margin:4px 0 16px 0;line-height:1.5;'; | |
| b.textContent='Data unavailable — could not load data.json ('+err+'). '+ | |
| 'This static demo needs data.json served alongside the page.'; | |
| ex.insertBefore(b,ex.firstChild); | |
| } | |
| }); | |
| function buildTicks(){ | |
| const T=document.getElementById('ticks'), L=document.getElementById('ticklabels'); | |
| T.innerHTML=''; L.innerHTML=''; | |
| NAMES.forEach((nm,i)=>{ | |
| const pct=i/10*100; | |
| const t=document.createElement('div'); t.className='tick'; t.dataset.i=i; | |
| t.style.left=pct+'%'; T.appendChild(t); | |
| const l=document.createElement('div'); l.className='tlabel'+(nm==='never'?' never':''); | |
| l.dataset.i=i; l.textContent=nm; | |
| l.style.left=pct+'%'; | |
| if(i===0){l.style.transform='translateX(0)';l.style.textAlign='left';} | |
| else if(i===NAMES.length-1){l.style.transform='translateX(-100%)';l.style.textAlign='right';} | |
| else{l.style.transform='translateX(-50%)';} | |
| l.addEventListener('click',()=>{document.getElementById('slider').value=i;setPos(i);}); | |
| L.appendChild(l); | |
| }); | |
| } | |
| function buildTable(){ | |
| const tb=document.getElementById('tbody'); tb.innerHTML=''; | |
| S.forEach((s,i)=>{ | |
| const tr=document.createElement('tr'); | |
| tr.className=(s.period_days===null?'never-row':'')+ (i===cur?' active':''); | |
| tr.dataset.i=i; | |
| const period=s.period_days===null?'∞':s.period_days+'d'; | |
| tr.innerHTML='<td class="td-name">'+s.name+'</td>'+ | |
| '<td class="td-mute">'+period+'</td>'+ | |
| '<td class="td-mute">'+Math.round(s.total_revealed)+'</td>'+ | |
| '<td class="td-c">'+f3(s.holdout_brier_final)+'</td>'+ | |
| '<td class="td-b">'+f3(s.holdout_brier_base_only)+'</td>'+ | |
| '<td class="td-a">'+f3(s.holdout_brier_raw)+'</td>'; | |
| tr.addEventListener('click',()=>{document.getElementById('slider').value=i;setPos(i);}); | |
| tb.appendChild(tr); | |
| }); | |
| } | |
| const X=[...Array(11).keys()]; | |
| function drawChart(){ | |
| const axisFont={family:"'JetBrains Mono',monospace",size:11,color:COL.mute}; | |
| const traces=[ | |
| // corridor band edges drawn via shapes; lines below | |
| {x:X,y:RAW,name:'(a) raw 3B',mode:'lines',line:{color:COL.red,width:1.6,dash:'dash',shape:'spline'}, | |
| opacity:.55,hovertemplate:'(a) raw 3B<br>%{y:.3f}<extra></extra>'}, | |
| {x:X,y:BASE,name:'(b) base rate',mode:'lines+markers',line:{color:COL.gold,width:2,shape:'spline'}, | |
| marker:{size:5,color:COL.gold},hovertemplate:'(b) base rate<br>%{y:.3f}<extra></extra>'}, | |
| {x:X,y:FINAL,name:'(c) mix (ours)',mode:'lines+markers',line:{color:COL.green,width:3,shape:'spline'}, | |
| marker:{size:6,color:COL.green},hovertemplate:'(c) mix<br>%{y:.3f}<extra></extra>'}, | |
| // moving highlight point | |
| {x:[0],y:[FINAL[0]],name:'',mode:'markers',showlegend:false,hoverinfo:'skip', | |
| marker:{size:18,color:COL.green,line:{color:'#fff',width:2.5}}} | |
| ]; | |
| const layout=baseLayout(); | |
| Plotly.newPlot('chart',traces,layout,{displayModeBar:false,responsive:true}); | |
| } | |
| function baseLayout(){ | |
| return { | |
| paper_bgcolor:COL.card, plot_bgcolor:COL.card, | |
| margin:PLOT_MARGIN, height:430, | |
| font:{family:"'JetBrains Mono',monospace",color:COL.mute}, | |
| showlegend:true, | |
| legend:{orientation:'h',y:1.12,x:0,font:{size:11,color:COL.mute},bgcolor:'rgba(0,0,0,0)'}, | |
| hoverlabel:{bgcolor:'#141414',bordercolor:COL.borderS,font:{family:"'JetBrains Mono',monospace",color:COL.text,size:12}}, | |
| xaxis:{tickmode:'array',tickvals:X,ticktext:NAMES,tickangle:-35, | |
| tickfont:{family:"'JetBrains Mono',monospace",size:9.5,color:COL.dim}, | |
| gridcolor:COL.border,zeroline:false,range:[-0.4,10.4],fixedrange:true}, | |
| yaxis:{title:{text:'Brier (lower = better)',font:{size:11,color:COL.mute}}, | |
| tickfont:{family:"'JetBrains Mono',monospace",size:10,color:COL.dim}, | |
| gridcolor:COL.border,zeroline:false,range:[0.196,0.312],fixedrange:true}, | |
| shapes:shapesFor(cur), | |
| annotations:annotationsFor(cur) | |
| }; | |
| } | |
| function shapesFor(i){ | |
| const isNever=(S[i]&&S[i].period_days===null); | |
| return [ | |
| // corridor band 0.205–0.220 | |
| {type:'rect',xref:'paper',x0:0,x1:1,yref:'y',y0:CORR_MIN,y1:CORR_MAX, | |
| fillcolor:'rgba(31,209,96,0.06)',line:{width:0},layer:'below'}, | |
| // base-only floor reference line | |
| {type:'line',xref:'paper',x0:0,x1:1,yref:'y',y0:FLOOR,y1:FLOOR, | |
| line:{color:COL.gold,width:1,dash:'dot'},layer:'below'}, | |
| // vertical guide connecting the lever to the point | |
| {type:'line',xref:'x',x0:i,x1:i,yref:'paper',y0:0,y1:1, | |
| line:{color:isNever?'rgba(255,42,42,0.5)':'rgba(255,255,255,0.16)',width:1},layer:'below'} | |
| ]; | |
| } | |
| function annotationsFor(i){ | |
| const a=[{ | |
| xref:'paper',yref:'y',x:0.012,y:FLOOR,xanchor:'left',yanchor:'bottom', | |
| text:'base-only floor ≈ '+FLOOR.toFixed(2),showarrow:false, | |
| font:{family:"'JetBrains Mono',monospace",size:9.5,color:COL.gold} | |
| }]; | |
| if(S[i]&&S[i].period_days===null){ | |
| a.push({xref:'x',yref:'y',x:10,y:FINAL[10],ax:-46,ay:0,axref:'pixel',ayref:'pixel', | |
| text:'collapse',showarrow:true,arrowhead:2,arrowcolor:COL.red,arrowwidth:1.4, | |
| font:{family:"'JetBrains Mono',monospace",size:11,color:COL.red}, | |
| xanchor:'right',yanchor:'middle'}); | |
| } | |
| return a; | |
| } | |
| function setPos(i){ | |
| cur=i; | |
| const s=S[i], isNever=(s.period_days===null); | |
| // chart: move highlight point, color, guide line, collapse annotation | |
| Plotly.restyle('chart',{x:[[i]],y:[[FINAL[i]]],'marker.color':isNever?COL.red:COL.green},[3]); | |
| Plotly.relayout('chart',{shapes:shapesFor(i),annotations:annotationsFor(i)}); | |
| // readout | |
| const ro=document.getElementById('readout'); | |
| ro.classList.toggle('collapsed',isNever); | |
| document.getElementById('ro-name').textContent=s.name; | |
| document.getElementById('ro-period').textContent = | |
| (isNever?'no reveals · 0 outcomes seen' | |
| :'every '+s.period_days+' day'+(s.period_days===1?'':'s')+' · '+REVEAL[i]+' outcomes seen'); | |
| document.getElementById('ro-brier').textContent=f3(FINAL[i]); | |
| document.getElementById('ro-b').textContent=f3(BASE[i]); | |
| document.getElementById('ro-a').textContent=f3(RAW[i]); | |
| const delta=FINAL[i]-RAW[i]; | |
| const dEl=document.getElementById('ro-delta'); | |
| dEl.textContent = delta<-0.0005 ? signed(delta)+' Brier' : '0.000 — none'; | |
| dEl.className='rv '+(delta<-0.0005?'green':'red'); | |
| // slider thumb tint | |
| const sl=document.getElementById('slider'); | |
| sl.classList.toggle('at-never',isNever); | |
| sl.setAttribute('aria-valuetext', s.name+' — Brier '+f3(FINAL[i])); | |
| // ticks + labels active state | |
| document.querySelectorAll('.tick').forEach(t=>t.classList.toggle('on',+t.dataset.i===i)); | |
| document.querySelectorAll('.tlabel').forEach(l=>l.classList.toggle('on',+l.dataset.i===i)); | |
| // table active row | |
| document.querySelectorAll('#tbody tr').forEach(tr=>tr.classList.toggle('active',+tr.dataset.i===i)); | |
| } | |
| </script> | |
| </body> | |
| </html> | |