Files
zeekayandHanzo Dev 277b2b15e7 benchmarks: one shelf for every run, the page as a story, the frozen record everywhere
/benchmarks is now one story: lead, proof, frontier, products, infrastructure,
boundaries, methods, then every benchmark and every run on one shelf. A
sticky chapter nav marks where you are. "/" opens a palette that jumps to
any benchmark; ⌘K stays the site search the header owns.

lib/results.ts builds one ledger from the files that hold the figures:
- the research runs: every Kai revision of every suite against Jev, the
  release gate, choice size, joint decisions, latency, validation splits;
- the leaderboard snapshot (Enso's boards);
- the engine's cells (Zen on the engine against llama.cpp);
- the memory, graph and code runs;
- the runtime passes.
That is 216 results across 35 benchmarks. Each is dated and marked live,
frozen or superseded. The one undated row, the sealed board's HarmBench
count, says so.

The shelf searches and highlights instantly. It is faceted by product,
category, metric, measured-by, date, status and result, with counts. Views
are kept in the URL, with named saved views, CSV/JSON export, and a compare
tray for rows of one benchmark and metric. Every benchmark without a
hand-written page gets /benchmarks/<slug>: its history over time,
conditions, hardware, source and reproduce command. The sitemap lists
these pages.

The prebuild now runs scripts/kai.mjs. It pulls the latest validated runs
(canonical, public, not inconsistent). The committed snapshot is the frozen
fallback when the API cannot be read or answers with fewer runs.

The home page's Kai line and /models' family line now read the frozen
harness from lib/tally (11 of 12, behind on Jailbreak). v2's 12 of 12
appears only where it is labelled.

Type follows the product pages (@hanzo/ui/marketing Display, Title,
Eyebrow, Lede). Motion is gui transitions, with no entrance that ships
hidden; the design system zeroes durations under reduced motion. The board
and shelf are imported only by the index, so the other benchmark pages stay
under budget. /benchmarks has its own budget, 440 KB.


Co-authored-by: Hanzo Dev <[email protected]>
2026-10-09 04:45:14 -07:00

105 lines
4.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { ReactNode } from 'react'
import { Cell, Table, Td, Th, Tr } from './parts'
export * from './parts'
/**
* The furniture every bench page is built from.
*
* One table renderer, not four. The published runs come in four shapes —
* retrieval rows, code rows, the per-category sections, the LongMemEval tally —
* and each was a table component of its own that differed only in which columns
* it spelled. A column is `{ head, get }`; the shape it reads is the caller's
* business, and the borders, the alignment, the tabular figures and the
* horizontal scroll are settled once here.
*
* The index is built from the same pieces, so a reader arriving from it does
* not land on a page that looks like a different site — and so the index holds
* no style value of its own, which keeps its source free of every digit that is
* not a figure read from the data.
*
* Every piece is a component on gui props. These pages are dark by design — a
* black page in white type whatever the site's theme — so the inks are stated
* against that ground rather than the theme's.
*/
export const n0 = (v: number | null | undefined) => (v == null ? '–' : v.toFixed(0))
export const n1 = (v: number | null | undefined) => (v == null ? '–' : v.toFixed(1))
export const ms = (v: number | null | undefined) => (v == null ? '–' : v.toFixed(2))
export type Interval = { mean: number; lo: number; hi: number }
export type Metric = Interval | number | null
export const val = (m: Metric | undefined) => (m == null ? null : typeof m === 'number' ? m : m.mean)
/** A rate as a percentage to one place, the precision every metric here carries. */
export const F = (m: Metric | undefined) => { const v = val(m); return v == null ? '–' : (v * 100).toFixed(1) }
/** The same to two places, for a rate near one hundred where one place hides the difference. */
export const F2 = (m: Metric | undefined) => { const v = val(m); return v == null ? '–' : (v * 100).toFixed(2) }
/** A rate as a percentage, for a bar. */
export const pc = (m: Metric | undefined) => { const v = val(m); return v == null ? null : v * 100 }
/** A duration in milliseconds at the precision its size needs: 0.063 ms, 1.4 ms, 5,357 ms. */
export const elapsed = (v: number | null | undefined) =>
v == null ? '–' : v >= 100 ? `${Math.round(v).toLocaleString('en-US')} ms` : `${v.toFixed(v < 1 ? 3 : 1)} ms`
/** Names joined as a sentence joins them: `a, b, and c`. */
export const list = (xs: readonly string[]) => new Intl.ListFormat('en').format(xs)
/**
* A metric's column head, in the one place it is spelled.
*
* The run files carry the key a scorer wrote (`substring_em`, `ndcg@20`); a
* reader needs the name the benchmark's own paper uses. Two pages spelling
* `sem` differently would be two benchmarks as far as anyone reading them is
* concerned.
*/
export const METRIC: Record<string, string> = {
of: 'in set', 'all@5': 'ALL@5', 'all@10': 'ALL@10', 'all@20': 'ALL@20', 'any@20': 'ANY@20',
'recall@10': 'R@10', mrr: 'MRR', 'ndcg@20': 'nDCG@20', supported: 'supported',
f1: 'F1', em: 'EM', substring_em: 'substring EM', sem: 'substring EM',
recall: 'recall', all: 'ALL', any: 'ANY',
examined: 'candidates', tokens: 'tokens/q', p50: 'p50 ms', p95: 'p95 ms',
}
/** Which metrics a section table shows, and in what order. Absent keys are dropped. */
export const SHOW = ['of', 'all@20', 'any@20', 'recall@10', 'recall', 'all', 'any', 'mrr', 'ndcg@20', 'supported', 'f1', 'em', 'substring_em', 'sem', 'examined', 'tokens', 'p50', 'p95']
/** Counts stay counts, milliseconds stay milliseconds, rates become percentages. */
export function metric(v: Metric | undefined, key: string): ReactNode {
if (v == null) return '–'
if (typeof v === 'number') {
if (key === 'examined' || key === 'tokens' || key === 'of') return v.toFixed(0)
if (key.startsWith('p')) return v.toFixed(2)
return (v * 100).toFixed(1)
}
return <Cell m={v} />
}
export type Col<R> = { head: ReactNode; get: (r: R) => ReactNode; left?: boolean }
/** The one table. Columns describe themselves; the rows are whatever shape the run file has. */
export function Grid<R>({ cols, rows, keyOf, dim }: { cols: Col<R>[]; rows: R[]; keyOf: (r: R) => string; dim?: (r: R) => boolean }) {
return (
<Table>
<thead>
<tr>
{cols.map((c, i) => (
<Th key={i} left={c.left}>
{c.head}
</Th>
))}
</tr>
</thead>
<tbody>
{rows.map((r) => (
<Tr key={keyOf(r)} dim={dim?.(r)}>
{cols.map((c, i) => (
<Td key={i} left={c.left}>
{c.get(r)}
</Td>
))}
</Tr>
))}
</tbody>
</Table>
)
}