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