general-eval-card / tests /transformations /slug-candidates.test.ts
Jenny Chim
Deploy DuckDB-backed frontend to
da8db3e
Raw
History Blame
7.72 kB
import { describe, expect, it } from "vitest"
// Executable spec for `notes/transformations/05-slug-candidates.md`.
//
// Replicates pipelineSlugify, getModelDetailSlugCandidates, and
// getDeveloperSlugCandidates from lib/model-data.ts:150-211 verbatim.
// Pipeline must produce identical outputs for every case below.
function pipelineSlugify(text: string): string {
return (
text
.replace(/[\x00-\x1f\x7f]/g, "")
.replace(/[^a-zA-Z0-9._-]/g, "_")
.replace(/^_+|_+$/g, "") || "unknown"
)
}
function getModelDetailSlugCandidates(modelId: string): string[] {
const normalized = modelId.trim()
const candidates = new Set<string>()
const withSlash = normalized.replace(/\//g, "__")
const withDots = withSlash.replace(/\./g, "-")
candidates.add(pipelineSlugify(withSlash))
candidates.add(pipelineSlugify(withSlash.toLowerCase()))
candidates.add(pipelineSlugify(withDots))
candidates.add(pipelineSlugify(withDots.toLowerCase()))
candidates.add(pipelineSlugify(normalized))
candidates.add(pipelineSlugify(normalized.toLowerCase()))
return Array.from(candidates)
}
function getDeveloperSlugCandidates(developerOrRouteId: string): string[] {
const normalized = developerOrRouteId.trim()
const candidates = new Set<string>()
const lowercase = normalized.toLowerCase()
const underscoreSlug = pipelineSlugify(normalized)
const lowercaseUnderscoreSlug = pipelineSlugify(lowercase)
const hyphenSlug = lowercase
.replace(/[\x00-\x1f\x7f]/g, "")
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "")
const compactSlug = lowercase.replace(/[^a-z0-9]+/g, "")
candidates.add(underscoreSlug)
candidates.add(lowercaseUnderscoreSlug)
candidates.add(underscoreSlug.replace(/_/g, "-"))
candidates.add(lowercaseUnderscoreSlug.replace(/_/g, "-"))
if (hyphenSlug) candidates.add(hyphenSlug)
if (compactSlug) candidates.add(compactSlug)
return Array.from(candidates)
}
// ---------------------------------------------------------------------------
// Group A β€” pipelineSlugify
// ---------------------------------------------------------------------------
describe("Group A β€” pipelineSlugify", () => {
const cases = [
{ input: "openai__gpt-5", expected: "openai__gpt-5", why: "passthrough (alnum + dash + underscore)" },
{ input: "openai__gpt-5.2", expected: "openai__gpt-5.2", why: "passthrough (dot allowed)" },
{ input: "openai/gpt-5", expected: "openai_gpt-5", why: "slash β†’ underscore (slash not in allowed set)" },
{ input: "OpenAI", expected: "OpenAI", why: "case preserved" },
{ input: "x0000001", expected: "x0000001", why: "passthrough" },
{ input: "foo bar", expected: "foo_bar", why: "space β†’ underscore" },
{ input: "foo!@#bar", expected: "foo___bar", why: "each special char β†’ underscore" },
{ input: "___foo___", expected: "foo", why: "trim leading/trailing underscores" },
{ input: "!!!", expected: "unknown", why: "empty after trim β†’ 'unknown' fallback" },
{ input: "", expected: "unknown", why: "empty β†’ 'unknown' fallback" },
{ input: "_", expected: "unknown", why: "single underscore trimmed β†’ empty β†’ 'unknown'" },
{ input: "a.b.c", expected: "a.b.c", why: "dots passthrough" },
{ input: "a-b-c", expected: "a-b-c", why: "dashes passthrough" },
]
it.each(cases)("'$input' β†’ '$expected' ($why)", ({ input, expected }) => {
expect(pipelineSlugify(input)).toBe(expected)
})
})
// ---------------------------------------------------------------------------
// Group B β€” getModelDetailSlugCandidates
// ---------------------------------------------------------------------------
describe("Group B β€” getModelDetailSlugCandidates", () => {
const cases = [
{
input: "openai/gpt-5",
expected: ["openai__gpt-5", "openai_gpt-5"],
why: "lowercase + no dots β†’ only slash + slash-stripped variants survive Set dedup",
},
{
input: "openai/gpt-5.2",
expected: ["openai__gpt-5.2", "openai__gpt-5-2", "openai_gpt-5.2"],
why: "dotted form β†’ slash, slash+dot-stripped, fallback",
},
{
input: "OpenAI/GPT-5",
expected: ["OpenAI__GPT-5", "openai__gpt-5", "OpenAI_GPT-5", "openai_gpt-5"],
why: "mixed case β†’ both case variants survive",
},
{
input: "anthropic/claude-3.7-sonnet",
expected: ["anthropic__claude-3.7-sonnet", "anthropic__claude-3-7-sonnet", "anthropic_claude-3.7-sonnet"],
why: "dotted version variant",
},
{
input: "unknown/foo",
expected: ["unknown__foo", "unknown_foo"],
why: "lowercase + no dots β†’ 2 candidates",
},
{
input: "openai__gpt-5",
expected: ["openai__gpt-5"],
why: "no slashes, no dots, lowercase β†’ all variants collapse to one",
},
]
it.each(cases)("'$input' β†’ $expected ($why)", ({ input, expected }) => {
expect(getModelDetailSlugCandidates(input)).toEqual(expected)
})
})
// ---------------------------------------------------------------------------
// Group C β€” getDeveloperSlugCandidates
// ---------------------------------------------------------------------------
describe("Group C β€” getDeveloperSlugCandidates", () => {
const cases = [
{
input: "openai",
expected: ["openai"],
why: "lowercase + no special chars β†’ all 6 variants collapse to one",
},
{
input: "OpenAI",
expected: ["OpenAI", "openai"],
why: "case-mixed β†’ 2 candidates (the case variant differs)",
},
{
input: "01-ai",
expected: ["01-ai", "01ai"],
why: "compactSlug strips the dash β†’ 2 candidates",
},
{
input: "Mistral AI",
expected: ["Mistral_AI", "mistral_ai", "Mistral-AI", "mistral-ai", "mistralai"],
why: "space β†’ underscore variants + hyphen variants + compact",
},
{
input: "01_ai",
expected: ["01_ai", "01-ai", "01ai"],
why: "underscore-slug + dash variant + compact",
},
{
input: "Allenai",
expected: ["Allenai", "allenai"],
why: "case-mixed but no special chars",
},
]
it.each(cases)("'$input' β†’ $expected ($why)", ({ input, expected }) => {
expect(getDeveloperSlugCandidates(input)).toEqual(expected)
})
})
// ---------------------------------------------------------------------------
// Group D β€” Production sanity (fixture-based)
// ---------------------------------------------------------------------------
//
// Concrete production cases from the audit (2026-04-28). For each, document
// which candidate position resolves to the actual file. These are the cases
// the pipeline-side fix needs to make redundant.
describe("Group D β€” production sanity (which candidate position wins)", () => {
it("openai/gpt-5.2 needs the dot→dash variant (position 1)", () => {
const candidates = getModelDetailSlugCandidates("openai/gpt-5.2")
expect(candidates[0]).toBe("openai__gpt-5.2") // would be the file IF cache used dotted form (it doesn't)
expect(candidates[1]).toBe("openai__gpt-5-2") // this is what actually exists in cache
})
it("anthropic/claude-3.7-sonnet needs the dot→dash variant (position 1)", () => {
const candidates = getModelDetailSlugCandidates("anthropic/claude-3.7-sonnet")
expect(candidates).toContain("anthropic__claude-3-7-sonnet")
})
it("OpenAI developer needs lowercase variant (position 1)", () => {
const candidates = getDeveloperSlugCandidates("Google")
expect(candidates).toEqual(["Google", "google"])
})
it("Allenai developer needs lowercase variant (position 1)", () => {
const candidates = getDeveloperSlugCandidates("Allenai")
expect(candidates).toEqual(["Allenai", "allenai"])
})
})