diff --git a/src/components/benchmark-body.tsx b/src/components/benchmark-body.tsx
index 5d4e58cb..b04a6d2c 100644
--- a/src/components/benchmark-body.tsx
+++ b/src/components/benchmark-body.tsx
@@ -430,6 +430,7 @@ export function BenchmarkBody({
seriesOverride30d={activePanel?.seriesByProvider30d}
metricLabelOverride={activePanel?.label}
unitOverride={activePanel?.unit}
+ higherIsBetterOverride={activePanel?.higherIsBetter}
/>
{activePanel?.description && (
diff --git a/src/components/time-series-chart.tsx b/src/components/time-series-chart.tsx
index e5274df4..36af2883 100644
--- a/src/components/time-series-chart.tsx
+++ b/src/components/time-series-chart.tsx
@@ -38,6 +38,12 @@ type Props = {
seriesOverride30d?: Record;
metricLabelOverride?: string;
unitOverride?: Benchmark["unit"];
+ /** Direction override for ranking when a metric panel is active. Bench
+ * level higher_is_better doesn't apply to companion metrics with
+ * inverse semantics (effective fee bps lower is better, time since
+ * last fill lower is better). When set, the chart's Top N selector
+ * picks the BEST N rather than the BIGGEST N. */
+ higherIsBetterOverride?: boolean;
topNControl?: { topN: number | null; setTopN: (n: number | null) => void };
disableTopN?: boolean;
};
@@ -93,6 +99,7 @@ export function TimeSeriesChart({
seriesOverride30d,
metricLabelOverride,
unitOverride,
+ higherIsBetterOverride,
onResetExcluded,
topNControl,
disableTopN,
@@ -178,9 +185,19 @@ export function TimeSeriesChart({
}))
.filter((l) => l.values.length > 0);
- built.sort((a, b) => mean(b.values.slice(-6)) - mean(a.values.slice(-6)));
+ // Respect higher_is_better when ranking lines. For a panel like
+ // effective fee bps where lower means better, the Top N selector
+ // should surface the BEST N (smallest values), matching the ledger
+ // table below which sorts the same way. Without this the chart and
+ // ledger would disagree on what Top 5 means.
+ const higherIsBetter = higherIsBetterOverride ?? benchmark.higherIsBetter;
+ built.sort((a, b) => {
+ const av = mean(a.values.slice(-6));
+ const bv = mean(b.values.slice(-6));
+ return higherIsBetter ? bv - av : av - bv;
+ });
return built;
- }, [benchmark, range, region, colors, excluded, seriesOverride, seriesOverride7d, seriesOverride30d]);
+ }, [benchmark, range, region, colors, excluded, seriesOverride, seriesOverride7d, seriesOverride30d, higherIsBetterOverride]);
// Top-N selector — sized off the post-filter line count via the
// shared `useTopN` hook so the option set agrees across every