From bd95a3746eadd54b49b717b4518cb8e35ee918e4 Mon Sep 17 00:00:00 2001 From: Jim-jimu <49069997+bmh201708@users.noreply.github.com> Date: Tue, 6 Oct 2026 15:59:08 +0800 Subject: [PATCH] fix(benchmark): preserve scoped run identities through study readback Signed-off-by: Jim-jimu <49069997+bmh201708@users.noreply.github.com> --- .../smoke/benchmark-study-contract-smoke.ts | 10 ++ .../dashboard/src/data/benchmark-study.ts | 9 ++ apps/presentation/dashboard/src/router.tsx | 1 + .../src/views/benchmark-study-page.tsx | 21 +-- .../benchmark-study/run-identity-after.png | Bin 0 -> 140237 bytes .../run-identity-ambiguous.png | Bin 0 -> 107533 bytes .../benchmark-study/run-identity-before.png | Bin 0 -> 159331 bytes ...ashboard-benchmark-study-browser-smoke.mjs | 54 +++++++- .../capabilities/benchmark_toolkit/README.md | 5 + .../benchmark_toolkit/experiment_board.py | 23 ++-- .../benchmark_toolkit/experiment_identity.py | 18 ++- .../benchmark_toolkit/study_projection.py | 25 ++-- .../test_benchmark_experiment_board.py | 56 ++++++++ .../test_benchmark_study_projection.py | 127 ++++++++++++++++++ 14 files changed, 313 insertions(+), 36 deletions(-) create mode 100644 docs/assets/benchmark-study/run-identity-after.png create mode 100644 docs/assets/benchmark-study/run-identity-ambiguous.png create mode 100644 docs/assets/benchmark-study/run-identity-before.png diff --git a/apps/presentation/dashboard/smoke/benchmark-study-contract-smoke.ts b/apps/presentation/dashboard/smoke/benchmark-study-contract-smoke.ts index d33197f68a..b34dd59e3f 100644 --- a/apps/presentation/dashboard/smoke/benchmark-study-contract-smoke.ts +++ b/apps/presentation/dashboard/smoke/benchmark-study-contract-smoke.ts @@ -2,9 +2,19 @@ import fixture from "../public/benchmark-study.example.json" with { type: "json" import { parseBenchmarkStudyDashboard, resolveBenchmarkStudyDashboardUrl, + selectBenchmarkStudyRun, } from "../src/data/benchmark-study.js"; const packet = parseBenchmarkStudyDashboard(fixture); +const first = packet.runs[0]!; +const second = { ...first, case_id: "another-case" }; +if (selectBenchmarkStudyRun([first, second], first.run_id, second.case_id) !== second) throw new Error("run selection lost its case"); +if (selectBenchmarkStudyRun([first, second], first.run_id, "") !== undefined) throw new Error("ambiguous legacy link selected a run"); +if (selectBenchmarkStudyRun([first], first.run_id, "") !== first) throw new Error("unique legacy link stopped resolving"); +if (selectBenchmarkStudyRun([first], first.run_id, "missing-case") !== undefined) throw new Error("stale case link selected another case"); +if (selectBenchmarkStudyRun([first], "missing-run", "") !== undefined) throw new Error("stale run link selected another run"); +if (selectBenchmarkStudyRun([first, first], first.run_id, first.case_id) !== undefined) throw new Error("duplicate full identity selected a run"); +if (selectBenchmarkStudyRun([first], "", "") !== first) throw new Error("unselected runs view lost its default"); if (packet.status !== "provisional") throw new Error("fixture must expose provisional coverage"); if (packet.campaign.intended_cell_denominator !== 8) throw new Error("campaign denominator drifted"); if (packet.campaign.selected_score_countable_cell_count !== 6) throw new Error("countable numerator drifted"); diff --git a/apps/presentation/dashboard/src/data/benchmark-study.ts b/apps/presentation/dashboard/src/data/benchmark-study.ts index b81f388393..ffda1dc700 100644 --- a/apps/presentation/dashboard/src/data/benchmark-study.ts +++ b/apps/presentation/dashboard/src/data/benchmark-study.ts @@ -196,6 +196,15 @@ export type BenchmarkStudyCase = BenchmarkStudyDashboard["cases"][number]; export type BenchmarkStudyRun = BenchmarkStudyDashboard["runs"][number]; export type BenchmarkStudyView = "campaign" | "arms" | "cases" | "runs"; +export function selectBenchmarkStudyRun( + runs: BenchmarkStudyRun[], runId: string, caseId: string, +): BenchmarkStudyRun | undefined { + if (!runId && !caseId) return runs[0]; + const matches = runs.filter((run) => run.run_id === runId && (!caseId || run.case_id === caseId)); + // Legacy runId-only bookmarks are safe only when they identify exactly one run. + return matches.length === 1 ? matches[0] : undefined; +} + export function parseBenchmarkStudyDashboard(value: unknown): BenchmarkStudyDashboard { return benchmarkStudyDashboardSchema.parse(value); } diff --git a/apps/presentation/dashboard/src/router.tsx b/apps/presentation/dashboard/src/router.tsx index cf1101ee4e..f6730d4eb7 100644 --- a/apps/presentation/dashboard/src/router.tsx +++ b/apps/presentation/dashboard/src/router.tsx @@ -38,6 +38,7 @@ const benchmarkStudySearchSchema = z.object({ dashboardUrl: z.string().optional().default(""), view: z.enum(["campaign", "arms", "cases", "runs"]).optional().default("campaign"), runId: z.string().optional().default(""), + caseId: z.string().optional().default(""), }); // Bookmarks remain valid, but the retired boards no longer ship a second UI. diff --git a/apps/presentation/dashboard/src/views/benchmark-study-page.tsx b/apps/presentation/dashboard/src/views/benchmark-study-page.tsx index 9017f0f0c2..a4928bee29 100644 --- a/apps/presentation/dashboard/src/views/benchmark-study-page.tsx +++ b/apps/presentation/dashboard/src/views/benchmark-study-page.tsx @@ -13,6 +13,7 @@ import { benchmarkStudyRoute } from "../router"; import { parseBenchmarkStudyDashboard, resolveBenchmarkStudyDashboardUrl, + selectBenchmarkStudyRun, type BenchmarkStudyArm, type BenchmarkStudyCase, type BenchmarkStudyDashboard, @@ -190,7 +191,7 @@ function ArmsView({ packet }: { packet: BenchmarkStudyDashboard }) { ); } -function CasesView({ packet, primaryMetric, onOpenRun }: { packet: BenchmarkStudyDashboard; primaryMetric: string; onOpenRun: (runId: string) => void }) { +function CasesView({ packet, primaryMetric, onOpenRun }: { packet: BenchmarkStudyDashboard; primaryMetric: string; onOpenRun: (runId: string, caseId: string) => void }) { return (
| {cell.selected_run_id && cell.score_countable ? ( - |