Spaces:
Running
Assisted runs: shown, labeled, and unranked by default
Browse filesProtocol-varied collections (first: the UK AISI inference-scaling study)
deliver several results per model, including oracle answer-feedback runs.
The backend never serves those a rank, but the single-metric table (and
the merged page, which renders through it) re-rank client-side by score —
which would have crowned an assisted 1.00 as #1.
- Plumb collection_id / protocol_condition through the eval-summary and
merged queries, probe-gated so pre-collections snapshots keep NULL
aliases (no binder errors, feature self-disabling).
- Assisted rows keep their place in the table but take no rank (em dash +
"assisted" chip); an explicit banner control re-includes them in
ranking (default off).
- Study-protocol caveat banner on pages carrying protocol rows: expanded
budgets are not comparable to standard published results.
- Distribution/Frontier plotbox stats exclude assisted rows — a "best"
that needed the answer oracle is not a frontier.
Pages without protocol data render identically (single activation gate;
NULL columns on old snapshots).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- components/eval-detail.tsx +100 -10
- lib/eval-processing.ts +22 -0
- lib/merged-adapter.ts +2 -0
- lib/view-data.ts +41 -3
- tests/assisted-results.test.ts +30 -0
|
@@ -53,6 +53,7 @@ import {
|
|
| 53 |
} from "lucide-react"
|
| 54 |
import type { BenchmarkCard, SourceData } from "@/lib/benchmark-schema"
|
| 55 |
import { tagLabel } from "@/lib/benchmark-schema"
|
|
|
|
| 56 |
import type { BenchmarkEvalSummary, ModelResultForBenchmark } from "@/lib/eval-processing"
|
| 57 |
import { isRecognizedEvaluator } from "@/lib/evaluators"
|
| 58 |
import { useEvaluatorSlug } from "@/components/org-metadata-provider"
|
|
@@ -851,6 +852,21 @@ export function EvalDetail({
|
|
| 851 |
|
| 852 |
const [showUnknownSize, setShowUnknownSize] = useState(true)
|
| 853 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 854 |
const hasParameterData = useMemo(
|
| 855 |
() => sortedResults.some((result) => getParamsBillions(result) != null),
|
| 856 |
[sortedResults]
|
|
@@ -871,21 +887,39 @@ export function EvalDetail({
|
|
| 871 |
const leaderboardRows = useMemo<LeaderboardRow[]>(() => {
|
| 872 |
let currentRank = 0
|
| 873 |
let previousScore: number | null = null
|
|
|
|
| 874 |
|
| 875 |
return filteredResults.map((modelResult, index) => {
|
| 876 |
-
|
| 877 |
-
|
| 878 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 879 |
}
|
| 880 |
|
| 881 |
return {
|
| 882 |
key: `${modelResult.model_info.id}-${index}`,
|
| 883 |
-
rank
|
| 884 |
modelResult,
|
| 885 |
normalizedScore: normalizeScore(modelResult.score),
|
| 886 |
}
|
| 887 |
})
|
| 888 |
-
}, [filteredResults])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 889 |
|
| 890 |
// Optional user-driven sort. `default` keeps the score-ordered rows
|
| 891 |
// the ranker already produced. The rank label is always by score
|
|
@@ -1560,7 +1594,43 @@ export function EvalDetail({
|
|
| 1560 |
|
| 1561 |
{/* Score distribution — paper-themed mean/median/quartile summary,
|
| 1562 |
with an optional Frontier toggle when models carry release dates. */}
|
| 1563 |
-
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1564 |
<div className="mb-4">
|
| 1565 |
<div className="flex justify-end mb-2">
|
| 1566 |
<EmbedButton
|
|
@@ -1590,10 +1660,10 @@ export function EvalDetail({
|
|
| 1590 |
series={[{
|
| 1591 |
key: "primary",
|
| 1592 |
label: lb.metric_config.unit ?? "Score",
|
| 1593 |
-
values:
|
| 1594 |
unit: lb.metric_config.unit,
|
| 1595 |
lowerIsBetter: lb.metric_config.lower_is_better,
|
| 1596 |
-
points:
|
| 1597 |
score: r.modelResult.score,
|
| 1598 |
releaseDate: r.modelResult.model_info.release_date,
|
| 1599 |
modelName: r.modelResult.model_info.name,
|
|
@@ -1866,6 +1936,7 @@ export function EvalDetail({
|
|
| 1866 |
: null
|
| 1867 |
const isTopRank = rank === 1
|
| 1868 |
const rankColor = rank === 1 ? "var(--accent)" : "var(--fg-muted)"
|
|
|
|
| 1869 |
|
| 1870 |
return (
|
| 1871 |
<Fragment key={key}>
|
|
@@ -1882,10 +1953,13 @@ export function EvalDetail({
|
|
| 1882 |
style={{
|
| 1883 |
fontSize: 14,
|
| 1884 |
fontWeight: isTopRank ? 600 : 500,
|
| 1885 |
-
color: rankColor,
|
| 1886 |
}}
|
|
|
|
|
|
|
|
|
|
| 1887 |
>
|
| 1888 |
-
#{rank}
|
| 1889 |
</span>
|
| 1890 |
</td>
|
| 1891 |
|
|
@@ -1911,6 +1985,22 @@ export function EvalDetail({
|
|
| 1911 |
>
|
| 1912 |
{modelResult.model_info.name}
|
| 1913 |
</Link>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1914 |
{familyLabel && (
|
| 1915 |
<div
|
| 1916 |
className="mt-0.5 font-mono uppercase truncate"
|
|
|
|
| 53 |
} from "lucide-react"
|
| 54 |
import type { BenchmarkCard, SourceData } from "@/lib/benchmark-schema"
|
| 55 |
import { tagLabel } from "@/lib/benchmark-schema"
|
| 56 |
+
import { isAssistedResult } from "@/lib/eval-processing"
|
| 57 |
import type { BenchmarkEvalSummary, ModelResultForBenchmark } from "@/lib/eval-processing"
|
| 58 |
import { isRecognizedEvaluator } from "@/lib/evaluators"
|
| 59 |
import { useEvaluatorSlug } from "@/components/org-metadata-provider"
|
|
|
|
| 852 |
|
| 853 |
const [showUnknownSize, setShowUnknownSize] = useState(true)
|
| 854 |
|
| 855 |
+
// Protocol-varied collections (e.g. the AISI inference-scaling study):
|
| 856 |
+
// rows may carry a protocol_condition. Assisted (answer-feedback) runs
|
| 857 |
+
// are shown but UNRANKED by default — mirroring the backend, which never
|
| 858 |
+
// serves them a rank — with an explicit opt-in that re-includes them in
|
| 859 |
+
// the client-side ranking.
|
| 860 |
+
const hasProtocolRows = useMemo(
|
| 861 |
+
() => lb.model_results.some((r) => r.protocol_condition != null),
|
| 862 |
+
[lb.model_results]
|
| 863 |
+
)
|
| 864 |
+
const hasAssistedRows = useMemo(
|
| 865 |
+
() => lb.model_results.some((r) => isAssistedResult(r.protocol_condition)),
|
| 866 |
+
[lb.model_results]
|
| 867 |
+
)
|
| 868 |
+
const [includeAssistedInRanking, setIncludeAssistedInRanking] = useState(false)
|
| 869 |
+
|
| 870 |
const hasParameterData = useMemo(
|
| 871 |
() => sortedResults.some((result) => getParamsBillions(result) != null),
|
| 872 |
[sortedResults]
|
|
|
|
| 887 |
const leaderboardRows = useMemo<LeaderboardRow[]>(() => {
|
| 888 |
let currentRank = 0
|
| 889 |
let previousScore: number | null = null
|
| 890 |
+
let rankedCount = 0
|
| 891 |
|
| 892 |
return filteredResults.map((modelResult, index) => {
|
| 893 |
+
// Assisted runs are visible but take no rank (rank 0 sentinel)
|
| 894 |
+
// unless the reader explicitly re-includes them.
|
| 895 |
+
const unranked =
|
| 896 |
+
!includeAssistedInRanking && isAssistedResult(modelResult.protocol_condition)
|
| 897 |
+
let rank = 0
|
| 898 |
+
if (!unranked) {
|
| 899 |
+
rankedCount += 1
|
| 900 |
+
if (previousScore === null || Math.abs(modelResult.score - previousScore) > 1e-9) {
|
| 901 |
+
currentRank = rankedCount
|
| 902 |
+
previousScore = modelResult.score
|
| 903 |
+
}
|
| 904 |
+
rank = currentRank
|
| 905 |
}
|
| 906 |
|
| 907 |
return {
|
| 908 |
key: `${modelResult.model_info.id}-${index}`,
|
| 909 |
+
rank,
|
| 910 |
modelResult,
|
| 911 |
normalizedScore: normalizeScore(modelResult.score),
|
| 912 |
}
|
| 913 |
})
|
| 914 |
+
}, [filteredResults, includeAssistedInRanking])
|
| 915 |
+
|
| 916 |
+
// Plotbox input: assisted runs stay out of the distribution stats and
|
| 917 |
+
// the frontier cumulative-best regardless of the ranking toggle — a
|
| 918 |
+
// "best" that needed the answer oracle is not a frontier.
|
| 919 |
+
const unassistedLeaderboardRows = useMemo(
|
| 920 |
+
() => leaderboardRows.filter((r) => !isAssistedResult(r.modelResult.protocol_condition)),
|
| 921 |
+
[leaderboardRows]
|
| 922 |
+
)
|
| 923 |
|
| 924 |
// Optional user-driven sort. `default` keeps the score-ordered rows
|
| 925 |
// the ranker already produced. The rank label is always by score
|
|
|
|
| 1594 |
|
| 1595 |
{/* Score distribution — paper-themed mean/median/quartile summary,
|
| 1596 |
with an optional Frontier toggle when models carry release dates. */}
|
| 1597 |
+
{hasProtocolRows && (
|
| 1598 |
+
<div
|
| 1599 |
+
className="mb-4 flex items-start gap-3 px-4 py-3"
|
| 1600 |
+
style={{
|
| 1601 |
+
border: "1px solid var(--border-soft)",
|
| 1602 |
+
borderLeft: "2px solid var(--fg-muted)",
|
| 1603 |
+
background: "var(--bg-warm)",
|
| 1604 |
+
color: "var(--fg)",
|
| 1605 |
+
}}
|
| 1606 |
+
>
|
| 1607 |
+
<div className="text-[13px] leading-relaxed">
|
| 1608 |
+
<span style={{ fontWeight: 600 }}>Study-specific protocol.</span>{" "}
|
| 1609 |
+
These results were run under expanded, study-specific inference
|
| 1610 |
+
budgets and are not directly comparable to standard published
|
| 1611 |
+
benchmark results.
|
| 1612 |
+
{hasAssistedRows && (
|
| 1613 |
+
<>
|
| 1614 |
+
{" "}Assisted runs — where the model is told when its answer
|
| 1615 |
+
is correct — are labeled and excluded from ranking
|
| 1616 |
+
{includeAssistedInRanking ? " (currently included)" : ""}.{" "}
|
| 1617 |
+
<button
|
| 1618 |
+
type="button"
|
| 1619 |
+
onClick={() => setIncludeAssistedInRanking((v) => !v)}
|
| 1620 |
+
className="underline underline-offset-2 hover:text-[color:var(--accent)]"
|
| 1621 |
+
style={{ color: "var(--fg-muted)" }}
|
| 1622 |
+
>
|
| 1623 |
+
{includeAssistedInRanking
|
| 1624 |
+
? "Exclude assisted runs from ranking"
|
| 1625 |
+
: "Include assisted runs in ranking"}
|
| 1626 |
+
</button>
|
| 1627 |
+
</>
|
| 1628 |
+
)}
|
| 1629 |
+
</div>
|
| 1630 |
+
</div>
|
| 1631 |
+
)}
|
| 1632 |
+
|
| 1633 |
+
{unassistedLeaderboardRows.length >= 3 && (
|
| 1634 |
<div className="mb-4">
|
| 1635 |
<div className="flex justify-end mb-2">
|
| 1636 |
<EmbedButton
|
|
|
|
| 1660 |
series={[{
|
| 1661 |
key: "primary",
|
| 1662 |
label: lb.metric_config.unit ?? "Score",
|
| 1663 |
+
values: unassistedLeaderboardRows.map((r) => r.modelResult.score),
|
| 1664 |
unit: lb.metric_config.unit,
|
| 1665 |
lowerIsBetter: lb.metric_config.lower_is_better,
|
| 1666 |
+
points: unassistedLeaderboardRows.map((r) => ({
|
| 1667 |
score: r.modelResult.score,
|
| 1668 |
releaseDate: r.modelResult.model_info.release_date,
|
| 1669 |
modelName: r.modelResult.model_info.name,
|
|
|
|
| 1936 |
: null
|
| 1937 |
const isTopRank = rank === 1
|
| 1938 |
const rankColor = rank === 1 ? "var(--accent)" : "var(--fg-muted)"
|
| 1939 |
+
const isAssisted = isAssistedResult(modelResult.protocol_condition)
|
| 1940 |
|
| 1941 |
return (
|
| 1942 |
<Fragment key={key}>
|
|
|
|
| 1953 |
style={{
|
| 1954 |
fontSize: 14,
|
| 1955 |
fontWeight: isTopRank ? 600 : 500,
|
| 1956 |
+
color: rank === 0 ? "var(--fg-subtle)" : rankColor,
|
| 1957 |
}}
|
| 1958 |
+
title={rank === 0
|
| 1959 |
+
? "Assisted run (answer feedback) — shown, not ranked"
|
| 1960 |
+
: undefined}
|
| 1961 |
>
|
| 1962 |
+
{rank === 0 ? "—" : `#${rank}`}
|
| 1963 |
</span>
|
| 1964 |
</td>
|
| 1965 |
|
|
|
|
| 1985 |
>
|
| 1986 |
{modelResult.model_info.name}
|
| 1987 |
</Link>
|
| 1988 |
+
{isAssisted && (
|
| 1989 |
+
<span
|
| 1990 |
+
className="ml-1.5 inline-block align-middle font-mono uppercase"
|
| 1991 |
+
style={{
|
| 1992 |
+
fontSize: 9,
|
| 1993 |
+
letterSpacing: "0.08em",
|
| 1994 |
+
color: "var(--fg-muted)",
|
| 1995 |
+
border: "1px solid var(--border-soft)",
|
| 1996 |
+
borderRadius: 3,
|
| 1997 |
+
padding: "1px 4px",
|
| 1998 |
+
}}
|
| 1999 |
+
title="The model was told when its answer was correct (oracle answer feedback)."
|
| 2000 |
+
>
|
| 2001 |
+
assisted
|
| 2002 |
+
</span>
|
| 2003 |
+
)}
|
| 2004 |
{familyLabel && (
|
| 2005 |
<div
|
| 2006 |
className="mt-0.5 font-mono uppercase truncate"
|
|
@@ -23,6 +23,23 @@ import type { EvalcardsAnnotations, RowAnnotations, SignalSummaries } from './ba
|
|
| 23 |
export type { BenchmarkCard }
|
| 24 |
export type { ModelEvaluationSummary }
|
| 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
export interface ModelResultForBenchmark {
|
| 27 |
model_info: ModelInfo
|
| 28 |
model_route_id?: string
|
|
@@ -273,6 +290,11 @@ export interface MergedObservationRow {
|
|
| 273 |
source_metadata: SourceMetadata
|
| 274 |
generation_config?: GenerationConfig
|
| 275 |
is_verified_evaluator?: boolean
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
}
|
| 277 |
|
| 278 |
export interface MergedBenchmarkSummary {
|
|
|
|
| 23 |
export type { BenchmarkCard }
|
| 24 |
export type { ModelEvaluationSummary }
|
| 25 |
|
| 26 |
+
|
| 27 |
+
/**
|
| 28 |
+
* True when a result ran under the oracle answer-feedback arm of a
|
| 29 |
+
* protocol-varied collection (the model was told when its answer was
|
| 30 |
+
* correct). Assisted rows are shown but excluded from client-side ranking
|
| 31 |
+
* by default — mirroring the backend, which never serves them a rank.
|
| 32 |
+
*/
|
| 33 |
+
export function isAssistedResult(protocolCondition: string | null | undefined): boolean {
|
| 34 |
+
if (!protocolCondition) return false
|
| 35 |
+
try {
|
| 36 |
+
const parsed = JSON.parse(protocolCondition) as { feedback?: unknown } | null
|
| 37 |
+
return parsed != null && typeof parsed === "object" && parsed.feedback === "answer_feedback"
|
| 38 |
+
} catch {
|
| 39 |
+
return false
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
export interface ModelResultForBenchmark {
|
| 44 |
model_info: ModelInfo
|
| 45 |
model_route_id?: string
|
|
|
|
| 290 |
source_metadata: SourceMetadata
|
| 291 |
generation_config?: GenerationConfig
|
| 292 |
is_verified_evaluator?: boolean
|
| 293 |
+
/** Collections: submission-channel id of the observation's source row. */
|
| 294 |
+
collection_id?: string
|
| 295 |
+
/** Protocol point (canonical sorted-key JSON) for protocol-varied
|
| 296 |
+
* collections; absent/null for ordinary observations. */
|
| 297 |
+
protocol_condition?: string | null
|
| 298 |
}
|
| 299 |
|
| 300 |
export interface MergedBenchmarkSummary {
|
|
@@ -99,6 +99,8 @@ export function mergedSummaryToEvalSummary(merged: MergedBenchmarkSummary): Benc
|
|
| 99 |
source_data: sourceData,
|
| 100 |
merged_source_slug: row.composite_slug,
|
| 101 |
is_verified_evaluator: row.is_verified_evaluator,
|
|
|
|
|
|
|
| 102 |
result: {
|
| 103 |
evaluation_name: metricDisplayName,
|
| 104 |
display_name: metricDisplayName,
|
|
|
|
| 99 |
source_data: sourceData,
|
| 100 |
merged_source_slug: row.composite_slug,
|
| 101 |
is_verified_evaluator: row.is_verified_evaluator,
|
| 102 |
+
collection_id: row.collection_id,
|
| 103 |
+
protocol_condition: row.protocol_condition,
|
| 104 |
result: {
|
| 105 |
evaluation_name: metricDisplayName,
|
| 106 |
display_name: metricDisplayName,
|
|
@@ -641,6 +641,8 @@ function reshapeCellToModelResult(row: Row): ModelResultForBenchmark {
|
|
| 641 |
source_data: sourceDataFromRow(row),
|
| 642 |
source_record_url: optionalString(row.source_record_url),
|
| 643 |
eee_record_url: optionalString(row.eee_record_url),
|
|
|
|
|
|
|
| 644 |
aggregate_components: asArray<NonNullable<ModelResultForBenchmark["aggregate_components"]>[number]>(
|
| 645 |
aggregateComponents
|
| 646 |
),
|
|
@@ -780,6 +782,32 @@ async function evalsViewHasParentDisplayName(): Promise<boolean> {
|
|
| 780 |
return evalsViewParentDisplayNameCache
|
| 781 |
}
|
| 782 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 783 |
async function getModelEvaluationRows(modelKey: string): Promise<Row[]> {
|
| 784 |
const hasParentDisplayName = await evalsViewHasParentDisplayName()
|
| 785 |
// model_key is the producer's addressable identifier — non-null for both
|
|
@@ -964,8 +992,9 @@ export async function getEvalSummaryById(evalId: string): Promise<BenchmarkEvalS
|
|
| 964 |
const evalRow = evalRows[0]
|
| 965 |
if (!evalRow) return null
|
| 966 |
|
|
|
|
| 967 |
let cellRows = await readRows<Row>(
|
| 968 |
-
`SELECT ${
|
| 969 |
FROM eval_results_view r
|
| 970 |
LEFT JOIN evals_view e ON r.evaluation_id = e.evaluation_id
|
| 971 |
WHERE r.evaluation_id = ?
|
|
@@ -978,7 +1007,7 @@ export async function getEvalSummaryById(evalId: string): Promise<BenchmarkEvalS
|
|
| 978 |
|
| 979 |
if (cellRows.length === 0) {
|
| 980 |
cellRows = await readRows<Row>(
|
| 981 |
-
`SELECT ${
|
| 982 |
FROM eval_results_view r
|
| 983 |
LEFT JOIN evals_view e ON r.evaluation_id = e.evaluation_id
|
| 984 |
WHERE r.evaluation_id = ?
|
|
@@ -1170,6 +1199,13 @@ const MERGED_ROW_COLUMNS = `
|
|
| 1170 |
CAST(to_json(slices) AS VARCHAR) AS slices
|
| 1171 |
`
|
| 1172 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1173 |
const MERGED_RESULT_COLUMNS = `
|
| 1174 |
r.evaluation_id,
|
| 1175 |
r.benchmark_id,
|
|
@@ -1206,6 +1242,8 @@ function mergedObservationFromRow(row: Row): MergedObservationRow {
|
|
| 1206 |
generation_config: (generationConfig ?? undefined) as GenerationConfig | undefined,
|
| 1207 |
is_verified_evaluator:
|
| 1208 |
row.is_verified_evaluator == null ? undefined : Boolean(row.is_verified_evaluator),
|
|
|
|
|
|
|
| 1209 |
}
|
| 1210 |
}
|
| 1211 |
|
|
@@ -1277,7 +1315,7 @@ export async function getMergedBenchmarkSummary(
|
|
| 1277 |
if (grain === "benchmark" || selectedSliceId) {
|
| 1278 |
const targetBenchmarkId = grain === "slice" ? selectedSliceId : asString(row.benchmark_id)
|
| 1279 |
resultRows = await readRows<Row>(
|
| 1280 |
-
`SELECT ${
|
| 1281 |
FROM eval_results_view r
|
| 1282 |
WHERE r.benchmark_id = ?
|
| 1283 |
AND r.metric_id_effective = ?
|
|
|
|
| 641 |
source_data: sourceDataFromRow(row),
|
| 642 |
source_record_url: optionalString(row.source_record_url),
|
| 643 |
eee_record_url: optionalString(row.eee_record_url),
|
| 644 |
+
collection_id: optionalString(row.collection_id),
|
| 645 |
+
protocol_condition: optionalString(row.protocol_condition) ?? undefined,
|
| 646 |
aggregate_components: asArray<NonNullable<ModelResultForBenchmark["aggregate_components"]>[number]>(
|
| 647 |
aggregateComponents
|
| 648 |
),
|
|
|
|
| 782 |
return evalsViewParentDisplayNameCache
|
| 783 |
}
|
| 784 |
|
| 785 |
+
// Probe (once per process) whether the loaded snapshot's eval_results_view
|
| 786 |
+
// carries the additive collections columns (collection_id /
|
| 787 |
+
// protocol_condition), so projections degrade to NULL aliases on older
|
| 788 |
+
// snapshots instead of binder-erroring the query. Same lifecycle as the
|
| 789 |
+
// parent_display_name probe above.
|
| 790 |
+
let ervCollectionColumnsCache: boolean | undefined
|
| 791 |
+
async function evalResultsViewHasCollectionColumns(): Promise<boolean> {
|
| 792 |
+
if (ervCollectionColumnsCache === undefined) {
|
| 793 |
+
try {
|
| 794 |
+
const columns = await readRows<{ column_name: string }>("DESCRIBE eval_results_view")
|
| 795 |
+
const names = new Set(columns.map((column) => column.column_name))
|
| 796 |
+
ervCollectionColumnsCache = names.has("collection_id") && names.has("protocol_condition")
|
| 797 |
+
} catch {
|
| 798 |
+
return false
|
| 799 |
+
}
|
| 800 |
+
}
|
| 801 |
+
return ervCollectionColumnsCache
|
| 802 |
+
}
|
| 803 |
+
|
| 804 |
+
function evalCellJoinColumns(hasCollections: boolean) {
|
| 805 |
+
return `${EVAL_CELL_JOIN_COLUMNS},
|
| 806 |
+
${hasCollections
|
| 807 |
+
? "r.collection_id, r.protocol_condition"
|
| 808 |
+
: "CAST(NULL AS VARCHAR) AS collection_id, CAST(NULL AS VARCHAR) AS protocol_condition"}`
|
| 809 |
+
}
|
| 810 |
+
|
| 811 |
async function getModelEvaluationRows(modelKey: string): Promise<Row[]> {
|
| 812 |
const hasParentDisplayName = await evalsViewHasParentDisplayName()
|
| 813 |
// model_key is the producer's addressable identifier — non-null for both
|
|
|
|
| 992 |
const evalRow = evalRows[0]
|
| 993 |
if (!evalRow) return null
|
| 994 |
|
| 995 |
+
const hasCollectionColumns = await evalResultsViewHasCollectionColumns()
|
| 996 |
let cellRows = await readRows<Row>(
|
| 997 |
+
`SELECT ${evalCellJoinColumns(hasCollectionColumns)}
|
| 998 |
FROM eval_results_view r
|
| 999 |
LEFT JOIN evals_view e ON r.evaluation_id = e.evaluation_id
|
| 1000 |
WHERE r.evaluation_id = ?
|
|
|
|
| 1007 |
|
| 1008 |
if (cellRows.length === 0) {
|
| 1009 |
cellRows = await readRows<Row>(
|
| 1010 |
+
`SELECT ${evalCellJoinColumns(hasCollectionColumns)}
|
| 1011 |
FROM eval_results_view r
|
| 1012 |
LEFT JOIN evals_view e ON r.evaluation_id = e.evaluation_id
|
| 1013 |
WHERE r.evaluation_id = ?
|
|
|
|
| 1199 |
CAST(to_json(slices) AS VARCHAR) AS slices
|
| 1200 |
`
|
| 1201 |
|
| 1202 |
+
function mergedResultColumns(hasCollections: boolean) {
|
| 1203 |
+
return `${MERGED_RESULT_COLUMNS},
|
| 1204 |
+
${hasCollections
|
| 1205 |
+
? "r.collection_id, r.protocol_condition"
|
| 1206 |
+
: "CAST(NULL AS VARCHAR) AS collection_id, CAST(NULL AS VARCHAR) AS protocol_condition"}`
|
| 1207 |
+
}
|
| 1208 |
+
|
| 1209 |
const MERGED_RESULT_COLUMNS = `
|
| 1210 |
r.evaluation_id,
|
| 1211 |
r.benchmark_id,
|
|
|
|
| 1242 |
generation_config: (generationConfig ?? undefined) as GenerationConfig | undefined,
|
| 1243 |
is_verified_evaluator:
|
| 1244 |
row.is_verified_evaluator == null ? undefined : Boolean(row.is_verified_evaluator),
|
| 1245 |
+
collection_id: optionalString(row.collection_id),
|
| 1246 |
+
protocol_condition: optionalString(row.protocol_condition) ?? undefined,
|
| 1247 |
}
|
| 1248 |
}
|
| 1249 |
|
|
|
|
| 1315 |
if (grain === "benchmark" || selectedSliceId) {
|
| 1316 |
const targetBenchmarkId = grain === "slice" ? selectedSliceId : asString(row.benchmark_id)
|
| 1317 |
resultRows = await readRows<Row>(
|
| 1318 |
+
`SELECT ${mergedResultColumns(await evalResultsViewHasCollectionColumns())}
|
| 1319 |
FROM eval_results_view r
|
| 1320 |
WHERE r.benchmark_id = ?
|
| 1321 |
AND r.metric_id_effective = ?
|
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { describe, expect, it } from "vitest"
|
| 2 |
+
|
| 3 |
+
import { isAssistedResult } from "@/lib/eval-processing"
|
| 4 |
+
|
| 5 |
+
// Assisted (oracle answer-feedback) classification drives shown-but-unranked
|
| 6 |
+
// leaderboard handling; misclassification either ranks an assisted run or
|
| 7 |
+
// strips a rank from a clean one.
|
| 8 |
+
describe("isAssistedResult", () => {
|
| 9 |
+
it("classifies the answer_feedback arm", () => {
|
| 10 |
+
expect(
|
| 11 |
+
isAssistedResult(
|
| 12 |
+
'{"compaction":false,"feedback":"answer_feedback","scaffold":"S-adaptive","token_limit":5000000}',
|
| 13 |
+
),
|
| 14 |
+
).toBe(true)
|
| 15 |
+
})
|
| 16 |
+
|
| 17 |
+
it("keeps clean and unknown arms unassisted", () => {
|
| 18 |
+
expect(isAssistedResult('{"feedback":"none"}')).toBe(false)
|
| 19 |
+
expect(isAssistedResult('{"feedback":"unknown"}')).toBe(false)
|
| 20 |
+
expect(isAssistedResult('{"token_limit":5000000}')).toBe(false)
|
| 21 |
+
})
|
| 22 |
+
|
| 23 |
+
it("treats absent/invalid protocol data as unassisted", () => {
|
| 24 |
+
expect(isAssistedResult(undefined)).toBe(false)
|
| 25 |
+
expect(isAssistedResult(null)).toBe(false)
|
| 26 |
+
expect(isAssistedResult("")).toBe(false)
|
| 27 |
+
expect(isAssistedResult("not json")).toBe(false)
|
| 28 |
+
expect(isAssistedResult('"answer_feedback"')).toBe(false)
|
| 29 |
+
})
|
| 30 |
+
})
|