From 95aae7b95f16509fdc99416a97e520c5db02f454 Mon Sep 17 00:00:00 2001 From: stroblme Date: Wed, 26 Aug 2026 13:18:16 +0200 Subject: [PATCH] Show what differs between the runs being compared --- frontend/src/components/Runs/RunsScreen.tsx | 97 +++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/frontend/src/components/Runs/RunsScreen.tsx b/frontend/src/components/Runs/RunsScreen.tsx index dd17cc0..5156c89 100644 --- a/frontend/src/components/Runs/RunsScreen.tsx +++ b/frontend/src/components/Runs/RunsScreen.tsx @@ -205,6 +205,13 @@ export function RunsScreen({ flow={runs.find((run) => run.id === selected[0])?.flow} /> )} + + {/* Below the chart, and only once there are two runs to hold apart. + The table above keeps its height and the page scrolls instead: + what differs is worth reading in full. */} + {selected.length > 1 && ( + selected.includes(run.id))} /> + )} ) @@ -546,3 +553,93 @@ function Compare({ ) } + +/** + * What actually differs between the runs being compared. + * + * Only the parameters that vary. Everything they share is by definition not + * why their curves came out differently, and a sweep shares almost everything + * — so listing it in full would bury the two knobs that were turned. + * + * Runs are the rows, as they are in the table above: a comparison of fifty + * grows downwards, where there is somewhere to grow. + */ +function ParamDiff({ rows }: { rows: RunRow[] }) { + const varying = varyingKeys(rows) + // Not a parameter, but it is part of what produced the number, and in a + // sweep it is often the only thing that moved. + const seedVaries = new Set(rows.map((run) => run.seed ?? null)).size > 1 + const keys = new Set() + for (const run of rows) + for (const key of Object.keys(run.params)) keys.add(key) + const shared = keys.size - varying.length + + if (varying.length === 0 && !seedVaries) { + return ( +

+ {keys.size === 0 + ? "These runs carried no parameters of their own; each took what its flow declares." + : `All ${keys.size} parameter${keys.size === 1 ? "" : "s"} are the same across these runs, and so is the seed. Whatever separates them is not in what they were asked.`} +

+ ) + } + + return ( +
+
+

What differs

+

+ {varying.length + (seedVaries ? 1 : 0)} of {keys.size + 1} varied + {shared > 0 + ? shared === 1 + ? "; the other one is the same across all of them" + : `; the other ${shared} are the same across all of them` + : ""} +

+
+ + + + + Run + {seedVaries && seed} + {varying.map((key) => ( + {key} + ))} + + + + {rows.map((run) => ( + + + + {shortId(run.id)} + + + {seedVaries && ( + + {run.seed ?? "—"} + + )} + {varying.map((key) => ( + + {key in run.params ? ( + + ) : ( + // Not "empty": this run was never given the parameter, and + // took whatever the flow declares as its default. + unset + )} + + ))} + + ))} + +
+
+ ) +}