Skip to content

a panel view read an unasked provider as a refusal, so bench 311 was built around it - #3416

Merged
Flotapponnier merged 1 commit into
devfrom
fix/panel-view-missing-is-not-zero
Oct 30, 2026
Merged

Flotapponnier merged 1 commit into
devfrom
fix/panel-view-missing-is-not-zero

Conversation

@Flotapponnier

Copy link
Copy Markdown
Collaborator

a panel view read an unasked provider as a refusal, so bench 311 was built around it

The ledger picked a row's value with activePanel.values[r.slug] ?? 0. A
metric panel holds one figure per provider and a provider we could not ask has
none, so that zero is not a missing reading. On a higher-is-better board it is
the worst possible one, printed as a number, ranked last, with a data bar
beside it.

Bench 311 hit this and routed around it rather than through it. Its capability
figures are published as columns, never as selectable views, and its
methodology says why in its own words: "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. Earlier today the same zero reached a page
anyway, through ?view= on panels declared tab: false, and that was closed
by shutting the route rather than fixing what it exposed.

The second half is quieter and was never noticed. The same ?? 0 fed 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. Four providers
reading 100 with one unasked produced a mean of 75 and gave the other three a
delta of +33 percent against a field that does not exist.

Columns already had the convention right: a custom cell renders "-" when its
value is null. This brings the panel path to the same rule. A missing value is
null, it prints as a dash, it carries no bar, it is excluded from the mean,
and it sorts last in BOTH directions, which one sentinel cannot do: the worst
place on a latency board is the largest number and on a coverage board it is
zero. Using zero for both is what put an unmeasured provider at the top of a
latency table.

The rules are in src/lib/ledger-value.ts rather than inline, because a rule
nobody can call is a rule nobody can test, and this one has three cases that
each fail differently. Eleven tests, mutation-checked twice: collapsing the
sort sentinel to zero fails one, and counting absences in the mean fails four.
A measured zero still passes through untouched, which matters now that a
getLogs window of 0 blocks is a real reading.

What this unlocks is the point. A capability, a window or any other
per-provider figure can now live in the view selector on any board without
lying about the rows it could not measure, which is where a reader choosing a
provider would actually look for it.

tsc clean, 827 tests pass.

…built around it

The ledger picked a row's value with `activePanel.values[r.slug] ?? 0`. A
metric panel holds one figure per provider and a provider we could not ask has
none, so that zero is not a missing reading. On a higher-is-better board it is
the worst possible one, printed as a number, ranked last, with a data bar
beside it.

Bench 311 hit this and routed around it rather than through it. Its capability
figures are published as columns, never as selectable views, and its
methodology says why in its own words: "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. Earlier today the same zero reached a page
anyway, through `?view=` on panels declared `tab: false`, and that was closed
by shutting the route rather than fixing what it exposed.

The second half is quieter and was never noticed. The same `?? 0` fed 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. Four providers
reading 100 with one unasked produced a mean of 75 and gave the other three a
delta of +33 percent against a field that does not exist.

Columns already had the convention right: a custom cell renders "-" when its
value is null. This brings the panel path to the same rule. A missing value is
null, it prints as a dash, it carries no bar, it is excluded from the mean,
and it sorts last in BOTH directions, which one sentinel cannot do: the worst
place on a latency board is the largest number and on a coverage board it is
zero. Using zero for both is what put an unmeasured provider at the top of a
latency table.

The rules are in src/lib/ledger-value.ts rather than inline, because a rule
nobody can call is a rule nobody can test, and this one has three cases that
each fail differently. Eleven tests, mutation-checked twice: collapsing the
sort sentinel to zero fails one, and counting absences in the mean fails four.
A measured zero still passes through untouched, which matters now that a
getLogs window of 0 blocks is a real reading.

What this unlocks is the point. A capability, a window or any other
per-provider figure can now live in the view selector on any board without
lying about the rows it could not measure, which is where a reader choosing a
provider would actually look for it.

tsc clean, 827 tests pass.
@Flotapponnier
Flotapponnier merged commit b25e222 into dev Oct 30, 2026
2 checks passed
Flotapponnier added a commit that referenced this pull request Oct 30, 2026
Of the engineer's five points, three were built and visible nowhere: the wider
method set with its archive call, the heavy eth_call, and Solana's v2 methods.
All three have been collecting for hours. None of them reached a page.

Four selectable views on bench 311, which is the keyed board by construction,
so none of them can land on a cohort that has no such data:

    eth_call work          heavy leg minus light leg, the compute term alone
    Archive read           round trip of a balance read 5,000,000 blocks deep
    getLogs, address       what answering an address-filtered query costs
    Solana v2              whether getProgramAccountsV2 is served

They read the round trip of calls the coverage pass already makes, so they
cost no additional request. The first three answer points 1 and 2; the fourth
answers the half of point 4 that was measurable.

WHY VIEWS AND NOT COLUMNS. The column list is at its cap of nine. More to the
point, a view could not carry an absent reading until today: the ledger read a
missing panel value as 0, which on a higher-is-better board is a refusal
nobody gave, and that is precisely why this bench published its capability as
columns and wrote the reason into its methodology. #3416 fixed the renderer, so
the surface the engineer actually asked for is available again. The columns
stay, since they fit nine answers on one screen; the views carry what a column
cannot, a number with a unit.

WHY NOT ON THE CHAIN RPC PAGES, which is where this information belongs and
where it will eventually go. Those pages default to the public cohort, which
has no capability data at all, so a reader landing on the default view and
clicking any of these would meet a board of dashes. Honest dashes since #3416,
and still a bad page. Filling them needs the range ladder and the capability
probe on the no-key harness, which is a larger piece, costed earlier at about
2.8 percent of that harness's existing call volume.

The eth_call view is the one to read with care for another week. The work term
measured 18 to 66 ms across eleven keyed cells, against 109 ms of dispersion
in the instrument that measured it, so it is published as a number and not yet
as a ranking anybody should act on. The hourly lane from #3412 is what will
settle that, and it is six times faster than the cadence this board runs at.

Every one of these is a COLD number: the coverage probe never reuses a
connection, so DNS, TCP and TLS are paid on each call. Their comparable is the
cold latency arm, not the warm one, and both the panel descriptions and the
methodology say so.

Cache keys move in lockstep, v123 / v116 / v61. providers-v32 deliberately
does not: no provider entered or left.

260 specs valid, tsc clean, 827 tests pass.
Flotapponnier added a commit that referenced this pull request Oct 30, 2026
…d first (#3420)

Read off the published blob twenty minutes after shipping the views, which is
the part no generic check covers: a new panel's values.

    eth_call work   getblock 98.6  dwellir 51.6  blockmachine 48.8
                    quicknode 16.0  alchemy 7.5   chainstack -1.6

A negative work term is not a small number, it is an impossible one. Both legs
are the same call through the same socket, one aggregating fifty state reads
and one a single read, so the heavy leg cannot be the faster one. At an hour
of samples the two averages simply crossed.

On a lower-is-better view that reading does not sit quietly at the bottom: it
ranks FIRST. The board would have crowned the provider whose measurement was
noisiest, which is the same fault as crowning a provider for a cell nobody
asked it.

So the panel withholds it. The query ends in > 0, the series disappears for
that provider, and the cell renders as a dash, which since #3416 means absent
rather than zero. A dash here says the pair has not separated yet, which is
true and useful; minus 1.6 ms says something that cannot happen.

This is also the measurement I said last week needed a week before anyone acts
on it. The hourly lane from #3412 is what will make the term stable; until
then the honest rendering of an unstable difference is no rendering.

Found by reading the values rather than by a check, which is why the audit
pass exists: the deterministic checks on this bench came back 6 PASS, 1 WARN,
0 FAIL, and none of them looks at a panel added twenty minutes earlier.

Cache keys move in lockstep, v124 / v117 / v62: a panel's values live in the
cached entry, so the old reading would otherwise sit there for the full TTL.

260 specs valid, tsc clean, 827 tests pass.
@Flotapponnier
Flotapponnier deleted the fix/panel-view-missing-is-not-zero branch November 3, 2026 11:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant