Skip to content

Commit 3ad2d0c

Browse files
cquil11claude
andcommitted
fix(inference): hide run picker when the scenario has no runs on the date
Follow-up to the scenario-scoped run picker: the empty-coverage fallback in restrictRunsToScenario() fired whenever scenarioRunIds was empty, which conflated two cases — "no per-run coverage rows for the date" (old data, where falling back is right) and "coverage exists but zero runs for this scenario" (e.g. 2026-07-02 / 2026-07-04, where only single_turn sweeps ran). In the second case the picker degraded to the old leaky behavior and listed 6 / 3 single_turn runs under Agentic Traces. restrictRunsToScenario() now takes coverageKnown (runConfigs.length > 0): when coverage data is unavailable it still falls back to the changelog-scoped list, but when coverage exists and the scenario has no runs it returns null so the picker hides — matching the (empty) chart instead of offering meaningless "as of run" cutoffs. 中文:场景化运行选择器的后续修复:restrictRunsToScenario() 原先只要 scenarioRunIds 为空就触发回退,混淆了两种情况——"当天没有任何按运行 的覆盖数据行"(旧数据,回退是正确的)与"覆盖数据存在但该场景当天没有 任何运行"(如 2026-07-02 / 2026-07-04,当天只有 single_turn 运行)。 在第二种情况下选择器退化回旧的泄漏行为,在 Agentic Traces 场景下列出 6 / 3 个 single_turn 运行。现在 restrictRunsToScenario() 接收 coverageKnown(runConfigs.length > 0):覆盖数据缺失时仍回退到 changelog 范围列表;覆盖数据存在但该场景无运行时返回 null,选择器随之 隐藏——与(空的)图表保持一致,而不是提供无意义的 "as of run" 截断点。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 50bf336 commit 3ad2d0c

3 files changed

Lines changed: 52 additions & 23 deletions

File tree

packages/app/src/components/inference/InferenceContext.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -395,12 +395,21 @@ export function InferenceProvider({
395395
);
396396

397397
// The picker list: the changelog/precision-scoped runs, further restricted to
398-
// the ones that shipped data for the selected scenario. Falls back to the
399-
// changelog-scoped list when coverage data is unavailable (old dates / JSON
400-
// mode) so the selector always renders.
398+
// the ones that shipped data for the selected scenario. When the date has
399+
// coverage rows but none for this scenario (e.g. only single_turn sweeps ran
400+
// that day while viewing Agentic Traces) the picker hides (null) rather than
401+
// listing other-scenario runs; only when coverage data is unavailable
402+
// altogether (old dates / JSON snapshots) does it fall back to the
403+
// changelog-scoped list so the selector still renders.
401404
const filteredAvailableRuns = useMemo(
402-
() => restrictRunsToScenario(changelogFilteredRuns, availableRuns, scenarioRunIds),
403-
[changelogFilteredRuns, availableRuns, scenarioRunIds],
405+
() =>
406+
restrictRunsToScenario(
407+
changelogFilteredRuns,
408+
availableRuns,
409+
scenarioRunIds,
410+
runConfigs.length > 0,
411+
),
412+
[changelogFilteredRuns, availableRuns, scenarioRunIds, runConfigs],
404413
);
405414

406415
const effectiveSelectedRunId = useMemo(() => {

packages/app/src/lib/utils.test.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -550,38 +550,50 @@ describe('restrictRunsToScenario', () => {
550550
};
551551

552552
it('keeps only runs present in the scenario coverage set', () => {
553-
const result = restrictRunsToScenario(runs, runs, new Set(['10']));
553+
const result = restrictRunsToScenario(runs, runs, new Set(['10']), true);
554554
expect(Object.keys(result!)).toEqual(['10']);
555555
});
556556

557-
it('falls back to the changelog-scoped list when coverage is empty', () => {
558-
const result = restrictRunsToScenario(runs, runs, new Set());
557+
it('falls back to the changelog-scoped list when coverage data is unavailable', () => {
558+
// Old dates / JSON snapshots without per-run coverage rows: we can't say
559+
// anything about scenarios, so the picker keeps the changelog-scoped list.
560+
const result = restrictRunsToScenario(runs, runs, new Set(), false);
559561
expect(result).toBe(runs);
560562
});
561563

564+
it('hides the picker when coverage exists but the scenario has no runs that date', () => {
565+
// Repro: 2026-07-02 / 2026-07-04 had only single_turn runs; on the Agentic
566+
// Traces scenario the picker must show NO runs (null), not fall back to
567+
// listing the single_turn runs.
568+
const result = restrictRunsToScenario(runs, runs, new Set(), true);
569+
expect(result).toBeNull();
570+
});
571+
562572
it('pulls a scenario run from the raw map when the changelog list omits it', () => {
563573
// A run that shipped data without a changelog entry: filterRunsByModel drops
564574
// it, but it is still a valid scenario run the picker must show.
565575
const changelogFiltered = { '10': runs['10'] };
566576
const allRuns = runs;
567-
const result = restrictRunsToScenario(changelogFiltered, allRuns, new Set(['10', '20']));
577+
const result = restrictRunsToScenario(changelogFiltered, allRuns, new Set(['10', '20']), true);
568578
expect(Object.keys(result!).toSorted()).toEqual(['10', '20']);
569579
expect(result!['20']).toBe(runs['20']);
570580
});
571581

572582
it('prefers the changelog-scoped entry over the raw one', () => {
573583
const scoped = makeRun([['dsv4-fp4-b200-sglang']], { runId: '10', conclusion: 'scoped' });
574-
const result = restrictRunsToScenario({ '10': scoped }, runs, new Set(['10']));
584+
const result = restrictRunsToScenario({ '10': scoped }, runs, new Set(['10']), true);
575585
expect(result!['10']).toBe(scoped);
576586
});
577587

578-
it('falls back to the changelog list when no scenario run survives', () => {
579-
const result = restrictRunsToScenario(runs, runs, new Set(['999']));
580-
expect(result).toBe(runs);
588+
it('returns null when no scenario run survives the restriction', () => {
589+
// Scenario runs exist in coverage but none resolve to a listable RunInfo
590+
// (e.g. still in progress, so absent from the workflow-runs map).
591+
const result = restrictRunsToScenario(runs, runs, new Set(['999']), true);
592+
expect(result).toBeNull();
581593
});
582594

583-
it('returns null changelog list unchanged', () => {
584-
expect(restrictRunsToScenario(null, null, new Set(['10']))).toBeNull();
595+
it('returns null changelog list unchanged when coverage is unavailable', () => {
596+
expect(restrictRunsToScenario(null, null, new Set(), false)).toBeNull();
585597
});
586598
});
587599

packages/app/src/lib/utils.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -300,25 +300,33 @@ export function filterRunsByModel(
300300
* entry, so `filterRunsByModel` may omit it while it is still a legitimate
301301
* scenario run the user must be able to select.
302302
*
303-
* Fallbacks that keep the selector rendering:
304-
* - `scenarioRunIds` empty → no coverage data (dates predating per-run
305-
* coverage, or JSON/fixtures mode): return the changelog-scoped list
306-
* unchanged rather than blanking the picker.
307-
* - Non-empty coverage but zero surviving runs (shouldn't happen in practice)
308-
* → also fall back to the changelog-scoped list.
303+
* `coverageKnown` says whether per-(run, config) coverage rows exist for the
304+
* date at all (`runConfigs.length > 0`). It distinguishes two very different
305+
* "empty `scenarioRunIds`" cases:
306+
* - `coverageKnown === false` → no coverage data (dates predating per-run
307+
* coverage, or JSON/fixtures snapshots without it): we can't say anything
308+
* about scenarios, so return the changelog-scoped list unchanged rather
309+
* than blanking the picker.
310+
* - `coverageKnown === true` and no scenario run survives → the date has
311+
* benchmark data but NONE for this scenario (e.g. only single_turn sweeps
312+
* ran that day while the user views Agentic Traces). Return null so the
313+
* picker hides instead of listing other-scenario runs — showing them is
314+
* exactly the leak this helper exists to prevent, and selecting one would
315+
* constrain an already-empty chart to a meaningless "as of run" cutoff.
309316
*/
310317
export function restrictRunsToScenario(
311318
changelogFiltered: Record<string, RunInfo> | null,
312319
allRuns: Record<string, RunInfo> | null,
313320
scenarioRunIds: Set<string>,
321+
coverageKnown: boolean,
314322
): Record<string, RunInfo> | null {
315-
if (scenarioRunIds.size === 0) return changelogFiltered;
323+
if (!coverageKnown) return changelogFiltered;
316324
const restricted: Record<string, RunInfo> = {};
317325
for (const runId of scenarioRunIds) {
318326
const info = changelogFiltered?.[runId] ?? allRuns?.[runId];
319327
if (info) restricted[runId] = info;
320328
}
321-
return Object.keys(restricted).length > 0 ? restricted : changelogFiltered;
329+
return Object.keys(restricted).length > 0 ? restricted : null;
322330
}
323331

324332
/**

0 commit comments

Comments
 (0)