diff --git a/packages/app/src/components/GlobalFilterContext.tsx b/packages/app/src/components/GlobalFilterContext.tsx index 2780a20..f605e1d 100644 --- a/packages/app/src/components/GlobalFilterContext.tsx +++ b/packages/app/src/components/GlobalFilterContext.tsx @@ -172,6 +172,38 @@ export function GlobalFilterProvider({ children }: { children: ReactNode }) { }); }, [availabilityRows, unofficialAvailable]); + // Auto-switch the selected model when an unofficial run is loaded that + // doesn't include the currently selected model. Without this, navigating + // to `?unofficialrun=` while the default `g_model=DeepSeek-R1` sticks + // leaves the user staring at a chart with no overlay points — they'd have + // to know to open the dropdown and pick the run's model themselves. + // + // Skipped when `g_model` was set explicitly in the URL (respect the user's + // intent) and when the current model is already covered by the overlay. + // + // We key the "did we already switch?" check against the stringified set of + // (model, sequence) pairs from the unofficial run, so navigating from one + // run to another with a different model will re-trigger the switch — but + // a manual model change while the same run set is loaded will stick. + const lastAutoSwitchKeyRef = useRef(''); + useEffect(() => { + if (unofficialAvailable.length === 0) { + lastAutoSwitchKeyRef.current = ''; + return; + } + const urlModel = getUrlParam('g_model'); + if (urlModel) return; + const key = unofficialAvailable + .map((a) => `${a.model}|${a.sequence}`) + .toSorted() + .join(','); + if (lastAutoSwitchKeyRef.current === key) return; + lastAutoSwitchKeyRef.current = key; + const unofficialModels = new Set(unofficialAvailable.map((a) => a.model)); + if (unofficialModels.has(selectedModel)) return; + setSelectedModel(unofficialAvailable[0].model); + }, [unofficialAvailable, selectedModel]); + // Sequences available for the selected model (DB ∪ unofficial run for this model) const availableSequences = useMemo(() => { const unofficialSeqs = unofficialAvailable diff --git a/packages/db/src/etl/normalizers.test.ts b/packages/db/src/etl/normalizers.test.ts index 5544e0e..e424e5b 100644 --- a/packages/db/src/etl/normalizers.test.ts +++ b/packages/db/src/etl/normalizers.test.ts @@ -73,6 +73,10 @@ describe('hwToGpuKey', () => { expect(hwToGpuKey('B200-DSV4')).toBe('b200'); }); + it('strips -cw suffix', () => { + expect(hwToGpuKey('gb300-cw')).toBe('gb300'); + }); + it('strips runner index suffix before other suffixes', () => { expect(hwToGpuKey('mi355x-amd_0')).toBe('mi355x'); expect(hwToGpuKey('mi355x-amd_2')).toBe('mi355x'); diff --git a/packages/db/src/etl/normalizers.ts b/packages/db/src/etl/normalizers.ts index 6f759b4..32c43f6 100644 --- a/packages/db/src/etl/normalizers.ts +++ b/packages/db/src/etl/normalizers.ts @@ -35,7 +35,8 @@ export function hwToGpuKey(hw: string): string | null { .replace(/-dgxc$/, '') .replace(/-nb$/, '') .replace(/-dsv4$/, '') - .replace(/-nv$/, ''); + .replace(/-nv$/, '') + .replace(/-cw$/, ''); return GPU_KEYS.has(base) ? base : null; }