Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 33 additions & 15 deletions src/components/ledger-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { useMemo, useState } from "react";
import { rateDecimals, successTitle } from "@/lib/sample-precision";
import { rowHref } from "@/lib/row-link";
import { barScale, fieldMean, sortableValue } from "@/lib/ledger-value";

import Link from "next/link";
import { ChevronDown, ChevronUp } from "lucide-react";
Expand Down Expand Up @@ -31,7 +32,7 @@
// imports unstable_cache + the bench loaders) and pulling it into
// this client component breaks the build.
const HEX_ADDRESS_SLUG = /^0x[a-f0-9]+$/;
function isHexAddressSlug(slug: string): boolean {

Check warning on line 35 in src/components/ledger-table.tsx

View workflow job for this annotation

GitHub Actions / check

'isHexAddressSlug' is defined but never used
return HEX_ADDRESS_SLUG.test(slug.toLowerCase());
}

Expand Down Expand Up @@ -230,11 +231,25 @@
// window's first custom column, or `panel.values[slug]` when a panel
// tab is active. Used for sort, filter, the inline data bar, and the
// displayed value in the headline column.
const pickValue = (r: ProviderResult): number => {
if (activePanel) return activePanel.values[r.slug] ?? 0;
if (customCols) return colValueW(r, customCols[0]) ?? 0;
// The honest value, which can be absent. A panel holds one figure per
// provider and a provider we could not ask has none; coercing that to 0
// publishes a refusal nobody gave. Bench 311 renders its capability
// figures as columns for exactly this reason, and said so in its
// methodology rather than fixing it here.
//
// Columns already distinguish the two: a custom cell renders "-" when its
// value is null. This brings the panel path to the same convention.
const pickValueOrNull = (r: ProviderResult): number | null => {
if (activePanel) return activePanel.values[r.slug] ?? null;
if (customCols) return colValueW(r, customCols[0]) ?? null;
return r.ms.p50;
};
// Numeric form for the places that need a scalar and have no way to
// express absence: sort position, the data-bar scale. Missing sorts as
// the worst value rather than the best, which is what 0 was doing on a
// higher-is-better board.
const pickValue = (r: ProviderResult): number =>
sortableValue(pickValueOrNull(r), higherIsBetter);
// Detected from the first provider's results — if ANY provider declares
// slot_p50/slot_p99 in its YAML queries, every row gets the column (with
// "-" for providers that don't declare it). Used by Solana-native benches
Expand Down Expand Up @@ -263,9 +278,9 @@
// Field-mean Δ — duplicated here so the sort comparator can rank by it
// without waiting on per-Row computation. Kept aligned with the same
// formula the Row uses for the displayed Δ% (see deltaPct below).
const fieldMeanRaw =
results.reduce((s, r) => s + pickValue(r), 0) /
Math.max(1, results.length);
// Rows with no value are excluded rather than counted as zero: a mean
// dragged down by absences makes every other row's delta wrong too.
const fieldMeanRaw = fieldMean(results.map((r) => pickValueOrNull(r)));
const deltaForSort = (r: ProviderResult): number => {
if (fieldMeanRaw === 0) return 0;
return (pickValue(r) - fieldMeanRaw) / fieldMeanRaw;
Expand Down Expand Up @@ -416,7 +431,7 @@
// Max + field-mean of the active column. Computed off `sorted` (the
// scored set) so the field mean isn't pulled to zero by augmented
// unavailable rows, which would flatten every delta to +999%.
const maxValue = Math.max(...sorted.map((r) => pickValue(r))) || 1;
const maxValue = barScale(sorted.map((r) => pickValueOrNull(r)));
const fieldValue =
sorted.reduce((s, r) => s + pickValue(r), 0) / Math.max(1, sorted.length);

Expand Down Expand Up @@ -698,7 +713,7 @@
r={r}
i={i}
unit={unit}
value={pickValue(r)}
value={pickValueOrNull(r)}
fieldValue={fieldValue}
maxValue={maxValue}
panelActive={panelActive}
Expand Down Expand Up @@ -739,7 +754,7 @@
r={r}
i={-1}
unit={unit}
value={pickValue(r)}
value={pickValueOrNull(r)}
fieldValue={fieldValue}
maxValue={maxValue}
panelActive={panelActive}
Expand Down Expand Up @@ -825,7 +840,7 @@
r: ProviderResult;
i: number;
unit: string;
value: number;
value: number | null;
fieldValue: number;
maxValue: number;
panelActive: boolean;
Expand Down Expand Up @@ -858,9 +873,10 @@
const isUnranked = !isUnresponsive && !!r.unrankedLabel;
const isOffline = !isUnresponsive && !isUnranked && r.availability === "unavailable";
const isMuted = isOffline || isUnresponsive;
const deltaPct = fieldValue > 0 ? ((value - fieldValue) / fieldValue) * 100 : 0;
const deltaPct =
value != null && fieldValue > 0 ? ((value - fieldValue) / fieldValue) * 100 : 0;
const deltaSign = deltaPct > 0 ? "+" : deltaPct < 0 ? "−" : "±";
const barPct = Math.max(2, (value / maxValue) * 100);
const barPct = value == null ? 0 : Math.max(2, (value / maxValue) * 100);

return (
<tr className={`border-b border-rule transition-colors hover:bg-paper-soft/50 ${isMuted ? "opacity-65" : ""}`}>
Expand Down Expand Up @@ -1134,9 +1150,11 @@
? customCells[0].v != null
? fmtUnit(customCells[0].v, customCells[0].unit)
: "-"
: panelActive
? fmtUnit(value, unit)
: fmtHeadline(value, { ...benchmark, unit }, r.slug)}
: value == null
? "-"
: panelActive
? fmtUnit(value, unit)
: fmtHeadline(value, { ...benchmark, unit }, r.slug)}
</span>
</span>
</td>
Expand Down
103 changes: 103 additions & 0 deletions src/lib/ledger-value.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { describe, expect, it } from "bun:test";

import { barScale, fieldMean, sortableValue } from "@/lib/ledger-value";

/**
* The case these exist for, in full, because it is the reason bench 311 was
* built around the problem instead of through it.
*
* A metric panel holds one figure per provider. A provider we could not ask
* has none, and the table read that as `?? 0`. On a higher-is-better board a
* zero is not an absence, it is the worst possible reading, printed as a
* number with a bar beside it. Bench 311's methodology states the
* consequence plainly: "a provider with no reading for it is shown as a zero
* rather than left out, which would state a refusal we never received", and
* its capability figures were published as columns to avoid it.
*
* The same `?? 0` was also in the field mean, which is the denominator of
* every row's delta, so one unmeasured provider moved the percentage printed
* next to all the others.
*/
describe("sortableValue", () => {
it("sorts a missing value last on a lower-is-better board", () => {
// Latency. The worst place is the largest number, and 0 would have put an
// unmeasured provider at the top of the table.
expect(sortableValue(null, false)).toBe(Number.POSITIVE_INFINITY);
expect(sortableValue(null, false)).toBeGreaterThan(sortableValue(99999, false));
});

it("sorts a missing value last on a higher-is-better board", () => {
// Capability, in percent. Here the worst place IS zero, which is why one
// sentinel cannot serve both directions.
expect(sortableValue(null, true)).toBe(0);
expect(sortableValue(null, true)).toBeLessThan(sortableValue(0.1, true));
});

it("passes a real zero through unchanged", () => {
// A measured 0 is a refusal we did receive, and it must keep its place:
// a getLogs window of 0 blocks means the narrowest span was refused,
// which is a fact about the provider rather than about our access.
expect(sortableValue(0, true)).toBe(0);
expect(sortableValue(0, false)).toBe(0);
});
});

describe("fieldMean", () => {
it("excludes missing rows instead of counting them as zero", () => {
// Four providers, one unmeasured. The mean of what was measured is 100.
// Counting the absence drags it to 75 and every other row's delta with it.
expect(fieldMean([100, 100, 100, null])).toBe(100);
});

it("is the plain mean when nothing is missing", () => {
expect(fieldMean([10, 20, 30])).toBe(20);
});

it("returns zero when nothing was measured", () => {
// The caller reads 0 as "no delta to show" rather than dividing by it.
expect(fieldMean([null, null])).toBe(0);
expect(fieldMean([])).toBe(0);
});

it("ignores the infinite sentinel if one ever reaches it", () => {
// sortableValue's lower-is-better sentinel is Infinity. If the two paths
// were ever crossed, a single Infinity would make the mean Infinity and
// every delta NaN, which renders as nothing at all and looks like a data
// outage rather than a bug.
expect(fieldMean([10, 20, Number.POSITIVE_INFINITY])).toBe(15);
});
});

describe("barScale", () => {
it("scales to the largest measured value", () => {
expect(barScale([10, 40, null])).toBe(40);
});

it("never returns zero, so dividing by it stays safe", () => {
expect(barScale([])).toBe(1);
expect(barScale([null, null])).toBe(1);
expect(barScale([0, 0])).toBe(1);
});

it("refuses an infinite sentinel, which would flatten every real bar", () => {
// This is the failure that would be hardest to read on the page: every
// bar becomes a sliver and nothing errors.
expect(barScale([10, 40, Number.POSITIVE_INFINITY])).toBe(40);
});
});

describe("the three together, on the shape that caused this", () => {
it("one unasked provider changes neither the mean nor the scale", () => {
// Bench 311's robinhood tab: five providers, one of which we could not
// ask on that chain. Measured values are the getLogs windows.
const measured = [500, 10_000, 10_000, 1_000_000];
const withGap: (number | null)[] = [...measured, null];
expect(fieldMean(withGap)).toBe(fieldMean(measured));
expect(barScale(withGap)).toBe(barScale(measured));
// And the unasked row is last rather than first on a board where more
// is better.
const keys = withGap.map((v) => sortableValue(v, true));
expect(Math.min(...keys)).toBe(0);
expect(keys[keys.length - 1]).toBe(0);
});
});
58 changes: 58 additions & 0 deletions src/lib/ledger-value.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* What the ledger does with a row that has no value.
*
* A metric panel holds one figure per provider, and a provider we could not
* ask has none. The table read that absence as `?? 0`, which on a
* higher-is-better board is not a missing reading, it is the worst possible
* one: a refusal nobody gave, ranked last, with a data bar of zero width and
* a number printed next to it.
*
* Bench 311 ran into this and routed around it rather than through it. Its
* capability figures are published as columns, and its methodology says why:
* "In a chart view the board renders one metric for every row, and a provider
* with no reading for it is shown as a zero rather than left out, which would
* state a refusal we never received." The columns were the workaround. This is
* the fix, and with it a capability or a window can live in the view selector
* on any board without lying about the rows it could not measure.
*
* Columns already had the convention right: a custom cell renders "-" when its
* value is null. Everything here brings the panel path to that same rule.
*/

/** Sort key for a possibly-absent value.
*
* Absent must sort LAST in both directions, which a single sentinel cannot
* do: on a lower-is-better board the worst value is the largest, and on a
* higher-is-better board it is the smallest. Using 0 for both is what put an
* unmeasured provider at the top of a latency board. */
export function sortableValue(
value: number | null,
higherIsBetter: boolean,
): number {
if (value != null) return value;
return higherIsBetter ? 0 : Number.POSITIVE_INFINITY;
}

/** Mean over the rows that have a value.
*
* Counting an absence as zero does not only misplace that row: the field
* mean is the denominator of every other row's delta, so one unmeasured
* provider moves the percentage printed beside all the others. Returns 0
* when nothing was measured, which the caller already treats as "no delta
* to show". */
export function fieldMean(values: (number | null)[]): number {
const present = values.filter((v): v is number => v != null && Number.isFinite(v));
if (present.length === 0) return 0;
return present.reduce((s, v) => s + v, 0) / present.length;
}

/** Scale for the inline data bars: the largest value actually measured.
*
* Infinite sentinels from `sortableValue` must never reach this, or every
* real bar collapses to nothing. Returns 1 when there is nothing to scale
* against, so a division by it is still safe. */
export function barScale(values: (number | null)[]): number {
const present = values.filter((v): v is number => v != null && Number.isFinite(v));
if (present.length === 0) return 1;
return Math.max(...present, 0) || 1;
}
Loading