Skip to content

stats + revenue: name every rail, and say when the canary is filtered out - #664

Merged
MikeyPetrillo merged 2 commits into
mainfrom
claude/sweet-brown-i99jl3
Aug 2, 2026
Merged

stats + revenue: name every rail, and say when the canary is filtered out#664
MikeyPetrillo merged 2 commits into
mainfrom
claude/sweet-brown-i99jl3

Conversation

@MikeyPetrillo

Copy link
Copy Markdown
Owner

Two findings, both surfaced by checking things that were reported as looking wrong but turned out to be reported correctly.

1. One chain shown as two rows; two rails shown as hex ids

Found while verifying the Monad rail was healthy. It is — but the per-chain split on the public /api/stats was reporting the same chain twice:

Shown as Reality
monad 19 + eip155:143 42 monad, 61
celo 35 + eip155:42220 16 celo, 51
stellar 71 + stellar:pubnet 20 stellar, 91
eip155:10 14, eip155:1329 9 optimism and sei — unnamed entirely

networkFromPaymentResponse maps CAIP2_NAMES[id] || id, so a chain missing from that map is booked under its raw id. Sei and Optimism, the two most recently added rails, were never added — every settlement on them has displayed publicly as a hex chain id since they shipped.

No money affected. What is affected: per-chain revenue reads low for every split rail, on a surface that looks authoritative.

Fixed both ways — the two missing names, plus mergeNetworkCounters folding raw-id counters into their named bucket at read time. Deliberately not a history rewrite: stored counters stay as recorded, and a chain we genuinely cannot name still reports under its raw id rather than vanishing, because silently dropping revenue is worse than showing a hex string. Totals asserted conserved.

scripts/test-chain-names.js fails if any offerable chain lacks a name, so a thirteenth rail cannot ship unnamed.

Note on the guard itself: its first version called railStatus(), which reads boot state and is empty offline — so the assertion that matters passed while checking zero rails. It now sources the static NETWORKS map and checks 12.

2. "I don't see any canary runs on the revenue page"

The canary was running fine — it settled on 11 of 12 rails that day, all present in /api/revenue/daily. Only Celo was missing, and Celo's facilitator is down.

The chart defaults to External scope, which is correct and stays: the canary buys from us with our own wallet, and counting it as revenue would inflate every number on the page. But that made "the canary stopped running" and "the canary is excluded by the current filter" look identical on screen.

The page now says, when internal settlements exist and are hidden: how many chains, how many days, which control reveals them, and why they are excluded. The number on the chart does not move. The note hides itself when the scope already includes internal, because a note that renders in every state is decoration.

Verification

  • 10 assertions in test-chain-names.js, 4 added to test-revenue-chart.js (jsdom), both in CI
  • Six mutations, all killed: removing optimism from the map, dropping unnameable chains, overwriting instead of summing, never showing the note, showing it when nothing is hidden, and dropping the why
  • Sweeps clean: 209 strict / 295 lenient tools, 526/526 through MCP, full offline battery

MikeyPetrillo and others added 2 commits August 2, 2026 18:43
…two rows

Found while checking whether the Monad rail was healthy. It is - but the
per-chain revenue split on the PUBLIC /api/stats was reporting the same chain
twice, and two rails not at all.

  monad 19  beside  eip155:143 42      -> one chain, 61 calls
  celo 35   beside  eip155:42220 16    -> one chain, 51 calls
  stellar 71 beside stellar:pubnet 20  -> one chain, 91 calls
  eip155:10 14, eip155:1329 9          -> optimism and sei, unnamed entirely

networkFromPaymentResponse maps CAIP2_NAMES[id] || id, so a chain missing from
that map is booked under its raw id. Sei and Optimism, the two most recently
added rails, were never added to it - so every settlement on them has been
displayed to the public as a hex chain id since they shipped. The older splits
are historical counters recorded before their entries existed.

Nothing was lost on-chain and no money is affected. What is affected is that
per-chain revenue reads low for every split rail, and a reader comparing rails
draws the wrong conclusion from a surface that looks authoritative.

Two fixes:
  * eip155:10 -> optimism and eip155:1329 -> sei, stopping the ongoing split.
  * mergeNetworkCounters folds raw-id counters into their named bucket at READ
    time. Deliberately not a history rewrite: the stored counters stay exactly
    as recorded and the merge is a presentation rule anyone can check against
    CAIP2_NAMES. A chain we genuinely cannot name still reports under its raw
    id rather than vanishing, because silently dropping revenue would be a far
    worse defect than showing a hex string.

scripts/test-chain-names.js (10 assertions, offline, in CI) fails if any
offerable chain lacks a name, so a thirteenth rail cannot ship unnamed.

Note on the test itself: its first version called railStatus(), which reads
boot state and is empty offline, so the assertion that matters passed while
checking ZERO rails. It now sources the static NETWORKS map and checks 12.
That vacuous-green shape is the same one this whole audit keeps turning up,
and it nearly shipped inside the guard against it.

Mutations killed: removing optimism from the map reproduces the original
defect, dropping unnameable chains loses revenue silently, and overwriting
instead of summing loses calls. Totals are asserted conserved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tered out

Reported as "I don't see any canary runs on the revenue page". The canary was
running fine - it settled on 11 of 12 rails that day, every one present in
/api/revenue/daily as internal transactions. Only Celo was missing, and Celo's
facilitator is down.

The chart defaults to External scope, which is correct and must stay: the
canary buys from us with our own wallet, and counting it as revenue would
inflate every number on the page. But that default made two very different
situations look identical on screen - "the canary stopped running" and "the
canary is excluded by the current filter" - and the default view was read as
the first on a day the second was true.

So when internal settlements EXIST in the window and the External filter is
hiding them, the page now says so: how many chains, how many days, which
control reveals them, and WHY they are excluded. The number on the chart does
not move. What changes is that a reader can tell absence from concealment,
which is the same fix as the seller-facing discovery note and for the same
reason - a gap nobody can see is a gap nobody investigates.

The note hides itself when the scope already includes internal, because a note
that renders in every state is decoration rather than signal.

4 assertions in scripts/test-revenue-chart.js (jsdom, in CI). Mutations killed:
never showing the note restores the invisible state, showing it when the canary
is already on screen makes it noise, and dropping the WHY leaves it reading as
a bug report rather than a deliberate exclusion.

Note on the test: these cases share one jsdom window, so the two new checks
restore the controls they flip. Leaving one flipped made the NEXT check fail on
a note that was working perfectly - a fault in the harness that reads exactly
like a fault in the page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@MikeyPetrillo
MikeyPetrillo merged commit 4fa09fd into main Aug 2, 2026
15 checks passed
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