"use client" import { useAudienceMode } from "@/components/audience-mode-provider" import { Fragment, useEffect, useMemo, useState } from "react" import Link from "next/link" import { BenchmarkSignalsStrip } from "@/components/signals/benchmark-signals-strip" import { SignalsRowBadges } from "@/components/signals/signals-row-badges" import { VerifiedBadge } from "@/components/signals/verified-badge" import { getCompletenessPopulatedCount } from "@/components/signals/signal-utils" import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible" import { ScoreDistribution } from "@/components/score-distribution" import { ParamRangePicker } from "@/components/param-range-picker" import { EmbedButton } from "@/components/embed-button" import { PARAM_RANGE_MAX_INDEX, paramStepToNumeric, parseParamsBillionsFromText, parseParamsBillionsFromModelName, } from "@/lib/param-range" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog" import { Input } from "@/components/ui/input" import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { cn, formatDateISO, humanizeEvaluationId, routeIdFromModelId, routeIdToPath } from "@/lib/utils" import { AlertTriangle, BarChart3, BookOpen, ChevronDown, ChevronUp, ExternalLink, FileText, Globe, Scale, Search, Shield, SlidersHorizontal, Tag, X, } from "lucide-react" import type { BenchmarkCard, SourceData } from "@/lib/benchmark-schema" import { tagLabel } from "@/lib/benchmark-schema" import { isAssistedResult } from "@/lib/eval-processing" import type { BenchmarkEvalSummary, ModelResultForBenchmark } from "@/lib/eval-processing" import { buildComputeProtocolSeries } from "@/lib/collections" import { CollectionTrajectories } from "@/components/collection-trajectories" import { isRecognizedEvaluator } from "@/lib/evaluators" import { useEvaluatorSlug } from "@/components/org-metadata-provider" import type { ComparisonIndex, EvalHierarchy } from "@/lib/backend-artifacts" import type { HierarchyEvalLocation } from "@/lib/hierarchy-lookup" import { PolicyOverview } from "@/components/policy-overview" import { ResearcherReproducibilityCard } from "@/components/researcher-reproducibility-card" import { KnownIssuesPanel } from "@/components/known-issues-panel" import { getKnownIssues, type KnownIssue } from "@/lib/known-issues" import { ApplesToApplesBanner } from "@/components/apples-to-apples-banner" import { ComparabilityPanel } from "@/components/signals/comparability-panel" import { FlagScoreButton } from "@/components/flag-score-button" interface SplitOption { id: string label: string } interface SplitConfig { options: SplitOption[] activeId: string onChange: (id: string) => void /** Picker label, e.g. "Split" or "Slice". */ label?: string } interface EvalDetailProps { summary: BenchmarkEvalSummary hierarchyLocation?: HierarchyEvalLocation | null /** Full eval hierarchy — used by the signals strip to find sibling * appearances of the same canonical benchmark across other suites. */ evalHierarchy?: EvalHierarchy | null /** Per-(eval, metric) leaderboard data — used to fetch sibling scores * for cross-suite comparability. */ comparisonIndex?: ComparisonIndex | null /** * Drives the leaderboard section when a split is selected. Defaults to * `summary` when omitted, preserving the single-summary behaviour. */ activeSummary?: BenchmarkEvalSummary splitConfig?: SplitConfig /** Rows for which this returns true get a warm background tint. Used by * the merged page for the ?source= pre-highlight. */ rowHighlight?: (modelResult: ModelResultForBenchmark) => boolean /** Merged pages only: link target for "view the study's per-setting * analysis" inside the study-protocol banner. The merged page has no * per-source evaluation_id in scope here, so MergedBenchmarkView * passes the resolved per-source href down. */ studySourceHref?: string } interface LeaderboardRow { key: string rank: number modelResult: ModelResultForBenchmark normalizedScore: number } type LeaderboardMetric = NonNullable[number] type LeaderboardMatrixRow = NonNullable[number] /** * Pick a representative row-level annotation for the matrix view. * * Reproducibility and provenance are typically constant across all metrics for * a given (model, benchmark) pair, so rendering them in every cell is just * noise. This helper grabs the first non-null annotation across visible metrics * and returns it for the row-level badge strip. */ function getRowLevelAnnotations( row: LeaderboardMatrixRow, visibleMetrics: LeaderboardMetric[] ) { const annotationsByMetric = row.annotations_by_metric if (!annotationsByMetric) { return null } for (const metric of visibleMetrics) { const annotations = annotationsByMetric[metric.column_key] if (annotations) { return annotations } } return null } /** * Compact dropdown shown above the leaderboard when an eval has multiple * splits (separate eval IDs that share a benchmark) or slices (subtasks within * one eval). Lives below the apples-to-apples banner so the hero/cards stay * stable while the leaderboard data swaps. */ function SplitPicker({ config, className, }: { config: { options: { id: string; label: string }[] activeId: string onChange: (id: string) => void label?: string } className?: string }) { return (
{config.label ?? "Split"}
) } const SLICE_PILL_THRESHOLD = 5 interface SliceTab { key: string label: string } /** * Slice picker that adapts to slice count. * * - <= SLICE_PILL_THRESHOLD: render every slice as a pill (current familiar UX). * - > SLICE_PILL_THRESHOLD: render "All slices" + currently-selected pill + * a "Browse N slices" button that opens a searchable dialog. Hundreds of * slices (e.g. AIRBench's 374) fit cleanly. */ function SliceSelector({ activeSliceTab, onChange, tabs, }: { activeSliceTab: string onChange: (key: string) => void tabs: SliceTab[] }) { const [browserOpen, setBrowserOpen] = useState(false) const [search, setSearch] = useState("") const useBrowser = tabs.length > SLICE_PILL_THRESHOLD const activeTab = tabs.find((tab) => tab.key === activeSliceTab) const filteredTabs = useMemo(() => { const query = search.trim().toLowerCase() if (!query) return tabs return tabs.filter((tab) => tab.label.toLowerCase().includes(query)) }, [search, tabs]) if (!useBrowser) { return (
Benchmark slices
{tabs.map((tab) => ( ))}
) } return (
Benchmark slices
{tabs.length} total
{activeTab && ( )}
{ setBrowserOpen(open) if (!open) setSearch("") }} > Browse benchmark slices {tabs.length} slices in this benchmark. Pick one to filter the leaderboard, or close to keep showing all slices. setSearch(event.target.value)} placeholder="Search slices..." autoFocus />
{filteredTabs.length === 0 ? (
No slices match "{search}".
) : ( filteredTabs.map((tab) => ( )) )}
) } function getParamsBillionsFromModelInfo(modelInfo: ModelResultForBenchmark["model_info"]) { const additionalDetails = modelInfo.additional_details const rawParamsBillions = additionalDetails?.params_billions ?? additionalDetails?.parameter_count ?? additionalDetails?.num_parameters ?? additionalDetails?.params if (typeof rawParamsBillions === "number") { return rawParamsBillions } if (typeof rawParamsBillions === "string") { const parsed = parseParamsBillionsFromText(rawParamsBillions) if (Number.isFinite(parsed)) { return parsed } } if (typeof modelInfo.parameter_count === "string") { const parsed = parseParamsBillionsFromText(modelInfo.parameter_count) if (Number.isFinite(parsed)) { return parsed } } return parseParamsBillionsFromModelName(modelInfo.name) } function getParamsBillions(modelResult: ModelResultForBenchmark) { return getParamsBillionsFromModelInfo(modelResult.model_info) } function formatMetadataValue(value: unknown): string { if (value == null) { return "N/A" } if (typeof value === "string") { return value } if (typeof value === "number") { return Number.isFinite(value) ? value.toLocaleString() : String(value) } if (typeof value === "boolean") { return value ? "true" : "false" } if (Array.isArray(value)) { return value.map((item) => formatMetadataValue(item)).join(", ") } try { return JSON.stringify(value) } catch { return String(value) } } // Re-exported as `formatDate` so the existing call sites in this file // keep working — the component code reads "formatDate" everywhere. The // shared YYYY-MM-DD implementation lives in `lib/utils` so model-page // and other surfaces format identically. const formatDate = formatDateISO /** * Render an evaluator org name. When `linkName` is a known evaluator (a * de-aliased name with a /evaluators/ page) the name links there; * otherwise it renders as plain text so we never emit a broken link. The * slug uses the shared, deterministic `evaluatorSlug` base helper. */ function EvaluatorName({ display, linkName, className, style, }: { display: React.ReactNode linkName: string | null className?: string style?: React.CSSProperties }) { const slugFor = useEvaluatorSlug() if (!linkName) { return {display} } return ( e.stopPropagation()} > {display} ) } /** * Render a benchmark-card field path (e.g. `methodology.metrics`, * `purpose_and_intended_users.goal`) as a human-readable label — * `Methodology › Metrics`, `Purpose and intended users › Goal`. * * Replaces underscores with spaces and joins dotted segments with a * `›` separator. Capitalises the first letter of each segment but * keeps the rest lower-case so multi-word segments like * `purpose_and_intended_users` don't render as a tower of capitals. */ function humanizeCardFieldPath(path: string): string { return path .split(".") .map((seg) => { const spaced = seg.replace(/_/g, " ").trim() if (!spaced) return seg return spaced.charAt(0).toUpperCase() + spaced.slice(1) }) .join(" › ") } /** * Card-quality notes from the AutoBenchmarkCard pipeline arrive as * strings shaped like `[Possible Hallucination], no supporting * evidence found in source material`. The leading bracketed label * names the *kind* of issue; the rest is the specific note. * * Split them so the renderer can promote the kind to a small badge * and treat the body as flowing prose. Falls back to `{tag: null, * body: }` when no leading bracket is present. */ function splitFlagNote(raw: string): { tag: string | null; body: string } { if (!raw) return { tag: null, body: "" } const match = /^\s*\[([^\]]+)\]\s*[,—\-:]?\s*(.*)$/.exec(raw) if (!match) return { tag: null, body: raw.trim() } return { tag: match[1].trim(), body: match[2].trim() } } function formatRawScore(score: number | null | undefined, unit?: string) { if (score == null || !Number.isFinite(score)) return "—" const suffix = unit ? ` ${unit}` : "" return `${score.toFixed(2)}${suffix}` } function isNumericScore(value: number | null | undefined): value is number { return typeof value === "number" && Number.isFinite(value) } /** * Sortable column-header button used by the single-metric leaderboard. * Lives inside a `` so the th's hairline border / cell layout still * apply; the button only owns the label, the arrow indicator, and the * click target. * * ` ) } function metricLabelReadsAsPercentage(metricLabel: string, unit?: string) { const normalized = `${metricLabel} ${unit ?? ""}`.toLowerCase() return unit === "%" || /percent|percentage|accuracy|exact match|win rate|pass@|precision|recall|f1/.test(normalized) } function describeLeaderboardMetric(metric: LeaderboardMetric) { const metricLabel = getMetricChipLabel(metric) const metricPhrase = metricLabelReadsAsPercentage(metricLabel, metric.unit) ? `${metricLabel} percentage` : metricLabel if (metric.scope === "subtask" && metric.subtask_name) { return `${metricPhrase} for ${metric.subtask_name}` } // Bold label already carries the compact name; only add a subtitle when the // canonical name says something more than the label (avoid echoing it). const canonical = metric.canonical_display_name?.trim() return canonical && canonical !== metricLabel ? canonical : "" } function compactizePath(value: string): string { const parts = value .split("/") .map((part) => part.trim()) .filter(Boolean) return parts[parts.length - 1] ?? value } function getCompactMetricLabel(value: string | undefined): string { if (value && value.trim()) return compactizePath(value) return "Metric" } /** * Humanise a raw metric identifier (metric_id / column_key) into a * compact, readable label. * * Two shapes the upstream view layer leaves un-curated: * - path-ish keys (`inspect_evals/avg_full_score`) → keep the tail * (`avg full score`). * - `.` keys (`cyse2-vulnerability-exploit.mean`, * `swebench-…-mariushobbhahn.mean`) → the slug prefix just repeats the * eval name, so collapse to the trailing stat (`Mean`). Without this the * column header echoes the raw UPPER.SLUG. */ function humanizeMetricKey(raw: string): string { const tail = compactizePath(raw) // `.mean` / `.std` / `.stderr` → just the trailing stat. const dotMatch = /^(.+)\.([a-z0-9_]+)$/i.exec(tail) if (dotMatch) { const [, prefix, stat] = dotMatch // Only collapse when the prefix looks like a slug (has a hyphen or is // long), not a genuinely dotted metric name. if (prefix.includes("-") || prefix.length > 6) { return humanizeMetricKey(stat) } } const spaced = tail.replace(/_/g, " ").trim() if (!spaced) return tail return spaced.charAt(0).toUpperCase() + spaced.slice(1) } /** * Build a chip-friendly label for a leaderboard metric. Prefers a curated * display_name / metric_name, then a humanised tail of metric_id / * column_key. The upstream pipeline frequently leaves display_name blank * (e.g. inspect_evals/avg_full_score → ifeval's final_acc, inst_loose_acc) * or echoes the raw column key as the "display name" (cyse2's * `cyse2-vulnerability-exploit.mean`). In both cases the humanised key tail * is what we want to surface — never the literal 'Metric' or a raw slug. */ function getMetricChipLabel(metric: { display_name?: string | null metric_name?: string | null metric_id?: string | null column_key?: string | null }): string { const key = metric.metric_id ?? metric.column_key ?? null // Treat a display/metric name that merely echoes the raw column key as // absent — it carries no more information than the key itself. const isRawEcho = (value: string | null | undefined) => !!value && !!key && value.trim() === key.trim() const candidates = [ isRawEcho(metric.display_name) ? null : metric.display_name, isRawEcho(metric.metric_name) ? null : metric.metric_name, ] for (const c of candidates) { if (c && String(c).trim()) { return compactizePath(String(c)).replace(/_/g, " ") } } if (key && key.trim()) { return humanizeMetricKey(key) } return "Metric" } /** * Best-effort "setup" caption for a row (e.g. "8-shot CoT", "0-shot"). * * Different sources record shots/CoT in different fields, so we look across * the common ones in priority order. If nothing useful is recorded we return * an empty string and the caller hides the caption rather than printing a * placeholder. */ function getSetupLabel(modelResult: ModelResultForBenchmark): string { const gen = modelResult.result.generation_config const args: Record | undefined = gen?.generation_args as Record | undefined const additional: Record | undefined = typeof gen?.additional_details === "object" && gen?.additional_details !== null ? (gen.additional_details as Record) : undefined const pickNumber = (...candidates: Array) => { for (const c of candidates) { if (typeof c === "number" && Number.isFinite(c)) return c if (typeof c === "string" && /^\d+$/.test(c.trim())) return Number(c.trim()) } return null } const pickString = (...candidates: Array) => { for (const c of candidates) { if (typeof c === "string" && c.trim()) return c.trim() } return null } const shots = pickNumber( args?.num_shots, args?.n_shots, args?.shots, args?.num_few_shot, additional?.num_shots, additional?.n_shots, additional?.shots, ) const promptingHint = pickString( args?.prompting_strategy, args?.reasoning, additional?.prompting_strategy, additional?.reasoning, ) const isCot = (() => { const candidates = [ args?.chain_of_thought, args?.cot, additional?.chain_of_thought, additional?.cot, ] if (candidates.some((c) => c === true)) return true if (promptingHint && /\bcot\b|chain.of.thought/i.test(promptingHint)) return true return false })() const parts: string[] = [] if (shots != null) parts.push(`${shots}-shot`) if (isCot) parts.push("CoT") if (parts.length === 0 && promptingHint) parts.push(promptingHint) return parts.join(" ") } export function EvalDetail({ summary, hierarchyLocation, evalHierarchy, comparisonIndex, activeSummary, splitConfig, rowHighlight, studySourceHref, }: EvalDetailProps) { const { mode } = useAudienceMode() const isResearchView = mode === "research" // The leaderboard section reads from `lb` (the active split when one is // selected, else the page-level summary). Hero / cards / signals continue to // read from `summary` so the rich info above the leaderboard stays stable. const lb = activeSummary ?? summary /** * Does the comparability data carry per-model attribution we can actually * surface? When false the apples-to-apples banner switches to honest copy * that doesn't promise a model list / panel that won't render. The * producer pipeline ships rollup counts even on benchmarks where the * per-row `has_*_divergence` flags and per-group breakdowns are empty * (e.g. cocoabench), so this guard avoids a misleading banner. */ const hasComparabilityActionableDetail = useMemo(() => { const ann = summary.evalcards?.annotations?.benchmark_comparability if ((ann?.variant_divergence_groups?.length ?? 0) > 0) return true if ((ann?.cross_party_divergence_groups?.length ?? 0) > 0) return true for (const r of summary.model_results ?? []) { const a = r.result?.evalcards?.annotations if (a?.variant_divergence?.has_variant_divergence) return true if (a?.cross_party_divergence?.has_cross_party_divergence) return true } return false }, [summary.evalcards?.annotations?.benchmark_comparability, summary.model_results]) // Multi-metric leaderboard is only meaningful when there is more than one // *root* metric. Subtask-scope entries are slices of one root metric (e.g. // Global MMLU has 19 language slices of `score`); promoting them to columns // here makes the matrix mix metrics and splits in confusing ways. Those // evals fall into the single-metric branch where a slice picker drives the // score column instead. const rootMetricCount = (lb.leaderboard_metrics ?? []).filter( (m) => m.scope !== "subtask", ).length const hasMultiMetricLeaderboard = rootMetricCount > 1 && (lb.leaderboard_rows?.length ?? 0) > 0 const [overviewOpen, setOverviewOpen] = useState(true) // Collapse the dense technical overview by default in policy mode; expand // for researchers. Reset whenever the user switches modes. useEffect(() => { setOverviewOpen(isResearchView) }, [isResearchView]) const [expandedRows, setExpandedRows] = useState>({}) const [leaderboardPage, setLeaderboardPage] = useState(1) const [minParamStep, setMinParamStep] = useState(0) const [maxParamStep, setMaxParamStep] = useState(PARAM_RANGE_MAX_INDEX) const maxScore = lb.metric_config.max_score ?? 1 const minScore = lb.metric_config.min_score ?? 0 const range = maxScore - minScore const normalizeScore = (raw: number) => (range > 0 ? (raw - minScore) / range : raw) const numericMinParams = useMemo(() => paramStepToNumeric(minParamStep, "min"), [minParamStep]) const numericMaxParams = useMemo(() => paramStepToNumeric(maxParamStep, "max"), [maxParamStep]) // Slice picker — visible when the eval has a single root metric but // multiple subtask-scope entries (e.g. Global MMLU's 19 languages). // Picking a slice swaps each model's score for that slice's score // pulled from `lb.leaderboard_rows[i].values["{rootMetric}::{slice}"]`. const subtaskSlices = useMemo(() => { const seen = new Map() for (const metric of lb.leaderboard_metrics ?? []) { if (metric.scope === "subtask" && metric.subtask_key && !seen.has(metric.subtask_key)) { seen.set(metric.subtask_key, metric.subtask_name ?? metric.subtask_key) } } return Array.from(seen, ([key, name]) => ({ key, label: name })) }, [lb.leaderboard_metrics]) // Suppress the slice picker when a split picker is already in play. // For evals like Fibble Arena both pickers partition the same axis // (each split is one of the per-lie variants; each slice is the // matrix-backfilled subtask for the same per-lie variant), so showing // both reads as a redundant control. The page-level split is more // authoritative — it loads richer per-eval data — so it wins. const hasSlicePicker = !hasMultiMetricLeaderboard && subtaskSlices.length > 1 && !splitConfig const ALL_SLICE_KEY = "__all__" const [activeSlice, setActiveSlice] = useState(ALL_SLICE_KEY) // Reset the picker when the underlying eval changes (e.g. user flips // the page-level split dropdown to a sibling that doesn't carry the // previously-selected slice). useEffect(() => { setActiveSlice(ALL_SLICE_KEY) }, [lb.evaluation_id]) const primaryMetricColumn = useMemo( () => (lb.leaderboard_metrics ?? []).find((m) => m.scope !== "subtask") ?.column_key, [lb.leaderboard_metrics], ) const slicedScoreByRoute = useMemo(() => { if (!hasSlicePicker || activeSlice === ALL_SLICE_KEY || !primaryMetricColumn) { return null } const columnKey = `${primaryMetricColumn}::${activeSlice}` const map = new Map() for (const row of lb.leaderboard_rows ?? []) { if (!row.model_route_id) continue const value = row.values[columnKey] if (typeof value === "number" && Number.isFinite(value)) { map.set(row.model_route_id, value) } } return map }, [ hasSlicePicker, activeSlice, primaryMetricColumn, lb.leaderboard_rows, ]) const sortedResults = useMemo(() => { const sourceResults = slicedScoreByRoute ? lb.model_results .map((result) => { const route = result.model_route_id const overrideScore = route ? slicedScoreByRoute.get(route) : undefined return overrideScore != null ? { ...result, score: overrideScore } : null }) .filter((r): r is NonNullable => r !== null) : lb.model_results return [...sourceResults].sort((a, b) => lb.metric_config.lower_is_better ? a.score - b.score : b.score - a.score ) }, [lb.model_results, lb.metric_config.lower_is_better, slicedScoreByRoute]) const [showUnknownSize, setShowUnknownSize] = useState(true) // Protocol-varied collections (e.g. the AISI inference-scaling study): // rows may carry a protocol_condition. Assisted (answer-feedback) runs // are shown but UNRANKED by default — mirroring the backend, which never // serves them a rank — with an explicit opt-in that re-includes them in // the client-side ranking. const hasProtocolRows = useMemo( () => lb.model_results.some((r) => r.protocol_condition != null), [lb.model_results] ) const protocolRowCount = useMemo( () => lb.model_results.filter((r) => r.protocol_condition != null).length, [lb.model_results] ) const allRowsHaveProtocol = protocolRowCount === lb.model_results.length const hasAssistedRows = useMemo( () => lb.model_results.some((r) => isAssistedResult(r.protocol_condition)), [lb.model_results] ) const [includeAssistedInRanking, setIncludeAssistedInRanking] = useState(false) const hasParameterData = useMemo( () => sortedResults.some((result) => getParamsBillions(result) != null), [sortedResults] ) const filteredResults = useMemo(() => { return sortedResults.filter((modelResult) => { const paramsBillions = getParamsBillions(modelResult) if (paramsBillions == null) return showUnknownSize if (numericMinParams != null && paramsBillions < numericMinParams) return false if (numericMaxParams != null && paramsBillions > numericMaxParams) return false return true }) }, [numericMaxParams, numericMinParams, showUnknownSize, sortedResults]) const leaderboardRows = useMemo(() => { let currentRank = 0 let previousScore: number | null = null let rankedCount = 0 return filteredResults.map((modelResult, index) => { // Assisted runs are visible but take no rank (rank 0 sentinel) // unless the reader explicitly re-includes them. const unranked = !includeAssistedInRanking && isAssistedResult(modelResult.protocol_condition) let rank = 0 if (!unranked) { rankedCount += 1 if (previousScore === null || Math.abs(modelResult.score - previousScore) > 1e-9) { currentRank = rankedCount previousScore = modelResult.score } rank = currentRank } return { key: `${modelResult.model_info.id}-${index}`, rank, modelResult, normalizedScore: normalizeScore(modelResult.score), } }) }, [filteredResults, includeAssistedInRanking]) // Plotbox input: assisted runs stay out of the distribution stats and // the frontier cumulative-best regardless of the ranking toggle — a // "best" that needed the answer oracle is not a frontier. const unassistedLeaderboardRows = useMemo( () => leaderboardRows.filter((r) => !isAssistedResult(r.modelResult.protocol_condition)), [leaderboardRows] ) // Compute-view protocol points, fed to the plotbox as a SEPARATE // series (the Distribution/Frontier paths never read it). Gated on the // per-source-only collection attachment + the server-chosen axis, so // the chip can never appear on merged pages. Assisted rows ARE // included here — the condition legend makes the labeling explicit. const computeProtocol = useMemo( () => buildComputeProtocolSeries(lb.model_results, summary.collection, isResearchView) ?? undefined, [summary.collection, lb.model_results, isResearchView], ) // Optional user-driven sort. `default` keeps the score-ordered rows // the ranker already produced. The rank label is always by score // regardless of row order — it's the model's standing on this metric, // not its position in the visible table. type RowSortKey = | "default" | "model" | "developer" | "score" | "evaluator" | "source" | "released" | "updated" const [userRowSort, setUserRowSort] = useState<{ key: RowSortKey; dir: "asc" | "desc" }>( { key: "default", dir: "desc" }, ) const orderedLeaderboardRows = useMemo(() => { if (userRowSort.key === "default") return leaderboardRows // `leaderboardRows` is already "best first" — descending for // higher-is-better metrics, ascending for lower-is-better. Sorting // by score just toggles that order verbatim. if (userRowSort.key === "score") { return userRowSort.dir === "desc" ? leaderboardRows : [...leaderboardRows].reverse() } const parseTs = (d?: string | null): number | null => { if (!d) return null const t = new Date(d).getTime() return Number.isFinite(t) ? t : null } const evaluatorOrder: Record = { first_party: 0, collaborative: 1, third_party: 2, } const sourceLabel = (r: ModelResultForBenchmark): string => (r.source_metadata.source_name?.trim() || r.source_metadata.source_organization_name?.trim() || (typeof r.source_metadata.source_type === "string" ? r.source_metadata.source_type : "") || "").toLowerCase() const dirSign = userRowSort.dir === "asc" ? 1 : -1 return [...leaderboardRows].sort((a, b) => { const ma = a.modelResult const mb = b.modelResult let cmp = 0 switch (userRowSort.key) { case "model": cmp = (ma.model_info.name ?? "").localeCompare(mb.model_info.name ?? "") break case "developer": cmp = (ma.model_info.developer ?? "").localeCompare(mb.model_info.developer ?? "") break case "evaluator": { const av = evaluatorOrder[ma.source_metadata.evaluator_relationship] ?? 99 const bv = evaluatorOrder[mb.source_metadata.evaluator_relationship] ?? 99 cmp = av - bv break } case "source": cmp = sourceLabel(ma).localeCompare(sourceLabel(mb)) break case "released": case "updated": { const ta = userRowSort.key === "released" ? parseTs(ma.model_info.release_date) : parseTs(ma.evaluation_timestamp) const tb = userRowSort.key === "released" ? parseTs(mb.model_info.release_date) : parseTs(mb.evaluation_timestamp) // Always push unknown timestamps to the bottom — flipping // direction shouldn't make missing data masquerade as old or // new; it's neither. if (ta == null && tb == null) cmp = 0 else if (ta == null) return 1 else if (tb == null) return -1 else cmp = ta - tb break } } // Stable name fallback so equal keys don't shuffle on re-render. if (cmp === 0) cmp = (ma.model_info.name ?? "").localeCompare(mb.model_info.name ?? "") return cmp * dirSign }) }, [leaderboardRows, userRowSort]) const LEADERBOARD_PAGE_SIZE = 50 const pagedLeaderboardRows = useMemo( () => orderedLeaderboardRows.slice(0, leaderboardPage * LEADERBOARD_PAGE_SIZE), [orderedLeaderboardRows, leaderboardPage] ) // First click on a column picks a sensible initial direction (alpha // for text, "best/most-recent first" for numeric/date). Second click // flips. Third click returns to the page's natural order. const naturalDir = (key: Exclude): "asc" | "desc" => key === "model" || key === "developer" || key === "evaluator" || key === "source" ? "asc" : "desc" const cycleRowSort = (key: Exclude) => setUserRowSort((prev) => { // For "score" the default order already IS desc, so the visible // first-click flip is to asc. if (key === "score") { if (prev.key !== "score") return { key: "score", dir: "asc" } return { key: "default", dir: "desc" } } const initial = naturalDir(key) if (prev.key !== key) return { key, dir: initial } if (prev.dir === initial) return { key, dir: initial === "asc" ? "desc" : "asc" } return { key: "default", dir: "desc" } }) const rowSortIndicator = (key: Exclude): "↑" | "↓" | null => { if (key === "score") { if (userRowSort.key === "default") return "↓" if (userRowSort.key === "score") return userRowSort.dir === "asc" ? "↑" : "↓" return null } if (userRowSort.key !== key) return null return userRowSort.dir === "asc" ? "↑" : "↓" } const avgScoreLabel = formatRawScore(lb.avg_score, lb.metric_config.unit) const scoreDirectionLabel = lb.metric_config.lower_is_better ? "Lower scores rank higher" : "Higher scores rank higher" const leaderboardTitle = isResearchView ? "Leaderboard" : "Reporting Comparison" const sourceDatasetLabel = summary.source_data?.hf_repo ?? summary.source_data?.dataset_name ?? "Summary source" const instanceDataLabel = summary.instance_data?.available ? `${summary.instance_data.url_count.toLocaleString()} linked URL${summary.instance_data.url_count === 1 ? "" : "s"}` : "Not linked" const leaderboardDescription = isResearchView ? lb.is_aggregated ? "Models ranked by average raw score across the composite's component benchmarks." : "Models ranked by raw score for this benchmark." : lb.is_aggregated ? "Averaged model results across the composite's component benchmarks, with drill-down to each component score." : "Model results with benchmark context, upstream dataset detail, and optional instance-data links." const reportingCompleteness = summary.evalcards?.annotations?.reporting_completeness const documentationPopulatedCount = reportingCompleteness ? getCompletenessPopulatedCount(reportingCompleteness) : null const toggleRow = (key: string) => setExpandedRows((current) => ({ ...current, [key]: !current[key], })) // Prefer the curated family name from hierarchy.json — the producer's // composite_benchmark_name often equals the eval's own slug (e.g. // "cyse2_interpreter_abuse"), so the header repeats itself. When the // hierarchy resolves a different parent family ("CySE2"), use that instead. const hierarchyHeaderOrg = (() => { const familyName = hierarchyLocation?.familyDisplayName?.trim() if (!familyName || familyName === summary.evaluation_name) { return null } return familyName })() const headerOrg = hierarchyHeaderOrg ?? (summary.composite_benchmark_name && summary.composite_benchmark_name !== summary.evaluation_name ? summary.composite_benchmark_name : null) // Surface the evaluator (org that ran the eval) as a hero kicker. Two // benchmarks can share the same upstream dataset (e.g. TIGER-Lab/MMLU-Pro // re-evaluated by both TIGER-Lab and Arcadia Impact) and otherwise look // identical in chrome — naming the evaluator up-front is the cheapest // way to make the pages visually distinct. const evaluatorList = summary.evaluator_names ?? [] // Validated evaluators (de-aliased names, same space as evaluator_names), // straight from the backend rollup — used to badge the "Reported by" names. const verifiedEvaluators = useMemo( () => new Set(summary.verified_evaluator_names ?? []), [summary.verified_evaluator_names], ) // De-aliased evaluator names that have a /evaluators/ page. The header // renders these names directly (always linkable); the per-row Source column // shows a *raw* source name, so we resolve it case-insensitively against the // known evaluator names and only link when it maps to a real evaluator page. // We key on the union of summary + active-split evaluator names so a split // view's Source cells still resolve. const knownEvaluatorByLower = useMemo(() => { const m = new Map() for (const n of [...(summary.evaluator_names ?? []), ...(lb.evaluator_names ?? [])]) { const t = (n ?? "").trim() if (t) m.set(t.toLowerCase(), t) } return m }, [summary.evaluator_names, lb.evaluator_names]) // Resolve a (raw or de-aliased) org name to a known evaluator's de-aliased // name, or null when it isn't a known evaluator (→ render plain text). The // per-row Source value is the *raw* source name (e.g. "crfm"), which can be // an alias of a de-aliased evaluator ("Stanford CRFM"); when it doesn't match // directly but the eval has exactly one evaluator, that row unambiguously // belongs to it, so we link to the sole evaluator. const soleEvaluator = knownEvaluatorByLower.size === 1 ? Array.from(knownEvaluatorByLower.values())[0] : null const resolveEvaluatorName = (raw: string | undefined | null): string | null => { const t = (raw ?? "").trim() if (!t) return null return knownEvaluatorByLower.get(t.toLowerCase()) ?? soleEvaluator } const heroLede = isResearchView ? summary.metric_config.evaluation_description : (summary.benchmark_card?.benchmark_details?.overview?.trim() || summary.benchmark_card?.purpose_and_intended_users?.goal?.trim() || summary.metric_config.evaluation_description) return (
{/* HERO ------------------------------------------------ */}
{evaluatorList.length > 0 && (
Reported by {evaluatorList.slice(0, 2).map((name, i) => ( {i > 0 ? ", " : null} ))} {evaluatorList.length > 2 ? ( +{evaluatorList.length - 2} more ) : null}
)}

{lb.evaluation_name}

{headerOrg && ( <> {headerOrg} · )} {lb.metric_config.score_type} · {lb.metric_config.lower_is_better ? "Lower is better ↓" : "Higher is better ↑"} {lb.derived_tags && lb.derived_tags.length > 0 && ( <> · {lb.derived_tags.map(tagLabel).join(", ")} )} {lb.tags?.languages && lb.tags.languages.length > 0 && ( <> · {lb.tags.languages.slice(0, 3).join(", ")} )}
{/* Study attribution, curated collections only. */} {summary.collection?.curated && (
Part of{" "} {summary.collection.display_name} {summary.collection.url && ( <> {" · "} paper ↗ )}
)} {/* Summary view renders the description inside the "At a glance" card just below — avoid duplicating it in the hero. Researcher view's heroLede is the metric-config description (different text from the overview), so it stays. */} {isResearchView && (

{heroLede}

)}
{/* AT A GLANCE (Summary view only) — pinned above the benchmark card so non-technical readers land on plain-language framing first. */} {!isResearchView && } {/* BENCHMARK CARD — top-level collapsible. In Researcher view it defaults open (methodology is the headline). In Summary view it defaults collapsed so non-technical readers aren't drowned in the dataset/methodology/risks fields up front. Suppressed entirely when there's nothing useful to show. */} {summary.benchmark_card && ( )} {/* TECHNICAL OVERVIEW — secondary, collapsed by default in policy mode. Holds metric spec, completeness/comparability signals, and benchmark structure (sub-tasks). Tucked away so the hero / card / policy note carry the page's primary read. -------------------------------- */}
{/* Four interpretive signals, benchmark-level. */} {/* Metric spec / nested datalist (paper-aligned hairline def-list) */}
{isResearchView ? "Metric specification" : "Reading context"}
Composite
{summary.is_aggregated ? summary.aggregate_sources?.map((source) => source.composite_benchmark_name).join(", ") || "Multiple composites" : summary.composite_benchmark_name}
{isResearchView ? "Benchmark ID" : "What this covers"}
{isResearchView ? humanizeEvaluationId(summary.evaluation_id) : summary.metric_config.evaluation_description}
{isResearchView ? "Score scale" : "How to read scores"}
{isResearchView ? `${summary.metric_config.min_score ?? 0} – ${summary.metric_config.max_score ?? 1}` : scoreDirectionLabel}
Models
{summary.models_count.toLocaleString()}
{hasMultiMetricLeaderboard ? "Measures" : "Avg score"}
{hasMultiMetricLeaderboard ? summary.metrics_count ?? summary.leaderboard_metrics?.length ?? 1 : avgScoreLabel}
{summary.tags?.domains && summary.tags.domains.length > 0 && ( <>
Domain tags
{summary.tags.domains.slice(0, 4).join(", ")} {summary.tags.domains.length > 4 ? ` +${summary.tags.domains.length - 4} more` : ""}
)}
Upstream dataset
{sourceDatasetLabel}
Instance data
{instanceDataLabel}
{reportingCompleteness && ( <>
Card completeness
{Math.round(reportingCompleteness.completeness_score * 100)}% ({documentationPopulatedCount}/{reportingCompleteness.total_fields_evaluated} fields)
)}
{/* The compact BenchmarkSignalsStrip above already covers * completeness and comparability with paper-aligned framing, * so the standalone rounded shadcn cards that used to live * here are intentionally dropped. */} {!hasMultiMetricLeaderboard && (summary.root_metrics?.length || summary.subtasks?.length) ? (
Benchmark structure

Benchmark-level summary metrics and slices grouped in one section.

{summary.root_metrics && summary.root_metrics.length > 0 && (
Benchmark-level metrics
{summary.root_metrics.map((metric) => ( {getCompactMetricLabel(metric.display_name)} {typeof metric.top_score === "number" ? ` · ${formatRawScore(metric.top_score, metric.unit)}` : ""} ))}
)} {summary.subtasks && summary.subtasks.length > 0 && (() => { // When every slice reports the same single metric (e.g. all // Global MMLU language splits share "score · proportion"), // hoist the metric label to the section header and render // each slice as a compact "name value" row in a multi- // column grid. Otherwise fall back to per-row metric badges. const firstMetric = summary.subtasks[0]?.metrics?.[0] const uniformSingleMetric = !!firstMetric && summary.subtasks.every( (s) => s.metrics.length === 1 && getCompactMetricLabel(s.metrics[0].display_name) === getCompactMetricLabel(firstMetric.display_name) && (s.metrics[0].unit ?? null) === (firstMetric.unit ?? null), ) const headerSuffix = uniformSingleMetric ? ` · ${getCompactMetricLabel(firstMetric!.display_name)}${ firstMetric!.unit ? ` (${firstMetric!.unit.toLowerCase()})` : "" }` : "" return (
Split breakdown · {summary.subtasks.length} {headerSuffix}
{uniformSingleMetric ? (
{summary.subtasks.map((slice) => { const metric = slice.metrics[0] return (
{slice.display_name || slice.subtask_name} {typeof metric.top_score === "number" ? formatRawScore(metric.top_score, metric.unit) : "—"}
) })}
) : (
    {summary.subtasks.map((slice) => (
  • {slice.display_name || slice.subtask_name}
    {slice.canonical_display_name && slice.canonical_display_name !== (slice.display_name || slice.subtask_name) && (
    {slice.canonical_display_name}
    )}
    {slice.metrics.map((metric) => ( {getCompactMetricLabel(metric.display_name)} {typeof metric.top_score === "number" ? ` · ${formatRawScore(metric.top_score, metric.unit)}` : ""} ))}
  • ))}
)}
) })()}
) : null}
{/* Comparability deep-dive — sits with the rest of the eval metadata above the leaderboard. Auto-hidden by the panel itself when there are no divergence groups to show. */} {hasMultiMetricLeaderboard ? (
) : (

{leaderboardTitle}

{/* Merged pages count OBSERVATION rows (one per model+source), so "5024 of 4882" phrasing would read as a broken filter — spell out both grains instead. */} {lb.merged_view ? `${leaderboardRows.length.toLocaleString()} results · ${lb.models_count.toLocaleString()} models` : leaderboardRows.length === lb.models_count ? `${lb.models_count} models` : `${leaderboardRows.length} of ${lb.models_count}`} {" · "} {lb.metric_config.lower_is_better ? "lower is better ↓" : "higher is better ↑"} {isResearchView && ( <> {" · "}scale {lb.metric_config.min_score ?? 0}–{lb.metric_config.max_score ?? 1} )}

{leaderboardDescription}

{splitConfig && ( )} {/* Subtask split picker for evals like Global MMLU Lite where the splits live as subtasks of a single eval (not as separate eval IDs the page-level SplitPicker can swap to). Suppressed when a page-level split is already in play — two pickers would partition the same axis (see fibble). */} {hasSlicePicker && ( ({ id: s.key, label: s.label })), ], }} /> )} {/* Score distribution — paper-themed mean/median/quartile summary, with an optional Frontier toggle when models carry release dates. */} {hasProtocolRows && (
Study-specific protocol.{" "} {allRowsHaveProtocol ? "This study ran models with much larger inference budgets than standard evaluations. Compare with published scores with caution." : `${protocolRowCount} of the results below come from a study that used much larger inference budgets. Compare them with the other rows or with published scores with caution.`} {hasAssistedRows && ( <> {" "}Assisted runs, where the model is told when its answer is correct, are labeled and excluded from ranking {includeAssistedInRanking ? " (currently included)" : ""}.{" "} )} {studySourceHref && ( <> {" "} View the study's per-setting analysis → )}
)} {unassistedLeaderboardRows.length >= 3 && (
r.modelResult.score), unit: lb.metric_config.unit, lowerIsBetter: lb.metric_config.lower_is_better, points: unassistedLeaderboardRows.map((r) => ({ score: r.modelResult.score, releaseDate: r.modelResult.model_info.release_date, modelName: r.modelResult.model_info.name, })), }]} protocol={computeProtocol} />
)} {/* Trajectory panels for per-source collection pages only: the attachment is per-source, and the section hides itself when the route serves no data. */} {summary.collection?.has_trajectories && ( )} {hasParameterData && (
{ setMinParamStep(0) setMaxParamStep(PARAM_RANGE_MAX_INDEX) }} showUnknownSize={showUnknownSize} onShowUnknownSizeChange={setShowUnknownSize} />
)}
{/* Mobile (< lg): compact embed-style list — rank, model · developer, score. Drops the expand chevron, the score bar, and the four extra columns. Tapping the row's model name still navigates to the model page; everything else stays on the desktop layout below. */}
{pagedLeaderboardRows.map(({ key, rank, modelResult }) => ( ))} {pagedLeaderboardRows.length === 0 && ( )}
# Model {lb.metric_config.unit ?? "Score"}
{rank} {modelResult.model_info.name} {modelResult.model_info.developer && ( · {modelResult.model_info.developer} )} {/* Unit suffix omitted — already shown in the column header so it doesn't need to repeat on every row. */} {formatRawScore(modelResult.score)}
No leaderboard entries match the selected parameter range.
{/* Desktop (≥ lg): full rich table with sortable columns, row expansion, score bar, evaluator/source/release/updated. */}
{pagedLeaderboardRows.map(({ key, rank, modelResult, normalizedScore }) => { const isExpanded = expandedRows[key] ?? false const slices = modelResult.score_details.details ? Object.entries(modelResult.score_details.details).filter(([, value]) => typeof value === "number") : [] const hasExpandableDetails = isResearchView || (modelResult.aggregate_components && modelResult.aggregate_components.length > 1) || slices.length > 1 const datasetName = Array.isArray(modelResult.source_data) ? undefined : modelResult.source_data.dataset_name const samples = Array.isArray(modelResult.source_data) ? undefined : modelResult.source_data.samples_number const rowAnnotations = modelResult.result.evalcards?.annotations const setupLabel = getSetupLabel(modelResult) const evaluatorRel = modelResult.source_metadata.evaluator_relationship const evaluatorTag = evaluatorRel === "first_party" ? "SELF" : evaluatorRel === "third_party" ? "THIRD-PARTY" : "—" const isThirdParty = evaluatorRel === "third_party" // Prefer the human-readable source name (e.g. "kaggle", // "Anthropic Eval Run") over `source_data.source_type`, // which can be a file format like "Parquet" that's // useless to a reader. Fall back to source_type only // when nothing else is set. const sourceTypeLabel = // De-aliased evaluator identity first: upstream raw // strings can carry stale spellings (e.g. the AISI // "Initiative"→"Institute" rename) that the registry // has already resolved. modelResult.evaluator_display_name?.trim() || modelResult.source_metadata.source_name?.trim() || modelResult.source_metadata.source_organization_name?.trim() || (!Array.isArray(modelResult.source_data) && modelResult.source_data.source_type) || modelResult.source_metadata.source_type || "" // Link the Source value to its evaluator page when the row's // org resolves to a known (de-aliased) evaluator. Try the org // name first, then the displayed source label. const sourceEvaluatorName = resolveEvaluatorName(modelResult.source_metadata.source_organization_name) ?? resolveEvaluatorName(modelResult.source_metadata.source_name) ?? resolveEvaluatorName(sourceTypeLabel) const familyLabel = modelResult.model_info.architecture ?? modelResult.model_info.parameter_count ?? null // Release date is benchmark-agnostic model metadata, but // showing it under the model name lets a researcher orient // a row in time without expanding it / clicking through. const releaseDateLabel = modelResult.model_info.release_date ? formatDate(modelResult.model_info.release_date).split(",")[0] : null const isTopRank = rank === 1 const rankColor = rank === 1 ? "var(--accent)" : "var(--fg-muted)" const isAssisted = isAssistedResult(modelResult.protocol_condition) return ( {isExpanded && ( )} ) })} {leaderboardRows.length === 0 && ( )}
Rank cycleRowSort("model")} /> cycleRowSort("developer")} /> cycleRowSort("score")} title="Sort by score" /> cycleRowSort("evaluator")} title="Sort by evaluator relationship (1st-party first)" /> cycleRowSort("source")} /> cycleRowSort("released")} title="Sort by model release date" />
{rank === 0 ? "—" : `#${rank}`}
{hasExpandableDetails && ( )}
{modelResult.model_info.name} {isAssisted && ( assisted )} {familyLabel && (
{familyLabel}
)} {/* Mobile-only developer line. On desktop the Developer is its own column; on narrow viewports it folds under the model name to save horizontal space. */}
{modelResult.model_info.developer ?? "Unknown developer"}
{modelResult.aggregate_components && modelResult.aggregate_components.length > 1 && (
Avg of {modelResult.aggregate_components.length}
)}
{modelResult.model_info.developer ?? "Unknown developer"}
{/* Score with inline performance bar so the previously-dedicated bar column can be dropped — its only purpose was visualising this same number. Caption shows shot/CoT setup or a differing dataset name when available; otherwise it's omitted. */}
{formatRawScore(modelResult.score, undefined)}
{setupLabel && (
{setupLabel}
)} {!setupLabel && datasetName && !isResearchView && datasetName !== lb.evaluation_name && (
{datasetName}
)} {/* Per-row signal badges (reproducibility, provenance, variant/cross-party divergence) — make the apples-to-apples banner's "per-row signal badges below" reference concrete on the single-metric leaderboard. */}
{evaluatorTag} {sourceTypeLabel ? ( {sourceEvaluatorName ? ( ) : modelResult.source_metadata.source_url ? ( e.stopPropagation()} > {sourceTypeLabel} ) : ( {sourceTypeLabel} )} ) : ( )} {modelResult.model_info.release_date ? formatDate(modelResult.model_info.release_date).split(",")[0] : }
{/* The Model Profile / Provenance / Score Breakdown panels were removed — model metadata lives on the model page (the model name in the row is a link), provenance is already in the EVALUATOR + SOURCE columns, and metric scale / score type are constants surfaced in the Metric Specification block above the leaderboard. The expanded row now focuses exclusively on the per-result reproducibility setup. */} {modelResult.aggregate_components && modelResult.aggregate_components.length > 1 && (
Composite score breakdown
{modelResult.aggregate_components.map((component, i) => ( ))}
Benchmark Source Raw
{component.composite_benchmark_name} {component.source_organization_name} {formatRawScore(component.score)}
)} {slices.length > 1 && (
Split breakdown
{slices.map(([sliceName, value]) => { const numericValue = value as number return ( ) })}
Split Raw
{sliceName.replace(/_/g, " ")} {formatRawScore(numericValue, lb.metric_config.unit)}
)} {isResearchView ? (
) : ( modelResult.result.generation_config && (
Generation config
Evaluation-time generation parameters.
{modelResult.result.generation_config.generation_args && Object.entries(modelResult.result.generation_config.generation_args).map(([key, value]) => (
{key.replace(/_/g, " ")}
{formatMetadataValue(value)}
))} {modelResult.result.generation_config.additional_details && (
Additional details
{formatMetadataValue(modelResult.result.generation_config.additional_details)}
)} {modelResult.result.generation_config.prompt_template && (
Prompt template
{formatMetadataValue(modelResult.result.generation_config.prompt_template)}
)}
) )}
No leaderboard entries match the selected parameter range.
{pagedLeaderboardRows.length < leaderboardRows.length && (
)}
)}
) } function MultiMetricLeaderboard({ summary, isResearchView, splitConfig, }: { summary: BenchmarkEvalSummary isResearchView: boolean splitConfig?: SplitConfig }) { const [page, setPage] = useState(1) // Default sort: the first root-scope metric (the benchmark's overall // score), falling back to the first metric overall, then to model name. // We don't sort by metric coverage by default — coverage tells you how // many slices reported, not how the model performed. const [sortKey, setSortKey] = useState(() => { const metrics = summary.leaderboard_metrics ?? [] const root = metrics.find((m) => m.scope === "root") return root?.column_key ?? metrics[0]?.column_key ?? "model" }) const [sortDirection, setSortDirection] = useState<"asc" | "desc">("desc") const [activeSliceTab, setActiveSliceTab] = useState("all") const [minParamStep, setMinParamStep] = useState(0) const [maxParamStep, setMaxParamStep] = useState(PARAM_RANGE_MAX_INDEX) const [expandedRows, setExpandedRows] = useState>({}) // Resolve a raw Source-column org name to a known (de-aliased) evaluator name // so the cell can link to /evaluators/; null → render plain text. const knownEvaluatorByLower = useMemo(() => { const m = new Map() for (const n of summary.evaluator_names ?? []) { const t = (n ?? "").trim() if (t) m.set(t.toLowerCase(), t) } return m }, [summary.evaluator_names]) const soleEvaluator = knownEvaluatorByLower.size === 1 ? Array.from(knownEvaluatorByLower.values())[0] : null const resolveEvaluatorName = (raw: string | undefined | null): string | null => { const t = (raw ?? "").trim() if (!t) return null return knownEvaluatorByLower.get(t.toLowerCase()) ?? soleEvaluator } // Index ModelResultForBenchmark entries by model_info.id so we can power the // research-mode reproducibility card from a multi-metric row. There may be // several entries per model (one per metric); we prefer one with a recorded // generation_config so the card has the most data to show. const modelResultByModelId = useMemo(() => { const map = new Map() for (const result of summary.model_results) { const id = result.model_info.id const existing = map.get(id) if (!existing) { map.set(id, result) continue } const existingHasGen = existing.result.generation_config != null const candidateHasGen = result.result.generation_config != null if (!existingHasGen && candidateHasGen) { map.set(id, result) } } return map }, [summary.model_results]) const toggleExpandedRow = (key: string) => setExpandedRows((current) => ({ ...current, [key]: !current[key] })) const leaderboardMetrics = summary.leaderboard_metrics ?? [] const leaderboardRows = summary.leaderboard_rows ?? [] const allMetricKeys = useMemo(() => leaderboardMetrics.map((metric) => metric.column_key), [leaderboardMetrics]) // Cap default visible columns to avoid hangs on benchmarks with hundreds of metrics // (e.g. helm_air_bench has 374 slice×metric pairs). Users can opt in to more. const DEFAULT_VISIBLE_METRIC_CAP = 24 const defaultVisibleMetricKeys = useMemo( () => allMetricKeys.slice(0, DEFAULT_VISIBLE_METRIC_CAP), [allMetricKeys] ) const [visibleMetricKeys, setVisibleMetricKeys] = useState(() => defaultVisibleMetricKeys) const leaderboardMetricMap = useMemo( () => new Map(leaderboardMetrics.map((metric) => [metric.column_key, metric])), [leaderboardMetrics] ) const visibleMetricKeySet = useMemo(() => new Set(visibleMetricKeys), [visibleMetricKeys]) // Labels for the "Visible measure columns" dropdown. The measure name alone // is ambiguous in two opposite ways: subtask benchmarks repeat one measure // across slices (ACE: every column is "Score"), while others repeat one // trivial slice across distinct measures (BFCL: Accuracy/Rank/… all "overall"). // So append the slice ONLY when the measure label actually collides with // another column — and never a trivial "overall"/"all"/"total" token. const metricDropdownLabels = useMemo(() => { const measureLabelOf = (m: LeaderboardMetric) => getMetricChipLabel(m) const measureCounts = new Map() for (const m of leaderboardMetrics) { const l = measureLabelOf(m) measureCounts.set(l, (measureCounts.get(l) ?? 0) + 1) } const isTrivialSlice = (s: string) => /^(overall|all|total|default)$/i.test(s) const out = new Map() for (const m of leaderboardMetrics) { const measureLabel = measureLabelOf(m) let label = measureLabel if ((measureCounts.get(measureLabel) ?? 0) > 1) { const subtask = m.subtask_name?.trim() ?? "" const keySuffix = m.column_key.includes("::") ? humanizeMetricKey(m.column_key.split("::").pop() ?? "") : "" const slice = subtask && !isTrivialSlice(subtask) ? subtask : keySuffix // Last resort: the humanised full key guarantees uniqueness when no // meaningful slice exists. label = slice ? `${measureLabel} · ${slice}` : `${measureLabel} · ${humanizeMetricKey(m.column_key)}` } const canonical = m.canonical_display_name?.trim() const description = canonical && canonical !== measureLabel && canonical !== label ? canonical : "" out.set(m.column_key, { label, description }) } return out }, [leaderboardMetrics]) // Every distinct subtask key surfaces as a slice option; metric chips // stay scoped to the eval's root metrics. Without this, evals like // Fibble Arena (3 metrics × 6 lies = 18 subtask entries) render every // (metric, slice) pair as its own chip/column — three "Mean Response // Time" chips next to three "Score" chips, etc. — which is what // produced the user-visible duplication. const sliceTabs = useMemo(() => { const seen = new Map() for (const metric of leaderboardMetrics) { if (metric.scope === "subtask" && metric.subtask_key && !seen.has(metric.subtask_key)) { seen.set(metric.subtask_key, metric.subtask_name ?? getCompactMetricLabel(metric.display_name)) } } return Array.from(seen, ([key, label]) => ({ key, label })) }, [leaderboardMetrics]) const hasSliceTabs = sliceTabs.length > 1 // A `.mean` column whose per-row values are identical to an // earlier column (e.g. cyse2's `cyse2-vulnerability-exploit.mean` mirrors // `accuracy`) is a redundant alias of the primary score, not a distinct // measure. Suppress it so the matrix doesn't render two columns of the same // numbers under a humanised "Mean" header next to the real metric. const duplicateMeanColumnKeys = useMemo(() => { const dupes = new Set() const meanMetrics = leaderboardMetrics.filter( (m) => m.scope !== "subtask" && /\.mean$/i.test(m.column_key), ) if (meanMetrics.length === 0) return dupes const others = leaderboardMetrics.filter((m) => m.scope !== "subtask") const valuesEqual = (a: string, b: string) => { let comparable = 0 for (const row of leaderboardRows) { const va = row.values[a] const vb = row.values[b] const aNum = isNumericScore(va) const bNum = isNumericScore(vb) if (aNum !== bNum) return false if (aNum && bNum && Math.abs(va - vb) > 1e-6) return false if (aNum && bNum) comparable += 1 } return comparable > 0 } for (const mean of meanMetrics) { const twin = others.find( (o) => o.column_key !== mean.column_key && valuesEqual(mean.column_key, o.column_key), ) if (twin) dupes.add(mean.column_key) } return dupes }, [leaderboardMetrics, leaderboardRows]) const visibleMetrics = useMemo( () => leaderboardMetrics.filter((metric) => { if (!visibleMetricKeySet.has(metric.column_key)) { return false } if (duplicateMeanColumnKeys.has(metric.column_key)) { return false } if (!hasSliceTabs || activeSliceTab === "all") { // "All" / no-slice-filter case: only show root metrics so the // chips stay one-per-metric instead of one-per-(metric, slice). return metric.scope !== "subtask" } return metric.scope === "subtask" && metric.subtask_key === activeSliceTab }), [activeSliceTab, duplicateMeanColumnKeys, hasSliceTabs, leaderboardMetrics, visibleMetricKeySet] ) const visibleMetricColumnKeySet = useMemo( () => new Set(visibleMetrics.map((metric) => metric.column_key)), [visibleMetrics] ) // Column-uniform percent presentation: matrix cells arrive on the // metric's canonical scale, so a percent-unit column whose values are // all fractions renders ×100 with a % suffix. Decided per column over // every row — a mixed column (old snapshot without canonical scores) // keeps raw values untouched rather than half-converting. const percentDisplayColumns = useMemo(() => { const out = new Set() for (const metric of leaderboardMetrics) { if (!/percent|%|pct/i.test(metric.unit ?? "")) continue let sawValue = false let allFractions = true for (const row of leaderboardRows) { const v = row.values[metric.column_key] if (typeof v !== "number" || !Number.isFinite(v)) continue sawValue = true if (Math.abs(v) > 1.5) { allFractions = false break } } if (sawValue && allFractions) out.add(metric.column_key) } return out }, [leaderboardMetrics, leaderboardRows]) const numericMinParams = useMemo(() => paramStepToNumeric(minParamStep, "min"), [minParamStep]) const numericMaxParams = useMemo(() => paramStepToNumeric(maxParamStep, "max"), [maxParamStep]) const [showUnknownSize, setShowUnknownSize] = useState(true) const hasParameterData = useMemo( () => leaderboardRows.some((row) => getParamsBillionsFromModelInfo(row.model_info) != null), [leaderboardRows] ) const filteredRows = useMemo(() => { return leaderboardRows.filter((row) => { const paramsBillions = getParamsBillionsFromModelInfo(row.model_info) if (paramsBillions == null) return showUnknownSize if (numericMinParams != null && paramsBillions < numericMinParams) return false if (numericMaxParams != null && paramsBillions > numericMaxParams) return false return true }) }, [leaderboardRows, numericMaxParams, numericMinParams, showUnknownSize]) const sortedRows = useMemo(() => { const rows = [...filteredRows] const compareNames = (left: LeaderboardMatrixRow, right: LeaderboardMatrixRow) => left.model_info.name.localeCompare(right.model_info.name) || (left.model_info.developer ?? "").localeCompare(right.model_info.developer ?? "") const compareTimestamps = (left: string, right: string) => { const leftNumeric = Number(left) const rightNumeric = Number(right) const leftTimestamp = !Number.isNaN(leftNumeric) && !left.includes("-") ? leftNumeric * 1000 : new Date(left).getTime() const rightTimestamp = !Number.isNaN(rightNumeric) && !right.includes("-") ? rightNumeric * 1000 : new Date(right).getTime() return leftTimestamp - rightTimestamp } rows.sort((left, right) => { if (sortKey === "model") { const comparison = compareNames(left, right) return sortDirection === "asc" ? comparison : -comparison } if (sortKey === "developer") { const comparison = (left.model_info.developer ?? "").localeCompare(right.model_info.developer ?? "") || compareNames(left, right) return sortDirection === "asc" ? comparison : -comparison } if (sortKey === "updated") { const comparison = compareTimestamps(left.evaluation_timestamp, right.evaluation_timestamp) || compareNames(left, right) return sortDirection === "asc" ? comparison : -comparison } if (sortKey === "released") { const lt = left.model_info.release_date const rt = right.model_info.release_date const lMissing = !lt const rMissing = !rt if (lMissing && rMissing) return compareNames(left, right) // Push unknown release dates to the bottom regardless of direction. if (lMissing) return 1 if (rMissing) return -1 const comparison = compareTimestamps(lt, rt) || compareNames(left, right) return sortDirection === "asc" ? comparison : -comparison } const metric = leaderboardMetricMap.get(sortKey) if (metric) { const leftValue = left.values[sortKey] const rightValue = right.values[sortKey] const leftHasValue = isNumericScore(leftValue) const rightHasValue = isNumericScore(rightValue) if (leftHasValue && rightHasValue) { const comparison = leftValue - rightValue || compareNames(left, right) return sortDirection === "asc" ? comparison : -comparison } if (leftHasValue !== rightHasValue) { return leftHasValue ? -1 : 1 } } return compareNames(left, right) }) return rows }, [filteredRows, leaderboardMetricMap, sortDirection, sortKey]) useEffect(() => { setPage(1) }, [maxParamStep, minParamStep, sortDirection, sortKey]) useEffect(() => { setVisibleMetricKeys(defaultVisibleMetricKeys) }, [defaultVisibleMetricKeys, summary.evaluation_id]) useEffect(() => { setActiveSliceTab("all") }, [summary.evaluation_id]) useEffect(() => { if (leaderboardMetricMap.has(sortKey) && !visibleMetricColumnKeySet.has(sortKey)) { // The currently-sorted metric was hidden — fall back to the first // visible root-scope metric, then the first visible metric overall, // then to the model name. const visibleRoot = leaderboardMetrics.find( (m) => m.scope === "root" && visibleMetricColumnKeySet.has(m.column_key), ) const fallback = visibleRoot?.column_key ?? leaderboardMetrics.find((m) => visibleMetricColumnKeySet.has(m.column_key))?.column_key ?? "model" setSortKey(fallback) setSortDirection("desc") } }, [leaderboardMetricMap, leaderboardMetrics, sortKey, visibleMetricColumnKeySet]) useEffect(() => { if (!hasSliceTabs) { if (activeSliceTab !== "all") { setActiveSliceTab("all") } return } if (activeSliceTab === "all") { return } if (!sliceTabs.some((tab) => tab.key === activeSliceTab)) { setActiveSliceTab("all") } }, [activeSliceTab, hasSliceTabs, sliceTabs]) const pagedRows = useMemo( () => sortedRows.slice(0, page * 50), [page, sortedRows] ) const rankByModelId = useMemo( () => new Map(sortedRows.map((row, index) => [row.model_info.id, index + 1])), [sortedRows] ) const setMetricVisibility = (metricKey: string, nextVisible: boolean) => { setVisibleMetricKeys((current) => { if (nextVisible) { return allMetricKeys.filter((key) => key === metricKey || current.includes(key)) } return current.filter((key) => key !== metricKey) }) } const getDefaultSortDirection = (key: string): "asc" | "desc" => { if (key === "model" || key === "developer") { return "asc" } if (key === "updated") { return "desc" } return leaderboardMetricMap.get(key)?.lower_is_better ? "asc" : "desc" } const handleSort = (key: string) => { if (sortKey === key) { setSortDirection((current) => (current === "asc" ? "desc" : "asc")) return } setSortKey(key) setSortDirection(getDefaultSortDirection(key)) } const getSortIndicator = (key: string) => { if (sortKey !== key) { return "" } return sortDirection === "asc" ? " ▲" : " ▼" } return (
{/* The parent EvalDetail already renders the apples-to-apples banner before this leaderboard section — duplicating it here made the box appear twice on multi-metric evals like fibble. */}

{isResearchView ? "Leaderboard" : "Reporting Comparison"}

{filteredRows.length === leaderboardRows.length ? `${leaderboardRows.length} models` : `${filteredRows.length} of ${leaderboardRows.length} models`} {" · "} {visibleMetrics.length === leaderboardMetrics.length ? `${leaderboardMetrics.length} measures` : `${visibleMetrics.length} of ${leaderboardMetrics.length} measures`}

{isResearchView ? "Each column is a reported benchmark measure." : "Each column is a separately reported measure so the benchmark can be read without flattening different results into one number."}

Visible measure columns setVisibleMetricKeys(allMetricKeys)} className="rounded-none focus:bg-[color:var(--bg-warm)]" style={{ padding: "8px 12px", color: "var(--accent)" }} > Show all {leaderboardMetrics.map((metric) => { const isVisible = visibleMetricKeySet.has(metric.column_key) const isLastVisible = isVisible && visibleMetrics.length === 1 const { label: visibleLabel, description: visibleDescription } = metricDropdownLabels.get(metric.column_key) ?? { label: getMetricChipLabel(metric), description: "", } return ( setMetricVisibility(metric.column_key, checked === true)} className="items-start rounded-none focus:bg-[color:var(--bg-warm)]" style={{ padding: "8px 12px 8px 32px" }} >
{visibleLabel} {visibleDescription && ( {visibleDescription} )}
) })}
{splitConfig && ( )} {/* Distribution panel — one curve, dropdown swaps between metrics */} {(() => { const distSeries = visibleMetrics .map((metric) => { // Same ×100 presentation as the leaderboard cells, so the // distribution axis and frontier labels match the table. const scale = percentDisplayColumns.has(metric.column_key) ? 100 : 1 const points: Array<{ score: number; releaseDate: string | null; modelName: string }> = [] for (const r of filteredRows) { const score = r.values[metric.column_key] if (!isNumericScore(score)) continue points.push({ score: score * scale, releaseDate: r.model_info?.release_date ?? null, modelName: r.model_info?.name ?? "", }) } if (points.length < 3) return null const label = getMetricChipLabel(metric) return { key: metric.column_key, label, caption: metric.unit ?? undefined, values: points.map((p) => p.score), unit: metric.unit ?? undefined, lowerIsBetter: metric.lower_is_better, points, } }) .filter((entry): entry is NonNullable => entry !== null) if (distSeries.length === 0) return null return (
) })()}
{hasParameterData && (
{ setMinParamStep(0) setMaxParamStep(PARAM_RANGE_MAX_INDEX) }} showUnknownSize={showUnknownSize} onShowUnknownSizeChange={setShowUnknownSize} />
)}
{visibleMetrics.map((metric) => { // When a slice is active in the dropdown, the slice // name is already shown above the table — no need to // repeat it as a per-column topline. const showSliceTopline = false const mainLabel = getMetricChipLabel(metric) return ( ) })} {pagedRows.map((row) => { const rank = rankByModelId.get(row.model_info.id) ?? 0 const expandKey = row.model_info.id const isExpanded = expandedRows[expandKey] ?? false const matchingResult = modelResultByModelId.get(row.model_info.id) const isTopRank = rank === 1 const rankColor = rank === 1 ? "var(--accent)" : "var(--fg-muted)" const familyLabel = row.model_info.architecture ?? row.model_info.parameter_count ?? null return ( {visibleMetrics.map((metric) => { const score = row.values[metric.column_key] const annotations = row.annotations_by_metric?.[metric.column_key] const valid = isNumericScore(score) const display = !valid ? "—" : percentDisplayColumns.has(metric.column_key) ? `${(score * 100).toFixed(1)}%` : formatRawScore(score, undefined) return ( ) })} {isResearchView && isExpanded && matchingResult && ( )} )})} {filteredRows.length === 0 && ( )}
Rank handleSort("model")} > Model{getSortIndicator("model")} handleSort("developer")} > {isResearchView ? "Developer" : "Provider"} {getSortIndicator("developer")} handleSort(metric.column_key)} title={describeLeaderboardMetric(metric)} > {showSliceTopline && (
{metric.subtask_name}
)} {mainLabel} {getSortIndicator(metric.column_key)}
Evaluator Source handleSort("released")} title="Sort by model release date" > Released{getSortIndicator("released")}
#{rank}
{isResearchView && matchingResult && ( )}
{row.model_info.name} {familyLabel && (
{familyLabel}
)}
{row.model_info.developer ?? "Unknown developer"}
{row.model_info.developer ?? "Unknown developer"}
{display}
{row.source_metadata?.evaluator_relationship === "first_party" ? "SELF" : row.source_metadata?.evaluator_relationship === "third_party" ? "THIRD-PARTY" : "—"} {(() => { const sourceLabel = row.source_metadata?.source_name?.trim() || row.source_metadata?.source_organization_name?.trim() const sourceEvaluatorName = resolveEvaluatorName(row.source_metadata?.source_organization_name) ?? resolveEvaluatorName(row.source_metadata?.source_name) return sourceLabel ? ( ) : ( ) })()} {row.model_info.release_date ? formatDate(row.model_info.release_date).split(",")[0] : }
No models match the selected parameter range.
{pagedRows.length < filteredRows.length && (
)}
) } function BenchmarkCardCollapsible({ card, isResearchView, defaultOpen = true, defaultRisksOpen = false, evaluationName = "", sourceDataFallback = null, knownIssues = [], }: { card: BenchmarkCard isResearchView: boolean defaultOpen?: boolean defaultRisksOpen?: boolean evaluationName?: string sourceDataFallback?: SourceData | null knownIssues?: KnownIssue[] }) { // Decide whether the panel has any meaningful content. We hide the // whole collapsible — header and body — when it doesn't. Fallback // values that duplicate the eval title don't count. const meaningful = (v: string | undefined | null) => Boolean(v && v.trim() && v.trim() !== "Not specified") const looksLikeEvalTitle = (v: string | undefined | null) => Boolean( v && evaluationName && v.trim().toLowerCase() === evaluationName.trim().toLowerCase(), ) const usefulFallback = (v: string | undefined | null) => meaningful(v) && !looksLikeEvalTitle(v) const purpose = card.purpose_and_intended_users const methodology = card.methodology const data = card.data const ethical = card.ethical_and_legal_considerations const sd = sourceDataFallback const tasks = toStringArray(purpose.tasks) const audience = toStringArray(purpose.audience) const domains = toStringArray(card.benchmark_details?.domains) const languages = toStringArray(card.benchmark_details?.languages) const resources = (card.benchmark_details?.resources ?? []).filter(Boolean) const flaggedFieldsRaw = card.flagged_fields as unknown const hasFlaggedFields = typeof flaggedFieldsRaw === "string" ? flaggedFieldsRaw.length > 2 : flaggedFieldsRaw != null && typeof flaggedFieldsRaw === "object" && Object.keys(flaggedFieldsRaw).length > 0 const hasMissingFields = (card.missing_fields ?? []).length > 0 const hasContent = knownIssues.length > 0 || meaningful(purpose.goal) || meaningful(methodology.interpretation) || meaningful(purpose.limitations) || (methodology.methods?.length ?? 0) > 0 || meaningful(methodology.calculation) || meaningful(methodology.validation) || (methodology.metrics?.length ?? 0) > 0 || tasks.length > 0 || audience.length > 0 || domains.length > 0 || languages.length > 0 || resources.length > 0 || (card.possible_risks?.length ?? 0) > 0 || meaningful(ethical?.data_licensing) || meaningful(ethical?.compliance_with_regulations) || meaningful(ethical?.privacy_and_anonymity) || meaningful(data?.size) || meaningful(data?.format) || usefulFallback(data?.source) || usefulFallback(sd?.hf_repo) || usefulFallback(sd?.dataset_name) || sd?.samples_number != null || meaningful(sd?.source_type) || (isResearchView && (Boolean(hasFlaggedFields) || hasMissingFields)) if (!hasContent) return null const [open, setOpen] = useState(defaultOpen) const sectionLinks: { label: string; id: string }[] = [ ...(methodology.metrics?.length || tasks.length || audience.length || meaningful(data?.size) || meaningful(data?.format) || usefulFallback(data?.source) || usefulFallback(sd?.hf_repo) || usefulFallback(sd?.dataset_name) || sd?.samples_number != null ? [{ label: "dataset", id: "bc-section-dataset" }, { label: "methodology", id: "bc-section-methodology" }] : []), ...(isResearchView && (card.possible_risks?.length ?? 0) > 0 ? [{ label: "risks", id: "bc-section-risks" }] : []), ...(resources.length > 0 ? [{ label: "resources", id: "bc-section-resources" }] : []), ] const handleSectionJump = (id: string) => { setOpen(true) requestAnimationFrame(() => { requestAnimationFrame(() => { const el = document.getElementById(id) if (el) el.scrollIntoView({ behavior: "smooth", block: "start" }) }) }) } return ( ) } function DetailPanel({ title, subtitle, children, }: { title: string subtitle: string children: React.ReactNode }) { return (
{title}
{subtitle}
{children}
) } function MetaRow({ label, value, }: { label: string value: React.ReactNode }) { // Hide rows whose value is missing or a generic placeholder. This keeps // the detail panels focused on fields we actually have data for. if (value == null) return null if (typeof value === "string") { const normalized = value.trim().toLowerCase() if ( normalized === "" || normalized === "unknown" || normalized === "n/a" || normalized === "not recorded" || normalized === "not specified" || normalized === "not linked" ) { return null } } return (
{label}
{value}
) } function toStringArray(value: unknown): string[] { const result = new Set() const visit = (candidate: unknown) => { if (!candidate) { return } if (Array.isArray(candidate)) { for (const item of candidate) { visit(item) } return } if (typeof candidate === "object") { for (const item of Object.values(candidate)) { visit(item) } return } if (typeof candidate !== "string") { return } const normalized = candidate.trim() if (!normalized || normalized === "Not specified") { return } for (const part of normalized.split(/[,;|]/)) { const token = part.trim() if (token && token !== "Not specified") { result.add(token) } } } visit(value) return Array.from(result) } function BenchmarkCardPanel({ card, isResearchView, defaultRisksOpen = false, sourceDataFallback = null, knownIssues = [], }: { card: BenchmarkCard isResearchView: boolean defaultRisksOpen?: boolean sourceDataFallback?: SourceData | null knownIssues?: KnownIssue[] }) { const [risksOpen, setRisksOpen] = useState(defaultRisksOpen) const details = card.benchmark_details const purpose = card.purpose_and_intended_users const methodology = card.methodology const data = card.data const ethical = card.ethical_and_legal_considerations const risks = card.possible_risks ?? [] // The backend currently emits `flagged_fields` as a JSON string // (DuckDB's `json_extract` typed as JSON, which crosses // @duckdb/node-api as a string). When the value lands as a string // here, `Object.entries(...)` would iterate it character by // character and render one `
  • ` per character — what the user // saw on `/evals/vals-ai%2Fterminal-bench-2`. Parse first when // needed, fall back to {} on malformed JSON. const flaggedFieldsRaw = card.flagged_fields const flaggedFieldsObj: Record = (() => { if (!flaggedFieldsRaw) return {} if (typeof flaggedFieldsRaw === "string") { try { const parsed = JSON.parse(flaggedFieldsRaw) return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? (parsed as Record) : {} } catch { return {} } } return flaggedFieldsRaw as Record })() const flaggedFields = Object.entries(flaggedFieldsObj) const missingFields = card.missing_fields ?? [] const domains = toStringArray(details.domains) const languages = toStringArray(details.languages) const resources = (details.resources ?? []).filter(Boolean) const tasks = toStringArray(purpose.tasks) const audience = toStringArray(purpose.audience) const license = ethical.data_licensing ?? "" const shortLicense = license && license !== "Not specified" ? license : null // The outer collapsible trigger names the panel; the prominent top // strip surfaces what readers most often want at a glance — domain // and language tags, license, and any flagged/missing-field badge. const hasChipStrip = domains.length > 0 || languages.length > 0 || Boolean(shortLicense) || flaggedFields.length > 0 || missingFields.length > 0 return (
    {hasChipStrip && (
    {domains.map((d) => ( {d} ))} {languages.map((l) => ( {l} ))} {shortLicense && {shortLicense}} {(flaggedFields.length > 0 || missingFields.length > 0) && ( {flaggedFields.length} flagged · {missingFields.length} missing )}
    )}
    {knownIssues.length > 0 && } {(() => { const meaningful = (v: string | undefined | null) => Boolean(v && v.trim() && v.trim() !== "Not specified") const showGoal = meaningful(purpose.goal) const showInterp = meaningful(methodology.interpretation) const showLimitations = meaningful(purpose.limitations) if (!showGoal && !showInterp && !showLimitations) return null return (
    {showGoal && (
    Goal

    {purpose.goal}

    )} {showInterp && (
    Score interpretation

    {methodology.interpretation}

    )} {showLimitations && (
    Limitations

    {purpose.limitations}

    )}
    ) })()} {(methodology.methods?.length > 0 || (methodology.calculation && methodology.calculation !== "Not specified") || (methodology.validation && methodology.validation !== "Not specified")) && (
    How tasks were sourced and scored
    {methodology.methods?.length > 0 && (
    Task setup
      {methodology.methods.map((m, i) => (
    1. {m}
    2. ))}
    )}
    {methodology.calculation && methodology.calculation !== "Not specified" && (
    Score calculation

    {methodology.calculation}

    )} {methodology.validation && methodology.validation !== "Not specified" && (
    Validation

    {methodology.validation}

    )}
    )} {/* Research-only: methodology + dataset details. Each tile falls back to whatever data is available — and hides entirely when nothing is. The card payload often arrives sparse for benchmarks that haven't been documented; the previous version rendered "Size / Format / Source" labels with empty values, which read as broken. */} {isResearchView && (() => { const meaningful = (v: string | undefined | null) => Boolean(v && v.trim() && v.trim() !== "Not specified") // Dataset row fallbacks pull from summary.source_data when // the card itself didn't fill those fields. The summary // payload almost always carries hf_repo / dataset_name even // for cards that are otherwise empty, so this turns a // blank tile into something useful. const sd = sourceDataFallback const datasetSize = meaningful(data.size) ? data.size : sd?.samples_number != null ? `${sd.samples_number.toLocaleString()} samples` : null const datasetFormat = meaningful(data.format) ? data.format : meaningful(sd?.source_type) ? sd!.source_type! : null const datasetSource = meaningful(data.source) ? data.source : meaningful(sd?.hf_repo) ? sd!.hf_repo! : meaningful(sd?.dataset_name) ? sd!.dataset_name! : null const showDataset = Boolean(datasetSize || datasetFormat || datasetSource) const showMethodology = methodology.metrics.length > 0 || tasks.length > 0 || audience.length > 0 if (!showDataset && !showMethodology) return null return (
    {showDataset && (
    Dataset
    {datasetSize && (
    Size
    {datasetSize}
    )} {datasetFormat && (
    Format
    {datasetFormat}
    )} {datasetSource && (
    Source
    {datasetSource}
    )}
    )} {showMethodology && (
    Methodology
    {methodology.metrics.length > 0 && (
    Metrics
    {methodology.metrics.join(", ")}
    )} {tasks.length > 0 && (
    Tasks
    {tasks.join(", ")}
    )} {audience.length > 0 && (
    Audience
    {audience.join("; ")}
    )}
    )}
    ) })()} {/* Generic IBM-style AI risks. These are boilerplate (per audit feedback: "least useful feature for policy users"), so in policy mode we hide them entirely — the curated known-issues panel above carries the benchmark-specific concerns. Researchers still get the full collapsible list. */} {risks.length > 0 && isResearchView && ( )} {/* Compliance / ethical notes (policy view emphasis). Hide the entire panel when none of the three fields are populated — otherwise the user sees an empty bordered box with just the section header. */} {!isResearchView && (() => { const showCompliance = ethical.compliance_with_regulations && ethical.compliance_with_regulations !== "Not specified" const showPrivacy = ethical.privacy_and_anonymity && ethical.privacy_and_anonymity !== "Not specified" if (!shortLicense && !showCompliance && !showPrivacy) return null return (
    Ethical & legal
    {shortLicense && (
    License
    {license}
    )} {showCompliance && (
    Compliance
    {ethical.compliance_with_regulations}
    )} {showPrivacy && (
    Privacy
    {ethical.privacy_and_anonymity}
    )}
    ) })()} {/* Flagged / missing fields warning */} {(flaggedFields.length > 0 || missingFields.length > 0) && isResearchView && (
    Card quality notes
    {flaggedFields.length > 0 && (
      {flaggedFields.map(([field, note]) => { const { tag, body } = splitFlagNote(note) return (
    • {humanizeCardFieldPath(field)} {tag && ( {tag} )}
      {body && ( {body} )}
    • ) })}
    )} {missingFields.length > 0 && (

    Missing: {missingFields.join(", ")}

    )}
    )} {/* External resources */} {resources.length > 0 && ( )}
    ) }