openvibers/openvibe.bench Commits
Bench B2: the results pages (benchmarks, runs, compare, models, value chart) (#27)
Changes
@@@ -61,3 +61,193 @@ html, body { margin: 0; background: var(--bg-primary, #0a0f1c); color: var(--tex.bm-kind-link:hover { text-decoration: underline; }.bm-kind-link:focus-visible { outline: 2px solid var(--room-accent); outline-offset: 2px; border-radius: 4px; }.bm-kind-meta { font-size: .82rem; color: var(--text-muted, #7386a3); }++++/* ---- Results pages (B2): benchmarks, a benchmark, a run, compare, a model. Classes start with br-. ---------- */++.br-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }++.br-mono, .br-mono-h { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }++.br-mono-h { font-size: clamp(1.5rem, 4.4vw, 2.4rem) !important; letter-spacing: -.01em !important; }++.br-fine { color: var(--text-muted, #7386a3); font-size: .86rem; line-height: 1.5; margin: 0; }++.br-chip { display: inline-flex; align-items: center; padding: 2px 9px; border-radius: 999px; font-size: .76rem; font-weight: 700; background: color-mix(in srgb, var(--room-accent) 14%, transparent); color: var(--room-strong); white-space: nowrap; }++.br-crumbs { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding-top: clamp(16px, 3vw, 28px); font-size: .86rem; color: var(--text-muted, #7386a3); min-width: 0; }++.br-crumbs a { color: var(--text-secondary, #96a7c2); text-decoration: none; }++.br-crumbs a:hover { color: var(--room-strong); }++.br-crumbs > span:last-child { color: var(--text-primary, #e6edf7); overflow-wrap: anywhere; }++++/* The page head: the title on the left, the action (or the score) on the right, stacked on phones */++.br-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 18px 32px; padding: 14px 0 4px; }++.br-head-main { flex: 1 1 420px; min-width: 0; }++.br-head-main h1 { margin: 6px 0 0; font-size: clamp(1.8rem, 5vw, 2.9rem); font-weight: 800; letter-spacing: -.03em; line-height: 1.06; overflow-wrap: anywhere; text-wrap: balance; }++.br-head-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin: 0; color: var(--text-muted, #7386a3); font-size: .86rem; }++.br-head-meta a { color: var(--room-strong); }++.br-head-act { flex: 0 1 300px; display: grid; gap: 8px; justify-items: start; }++++/* Facts, environment and totals: label over value, in a wrapping grid */++.br-facts, .br-env, .br-totals { display: grid; gap: 10px; margin: 22px 0 0; }++.br-facts { grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr)); }++.br-env { grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); margin-top: 12px; }++.br-facts > div, .br-env > div { padding: 12px 14px; border-radius: 14px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); min-width: 0; }++.br-facts dt, .br-env dt, .br-totals dt { font-size: .7rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted, #7386a3); }++.br-facts dd, .br-env dd, .br-totals dd { margin: 4px 0 0; font-weight: 650; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }++.br-env dd a { color: var(--room-strong); }++.br-totals { grid-template-columns: repeat(3, auto); justify-content: start; gap: 4px 22px; margin-top: 12px; }++++/* A score out of 100, its thin bar under it */++.br-score { display: inline-flex; flex-wrap: wrap; align-items: baseline; column-gap: 2px; min-width: 92px; font-variant-numeric: tabular-nums; }++.br-score-n { font-weight: 800; font-size: 1rem; }++.br-score-of { font-size: .74rem; color: var(--text-muted, #7386a3); }++.br-bar { flex: 0 0 100%; display: block; height: 4px; margin-top: 4px; border-radius: 999px; background: color-mix(in srgb, var(--text-muted, #7386a3) 22%, transparent); overflow: hidden; }++.br-bar > span { display: block; height: 100%; border-radius: inherit; background: var(--room-accent); }++.br-score.is-big { min-width: 200px; }++.br-score.is-big .br-score-n { font-size: clamp(3rem, 9vw, 4.4rem); line-height: .95; letter-spacing: -.04em; }++.br-score.is-big .br-score-of { font-size: 1rem; }++.br-score.is-big .br-bar { height: 6px; margin-top: 10px; }++.br-head-score { flex: 0 1 auto; }++++/* Verified / submitted */++.br-prov { display: inline-flex; align-items: center; gap: 5px; padding: 2px 9px; border-radius: 999px; font-size: .74rem; font-weight: 750; white-space: nowrap; }++.br-prov.is-verified { background: color-mix(in srgb, var(--success, #22c55e) 15%, transparent); color: var(--success, #22c55e); }++.br-prov.is-verified::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }++.br-prov.is-submitted { border: 1px solid var(--border, #1f2d47); color: var(--text-muted, #7386a3); }++++/* Rank-by tabs: links, so every metric has its own URL */++.br-tabs { display: flex; flex-wrap: wrap; gap: 4px; padding: 3px; border-radius: 999px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); }++.br-tab { display: inline-flex; align-items: center; min-height: 34px; padding: 0 13px; border-radius: 999px; font-size: .86rem; font-weight: 700; color: var(--text-secondary, #96a7c2) !important; text-decoration: none; }++.br-tab:hover { color: var(--text-primary, #e6edf7) !important; }++.br-tab[aria-current="page"] { background: var(--room-fill); color: var(--room-on) !important; }++.br-tab:focus-visible, .br-filter:focus-visible { outline: 2px solid var(--room-accent); outline-offset: 2px; }++++/* The value chart */++.br-chart { margin: 4px 0 16px; padding: 14px 14px 10px; border-radius: 18px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); }++.br-chart svg { display: block; width: 100%; height: auto; overflow: visible; }++.br-chart figcaption { margin-top: 6px; font-size: .82rem; color: var(--text-muted, #7386a3); }++.br-grid { stroke: var(--border, #1f2d47); stroke-width: 1; }++.br-axis { fill: var(--text-muted, #7386a3); font-size: 11px; font-variant-numeric: tabular-nums; }++.br-chart-empty { fill: var(--text-secondary, #96a7c2); font-size: 14px; font-weight: 600; }++.br-front { fill: none; stroke: var(--room-accent); stroke-width: 2; stroke-dasharray: 5 4; opacity: .8; }++.br-dot circle { fill: var(--bg-card, #0f1729); stroke: var(--text-secondary, #96a7c2); stroke-width: 2; }++.br-dot text { fill: var(--text-secondary, #96a7c2); font-size: 12px; font-weight: 600; paint-order: stroke; stroke: var(--bg-card, #0f1729); stroke-width: 4px; stroke-linejoin: round; }++.br-dot.is-front circle { fill: var(--room-accent); stroke: var(--room-accent); }++.br-dot.is-front text { fill: var(--text-primary, #e6edf7); font-weight: 750; }++++/* Tables: scroll inside their own box on phones, never the page */++.br-table-wrap { overflow-x: auto; border: 1px solid var(--border, #1f2d47); border-radius: 16px; background: var(--bg-card, #0f1729); }++.br-table { width: 100%; border-collapse: collapse; font-size: .92rem; }++.br-table th, .br-table td { padding: 11px 14px; text-align: left; border-bottom: 1px solid var(--border, #1f2d47); vertical-align: middle; }++.br-table tbody tr:last-child > * { border-bottom: 0; }++.br-table thead th { font-size: .7rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted, #7386a3); white-space: nowrap; }++.br-table tbody th { font-weight: 650; color: var(--text-secondary, #96a7c2); white-space: nowrap; }++.br-num { text-align: right !important; font-variant-numeric: tabular-nums; white-space: nowrap; }++.br-rank { width: 2.5em; color: var(--text-muted, #7386a3); font-variant-numeric: tabular-nums; }++.br-model { font-weight: 750; color: var(--text-primary, #e6edf7) !important; text-decoration: none; overflow-wrap: anywhere; }++.br-model:hover { color: var(--room-strong) !important; }++.br-table td.is-best { color: var(--room-strong); font-weight: 800; }++.br-table a { color: var(--room-strong); }++++/* Run lists */++.br-runs { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }++.br-run { display: flex; align-items: center; gap: 10px; padding: 4px 12px 4px 4px; border-radius: 14px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); min-width: 0; }++.br-run:hover { border-color: color-mix(in srgb, var(--room-accent) 55%, var(--border, #1f2d47)); }++.br-run-link { flex: 1; display: flex; align-items: center; justify-content: space-between; gap: 14px; min-height: 52px; padding: 6px 10px; color: inherit !important; text-decoration: none; min-width: 0; }++.br-run-main { display: grid; gap: 2px; min-width: 0; }++.br-run-model { font-weight: 750; overflow-wrap: anywhere; }++.br-run-sub { font-size: .82rem; color: var(--text-muted, #7386a3); overflow-wrap: anywhere; }++++/* Tasks */++.br-tasks, .br-ptasks { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }++.br-task { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 12px; align-items: start; padding: 14px; border-radius: 14px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); }++.br-task p { margin: 0; line-height: 1.55; color: var(--text-secondary, #96a7c2); }++.br-task.is-hidden { border-style: dashed; background: transparent; }++.br-task-id { display: inline-flex; padding: 2px 8px; border-radius: 8px; background: var(--bg-hover, rgba(255,255,255,.05)); font-size: .78rem; font-weight: 700; color: var(--text-primary, #e6edf7); white-space: nowrap; margin: 0; }++.br-ptask { display: grid; gap: 10px; padding: 14px; border-radius: 16px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); min-width: 0; }++.br-ptask-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; }++.br-ptask-meta { margin-left: auto; font-size: .84rem; color: var(--text-muted, #7386a3); font-variant-numeric: tabular-nums; }++.br-ptask-prompt { margin: 0; color: var(--text-secondary, #96a7c2); line-height: 1.55; }++++/* Outputs: live frames from the render origin */++.br-outs { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }++.br-out { margin: 0; display: grid; gap: 6px; min-width: 0; }++.br-out-frame, .br-out-img { width: 100%; max-width: 100%; aspect-ratio: 4 / 3; border: 1px solid var(--border, #1f2d47); border-radius: 12px; background: #fff; display: block; }++.br-out-img { object-fit: contain; background: var(--bg-primary, #0a0f1c); }++.br-out figcaption { font-size: .76rem; color: var(--text-muted, #7386a3); }++.br-out-link { font-size: .86rem; overflow-wrap: anywhere; color: var(--room-strong); }++++/* Where a run sits among its model's runs */++.br-pct { display: grid; gap: 8px; margin-top: 18px; padding: 14px 16px; border-radius: 16px; background: color-mix(in srgb, var(--room-accent) 8%, var(--bg-card, #0f1729)); border: 1px solid color-mix(in srgb, var(--room-accent) 24%, transparent); }++.br-pct p { margin: 0; line-height: 1.5; }++.br-pct-strip { position: relative; height: 8px; border-radius: 999px; background: linear-gradient(90deg, color-mix(in srgb, var(--text-muted, #7386a3) 25%, transparent), color-mix(in srgb, var(--room-accent) 45%, transparent)); }++.br-pct-strip > span { position: absolute; top: 50%; width: 16px; height: 16px; margin: -8px 0 0 -8px; border-radius: 50%; background: var(--room-accent); border: 3px solid var(--bg-card, #0f1729); }++++/* Benchmark cards */++.br-cards { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); }++.br-card { min-width: 0; }++.br-card-link { height: 100%; display: grid; align-content: start; gap: 8px; padding: 16px; border-radius: 18px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); color: inherit !important; text-decoration: none; transition: border-color .18s ease, transform .18s ease; }++.br-card-link:hover { border-color: color-mix(in srgb, var(--room-accent) 60%, var(--border, #1f2d47)); transform: translateY(-1px); }++.br-card-link:focus-visible { outline: 2px solid var(--room-accent); outline-offset: 2px; }++.br-card-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }++.br-card-v { font-size: .76rem; color: var(--text-muted, #7386a3); font-variant-numeric: tabular-nums; }++.br-card-title { font-size: 1.08rem; font-weight: 800; letter-spacing: -.01em; }++.br-card-desc { color: var(--text-secondary, #96a7c2); font-size: .9rem; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }++.br-card-foot { font-size: .8rem; color: var(--text-muted, #7386a3); }++@media (prefers-reduced-motion: reduce) { .br-card-link { transition: none; } .br-card-link:hover { transform: none; } }++++/* Search and filters */++.br-search { display: flex; gap: 8px; max-width: 560px; }++.br-search input { flex: 1; min-width: 0; min-height: 44px; padding: 0 14px; border-radius: 999px; border: 1px solid var(--border, #1f2d47); background: var(--bg-input, var(--bg-card, #0f1729)); color: var(--text-primary, #e6edf7); font: inherit; }++.br-search input:focus-visible { outline: 2px solid var(--room-accent); outline-offset: 1px; }++.br-search .bm-btn { min-height: 44px; }++.br-filters { display: flex; flex-wrap: wrap; gap: 6px; margin: 14px 0 18px; }++.br-filter { display: inline-flex; align-items: center; min-height: 36px; padding: 0 14px; border-radius: 999px; border: 1px solid var(--border, #1f2d47); color: var(--text-secondary, #96a7c2) !important; text-decoration: none; font-size: .88rem; font-weight: 650; text-transform: capitalize; }++.br-filter[aria-current="page"] { background: var(--room-fill); border-color: transparent; color: var(--room-on) !important; }++++/* Empty states: one line of what, one line of why, one way forward */++.br-empty { display: grid; justify-items: start; gap: 6px; padding: 18px; border-radius: 16px; border: 1px dashed var(--border, #1f2d47); color: var(--text-secondary, #96a7c2); }++.br-empty p { margin: 0; line-height: 1.5; }++.br-empty-t { font-weight: 750; color: var(--text-primary, #e6edf7); }++.br-api { margin-top: 28px; }++.br-again .bm-actions { margin-top: 10px; }++++/* Compare */++.br-cmp thead th { text-transform: none; letter-spacing: 0; font-size: .92rem; color: var(--text-primary, #e6edf7); vertical-align: top; }++.br-cmp thead th a { font-weight: 800; }++.br-cmp-sub { display: block; margin: 2px 0 6px; font-size: .78rem; font-weight: 500; color: var(--text-muted, #7386a3); }++.br-cmp-row { display: grid; gap: 8px; margin-top: 14px; }++.br-cmp-outs { display: grid; gap: 10px; grid-template-columns: repeat(var(--n, 2), minmax(0, 1fr)); }++.br-cmp-out { min-width: 0; }++@media (max-width: 720px) { .br-cmp-outs { grid-template-columns: minmax(0, 1fr); } }++++/* ---- The showcase: two models, one prompt, live frames side by side. Classes start with sc-. ---------------- */++.sc-showcase { max-width: 1180px; margin: 0 auto; padding: clamp(20px, 4vw, 40px) 16px 64px; }++.sc-showcase > h1 { margin: 0; font-size: clamp(1.8rem, 5vw, 2.8rem); font-weight: 800; letter-spacing: -.03em; line-height: 1.08; text-wrap: balance; }++.sc-lede { margin: 10px 0 24px; max-width: 680px; color: var(--text-secondary, #96a7c2); line-height: 1.55; }++.sc-pairs { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 520px), 1fr)); }++.sc-pair { display: grid; gap: 12px; padding: 14px; border-radius: 20px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); min-width: 0; }++.sc-pair-prompt { margin: 0; font-size: .98rem; font-weight: 650; line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }++.sc-pair-slots, .sc-round-panes { display: grid; gap: 10px; grid-template-columns: repeat(2, minmax(0, 1fr)); }++.sc-round-panes { gap: 14px; margin-top: 16px; }++@media (max-width: 560px) { .sc-pair-slots, .sc-round-panes { grid-template-columns: minmax(0, 1fr); } }++.sc-pane { margin: 0; display: grid; gap: 6px; min-width: 0; }++.sc-pane figcaption { display: flex; justify-content: space-between; align-items: center; font-size: .78rem; font-weight: 700; color: var(--text-muted, #7386a3); }++.sc-pane-label { letter-spacing: .04em; text-transform: uppercase; }++.sc-pane-clock { font-variant-numeric: tabular-nums; }++.sc-pane-frame { width: 100%; max-width: 100%; aspect-ratio: 4 / 3; border: 1px solid var(--border, #1f2d47); border-radius: 12px; background: #fff; display: block; }++.sc-round .sc-pane-frame { aspect-ratio: 16 / 11; }++.sc-pane-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(90px, 1fr)); gap: 6px; margin: 4px 0 0; font-size: .82rem; }++.sc-pane-facts dt { color: var(--text-muted, #7386a3); font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 800; }++.sc-pane-facts dd { margin: 2px 0 0; font-weight: 650; overflow-wrap: anywhere; }++.sc-pair-meta, .sc-round-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin: 0; font-size: .86rem; color: var(--text-muted, #7386a3); }++.sc-round-meta { margin-top: 10px; }++.sc-kind { padding: 2px 10px; border-radius: 999px; background: color-mix(in srgb, var(--room-accent) 14%, transparent); color: var(--room-strong); font-weight: 700; }++.sc-votes { font-variant-numeric: tabular-nums; }++.sc-pair-link { margin-left: auto; font-weight: 750; color: var(--room-strong) !important; text-decoration: none; }++.sc-pair-link:hover { text-decoration: underline; }++.sc-round-prompt { font-size: clamp(1.3rem, 3.6vw, 2rem) !important; line-height: 1.25 !important; letter-spacing: -.015em !important; }++.sc-vote { margin-top: 18px; padding: 16px; border-radius: 18px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); display: grid; gap: 12px; }++.sc-vote p { margin: 0; }++.sc-vote fieldset { margin: 0; padding: 0; border: 0; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }++.sc-vote legend { width: 100%; margin-bottom: 8px; font-weight: 800; }++.sc-vote label { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 16px; border-radius: 999px; border: 1px solid var(--border, #1f2d47); cursor: pointer; font-weight: 650; }++.sc-vote label:has(input:checked) { border-color: var(--room-accent); background: color-mix(in srgb, var(--room-accent) 14%, transparent); }++.sc-vote input[type="radio"], .sc-vote input[type="checkbox"] { accent-color: var(--room-accent); }++.sc-vote button { justify-self: start; min-height: 44px; padding: 0 20px; border: 0; border-radius: 999px; background: var(--room-fill); color: var(--room-on); font: inherit; font-weight: 750; cursor: pointer; }++.sc-vote a { color: var(--room-strong); font-weight: 700; }++.sc-empty { color: var(--text-muted, #7386a3); }@@@ -320,9 +320,16 @@ function createRegistry(s, { log = console } = {}) {}/** The registry list: by kind, by tag, or by a search over the title and the description. */-- async function listBenchmarks({ kind = null, tag = null, q = null, limit = 50 } = {}) {++ /**++ * Benchmarks for a listing: the public ones, plus every one the `owner` owns when one is named. Unlisted and++ * private benchmarks are never listed to anyone else (an unlisted one is reachable by its id; a private one only++ * by its owner and the executor).++ */++ async function listBenchmarks({ kind = null, tag = null, q = null, limit = 50, owner = null } = {}) {const where = [];const params = [];++ if (owner) { params.push(String(owner)); where.push(`(visibility = 'public' OR owner = $${params.length})`); }++ else where.push("visibility = 'public'");if (kind) { params.push(String(kind)); where.push(`kind = $${params.length}`); }if (tag) { params.push(JSON.stringify([String(tag)])); where.push(`tags @> $${params.length}::jsonb`); }if (q) {@@@ -456,8 +463,9 @@ function createRegistry(s, { log = console } = {}) {const params = [ref.id, wanted];let sql = `SELECT * FROM bench_runs WHERE benchmark_id = $1 AND benchmark_version = ANY($2::int[])`;if (!includeSubmitted) sql += " AND provenance = 'verified'";-- if (harness) { params.push(JSON.stringify([String(harness)])); sql += ` AND harness->>'name' = $3`; }-- if (since) { params.push(String(since)); sql += ' AND created_at >= $4::timestamptz'; }++ // Each filter takes the next placeholder: `since` alone is $3, not $4.++ if (harness) { params.push(String(harness)); sql += ` AND harness->>'name' = $${params.length}`; }++ if (since) { params.push(String(since)); sql += ` AND created_at >= $${params.length}::timestamptz`; }const rows = await db.many(sql, params);const byModel = new Map();for (const row of rows) {@@@ -534,9 +542,76 @@ function createRegistry(s, { log = console } = {}) {};}++ /**++ * Runs, newest first, for the pages: a benchmark's latest runs, a model's, or one person's. Without tasks: a list++ * row needs the totals only. Submitted runs are listed (and labelled) unless `verifiedOnly`.++ */++ /** How many runs each benchmark has, verified and submitted: the listing's counts. */++ async function runCounts() {++ const rows = await db.many('SELECT benchmark_id, COUNT(*)::int AS n FROM bench_runs GROUP BY benchmark_id');++ return new Map(rows.map((r) => [r.benchmark_id, num(r.n)]));++ }++++ async function listRuns({ benchmark = null, model = null, createdBy = null, verifiedOnly = false, publicOnly = false, limit = 20 } = {}) {++ const where = [];++ const params = [];++ const add = (clause, value) => { params.push(value); where.push(clause.replace('?', `$${params.length}`)); };++ if (benchmark) {++ const ref = parseRef(benchmark);++ if (!ref) return [];++ add('benchmark_id = ?', ref.id);++ if (ref.version != null) add('benchmark_version = ?', ref.version);++ }++ if (model) add('model = ?', String(model));++ if (createdBy) add('created_by = ?', String(createdBy));++ if (verifiedOnly) where.push("provenance = 'verified'");++ // A listing across benchmarks (a model's page) shows the public benchmarks' runs only.++ if (publicOnly) where.push("benchmark_id IN (SELECT id FROM bench_benchmarks WHERE visibility = 'public')");++ params.push(Math.min(100, Math.max(1, Number(limit) || 20)));++ const rows = await db.many(++ `SELECT * FROM bench_runs ${where.length ? `WHERE ${where.join(' AND ')}` : ''} ORDER BY created_at DESC, id DESC LIMIT $${params.length}`,++ params);++ return rows.map((row) => wireRun(row));++ }++++ /**++ * One model across every public benchmark it ran: per benchmark, its verified runs, the median score, cost and time, and++ * the spread between its best and worst run. The model page reads this.++ */++ async function modelSummary(model) {++ const rows = await db.many(++ "SELECT benchmark_id, score, cost_usd, ms FROM bench_runs WHERE model = $1 AND provenance = 'verified'"++ + " AND benchmark_id IN (SELECT id FROM bench_benchmarks WHERE visibility = 'public')",++ [String(model || '')]);++ const byBenchmark = new Map();++ for (const row of rows) {++ if (!byBenchmark.has(row.benchmark_id)) byBenchmark.set(row.benchmark_id, []);++ byBenchmark.get(row.benchmark_id).push(row);++ }++ const round = (v, p) => (v == null ? null : Math.round(v * p) / p);++ const out = [];++ for (const [benchmarkId, list] of byBenchmark) {++ const scores = list.map((r) => num(r.score));++ const b = await getBenchmark(benchmarkId);++ out.push({++ benchmark_id: benchmarkId,++ title: b ? b.title : benchmarkId,++ kind: b ? b.kind : null,++ runs: list.length,++ score: round(median(scores), 1000),++ best: Math.max(...scores),++ worst: Math.min(...scores),++ cost_usd: round(median(list.map((r) => num(r.cost_usd))), 1e6),++ ms: round(median(list.map((r) => num(r.ms))), 1),++ });++ }++ out.sort((a, b) => b.runs - a.runs || a.title.localeCompare(b.title));++ return { model: String(model || ''), runs: rows.length, benchmarks: out };++ }++return {createBenchmark, getBenchmark, getVersion, latestVersion, getDefinition, saveDraft, freezeVersion,-- forkBenchmark, listBenchmarks, publishRun, getRun, compareRuns, rankings, percentile,++ forkBenchmark, listBenchmarks, publishRun, getRun, compareRuns, rankings, percentile, listRuns, modelSummary, runCounts,};}@@@ -25,6 +25,8 @@ function load(env = process.env) {nodeEnv,isProduction,baseUrl,++ // "Run it yourself" on a benchmark page opens this openvibe.codes page (stage B3); unset, the page offers the API.++ codesRunUrl: env.CODES_BENCH_RUN_URL ? trim(env.CODES_BENCH_RUN_URL) : null,trustProxy: env.TRUST_PROXY != null ? Number(env.TRUST_PROXY) : 2,drill: env.BENCH_DRILL === '1' || env.BENCH_DRILL === 'true',limits: {@@@ -11,6 +11,7 @@ const { createDiscoveryRoutes, homeJsonLd } = require('./discovery');const { raw } = require('../render/html');const { send } = require('../render/layout');const views = require('../views');++const results = require('../views/results');const PUBLIC_CACHE = 'public, max-age=60';@@@ -43,22 +44,129 @@ function oneGraph(nodes) {}function createPageRoutes(ctx) {-- const { config, bench } = ctx;++ const { config, bench, registry } = ctx;const r = asyncRouter();const base = () => String(config.baseUrl).replace(/\/+$/, '');const page = (req, res, o, status = 200) => send(res, status, { viewer: req.viewer, config, path: req.originalUrl, ...o });r.get('/', async (req, res) => {const kinds = await bench.listKinds();++ const benchmarks = await registry.listBenchmarks({ limit: 6 });++ const counts = await registry.runCounts();++ for (const b of benchmarks) b.runs = counts.get(b.id) || 0;return page(req, res, {index: true, cache: PUBLIC_CACHE,title: null,-- description: 'OpenVibe.Bench is one AI benchmark and comparison engine for every room: blind votes, rubrics, graders, test suites and game outcomes, with reproducible pinned rounds and an open dataset per kind.',++ description: 'OpenVibe.Bench shows what AI models really make: the same tasks on every model, outputs live side by side, every run published with its cost and time, free and open.',jsonLd: oneGraph([...homeJsonLd(config), ...kinds.map((k) => datasetJsonLd(k, base())), seo.jsonLd.organization()]),-- body: raw(views.home({ kinds, counts: { kinds: kinds.length } })),++ body: raw(views.home({ kinds, counts: { kinds: kinds.length }, benchmarks })),});});++ // ---- the results pages (B2) ----------------------------------------------------------------------------++ const subjectOf = (req) => (req.viewer && req.viewer.kind === 'user' ? (req.viewer.subject || req.viewer.id || null) : null);++ const notFound = (req, res, what) => page(req, res, { title: `No such ${what}`, body: raw(views.notFound()) }, 404);++ const METRIC_IDS = results.METRICS.map((m) => m.id);++++ r.get('/benchmarks', async (req, res) => {++ const q = String(req.query.q || '').slice(0, 80);++ const family = String(req.query.kind || '').replace(/[^a-z0-9._-]/gi, '').slice(0, 40) || null;++ const all = await registry.listBenchmarks({ q: q || null, limit: 200 });++ const kinds = [...new Set(all.map((b) => b.kind).filter(Boolean))];++ const list = family ? all.filter((b) => b.kind === family || String(b.kind).startsWith(`${family}.`)) : all;++ const counts = await registry.runCounts();++ for (const b of list) b.runs = counts.get(b.id) || 0;++ return page(req, res, {++ index: !q && !family, cache: PUBLIC_CACHE,++ title: 'Benchmarks',++ description: 'Versioned AI benchmarks anyone can run again: tasks, judges and limits, with every run published.',++ jsonLd: [seo.jsonLd.webPage({ name: 'Benchmarks', url: `${base()}/benchmarks`, description: 'Versioned AI benchmarks anyone can run again.', siteUrl: base() })],++ body: raw(String(results.benchmarksIndex({ benchmarks: list, kinds, kind: family, q }))),++ });++ });++++ r.get('/benchmarks/:ref', async (req, res) => {++ const ref = String(req.params.ref || '');++ const out = await registry.getDefinition(ref, { reveal: false });++ const subject = subjectOf(req);++ if (!out || (out.benchmark.visibility === 'private' && out.benchmark.owner !== subject)) return notFound(req, res, 'benchmark');++ const metric = METRIC_IDS.includes(String(req.query.metric)) ? String(req.query.metric) : 'score';++ const id = out.benchmark.id;++ const [rankings, runs] = await Promise.all([++ registry.rankings({ benchmark: id, metric }),++ registry.listRuns({ benchmark: id, limit: 8 }),++ ]);++ const isPublic = out.benchmark.visibility === 'public';++ return page(req, res, {++ index: isPublic && metric === 'score', cache: isPublic ? PUBLIC_CACHE : null,++ title: out.benchmark.title,++ description: out.benchmark.description || `${out.benchmark.title}: rankings, value and every run.`,++ jsonLd: [seo.jsonLd.webPage({ name: out.benchmark.title, url: `${base()}/benchmarks/${encodeURIComponent(id)}`, description: out.benchmark.description || out.benchmark.title, siteUrl: base() })],++ body: raw(String(results.benchmarkPage({++ benchmark: out.benchmark, definition: out.definition, version: out.version && out.version.version,++ rankings, metric, runs, codesRunUrl: config.codesRunUrl || null,++ }))),++ });++ });++++ r.get('/runs/:id', async (req, res) => {++ const run = await registry.getRun(String(req.params.id || ''));++ if (!run) return notFound(req, res, 'run');++ const def = await registry.getDefinition(`${run.benchmark_id}@${run.benchmark_version}`, { reveal: false });++ const benchmark = def ? def.benchmark : null;++ if (benchmark && benchmark.visibility === 'private' && benchmark.owner !== subjectOf(req)) return notFound(req, res, 'run');++ const pct = run.score != null ? await registry.percentile({ benchmark: run.benchmark_id, model: run.model, score: run.score }) : null;++ const isPublic = !benchmark || benchmark.visibility === 'public';++ return page(req, res, {++ index: isPublic && run.provenance === 'verified', cache: isPublic ? PUBLIC_CACHE : null,++ title: `${run.model} on ${benchmark ? benchmark.title : run.benchmark_id}`,++ description: `${run.model} scored ${results.fmtScore(run.score)} out of 100 on ${benchmark ? benchmark.title : 'this benchmark'}, for ${results.fmtUsd(run.cost_usd)}.`,++ body: raw(String(results.runPage({ run, benchmark, definition: def && def.definition, pct }))),++ });++ });++++ r.get('/compare', async (req, res) => {++ const refs = String(req.query.runs || '').split(',').map((x) => x.trim()).filter(Boolean).slice(0, 4);++ let cmp = refs.length ? await registry.compareRuns(refs) : null;++ const titles = {};++ if (cmp) {++ const subject = subjectOf(req);++ const keep = [];++ for (const run of cmp.runs) {++ const b = await registry.getBenchmark(run.benchmark_id);++ if (b && b.visibility === 'private' && b.owner !== subject) continue;++ if (b) titles[b.id] = b.title;++ keep.push(run);++ }++ cmp = keep.length ? { ...cmp, runs: keep, rows: cmp.rows.map((row) => ({ ...row, scores: keep.map((run) => { const t = run.tasks.find((x) => x.task_id === row.task_id); return t ? t.score : null; }) })) } : null;++ }++ return page(req, res, {++ index: false, cache: PUBLIC_CACHE,++ title: cmp ? `Compare: ${cmp.runs.map((x) => x.model).join(' vs ')}` : 'Compare runs',++ description: 'Runs side by side: the same tasks, their scores, cost, time and outputs.',++ body: raw(String(results.comparePage({ cmp, titles }))),++ });++ });++++ r.get('/models/:model', async (req, res) => {++ const model = String(req.params.model || '').slice(0, 160);++ const [summary, runs] = await Promise.all([++ registry.modelSummary(model),++ registry.listRuns({ model, publicOnly: true, limit: 12 }),++ ]);++ const titles = {};++ for (const b of summary.benchmarks) titles[b.benchmark_id] = b.title;++ for (const run of runs) {++ if (!titles[run.benchmark_id]) { const b = await registry.getBenchmark(run.benchmark_id); if (b) titles[b.id] = b.title; }++ }++ return page(req, res, {++ index: summary.runs > 0, cache: PUBLIC_CACHE,++ title: model,++ description: `${model} across OpenVibe.Bench: its median score, spread, cost and time on every benchmark it ran.`,++ body: raw(String(results.modelPage({ model, summary, runs, titles }))),++ }, summary.runs > 0 || runs.length ? 200 : 404);++ });++r.get('/docs', (req, res) => page(req, res, {index: true, cache: PUBLIC_CACHE,title: 'The Bench API',@@@ -129,7 +129,10 @@ function createRegistryApi(ctx) {r.get('/benchmarks', async (req, res) => {try {++ // ?mine=1 adds the caller's own unlisted and private benchmarks; nobody else ever sees those in a list.++ const mine = req.query.mine && req.principal && req.principal.kind === 'user' ? req.principal.subject : null;const list = await registry.listBenchmarks({++ owner: mine,kind: req.query.kind ? String(req.query.kind) : null,tag: req.query.tag ? String(req.query.tag) : null,q: req.query.q ? String(req.query.q) : null,@@@ -151,7 +154,9 @@ function createRegistryApi(ctx) {}const out = await registry.getDefinition(ref, { reveal });if (!out) return problem(res, 404, 'bench.benchmark_not_found', 'No such benchmark.');-- res.set('Cache-Control', 'public, max-age=60');++ // A private benchmark answers only its owner and the executor; to everyone else it does not exist.++ if (out.benchmark.visibility === 'private' && !reveal) return problem(res, 404, 'bench.benchmark_not_found', 'No such benchmark.');++ res.set('Cache-Control', out.benchmark.visibility === 'public' ? 'public, max-age=60' : 'private, no-store');return res.json({benchmark: out.benchmark,version: { ...out.version, definition: out.definition },@@@ -28,7 +28,7 @@ function createRenderRoutes(ctx) {function bare(res) {res.removeHeader('Set-Cookie');res.removeHeader('X-Frame-Options'); // helmet's DENY; frame-ancestors in each response's CSP names who may frame it-- res.set('Cache-Control', 'no-store');++ res.set('Cache-Control', 'no-store, no-transform'); // no-transform: Cloudflare injects no analytics beacon (the frame's CSP refuses it)res.set('X-Content-Type-Options', 'nosniff');res.set('Referrer-Policy', 'no-referrer');return res;@@@ -129,7 +129,7 @@ async function loadStats(ctx) {total_cost_usd: Math.round(totalCost * 1e6) / 1e6,cost_per_entry_usd: entries ? Math.round((totalCost / entries) * 1e6) / 1e6 : null,median_cost_usd: c.median_cost == null ? null : num(c.median_cost),-- median_ms: c.medemon_ms == null ? null : num(c.median_ms),++ median_ms: c.median_ms == null ? null : num(c.median_ms),p95_ms: c.p95_ms == null ? null : num(c.p95_ms),tokens_per_entry: entries ? Math.round(num(c.tokens) / entries) : 0,error_rate: entries ? num(c.errors) / entries : 0,@@@ -19,6 +19,8 @@ const TAGLINE = 'One AI benchmark and comparison engine for every room.';const PUBLIC_DIR = path.join(__dirname, '..', '..', 'public');const NAV = [{ label: 'Home', href: '/' },++ { label: 'Benchmarks', href: '/benchmarks' },++ { label: 'Showcase', href: '/showcase' },{ label: 'Docs', href: '/docs' },];@@@ -44,7 +46,7 @@ function renderPage(o) {const nav = {service: 'bench',apiBase: NETWORK_URL,-- links: NAV.map((l) => ({ label: l.label, href: l.href, active: pathNow === l.href || pathNow.startsWith(`${l.href}/`) })),++ links: NAV.map((l) => ({ label: l.label, href: l.href, active: l.href === '/' ? pathNow === '/' : (pathNow.split('?')[0] === l.href || pathNow.startsWith(`${l.href}/`) || (l.href === '/benchmarks' && /^\/(runs|models|compare)(\/|\?|$)/.test(pathNow))) })),history: { type: 'page', title: o.title || SITE_NAME },silentLogin: `${o.config.baseUrl}/auth/login?silent=1&next={url}`,sessionUrl: '/auth/me',@@@ -1,8 +1,8 @@'use strict';/**-- * Bench's own origin pages (the main session designs them later): a plain home that says what Bench is, lists the-- * every kind and links to boards and docs, and /docs for the API. Ids and classes start with `bm-`.++ * Bench's own origin pages: the home (what Bench shows, the newest benchmarks, the arena kinds for developers) and++ * /docs for the API. The results pages are in ./results.js. Ids and classes start with `bm-`.*/const { esc } = require('../render/html');@@@ -10,21 +10,24 @@ function kindRow(k) {return `<li class="bm-kind"><a class="bm-kind-link" href="/api/v1/boards/${esc(k.id)}?type=elo">${esc(k.id)}</a><span class="bm-kind-meta">${esc(k.room)} · ${esc(k.judge)} · ${esc(k.name)}</span></li>`;}--function home({ kinds = [], counts = { kinds: 0 } } = {}) {++function home({ kinds = [], counts = { kinds: 0 }, benchmarks = [] } = {}) {++ const { benchmarkCard } = require('./results');++ const cards = benchmarks.slice(0, 6).map((b) => String(benchmarkCard(b))).join('');return `<div class="bm-wrap bm-home" id="bm-home">--<header class="bm-hero"><p class="bm-kicker">OpenVibe.Bench</p><h1>One benchmark engine for every room</h1>--<p class="bm-lede">Put AI models side by side on real work: a page design, a game, a meme, a code fix, a web task. People vote blind, graders and tests score the rest, and every round is pinned to the exact model it ran, so anyone can run it again.</p>--<div class="bm-actions"><a class="bm-btn" href="/docs">Read the API</a><a class="bm-btn bm-btn-quiet" href="#bm-kinds">The kinds</a></div></header>++<header class="bm-hero"><p class="bm-kicker">OpenVibe.Bench</p><h1>See what AI really makes</h1>++<p class="bm-lede">Every model on the same tasks: real pages, games, scenes and fixes, shown live side by side. Every run is published with what it cost and how long it took, and anyone can run it again.</p>++<div class="bm-actions"><a class="bm-btn" href="/benchmarks">Browse benchmarks</a><a class="bm-btn bm-btn-quiet" href="/showcase">Vote in the showcase</a></div></header><ul class="bm-why" aria-label="What Bench promises">--<li><b>Free and open</b><span>The public arena costs nothing, and every kind's votes and results download as JSONL, without voter names.</span></li>--<li><b>Cost per solved task</b><span>Boards rank quality against what a solved task really cost, with confidence intervals, not a single score.</span></li>--<li><b>Every room, one engine</b><span>Design, Games, Meme, Vision, Codes, Surf, Chat and speech share one API, SDK and MCP tools.</span></li>--<li><b>Your own evals</b><span>Private task suites on your models or keys, free up to a daily cap, never published.</span></li>++<li><b>Outputs, not just scores</b><span>The pages, games and drawings themselves, live in sandboxed frames, next to the numbers.</span></li>++<li><b>Every run published</b><span>Whatever it scored. No private variants, no best of ten: the service that ran it publishes it.</span></li>++<li><b>Value you can read</b><span>Score against cost per run, with the frontier marked, so the cheapest good model is obvious.</span></li>++<li><b>Free and open</b><span>Votes, runs and outputs download as JSONL. Versions are frozen, so every result can be repeated.</span></li></ul>--<section class="bm-section" id="bm-kinds" aria-labelledby="bm-kinds-h"><div class="bm-head-row"><h2 id="bm-kinds-h">Kinds</h2><span class="bm-count">${Number(counts.kinds) || kinds.length}</span></div>++<section class="bm-section" aria-labelledby="bm-bench-h"><div class="bm-head-row"><h2 id="bm-bench-h">Benchmarks</h2><a class="bm-more" href="/benchmarks">All of them</a></div>++${cards ? `<ul class="br-cards">${cards}</ul>` : '<p class="bm-muted">No benchmark is published yet.</p>'}</section>++<section class="bm-section" id="bm-kinds" aria-labelledby="bm-kinds-h"><div class="bm-head-row"><h2 id="bm-kinds-h">For developers: the arena kinds</h2><span class="bm-count">${Number(counts.kinds) || kinds.length}</span></div>++<p class="bm-fine">Each kind is a room's arena with its judge and entry type. Its board is JSON at <code>/api/v1/boards/:kind</code>, and the <a href="/docs">API</a> covers the rest.</p>${kinds.length ? `<ul class="bm-kinds">${kinds.map(kindRow).join('')}</ul>` : '<p class="bm-muted">No kinds are seeded yet.</p>'}</section>--<section class="bm-section" id="bm-boards"><div class="bm-head-row"><h2>Boards</h2></div>--<p class="bm-fine">Boards are JSON at <code>/api/v1/boards/:kind?type=elo|pareto|cost</code>. Public HTML boards render in OpenVibe.Report; rooms show their own arenas through Bench.</p></section></div>`;}@@@ -52,6 +55,15 @@ ${ep('POST', '/api/v1/evals', 'Create a private task suite (never in the public${ep('POST', '/api/v1/evals/:id/run', 'Run a private eval against chosen offers, under the free daily cap.')}${ep('GET', '/api/v1/evals/:id/results', 'A private eval and its runs.')}</dl></section>++<section id="br-publish"><h2>Benchmarks and runs</h2><p class="bm-fine">A benchmark is a versioned set of tasks, judges and limits; a frozen version never changes once a run names it. A run published by a service (openvibe.codes, Run, a Node worker) is <b>verified</b>; one published with a person's token is <b>submitted</b>, labelled, and never ranked by default.</p><dl class="bm-eps">++${ep('GET', '/api/v1/benchmarks?kind=&tag=&q=&mine=1', 'The public benchmarks; <code>mine=1</code> adds your own unlisted ones.')}++${ep('GET', '/api/v1/benchmarks/:id[@version]', 'A definition. Held-out tasks keep their prompt for the executor and the owner.')}++${ep('POST', '/api/v1/benchmarks', 'Create one (<code>bench.benchmark.write</code>); <code>PUT</code> saves a draft, <code>POST …/versions</code> freezes it, <code>POST …/fork</code> forks it.')}++${ep('POST', '/api/v1/runs', 'Publish a run: <code>{ benchmark: "bmk_…@N", model, provider, harness: { name, version }, executor, tasks: [{ task_id, score, cost_usd, ms, tokens, artifacts }], score, cost_usd, ms, tokens }</code>.')}++${ep('GET', '/api/v1/runs/:id', 'A run with its tasks; <code>/api/v1/compare?runs=a,b</code> puts up to four side by side.')}++${ep('GET', '/api/v1/rankings?benchmark=&metric=score|value|speed|consistency&harness=&since=', 'Medians per model over verified runs; value is score per dollar, speed is score per minute.')}++${ep('GET', '/api/v1/percentile?benchmark=&model=&score=', 'Where a score sits among a model’s verified runs.')}++</dl></section><section><h2>MCP</h2><p class="bm-fine"><code>POST /mcp</code> exposes <code>bench.list_kinds</code>, <code>bench.start_round</code>, <code>bench.next_pair</code>, <code>bench.cast_judgement</code>, <code>bench.get_board</code> and <code>bench.run_eval</code>.</p></section></div>`;}nnew file mode 100644@@@ -0,0 +1,301 @@++'use strict';++++/**++ * The results pages (stage B2): the benchmark list, a benchmark with its rankings and value chart, a run (Geekbench++ * style: the environment, the score, where it sits, each task and its outputs), compare, and a model across++ * benchmarks. Server-rendered and complete without JavaScript. Everything dynamic goes through html`` (escaped).++ * Ids and classes start with `br-`.++ */++const { html, raw, render } = require('../render/html');++const renderLib = require('../bench/render');++++const MEDIA_ORIGIN = 'https://openvibe.media';++++// ---- numbers -------------------------------------------------------------------------------------------------++++const fmtScore = (v) => (v == null ? '—' : (Math.round(Number(v) * 10) / 10).toFixed(1).replace(/\.0$/, ''));++function fmtUsd(v) {++ if (v == null) return '—';++ const n = Number(v);++ if (n === 0) return '$0';++ if (n < 0.01) return `$${n.toPrecision(2)}`;++ return `$${n.toFixed(2)}`;++}++function fmtMs(v) {++ if (v == null) return '—';++ const s = Number(v) / 1000;++ if (s < 1) return `${Math.round(Number(v))} ms`;++ if (s < 90) return `${Math.round(s * 10) / 10} s`;++ return `${Math.round(s / 6) / 10} min`;++}++function fmtTokens(v) {++ if (v == null) return '—';++ const n = Number(v);++ if (n >= 1e6) return `${Math.round(n / 1e5) / 10}M`;++ if (n >= 1e3) return `${Math.round(n / 100) / 10}K`;++ return String(n);++}++const fmtDate = (iso) => (iso ? html`<time datetime="${iso}">${String(iso).slice(0, 10)}</time>` : '—');++function ordinal(n) {++ const v = Math.round(Number(n));++ const t = v % 100;++ if (t >= 11 && t <= 13) return `${v}th`;++ return `${v}${({ 1: 'st', 2: 'nd', 3: 'rd' })[v % 10] || 'th'}`;++}++const plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;++++// ---- links ---------------------------------------------------------------------------------------------------++++const benchmarkHref = (id) => `/benchmarks/${encodeURIComponent(id)}`;++const runHref = (id) => `/runs/${encodeURIComponent(id)}`;++const modelHref = (m) => `/models/${encodeURIComponent(m)}`;++const compareHref = (ids) => `/compare?runs=${ids.map(encodeURIComponent).join(',')}`;++++// ---- small pieces --------------------------------------------------------------------------------------------++++const kindChip = (kind) => (kind ? html`<span class="br-chip br-mono">${kind}</span>` : '');++++function provenance(p) {++ return p === 'verified'++ ? html`<span class="br-prov is-verified" title="Run by openvibe.codes, Run or a Node worker, and published by that service">Verified</span>`++ : html`<span class="br-prov is-submitted" title="Published by a person; nobody re-ran it">Submitted</span>`;++}++++/** A score out of 100 with a thin bar under it. */++function scoreBar(score, { big = false } = {}) {++ const pct = score == null ? 0 : Math.max(0, Math.min(100, Number(score)));++ return html`<span class="br-score${big ? ' is-big' : ''}"><span class="br-score-n">${fmtScore(score)}</span><span class="br-score-of">/100</span><span class="br-bar" aria-hidden="true"><span style="width:${pct.toFixed(1)}%"></span></span></span>`;++}++++function empty(title, text, action = '') {++ return html`<div class="br-empty"><p class="br-empty-t">${title}</p><p>${text}</p>${action}</div>`;++}++++function harnessLabel(h) {++ if (!h || !h.name) return '—';++ return h.version ? `${h.name} ${h.version}` : h.name;++}++++// ---- the value chart -----------------------------------------------------------------------------------------++++/**++ * Score against cost per run, one dot per model, cost on a log scale. The frontier joins the models nobody beats on++ * both at once (no other model is cheaper and better). Drawn as SVG on the server; the table under it carries the++ * same numbers for screen readers.++ */++function valueChart(entries) {++ const W = 880; const H = 320; const L = 44; const R = 16; const T = 14; const B = 40;++ const pts = entries.filter((e) => e.score != null && e.cost_usd != null && e.cost_usd > 0);++ const grid = [0, 25, 50, 75, 100].map((y) => {++ const py = T + (H - T - B) * (1 - y / 100);++ return html`<line class="br-grid" x1="${L}" x2="${W - R}" y1="${py}" y2="${py}"/><text class="br-axis" x="${L - 8}" y="${py + 4}" text-anchor="end">${y}</text>`;++ });++ if (!pts.length) {++ return html`<figure class="br-chart" aria-label="Score against cost: no verified runs yet"><svg viewBox="0 0 ${W} ${H}" role="img" preserveAspectRatio="xMidYMid meet">${grid}<text class="br-axis" x="${(L + W - R) / 2}" y="${H - 8}" text-anchor="middle">Cost per run (log scale)</text><text class="br-chart-empty" x="${(L + W - R) / 2}" y="${(T + H - B) / 2}" text-anchor="middle">The chart fills in with the first verified runs</text></svg></figure>`;++ }++ const costs = pts.map((p) => Math.log10(p.cost_usd));++ let lo = Math.floor(Math.min(...costs)); let hi = Math.ceil(Math.max(...costs));++ if (hi === lo) { lo -= 1; hi += 1; }++ const x = (c) => L + (W - L - R) * ((Math.log10(c) - lo) / (hi - lo));++ const y = (s) => T + (H - T - B) * (1 - s / 100);++ const ticks = [];++ for (let e = lo; e <= hi; e++) {++ const px = L + (W - L - R) * ((e - lo) / (hi - lo));++ ticks.push(html`<text class="br-axis" x="${px}" y="${H - B + 18}" text-anchor="middle">${fmtUsd(10 ** e)}</text>`);++ }++ // The frontier: walk from the cheapest up, keeping each model that scores higher than every cheaper one.++ const sorted = [...pts].sort((a, b) => a.cost_usd - b.cost_usd || b.score - a.score);++ const frontier = [];++ let best = -Infinity;++ for (const p of sorted) if (p.score > best) { frontier.push(p); best = p.score; }++ const onFrontier = new Set(frontier.map((p) => p.model));++ let path = '';++ frontier.forEach((p, i) => {++ const px = x(p.cost_usd).toFixed(1); const py = y(p.score).toFixed(1);++ if (i === 0) path += `M${px} ${py}`;++ else path += ` H${px} V${py}`;++ });++ // Labels sit beside their dot; one that would overlap a label already placed moves down (or up) by a line.++ const placed = [];++ const labelY = (px, py, anchor) => {++ const w = 7 * 22; const x0 = anchor === 'end' ? px - w : px; let ly = py + 4;++ for (let tries = 0; tries < 6; tries++) {++ const hit = placed.find((b) => Math.abs(b.y - ly) < 13 && x0 < b.x0 + b.w && b.x0 < x0 + w);++ if (!hit) break;++ ly = hit.y + (ly >= hit.y ? 13 : -13);++ }++ placed.push({ x0, w, y: ly });++ return ly;++ };++ const dots = [...pts].sort((a, b) => b.score - a.score).map((p) => {++ const px = x(p.cost_usd); const py = y(p.score);++ const anchor = px > W - 180 ? 'end' : 'start';++ const dx = anchor === 'end' ? -9 : 9;++ const ly = labelY(px + dx, py, anchor);++ return html`<g class="br-dot${onFrontier.has(p.model) ? ' is-front' : ''}"><circle cx="${px.toFixed(1)}" cy="${py.toFixed(1)}" r="5"><title>${p.model}: ${fmtScore(p.score)} for ${fmtUsd(p.cost_usd)} a run</title></circle><text x="${(px + dx).toFixed(1)}" y="${ly.toFixed(1)}" text-anchor="${anchor}">${p.model}</text></g>`;++ });++ return html`<figure class="br-chart" aria-label="Score against cost per run; the line is the frontier"><svg viewBox="0 0 ${W} ${H}" role="img" preserveAspectRatio="xMidYMid meet">${grid}${ticks}<text class="br-axis" x="${(L + W - R) / 2}" y="${H - 4}" text-anchor="middle">Cost per run (log scale)</text>${path ? raw(`<path class="br-front" d="${path}"/>`) : ''}${dots}</svg><figcaption>Up is better, left is cheaper. The line joins the models no other model beats on both.</figcaption></figure>`;++}++++// ---- the rankings table --------------------------------------------------------------------------------------++++const METRICS = [++ { id: 'score', label: 'Score' },++ { id: 'value', label: 'Value', hint: 'score per dollar' },++ { id: 'speed', label: 'Speed', hint: 'score per minute' },++ { id: 'consistency', label: 'Steadiness', hint: 'spread inside a session, lower is steadier' },++];++++function metricTabs(base, current) {++ return html`<nav class="br-tabs" aria-label="Rank by">${METRICS.map((m) => html`<a class="br-tab" href="${base}?metric=${m.id}#br-rank"${m.id === current ? raw(' aria-current="page"') : ''}${m.hint ? raw(` title="${m.hint}"`) : ''}>${m.label}</a>`)}</nav>`;++}++++function rankingsTable(entries, metric) {++ if (!entries.length) return '';++ const col = { value: (e) => (e.value == null ? '—' : `${fmtScore(e.value)} / $`), speed: (e) => (e.speed == null ? '—' : `${fmtScore(e.speed)} / min`), consistency: (e) => (e.consistency == null ? '—' : `±${fmtScore(e.consistency)}`) }[metric];++ return html`<div class="br-table-wrap"><table class="br-table"><thead><tr><th scope="col">#</th><th scope="col">Model</th><th scope="col">Score</th>${col ? html`<th scope="col">${METRICS.find((m) => m.id === metric).label}</th>` : ''}<th scope="col" class="br-num">Cost / run</th><th scope="col" class="br-num">Time</th><th scope="col" class="br-num">Runs</th></tr></thead><tbody>${entries.map((e, i) => html`<tr><td class="br-rank">${i + 1}</td><td><a class="br-model" href="${modelHref(e.model)}">${e.model}</a></td><td>${scoreBar(e.score)}</td>${col ? html`<td class="br-num">${col(e)}</td>` : ''}<td class="br-num">${fmtUsd(e.cost_usd)}</td><td class="br-num">${fmtMs(e.ms)}</td><td class="br-num">${e.runs}</td></tr>`)}</tbody></table></div>`;++}++++// ---- runs list -----------------------------------------------------------------------------------------------++++function runsList(runs, { showBenchmark = false, titles = {} } = {}) {++ if (!runs.length) return '';++ return html`<ul class="br-runs">${runs.map((r) => html`<li class="br-run"><a class="br-run-link" href="${runHref(r.id)}"><span class="br-run-main"><span class="br-run-model">${r.model}</span><span class="br-run-sub">${showBenchmark ? html`${titles[r.benchmark_id] || r.benchmark_id} · ` : ''}${harnessLabel(r.harness)} · ${fmtDate(r.created_at)}</span></span>${scoreBar(r.score)}</a>${provenance(r.provenance)}</li>`)}</ul>`;++}++++// ---- outputs -------------------------------------------------------------------------------------------------++++/** An output: a live frame when it is ours to frame (the render origin), a picture from Media, else a plain link. */++function artifact(a, label) {++ const url = String(a.url || '');++ if (url.startsWith(`${renderLib.RENDER_ORIGIN}/render/`)) {++ return html`<figure class="br-out"><iframe class="br-out-frame" src="${url}" title="${label}" sandbox="${renderLib.WRAPPER_SANDBOX}" referrerpolicy="no-referrer" loading="lazy"></iframe><figcaption>${a.kind}</figcaption></figure>`;++ }++ if (url.startsWith(`${MEDIA_ORIGIN}/`) && /^(image|screenshot|png|jpeg|webp)$/i.test(String(a.kind))) {++ return html`<figure class="br-out"><img class="br-out-img" src="${url}" alt="${label}" loading="lazy"><figcaption>${a.kind}</figcaption></figure>`;++ }++ if (/^https:\/\//.test(url)) return html`<a class="br-out-link" href="${url}" rel="noopener nofollow ugc">${a.kind}: ${url.replace(/^https:\/\//, '').slice(0, 60)}</a>`;++ return html`<span class="br-out-link">${a.kind}</span>`;++}++++// ---- pages ---------------------------------------------------------------------------------------------------++++function benchmarksIndex({ benchmarks = [], kinds = [], kind = null, q = '' } = {}) {++ const families = [...new Set(kinds.map((k) => String(k).split('.')[0]))].sort();++ const chip = (label, value) => {++ const on = (value || null) === (kind || null);++ const href = value ? `/benchmarks?kind=${encodeURIComponent(value)}` : '/benchmarks';++ return html`<a class="br-filter" href="${href}"${on ? raw(' aria-current="page"') : ''}>${label}</a>`;++ };++ return html`<div class="bm-wrap br" id="br-benchmarks">++<header class="bm-page-h"><p class="bm-kicker">Benchmarks</p><h1>Benchmarks anyone can run again</h1>++<p class="bm-lede">Each one is a versioned set of tasks with its judges and limits. A version never changes once a run names it, so every score here can be repeated.</p></header>++<form class="br-search" method="get" action="/benchmarks" role="search"><label class="br-sr" for="br-q">Search benchmarks</label><input id="br-q" name="q" type="search" value="${q}" placeholder="Search by title, tag or kind" autocomplete="off">${kind ? html`<input type="hidden" name="kind" value="${kind}">` : ''}<button class="bm-btn bm-btn-small" type="submit">Search</button></form>++<nav class="br-filters" aria-label="Filter by family">${chip('All', null)}${families.map((f) => chip(f, f))}</nav>++${benchmarks.length ? html`<ul class="br-cards">${benchmarks.map(benchmarkCard)}</ul>` : empty('No benchmark matches', q ? 'Try a shorter search, or clear the filter.' : 'None are published yet.', html`<a class="bm-btn bm-btn-quiet bm-btn-small" href="/benchmarks">Show all</a>`)}++</div>`;++}++++function benchmarkCard(b) {++ const tasks = ((b.draft && b.draft.tasks) || []).length;++ return html`<li class="br-card"><a class="br-card-link" href="${benchmarkHref(b.id)}"><span class="br-card-top">${kindChip(b.kind)}<span class="br-card-v">v${b.latest_version || 0}</span></span><span class="br-card-title">${b.title}</span><span class="br-card-desc">${b.description}</span><span class="br-card-foot">${plural(tasks, 'task')}${b.runs != null ? html` · ${plural(b.runs, 'run')}` : ''}${b.parent ? ' · a fork' : ''}</span></a></li>`;++}++++function benchmarkPage({ benchmark, definition, version, rankings, metric = 'score', runs = [], codesRunUrl = null }) {++ const d = definition || {};++ const tasks = Array.isArray(d.tasks) ? d.tasks : [];++ const shown = tasks.filter((t) => !t.holdout && t.prompt);++ const hidden = tasks.length - shown.length;++ const judges = Array.isArray(d.judges) ? d.judges : [];++ const limits = d.limits || {};++ const entries = (rankings && rankings.entries) || [];++ const base = benchmarkHref(benchmark.id);++ const runYourself = codesRunUrl++ ? html`<a class="bm-btn" href="${codesRunUrl}?benchmark=${encodeURIComponent(`${benchmark.id}@${version || benchmark.latest_version}`)}">Run it yourself</a>`++ : html`<a class="bm-btn bm-btn-quiet" href="/docs#br-publish">Publish a run</a>`;++ return html`<div class="bm-wrap br" id="br-benchmark">++<nav class="br-crumbs" aria-label="Breadcrumb"><a href="/benchmarks">Benchmarks</a><span aria-hidden="true">/</span><span>${benchmark.title}</span></nav>++<header class="br-head"><div class="br-head-main"><p class="br-head-meta">${kindChip(benchmark.kind)}<span>v${version || benchmark.latest_version || 0}</span><span>by ${benchmark.owner}</span>${benchmark.parent ? html`<a href="${benchmarkHref(benchmark.parent)}">forked</a>` : ''}</p>++<h1>${benchmark.title}</h1>${benchmark.description ? html`<p class="bm-lede">${benchmark.description}</p>` : ''}</div>++<div class="br-head-act">${runYourself}<p class="br-fine">${codesRunUrl ? 'On openvibe.codes, with your own keys. The result is published here.' : 'Running it on openvibe.codes with your own keys is coming. Today a run is published through the API.'}</p></div></header>++<dl class="br-facts"><div><dt>Tasks</dt><dd>${tasks.length}${hidden ? html` <span class="br-fine">(${hidden} hidden)</span>` : ''}</dd></div><div><dt>Judged by</dt><dd>${judges.length ? judges.map((j) => String(j.type).replace(/_/g, ' ')).join(', ') : '—'}</dd></div><div><dt>Limits</dt><dd>${[limits.ms ? fmtMs(limits.ms) : null, limits.tokens ? `${fmtTokens(limits.tokens)} tokens` : null, limits.usd ? fmtUsd(limits.usd) : null].filter(Boolean).join(' · ') || '—'}</dd></div><div><dt>Verified runs</dt><dd>${entries.reduce((n, e) => n + e.runs, 0)}</dd></div></dl>++<section class="bm-section" id="br-rank" aria-labelledby="br-rank-h"><div class="bm-head-row"><h2 id="br-rank-h">Rankings</h2>${metricTabs(base, metric)}</div>++${valueChart(entries)}++${entries.length ? rankingsTable(entries, metric) : empty('No verified runs yet', 'A run counts here once openvibe.codes, Run or a Node worker ran it and published it. Submitted runs are listed below but never ranked.')}++</section>++<section class="bm-section" aria-labelledby="br-tasks-h"><div class="bm-head-row"><h2 id="br-tasks-h">Tasks</h2><span class="bm-count">${tasks.length}</span></div>++<ol class="br-tasks">${shown.map((t) => html`<li class="br-task"><span class="br-task-id br-mono">${t.id}</span><p>${t.prompt}</p></li>`)}${hidden ? html`<li class="br-task is-hidden"><span class="br-task-id br-mono">${plural(hidden, 'task')}</span><p>Held out: only the executor sees ${hidden === 1 ? 'it' : 'them'}, so nobody can tune for the answer.</p></li>` : ''}</ol></section>++<section class="bm-section" aria-labelledby="br-latest-h"><div class="bm-head-row"><h2 id="br-latest-h">Latest runs</h2>${runs.length > 1 ? html`<a class="bm-more" href="${compareHref(runs.slice(0, 2).map((r) => r.id))}">Compare the newest two</a>` : ''}</div>++${runs.length ? runsList(runs) : empty('No runs yet', 'The first run shows up here, verified or submitted.')}</section>++<p class="br-fine br-api">The same data as JSON: <a href="/api/v1/benchmarks/${encodeURIComponent(benchmark.id)}">definition</a> · <a href="/api/v1/rankings?benchmark=${encodeURIComponent(benchmark.id)}&metric=${metric}">rankings</a></p>++</div>`;++}++++function runPage({ run, benchmark, definition, pct }) {++ const tasksDef = new Map(((definition && definition.tasks) || []).map((t) => [t.id, t]));++ const env = [++ ['Model', html`<a href="${modelHref(run.model)}">${run.model}</a>`],++ ['Provider', run.provider || '—'],++ ['Route', run.route && Object.keys(run.route).length ? Object.entries(run.route).map(([k, v]) => `${k} ${v}`).join(' · ') : '—'],++ ['Harness', harnessLabel(run.harness)],++ ['Settings', [run.settings && run.settings.effort ? `effort ${run.settings.effort}` : null, run.settings && run.settings.temperature != null ? `temperature ${run.settings.temperature}` : null].filter(Boolean).join(' · ') || 'defaults'],++ ['Ran on', run.executor ? ({ codes: 'openvibe.codes', run: 'OpenVibe.Run', node: 'a Node worker', submitted: 'not re-run' })[run.executor.kind] || run.executor.kind : '—'],++ ['Hardware', run.hardware ? Object.entries(run.hardware).map(([k, v]) => `${k} ${v}`).join(' · ') : '—'],++ ['Benchmark', html`<a href="${benchmarkHref(run.benchmark_id)}">${benchmark ? benchmark.title : run.benchmark_id}</a> <span class="br-fine">v${run.benchmark_version}</span>`],++ ];++ const pctLine = pct && pct.runs > 1 && pct.percentile != null++ ? html`<div class="br-pct"><div class="br-pct-strip" aria-hidden="true"><span style="left:${Math.max(0, Math.min(100, pct.percentile)).toFixed(1)}%"></span></div><p><b>${ordinal(pct.percentile)} percentile</b> of ${pct.runs} verified runs of ${run.model} on this benchmark. Median ${fmtScore(pct.median)}, best ${fmtScore(pct.best)}.</p></div>`++ : html`<p class="br-fine">Where it sits shows once ${run.model} has more verified runs here.</p>`;++ return html`<div class="bm-wrap br" id="br-run">++<nav class="br-crumbs" aria-label="Breadcrumb"><a href="/benchmarks">Benchmarks</a><span aria-hidden="true">/</span><a href="${benchmarkHref(run.benchmark_id)}">${benchmark ? benchmark.title : run.benchmark_id}</a><span aria-hidden="true">/</span><span class="br-mono">${run.id}</span></nav>++<header class="br-head br-run-head"><div class="br-head-main"><p class="br-head-meta">${provenance(run.provenance)}<span>${fmtDate(run.created_at)}</span></p><h1>${run.model}</h1><p class="bm-lede">on ${benchmark ? benchmark.title : run.benchmark_id}, through ${harnessLabel(run.harness)}</p></div>++<div class="br-head-score">${scoreBar(run.score, { big: true })}<dl class="br-totals"><div><dt>Cost</dt><dd>${fmtUsd(run.cost_usd)}</dd></div><div><dt>Time</dt><dd>${fmtMs(run.ms)}</dd></div><div><dt>Tokens</dt><dd>${fmtTokens(run.tokens)}</dd></div></dl></div></header>++${pctLine}++<section class="bm-section" aria-labelledby="br-env-h"><h2 id="br-env-h">Environment</h2><dl class="br-env">${env.map(([k, v]) => html`<div><dt>${k}</dt><dd>${v}</dd></div>`)}</dl></section>++<section class="bm-section" aria-labelledby="br-pt-h"><div class="bm-head-row"><h2 id="br-pt-h">Tasks</h2><span class="bm-count">${(run.tasks || []).length}</span></div>++${(run.tasks || []).length ? html`<ol class="br-ptasks">${run.tasks.map((t) => {++ const def = tasksDef.get(t.task_id);++ const prompt = def && def.prompt && !def.holdout ? def.prompt : 'A held-out task: its prompt stays with the executor.';++ return html`<li class="br-ptask"><div class="br-ptask-head"><span class="br-task-id br-mono">${t.task_id}</span>${scoreBar(t.score)}<span class="br-ptask-meta">${fmtUsd(t.cost_usd)} · ${fmtMs(t.ms)} · ${fmtTokens(t.tokens)} tokens</span></div><p class="br-ptask-prompt">${prompt}</p>${t.artifacts && t.artifacts.length ? html`<div class="br-outs">${t.artifacts.map((a, i) => artifact(a, `${t.task_id} output ${i + 1}`))}</div>` : ''}${t.transcript_url && /^https:\/\//.test(t.transcript_url) ? html`<a class="bm-more" href="${t.transcript_url}" rel="noopener nofollow">Transcript</a>` : ''}</li>`;++ })}</ol>` : empty('No task results', 'This run published its totals only.')}</section>++<section class="bm-section br-again" aria-labelledby="br-again-h"><h2 id="br-again-h">Again</h2><p class="br-fine">The benchmark version is frozen, so this run can be repeated exactly: the same tasks, the same judges.</p><div class="bm-actions"><a class="bm-btn bm-btn-quiet" href="${benchmarkHref(run.benchmark_id)}">See every model on it</a><a class="bm-btn bm-btn-quiet" href="/api/v1/runs/${encodeURIComponent(run.id)}">The run as JSON</a></div></section>++</div>`;++}++++function comparePage({ cmp, titles = {} }) {++ if (!cmp) {++ return html`<div class="bm-wrap br" id="br-compare"><header class="bm-page-h"><p class="bm-kicker">Compare</p><h1>Compare runs</h1><p class="bm-lede">Open a benchmark, then compare two to four of its runs: the same tasks side by side, with their scores, cost, time and outputs.</p></header>${empty('Nothing to compare', 'Add runs with ?runs=run_a,run_b, or pick them from a benchmark.', html`<a class="bm-btn bm-btn-small" href="/benchmarks">Benchmarks</a>`)}</div>`;++ }++ const { runs, rows } = cmp;++ const best = (vals, hi = true) => { const v = vals.filter((x) => x != null); return v.length ? (hi ? Math.max(...v) : Math.min(...v)) : null; };++ const cell = (v, b, f) => html`<td class="br-num${v != null && v === b ? ' is-best' : ''}">${f(v)}</td>`;++ const line = (label, vals, f, hi = true) => { const b = best(vals, hi); return html`<tr><th scope="row">${label}</th>${vals.map((v) => cell(v, b, f))}</tr>`; };++ return html`<div class="bm-wrap br" id="br-compare">++<header class="bm-page-h"><p class="bm-kicker">Compare</p><h1>${runs.map((r) => r.model).join(' vs ')}</h1><p class="bm-lede">${[...new Set(runs.map((r) => titles[r.benchmark_id] || r.benchmark_id))].join(', ')}. The best value in each row is marked.</p></header>++<div class="br-table-wrap"><table class="br-table br-cmp"><thead><tr><th scope="col"><span class="br-sr">Measure</span></th>${runs.map((r) => html`<th scope="col"><a href="${runHref(r.id)}">${r.model}</a><span class="br-cmp-sub">${harnessLabel(r.harness)}</span>${provenance(r.provenance)}</th>`)}</tr></thead><tbody>++${line('Score', runs.map((r) => r.score), fmtScore)}${line('Cost', runs.map((r) => r.cost_usd), fmtUsd, false)}${line('Time', runs.map((r) => r.ms), fmtMs, false)}${line('Tokens', runs.map((r) => r.tokens), fmtTokens, false)}++${rows.map((row) => line(html`<span class="br-mono">${row.task_id}</span>`, row.scores, fmtScore))}++</tbody></table></div>++${rows.some((row) => runs.some((r) => ((r.tasks.find((t) => t.task_id === row.task_id) || {}).artifacts || []).length)) ? html`<section class="bm-section" aria-labelledby="br-cmp-out-h"><h2 id="br-cmp-out-h">Outputs side by side</h2>${rows.map((row) => html`<div class="br-cmp-row"><p class="br-task-id br-mono">${row.task_id}</p><div class="br-cmp-outs" style="--n:${runs.length}">${runs.map((r) => {++ const t = r.tasks.find((x) => x.task_id === row.task_id);++ const a = t && t.artifacts && t.artifacts[0];++ return html`<div class="br-cmp-out"><p class="br-cmp-sub">${r.model}</p>${a ? artifact(a, `${r.model} ${row.task_id}`) : html`<p class="br-fine">No output</p>`}</div>`;++ })}</div></div>`)}</section>` : ''}++</div>`;++}++++function modelPage({ model, summary, runs = [], titles = {} }) {++ const rows = (summary && summary.benchmarks) || [];++ return html`<div class="bm-wrap br" id="br-model">++<nav class="br-crumbs" aria-label="Breadcrumb"><a href="/benchmarks">Benchmarks</a><span aria-hidden="true">/</span><span>Models</span></nav>++<header class="bm-page-h"><p class="bm-kicker">Model</p><h1 class="br-mono-h">${model}</h1><p class="bm-lede">${summary && summary.runs ? `${plural(summary.runs, 'verified run')} across ${plural(rows.length, 'benchmark')}.` : 'No verified runs yet.'}</p></header>++<section class="bm-section" aria-labelledby="br-mb-h"><h2 id="br-mb-h">By benchmark</h2>++${rows.length ? html`<div class="br-table-wrap"><table class="br-table"><thead><tr><th scope="col">Benchmark</th><th scope="col">Median</th><th scope="col" class="br-num">Spread</th><th scope="col" class="br-num">Cost / run</th><th scope="col" class="br-num">Time</th><th scope="col" class="br-num">Runs</th></tr></thead><tbody>${rows.map((b) => html`<tr><td><a href="${benchmarkHref(b.benchmark_id)}">${b.title}</a> ${kindChip(b.kind)}</td><td>${scoreBar(b.score)}</td><td class="br-num">${b.runs > 1 ? `${fmtScore(b.worst)}–${fmtScore(b.best)}` : '—'}</td><td class="br-num">${fmtUsd(b.cost_usd)}</td><td class="br-num">${fmtMs(b.ms)}</td><td class="br-num">${b.runs}</td></tr>`)}</tbody></table></div>` : empty('Nothing measured yet', 'This model shows up here after its first verified run.', html`<a class="bm-btn bm-btn-small" href="/benchmarks">Pick a benchmark</a>`)}</section>++${runs.length ? html`<section class="bm-section" aria-labelledby="br-mr-h"><h2 id="br-mr-h">Latest runs</h2>${runsList(runs, { showBenchmark: true, titles })}</section>` : ''}++</div>`;++}++++module.exports = {++ benchmarksIndex, benchmarkPage, runPage, comparePage, modelPage, valueChart, METRICS,++ fmtScore, fmtUsd, fmtMs, fmtTokens, ordinal, benchmarkCard, render,++};nnew file mode 100644@@@ -0,0 +1,175 @@++'use strict';++++/**++ * The results pages (stage B2) and the rules they rest on.++ *++ * Under test: every page renders from the registry's own data (benchmarks, a benchmark with its rankings and value++ * chart, a run, compare, a model); dynamic text is escaped; an unlisted benchmark is reachable by its id but listed++ * to nobody but its owner, and its runs stay off a model's page; the rankings'++ * `since` and `harness` filters work on their own; the value chart marks the frontier and only the frontier.++ */++const assert = require('assert');++const { boot, check, done } = require('./helpers/boot');++const results = require('../server/views/results');++++const TASKS = [++ { id: 't1', prompt: 'Build a one-screen arcade game with a paddle, bricks, a ball and a score.', files: [], expected: null, holdout: false },++ { id: 't2', prompt: 'A held-out snake game.', files: [], expected: null, holdout: true },++];++++function definition(over = {}) {++ return {++ title: 'Pages test arena',++ description: 'A benchmark for the page tests.',++ kind: 'games.play',++ tags: ['games'],++ visibility: 'public',++ tasks: TASKS,++ judges: [{ type: 'game_outcome', version: '1.0', config: {} }],++ scoring: { method: 'mean', scale: { min: 0, max: 100 } },++ limits: { ms: 120000, tokens: 200000, usd: 0.5 },++ matrix: { models: ['model-a'], harnesses: ['claude-code'] },++ ...over,++ };++}++++function runDoc(benchmark, over = {}) {++ return {++ benchmark,++ model: 'model-a',++ route: { provider: 'acme' },++ provider: 'acme',++ harness: { name: 'claude-code', version: '3.1.0' },++ settings: { temperature: 1, effort: 'high' },++ executor: { kind: 'codes', id: 'tsk_pages' },++ tasks: [++ { task_id: 't1', score: 80, cost_usd: 0.01, ms: 30000, tokens: 5000, artifacts: [{ kind: 'html', url: 'https://bench-render.openvibe.services/render/w/ent_pages' }] },++ { task_id: 't2', score: 60, cost_usd: 0.01, ms: 30000, tokens: 5000, artifacts: [] },++ ],++ score: 70,++ cost_usd: 0.02,++ ms: 60000,++ tokens: 10000,++ ...over,++ };++}++++(async () => {++ const t = await boot();++ const alice = t.network.addUser('alice');++ const bob = t.network.addUser('bob');++ const publisher = t.network.serviceToken({ sub: 'svc:codes', audience: 'openvibe.bench', cap: ['bench.run.publish', 'bench.benchmark.write'] });++++ const create = async (over, as) => {++ const res = await t.get('/api/v1/benchmarks', as ? { as, json: definition(over) } : { bearer: publisher, json: definition(over) });++ assert.strictEqual(res.status, 201, res.text);++ const id = res.json().benchmark.id;++ const frozen = await t.get(`/api/v1/benchmarks/${id}/versions`, as ? { as, json: {} } : { bearer: publisher, json: {} });++ assert.strictEqual(frozen.status, 201, frozen.text);++ return { id, version: frozen.json().version.version };++ };++ const publish = async (ref, over) => {++ const res = await t.get('/api/v1/runs', { bearer: publisher, json: runDoc(ref, over) });++ assert.strictEqual(res.status, 201, res.text);++ return res.json().run.id;++ };++++ const pub = await create({ title: 'Pages <script>alert(1)</script> arena' });++ const cheap = await publish(`${pub.id}@${pub.version}`, { model: 'model-cheap', score: 60, cost_usd: 0.002 });++ const best = await publish(`${pub.id}@${pub.version}`, { model: 'model-best', score: 90, cost_usd: 0.05 });++ await publish(`${pub.id}@${pub.version}`, { model: 'model-worse', score: 55, cost_usd: 0.04, harness: { name: 'opencode', version: '1.4.2' } });++ const priv = await create({ title: 'Alice unlisted prompts', visibility: 'unlisted' }, alice);++ await publish(`${priv.id}@${priv.version}`, { model: 'model-best', score: 12, cost_usd: 0.01 });++++ await check('the benchmarks page lists the public benchmarks and escapes their titles', async () => {++ const res = await t.get('/benchmarks');++ assert.strictEqual(res.status, 200, res.text.slice(0, 300));++ assert.ok(res.text.includes('Pages <script>alert(1)</script> arena'), 'the title is escaped');++ assert.ok(!res.text.includes('<script>alert(1)</script>'), 'never raw');++ assert.ok(!res.text.includes('Alice unlisted prompts'), 'an unlisted benchmark is not listed');++ });++++ await check('a benchmark page shows its rankings, its value chart and its runs', async () => {++ const res = await t.get(`/benchmarks/${pub.id}`);++ assert.strictEqual(res.status, 200, res.text.slice(0, 300));++ assert.ok(res.text.includes('id="br-rank"'), 'the rankings section');++ assert.ok(res.text.includes('class="br-chart"'), 'the value chart');++ for (const m of ['model-best', 'model-cheap', 'model-worse']) assert.ok(res.text.includes(m), `${m} is ranked`);++ assert.ok(res.text.includes('Held out'), 'the holdout task is counted, its prompt is not shown');++ assert.ok(!res.text.includes('A held-out snake game.'), 'the holdout prompt never reaches the page');++ const value = await t.get(`/benchmarks/${pub.id}?metric=value`);++ assert.ok(value.text.includes('aria-current="page"') && value.text.includes('/ $'), 'the value tab is current and shows score per dollar');++ });++++ await check('a run page shows the environment, the score, the provenance and the outputs', async () => {++ const res = await t.get(`/runs/${best}`);++ assert.strictEqual(res.status, 200, res.text.slice(0, 300));++ assert.ok(res.text.includes('model-best'));++ assert.ok(res.text.includes('Verified'), 'the provenance badge');++ assert.ok(res.text.includes('claude-code 3.1.0'), 'the harness and its version');++ assert.ok(res.text.includes('src="https://bench-render.openvibe.services/render/w/ent_pages"'), 'an output from the render origin is framed');++ assert.ok(res.text.includes('sandbox="'), 'and sandboxed');++ assert.ok(res.text.includes('A held-out task'), 'a holdout task keeps its prompt hidden on the run page too');++ assert.strictEqual((await t.get('/runs/brn_nope')).status, 404);++ });++++ await check('compare puts runs side by side and marks the best in each row', async () => {++ const res = await t.get(`/compare?runs=${best},${cheap}`);++ assert.strictEqual(res.status, 200, res.text.slice(0, 300));++ assert.ok(res.text.includes('model-best vs model-cheap'));++ assert.ok(res.text.includes('is-best'), 'a best value is marked');++ assert.strictEqual((await t.get('/compare')).status, 200, 'an empty compare explains itself');++ });++++ await check('a model page shows the public benchmarks only', async () => {++ const res = await t.get('/models/model-best');++ assert.strictEqual(res.status, 200, res.text.slice(0, 300));++ assert.ok(res.text.includes('Pages <script>'), 'its public benchmark');++ assert.ok(!res.text.includes('Alice unlisted prompts'), 'never an unlisted benchmark, not even its title');++ assert.strictEqual((await t.get('/models/nobody-ran-this')).status, 404);++ });++++ await check('an unlisted benchmark is reachable by its id and listed to nobody but its owner', async () => {++ assert.strictEqual((await t.get(`/api/v1/benchmarks/${priv.id}`)).status, 200, 'reachable by id');++ const page = await t.get(`/benchmarks/${priv.id}`);++ assert.strictEqual(page.status, 200, 'its page too');++ assert.ok(page.text.includes('noindex'), 'but kept out of search engines');++ const list = await t.get('/api/v1/benchmarks');++ assert.ok(!list.json().benchmarks.some((b) => b.id === priv.id), 'never in the public list');++ const mine = await t.get('/api/v1/benchmarks?mine=1', { as: alice });++ assert.ok(mine.json().benchmarks.some((b) => b.id === priv.id), 'the owner lists it with ?mine=1');++ const theirs = await t.get('/api/v1/benchmarks?mine=1', { as: bob });++ assert.ok(!theirs.json().benchmarks.some((b) => b.id === priv.id), 'nobody else does');++ });++++ await check('the rankings filter by since alone and by harness name', async () => {++ const since = await t.get(`/api/v1/rankings?benchmark=${pub.id}&metric=score&since=2000-01-01T00:00:00Z`);++ assert.strictEqual(since.status, 200, since.text);++ assert.strictEqual(since.json().rankings.entries.length, 3, '`since` without `harness` is its own placeholder');++ const harness = await t.get(`/api/v1/rankings?benchmark=${pub.id}&metric=score&harness=opencode`);++ assert.strictEqual(harness.status, 200, harness.text);++ assert.deepStrictEqual(harness.json().rankings.entries.map((e) => e.model), ['model-worse'], 'the harness name matches');++ });++++ await check('the value chart marks the frontier and only the frontier', () => {++ const svg = String(results.valueChart([++ { model: 'cheap', score: 60, cost_usd: 0.002 },++ { model: 'best', score: 90, cost_usd: 0.05 },++ { model: 'dominated', score: 55, cost_usd: 0.04 },++ ]));++ const front = [...svg.matchAll(/<g class="br-dot( is-front)?">.*?<text[^>]*>([^<]+)<\/text>/g)].map((m) => [m[2], Boolean(m[1])]);++ const by = Object.fromEntries(front);++ assert.strictEqual(by.cheap, true);++ assert.strictEqual(by.best, true);++ assert.strictEqual(by.dominated, false, 'a model both dearer and worse than another is off the frontier');++ assert.ok(String(results.valueChart([])).includes('fills in with the first verified runs'), 'the empty chart says so');++ });++++ await check('the render origin asks Cloudflare not to rewrite its frames', async () => {++ const res = await t.get('/render/w/ent_nope');++ assert.match(String(res.headers.get('cache-control')), /no-transform/);++ });++++ await check('stop', async () => { await t.close(); });++ done();++})();
@@ -61,3 +61,193 @@ html, body { margin: 0; background: var(--bg-primary, #0a0f1c); color: var(--tex
@@ -61,3 +61,193 @@ html, body { margin: 0; background: var(--bg-primary, #0a0f1c); color: var(--tex
.bm-kind-link:hover { text-decoration: underline; }
.bm-kind-link:hover { text-decoration: underline; }
.bm-kind-link:focus-visible { outline: 2px solid var(--room-accent); outline-offset: 2px; border-radius: 4px; }
.bm-kind-link:focus-visible { outline: 2px solid var(--room-accent); outline-offset: 2px; border-radius: 4px; }
.bm-kind-meta { font-size: .82rem; color: var(--text-muted, #7386a3); }
.bm-kind-meta { font-size: .82rem; color: var(--text-muted, #7386a3); }
+
+/* ---- Results pages (B2): benchmarks, a benchmark, a run, compare, a model. Classes start with br-. ---------- */
+.br-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
+.br-mono, .br-mono-h { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
+.br-mono-h { font-size: clamp(1.5rem, 4.4vw, 2.4rem) !important; letter-spacing: -.01em !important; }
+.br-fine { color: var(--text-muted, #7386a3); font-size: .86rem; line-height: 1.5; margin: 0; }
+.br-chip { display: inline-flex; align-items: center; padding: 2px 9px; border-radius: 999px; font-size: .76rem; font-weight: 700; background: color-mix(in srgb, var(--room-accent) 14%, transparent); color: var(--room-strong); white-space: nowrap; }
+.br-crumbs { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding-top: clamp(16px, 3vw, 28px); font-size: .86rem; color: var(--text-muted, #7386a3); min-width: 0; }
+.br-crumbs a { color: var(--text-secondary, #96a7c2); text-decoration: none; }
+.br-crumbs a:hover { color: var(--room-strong); }
+.br-crumbs > span:last-child { color: var(--text-primary, #e6edf7); overflow-wrap: anywhere; }
+
+/* The page head: the title on the left, the action (or the score) on the right, stacked on phones */
+.br-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 18px 32px; padding: 14px 0 4px; }
+.br-head-main { flex: 1 1 420px; min-width: 0; }
+.br-head-main h1 { margin: 6px 0 0; font-size: clamp(1.8rem, 5vw, 2.9rem); font-weight: 800; letter-spacing: -.03em; line-height: 1.06; overflow-wrap: anywhere; text-wrap: balance; }
+.br-head-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin: 0; color: var(--text-muted, #7386a3); font-size: .86rem; }
+.br-head-meta a { color: var(--room-strong); }
+.br-head-act { flex: 0 1 300px; display: grid; gap: 8px; justify-items: start; }
+
+/* Facts, environment and totals: label over value, in a wrapping grid */
+.br-facts, .br-env, .br-totals { display: grid; gap: 10px; margin: 22px 0 0; }
+.br-facts { grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr)); }
+.br-env { grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); margin-top: 12px; }
+.br-facts > div, .br-env > div { padding: 12px 14px; border-radius: 14px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); min-width: 0; }
+.br-facts dt, .br-env dt, .br-totals dt { font-size: .7rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted, #7386a3); }
+.br-facts dd, .br-env dd, .br-totals dd { margin: 4px 0 0; font-weight: 650; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
+.br-env dd a { color: var(--room-strong); }
+.br-totals { grid-template-columns: repeat(3, auto); justify-content: start; gap: 4px 22px; margin-top: 12px; }
+
+/* A score out of 100, its thin bar under it */
+.br-score { display: inline-flex; flex-wrap: wrap; align-items: baseline; column-gap: 2px; min-width: 92px; font-variant-numeric: tabular-nums; }
+.br-score-n { font-weight: 800; font-size: 1rem; }
+.br-score-of { font-size: .74rem; color: var(--text-muted, #7386a3); }
+.br-bar { flex: 0 0 100%; display: block; height: 4px; margin-top: 4px; border-radius: 999px; background: color-mix(in srgb, var(--text-muted, #7386a3) 22%, transparent); overflow: hidden; }
+.br-bar > span { display: block; height: 100%; border-radius: inherit; background: var(--room-accent); }
+.br-score.is-big { min-width: 200px; }
+.br-score.is-big .br-score-n { font-size: clamp(3rem, 9vw, 4.4rem); line-height: .95; letter-spacing: -.04em; }
+.br-score.is-big .br-score-of { font-size: 1rem; }
+.br-score.is-big .br-bar { height: 6px; margin-top: 10px; }
+.br-head-score { flex: 0 1 auto; }
+
+/* Verified / submitted */
+.br-prov { display: inline-flex; align-items: center; gap: 5px; padding: 2px 9px; border-radius: 999px; font-size: .74rem; font-weight: 750; white-space: nowrap; }
+.br-prov.is-verified { background: color-mix(in srgb, var(--success, #22c55e) 15%, transparent); color: var(--success, #22c55e); }
+.br-prov.is-verified::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
+.br-prov.is-submitted { border: 1px solid var(--border, #1f2d47); color: var(--text-muted, #7386a3); }
+
+/* Rank-by tabs: links, so every metric has its own URL */
+.br-tabs { display: flex; flex-wrap: wrap; gap: 4px; padding: 3px; border-radius: 999px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); }
+.br-tab { display: inline-flex; align-items: center; min-height: 34px; padding: 0 13px; border-radius: 999px; font-size: .86rem; font-weight: 700; color: var(--text-secondary, #96a7c2) !important; text-decoration: none; }
+.br-tab:hover { color: var(--text-primary, #e6edf7) !important; }
+.br-tab[aria-current="page"] { background: var(--room-fill); color: var(--room-on) !important; }
+.br-tab:focus-visible, .br-filter:focus-visible { outline: 2px solid var(--room-accent); outline-offset: 2px; }
+
+/* The value chart */
+.br-chart { margin: 4px 0 16px; padding: 14px 14px 10px; border-radius: 18px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); }
+.br-chart svg { display: block; width: 100%; height: auto; overflow: visible; }
+.br-chart figcaption { margin-top: 6px; font-size: .82rem; color: var(--text-muted, #7386a3); }
+.br-grid { stroke: var(--border, #1f2d47); stroke-width: 1; }
+.br-axis { fill: var(--text-muted, #7386a3); font-size: 11px; font-variant-numeric: tabular-nums; }
+.br-chart-empty { fill: var(--text-secondary, #96a7c2); font-size: 14px; font-weight: 600; }
+.br-front { fill: none; stroke: var(--room-accent); stroke-width: 2; stroke-dasharray: 5 4; opacity: .8; }
+.br-dot circle { fill: var(--bg-card, #0f1729); stroke: var(--text-secondary, #96a7c2); stroke-width: 2; }
+.br-dot text { fill: var(--text-secondary, #96a7c2); font-size: 12px; font-weight: 600; paint-order: stroke; stroke: var(--bg-card, #0f1729); stroke-width: 4px; stroke-linejoin: round; }
+.br-dot.is-front circle { fill: var(--room-accent); stroke: var(--room-accent); }
+.br-dot.is-front text { fill: var(--text-primary, #e6edf7); font-weight: 750; }
+
+/* Tables: scroll inside their own box on phones, never the page */
+.br-table-wrap { overflow-x: auto; border: 1px solid var(--border, #1f2d47); border-radius: 16px; background: var(--bg-card, #0f1729); }
+.br-table { width: 100%; border-collapse: collapse; font-size: .92rem; }
+.br-table th, .br-table td { padding: 11px 14px; text-align: left; border-bottom: 1px solid var(--border, #1f2d47); vertical-align: middle; }
+.br-table tbody tr:last-child > * { border-bottom: 0; }
+.br-table thead th { font-size: .7rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted, #7386a3); white-space: nowrap; }
+.br-table tbody th { font-weight: 650; color: var(--text-secondary, #96a7c2); white-space: nowrap; }
+.br-num { text-align: right !important; font-variant-numeric: tabular-nums; white-space: nowrap; }
+.br-rank { width: 2.5em; color: var(--text-muted, #7386a3); font-variant-numeric: tabular-nums; }
+.br-model { font-weight: 750; color: var(--text-primary, #e6edf7) !important; text-decoration: none; overflow-wrap: anywhere; }
+.br-model:hover { color: var(--room-strong) !important; }
+.br-table td.is-best { color: var(--room-strong); font-weight: 800; }
+.br-table a { color: var(--room-strong); }
+
+/* Run lists */
+.br-runs { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
+.br-run { display: flex; align-items: center; gap: 10px; padding: 4px 12px 4px 4px; border-radius: 14px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); min-width: 0; }
+.br-run:hover { border-color: color-mix(in srgb, var(--room-accent) 55%, var(--border, #1f2d47)); }
+.br-run-link { flex: 1; display: flex; align-items: center; justify-content: space-between; gap: 14px; min-height: 52px; padding: 6px 10px; color: inherit !important; text-decoration: none; min-width: 0; }
+.br-run-main { display: grid; gap: 2px; min-width: 0; }
+.br-run-model { font-weight: 750; overflow-wrap: anywhere; }
+.br-run-sub { font-size: .82rem; color: var(--text-muted, #7386a3); overflow-wrap: anywhere; }
+
+/* Tasks */
+.br-tasks, .br-ptasks { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
+.br-task { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 12px; align-items: start; padding: 14px; border-radius: 14px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); }
+.br-task p { margin: 0; line-height: 1.55; color: var(--text-secondary, #96a7c2); }
+.br-task.is-hidden { border-style: dashed; background: transparent; }
+.br-task-id { display: inline-flex; padding: 2px 8px; border-radius: 8px; background: var(--bg-hover, rgba(255,255,255,.05)); font-size: .78rem; font-weight: 700; color: var(--text-primary, #e6edf7); white-space: nowrap; margin: 0; }
+.br-ptask { display: grid; gap: 10px; padding: 14px; border-radius: 16px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); min-width: 0; }
+.br-ptask-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; }
+.br-ptask-meta { margin-left: auto; font-size: .84rem; color: var(--text-muted, #7386a3); font-variant-numeric: tabular-nums; }
+.br-ptask-prompt { margin: 0; color: var(--text-secondary, #96a7c2); line-height: 1.55; }
+
+/* Outputs: live frames from the render origin */
+.br-outs { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }
+.br-out { margin: 0; display: grid; gap: 6px; min-width: 0; }
+.br-out-frame, .br-out-img { width: 100%; max-width: 100%; aspect-ratio: 4 / 3; border: 1px solid var(--border, #1f2d47); border-radius: 12px; background: #fff; display: block; }
+.br-out-img { object-fit: contain; background: var(--bg-primary, #0a0f1c); }
+.br-out figcaption { font-size: .76rem; color: var(--text-muted, #7386a3); }
+.br-out-link { font-size: .86rem; overflow-wrap: anywhere; color: var(--room-strong); }
+
+/* Where a run sits among its model's runs */
+.br-pct { display: grid; gap: 8px; margin-top: 18px; padding: 14px 16px; border-radius: 16px; background: color-mix(in srgb, var(--room-accent) 8%, var(--bg-card, #0f1729)); border: 1px solid color-mix(in srgb, var(--room-accent) 24%, transparent); }
+.br-pct p { margin: 0; line-height: 1.5; }
+.br-pct-strip { position: relative; height: 8px; border-radius: 999px; background: linear-gradient(90deg, color-mix(in srgb, var(--text-muted, #7386a3) 25%, transparent), color-mix(in srgb, var(--room-accent) 45%, transparent)); }
+.br-pct-strip > span { position: absolute; top: 50%; width: 16px; height: 16px; margin: -8px 0 0 -8px; border-radius: 50%; background: var(--room-accent); border: 3px solid var(--bg-card, #0f1729); }
+
+/* Benchmark cards */
+.br-cards { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); }
+.br-card { min-width: 0; }
+.br-card-link { height: 100%; display: grid; align-content: start; gap: 8px; padding: 16px; border-radius: 18px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); color: inherit !important; text-decoration: none; transition: border-color .18s ease, transform .18s ease; }
+.br-card-link:hover { border-color: color-mix(in srgb, var(--room-accent) 60%, var(--border, #1f2d47)); transform: translateY(-1px); }
+.br-card-link:focus-visible { outline: 2px solid var(--room-accent); outline-offset: 2px; }
+.br-card-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
+.br-card-v { font-size: .76rem; color: var(--text-muted, #7386a3); font-variant-numeric: tabular-nums; }
+.br-card-title { font-size: 1.08rem; font-weight: 800; letter-spacing: -.01em; }
+.br-card-desc { color: var(--text-secondary, #96a7c2); font-size: .9rem; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
+.br-card-foot { font-size: .8rem; color: var(--text-muted, #7386a3); }
+@media (prefers-reduced-motion: reduce) { .br-card-link { transition: none; } .br-card-link:hover { transform: none; } }
+
+/* Search and filters */
+.br-search { display: flex; gap: 8px; max-width: 560px; }
+.br-search input { flex: 1; min-width: 0; min-height: 44px; padding: 0 14px; border-radius: 999px; border: 1px solid var(--border, #1f2d47); background: var(--bg-input, var(--bg-card, #0f1729)); color: var(--text-primary, #e6edf7); font: inherit; }
+.br-search input:focus-visible { outline: 2px solid var(--room-accent); outline-offset: 1px; }
+.br-search .bm-btn { min-height: 44px; }
+.br-filters { display: flex; flex-wrap: wrap; gap: 6px; margin: 14px 0 18px; }
+.br-filter { display: inline-flex; align-items: center; min-height: 36px; padding: 0 14px; border-radius: 999px; border: 1px solid var(--border, #1f2d47); color: var(--text-secondary, #96a7c2) !important; text-decoration: none; font-size: .88rem; font-weight: 650; text-transform: capitalize; }
+.br-filter[aria-current="page"] { background: var(--room-fill); border-color: transparent; color: var(--room-on) !important; }
+
+/* Empty states: one line of what, one line of why, one way forward */
+.br-empty { display: grid; justify-items: start; gap: 6px; padding: 18px; border-radius: 16px; border: 1px dashed var(--border, #1f2d47); color: var(--text-secondary, #96a7c2); }
+.br-empty p { margin: 0; line-height: 1.5; }
+.br-empty-t { font-weight: 750; color: var(--text-primary, #e6edf7); }
+.br-api { margin-top: 28px; }
+.br-again .bm-actions { margin-top: 10px; }
+
+/* Compare */
+.br-cmp thead th { text-transform: none; letter-spacing: 0; font-size: .92rem; color: var(--text-primary, #e6edf7); vertical-align: top; }
+.br-cmp thead th a { font-weight: 800; }
+.br-cmp-sub { display: block; margin: 2px 0 6px; font-size: .78rem; font-weight: 500; color: var(--text-muted, #7386a3); }
+.br-cmp-row { display: grid; gap: 8px; margin-top: 14px; }
+.br-cmp-outs { display: grid; gap: 10px; grid-template-columns: repeat(var(--n, 2), minmax(0, 1fr)); }
+.br-cmp-out { min-width: 0; }
+@media (max-width: 720px) { .br-cmp-outs { grid-template-columns: minmax(0, 1fr); } }
+
+/* ---- The showcase: two models, one prompt, live frames side by side. Classes start with sc-. ---------------- */
+.sc-showcase { max-width: 1180px; margin: 0 auto; padding: clamp(20px, 4vw, 40px) 16px 64px; }
+.sc-showcase > h1 { margin: 0; font-size: clamp(1.8rem, 5vw, 2.8rem); font-weight: 800; letter-spacing: -.03em; line-height: 1.08; text-wrap: balance; }
+.sc-lede { margin: 10px 0 24px; max-width: 680px; color: var(--text-secondary, #96a7c2); line-height: 1.55; }
+.sc-pairs { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 520px), 1fr)); }
+.sc-pair { display: grid; gap: 12px; padding: 14px; border-radius: 20px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); min-width: 0; }
+.sc-pair-prompt { margin: 0; font-size: .98rem; font-weight: 650; line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
+.sc-pair-slots, .sc-round-panes { display: grid; gap: 10px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
+.sc-round-panes { gap: 14px; margin-top: 16px; }
+@media (max-width: 560px) { .sc-pair-slots, .sc-round-panes { grid-template-columns: minmax(0, 1fr); } }
+.sc-pane { margin: 0; display: grid; gap: 6px; min-width: 0; }
+.sc-pane figcaption { display: flex; justify-content: space-between; align-items: center; font-size: .78rem; font-weight: 700; color: var(--text-muted, #7386a3); }
+.sc-pane-label { letter-spacing: .04em; text-transform: uppercase; }
+.sc-pane-clock { font-variant-numeric: tabular-nums; }
+.sc-pane-frame { width: 100%; max-width: 100%; aspect-ratio: 4 / 3; border: 1px solid var(--border, #1f2d47); border-radius: 12px; background: #fff; display: block; }
+.sc-round .sc-pane-frame { aspect-ratio: 16 / 11; }
+.sc-pane-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(90px, 1fr)); gap: 6px; margin: 4px 0 0; font-size: .82rem; }
+.sc-pane-facts dt { color: var(--text-muted, #7386a3); font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 800; }
+.sc-pane-facts dd { margin: 2px 0 0; font-weight: 650; overflow-wrap: anywhere; }
+.sc-pair-meta, .sc-round-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin: 0; font-size: .86rem; color: var(--text-muted, #7386a3); }
+.sc-round-meta { margin-top: 10px; }
+.sc-kind { padding: 2px 10px; border-radius: 999px; background: color-mix(in srgb, var(--room-accent) 14%, transparent); color: var(--room-strong); font-weight: 700; }
+.sc-votes { font-variant-numeric: tabular-nums; }
+.sc-pair-link { margin-left: auto; font-weight: 750; color: var(--room-strong) !important; text-decoration: none; }
+.sc-pair-link:hover { text-decoration: underline; }
+.sc-round-prompt { font-size: clamp(1.3rem, 3.6vw, 2rem) !important; line-height: 1.25 !important; letter-spacing: -.015em !important; }
+.sc-vote { margin-top: 18px; padding: 16px; border-radius: 18px; background: var(--bg-card, #0f1729); border: 1px solid var(--border, #1f2d47); display: grid; gap: 12px; }
+.sc-vote p { margin: 0; }
+.sc-vote fieldset { margin: 0; padding: 0; border: 0; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
+.sc-vote legend { width: 100%; margin-bottom: 8px; font-weight: 800; }
+.sc-vote label { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 16px; border-radius: 999px; border: 1px solid var(--border, #1f2d47); cursor: pointer; font-weight: 650; }
+.sc-vote label:has(input:checked) { border-color: var(--room-accent); background: color-mix(in srgb, var(--room-accent) 14%, transparent); }
+.sc-vote input[type="radio"], .sc-vote input[type="checkbox"] { accent-color: var(--room-accent); }
+.sc-vote button { justify-self: start; min-height: 44px; padding: 0 20px; border: 0; border-radius: 999px; background: var(--room-fill); color: var(--room-on); font: inherit; font-weight: 750; cursor: pointer; }
+.sc-vote a { color: var(--room-strong); font-weight: 700; }
+.sc-empty { color: var(--text-muted, #7386a3); }
@@ -320,9 +320,16 @@ function createRegistry(s, { log = console } = {}) {
@@ -320,9 +320,16 @@ function createRegistry(s, { log = console } = {}) {
}
}
/** The registry list: by kind, by tag, or by a search over the title and the description. */
/** The registry list: by kind, by tag, or by a search over the title and the description. */
- async function listBenchmarks({ kind = null, tag = null, q = null, limit = 50 } = {}) {
+ /**
+ * Benchmarks for a listing: the public ones, plus every one the `owner` owns when one is named. Unlisted and
+ * private benchmarks are never listed to anyone else (an unlisted one is reachable by its id; a private one only
+ * by its owner and the executor).
+ */
+ async function listBenchmarks({ kind = null, tag = null, q = null, limit = 50, owner = null } = {}) {
const where = [];
const where = [];
const params = [];
const params = [];
+ if (owner) { params.push(String(owner)); where.push(`(visibility = 'public' OR owner = $${params.length})`); }
+ else where.push("visibility = 'public'");
if (kind) { params.push(String(kind)); where.push(`kind = $${params.length}`); }
if (kind) { params.push(String(kind)); where.push(`kind = $${params.length}`); }
if (tag) { params.push(JSON.stringify([String(tag)])); where.push(`tags @> $${params.length}::jsonb`); }
if (tag) { params.push(JSON.stringify([String(tag)])); where.push(`tags @> $${params.length}::jsonb`); }
if (q) {
if (q) {
@@ -456,8 +463,9 @@ function createRegistry(s, { log = console } = {}) {
@@ -456,8 +463,9 @@ function createRegistry(s, { log = console } = {}) {
const params = [ref.id, wanted];
const params = [ref.id, wanted];
let sql = `SELECT * FROM bench_runs WHERE benchmark_id = $1 AND benchmark_version = ANY($2::int[])`;
let sql = `SELECT * FROM bench_runs WHERE benchmark_id = $1 AND benchmark_version = ANY($2::int[])`;
if (!includeSubmitted) sql += " AND provenance = 'verified'";
if (!includeSubmitted) sql += " AND provenance = 'verified'";
- if (harness) { params.push(JSON.stringify([String(harness)])); sql += ` AND harness->>'name' = $3`; }
- if (since) { params.push(String(since)); sql += ' AND created_at >= $4::timestamptz'; }
+ // Each filter takes the next placeholder: `since` alone is $3, not $4.
+ if (harness) { params.push(String(harness)); sql += ` AND harness->>'name' = $${params.length}`; }
+ if (since) { params.push(String(since)); sql += ` AND created_at >= $${params.length}::timestamptz`; }
const rows = await db.many(sql, params);
const rows = await db.many(sql, params);
const byModel = new Map();
const byModel = new Map();
for (const row of rows) {
for (const row of rows) {
@@ -534,9 +542,76 @@ function createRegistry(s, { log = console } = {}) {
@@ -534,9 +542,76 @@ function createRegistry(s, { log = console } = {}) {
};
};
}
}
+ /**
+ * Runs, newest first, for the pages: a benchmark's latest runs, a model's, or one person's. Without tasks: a list
+ * row needs the totals only. Submitted runs are listed (and labelled) unless `verifiedOnly`.
+ */
+ /** How many runs each benchmark has, verified and submitted: the listing's counts. */
+ async function runCounts() {
+ const rows = await db.many('SELECT benchmark_id, COUNT(*)::int AS n FROM bench_runs GROUP BY benchmark_id');
+ return new Map(rows.map((r) => [r.benchmark_id, num(r.n)]));
+ }
+
+ async function listRuns({ benchmark = null, model = null, createdBy = null, verifiedOnly = false, publicOnly = false, limit = 20 } = {}) {
+ const where = [];
+ const params = [];
+ const add = (clause, value) => { params.push(value); where.push(clause.replace('?', `$${params.length}`)); };
+ if (benchmark) {
+ const ref = parseRef(benchmark);
+ if (!ref) return [];
+ add('benchmark_id = ?', ref.id);
+ if (ref.version != null) add('benchmark_version = ?', ref.version);
+ }
+ if (model) add('model = ?', String(model));
+ if (createdBy) add('created_by = ?', String(createdBy));
+ if (verifiedOnly) where.push("provenance = 'verified'");
+ // A listing across benchmarks (a model's page) shows the public benchmarks' runs only.
+ if (publicOnly) where.push("benchmark_id IN (SELECT id FROM bench_benchmarks WHERE visibility = 'public')");
+ params.push(Math.min(100, Math.max(1, Number(limit) || 20)));
+ const rows = await db.many(
+ `SELECT * FROM bench_runs ${where.length ? `WHERE ${where.join(' AND ')}` : ''} ORDER BY created_at DESC, id DESC LIMIT $${params.length}`,
+ params);
+ return rows.map((row) => wireRun(row));
+ }
+
+ /**
+ * One model across every public benchmark it ran: per benchmark, its verified runs, the median score, cost and time, and
+ * the spread between its best and worst run. The model page reads this.
+ */
+ async function modelSummary(model) {
+ const rows = await db.many(
+ "SELECT benchmark_id, score, cost_usd, ms FROM bench_runs WHERE model = $1 AND provenance = 'verified'"
+ + " AND benchmark_id IN (SELECT id FROM bench_benchmarks WHERE visibility = 'public')",
+ [String(model || '')]);
+ const byBenchmark = new Map();
+ for (const row of rows) {
+ if (!byBenchmark.has(row.benchmark_id)) byBenchmark.set(row.benchmark_id, []);
+ byBenchmark.get(row.benchmark_id).push(row);
+ }
+ const round = (v, p) => (v == null ? null : Math.round(v * p) / p);
+ const out = [];
+ for (const [benchmarkId, list] of byBenchmark) {
+ const scores = list.map((r) => num(r.score));
+ const b = await getBenchmark(benchmarkId);
+ out.push({
+ benchmark_id: benchmarkId,
+ title: b ? b.title : benchmarkId,
+ kind: b ? b.kind : null,
+ runs: list.length,
+ score: round(median(scores), 1000),
+ best: Math.max(...scores),
+ worst: Math.min(...scores),
+ cost_usd: round(median(list.map((r) => num(r.cost_usd))), 1e6),
+ ms: round(median(list.map((r) => num(r.ms))), 1),
+ });
+ }
+ out.sort((a, b) => b.runs - a.runs || a.title.localeCompare(b.title));
+ return { model: String(model || ''), runs: rows.length, benchmarks: out };
+ }
+
return {
return {
createBenchmark, getBenchmark, getVersion, latestVersion, getDefinition, saveDraft, freezeVersion,
createBenchmark, getBenchmark, getVersion, latestVersion, getDefinition, saveDraft, freezeVersion,
- forkBenchmark, listBenchmarks, publishRun, getRun, compareRuns, rankings, percentile,
+ forkBenchmark, listBenchmarks, publishRun, getRun, compareRuns, rankings, percentile, listRuns, modelSummary, runCounts,
};
};
}
}
@@ -25,6 +25,8 @@ function load(env = process.env) {
@@ -25,6 +25,8 @@ function load(env = process.env) {
nodeEnv,
nodeEnv,
isProduction,
isProduction,
baseUrl,
baseUrl,
+ // "Run it yourself" on a benchmark page opens this openvibe.codes page (stage B3); unset, the page offers the API.
+ codesRunUrl: env.CODES_BENCH_RUN_URL ? trim(env.CODES_BENCH_RUN_URL) : null,
trustProxy: env.TRUST_PROXY != null ? Number(env.TRUST_PROXY) : 2,
trustProxy: env.TRUST_PROXY != null ? Number(env.TRUST_PROXY) : 2,
drill: env.BENCH_DRILL === '1' || env.BENCH_DRILL === 'true',
drill: env.BENCH_DRILL === '1' || env.BENCH_DRILL === 'true',
limits: {
limits: {
@@ -11,6 +11,7 @@ const { createDiscoveryRoutes, homeJsonLd } = require('./discovery');
@@ -11,6 +11,7 @@ const { createDiscoveryRoutes, homeJsonLd } = require('./discovery');
const { raw } = require('../render/html');
const { raw } = require('../render/html');
const { send } = require('../render/layout');
const { send } = require('../render/layout');
const views = require('../views');
const views = require('../views');
+const results = require('../views/results');
const PUBLIC_CACHE = 'public, max-age=60';
const PUBLIC_CACHE = 'public, max-age=60';
@@ -43,22 +44,129 @@ function oneGraph(nodes) {
@@ -43,22 +44,129 @@ function oneGraph(nodes) {
}
}
function createPageRoutes(ctx) {
function createPageRoutes(ctx) {
- const { config, bench } = ctx;
+ const { config, bench, registry } = ctx;
const r = asyncRouter();
const r = asyncRouter();
const base = () => String(config.baseUrl).replace(/\/+$/, '');
const base = () => String(config.baseUrl).replace(/\/+$/, '');
const page = (req, res, o, status = 200) => send(res, status, { viewer: req.viewer, config, path: req.originalUrl, ...o });
const page = (req, res, o, status = 200) => send(res, status, { viewer: req.viewer, config, path: req.originalUrl, ...o });
r.get('/', async (req, res) => {
r.get('/', async (req, res) => {
const kinds = await bench.listKinds();
const kinds = await bench.listKinds();
+ const benchmarks = await registry.listBenchmarks({ limit: 6 });
+ const counts = await registry.runCounts();
+ for (const b of benchmarks) b.runs = counts.get(b.id) || 0;
return page(req, res, {
return page(req, res, {
index: true, cache: PUBLIC_CACHE,
index: true, cache: PUBLIC_CACHE,
title: null,
title: null,
- description: 'OpenVibe.Bench is one AI benchmark and comparison engine for every room: blind votes, rubrics, graders, test suites and game outcomes, with reproducible pinned rounds and an open dataset per kind.',
+ description: 'OpenVibe.Bench shows what AI models really make: the same tasks on every model, outputs live side by side, every run published with its cost and time, free and open.',
jsonLd: oneGraph([...homeJsonLd(config), ...kinds.map((k) => datasetJsonLd(k, base())), seo.jsonLd.organization()]),
jsonLd: oneGraph([...homeJsonLd(config), ...kinds.map((k) => datasetJsonLd(k, base())), seo.jsonLd.organization()]),
- body: raw(views.home({ kinds, counts: { kinds: kinds.length } })),
+ body: raw(views.home({ kinds, counts: { kinds: kinds.length }, benchmarks })),
});
});
});
});
+ // ---- the results pages (B2) ----------------------------------------------------------------------------
+ const subjectOf = (req) => (req.viewer && req.viewer.kind === 'user' ? (req.viewer.subject || req.viewer.id || null) : null);
+ const notFound = (req, res, what) => page(req, res, { title: `No such ${what}`, body: raw(views.notFound()) }, 404);
+ const METRIC_IDS = results.METRICS.map((m) => m.id);
+
+ r.get('/benchmarks', async (req, res) => {
+ const q = String(req.query.q || '').slice(0, 80);
+ const family = String(req.query.kind || '').replace(/[^a-z0-9._-]/gi, '').slice(0, 40) || null;
+ const all = await registry.listBenchmarks({ q: q || null, limit: 200 });
+ const kinds = [...new Set(all.map((b) => b.kind).filter(Boolean))];
+ const list = family ? all.filter((b) => b.kind === family || String(b.kind).startsWith(`${family}.`)) : all;
+ const counts = await registry.runCounts();
+ for (const b of list) b.runs = counts.get(b.id) || 0;
+ return page(req, res, {
+ index: !q && !family, cache: PUBLIC_CACHE,
+ title: 'Benchmarks',
+ description: 'Versioned AI benchmarks anyone can run again: tasks, judges and limits, with every run published.',
+ jsonLd: [seo.jsonLd.webPage({ name: 'Benchmarks', url: `${base()}/benchmarks`, description: 'Versioned AI benchmarks anyone can run again.', siteUrl: base() })],
+ body: raw(String(results.benchmarksIndex({ benchmarks: list, kinds, kind: family, q }))),
+ });
+ });
+
+ r.get('/benchmarks/:ref', async (req, res) => {
+ const ref = String(req.params.ref || '');
+ const out = await registry.getDefinition(ref, { reveal: false });
+ const subject = subjectOf(req);
+ if (!out || (out.benchmark.visibility === 'private' && out.benchmark.owner !== subject)) return notFound(req, res, 'benchmark');
+ const metric = METRIC_IDS.includes(String(req.query.metric)) ? String(req.query.metric) : 'score';
+ const id = out.benchmark.id;
+ const [rankings, runs] = await Promise.all([
+ registry.rankings({ benchmark: id, metric }),
+ registry.listRuns({ benchmark: id, limit: 8 }),
+ ]);
+ const isPublic = out.benchmark.visibility === 'public';
+ return page(req, res, {
+ index: isPublic && metric === 'score', cache: isPublic ? PUBLIC_CACHE : null,
+ title: out.benchmark.title,
+ description: out.benchmark.description || `${out.benchmark.title}: rankings, value and every run.`,
+ jsonLd: [seo.jsonLd.webPage({ name: out.benchmark.title, url: `${base()}/benchmarks/${encodeURIComponent(id)}`, description: out.benchmark.description || out.benchmark.title, siteUrl: base() })],
+ body: raw(String(results.benchmarkPage({
+ benchmark: out.benchmark, definition: out.definition, version: out.version && out.version.version,
+ rankings, metric, runs, codesRunUrl: config.codesRunUrl || null,
+ }))),
+ });
+ });
+
+ r.get('/runs/:id', async (req, res) => {
+ const run = await registry.getRun(String(req.params.id || ''));
+ if (!run) return notFound(req, res, 'run');
+ const def = await registry.getDefinition(`${run.benchmark_id}@${run.benchmark_version}`, { reveal: false });
+ const benchmark = def ? def.benchmark : null;
+ if (benchmark && benchmark.visibility === 'private' && benchmark.owner !== subjectOf(req)) return notFound(req, res, 'run');
+ const pct = run.score != null ? await registry.percentile({ benchmark: run.benchmark_id, model: run.model, score: run.score }) : null;
+ const isPublic = !benchmark || benchmark.visibility === 'public';
+ return page(req, res, {
+ index: isPublic && run.provenance === 'verified', cache: isPublic ? PUBLIC_CACHE : null,
+ title: `${run.model} on ${benchmark ? benchmark.title : run.benchmark_id}`,
+ description: `${run.model} scored ${results.fmtScore(run.score)} out of 100 on ${benchmark ? benchmark.title : 'this benchmark'}, for ${results.fmtUsd(run.cost_usd)}.`,
+ body: raw(String(results.runPage({ run, benchmark, definition: def && def.definition, pct }))),
+ });
+ });
+
+ r.get('/compare', async (req, res) => {
+ const refs = String(req.query.runs || '').split(',').map((x) => x.trim()).filter(Boolean).slice(0, 4);
+ let cmp = refs.length ? await registry.compareRuns(refs) : null;
+ const titles = {};
+ if (cmp) {
+ const subject = subjectOf(req);
+ const keep = [];
+ for (const run of cmp.runs) {
+ const b = await registry.getBenchmark(run.benchmark_id);
+ if (b && b.visibility === 'private' && b.owner !== subject) continue;
+ if (b) titles[b.id] = b.title;
+ keep.push(run);
+ }
+ cmp = keep.length ? { ...cmp, runs: keep, rows: cmp.rows.map((row) => ({ ...row, scores: keep.map((run) => { const t = run.tasks.find((x) => x.task_id === row.task_id); return t ? t.score : null; }) })) } : null;
+ }
+ return page(req, res, {
+ index: false, cache: PUBLIC_CACHE,
+ title: cmp ? `Compare: ${cmp.runs.map((x) => x.model).join(' vs ')}` : 'Compare runs',
+ description: 'Runs side by side: the same tasks, their scores, cost, time and outputs.',
+ body: raw(String(results.comparePage({ cmp, titles }))),
+ });
+ });
+
+ r.get('/models/:model', async (req, res) => {
+ const model = String(req.params.model || '').slice(0, 160);
+ const [summary, runs] = await Promise.all([
+ registry.modelSummary(model),
+ registry.listRuns({ model, publicOnly: true, limit: 12 }),
+ ]);
+ const titles = {};
+ for (const b of summary.benchmarks) titles[b.benchmark_id] = b.title;
+ for (const run of runs) {
+ if (!titles[run.benchmark_id]) { const b = await registry.getBenchmark(run.benchmark_id); if (b) titles[b.id] = b.title; }
+ }
+ return page(req, res, {
+ index: summary.runs > 0, cache: PUBLIC_CACHE,
+ title: model,
+ description: `${model} across OpenVibe.Bench: its median score, spread, cost and time on every benchmark it ran.`,
+ body: raw(String(results.modelPage({ model, summary, runs, titles }))),
+ }, summary.runs > 0 || runs.length ? 200 : 404);
+ });
+
r.get('/docs', (req, res) => page(req, res, {
r.get('/docs', (req, res) => page(req, res, {
index: true, cache: PUBLIC_CACHE,
index: true, cache: PUBLIC_CACHE,
title: 'The Bench API',
title: 'The Bench API',
@@ -129,7 +129,10 @@ function createRegistryApi(ctx) {
@@ -129,7 +129,10 @@ function createRegistryApi(ctx) {
r.get('/benchmarks', async (req, res) => {
r.get('/benchmarks', async (req, res) => {
try {
try {
+ // ?mine=1 adds the caller's own unlisted and private benchmarks; nobody else ever sees those in a list.
+ const mine = req.query.mine && req.principal && req.principal.kind === 'user' ? req.principal.subject : null;
const list = await registry.listBenchmarks({
const list = await registry.listBenchmarks({
+ owner: mine,
kind: req.query.kind ? String(req.query.kind) : null,
kind: req.query.kind ? String(req.query.kind) : null,
tag: req.query.tag ? String(req.query.tag) : null,
tag: req.query.tag ? String(req.query.tag) : null,
q: req.query.q ? String(req.query.q) : null,
q: req.query.q ? String(req.query.q) : null,
@@ -151,7 +154,9 @@ function createRegistryApi(ctx) {
@@ -151,7 +154,9 @@ function createRegistryApi(ctx) {
}
}
const out = await registry.getDefinition(ref, { reveal });
const out = await registry.getDefinition(ref, { reveal });
if (!out) return problem(res, 404, 'bench.benchmark_not_found', 'No such benchmark.');
if (!out) return problem(res, 404, 'bench.benchmark_not_found', 'No such benchmark.');
- res.set('Cache-Control', 'public, max-age=60');
+ // A private benchmark answers only its owner and the executor; to everyone else it does not exist.
+ if (out.benchmark.visibility === 'private' && !reveal) return problem(res, 404, 'bench.benchmark_not_found', 'No such benchmark.');
+ res.set('Cache-Control', out.benchmark.visibility === 'public' ? 'public, max-age=60' : 'private, no-store');
return res.json({
return res.json({
benchmark: out.benchmark,
benchmark: out.benchmark,
version: { ...out.version, definition: out.definition },
version: { ...out.version, definition: out.definition },
@@ -28,7 +28,7 @@ function createRenderRoutes(ctx) {
@@ -28,7 +28,7 @@ function createRenderRoutes(ctx) {
function bare(res) {
function bare(res) {
res.removeHeader('Set-Cookie');
res.removeHeader('Set-Cookie');
res.removeHeader('X-Frame-Options'); // helmet's DENY; frame-ancestors in each response's CSP names who may frame it
res.removeHeader('X-Frame-Options'); // helmet's DENY; frame-ancestors in each response's CSP names who may frame it
- res.set('Cache-Control', 'no-store');
+ res.set('Cache-Control', 'no-store, no-transform'); // no-transform: Cloudflare injects no analytics beacon (the frame's CSP refuses it)
res.set('X-Content-Type-Options', 'nosniff');
res.set('X-Content-Type-Options', 'nosniff');
res.set('Referrer-Policy', 'no-referrer');
res.set('Referrer-Policy', 'no-referrer');
return res;
return res;
@@ -129,7 +129,7 @@ async function loadStats(ctx) {
@@ -129,7 +129,7 @@ async function loadStats(ctx) {
total_cost_usd: Math.round(totalCost * 1e6) / 1e6,
total_cost_usd: Math.round(totalCost * 1e6) / 1e6,
cost_per_entry_usd: entries ? Math.round((totalCost / entries) * 1e6) / 1e6 : null,
cost_per_entry_usd: entries ? Math.round((totalCost / entries) * 1e6) / 1e6 : null,
median_cost_usd: c.median_cost == null ? null : num(c.median_cost),
median_cost_usd: c.median_cost == null ? null : num(c.median_cost),
- median_ms: c.medemon_ms == null ? null : num(c.median_ms),
+ median_ms: c.median_ms == null ? null : num(c.median_ms),
p95_ms: c.p95_ms == null ? null : num(c.p95_ms),
p95_ms: c.p95_ms == null ? null : num(c.p95_ms),
tokens_per_entry: entries ? Math.round(num(c.tokens) / entries) : 0,
tokens_per_entry: entries ? Math.round(num(c.tokens) / entries) : 0,
error_rate: entries ? num(c.errors) / entries : 0,
error_rate: entries ? num(c.errors) / entries : 0,
@@ -19,6 +19,8 @@ const TAGLINE = 'One AI benchmark and comparison engine for every room.';
@@ -19,6 +19,8 @@ const TAGLINE = 'One AI benchmark and comparison engine for every room.';
const PUBLIC_DIR = path.join(__dirname, '..', '..', 'public');
const PUBLIC_DIR = path.join(__dirname, '..', '..', 'public');
const NAV = [
const NAV = [
{ label: 'Home', href: '/' },
{ label: 'Home', href: '/' },
+ { label: 'Benchmarks', href: '/benchmarks' },
+ { label: 'Showcase', href: '/showcase' },
{ label: 'Docs', href: '/docs' },
{ label: 'Docs', href: '/docs' },
];
];
@@ -44,7 +46,7 @@ function renderPage(o) {
@@ -44,7 +46,7 @@ function renderPage(o) {
const nav = {
const nav = {
service: 'bench',
service: 'bench',
apiBase: NETWORK_URL,
apiBase: NETWORK_URL,
- links: NAV.map((l) => ({ label: l.label, href: l.href, active: pathNow === l.href || pathNow.startsWith(`${l.href}/`) })),
+ links: NAV.map((l) => ({ label: l.label, href: l.href, active: l.href === '/' ? pathNow === '/' : (pathNow.split('?')[0] === l.href || pathNow.startsWith(`${l.href}/`) || (l.href === '/benchmarks' && /^\/(runs|models|compare)(\/|\?|$)/.test(pathNow))) })),
history: { type: 'page', title: o.title || SITE_NAME },
history: { type: 'page', title: o.title || SITE_NAME },
silentLogin: `${o.config.baseUrl}/auth/login?silent=1&next={url}`,
silentLogin: `${o.config.baseUrl}/auth/login?silent=1&next={url}`,
sessionUrl: '/auth/me',
sessionUrl: '/auth/me',
@@ -1,8 +1,8 @@
@@ -1,8 +1,8 @@
'use strict';
'use strict';
/**
/**
- * Bench's own origin pages (the main session designs them later): a plain home that says what Bench is, lists the
- * every kind and links to boards and docs, and /docs for the API. Ids and classes start with `bm-`.
+ * Bench's own origin pages: the home (what Bench shows, the newest benchmarks, the arena kinds for developers) and
+ * /docs for the API. The results pages are in ./results.js. Ids and classes start with `bm-`.
*/
*/
const { esc } = require('../render/html');
const { esc } = require('../render/html');
@@ -10,21 +10,24 @@ function kindRow(k) {
@@ -10,21 +10,24 @@ function kindRow(k) {
return `<li class="bm-kind"><a class="bm-kind-link" href="/api/v1/boards/${esc(k.id)}?type=elo">${esc(k.id)}</a><span class="bm-kind-meta">${esc(k.room)} · ${esc(k.judge)} · ${esc(k.name)}</span></li>`;
return `<li class="bm-kind"><a class="bm-kind-link" href="/api/v1/boards/${esc(k.id)}?type=elo">${esc(k.id)}</a><span class="bm-kind-meta">${esc(k.room)} · ${esc(k.judge)} · ${esc(k.name)}</span></li>`;
}
}
-function home({ kinds = [], counts = { kinds: 0 } } = {}) {
+function home({ kinds = [], counts = { kinds: 0 }, benchmarks = [] } = {}) {
+ const { benchmarkCard } = require('./results');
+ const cards = benchmarks.slice(0, 6).map((b) => String(benchmarkCard(b))).join('');
return `<div class="bm-wrap bm-home" id="bm-home">
return `<div class="bm-wrap bm-home" id="bm-home">
-<header class="bm-hero"><p class="bm-kicker">OpenVibe.Bench</p><h1>One benchmark engine for every room</h1>
-<p class="bm-lede">Put AI models side by side on real work: a page design, a game, a meme, a code fix, a web task. People vote blind, graders and tests score the rest, and every round is pinned to the exact model it ran, so anyone can run it again.</p>
-<div class="bm-actions"><a class="bm-btn" href="/docs">Read the API</a><a class="bm-btn bm-btn-quiet" href="#bm-kinds">The kinds</a></div></header>
+<header class="bm-hero"><p class="bm-kicker">OpenVibe.Bench</p><h1>See what AI really makes</h1>
+<p class="bm-lede">Every model on the same tasks: real pages, games, scenes and fixes, shown live side by side. Every run is published with what it cost and how long it took, and anyone can run it again.</p>
+<div class="bm-actions"><a class="bm-btn" href="/benchmarks">Browse benchmarks</a><a class="bm-btn bm-btn-quiet" href="/showcase">Vote in the showcase</a></div></header>
<ul class="bm-why" aria-label="What Bench promises">
<ul class="bm-why" aria-label="What Bench promises">
-<li><b>Free and open</b><span>The public arena costs nothing, and every kind's votes and results download as JSONL, without voter names.</span></li>
-<li><b>Cost per solved task</b><span>Boards rank quality against what a solved task really cost, with confidence intervals, not a single score.</span></li>
-<li><b>Every room, one engine</b><span>Design, Games, Meme, Vision, Codes, Surf, Chat and speech share one API, SDK and MCP tools.</span></li>
-<li><b>Your own evals</b><span>Private task suites on your models or keys, free up to a daily cap, never published.</span></li>
+<li><b>Outputs, not just scores</b><span>The pages, games and drawings themselves, live in sandboxed frames, next to the numbers.</span></li>
+<li><b>Every run published</b><span>Whatever it scored. No private variants, no best of ten: the service that ran it publishes it.</span></li>
+<li><b>Value you can read</b><span>Score against cost per run, with the frontier marked, so the cheapest good model is obvious.</span></li>
+<li><b>Free and open</b><span>Votes, runs and outputs download as JSONL. Versions are frozen, so every result can be repeated.</span></li>
</ul>
</ul>
-<section class="bm-section" id="bm-kinds" aria-labelledby="bm-kinds-h"><div class="bm-head-row"><h2 id="bm-kinds-h">Kinds</h2><span class="bm-count">${Number(counts.kinds) || kinds.length}</span></div>
+<section class="bm-section" aria-labelledby="bm-bench-h"><div class="bm-head-row"><h2 id="bm-bench-h">Benchmarks</h2><a class="bm-more" href="/benchmarks">All of them</a></div>
+${cards ? `<ul class="br-cards">${cards}</ul>` : '<p class="bm-muted">No benchmark is published yet.</p>'}</section>
+<section class="bm-section" id="bm-kinds" aria-labelledby="bm-kinds-h"><div class="bm-head-row"><h2 id="bm-kinds-h">For developers: the arena kinds</h2><span class="bm-count">${Number(counts.kinds) || kinds.length}</span></div>
+<p class="bm-fine">Each kind is a room's arena with its judge and entry type. Its board is JSON at <code>/api/v1/boards/:kind</code>, and the <a href="/docs">API</a> covers the rest.</p>
${kinds.length ? `<ul class="bm-kinds">${kinds.map(kindRow).join('')}</ul>` : '<p class="bm-muted">No kinds are seeded yet.</p>'}</section>
${kinds.length ? `<ul class="bm-kinds">${kinds.map(kindRow).join('')}</ul>` : '<p class="bm-muted">No kinds are seeded yet.</p>'}</section>
-<section class="bm-section" id="bm-boards"><div class="bm-head-row"><h2>Boards</h2></div>
-<p class="bm-fine">Boards are JSON at <code>/api/v1/boards/:kind?type=elo|pareto|cost</code>. Public HTML boards render in OpenVibe.Report; rooms show their own arenas through Bench.</p></section>
</div>`;
</div>`;
}
}
@@ -52,6 +55,15 @@ ${ep('POST', '/api/v1/evals', 'Create a private task suite (never in the public
@@ -52,6 +55,15 @@ ${ep('POST', '/api/v1/evals', 'Create a private task suite (never in the public
${ep('POST', '/api/v1/evals/:id/run', 'Run a private eval against chosen offers, under the free daily cap.')}
${ep('POST', '/api/v1/evals/:id/run', 'Run a private eval against chosen offers, under the free daily cap.')}
${ep('GET', '/api/v1/evals/:id/results', 'A private eval and its runs.')}
${ep('GET', '/api/v1/evals/:id/results', 'A private eval and its runs.')}
</dl></section>
</dl></section>
+<section id="br-publish"><h2>Benchmarks and runs</h2><p class="bm-fine">A benchmark is a versioned set of tasks, judges and limits; a frozen version never changes once a run names it. A run published by a service (openvibe.codes, Run, a Node worker) is <b>verified</b>; one published with a person's token is <b>submitted</b>, labelled, and never ranked by default.</p><dl class="bm-eps">
+${ep('GET', '/api/v1/benchmarks?kind=&tag=&q=&mine=1', 'The public benchmarks; <code>mine=1</code> adds your own unlisted ones.')}
+${ep('GET', '/api/v1/benchmarks/:id[@version]', 'A definition. Held-out tasks keep their prompt for the executor and the owner.')}
+${ep('POST', '/api/v1/benchmarks', 'Create one (<code>bench.benchmark.write</code>); <code>PUT</code> saves a draft, <code>POST …/versions</code> freezes it, <code>POST …/fork</code> forks it.')}
+${ep('POST', '/api/v1/runs', 'Publish a run: <code>{ benchmark: "bmk_…@N", model, provider, harness: { name, version }, executor, tasks: [{ task_id, score, cost_usd, ms, tokens, artifacts }], score, cost_usd, ms, tokens }</code>.')}
+${ep('GET', '/api/v1/runs/:id', 'A run with its tasks; <code>/api/v1/compare?runs=a,b</code> puts up to four side by side.')}
+${ep('GET', '/api/v1/rankings?benchmark=&metric=score|value|speed|consistency&harness=&since=', 'Medians per model over verified runs; value is score per dollar, speed is score per minute.')}
+${ep('GET', '/api/v1/percentile?benchmark=&model=&score=', 'Where a score sits among a model’s verified runs.')}
+</dl></section>
<section><h2>MCP</h2><p class="bm-fine"><code>POST /mcp</code> exposes <code>bench.list_kinds</code>, <code>bench.start_round</code>, <code>bench.next_pair</code>, <code>bench.cast_judgement</code>, <code>bench.get_board</code> and <code>bench.run_eval</code>.</p></section>
<section><h2>MCP</h2><p class="bm-fine"><code>POST /mcp</code> exposes <code>bench.list_kinds</code>, <code>bench.start_round</code>, <code>bench.next_pair</code>, <code>bench.cast_judgement</code>, <code>bench.get_board</code> and <code>bench.run_eval</code>.</p></section>
</div>`;
</div>`;
}
}
new file mode 100644
new file mode 100644
@@ -0,0 +1,301 @@
@@ -0,0 +1,301 @@
+'use strict';
+
+/**
+ * The results pages (stage B2): the benchmark list, a benchmark with its rankings and value chart, a run (Geekbench
+ * style: the environment, the score, where it sits, each task and its outputs), compare, and a model across
+ * benchmarks. Server-rendered and complete without JavaScript. Everything dynamic goes through html`` (escaped).
+ * Ids and classes start with `br-`.
+ */
+const { html, raw, render } = require('../render/html');
+const renderLib = require('../bench/render');
+
+const MEDIA_ORIGIN = 'https://openvibe.media';
+
+// ---- numbers -------------------------------------------------------------------------------------------------
+
+const fmtScore = (v) => (v == null ? '—' : (Math.round(Number(v) * 10) / 10).toFixed(1).replace(/\.0$/, ''));
+function fmtUsd(v) {
+ if (v == null) return '—';
+ const n = Number(v);
+ if (n === 0) return '$0';
+ if (n < 0.01) return `$${n.toPrecision(2)}`;
+ return `$${n.toFixed(2)}`;
+}
+function fmtMs(v) {
+ if (v == null) return '—';
+ const s = Number(v) / 1000;
+ if (s < 1) return `${Math.round(Number(v))} ms`;
+ if (s < 90) return `${Math.round(s * 10) / 10} s`;
+ return `${Math.round(s / 6) / 10} min`;
+}
+function fmtTokens(v) {
+ if (v == null) return '—';
+ const n = Number(v);
+ if (n >= 1e6) return `${Math.round(n / 1e5) / 10}M`;
+ if (n >= 1e3) return `${Math.round(n / 100) / 10}K`;
+ return String(n);
+}
+const fmtDate = (iso) => (iso ? html`<time datetime="${iso}">${String(iso).slice(0, 10)}</time>` : '—');
+function ordinal(n) {
+ const v = Math.round(Number(n));
+ const t = v % 100;
+ if (t >= 11 && t <= 13) return `${v}th`;
+ return `${v}${({ 1: 'st', 2: 'nd', 3: 'rd' })[v % 10] || 'th'}`;
+}
+const plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
+
+// ---- links ---------------------------------------------------------------------------------------------------
+
+const benchmarkHref = (id) => `/benchmarks/${encodeURIComponent(id)}`;
+const runHref = (id) => `/runs/${encodeURIComponent(id)}`;
+const modelHref = (m) => `/models/${encodeURIComponent(m)}`;
+const compareHref = (ids) => `/compare?runs=${ids.map(encodeURIComponent).join(',')}`;
+
+// ---- small pieces --------------------------------------------------------------------------------------------
+
+const kindChip = (kind) => (kind ? html`<span class="br-chip br-mono">${kind}</span>` : '');
+
+function provenance(p) {
+ return p === 'verified'
+ ? html`<span class="br-prov is-verified" title="Run by openvibe.codes, Run or a Node worker, and published by that service">Verified</span>`
+ : html`<span class="br-prov is-submitted" title="Published by a person; nobody re-ran it">Submitted</span>`;
+}
+
+/** A score out of 100 with a thin bar under it. */
+function scoreBar(score, { big = false } = {}) {
+ const pct = score == null ? 0 : Math.max(0, Math.min(100, Number(score)));
+ return html`<span class="br-score${big ? ' is-big' : ''}"><span class="br-score-n">${fmtScore(score)}</span><span class="br-score-of">/100</span><span class="br-bar" aria-hidden="true"><span style="width:${pct.toFixed(1)}%"></span></span></span>`;
+}
+
+function empty(title, text, action = '') {
+ return html`<div class="br-empty"><p class="br-empty-t">${title}</p><p>${text}</p>${action}</div>`;
+}
+
+function harnessLabel(h) {
+ if (!h || !h.name) return '—';
+ return h.version ? `${h.name} ${h.version}` : h.name;
+}
+
+// ---- the value chart -----------------------------------------------------------------------------------------
+
+/**
+ * Score against cost per run, one dot per model, cost on a log scale. The frontier joins the models nobody beats on
+ * both at once (no other model is cheaper and better). Drawn as SVG on the server; the table under it carries the
+ * same numbers for screen readers.
+ */
+function valueChart(entries) {
+ const W = 880; const H = 320; const L = 44; const R = 16; const T = 14; const B = 40;
+ const pts = entries.filter((e) => e.score != null && e.cost_usd != null && e.cost_usd > 0);
+ const grid = [0, 25, 50, 75, 100].map((y) => {
+ const py = T + (H - T - B) * (1 - y / 100);
+ return html`<line class="br-grid" x1="${L}" x2="${W - R}" y1="${py}" y2="${py}"/><text class="br-axis" x="${L - 8}" y="${py + 4}" text-anchor="end">${y}</text>`;
+ });
+ if (!pts.length) {
+ return html`<figure class="br-chart" aria-label="Score against cost: no verified runs yet"><svg viewBox="0 0 ${W} ${H}" role="img" preserveAspectRatio="xMidYMid meet">${grid}<text class="br-axis" x="${(L + W - R) / 2}" y="${H - 8}" text-anchor="middle">Cost per run (log scale)</text><text class="br-chart-empty" x="${(L + W - R) / 2}" y="${(T + H - B) / 2}" text-anchor="middle">The chart fills in with the first verified runs</text></svg></figure>`;
+ }
+ const costs = pts.map((p) => Math.log10(p.cost_usd));
+ let lo = Math.floor(Math.min(...costs)); let hi = Math.ceil(Math.max(...costs));
+ if (hi === lo) { lo -= 1; hi += 1; }
+ const x = (c) => L + (W - L - R) * ((Math.log10(c) - lo) / (hi - lo));
+ const y = (s) => T + (H - T - B) * (1 - s / 100);
+ const ticks = [];
+ for (let e = lo; e <= hi; e++) {
+ const px = L + (W - L - R) * ((e - lo) / (hi - lo));
+ ticks.push(html`<text class="br-axis" x="${px}" y="${H - B + 18}" text-anchor="middle">${fmtUsd(10 ** e)}</text>`);
+ }
+ // The frontier: walk from the cheapest up, keeping each model that scores higher than every cheaper one.
+ const sorted = [...pts].sort((a, b) => a.cost_usd - b.cost_usd || b.score - a.score);
+ const frontier = [];
+ let best = -Infinity;
+ for (const p of sorted) if (p.score > best) { frontier.push(p); best = p.score; }
+ const onFrontier = new Set(frontier.map((p) => p.model));
+ let path = '';
+ frontier.forEach((p, i) => {
+ const px = x(p.cost_usd).toFixed(1); const py = y(p.score).toFixed(1);
+ if (i === 0) path += `M${px} ${py}`;
+ else path += ` H${px} V${py}`;
+ });
+ // Labels sit beside their dot; one that would overlap a label already placed moves down (or up) by a line.
+ const placed = [];
+ const labelY = (px, py, anchor) => {
+ const w = 7 * 22; const x0 = anchor === 'end' ? px - w : px; let ly = py + 4;
+ for (let tries = 0; tries < 6; tries++) {
+ const hit = placed.find((b) => Math.abs(b.y - ly) < 13 && x0 < b.x0 + b.w && b.x0 < x0 + w);
+ if (!hit) break;
+ ly = hit.y + (ly >= hit.y ? 13 : -13);
+ }
+ placed.push({ x0, w, y: ly });
+ return ly;
+ };
+ const dots = [...pts].sort((a, b) => b.score - a.score).map((p) => {
+ const px = x(p.cost_usd); const py = y(p.score);
+ const anchor = px > W - 180 ? 'end' : 'start';
+ const dx = anchor === 'end' ? -9 : 9;
+ const ly = labelY(px + dx, py, anchor);
+ return html`<g class="br-dot${onFrontier.has(p.model) ? ' is-front' : ''}"><circle cx="${px.toFixed(1)}" cy="${py.toFixed(1)}" r="5"><title>${p.model}: ${fmtScore(p.score)} for ${fmtUsd(p.cost_usd)} a run</title></circle><text x="${(px + dx).toFixed(1)}" y="${ly.toFixed(1)}" text-anchor="${anchor}">${p.model}</text></g>`;
+ });
+ return html`<figure class="br-chart" aria-label="Score against cost per run; the line is the frontier"><svg viewBox="0 0 ${W} ${H}" role="img" preserveAspectRatio="xMidYMid meet">${grid}${ticks}<text class="br-axis" x="${(L + W - R) / 2}" y="${H - 4}" text-anchor="middle">Cost per run (log scale)</text>${path ? raw(`<path class="br-front" d="${path}"/>`) : ''}${dots}</svg><figcaption>Up is better, left is cheaper. The line joins the models no other model beats on both.</figcaption></figure>`;
+}
+
+// ---- the rankings table --------------------------------------------------------------------------------------
+
+const METRICS = [
+ { id: 'score', label: 'Score' },
+ { id: 'value', label: 'Value', hint: 'score per dollar' },
+ { id: 'speed', label: 'Speed', hint: 'score per minute' },
+ { id: 'consistency', label: 'Steadiness', hint: 'spread inside a session, lower is steadier' },
+];
+
+function metricTabs(base, current) {
+ return html`<nav class="br-tabs" aria-label="Rank by">${METRICS.map((m) => html`<a class="br-tab" href="${base}?metric=${m.id}#br-rank"${m.id === current ? raw(' aria-current="page"') : ''}${m.hint ? raw(` title="${m.hint}"`) : ''}>${m.label}</a>`)}</nav>`;
+}
+
+function rankingsTable(entries, metric) {
+ if (!entries.length) return '';
+ const col = { value: (e) => (e.value == null ? '—' : `${fmtScore(e.value)} / $`), speed: (e) => (e.speed == null ? '—' : `${fmtScore(e.speed)} / min`), consistency: (e) => (e.consistency == null ? '—' : `±${fmtScore(e.consistency)}`) }[metric];
+ return html`<div class="br-table-wrap"><table class="br-table"><thead><tr><th scope="col">#</th><th scope="col">Model</th><th scope="col">Score</th>${col ? html`<th scope="col">${METRICS.find((m) => m.id === metric).label}</th>` : ''}<th scope="col" class="br-num">Cost / run</th><th scope="col" class="br-num">Time</th><th scope="col" class="br-num">Runs</th></tr></thead><tbody>${entries.map((e, i) => html`<tr><td class="br-rank">${i + 1}</td><td><a class="br-model" href="${modelHref(e.model)}">${e.model}</a></td><td>${scoreBar(e.score)}</td>${col ? html`<td class="br-num">${col(e)}</td>` : ''}<td class="br-num">${fmtUsd(e.cost_usd)}</td><td class="br-num">${fmtMs(e.ms)}</td><td class="br-num">${e.runs}</td></tr>`)}</tbody></table></div>`;
+}
+
+// ---- runs list -----------------------------------------------------------------------------------------------
+
+function runsList(runs, { showBenchmark = false, titles = {} } = {}) {
+ if (!runs.length) return '';
+ return html`<ul class="br-runs">${runs.map((r) => html`<li class="br-run"><a class="br-run-link" href="${runHref(r.id)}"><span class="br-run-main"><span class="br-run-model">${r.model}</span><span class="br-run-sub">${showBenchmark ? html`${titles[r.benchmark_id] || r.benchmark_id} · ` : ''}${harnessLabel(r.harness)} · ${fmtDate(r.created_at)}</span></span>${scoreBar(r.score)}</a>${provenance(r.provenance)}</li>`)}</ul>`;
+}
+
+// ---- outputs -------------------------------------------------------------------------------------------------
+
+/** An output: a live frame when it is ours to frame (the render origin), a picture from Media, else a plain link. */
+function artifact(a, label) {
+ const url = String(a.url || '');
+ if (url.startsWith(`${renderLib.RENDER_ORIGIN}/render/`)) {
+ return html`<figure class="br-out"><iframe class="br-out-frame" src="${url}" title="${label}" sandbox="${renderLib.WRAPPER_SANDBOX}" referrerpolicy="no-referrer" loading="lazy"></iframe><figcaption>${a.kind}</figcaption></figure>`;
+ }
+ if (url.startsWith(`${MEDIA_ORIGIN}/`) && /^(image|screenshot|png|jpeg|webp)$/i.test(String(a.kind))) {
+ return html`<figure class="br-out"><img class="br-out-img" src="${url}" alt="${label}" loading="lazy"><figcaption>${a.kind}</figcaption></figure>`;
+ }
+ if (/^https:\/\//.test(url)) return html`<a class="br-out-link" href="${url}" rel="noopener nofollow ugc">${a.kind}: ${url.replace(/^https:\/\//, '').slice(0, 60)}</a>`;
+ return html`<span class="br-out-link">${a.kind}</span>`;
+}
+
+// ---- pages ---------------------------------------------------------------------------------------------------
+
+function benchmarksIndex({ benchmarks = [], kinds = [], kind = null, q = '' } = {}) {
+ const families = [...new Set(kinds.map((k) => String(k).split('.')[0]))].sort();
+ const chip = (label, value) => {
+ const on = (value || null) === (kind || null);
+ const href = value ? `/benchmarks?kind=${encodeURIComponent(value)}` : '/benchmarks';
+ return html`<a class="br-filter" href="${href}"${on ? raw(' aria-current="page"') : ''}>${label}</a>`;
+ };
+ return html`<div class="bm-wrap br" id="br-benchmarks">
+<header class="bm-page-h"><p class="bm-kicker">Benchmarks</p><h1>Benchmarks anyone can run again</h1>
+<p class="bm-lede">Each one is a versioned set of tasks with its judges and limits. A version never changes once a run names it, so every score here can be repeated.</p></header>
+<form class="br-search" method="get" action="/benchmarks" role="search"><label class="br-sr" for="br-q">Search benchmarks</label><input id="br-q" name="q" type="search" value="${q}" placeholder="Search by title, tag or kind" autocomplete="off">${kind ? html`<input type="hidden" name="kind" value="${kind}">` : ''}<button class="bm-btn bm-btn-small" type="submit">Search</button></form>
+<nav class="br-filters" aria-label="Filter by family">${chip('All', null)}${families.map((f) => chip(f, f))}</nav>
+${benchmarks.length ? html`<ul class="br-cards">${benchmarks.map(benchmarkCard)}</ul>` : empty('No benchmark matches', q ? 'Try a shorter search, or clear the filter.' : 'None are published yet.', html`<a class="bm-btn bm-btn-quiet bm-btn-small" href="/benchmarks">Show all</a>`)}
+</div>`;
+}
+
+function benchmarkCard(b) {
+ const tasks = ((b.draft && b.draft.tasks) || []).length;
+ return html`<li class="br-card"><a class="br-card-link" href="${benchmarkHref(b.id)}"><span class="br-card-top">${kindChip(b.kind)}<span class="br-card-v">v${b.latest_version || 0}</span></span><span class="br-card-title">${b.title}</span><span class="br-card-desc">${b.description}</span><span class="br-card-foot">${plural(tasks, 'task')}${b.runs != null ? html` · ${plural(b.runs, 'run')}` : ''}${b.parent ? ' · a fork' : ''}</span></a></li>`;
+}
+
+function benchmarkPage({ benchmark, definition, version, rankings, metric = 'score', runs = [], codesRunUrl = null }) {
+ const d = definition || {};
+ const tasks = Array.isArray(d.tasks) ? d.tasks : [];
+ const shown = tasks.filter((t) => !t.holdout && t.prompt);
+ const hidden = tasks.length - shown.length;
+ const judges = Array.isArray(d.judges) ? d.judges : [];
+ const limits = d.limits || {};
+ const entries = (rankings && rankings.entries) || [];
+ const base = benchmarkHref(benchmark.id);
+ const runYourself = codesRunUrl
+ ? html`<a class="bm-btn" href="${codesRunUrl}?benchmark=${encodeURIComponent(`${benchmark.id}@${version || benchmark.latest_version}`)}">Run it yourself</a>`
+ : html`<a class="bm-btn bm-btn-quiet" href="/docs#br-publish">Publish a run</a>`;
+ return html`<div class="bm-wrap br" id="br-benchmark">
+<nav class="br-crumbs" aria-label="Breadcrumb"><a href="/benchmarks">Benchmarks</a><span aria-hidden="true">/</span><span>${benchmark.title}</span></nav>
+<header class="br-head"><div class="br-head-main"><p class="br-head-meta">${kindChip(benchmark.kind)}<span>v${version || benchmark.latest_version || 0}</span><span>by ${benchmark.owner}</span>${benchmark.parent ? html`<a href="${benchmarkHref(benchmark.parent)}">forked</a>` : ''}</p>
+<h1>${benchmark.title}</h1>${benchmark.description ? html`<p class="bm-lede">${benchmark.description}</p>` : ''}</div>
+<div class="br-head-act">${runYourself}<p class="br-fine">${codesRunUrl ? 'On openvibe.codes, with your own keys. The result is published here.' : 'Running it on openvibe.codes with your own keys is coming. Today a run is published through the API.'}</p></div></header>
+<dl class="br-facts"><div><dt>Tasks</dt><dd>${tasks.length}${hidden ? html` <span class="br-fine">(${hidden} hidden)</span>` : ''}</dd></div><div><dt>Judged by</dt><dd>${judges.length ? judges.map((j) => String(j.type).replace(/_/g, ' ')).join(', ') : '—'}</dd></div><div><dt>Limits</dt><dd>${[limits.ms ? fmtMs(limits.ms) : null, limits.tokens ? `${fmtTokens(limits.tokens)} tokens` : null, limits.usd ? fmtUsd(limits.usd) : null].filter(Boolean).join(' · ') || '—'}</dd></div><div><dt>Verified runs</dt><dd>${entries.reduce((n, e) => n + e.runs, 0)}</dd></div></dl>
+<section class="bm-section" id="br-rank" aria-labelledby="br-rank-h"><div class="bm-head-row"><h2 id="br-rank-h">Rankings</h2>${metricTabs(base, metric)}</div>
+${valueChart(entries)}
+${entries.length ? rankingsTable(entries, metric) : empty('No verified runs yet', 'A run counts here once openvibe.codes, Run or a Node worker ran it and published it. Submitted runs are listed below but never ranked.')}
+</section>
+<section class="bm-section" aria-labelledby="br-tasks-h"><div class="bm-head-row"><h2 id="br-tasks-h">Tasks</h2><span class="bm-count">${tasks.length}</span></div>
+<ol class="br-tasks">${shown.map((t) => html`<li class="br-task"><span class="br-task-id br-mono">${t.id}</span><p>${t.prompt}</p></li>`)}${hidden ? html`<li class="br-task is-hidden"><span class="br-task-id br-mono">${plural(hidden, 'task')}</span><p>Held out: only the executor sees ${hidden === 1 ? 'it' : 'them'}, so nobody can tune for the answer.</p></li>` : ''}</ol></section>
+<section class="bm-section" aria-labelledby="br-latest-h"><div class="bm-head-row"><h2 id="br-latest-h">Latest runs</h2>${runs.length > 1 ? html`<a class="bm-more" href="${compareHref(runs.slice(0, 2).map((r) => r.id))}">Compare the newest two</a>` : ''}</div>
+${runs.length ? runsList(runs) : empty('No runs yet', 'The first run shows up here, verified or submitted.')}</section>
+<p class="br-fine br-api">The same data as JSON: <a href="/api/v1/benchmarks/${encodeURIComponent(benchmark.id)}">definition</a> · <a href="/api/v1/rankings?benchmark=${encodeURIComponent(benchmark.id)}&metric=${metric}">rankings</a></p>
+</div>`;
+}
+
+function runPage({ run, benchmark, definition, pct }) {
+ const tasksDef = new Map(((definition && definition.tasks) || []).map((t) => [t.id, t]));
+ const env = [
+ ['Model', html`<a href="${modelHref(run.model)}">${run.model}</a>`],
+ ['Provider', run.provider || '—'],
+ ['Route', run.route && Object.keys(run.route).length ? Object.entries(run.route).map(([k, v]) => `${k} ${v}`).join(' · ') : '—'],
+ ['Harness', harnessLabel(run.harness)],
+ ['Settings', [run.settings && run.settings.effort ? `effort ${run.settings.effort}` : null, run.settings && run.settings.temperature != null ? `temperature ${run.settings.temperature}` : null].filter(Boolean).join(' · ') || 'defaults'],
+ ['Ran on', run.executor ? ({ codes: 'openvibe.codes', run: 'OpenVibe.Run', node: 'a Node worker', submitted: 'not re-run' })[run.executor.kind] || run.executor.kind : '—'],
+ ['Hardware', run.hardware ? Object.entries(run.hardware).map(([k, v]) => `${k} ${v}`).join(' · ') : '—'],
+ ['Benchmark', html`<a href="${benchmarkHref(run.benchmark_id)}">${benchmark ? benchmark.title : run.benchmark_id}</a> <span class="br-fine">v${run.benchmark_version}</span>`],
+ ];
+ const pctLine = pct && pct.runs > 1 && pct.percentile != null
+ ? html`<div class="br-pct"><div class="br-pct-strip" aria-hidden="true"><span style="left:${Math.max(0, Math.min(100, pct.percentile)).toFixed(1)}%"></span></div><p><b>${ordinal(pct.percentile)} percentile</b> of ${pct.runs} verified runs of ${run.model} on this benchmark. Median ${fmtScore(pct.median)}, best ${fmtScore(pct.best)}.</p></div>`
+ : html`<p class="br-fine">Where it sits shows once ${run.model} has more verified runs here.</p>`;
+ return html`<div class="bm-wrap br" id="br-run">
+<nav class="br-crumbs" aria-label="Breadcrumb"><a href="/benchmarks">Benchmarks</a><span aria-hidden="true">/</span><a href="${benchmarkHref(run.benchmark_id)}">${benchmark ? benchmark.title : run.benchmark_id}</a><span aria-hidden="true">/</span><span class="br-mono">${run.id}</span></nav>
+<header class="br-head br-run-head"><div class="br-head-main"><p class="br-head-meta">${provenance(run.provenance)}<span>${fmtDate(run.created_at)}</span></p><h1>${run.model}</h1><p class="bm-lede">on ${benchmark ? benchmark.title : run.benchmark_id}, through ${harnessLabel(run.harness)}</p></div>
+<div class="br-head-score">${scoreBar(run.score, { big: true })}<dl class="br-totals"><div><dt>Cost</dt><dd>${fmtUsd(run.cost_usd)}</dd></div><div><dt>Time</dt><dd>${fmtMs(run.ms)}</dd></div><div><dt>Tokens</dt><dd>${fmtTokens(run.tokens)}</dd></div></dl></div></header>
+${pctLine}
+<section class="bm-section" aria-labelledby="br-env-h"><h2 id="br-env-h">Environment</h2><dl class="br-env">${env.map(([k, v]) => html`<div><dt>${k}</dt><dd>${v}</dd></div>`)}</dl></section>
+<section class="bm-section" aria-labelledby="br-pt-h"><div class="bm-head-row"><h2 id="br-pt-h">Tasks</h2><span class="bm-count">${(run.tasks || []).length}</span></div>
+${(run.tasks || []).length ? html`<ol class="br-ptasks">${run.tasks.map((t) => {
+ const def = tasksDef.get(t.task_id);
+ const prompt = def && def.prompt && !def.holdout ? def.prompt : 'A held-out task: its prompt stays with the executor.';
+ return html`<li class="br-ptask"><div class="br-ptask-head"><span class="br-task-id br-mono">${t.task_id}</span>${scoreBar(t.score)}<span class="br-ptask-meta">${fmtUsd(t.cost_usd)} · ${fmtMs(t.ms)} · ${fmtTokens(t.tokens)} tokens</span></div><p class="br-ptask-prompt">${prompt}</p>${t.artifacts && t.artifacts.length ? html`<div class="br-outs">${t.artifacts.map((a, i) => artifact(a, `${t.task_id} output ${i + 1}`))}</div>` : ''}${t.transcript_url && /^https:\/\//.test(t.transcript_url) ? html`<a class="bm-more" href="${t.transcript_url}" rel="noopener nofollow">Transcript</a>` : ''}</li>`;
+ })}</ol>` : empty('No task results', 'This run published its totals only.')}</section>
+<section class="bm-section br-again" aria-labelledby="br-again-h"><h2 id="br-again-h">Again</h2><p class="br-fine">The benchmark version is frozen, so this run can be repeated exactly: the same tasks, the same judges.</p><div class="bm-actions"><a class="bm-btn bm-btn-quiet" href="${benchmarkHref(run.benchmark_id)}">See every model on it</a><a class="bm-btn bm-btn-quiet" href="/api/v1/runs/${encodeURIComponent(run.id)}">The run as JSON</a></div></section>
+</div>`;
+}
+
+function comparePage({ cmp, titles = {} }) {
+ if (!cmp) {
+ return html`<div class="bm-wrap br" id="br-compare"><header class="bm-page-h"><p class="bm-kicker">Compare</p><h1>Compare runs</h1><p class="bm-lede">Open a benchmark, then compare two to four of its runs: the same tasks side by side, with their scores, cost, time and outputs.</p></header>${empty('Nothing to compare', 'Add runs with ?runs=run_a,run_b, or pick them from a benchmark.', html`<a class="bm-btn bm-btn-small" href="/benchmarks">Benchmarks</a>`)}</div>`;
+ }
+ const { runs, rows } = cmp;
+ const best = (vals, hi = true) => { const v = vals.filter((x) => x != null); return v.length ? (hi ? Math.max(...v) : Math.min(...v)) : null; };
+ const cell = (v, b, f) => html`<td class="br-num${v != null && v === b ? ' is-best' : ''}">${f(v)}</td>`;
+ const line = (label, vals, f, hi = true) => { const b = best(vals, hi); return html`<tr><th scope="row">${label}</th>${vals.map((v) => cell(v, b, f))}</tr>`; };
+ return html`<div class="bm-wrap br" id="br-compare">
+<header class="bm-page-h"><p class="bm-kicker">Compare</p><h1>${runs.map((r) => r.model).join(' vs ')}</h1><p class="bm-lede">${[...new Set(runs.map((r) => titles[r.benchmark_id] || r.benchmark_id))].join(', ')}. The best value in each row is marked.</p></header>
+<div class="br-table-wrap"><table class="br-table br-cmp"><thead><tr><th scope="col"><span class="br-sr">Measure</span></th>${runs.map((r) => html`<th scope="col"><a href="${runHref(r.id)}">${r.model}</a><span class="br-cmp-sub">${harnessLabel(r.harness)}</span>${provenance(r.provenance)}</th>`)}</tr></thead><tbody>
+${line('Score', runs.map((r) => r.score), fmtScore)}${line('Cost', runs.map((r) => r.cost_usd), fmtUsd, false)}${line('Time', runs.map((r) => r.ms), fmtMs, false)}${line('Tokens', runs.map((r) => r.tokens), fmtTokens, false)}
+${rows.map((row) => line(html`<span class="br-mono">${row.task_id}</span>`, row.scores, fmtScore))}
+</tbody></table></div>
+${rows.some((row) => runs.some((r) => ((r.tasks.find((t) => t.task_id === row.task_id) || {}).artifacts || []).length)) ? html`<section class="bm-section" aria-labelledby="br-cmp-out-h"><h2 id="br-cmp-out-h">Outputs side by side</h2>${rows.map((row) => html`<div class="br-cmp-row"><p class="br-task-id br-mono">${row.task_id}</p><div class="br-cmp-outs" style="--n:${runs.length}">${runs.map((r) => {
+ const t = r.tasks.find((x) => x.task_id === row.task_id);
+ const a = t && t.artifacts && t.artifacts[0];
+ return html`<div class="br-cmp-out"><p class="br-cmp-sub">${r.model}</p>${a ? artifact(a, `${r.model} ${row.task_id}`) : html`<p class="br-fine">No output</p>`}</div>`;
+ })}</div></div>`)}</section>` : ''}
+</div>`;
+}
+
+function modelPage({ model, summary, runs = [], titles = {} }) {
+ const rows = (summary && summary.benchmarks) || [];
+ return html`<div class="bm-wrap br" id="br-model">
+<nav class="br-crumbs" aria-label="Breadcrumb"><a href="/benchmarks">Benchmarks</a><span aria-hidden="true">/</span><span>Models</span></nav>
+<header class="bm-page-h"><p class="bm-kicker">Model</p><h1 class="br-mono-h">${model}</h1><p class="bm-lede">${summary && summary.runs ? `${plural(summary.runs, 'verified run')} across ${plural(rows.length, 'benchmark')}.` : 'No verified runs yet.'}</p></header>
+<section class="bm-section" aria-labelledby="br-mb-h"><h2 id="br-mb-h">By benchmark</h2>
+${rows.length ? html`<div class="br-table-wrap"><table class="br-table"><thead><tr><th scope="col">Benchmark</th><th scope="col">Median</th><th scope="col" class="br-num">Spread</th><th scope="col" class="br-num">Cost / run</th><th scope="col" class="br-num">Time</th><th scope="col" class="br-num">Runs</th></tr></thead><tbody>${rows.map((b) => html`<tr><td><a href="${benchmarkHref(b.benchmark_id)}">${b.title}</a> ${kindChip(b.kind)}</td><td>${scoreBar(b.score)}</td><td class="br-num">${b.runs > 1 ? `${fmtScore(b.worst)}–${fmtScore(b.best)}` : '—'}</td><td class="br-num">${fmtUsd(b.cost_usd)}</td><td class="br-num">${fmtMs(b.ms)}</td><td class="br-num">${b.runs}</td></tr>`)}</tbody></table></div>` : empty('Nothing measured yet', 'This model shows up here after its first verified run.', html`<a class="bm-btn bm-btn-small" href="/benchmarks">Pick a benchmark</a>`)}</section>
+${runs.length ? html`<section class="bm-section" aria-labelledby="br-mr-h"><h2 id="br-mr-h">Latest runs</h2>${runsList(runs, { showBenchmark: true, titles })}</section>` : ''}
+</div>`;
+}
+
+module.exports = {
+ benchmarksIndex, benchmarkPage, runPage, comparePage, modelPage, valueChart, METRICS,
+ fmtScore, fmtUsd, fmtMs, fmtTokens, ordinal, benchmarkCard, render,
+};
new file mode 100644
new file mode 100644
@@ -0,0 +1,175 @@
@@ -0,0 +1,175 @@
+'use strict';
+
+/**
+ * The results pages (stage B2) and the rules they rest on.
+ *
+ * Under test: every page renders from the registry's own data (benchmarks, a benchmark with its rankings and value
+ * chart, a run, compare, a model); dynamic text is escaped; an unlisted benchmark is reachable by its id but listed
+ * to nobody but its owner, and its runs stay off a model's page; the rankings'
+ * `since` and `harness` filters work on their own; the value chart marks the frontier and only the frontier.
+ */
+const assert = require('assert');
+const { boot, check, done } = require('./helpers/boot');
+const results = require('../server/views/results');
+
+const TASKS = [
+ { id: 't1', prompt: 'Build a one-screen arcade game with a paddle, bricks, a ball and a score.', files: [], expected: null, holdout: false },
+ { id: 't2', prompt: 'A held-out snake game.', files: [], expected: null, holdout: true },
+];
+
+function definition(over = {}) {
+ return {
+ title: 'Pages test arena',
+ description: 'A benchmark for the page tests.',
+ kind: 'games.play',
+ tags: ['games'],
+ visibility: 'public',
+ tasks: TASKS,
+ judges: [{ type: 'game_outcome', version: '1.0', config: {} }],
+ scoring: { method: 'mean', scale: { min: 0, max: 100 } },
+ limits: { ms: 120000, tokens: 200000, usd: 0.5 },
+ matrix: { models: ['model-a'], harnesses: ['claude-code'] },
+ ...over,
+ };
+}
+
+function runDoc(benchmark, over = {}) {
+ return {
+ benchmark,
+ model: 'model-a',
+ route: { provider: 'acme' },
+ provider: 'acme',
+ harness: { name: 'claude-code', version: '3.1.0' },
+ settings: { temperature: 1, effort: 'high' },
+ executor: { kind: 'codes', id: 'tsk_pages' },
+ tasks: [
+ { task_id: 't1', score: 80, cost_usd: 0.01, ms: 30000, tokens: 5000, artifacts: [{ kind: 'html', url: 'https://bench-render.openvibe.services/render/w/ent_pages' }] },
+ { task_id: 't2', score: 60, cost_usd: 0.01, ms: 30000, tokens: 5000, artifacts: [] },
+ ],
+ score: 70,
+ cost_usd: 0.02,
+ ms: 60000,
+ tokens: 10000,
+ ...over,
+ };
+}
+
+(async () => {
+ const t = await boot();
+ const alice = t.network.addUser('alice');
+ const bob = t.network.addUser('bob');
+ const publisher = t.network.serviceToken({ sub: 'svc:codes', audience: 'openvibe.bench', cap: ['bench.run.publish', 'bench.benchmark.write'] });
+
+ const create = async (over, as) => {
+ const res = await t.get('/api/v1/benchmarks', as ? { as, json: definition(over) } : { bearer: publisher, json: definition(over) });
+ assert.strictEqual(res.status, 201, res.text);
+ const id = res.json().benchmark.id;
+ const frozen = await t.get(`/api/v1/benchmarks/${id}/versions`, as ? { as, json: {} } : { bearer: publisher, json: {} });
+ assert.strictEqual(frozen.status, 201, frozen.text);
+ return { id, version: frozen.json().version.version };
+ };
+ const publish = async (ref, over) => {
+ const res = await t.get('/api/v1/runs', { bearer: publisher, json: runDoc(ref, over) });
+ assert.strictEqual(res.status, 201, res.text);
+ return res.json().run.id;
+ };
+
+ const pub = await create({ title: 'Pages <script>alert(1)</script> arena' });
+ const cheap = await publish(`${pub.id}@${pub.version}`, { model: 'model-cheap', score: 60, cost_usd: 0.002 });
+ const best = await publish(`${pub.id}@${pub.version}`, { model: 'model-best', score: 90, cost_usd: 0.05 });
+ await publish(`${pub.id}@${pub.version}`, { model: 'model-worse', score: 55, cost_usd: 0.04, harness: { name: 'opencode', version: '1.4.2' } });
+ const priv = await create({ title: 'Alice unlisted prompts', visibility: 'unlisted' }, alice);
+ await publish(`${priv.id}@${priv.version}`, { model: 'model-best', score: 12, cost_usd: 0.01 });
+
+ await check('the benchmarks page lists the public benchmarks and escapes their titles', async () => {
+ const res = await t.get('/benchmarks');
+ assert.strictEqual(res.status, 200, res.text.slice(0, 300));
+ assert.ok(res.text.includes('Pages <script>alert(1)</script> arena'), 'the title is escaped');
+ assert.ok(!res.text.includes('<script>alert(1)</script>'), 'never raw');
+ assert.ok(!res.text.includes('Alice unlisted prompts'), 'an unlisted benchmark is not listed');
+ });
+
+ await check('a benchmark page shows its rankings, its value chart and its runs', async () => {
+ const res = await t.get(`/benchmarks/${pub.id}`);
+ assert.strictEqual(res.status, 200, res.text.slice(0, 300));
+ assert.ok(res.text.includes('id="br-rank"'), 'the rankings section');
+ assert.ok(res.text.includes('class="br-chart"'), 'the value chart');
+ for (const m of ['model-best', 'model-cheap', 'model-worse']) assert.ok(res.text.includes(m), `${m} is ranked`);
+ assert.ok(res.text.includes('Held out'), 'the holdout task is counted, its prompt is not shown');
+ assert.ok(!res.text.includes('A held-out snake game.'), 'the holdout prompt never reaches the page');
+ const value = await t.get(`/benchmarks/${pub.id}?metric=value`);
+ assert.ok(value.text.includes('aria-current="page"') && value.text.includes('/ $'), 'the value tab is current and shows score per dollar');
+ });
+
+ await check('a run page shows the environment, the score, the provenance and the outputs', async () => {
+ const res = await t.get(`/runs/${best}`);
+ assert.strictEqual(res.status, 200, res.text.slice(0, 300));
+ assert.ok(res.text.includes('model-best'));
+ assert.ok(res.text.includes('Verified'), 'the provenance badge');
+ assert.ok(res.text.includes('claude-code 3.1.0'), 'the harness and its version');
+ assert.ok(res.text.includes('src="https://bench-render.openvibe.services/render/w/ent_pages"'), 'an output from the render origin is framed');
+ assert.ok(res.text.includes('sandbox="'), 'and sandboxed');
+ assert.ok(res.text.includes('A held-out task'), 'a holdout task keeps its prompt hidden on the run page too');
+ assert.strictEqual((await t.get('/runs/brn_nope')).status, 404);
+ });
+
+ await check('compare puts runs side by side and marks the best in each row', async () => {
+ const res = await t.get(`/compare?runs=${best},${cheap}`);
+ assert.strictEqual(res.status, 200, res.text.slice(0, 300));
+ assert.ok(res.text.includes('model-best vs model-cheap'));
+ assert.ok(res.text.includes('is-best'), 'a best value is marked');
+ assert.strictEqual((await t.get('/compare')).status, 200, 'an empty compare explains itself');
+ });
+
+ await check('a model page shows the public benchmarks only', async () => {
+ const res = await t.get('/models/model-best');
+ assert.strictEqual(res.status, 200, res.text.slice(0, 300));
+ assert.ok(res.text.includes('Pages <script>'), 'its public benchmark');
+ assert.ok(!res.text.includes('Alice unlisted prompts'), 'never an unlisted benchmark, not even its title');
+ assert.strictEqual((await t.get('/models/nobody-ran-this')).status, 404);
+ });
+
+ await check('an unlisted benchmark is reachable by its id and listed to nobody but its owner', async () => {
+ assert.strictEqual((await t.get(`/api/v1/benchmarks/${priv.id}`)).status, 200, 'reachable by id');
+ const page = await t.get(`/benchmarks/${priv.id}`);
+ assert.strictEqual(page.status, 200, 'its page too');
+ assert.ok(page.text.includes('noindex'), 'but kept out of search engines');
+ const list = await t.get('/api/v1/benchmarks');
+ assert.ok(!list.json().benchmarks.some((b) => b.id === priv.id), 'never in the public list');
+ const mine = await t.get('/api/v1/benchmarks?mine=1', { as: alice });
+ assert.ok(mine.json().benchmarks.some((b) => b.id === priv.id), 'the owner lists it with ?mine=1');
+ const theirs = await t.get('/api/v1/benchmarks?mine=1', { as: bob });
+ assert.ok(!theirs.json().benchmarks.some((b) => b.id === priv.id), 'nobody else does');
+ });
+
+ await check('the rankings filter by since alone and by harness name', async () => {
+ const since = await t.get(`/api/v1/rankings?benchmark=${pub.id}&metric=score&since=2000-01-01T00:00:00Z`);
+ assert.strictEqual(since.status, 200, since.text);
+ assert.strictEqual(since.json().rankings.entries.length, 3, '`since` without `harness` is its own placeholder');
+ const harness = await t.get(`/api/v1/rankings?benchmark=${pub.id}&metric=score&harness=opencode`);
+ assert.strictEqual(harness.status, 200, harness.text);
+ assert.deepStrictEqual(harness.json().rankings.entries.map((e) => e.model), ['model-worse'], 'the harness name matches');
+ });
+
+ await check('the value chart marks the frontier and only the frontier', () => {
+ const svg = String(results.valueChart([
+ { model: 'cheap', score: 60, cost_usd: 0.002 },
+ { model: 'best', score: 90, cost_usd: 0.05 },
+ { model: 'dominated', score: 55, cost_usd: 0.04 },
+ ]));
+ const front = [...svg.matchAll(/<g class="br-dot( is-front)?">.*?<text[^>]*>([^<]+)<\/text>/g)].map((m) => [m[2], Boolean(m[1])]);
+ const by = Object.fromEntries(front);
+ assert.strictEqual(by.cheap, true);
+ assert.strictEqual(by.best, true);
+ assert.strictEqual(by.dominated, false, 'a model both dearer and worse than another is off the frontier');
+ assert.ok(String(results.valueChart([])).includes('fills in with the first verified runs'), 'the empty chart says so');
+ });
+
+ await check('the render origin asks Cloudflare not to rewrite its frames', async () => {
+ const res = await t.get('/render/w/ent_nope');
+ assert.match(String(res.headers.get('cache-control')), /no-transform/);
+ });
+
+ await check('stop', async () => { await t.close(); });
+ done();
+})();