fix(intelligence): synthesize base-model arena rows from effort/harness variants; drop MODEL_ALIAS_MAP (#11504) (#11506)

Validated in a combined 4-PR batch worktree off release/v3.8.51 tip (stacked on #11492, merged first).
- TDD-first: the new base-model-synthesis describe block failed 5/5 pre-fix, passes now
- Focused test: tests/unit/arena-elo-sync.test.ts — 56/56 pass, part of batch's 246/246 node:test + 126/126 vitest runs
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity, check:cycles — all OK

Thanks for closing the arena-lookup gap for harness/effort-annotated leaderboard rows and retiring MODEL_ALIAS_MAP's cross-generation score copying in favor of scoresAs + registry-owned aliases.
This commit is contained in:
MumuTW
2026-08-26 00:51:56 +08:00
committed by GitHub
parent 78d10da84c
commit a15af27c78
3 changed files with 209 additions and 40 deletions

View File

@@ -10,6 +10,8 @@
* On by default; opt out via Dashboard Feature Flags or ARENA_ELO_SYNC_ENABLED=false.
*/
import { resolveScoresAs } from "@omniroute/open-sse/services/autoCombo/scoresAs.ts";
import { isArenaEloSyncEnabled } from "@/shared/utils/featureFlags";
import { backupDbFile } from "./db/backup";
@@ -139,22 +141,6 @@ const VENDOR_PREFIXES = [
"ai21/",
] as const;
/**
* OmniRoute model aliases: canonical name → known aliases.
* Creates additional DB entries for each alias so that models
* are findable under any name OmniRoute uses internally.
*/
const MODEL_ALIAS_MAP: Record<string, string[]> = {
"claude-opus-4-6-thinking": ["claude-opus-4", "anthropic/claude-opus-4"],
"claude-sonnet-4-5": ["claude-sonnet-4.5", "anthropic/claude-sonnet-4.5"],
"gpt-5.5": ["openai/gpt-5.5", "gpt-5"],
"gemini-3-flash": ["google/gemini-3-flash", "gemini-flash"],
"deepseek-r1": ["deepseek/deepseek-r1", "if/deepseek-r1"],
"kimi-k2-thinking": ["moonshot/kimi-k2"],
"qwen3-coder-plus": ["alibaba/qwen3-coder"],
"llama-4": ["meta/llama-4", "llama4"],
};
/** Votes threshold for "high" confidence. */
const HIGH_CONFIDENCE_VOTES = 5000;
@@ -196,17 +182,25 @@ function getEffectiveArenaEloSyncEnabled(): boolean {
// ─── Model name normalization ────────────────────────────
/**
* Trailing harness annotation the Arena leaderboard appends to some entries,
* e.g. "gpt-5.6-sol-xhigh (codex-harness)". It describes the scaffold the model
* was measured under, not the model id, so it never belongs in a stored key.
*/
const HARNESS_ANNOTATION_RE = /\s*\([^)]*\)\s*$/;
/**
* Normalize a model name from the Arena leaderboard.
*
* Lowercases the name and strips known vendor prefixes
* (e.g. "anthropic/claude-opus-4" → "claude-opus-4").
* Lowercases the name, drops a trailing harness annotation
* ("gpt-5.6-sol-xhigh (codex-harness)" → "gpt-5.6-sol-xhigh") and strips known
* vendor prefixes ("anthropic/claude-opus-4" → "claude-opus-4").
*
* @param rawName - The raw model name from the API response.
* @returns The cleaned, lowercase model name.
*/
export function normalizeModelName(rawName: string): string {
let name = rawName.toLowerCase();
let name = rawName.toLowerCase().replace(HARNESS_ANNOTATION_RE, "");
for (const prefix of VENDOR_PREFIXES) {
if (name.startsWith(prefix)) {
name = name.slice(prefix.length);
@@ -295,7 +289,14 @@ function computeConfidence(votes: number): "high" | "medium" | "low" {
* - "text" → default, review, documentation, debugging
* - "code" → coding
*
* Known OmniRoute model aliases are also expanded into additional entries.
* The leaderboard scores harness × effort combinations as separate entries
* ("claude-opus-5-high", "claude-opus-5-max"), so a request for the bare id
* would miss every row. Each variant that `resolveScoresAs()` resolves to a
* routable base id therefore also contributes a synthesized base row carrying
* the BEST task fit among that base's variants (the per-effort entries measure
* the same weights at different budgets — the model's ceiling is the max, and
* cost/latency are separate factors in the 12-factor score). An explicitly
* measured base row is never lowered by synthesis.
*
* @param data - Map of leaderboard category → Arena leaderboard data.
* @returns Array of model intelligence entries ready for DB upsert.
@@ -325,7 +326,7 @@ export function transformToModelIntelligence(
const taskFit = 0.4 + 0.58 * ((model.score - minElo) / eloRange);
for (const taskCategory of taskCategories) {
const entry: Omit<ModelIntelligenceEntry, "syncedAt"> = {
entries.push({
model: normalizedModel,
category: taskCategory,
source: "arena_elo",
@@ -333,24 +334,63 @@ export function transformToModelIntelligence(
eloRaw: model.score,
confidence,
expiresAt,
};
entries.push(entry);
// Expand known aliases
const aliases = MODEL_ALIAS_MAP[normalizedModel];
if (aliases) {
for (const alias of aliases) {
entries.push({
...entry,
model: alias,
});
}
}
});
}
}
}
return entries;
return withSynthesizedBaseRows(entries);
}
/**
* Add one synthesized base row per (base, category) for every leaderboard entry
* that is an effort/alias variant of a routable catalog id.
*
* Runs as a pass over the finished variant rows so that all variants of a base
* are visible at once: the winner is the highest task fit, and it contributes
* its own `eloRaw` and `confidence` (no invented confidence label — the column's
* vocabulary stays high/medium/low). A base that the leaderboard measured
* directly keeps its own row unless a variant scored strictly higher.
*
* Resolution never guesses: `resolveScoresAs` returning `via: null` means the
* stripped base is not a catalog id, so nothing is synthesized for it.
*
* @param entries - Variant rows, one per (leaderboard entry, task category).
* @returns The same rows plus the synthesized base rows.
*/
function withSynthesizedBaseRows(
entries: Array<Omit<ModelIntelligenceEntry, "syncedAt">>
): Array<Omit<ModelIntelligenceEntry, "syncedAt">> {
const keyOf = (model: string, category: string) => `${model}|${category}`;
const indexByKey = new Map<string, number>();
entries.forEach((entry, index) => indexByKey.set(keyOf(entry.model, entry.category), index));
const best = new Map<string, Omit<ModelIntelligenceEntry, "syncedAt">>();
for (const entry of entries) {
const { base, via } = resolveScoresAs(entry.model);
if (via === null || base === entry.model) continue;
const key = keyOf(base, entry.category);
const current = best.get(key);
if (!current || entry.score > current.score) {
best.set(key, { ...entry, model: base });
}
}
const result = [...entries];
for (const [key, candidate] of best) {
const existingIndex = indexByKey.get(key);
if (existingIndex === undefined) {
result.push(candidate);
continue;
}
// The leaderboard measured the base itself — only a strictly better variant wins.
if (candidate.score > result[existingIndex].score) {
result[existingIndex] = candidate;
}
}
return result;
}
// ─── Main sync function ──────────────────────────────────