Skip to content

pin why nova's active-markets card is absent, not broken - #3158

Merged
Flotapponnier merged 1 commit into
devfrom
test/unranked-card-intent
Oct 22, 2026
Merged

Flotapponnier merged 1 commit into
devfrom
test/unranked-card-intent

Conversation

@Flotapponnier

Copy link
Copy Markdown
Collaborator

Last piece of the Nova work (#3150, #3153, #3157), and the only one that changes no behaviour.

perp-venue-section filters cards to value !== null && rank !== null, so the venue bench-cards strip on /products/nova-markets renders no Active markets card: Nova's value is 493 and its rank is null by design (#3150).

I checked that while verifying the product page and it reads as a bug. "Show the number we have" is the obvious-looking fix, and it would be the wrong one: on bench 116 the 493 travels with its Registry unpruned label and an FAQ explaining that Gains delisted 315 pairs of the same 493-pair registry and Nova none. A card has room for neither, so a bare 493 beside Gains' 178 is precisely the comparison the unranked label exists to prevent.

Two assertions, so the next person meets the reasoning instead of the symptom:

  • the section filter is still the thing that drops the card
  • the underlying row still carries the measured value, since hiding the card must not blank the figure bench 116 renders beside the label

691 pass, lint at its 9 pre-existing warnings.

perp-venue-section filters cards to `value !== null && rank !== null`, so
the venue bench-cards strip on /products/nova-markets shows no Active
markets card: the value is 493 and the rank is null by design.

That reads as a bug, and "show the number we have" is the obvious-looking
fix. It would be the wrong one. On bench 116 the 493 travels with its
"Registry unpruned" label and an FAQ explaining that Gains delisted 315
pairs of the same 493-pair registry and Nova none. A card has room for
neither, so a bare 493 beside Gains' 178 is exactly the comparison the
unranked label exists to prevent.

Two assertions: the section filter is still the thing that drops it, and
the underlying row still carries the measured value, since hiding the
card must not blank the figure bench 116 renders next to the label.
@Flotapponnier
Flotapponnier merged commit 8941111 into dev Oct 22, 2026
2 checks passed
Flotapponnier added a commit that referenced this pull request Oct 22, 2026
…uct page (#3160)

* nova joins the perp cohort, and the brand assets where they belong (#3150)

* the brand assets, in public/logos where they belong

Florent dropped route.png and nova_market.jpeg at the repository root. Both
are now under public/logos with the names the manifest resolves, and the root
is clean.

**Nova** replaces the SVG I lifted from their homepage yesterday. The two are
the same mark and opposite in tone: the inline SVG is three paths at #F3F3F3
on transparent, the dark-surface variant, while the supplied asset is the
mark in black on its own near-white ground. That inverts the chip decision,
so nova-markets comes back out of NEEDS_DARK_CHIP: an asset carrying its own
light background needs no chip behind it, and leaving the entry would have
put a dark tile under a light square.

Checked by rendering both at 28 and 56 px, circular-cropped, over #faf9f7 and
over #0b0b0c. Both read as a light disc with a dark mark on either page.

**Route** already had a logo and a manifest line; this is the same mark at
400x400 instead of 184x184. Worth taking for the resolution. It does carry
more padding than the old crop, so the glyph sits slightly smaller inside the
chip, which is visible side by side at 56 px and not at 28.

The SVG is deleted rather than kept as a second file: two assets for one slug
is how the wrong one gets served later.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* nova joins the perp cohort, and the one board it cannot be ranked on

Nova runs the same gTrade software as Gains on Arbitrum, so it is read by
the Gains source pointed at its own hosts rather than by a copy of it.
It has no DefiLlama entry of any kind (checked across all 8795 protocols
on 2026-10-22), so the native backend is the only path for every figure
and it carries no TVL or 30d volume at all.

Open interest is new: both venues hold it in collaterals[].pairOis[] and
neither source read it. Gains keeps DefiLlama above the native read in
the router so its published row does not move; Nova is on no DefiLlama
page, so the native read is the only one. Each collateral converts at its
own decimals and USD price, and the read refuses rather than returning a
zero when a collateral declares neither, because a zero reads as "no
positions" instead of "not measured".

Where it lands:

  041 volume share    ranked, last at $1.38M against aevo's $2.13M
  116 active markets  measured, unranked
  271 volume / OI     excluded, reason recorded in the methodology

116 is the interesting one. Nova and Gains ship the identical 493-pair
registry; gTrade delists a pair by setting its max leverage override to
0.001x rather than removing it, and Gains carries that override on 315
pairs where Nova carries it on none. Nova's 493 is therefore the catalog
it inherited, not a book anyone has confirmed is openable, so ranking the
two together would publish "Nova lists 2.8x the markets of Gains" off one
list. The row is published with `unranked: Registry unpruned`.

The product page's Active markets card computes its own rank from the
cohort, so it could have disagreed with the bench silently. It now shares
the exclusion, which is the same shape as the CEX filter already sitting
two lines above it for the same reason.

271 is excluded for the opposite problem to the usual one: both series
exist and the denominator is too small to divide by. $11,269 of open
interest across one pair against $1.38M of volume is a ratio of 123x
that would top the board, which describes a venue with almost no open
positions rather than one turning its book over 123 times a day.

Also maps Nova's hype-1000 group (one pair, HYPE1000/USD) to crypto,
without which one unknown group withholds its whole breadth read.

Cache keys move in lockstep, since a cached entry holds the provider set
current when it was written and a bench gaining a row needs the key to
move or the row never appears.

Tests: the OI conversion and its refusal path, that the two gTrade
configurations cannot share a venue, label or host, that the unranked
card neither ranks Nova nor pushes Gains down a place, and that the
exclusion set and the bench spec cannot drift apart. Each was checked
against a mutation of the code it covers. The live test against both
backends is behind OCB_LIVE=1, as the leverage-terms one is.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* nova was publishing 75% health for a figure it cannot produce (#3153)

perp_venue_health is the share of a venue's metrics that resolved on the
tick, and its denominator is every metric whose priorityMap is non-empty.
The mFees30d case ends in a fall-through returning DefiLlama for any
venue it does not name, so Nova inherited it. Nova is on no DefiLlama
page at all, so that source can never answer, and the metric still
counted: 3 of 4, published as a 75% success rate on benches 041 and 116
while every figure Nova can produce resolved on every tick.

Caught on the VPS right after the deploy, from perp_venue_health{venue=
"nova"} 0.75 next to three source_used lines that had all succeeded.

This is the same failure the volume_30d exemption two lines below already
documents, where leaving a sourceless metric in the denominator pinned
every venue at 6/7 and read as a reliability problem on four bench pages.
The difference is that volume_30d is still attempted because a native
source may serve it one day, whereas here there is no source to attempt,
so the priority is nil rather than exempt.

The test pins both halves: the three metrics Nova publishes name only its
own source, and the four it cannot publish name nothing. Verified against
a mutation that restores the fall-through.

* one company, two product pages: nova was indexable at both slugs (#3157)

Nova was already on the site as a Hyperliquid frontend under the product
slug "nova-markets" (bench 030, where its logo lives) when #3150 added it
to the perp cohort as "nova". "nova" then became a provider slug on
benches 041 and 116, so /products/nova started generating its own page.

Both answered 200 with their own canonical:

  /products/nova          "Nova: trading benchmark 2026, live rank"
                          the perp cards, no logo
  /products/nova-markets  "Nova: Hyperliquid frontend fees, volume..."
                          the logo and the frontend bench, no perp cards

Neither showed the whole venue, and the two competed for the same name.
This is live on production as well as staging, because the product page
reads its measured values from the worker blob and the worker builds from
dev, so prod already serves "Nova ranks #24 of 24 on Perp DEX volume
share at $1.34M" from a page whose code has never heard of Nova.

PERP_PRODUCT_SLUGS now maps nova -> nova-markets, which is the convention
already used for gmx-v2 -> gmx and trade-xyz -> xyz, so every cohort link
points at the page that has the logo. PERP_VENUE_META gains the entry
that gives that page the perp venue dashboard. And /products/nova 308s,
in both generateMetadata and the component, because this file already
records that a metadata-only redirect left a cached 404 behind (merkle,
2026-07-11).

Also fixes the one pre-existing instance of the same gap, found by the
new test: ondo was the only cohort venue with no PERP_VENUE_META entry,
so /products/ondo got the generic bench cards and no perp dashboard.
Ondo Perps, not Ondo Finance, which is a separate provider here carrying
the protocol P/F row.

The test pins the three places that have to agree, since a mapping that
moves the links while leaving the duplicate page behind looks fixed. Note
that not every entry in the map is an alias: coinbase ->
coinbase-international maps the cohort link only, because
/products/coinbase is US retail Coinbase and legitimately keeps its page.
Checked against prod before asserting it, and both halves verified
against a mutation.

* pin why nova's active-markets card is absent, not broken (#3158)

perp-venue-section filters cards to `value !== null && rank !== null`, so
the venue bench-cards strip on /products/nova-markets shows no Active
markets card: the value is 493 and the rank is null by design.

That reads as a bug, and "show the number we have" is the obvious-looking
fix. It would be the wrong one. On bench 116 the 493 travels with its
"Registry unpruned" label and an FAQ explaining that Gains delisted 315
pairs of the same 493-pair registry and Nova none. A card has room for
neither, so a bare 493 beside Gains' 178 is exactly the comparison the
unranked label exists to prevent.

Two assertions: the section filter is still the thing that drops it, and
the underlying row still carries the measured value, since hiding the
card must not blank the figure bench 116 renders next to the label.

* date the two counts the 116 formula hand-types

The provider formula read "the identical 493-pair gTrade registry; Gains
has delisted 315, Nova none" with no date. Both numbers move: the
registry grows and Gains delists more pairs, and an undated count in a
field readers see in the table goes quietly false.

The repo dates this kind of claim everywhere else, including the bullet
right above this one ("listed 355 Gains pairs where 178 can be opened
today") and bench 271's bands ("Hyperliquid 0.5x ... on 2026-09-22"). The
methodology bullet for this row already carried the date; the formula did
not. Reworded so both counts sit behind "on 2026-10-22", at 228 of the
240 characters the schema allows.

Found auditing my own prose against the editorial rules before this goes
to production. No em dashes and no marketing adjectives in the 32 added
spec lines; this was the one real finding.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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