Spaces:
Running
Eval detail polish: hide empty fields, redesign splits, surface evaluator
Browse filesBenchmark card now hides Goal/Score interp/Limitations cards when the
underlying value is empty or "Not specified", and collapses the
Ethical & legal section entirely when license + compliance + privacy
are all missing. The previous behavior rendered placeholder boxes
that read "Not specified" with no signal value.
Policy note hides Caveat / Intended for rows with the same sentinel,
filters "Not specified" out of the domain/language chip strip, and
re-themes the splits panel away from a bordered box with bullet list
to inline header + chip layout. "Slices" → "Splits" throughout the
policy note. (benchmark-detail.tsx still uses "slice" terminology in
several places — left untouched, distinct concept.)
Eval detail hero now leads with a "REPORTED BY <evaluator>" kicker
above the title. Two evaluations can share an upstream dataset (e.g.
both TIGER-Lab and Arcadia Impact reporting against
TIGER-Lab/MMLU-Pro) and otherwise look indistinguishable; naming the
evaluator up front is the cheapest way to disambiguate. Also relabels
"Source dataset" to "Upstream dataset" in the overview details strip
and the eval-card mini panel — same motivation: it's the canonical
dataset, not the source of these particular numbers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- components/eval-card.tsx +1 -1
- components/eval-detail.tsx +140 -87
- components/policy-overview.tsx +63 -38
|
@@ -327,7 +327,7 @@ function ProvenanceRow({
|
|
| 327 |
<div className="rounded-xl border border-border/60 bg-background/60 p-3">
|
| 328 |
<div className="mb-2 flex items-center gap-1.5 text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
| 329 |
<Database className="h-3 w-3" />
|
| 330 |
-
|
| 331 |
</div>
|
| 332 |
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-sm">
|
| 333 |
{datasetName && (
|
|
|
|
| 327 |
<div className="rounded-xl border border-border/60 bg-background/60 p-3">
|
| 328 |
<div className="mb-2 flex items-center gap-1.5 text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
| 329 |
<Database className="h-3 w-3" />
|
| 330 |
+
Upstream dataset
|
| 331 |
</div>
|
| 332 |
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-sm">
|
| 333 |
{datasetName && (
|
|
@@ -756,7 +756,7 @@ export function EvalDetail({
|
|
| 756 |
: "Models ranked by raw score for this benchmark."
|
| 757 |
: lb.is_aggregated
|
| 758 |
? "Averaged model results across the composite's component benchmarks, with drill-down to each component score."
|
| 759 |
-
: "Model results with benchmark context,
|
| 760 |
const reportingCompleteness = summary.evalcards?.annotations?.reporting_completeness
|
| 761 |
const documentationPopulatedCount = reportingCompleteness
|
| 762 |
? getCompletenessPopulatedCount(reportingCompleteness)
|
|
@@ -784,6 +784,19 @@ export function EvalDetail({
|
|
| 784 |
? summary.composite_benchmark_name
|
| 785 |
: null)
|
| 786 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 787 |
const heroLede = isResearchView
|
| 788 |
? summary.metric_config.evaluation_description
|
| 789 |
: (summary.benchmark_card?.benchmark_details?.overview?.trim()
|
|
@@ -794,6 +807,20 @@ export function EvalDetail({
|
|
| 794 |
<div className="space-y-12">
|
| 795 |
{/* HERO — paper §3.1 ------------------------------------------------ */}
|
| 796 |
<header className="motion-academic-enter">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 797 |
<h1
|
| 798 |
className="font-bold tracking-[-0.025em]"
|
| 799 |
style={{ fontSize: "clamp(40px, 5vw, 60px)", lineHeight: 1.04, margin: "0 0 12px" }}
|
|
@@ -934,7 +961,7 @@ export function EvalDetail({
|
|
| 934 |
</dd>
|
| 935 |
</>
|
| 936 |
)}
|
| 937 |
-
<dt>
|
| 938 |
<dd>{sourceDatasetLabel}</dd>
|
| 939 |
<dt>Instance data</dt>
|
| 940 |
<dd>{instanceDataLabel}</dd>
|
|
@@ -2628,58 +2655,71 @@ function BenchmarkCardPanel({
|
|
| 2628 |
<div className="space-y-6 p-5 sm:p-6">
|
| 2629 |
{knownIssues.length > 0 && <KnownIssuesPanel issues={knownIssues} variant="full" />}
|
| 2630 |
|
| 2631 |
-
|
| 2632 |
-
|
| 2633 |
-
|
| 2634 |
-
|
| 2635 |
-
|
| 2636 |
-
|
| 2637 |
-
|
| 2638 |
-
|
| 2639 |
-
|
| 2640 |
-
|
| 2641 |
-
|
| 2642 |
-
|
| 2643 |
-
|
| 2644 |
-
|
| 2645 |
-
|
| 2646 |
-
|
| 2647 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2648 |
|
| 2649 |
-
|
| 2650 |
-
|
| 2651 |
-
|
| 2652 |
-
|
| 2653 |
-
|
| 2654 |
-
|
| 2655 |
-
|
| 2656 |
-
|
| 2657 |
-
|
| 2658 |
-
|
| 2659 |
-
|
| 2660 |
-
|
| 2661 |
-
|
| 2662 |
-
|
| 2663 |
-
|
| 2664 |
-
|
|
|
|
| 2665 |
|
| 2666 |
-
|
| 2667 |
-
|
| 2668 |
-
|
| 2669 |
-
|
| 2670 |
-
|
| 2671 |
-
|
| 2672 |
-
|
| 2673 |
-
|
| 2674 |
-
|
| 2675 |
-
|
| 2676 |
-
|
| 2677 |
-
|
| 2678 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2679 |
</div>
|
| 2680 |
-
|
| 2681 |
-
|
| 2682 |
-
</div>
|
| 2683 |
|
| 2684 |
{(methodology.methods?.length > 0 ||
|
| 2685 |
(methodology.calculation && methodology.calculation !== "Not specified") ||
|
|
@@ -2879,43 +2919,56 @@ function BenchmarkCardPanel({
|
|
| 2879 |
</Collapsible>
|
| 2880 |
)}
|
| 2881 |
|
| 2882 |
-
{/* Compliance / ethical notes (policy view emphasis)
|
| 2883 |
-
|
| 2884 |
-
|
| 2885 |
-
|
| 2886 |
-
|
| 2887 |
-
|
| 2888 |
-
|
| 2889 |
-
|
| 2890 |
-
|
| 2891 |
-
|
| 2892 |
-
|
| 2893 |
-
|
| 2894 |
-
|
| 2895 |
-
|
| 2896 |
-
|
| 2897 |
-
|
| 2898 |
-
|
| 2899 |
-
|
| 2900 |
-
|
| 2901 |
-
|
| 2902 |
-
|
| 2903 |
-
|
| 2904 |
-
|
| 2905 |
-
|
| 2906 |
-
|
| 2907 |
-
|
| 2908 |
-
</div>
|
| 2909 |
-
)}
|
| 2910 |
-
{ethical.privacy_and_anonymity && ethical.privacy_and_anonymity !== "Not specified" && (
|
| 2911 |
-
<div className="col-span-full flex gap-2">
|
| 2912 |
-
<dt className="w-28 shrink-0" style={{ color: "var(--fg-muted)" }}>Privacy</dt>
|
| 2913 |
-
<dd className="font-medium">{ethical.privacy_and_anonymity}</dd>
|
| 2914 |
</div>
|
| 2915 |
-
|
| 2916 |
-
|
| 2917 |
-
|
| 2918 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2919 |
|
| 2920 |
{/* Flagged / missing fields warning */}
|
| 2921 |
{(flaggedFields.length > 0 || missingFields.length > 0) && isResearchView && (
|
|
|
|
| 756 |
: "Models ranked by raw score for this benchmark."
|
| 757 |
: lb.is_aggregated
|
| 758 |
? "Averaged model results across the composite's component benchmarks, with drill-down to each component score."
|
| 759 |
+
: "Model results with benchmark context, upstream dataset detail, and optional instance-data links."
|
| 760 |
const reportingCompleteness = summary.evalcards?.annotations?.reporting_completeness
|
| 761 |
const documentationPopulatedCount = reportingCompleteness
|
| 762 |
? getCompletenessPopulatedCount(reportingCompleteness)
|
|
|
|
| 784 |
? summary.composite_benchmark_name
|
| 785 |
: null)
|
| 786 |
|
| 787 |
+
// Surface the evaluator (org that ran the eval) as a hero kicker. Two
|
| 788 |
+
// benchmarks can share the same upstream dataset (e.g. TIGER-Lab/MMLU-Pro
|
| 789 |
+
// re-evaluated by both TIGER-Lab and Arcadia Impact) and otherwise look
|
| 790 |
+
// identical in chrome — naming the evaluator up-front is the cheapest
|
| 791 |
+
// way to make the pages visually distinct.
|
| 792 |
+
const evaluatorList = summary.evaluator_names ?? []
|
| 793 |
+
const reporterLabel = (() => {
|
| 794 |
+
if (evaluatorList.length === 0) return null
|
| 795 |
+
const head = evaluatorList.slice(0, 2)
|
| 796 |
+
const extra = evaluatorList.length - head.length
|
| 797 |
+
return extra > 0 ? `${head.join(", ")} +${extra} more` : head.join(", ")
|
| 798 |
+
})()
|
| 799 |
+
|
| 800 |
const heroLede = isResearchView
|
| 801 |
? summary.metric_config.evaluation_description
|
| 802 |
: (summary.benchmark_card?.benchmark_details?.overview?.trim()
|
|
|
|
| 807 |
<div className="space-y-12">
|
| 808 |
{/* HERO — paper §3.1 ------------------------------------------------ */}
|
| 809 |
<header className="motion-academic-enter">
|
| 810 |
+
{reporterLabel && (
|
| 811 |
+
<div
|
| 812 |
+
className="font-mono uppercase"
|
| 813 |
+
style={{
|
| 814 |
+
fontSize: 11,
|
| 815 |
+
letterSpacing: "0.16em",
|
| 816 |
+
color: "var(--fg-subtle)",
|
| 817 |
+
margin: "0 0 10px",
|
| 818 |
+
}}
|
| 819 |
+
>
|
| 820 |
+
<span style={{ color: "var(--fg-muted)" }}>Reported by </span>
|
| 821 |
+
<span style={{ color: "var(--fg)" }}>{reporterLabel}</span>
|
| 822 |
+
</div>
|
| 823 |
+
)}
|
| 824 |
<h1
|
| 825 |
className="font-bold tracking-[-0.025em]"
|
| 826 |
style={{ fontSize: "clamp(40px, 5vw, 60px)", lineHeight: 1.04, margin: "0 0 12px" }}
|
|
|
|
| 961 |
</dd>
|
| 962 |
</>
|
| 963 |
)}
|
| 964 |
+
<dt>Upstream dataset</dt>
|
| 965 |
<dd>{sourceDatasetLabel}</dd>
|
| 966 |
<dt>Instance data</dt>
|
| 967 |
<dd>{instanceDataLabel}</dd>
|
|
|
|
| 2655 |
<div className="space-y-6 p-5 sm:p-6">
|
| 2656 |
{knownIssues.length > 0 && <KnownIssuesPanel issues={knownIssues} variant="full" />}
|
| 2657 |
|
| 2658 |
+
{(() => {
|
| 2659 |
+
const meaningful = (v: string | undefined | null) =>
|
| 2660 |
+
Boolean(v && v.trim() && v.trim() !== "Not specified")
|
| 2661 |
+
const showGoal = meaningful(purpose.goal)
|
| 2662 |
+
const showInterp = meaningful(methodology.interpretation)
|
| 2663 |
+
const showLimitations = meaningful(purpose.limitations)
|
| 2664 |
+
if (!showGoal && !showInterp && !showLimitations) return null
|
| 2665 |
+
return (
|
| 2666 |
+
<div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
| 2667 |
+
{showGoal && (
|
| 2668 |
+
<div
|
| 2669 |
+
style={{
|
| 2670 |
+
padding: 16,
|
| 2671 |
+
border: "1px solid var(--border-soft)",
|
| 2672 |
+
background: "var(--bg)",
|
| 2673 |
+
}}
|
| 2674 |
+
>
|
| 2675 |
+
<div
|
| 2676 |
+
className="mb-2 flex items-center gap-2 font-mono uppercase"
|
| 2677 |
+
style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--fg-subtle)" }}
|
| 2678 |
+
>
|
| 2679 |
+
<Scale className="h-3 w-3" /> Goal
|
| 2680 |
+
</div>
|
| 2681 |
+
<p className="text-[13px] leading-[1.55]" style={{ color: "var(--fg)" }}>{purpose.goal}</p>
|
| 2682 |
+
</div>
|
| 2683 |
+
)}
|
| 2684 |
|
| 2685 |
+
{showInterp && (
|
| 2686 |
+
<div
|
| 2687 |
+
style={{
|
| 2688 |
+
padding: 16,
|
| 2689 |
+
border: "1px solid var(--border-soft)",
|
| 2690 |
+
background: "var(--bg)",
|
| 2691 |
+
}}
|
| 2692 |
+
>
|
| 2693 |
+
<div
|
| 2694 |
+
className="mb-2 flex items-center gap-2 font-mono uppercase"
|
| 2695 |
+
style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--fg-subtle)" }}
|
| 2696 |
+
>
|
| 2697 |
+
<BarChart3 className="h-3 w-3" /> Score interpretation
|
| 2698 |
+
</div>
|
| 2699 |
+
<p className="text-[13px] leading-[1.55]" style={{ color: "var(--fg)" }}>{methodology.interpretation}</p>
|
| 2700 |
+
</div>
|
| 2701 |
+
)}
|
| 2702 |
|
| 2703 |
+
{showLimitations && (
|
| 2704 |
+
<div
|
| 2705 |
+
style={{
|
| 2706 |
+
padding: 16,
|
| 2707 |
+
border: "1px solid var(--accent)",
|
| 2708 |
+
background: "var(--bg-warm)",
|
| 2709 |
+
}}
|
| 2710 |
+
>
|
| 2711 |
+
<div
|
| 2712 |
+
className="mb-2 flex items-center gap-2 font-mono uppercase"
|
| 2713 |
+
style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--accent)" }}
|
| 2714 |
+
>
|
| 2715 |
+
<AlertTriangle className="h-3 w-3" /> Limitations
|
| 2716 |
+
</div>
|
| 2717 |
+
<p className="text-[13px] leading-[1.55]" style={{ color: "var(--accent)" }}>{purpose.limitations}</p>
|
| 2718 |
+
</div>
|
| 2719 |
+
)}
|
| 2720 |
</div>
|
| 2721 |
+
)
|
| 2722 |
+
})()}
|
|
|
|
| 2723 |
|
| 2724 |
{(methodology.methods?.length > 0 ||
|
| 2725 |
(methodology.calculation && methodology.calculation !== "Not specified") ||
|
|
|
|
| 2919 |
</Collapsible>
|
| 2920 |
)}
|
| 2921 |
|
| 2922 |
+
{/* Compliance / ethical notes (policy view emphasis). Hide the
|
| 2923 |
+
entire panel when none of the three fields are populated —
|
| 2924 |
+
otherwise the user sees an empty bordered box with just the
|
| 2925 |
+
section header. */}
|
| 2926 |
+
{!isResearchView &&
|
| 2927 |
+
(() => {
|
| 2928 |
+
const showCompliance =
|
| 2929 |
+
ethical.compliance_with_regulations &&
|
| 2930 |
+
ethical.compliance_with_regulations !== "Not specified"
|
| 2931 |
+
const showPrivacy =
|
| 2932 |
+
ethical.privacy_and_anonymity &&
|
| 2933 |
+
ethical.privacy_and_anonymity !== "Not specified"
|
| 2934 |
+
if (!shortLicense && !showCompliance && !showPrivacy) return null
|
| 2935 |
+
return (
|
| 2936 |
+
<div
|
| 2937 |
+
style={{
|
| 2938 |
+
padding: 16,
|
| 2939 |
+
border: "1px solid var(--border-soft)",
|
| 2940 |
+
background: "var(--bg)",
|
| 2941 |
+
}}
|
| 2942 |
+
>
|
| 2943 |
+
<div
|
| 2944 |
+
className="mb-3 font-mono uppercase"
|
| 2945 |
+
style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--fg-subtle)" }}
|
| 2946 |
+
>
|
| 2947 |
+
Ethical & legal
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2948 |
</div>
|
| 2949 |
+
<dl className="grid gap-x-6 gap-y-2 text-[13px] sm:grid-cols-2">
|
| 2950 |
+
{shortLicense && (
|
| 2951 |
+
<div className="flex gap-2">
|
| 2952 |
+
<dt className="w-28 shrink-0" style={{ color: "var(--fg-muted)" }}>License</dt>
|
| 2953 |
+
<dd className="font-medium">{license}</dd>
|
| 2954 |
+
</div>
|
| 2955 |
+
)}
|
| 2956 |
+
{showCompliance && (
|
| 2957 |
+
<div className="flex gap-2">
|
| 2958 |
+
<dt className="w-28 shrink-0" style={{ color: "var(--fg-muted)" }}>Compliance</dt>
|
| 2959 |
+
<dd className="font-medium">{ethical.compliance_with_regulations}</dd>
|
| 2960 |
+
</div>
|
| 2961 |
+
)}
|
| 2962 |
+
{showPrivacy && (
|
| 2963 |
+
<div className="col-span-full flex gap-2">
|
| 2964 |
+
<dt className="w-28 shrink-0" style={{ color: "var(--fg-muted)" }}>Privacy</dt>
|
| 2965 |
+
<dd className="font-medium">{ethical.privacy_and_anonymity}</dd>
|
| 2966 |
+
</div>
|
| 2967 |
+
)}
|
| 2968 |
+
</dl>
|
| 2969 |
+
</div>
|
| 2970 |
+
)
|
| 2971 |
+
})()}
|
| 2972 |
|
| 2973 |
{/* Flagged / missing fields warning */}
|
| 2974 |
{(flaggedFields.length > 0 || missingFields.length > 0) && isResearchView && (
|
|
@@ -94,7 +94,7 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
|
|
| 94 |
.map((s) => s.composite_benchmark_name)
|
| 95 |
.filter((s): s is string => typeof s === "string" && s.length > 0)
|
| 96 |
|
| 97 |
-
const
|
| 98 |
const seen = new Set<string>()
|
| 99 |
const labels: string[] = []
|
| 100 |
const add = (raw: string | undefined | null) => {
|
|
@@ -106,8 +106,8 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
|
|
| 106 |
seen.add(key)
|
| 107 |
labels.push(trimmed)
|
| 108 |
}
|
| 109 |
-
for (const
|
| 110 |
-
add(
|
| 111 |
}
|
| 112 |
for (const metric of summary.leaderboard_metrics ?? []) {
|
| 113 |
if (metric.scope === "subtask") {
|
|
@@ -119,14 +119,14 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
|
|
| 119 |
}, [summary.subtasks, summary.leaderboard_metrics, aggregateNames])
|
| 120 |
|
| 121 |
const isMatrix = (summary.leaderboard_metrics?.length ?? 0) > 1
|
| 122 |
-
const isParentPage = isAggregated || (isMatrix &&
|
| 123 |
const useComponentDescription = !isParentPage
|
| 124 |
|
| 125 |
-
const parentFallback = isParentPage &&
|
| 126 |
-
? `${summary.evaluation_name} reports results across ${
|
| 127 |
-
isAggregated ? "component benchmarks" : "
|
| 128 |
}. Each is evaluated separately; the score shown is the ${
|
| 129 |
-
isAggregated ? "average" : "per-
|
| 130 |
}.`
|
| 131 |
: null
|
| 132 |
|
|
@@ -139,7 +139,7 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
|
|
| 139 |
""
|
| 140 |
|
| 141 |
const [expanded, setExpanded] = useState(false)
|
| 142 |
-
const [
|
| 143 |
const isLong = summaryText.length > SUMMARY_PREVIEW_CHARS
|
| 144 |
const visibleText = expanded || !isLong
|
| 145 |
? summaryText
|
|
@@ -148,13 +148,17 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
|
|
| 148 |
const domains = useMemo(() => {
|
| 149 |
const fromTags = summary.tags?.domains ?? []
|
| 150 |
const fromCard = cardMatchesEval ? card?.benchmark_details?.domains ?? [] : []
|
| 151 |
-
return Array.from(new Set([...fromTags, ...fromCard].map((d) => d.trim()).filter(Boolean)))
|
|
|
|
|
|
|
| 152 |
}, [summary.tags?.domains, card?.benchmark_details?.domains, cardMatchesEval])
|
| 153 |
|
| 154 |
const languages = useMemo(() => {
|
| 155 |
const fromTags = summary.tags?.languages ?? []
|
| 156 |
const fromCard = cardMatchesEval ? card?.benchmark_details?.languages ?? [] : []
|
| 157 |
-
return Array.from(new Set([...fromTags, ...fromCard].map((d) => d.trim()).filter(Boolean)))
|
|
|
|
|
|
|
| 158 |
}, [summary.tags?.languages, card?.benchmark_details?.languages, cardMatchesEval])
|
| 159 |
|
| 160 |
const license = card?.ethical_and_legal_considerations?.data_licensing
|
|
@@ -201,12 +205,22 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
|
|
| 201 |
: "Higher scores are better"
|
| 202 |
|
| 203 |
// Policy-note triple (paper §4.2.2): What it measures · Main caveat · Intended for.
|
|
|
|
|
|
|
| 204 |
const measuresText = visibleText
|
| 205 |
-
const
|
|
|
|
|
|
|
| 206 |
const audienceArr = card?.purpose_and_intended_users?.audience
|
| 207 |
-
const
|
| 208 |
? audienceArr.filter(Boolean).join("; ")
|
| 209 |
-
:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
|
| 211 |
return (
|
| 212 |
<section className="ec-card warm" style={{ padding: "20px 24px" }}>
|
|
@@ -304,41 +318,52 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
|
|
| 304 |
</dd>
|
| 305 |
</dl>
|
| 306 |
|
| 307 |
-
{isParentPage &&
|
| 308 |
-
<div
|
| 309 |
-
className="mt-4"
|
| 310 |
-
style={{ border: "1px solid var(--border-soft)", background: "var(--bg)" }}
|
| 311 |
-
>
|
| 312 |
<button
|
| 313 |
type="button"
|
| 314 |
-
onClick={() =>
|
| 315 |
-
aria-expanded={
|
| 316 |
-
className="flex
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 317 |
>
|
|
|
|
| 318 |
<span
|
| 319 |
-
className="
|
| 320 |
-
style={{ fontSize: 10, letterSpacing: "0.14em"
|
| 321 |
>
|
| 322 |
-
|
| 323 |
-
|
|
|
|
| 324 |
</span>
|
| 325 |
-
{
|
| 326 |
-
<ChevronUp className="h-
|
| 327 |
) : (
|
| 328 |
-
<ChevronDown className="h-
|
| 329 |
)}
|
| 330 |
</button>
|
| 331 |
-
{
|
| 332 |
-
<
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 338 |
{name}
|
| 339 |
-
</
|
| 340 |
))}
|
| 341 |
-
</
|
| 342 |
)}
|
| 343 |
</div>
|
| 344 |
)}
|
|
|
|
| 94 |
.map((s) => s.composite_benchmark_name)
|
| 95 |
.filter((s): s is string => typeof s === "string" && s.length > 0)
|
| 96 |
|
| 97 |
+
const splitLabels = useMemo(() => {
|
| 98 |
const seen = new Set<string>()
|
| 99 |
const labels: string[] = []
|
| 100 |
const add = (raw: string | undefined | null) => {
|
|
|
|
| 106 |
seen.add(key)
|
| 107 |
labels.push(trimmed)
|
| 108 |
}
|
| 109 |
+
for (const split of summary.subtasks ?? []) {
|
| 110 |
+
add(split.display_name || split.subtask_name)
|
| 111 |
}
|
| 112 |
for (const metric of summary.leaderboard_metrics ?? []) {
|
| 113 |
if (metric.scope === "subtask") {
|
|
|
|
| 119 |
}, [summary.subtasks, summary.leaderboard_metrics, aggregateNames])
|
| 120 |
|
| 121 |
const isMatrix = (summary.leaderboard_metrics?.length ?? 0) > 1
|
| 122 |
+
const isParentPage = isAggregated || (isMatrix && splitLabels.length > 1)
|
| 123 |
const useComponentDescription = !isParentPage
|
| 124 |
|
| 125 |
+
const parentFallback = isParentPage && splitLabels.length > 1
|
| 126 |
+
? `${summary.evaluation_name} reports results across ${splitLabels.length} ${
|
| 127 |
+
isAggregated ? "component benchmarks" : "splits"
|
| 128 |
}. Each is evaluated separately; the score shown is the ${
|
| 129 |
+
isAggregated ? "average" : "per-split result"
|
| 130 |
}.`
|
| 131 |
: null
|
| 132 |
|
|
|
|
| 139 |
""
|
| 140 |
|
| 141 |
const [expanded, setExpanded] = useState(false)
|
| 142 |
+
const [splitsOpen, setSplitsOpen] = useState(false)
|
| 143 |
const isLong = summaryText.length > SUMMARY_PREVIEW_CHARS
|
| 144 |
const visibleText = expanded || !isLong
|
| 145 |
? summaryText
|
|
|
|
| 148 |
const domains = useMemo(() => {
|
| 149 |
const fromTags = summary.tags?.domains ?? []
|
| 150 |
const fromCard = cardMatchesEval ? card?.benchmark_details?.domains ?? [] : []
|
| 151 |
+
return Array.from(new Set([...fromTags, ...fromCard].map((d) => d.trim()).filter(Boolean)))
|
| 152 |
+
.filter((d) => d.toLowerCase() !== "not specified")
|
| 153 |
+
.slice(0, 6)
|
| 154 |
}, [summary.tags?.domains, card?.benchmark_details?.domains, cardMatchesEval])
|
| 155 |
|
| 156 |
const languages = useMemo(() => {
|
| 157 |
const fromTags = summary.tags?.languages ?? []
|
| 158 |
const fromCard = cardMatchesEval ? card?.benchmark_details?.languages ?? [] : []
|
| 159 |
+
return Array.from(new Set([...fromTags, ...fromCard].map((d) => d.trim()).filter(Boolean)))
|
| 160 |
+
.filter((d) => d.toLowerCase() !== "not specified")
|
| 161 |
+
.slice(0, 4)
|
| 162 |
}, [summary.tags?.languages, card?.benchmark_details?.languages, cardMatchesEval])
|
| 163 |
|
| 164 |
const license = card?.ethical_and_legal_considerations?.data_licensing
|
|
|
|
| 205 |
: "Higher scores are better"
|
| 206 |
|
| 207 |
// Policy-note triple (paper §4.2.2): What it measures · Main caveat · Intended for.
|
| 208 |
+
// Filter the literal "Not specified" sentinel so the row collapses
|
| 209 |
+
// entirely instead of rendering a placeholder.
|
| 210 |
const measuresText = visibleText
|
| 211 |
+
const rawCaveat = card?.purpose_and_intended_users?.limitations?.trim() || ""
|
| 212 |
+
const caveatText =
|
| 213 |
+
rawCaveat && rawCaveat.toLowerCase() !== "not specified" ? rawCaveat : null
|
| 214 |
const audienceArr = card?.purpose_and_intended_users?.audience
|
| 215 |
+
const audienceJoined = Array.isArray(audienceArr)
|
| 216 |
? audienceArr.filter(Boolean).join("; ")
|
| 217 |
+
: typeof audienceArr === "string"
|
| 218 |
+
? audienceArr
|
| 219 |
+
: ""
|
| 220 |
+
const audienceText =
|
| 221 |
+
audienceJoined && audienceJoined.toLowerCase() !== "not specified"
|
| 222 |
+
? audienceJoined
|
| 223 |
+
: ""
|
| 224 |
|
| 225 |
return (
|
| 226 |
<section className="ec-card warm" style={{ padding: "20px 24px" }}>
|
|
|
|
| 318 |
</dd>
|
| 319 |
</dl>
|
| 320 |
|
| 321 |
+
{isParentPage && splitLabels.length > 1 && (
|
| 322 |
+
<div className="mt-4">
|
|
|
|
|
|
|
|
|
|
| 323 |
<button
|
| 324 |
type="button"
|
| 325 |
+
onClick={() => setSplitsOpen((v) => !v)}
|
| 326 |
+
aria-expanded={splitsOpen}
|
| 327 |
+
className="inline-flex items-center gap-1.5 cursor-pointer hover:text-[color:var(--fg)] transition-colors"
|
| 328 |
+
style={{
|
| 329 |
+
background: "transparent",
|
| 330 |
+
border: 0,
|
| 331 |
+
padding: 0,
|
| 332 |
+
color: "var(--fg-subtle)",
|
| 333 |
+
}}
|
| 334 |
>
|
| 335 |
+
<Layers className="h-3.5 w-3.5" />
|
| 336 |
<span
|
| 337 |
+
className="font-mono uppercase"
|
| 338 |
+
style={{ fontSize: 10, letterSpacing: "0.14em" }}
|
| 339 |
>
|
| 340 |
+
{isAggregated
|
| 341 |
+
? `Component benchmarks · ${splitLabels.length}`
|
| 342 |
+
: `Splits · ${splitLabels.length}`}
|
| 343 |
</span>
|
| 344 |
+
{splitsOpen ? (
|
| 345 |
+
<ChevronUp className="h-3.5 w-3.5" />
|
| 346 |
) : (
|
| 347 |
+
<ChevronDown className="h-3.5 w-3.5" />
|
| 348 |
)}
|
| 349 |
</button>
|
| 350 |
+
{splitsOpen && (
|
| 351 |
+
<div className="mt-2 flex flex-wrap gap-1.5">
|
| 352 |
+
{splitLabels.map((name) => (
|
| 353 |
+
<span
|
| 354 |
+
key={name}
|
| 355 |
+
className="ec-tag outline"
|
| 356 |
+
style={{
|
| 357 |
+
textTransform: "none",
|
| 358 |
+
fontFamily: "var(--font-mono)",
|
| 359 |
+
fontSize: 11,
|
| 360 |
+
letterSpacing: "0.02em",
|
| 361 |
+
}}
|
| 362 |
+
>
|
| 363 |
{name}
|
| 364 |
+
</span>
|
| 365 |
))}
|
| 366 |
+
</div>
|
| 367 |
)}
|
| 368 |
</div>
|
| 369 |
)}
|