import clsx from "clsx";
import { FlaskConical } from "lucide-react";
import { fmt } from "@/lib/data";
import type { ModelRow, Provenance, SplitInfo, SplitMetrics } from "@/lib/types";
import SectionLabel from "./SectionLabel";
export interface GeneralizationStripProps {
model: ModelRow;
hardInfo: SplitInfo;
}
function hasNumbers(m?: SplitMetrics): boolean {
return !!m && Object.values(m).some((v) => typeof v === "number");
}
function DeltaTile({
label,
test,
hard,
}: {
label: string;
test?: number;
hard?: number;
}) {
const d =
typeof test === "number" && typeof hard === "number" ? hard - test : null;
const degrading = d !== null && d > 0;
return (
Δ {label}
{d === null ? "—" : `${d >= 0 ? "+" : "−"}${Math.abs(d).toFixed(2)}`}
{fmt(test)} → {fmt(hard)}
);
}
function GhostTile({ label }: { label: string }) {
return (
Δ {label}
—
test → hard
);
}
function gapCopy(provenance: Provenance): string {
if (provenance === "running")
return "This model’s pilot run is executing on Test + Hard right now — the delta lands here the moment it commits.";
if (provenance === "planned")
return "A platform run covering Test + Hard is on the roadmap for this model.";
return "Published results cover Test only; the platform pilot re-runs every model on Test + Hard, and this gap closes when its run lands.";
}
/**
* Test → Hard generalization: signed delta tiles when both splits are
* measured (amber when degrading), otherwise a dashed evidence-gap callout
* with ghost tiles showing the shape of what will appear.
*/
export default function GeneralizationStrip({
model,
hardInfo,
}: GeneralizationStripProps) {
const test = model.metrics?.test;
const hard = model.metrics?.hard;
const measured = hasNumbers(test) && hasNumbers(hard);
return (
{measured ? (
The Hard split holds{" "}
{fmt(hardInfo.hours)}
{" "}h of rare and
unseen code-switched terms. A positive Δ (amber) means the model
degrades off the common-term distribution.
) : (
Evidence gap — no Hard-split measurement yet
The Hard split holds{" "}
{fmt(hardInfo.hours)}
{" "}h /{" "}
{hardInfo.utts.toLocaleString("en-US")}
{" "}
utterances of rare and unseen code-switched terms — the
generalization leaderboard. {gapCopy(model.provenance)}
)}
);
}