fix(seo): drop dead /alternatives + jupiter-vs-raydium compare#749
Merged
Conversation
This was referenced Jun 26, 2026
…cing (follow-up A) (#741) Completes PR #732 (sample-health system) by surfacing the computed dataConfidence/sampleHealth/expectedN to users + machine-readable consumers. Was dead-code on the data layer until this PR. UI (ledger-table.tsx): - Filter rows tagged 'insufficient' out of the sorted ranking. - 'Low sample' pill on rows with dataConfidence='low' + tooltip showing the actual sample-health ratio ('45% of expected'). APIs: - /api/citable: returns expectedN + dataConfidence per row. When bench-wide aggregate is 'insufficient', returns value=null + leader=null (refuses to crown a leader from undersized samples). - /api/stat/[slug]: same treatment + drops 'insufficient' rows from the machine-readable ranking array. Per-row sampleHealth + dataConfidence exposed for downstream tooling. Library (citation.ts): - citationCandidates() drops 'insufficient' rows from the leader candidate set. - fieldValue/leader/headlineSentence return null/'insufficient data' when bench-wide is insufficient. - isInsufficient() helper preserved from main (used by hub cards + /api/citable hot path). Effect: bench pages where YAML declares expected_n now visually communicate sample confidence; agents/journalists hitting the citable API can't accidentally quote a leader drawn from 3 data points; the methodology page's 'n >= 1000' claim becomes honest. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…dCategory (D.2) (#743) Final cherry-pick from dev-archive — adds 7 new SEO-indexable hub pages (one per benchmark category) that target long-tail queries like 'best crypto aggregator benchmarks 2026'. D.2 was deferred from PR D because the BenchmarkCard ↔ MiniChart ↔ BenchmarkCardData type chain had cascading TS errors. Follow-up A (citation.ts isInsufficient → InsufficientCheckInput structural subset) silently fixed those, so this lands cleanly now. Files: - src/app/benchmarks/category/[cat]/page.tsx (new) — server route that renders BenchmarkGrid pre-filtered to one category + breadcrumb + ItemList JSON-LD. generateStaticParams builds the 7 hub routes from CATEGORIES. Each page is fully indexable (canonical, OG, etc.). - src/components/benchmark-grid.tsx (updated) — adds two optional props (lockedCategory, allCategories). Backward compatible: when unset the grid behaves exactly as before (used on /benchmarks). When set (category hub routes), the grid pre-filters and shows the full category pill list so users can hop between hubs. URLs that ship after deploy: - /benchmarks/category/aggregators - /benchmarks/category/bridges - /benchmarks/category/blockchains - /benchmarks/category/trading - /benchmarks/category/wallets - /benchmarks/category/rpcs - /benchmarks/category/nft-apis Each renders the canonical bench grid filtered to that category with its own H1, meta description, and structured data. Sitemap pickup automatic on next regen. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…dead compare pair Two SEO regressions feeding 404s into Google's crawl: 1. /products/<slug> for perp/PM venues without an alternatives YAML (lighter, manifold, vertex, grvt, ostium, variational, pacifica, aevo, edgex, paradex, extended, myriad, limitless, aster) hardcoded a /alternatives/<slug> footer link in PmVenueSection and PerpVenueSection. Now gated on loadAlternativeSlugs() membership so only venues with an actual YAML emit the link. 2. /compare hub rendered jupiter-vs-raydium even though raydium has no bench appearances, so /compare/jupiter-vs-raydium 404s downstream. Pre-filter COMPARE_PAIRS against getProvider() so dead pairs disappear from the list and the JSON-LD ItemList until both sides resolve. Plus a defensive guard in buildAlternativesReverseMap() so the emitted alt.slug is always a known live YAML, even if the alt list source ever changes shape.
Flotapponnier
force-pushed
the
fix/seo-dead-alternatives-and-compare
branch
from
June 26, 2026 13:31
a108615 to
7377679
Compare
Flotapponnier
added a commit
that referenced
this pull request
Jun 26, 2026
PR #749 stopped /compare from rendering pairs where either provider is unresolved (e.g. jupiter-vs-raydium), but the search index built in buildSearchIndex iterated COMPARE_PAIRS directly. Ahrefs crawls the embedded JSON and flagged /compare → /compare/jupiter-vs-raydium as a dead internal link. Same getProvider() probe as /compare/page.tsx, so the two surfaces stay in lockstep. Co-authored-by: Florent Tapponnier <contact@mobula.io>
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/alternatives/<slug>footer links inpm-venue-section.tsxandperp-venue-section.tsxonloadAlternativeSlugs()membership — kills 14 dead 404s (lighter, manifold, vertex, grvt, ostium, variational, pacifica, aevo, edgex, paradex, extended, myriad, limitless, aster)COMPARE_PAIRSentry viagetProvider()incompare/page.tsxand skip pairs where either side is unresolved — killsjupiter-vs-raydiumfrom the rendered list + JSON-LDTest plan
/perpsand/pmfooters — only resolvable alternatives links visible/compare— no jupiter-vs-raydium card