diff --git a/app/renderer/sections/Compare.test.tsx b/app/renderer/sections/Compare.test.tsx
index c547099f..edfa6641 100644
--- a/app/renderer/sections/Compare.test.tsx
+++ b/app/renderer/sections/Compare.test.tsx
@@ -3,6 +3,7 @@ import { render, screen, waitFor, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { __resetPolledMemo } from '../hooks/usePolled'
import type { CohortComparisonReport, CompareJsonReport, ModelStats } from '../lib/types'
import { Compare } from './Compare'
@@ -162,6 +163,21 @@ describe('Compare', () => {
expect(mocks.getCompareModels).toHaveBeenCalledWith('30days', 'all')
})
+ it('never requests the previous pair against a period whose models do not include it', async () => {
+ __resetPolledMemo()
+ const haiku = { ...modelA, model: 'Haiku 5' }
+ const gpt = { ...modelB, model: 'GPT-6' }
+ mocks.getCompareModels.mockImplementation(async period => period === 'today' ? [haiku, gpt] : [modelA, modelB])
+ mocks.getCompare.mockResolvedValue(report)
+ const { rerender } = render()
+ await waitFor(() => expect(mocks.getCompare).toHaveBeenCalledWith('30days', 'all', 'Opus 4.8', 'Sonnet 5'))
+
+ rerender()
+ await waitFor(() => expect(mocks.getCompare).toHaveBeenCalledWith('today', 'all', 'Haiku 5', 'GPT-6'))
+ const stale = mocks.getCompare.mock.calls.filter(([period, , a, b]) => period === 'today' && (a === 'Opus 4.8' || b === 'Sonnet 5'))
+ expect(stale).toEqual([])
+ })
+
it('renders the need-two-models note without requesting a report', async () => {
mocks.getCompareModels.mockResolvedValue([modelA])
render()
@@ -334,6 +350,23 @@ describe('Compare cohorts mode', () => {
})
})
+ it('never requests the previous pair against a period whose models do not include it', async () => {
+ __resetPolledMemo()
+ const haiku = { ...modelA, model: 'Haiku 5' }
+ const gpt = { ...modelB, model: 'GPT-6' }
+ mocks.getCompareCohortModels.mockImplementation(async period =>
+ period === 'today' ? { ...facets, models: [haiku, gpt] } : facets)
+ const user = userEvent.setup()
+ const { rerender } = render()
+ await user.click(await screen.findByRole('tab', { name: 'Cohorts' }))
+ await waitFor(() => expect(mocks.getCompareCohort).toHaveBeenCalledWith('30days', 'all', 'Opus 4.8', 'Sonnet 5', undefined, undefined, undefined))
+
+ rerender()
+ await waitFor(() => expect(mocks.getCompareCohort).toHaveBeenCalledWith('today', 'all', 'Haiku 5', 'GPT-6', undefined, undefined, undefined))
+ const stale = mocks.getCompareCohort.mock.calls.filter(([period, , a, b]) => period === 'today' && (a === 'Opus 4.8' || b === 'Sonnet 5'))
+ expect(stale).toEqual([])
+ })
+
it('returns to the classic comparison unchanged', async () => {
const user = await openCohorts()
mocks.getCompareModels.mockResolvedValue([modelA, modelB])
diff --git a/app/renderer/sections/Compare.tsx b/app/renderer/sections/Compare.tsx
index 22b6e9bb..28d41475 100644
--- a/app/renderer/sections/Compare.tsx
+++ b/app/renderer/sections/Compare.tsx
@@ -194,7 +194,7 @@ function ClassicCompare({
}}
/>
- {modelA && modelB && modelA !== modelB && (
+ {modelA && modelB && modelA !== modelB && modelRows.some(row => row.model === modelA) && modelRows.some(row => row.model === modelB) && (
!!model && !!facets.data?.models.some(row => row.model === model)
const report = usePolled(
() => codeburn.getCompareCohort(period, provider, modelA ?? '', modelB ?? '', range ?? undefined, project ? [project] : undefined, category || undefined),
[period, provider, modelA, modelB, range?.from, range?.to, project, category, refreshToken],
{
- enabled: ready && !!modelA && !!modelB && modelA !== modelB,
+ enabled: ready && listed(modelA) && listed(modelB) && modelA !== modelB,
memoKey: reportMemoKey('cohort-v2', period, provider, range, JSON.stringify([modelA, modelB, project, category])),
},
)