Spaces:
Running
Running
Download lib/eval-processing.ts from evaleval/general-eval-card: direct link, hf CLI and curl.
- Browser
- Download file 37.5 kB
-
https://huggingface.co/spaces/evaleval/general-eval-card/resolve/main/lib/eval-processing.ts
- Command line
-
hf download hf://spaces/evaleval/general-eval-card/lib/eval-processing.ts
-
curl -L -o eval-processing.ts https://huggingface.co/spaces/evaleval/general-eval-card/resolve/main/lib/eval-processing.ts
37.5 kB
| /** | |
| * Benchmark-first evaluation types, shared between the v2 view-layer reader | |
| * (lib/view-data.ts) and its UI consumers. The data-shaping functions that | |
| * used to live here were part of the legacy v1 (HF-JSON / duckdb) backend and | |
| * were removed once the producer pipeline took over aggregation. | |
| */ | |
| import type { | |
| BenchmarkCard, | |
| BenchmarkEvaluation, | |
| EvalLibrary, | |
| EvalTag, | |
| GenerationConfig, | |
| ModelInfo, | |
| SourceMetadata, | |
| SourceData, | |
| ScoreDetails, | |
| MetricConfig, | |
| EvaluationResult, | |
| ModelEvaluationSummary, | |
| } from './benchmark-schema' | |
| import type { | |
| ComparabilityStatus, | |
| EvalcardsAnnotations, | |
| RowAnnotations, | |
| SignalSummaries, | |
| } from './backend-artifacts' | |
| import type { | |
| CollectionAttachment, | |
| CollectionsSidecarEntry, | |
| ProtocolAxesByCollection, | |
| StudyRef, | |
| } from './collections' | |
| export type { BenchmarkCard } | |
| export type { ModelEvaluationSummary } | |
| /** | |
| * True when a result ran under the oracle answer-feedback arm of a | |
| * protocol-varied collection (the model was told when its answer was | |
| * correct). Assisted rows are shown but excluded from client-side ranking | |
| * by default — mirroring the backend, which never serves them a rank. | |
| */ | |
| export function isAssistedResult(protocolCondition: string | null | undefined): boolean { | |
| if (!protocolCondition) return false | |
| try { | |
| const parsed = JSON.parse(protocolCondition) as { feedback?: unknown } | null | |
| return parsed != null && typeof parsed === "object" && parsed.feedback === "answer_feedback" | |
| } catch { | |
| return false | |
| } | |
| } | |
| export interface ScoreSpread { | |
| /** How many scores the range spans. */ | |
| n: number | |
| min: number | |
| max: number | |
| } | |
| /** | |
| * Where a model's runs on one page landed: the smallest and the largest, | |
| * and how many there were. | |
| * | |
| * Descriptive only, and deliberately so. The runs are different | |
| * CONFIGURATIONS (token budget, thinking tokens, effort, answer oracle), | |
| * not repeated draws of one quantity, so there is no population to | |
| * estimate and no sampling error to bound. An interval computed from | |
| * them would narrow as the study added design points while the observed | |
| * range stayed as wide, and would then be read as a claim about the | |
| * model's ability. The observed endpoints make no such claim. | |
| */ | |
| export function summariseScoreSpread(values: readonly number[]): ScoreSpread | null { | |
| const finite = values.filter((value) => Number.isFinite(value)) | |
| if (finite.length === 0) return null | |
| return { n: finite.length, min: Math.min(...finite), max: Math.max(...finite) } | |
| } | |
| /** A parsed `judge_condition`. `judges` holds the canonical | |
| * model ids of the LLM judges behind the number, `label` the source's own | |
| * name for the channel. */ | |
| export interface JudgeCondition { | |
| judges: string[] | |
| label: string | null | |
| } | |
| /** | |
| * Parse the view's canonical `judge_condition` JSON | |
| * (`{"judges":[...],"label":"..."}`). NULL/absent means the source did not | |
| * disclose a judge — never "no judge" — so it parses to null and the row | |
| * is labelled as an ordinary result. Orthogonal to `protocol_condition`, | |
| * whose semantics (isAssistedResult above) are unchanged. | |
| */ | |
| export function parseJudgeCondition( | |
| raw: string | null | undefined, | |
| ): JudgeCondition | null { | |
| if (!raw) return null | |
| try { | |
| const parsed = JSON.parse(raw) as { judges?: unknown; label?: unknown } | null | |
| if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) return null | |
| // Trim, drop empties, dedupe. A blank id would render "judged by " | |
| // and a repeated one would inflate "mean of N judges" — both claim | |
| // something about the panel that isn't in the data. | |
| const judges = Array.isArray(parsed.judges) | |
| ? [ | |
| ...new Set( | |
| parsed.judges | |
| .filter((judge): judge is string => typeof judge === "string") | |
| .map((judge) => judge.trim()) | |
| .filter((judge) => judge.length > 0), | |
| ), | |
| ] | |
| : [] | |
| const label = | |
| typeof parsed.label === "string" && parsed.label.trim().length > 0 | |
| ? parsed.label.trim() | |
| : null | |
| if (judges.length === 0 && label == null) return null | |
| return { judges, label } | |
| } catch { | |
| return null | |
| } | |
| } | |
| /** | |
| * Row label for a judged result: the judge when a single model graded it, | |
| * the panel size when several did, plus the panel's display names for the | |
| * row's tooltip. `displayName` resolves a judge's canonical model id to its | |
| * registry display name (server-built, see BenchmarkEvalSummary | |
| * .judge_display_names) and falls back to the raw id. Returns null when the | |
| * source disclosed no judge at all. | |
| */ | |
| export function judgeConditionSummary( | |
| raw: string | null | undefined, | |
| displayName: (modelId: string) => string, | |
| ): { label: string; names: string[]; judges: string[] } | null { | |
| const condition = parseJudgeCondition(raw) | |
| if (!condition || condition.judges.length === 0) return null | |
| const names = condition.judges.map(displayName) | |
| return { | |
| label: names.length === 1 ? `judged by ${names[0]}` : `mean of ${names.length} judges`, | |
| names, | |
| // The raw ids behind the names. Two dated variants that folded into | |
| // one survivor resolve to the SAME display name, so the id is the | |
| // only thing that tells a reader which reading a row is. | |
| judges: condition.judges, | |
| } | |
| } | |
| /** One non-headline judge reading of a (model, metric) cell: the panel the | |
| * producer did not pick, and the number it published. */ | |
| export interface JudgeReading { | |
| judge_condition: string | |
| score: number | null | |
| } | |
| /** | |
| * Judge treatment for one cell of the multi-metric matrix, which is a pivot | |
| * of headline readings only. `label` is the same "judged by …" / "mean of N | |
| * judges" wording the per-row leaderboard uses, and `tooltip` names the | |
| * panel's members and then lists every OTHER judge reading of the same | |
| * (model, metric) with its value — the pivot has no row to put those on, so | |
| * dropping them would hide a disagreement the page is meant to show. | |
| * `formatScore` renders an alternate's number the way the column renders its | |
| * cells. Returns null when nothing about the cell names a judge. | |
| */ | |
| export function judgeCellSummary( | |
| condition: string | null | undefined, | |
| alternates: JudgeReading[] | undefined, | |
| displayName: (modelId: string) => string, | |
| formatScore: (score: number) => string, | |
| ): { label: string; tooltip: string } | null { | |
| const headline = judgeConditionSummary(condition, displayName) | |
| const others = (alternates ?? []) | |
| .map((reading) => ({ | |
| summary: judgeConditionSummary(reading.judge_condition, displayName), | |
| score: reading.score, | |
| })) | |
| .filter( | |
| (reading): reading is { summary: NonNullable<typeof reading.summary>; score: number | null } => | |
| reading.summary !== null, | |
| ) | |
| if (!headline && others.length === 0) return null | |
| const lines: string[] = [] | |
| if (headline) { | |
| lines.push( | |
| headline.names.length > 1 | |
| ? `Judges: ${headline.names.join(", ")}` | |
| : `Judge model id: ${headline.judges[0]}`, | |
| ) | |
| } | |
| if (others.length > 0) { | |
| lines.push("Other judge readings, not ranked:") | |
| for (const other of others) { | |
| const value = | |
| typeof other.score === "number" && Number.isFinite(other.score) | |
| ? formatScore(other.score) | |
| : "—" | |
| lines.push(`${other.summary.label}: ${value}`) | |
| } | |
| } | |
| return { | |
| // No headline judge but alternates exist (the producer's pick was an | |
| // undisclosed-judge row): say so rather than showing nothing. | |
| label: | |
| headline?.label | |
| ?? `${others.length} other judge reading${others.length === 1 ? "" : "s"}`, | |
| tooltip: lines.join("\n"), | |
| } | |
| } | |
| /** | |
| * The matrix column the page ranks on: the eval's `primary_metric_id`, which | |
| * is the metric every other surface on the page summarises. A payload that | |
| * declares no primary metric, or names one no column carries, falls back to | |
| * the first root metric and then to the first column. | |
| */ | |
| export function primaryMetricColumnKey( | |
| metrics: Array<{ column_key: string; metric_id?: string; scope?: string }> | undefined, | |
| primaryMetricId: string | null | undefined, | |
| ): string | undefined { | |
| const all = metrics ?? [] | |
| const roots = all.filter((metric) => metric.scope !== "subtask") | |
| const primary = primaryMetricId?.trim() | |
| const declared = primary | |
| ? roots.find((metric) => metric.column_key === primary || metric.metric_id === primary) | |
| : undefined | |
| return declared?.column_key ?? roots[0]?.column_key ?? all[0]?.column_key | |
| } | |
| /** A row the backend did not pick as its model's headline reading (a losing | |
| * judge panel or protocol arm) — shown beneath the headline, never ranked. | |
| * An absent field reads as "headline", which is what a payload assembled | |
| * outside the view layer (a fixture, an embed) gets. */ | |
| export function isHeadlineResult(result: { | |
| is_headline?: boolean | null | |
| }): boolean { | |
| return result.is_headline !== false | |
| } | |
| /** | |
| * Score standings for rows already in score order: one rank per ranked | |
| * row, ties sharing a rank, and 0 for every row the caller says takes no | |
| * rank (an assisted run, a losing judge panel, a secondary protocol | |
| * point). The standing is the model's position in the field, so it is | |
| * assigned once here and never recomputed from a row's display position. | |
| */ | |
| export function scoreStandings<T>( | |
| rows: T[], | |
| score: (row: T) => number, | |
| ranked: (row: T) => boolean, | |
| ): number[] { | |
| let currentRank = 0 | |
| let previousScore: number | null = null | |
| let rankedCount = 0 | |
| return rows.map((row) => { | |
| if (!ranked(row)) return 0 | |
| rankedCount += 1 | |
| const value = score(row) | |
| if (previousScore === null || Math.abs(value - previousScore) > 1e-9) { | |
| currentRank = rankedCount | |
| previousScore = value | |
| } | |
| return currentRank | |
| }) | |
| } | |
| /** The identity a model's rows group under: the producer's route id when | |
| * it resolved one, else whatever identifies the model at all. */ | |
| export function modelGroupKey(result: { | |
| model_route_id?: string | |
| model_info?: { id?: string; name?: string } | |
| }): string { | |
| return result.model_route_id ?? result.model_info?.id ?? result.model_info?.name ?? "" | |
| } | |
| /** | |
| * A stable identity for one observation: the model, the source it came | |
| * from, the protocol point it ran at, the judge panel that scored it and | |
| * the source's own label for the number. Everything the page can use to | |
| * tell two readings of the same model apart, and nothing that depends on | |
| * where the reading currently sits in the table. | |
| */ | |
| export function observationKey(result: ModelResultForBenchmark): string { | |
| return [ | |
| result.model_route_id ?? result.model_info?.id ?? result.model_info?.name ?? "", | |
| result.merged_source_slug ?? result.source_metadata?.source_name ?? "", | |
| result.collection_id ?? "", | |
| result.protocol_condition ?? "", | |
| result.judge_condition ?? "", | |
| result.metric_source_label ?? "", | |
| ].join("|") | |
| } | |
| /** | |
| * Group rows so that a model's non-headline readings (its judge panels and | |
| * protocol arms) stay attached beneath its headline row. | |
| * | |
| * Sorting a leaderboard must reorder these GROUPS, never the flattened row | |
| * list: reversing a flat list alone puts every secondary row above its own | |
| * headline, and an arbitrary key sort separates them from their model | |
| * entirely. A non-headline row whose model has no group yet opens one of | |
| * its own rather than attaching to an unrelated model above it. | |
| */ | |
| export function groupByHeadlineModel<T>( | |
| rows: readonly T[], | |
| resultOf: (row: T) => { is_headline?: boolean | null; model_route_id?: string; model_info?: { id?: string; name?: string } }, | |
| ): T[][] { | |
| const groups: T[][] = [] | |
| const openByModel = new Map<string, T[]>() | |
| for (const row of rows) { | |
| const result = resultOf(row) | |
| const key = modelGroupKey(result) | |
| const open = openByModel.get(key) | |
| if (open && !isHeadlineResult(result)) { | |
| open.push(row) | |
| continue | |
| } | |
| const group = [row] | |
| groups.push(group) | |
| openByModel.set(key, group) | |
| } | |
| return groups | |
| } | |
| /** | |
| * The direction the ranker's own row order already reads in: best first, | |
| * which is ASCENDING when the metric's better end is the low one. A score | |
| * sort that assumes "best first == descending" shows a lower-is-better | |
| * board upside down and then reverses the wrong way on the toggle. | |
| */ | |
| export function scoreSortBaseDirection(lowerIsBetter?: boolean | null): "asc" | "desc" { | |
| return lowerIsBetter ? "asc" : "desc" | |
| } | |
| /** | |
| * Score-ordered rows for a user-chosen direction. Takes the GROUPS the | |
| * ranker produced (each a headline row plus the judge / protocol readings | |
| * beneath it) so a reversal moves whole models — reversing the flat row | |
| * list would put every secondary reading above its own headline. | |
| */ | |
| export function orderGroupsByScore<T>( | |
| groups: readonly T[][], | |
| direction: "asc" | "desc", | |
| lowerIsBetter?: boolean | null, | |
| ): T[] { | |
| return direction === scoreSortBaseDirection(lowerIsBetter) | |
| ? groups.flat() | |
| : [...groups].reverse().flat() | |
| } | |
| /** | |
| * Composite comparison view: one score per (model, sub-eval) across a | |
| * suite's child evaluations, for the models x sub-evals matrix. | |
| * | |
| * Headline rows only. The cell is written once per matching row, so | |
| * without the filter a later judge panel or protocol arm overwrites the | |
| * model's summary reading — and that overwritten number is then averaged | |
| * across the suite and ranked as the model's standing. | |
| */ | |
| export function compositeScoresByModel( | |
| subSummaries: ReadonlyArray<{ | |
| evaluation_name: string | |
| model_results: ModelResultForBenchmark[] | |
| }>, | |
| ): Map<string, { name: string; developer: string; scores: Map<string, number | null> }> { | |
| const modelScores = new Map< | |
| string, | |
| { name: string; developer: string; scores: Map<string, number | null> } | |
| >() | |
| for (const sub of subSummaries) { | |
| for (const result of sub.model_results) { | |
| if (!isHeadlineResult(result)) continue | |
| const id = result.model_info.id | |
| const existing = modelScores.get(id) ?? { | |
| name: result.model_info.name, | |
| developer: result.model_info.developer ?? "", | |
| scores: new Map<string, number | null>(), | |
| } | |
| existing.scores.set(sub.evaluation_name, result.score) | |
| modelScores.set(id, existing) | |
| } | |
| } | |
| return modelScores | |
| } | |
| export interface ModelResultForBenchmark { | |
| model_info: ModelInfo | |
| model_route_id?: string | |
| /** | |
| * model-resolution-rework: server-provided group canonical id. Used as | |
| * the routing fallback when `model_route_id` is absent — replaces the | |
| * old client-side family-route computation (since removed). | |
| */ | |
| model_group_id?: string | |
| score: number | |
| score_details: ScoreDetails | |
| evaluation_timestamp: string | |
| source_metadata: SourceMetadata | |
| source_data: BenchmarkEvaluation['source_data'] | |
| /** Per-result verification flag; mirrors `result.is_verified_evaluator`. */ | |
| is_verified_evaluator?: boolean | |
| /** De-aliased evaluator identity (registry canonical display name when | |
| * the org resolves, raw string otherwise). Preferred for the Source | |
| * label so upstream spelling drift never leaks into display; the raw | |
| * source_metadata strings stay available for provenance. */ | |
| evaluator_display_name?: string | |
| result: EvaluationResult | |
| /** URL to the underlying record JSON in the upstream HF dataset, when known. */ | |
| source_record_url?: string | |
| /** Deep-link to the raw EEE_datastore source record this score came from, when known. */ | |
| eee_record_url?: string | |
| /** Merged-page rows only (set by lib/merged-adapter): the observation's | |
| * source composite slug, used for the ?source= row pre-highlight. */ | |
| merged_source_slug?: string | |
| /** Merged-page rows only: how `score` was rescaled to sit on the page's | |
| * scale (see MergedObservationRow.scale_harmonized). */ | |
| scale_harmonized?: "mul100" | "div100" | "of_total" | |
| scale_harmonized_total?: number | |
| /** Collections (see the backend's collections spec, warehouse-outputs section): submission-channel id of | |
| * the row's representative fact row — key into the snapshot's | |
| * `collections.json` sidecar. */ | |
| collection_id?: string | |
| /** Protocol point for protocol-varied collections: canonical sorted-key | |
| * JSON typed by the collection's declared `protocol_axes`; absent/null | |
| * for ordinary rows. The view ships one row per protocol point; rows | |
| * whose reserved `feedback` key is `answer_feedback` are | |
| * shown-but-not-ranked (backend already emits NULL position for them). */ | |
| protocol_condition?: string | null | |
| /** Canonical `{"judges":[...],"label":"..."}` JSON for a | |
| * judged result; absent/null when the source disclosed no judge. */ | |
| judge_condition?: string | null | |
| /** True on the one row per (composite, benchmark, metric, model) the | |
| * producer picked as the page's summary reading. The view layer always | |
| * projects it, deriving it from the producer's ranking on a snapshot | |
| * that predates the column — see isHeadlineResult. */ | |
| is_headline?: boolean | null | |
| /** The source's own label for the published number (`gpt_score`). | |
| * Display and provenance only — never a key. */ | |
| metric_source_label?: string | null | |
| /** The harness that produced the run, and its version when the source | |
| * named one. Carried on the row because the reproducibility slots ask | |
| * which harness a re-runner would have to obtain and pin. */ | |
| eval_library?: EvalLibrary | null | |
| /** How the score was produced: `generative` when the model wrote the | |
| * answer, `log_prob` when the harness scored likelihoods over fixed | |
| * choices. The producer's own classification, so it outranks anything | |
| * inferred from a row's raw fields; absent on a snapshot predating the | |
| * column, and null when the producer could not classify the row. */ | |
| scoring_mode?: string | null | |
| /** The row's comparability verdict; only `ok` groups were assessed. */ | |
| comparability_status?: ComparabilityStatus | null | |
| /** The number the source published, before any canonical-scale | |
| * conversion applied to `score`. */ | |
| score_published?: number | |
| aggregate_components?: Array<{ | |
| evaluation_id: string | |
| composite_benchmark_key: string | |
| composite_benchmark_name: string | |
| score: number | |
| normalized_score: number | |
| evaluation_timestamp: string | |
| source_name?: string | |
| source_type: SourceMetadata["source_type"] | |
| source_organization_name: string | |
| evaluator_relationship: SourceMetadata["evaluator_relationship"] | |
| }> | |
| } | |
| export interface BenchmarkEvalSummary extends SignalSummaries { | |
| evaluation_name: string | |
| /** Registry display names for the judge model ids named in this page's | |
| * judge conditions, keyed by the raw id the condition carries (which | |
| * can be a dated variant that folded into the named model). Built | |
| * server-side from models_view; absent when no row on the page names a | |
| * judge, and missing an entry when models_view has no matching row — | |
| * the label then falls back to the raw id. */ | |
| judge_display_names?: Record<string, string> | |
| /** URL-safe slug derived from evaluation_name */ | |
| evaluation_id: string | |
| /** True when this summary was adapted from a merged all-sources payload | |
| * (lib/merged-adapter) — lets shared UI phrase observation-grain rows | |
| * correctly ("N results · M models", not "N of M"). */ | |
| merged_view?: true | |
| canonical_display_name?: string | |
| composite_benchmark_key: string | |
| composite_benchmark_name: string | |
| derived_tags?: EvalTag[] | |
| metric_config: MetricConfig | |
| model_results: ModelResultForBenchmark[] | |
| models_count: number | |
| /** Unique evaluator organisation names */ | |
| evaluator_names: string[] | |
| /** Subset of `evaluator_names` that are validated submitters (badge). */ | |
| verified_evaluator_names?: string[] | |
| source_types: SourceMetadata["source_type"][] | |
| latest_source_name?: string | |
| third_party_ratio: number | |
| missing_generation_config_count: number | |
| best_model: { name: string; score: number } | null | |
| worst_model: { name: string; score: number } | null | |
| avg_score: number | |
| /** avg_score normalised to 0-1 using metric_config.min/max_score */ | |
| avg_score_norm: number | null | |
| /** Rich benchmark card from the metadata/ folder, when available */ | |
| benchmark_card?: BenchmarkCard | |
| is_aggregated?: boolean | |
| aggregate_sources?: Array<{ | |
| evaluation_id: string | |
| composite_benchmark_key: string | |
| composite_benchmark_name: string | |
| models_count: number | |
| avg_score_norm: number | null | |
| }> | |
| /** Tags from the pipeline (domains, languages, tasks) */ | |
| tags?: { domains: string[]; languages: string[]; tasks: string[] } | |
| /** Number of distinct metrics for this benchmark */ | |
| metrics_count?: number | |
| /** Names of all metrics */ | |
| metric_names?: string[] | |
| /** Instance-level data availability */ | |
| instance_data?: { available: boolean; url_count: number; sample_urls: string[]; models_with_loaded_instances: number } | |
| /** Canonical benchmark id (the registry-resolved benchmark). Drives | |
| * benchmark-card lookups regardless of slice/composite axis. */ | |
| benchmark_id?: string | |
| /** Family display name. */ | |
| benchmark_family_name?: string | |
| /** Composite (leaderboard) slug — e.g. "wasp", "helm-classic". */ | |
| composite_slug?: string | |
| /** Composite display name — e.g. "WASP", "HELM Classic". */ | |
| composite_display_name?: string | |
| /** Curated multi-benchmark family slug (e.g. "mmlu"), defaults to | |
| * benchmark id for singletons. */ | |
| family_id?: string | |
| /** Family display, post-cutover canonical name. */ | |
| family_display_name?: string | |
| /** Parent benchmark id — populated when this row is a slice of a | |
| * root benchmark; null for non-slice rows. */ | |
| parent_benchmark_id?: string | |
| /** True when this row is a within-benchmark slice cut. */ | |
| is_slice?: boolean | |
| /** Source dataset metadata from the pipeline */ | |
| source_data?: SourceData | |
| /** Best raw score reported in the eval summary list */ | |
| top_score?: number | |
| /** Count of nested subtasks reported for the benchmark */ | |
| subtasks_count?: number | |
| /** Whether this row is a summary/rollup score for a composite */ | |
| is_summary_score?: boolean | |
| /** Evaluation_ids this benchmark summary is composed of. */ | |
| constituent_evaluation_ids?: string[] | |
| /** Canonical benchmark-level metrics from root metrics[] */ | |
| root_metrics?: BenchmarkSummaryMetric[] | |
| /** Canonical benchmark subdivisions from subtasks[] */ | |
| subtasks?: BenchmarkSummarySubtask[] | |
| /** The metric the page ranks on (`evals_view.primary_metric_id`) — the one | |
| * every other surface here summarises. The multi-metric matrix sorts and | |
| * charts this column rather than whichever measure happens to come first. | |
| * Absent on payloads assembled outside the view layer. */ | |
| primary_metric_id?: string | |
| /** Matrix columns for multi-metric benchmark leaderboards */ | |
| leaderboard_metrics?: BenchmarkLeaderboardMetric[] | |
| /** Matrix rows for multi-metric benchmark leaderboards */ | |
| leaderboard_rows?: BenchmarkLeaderboardRow[] | |
| evalcards?: { annotations?: EvalcardsAnnotations } | |
| /** Curated protocol-varied collection attachment. Per-source-only: | |
| * built server-side from the | |
| * collections.json sidecar; the merged adapter never sets it, which | |
| * gates every collection surface off merged summaries. Per-source | |
| * embeds carry it and render the study surfaces deliberately. */ | |
| collection?: CollectionAttachment | |
| /** Curated studies the visible rows come from. Attribution only, and | |
| * the one study surface a merged summary carries. */ | |
| study_refs?: StudyRef[] | |
| /** Declared protocol axes keyed by collection id, for a page whose rows | |
| * span several collections. Descriptor lookup only: it gives a row's | |
| * numbers their unit and says which axes apply to which row. */ | |
| protocol_axes_by_collection?: ProtocolAxesByCollection | |
| /** Source ↔ merged switcher data for per-source pages. | |
| * Absent when the page has neither a merged page nor sibling sources, | |
| * and on old snapshots. */ | |
| source_options?: EvalSourceOptions | |
| } | |
| export interface EvalSourceOption { | |
| /** Per-source eval page id (URL-encoded, straight off evals_view). */ | |
| evaluation_id: string | |
| composite_slug?: string | |
| composite_display_name?: string | |
| models_count?: number | |
| } | |
| export interface EvalSourceOptions { | |
| /** Merged-page id to navigate to, or null when NO merged page exists — | |
| * the switcher must never navigate to a nonexistent merged page. */ | |
| merged_evaluation_id: string | null | |
| sources: EvalSourceOption[] | |
| } | |
| export interface BenchmarkSummaryMetric { | |
| metric_summary_id: string | |
| metric_name: string | |
| display_name: string | |
| canonical_display_name?: string | |
| metric_key?: string | |
| lower_is_better: boolean | |
| models_count: number | |
| top_score?: number | |
| unit?: string | |
| } | |
| export interface BenchmarkSummarySubtask { | |
| subtask_key: string | |
| subtask_name: string | |
| display_name: string | |
| canonical_display_name?: string | |
| metrics: BenchmarkSummaryMetric[] | |
| } | |
| export interface BenchmarkLeaderboardMetric { | |
| column_key: string | |
| /** Registry metric id. Equal to `column_key` on root metrics; a subtask | |
| * entry keys its column "<metric_id>::<slice>" and carries the base id | |
| * here. Matches `evals_view.primary_metric_id`. */ | |
| metric_id?: string | |
| metric_summary_id: string | |
| metric_name: string | |
| display_name: string | |
| canonical_display_name?: string | |
| lower_is_better: boolean | |
| unit?: string | |
| scope: "root" | "subtask" | |
| subtask_key?: string | |
| subtask_name?: string | |
| } | |
| export interface BenchmarkLeaderboardRow { | |
| model_info: ModelInfo | |
| model_route_id?: string | |
| /** model-resolution-rework: server group id, routing fallback. */ | |
| model_group_id?: string | |
| evaluation_timestamp: string | |
| source_metadata: SourceMetadata | |
| source_data: BenchmarkEvaluation["source_data"] | |
| values: Record<string, number | null> | |
| /** Merged-page rows only: hover text for a score that was rescaled to | |
| * sit on the page's scale (see scaleHarmonizedTitle). */ | |
| rescaled_title?: string | |
| /** Per-column verified-evaluator flag, keyed identically to `values`. */ | |
| verified?: Record<string, boolean> | |
| annotations_by_metric?: Record<string, RowAnnotations | null | undefined> | |
| /** Per-column comparability verdict, keyed identically to `values`. | |
| * Prebaked matrix cells carry no annotation struct, so this is what | |
| * lets a matrix cell render "not assessable" instead of silence. */ | |
| comparability_status_by_metric?: Record<string, ComparabilityStatus | null | undefined> | |
| /** Per-column `judge_condition` of the headline reading the cell shows, | |
| * keyed identically to `values`. */ | |
| judge_condition_by_metric?: Record<string, string | null | undefined> | |
| /** Per-column non-headline judge readings of the same (model, metric). | |
| * The pivot keeps one row per model, so these ride the cell rather than | |
| * becoming rows of their own. */ | |
| judge_alternates_by_metric?: Record<string, JudgeReading[] | undefined> | |
| metrics_present: number | |
| } | |
| export type BenchmarkEvalListItem = Omit<BenchmarkEvalSummary, "model_results"> | |
| // --------------------------------------------------------------------------- | |
| // Merged benchmark view (merged-benchmark-view spec F1) — one page per | |
| // resolved canonical benchmark, merging every publishing source at | |
| // observation grain. Backed by `merged_evals_view.parquet` plus a live | |
| // query over `eval_results_view`. | |
| // --------------------------------------------------------------------------- | |
| /** 'flagged' rows have no canonical-scale score (never guessed); 'no_bounds' | |
| * rows pass the raw score through unconverted; 'curated' rows were | |
| * multiplied by a registry-declared factor (e.g. raw 1-10 onto 0-1). */ | |
| export type MergedScaleConversion = "none" | "div100" | "mul100" | "curated" | "flagged" | "no_bounds" | |
| export interface MergedAggregateSource { | |
| /** Per-source eval page id; null for slice-only sources (no top-level page target). */ | |
| evaluation_id: string | null | |
| composite_slug: string | |
| composite_display_name: string | |
| models_count: number | |
| results_count: number | |
| /** False = excluded from the default view (source reports only other metrics). */ | |
| reports_preferred: boolean | |
| /** True = source reports slice-level results only (disclosure note). */ | |
| slice_only: boolean | |
| } | |
| export interface MergedMetricOption { | |
| metric_id: string | |
| display_name: string | |
| results_count: number | |
| models_count: number | |
| sources_count: number | |
| lower_is_better: boolean | null | |
| } | |
| export interface MergedSliceOption { | |
| slice_id: string | |
| display_name: string | |
| } | |
| export interface MergedBestResult { | |
| model_name: string | null | |
| model_key: string | null | |
| score: number | null | |
| score_canonical: number | null | |
| composite_slug: string | null | |
| evaluation_id: string | null | |
| } | |
| /** One (model, source) observation row. Echo republications stay visible — | |
| * the merged accessor never dedupes by model identity (spec design pt 3). */ | |
| export interface MergedObservationRow { | |
| model_info: ModelInfo | |
| model_route_id?: string | |
| model_key?: string | |
| /** The observation's per-source evaluation_id (two-segment) — Source link target. */ | |
| evaluation_id: string | |
| composite_slug: string | |
| composite_display_name?: string | |
| score: number | |
| /** Score on the metric's registry canonical scale; null for flagged rows. */ | |
| score_canonical: number | null | |
| scale_conversion: MergedScaleConversion | null | |
| evaluation_timestamp: string | |
| source_metadata: SourceMetadata | |
| /** The row's own upstream dataset provenance (repo, url, version, | |
| * sample count). Absent when the fact row carries none. */ | |
| source_data?: SourceData | |
| generation_config?: GenerationConfig | |
| /** Same meaning as on ModelResultForBenchmark: the harness the | |
| * reproducibility slots ask a re-runner to obtain and pin. */ | |
| eval_library?: EvalLibrary | null | |
| is_verified_evaluator?: boolean | |
| /** De-aliased evaluator identity (canonical display when resolvable). */ | |
| evaluator_display_name?: string | |
| /** Collections: submission-channel id of the observation's source row. */ | |
| collection_id?: string | |
| /** Protocol point (canonical sorted-key JSON) for protocol-varied | |
| * collections; absent/null for ordinary observations. */ | |
| protocol_condition?: string | null | |
| /** Same meanings as on ModelResultForBenchmark. Merged pages | |
| * pool one observation per (model, source), so only headline rows | |
| * belong in the pool (see lib/merged-adapter). */ | |
| judge_condition?: string | null | |
| is_headline?: boolean | null | |
| metric_source_label?: string | null | |
| comparability_status?: ComparabilityStatus | null | |
| /** Same meaning as on ModelResultForBenchmark. */ | |
| scoring_mode?: string | null | |
| /** The number the source published, before any canonical-scale | |
| * conversion applied to `score`. */ | |
| score_published?: number | |
| /** Set when the merged accessor moved this row's `score_canonical` | |
| * between the fraction and percent scales so it sits on the same scale | |
| * as the page's other sources (see harmonizeUnboundedScales). Only | |
| * 'no_bounds' rows are ever moved. 'of_total' rows were published as | |
| * raw totals and divided by the benchmark's published maximum. */ | |
| scale_harmonized?: "mul100" | "div100" | "of_total" | |
| /** The published maximum an 'of_total' row was divided by. */ | |
| scale_harmonized_total?: number | |
| } | |
| export interface MergedBenchmarkSummary { | |
| /** Discriminator vs the per-source BenchmarkEvalSummary payload. */ | |
| merged: true | |
| /** Single-segment percent-encoded benchmark id (never contains %2F). */ | |
| evaluation_id: string | |
| benchmark_id: string | |
| display_name: string | |
| family_id?: string | null | |
| family_display_name?: string | null | |
| /** 'slice' = benchmark has no top-level data; page shows a slice selector. */ | |
| grain: "benchmark" | "slice" | |
| preferred_metric_id: string | |
| preferred_metric_display_name: string | |
| preferred_from_registry: boolean | |
| lower_is_better: boolean | |
| /** Counts at default-metric grain (spec P5). */ | |
| sources_count: number | |
| all_sources_count: number | |
| results_count: number | |
| models_count: number | |
| best_result: MergedBestResult | null | |
| aggregate_sources: MergedAggregateSource[] | |
| metrics: MergedMetricOption[] | |
| /** Non-null only for grain='slice'. */ | |
| slices: MergedSliceOption[] | null | |
| /** Metric actually queried for `results` (defaults to preferred). */ | |
| selected_metric_id: string | |
| selected_lower_is_better: boolean | |
| /** For grain='slice': the slice actually queried (defaults to the first). */ | |
| selected_slice_id: string | null | |
| results: MergedObservationRow[] | |
| /** Registry display names for the judge ids named by these rows, keyed | |
| * by the raw id — same map and same fallback rule as | |
| * BenchmarkEvalSummary.judge_display_names. */ | |
| judge_display_names?: Record<string, string> | |
| /** The benchmark's card, sourced from a per-source instantiation that | |
| * authored one (preferring a source that reports the preferred metric). */ | |
| benchmark_card?: BenchmarkCard | null | |
| /** `collections.json` entries for the curated collections these rows | |
| * belong to, keyed by collection_id. Lets the reader name the study a | |
| * row comes from and give its protocol numbers their declared units | |
| * without a second fetch. */ | |
| collections?: Record<string, CollectionsSidecarEntry> | |
| } | |
| /** | |
| * Collapse leaderboard rows that describe the same model under two | |
| * source attributions (typical: one record with `developer: "OpenAI"`, | |
| * another with `developer: "unknown"` from a source that didn't carry | |
| * the developer field, both pointing at the same physical model). We | |
| * only merge when every shared score column is byte-equal across the | |
| * duplicates — that guarantees we never mask a legitimate second run | |
| * that happens to share a name. When merging, we keep the attribution | |
| * that actually identifies a developer. | |
| */ | |
| function devAttributionScore(developer: string | undefined | null): number { | |
| if (!developer) return 0 | |
| const lower = developer.trim().toLowerCase() | |
| if (!lower || lower === "unknown") return 0 | |
| return 1 | |
| } | |
| function routeAttributionScore(routeId: string | undefined | null): number { | |
| if (!routeId) return 0 | |
| const lower = routeId.toLowerCase() | |
| return lower.startsWith("unknown%2f") || lower.startsWith("unknown/") ? 0 : 1 | |
| } | |
| export function dedupeLeaderboardRowsByModelIdentity( | |
| rows: BenchmarkLeaderboardRow[], | |
| ): BenchmarkLeaderboardRow[] { | |
| if (rows.length < 2) return rows | |
| const groups = new Map<string, BenchmarkLeaderboardRow[]>() | |
| for (const row of rows) { | |
| const name = (row.model_info?.name ?? "").trim().toLowerCase() | |
| if (!name) continue | |
| const bucket = groups.get(name) | |
| if (bucket) bucket.push(row) | |
| else groups.set(name, [row]) | |
| } | |
| const result: BenchmarkLeaderboardRow[] = [] | |
| const consumed = new WeakSet<BenchmarkLeaderboardRow>() | |
| for (const row of rows) { | |
| if (consumed.has(row)) continue | |
| const name = (row.model_info?.name ?? "").trim().toLowerCase() | |
| const bucket = name ? groups.get(name) : null | |
| if (!bucket || bucket.length < 2) { | |
| result.push(row) | |
| continue | |
| } | |
| // Verify per-column score agreement before merging. Any conflict | |
| // (two different numbers for the same column key) means the rows | |
| // are distinct runs that happen to share a model name — leave them. | |
| let conflict = false | |
| const valuesByKey: Record<string, number> = {} | |
| outer: for (const candidate of bucket) { | |
| for (const [key, raw] of Object.entries(candidate.values ?? {})) { | |
| if (typeof raw !== "number" || !Number.isFinite(raw)) continue | |
| if (key in valuesByKey) { | |
| if (valuesByKey[key] !== raw) { | |
| conflict = true | |
| break outer | |
| } | |
| } else { | |
| valuesByKey[key] = raw | |
| } | |
| } | |
| } | |
| if (conflict) { | |
| result.push(row) | |
| continue | |
| } | |
| // Pick the canonical row: best developer attribution, then best | |
| // route id, then most populated values map as a tiebreaker. | |
| const canonical = [...bucket].sort((a, b) => { | |
| const devDelta = devAttributionScore(b.model_info?.developer) - devAttributionScore(a.model_info?.developer) | |
| if (devDelta !== 0) return devDelta | |
| const routeDelta = routeAttributionScore(b.model_route_id) - routeAttributionScore(a.model_route_id) | |
| if (routeDelta !== 0) return routeDelta | |
| return Object.keys(b.values ?? {}).length - Object.keys(a.values ?? {}).length | |
| })[0] | |
| const mergedValues: Record<string, number | null> = { ...(canonical.values ?? {}) } | |
| const mergedAnnotations: Record<string, unknown> = { ...(canonical.annotations_by_metric ?? {}) } | |
| const mergedStatus: Record<string, unknown> = { | |
| ...(canonical.comparability_status_by_metric ?? {}), | |
| } | |
| for (const candidate of bucket) { | |
| if (candidate === canonical) continue | |
| for (const [key, raw] of Object.entries(candidate.values ?? {})) { | |
| if (mergedValues[key] == null && raw != null) mergedValues[key] = raw | |
| } | |
| for (const [key, ann] of Object.entries(candidate.annotations_by_metric ?? {})) { | |
| if (mergedAnnotations[key] == null && ann != null) mergedAnnotations[key] = ann | |
| } | |
| for (const [key, status] of Object.entries(candidate.comparability_status_by_metric ?? {})) { | |
| if (mergedStatus[key] == null && status != null) mergedStatus[key] = status | |
| } | |
| consumed.add(candidate) | |
| } | |
| result.push({ | |
| ...canonical, | |
| values: mergedValues, | |
| annotations_by_metric: mergedAnnotations as typeof canonical.annotations_by_metric, | |
| comparability_status_by_metric: | |
| mergedStatus as typeof canonical.comparability_status_by_metric, | |
| }) | |
| consumed.add(canonical) | |
| } | |
| return result | |
| } | |