Repository navigation
Expand file tree
/
Copy pathremoved-benches.ts
More file actions
508 lines (498 loc) · 27.5 KB
/
Copy pathremoved-benches.ts
File metadata and controls
508 lines (498 loc) · 27.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
/**
* Which bench slugs production does not serve, and what a hit on one gets.
*
* This file holds three sets, and they are NOT interchangeable. Each has its
* own docblock below; this is the map, because an earlier version of this
* comment described all of them as one and got the status code wrong.
*
* REMOVED_BENCH_SLUGS retired for good, plus a few held for review.
* src/middleware.ts answers 410 Gone on prod, which is
* the SEO-correct signal for a URL that was indexed.
* RENAMED_BENCH_SLUGS split or renamed; a 308 to the successor, issued from
* next.config.ts redirects() so it costs no invocation.
* Checked before the 410 so a rename always wins.
* DEV_ONLY_BENCH_SLUGS the staging pipeline: still being validated, or held
* back on purpose. Dropped at the loader, so the page
* 404s rather than 410s. Nothing was ever published at
* those URLs, so there is no signal to preserve.
*
* The loader gate (src/lib/materialize/load.ts) is what keeps every rendered
* surface consistent: catalog index, category pages, /rpc hub, compare pairs,
* /api/citable, /api/stat, llms.txt, RSS, MCP and the Markdown views never
* link or cite a slug this deployment does not serve. The sitemap is dropped
* separately in src/lib/sitemap-builder.ts, through the isDevOnlyBench and
* isDevOnlyRoute helpers below rather than the sets directly, and is served by
* src/app/sitemap.xml/route.ts (there is no src/app/sitemap.ts; it became a
* Route Handler so it could set its own Cache-Control).
*
* Moving a bench to production = remove its slug from DEV_ONLY_BENCH_SLUGS,
* bump the bench-set cache keys in src/lib/spec.ts, ship dev to main.
*
* TWO PRODUCTION ENDPOINTS DELIBERATELY DO NOT ENFORCE ANY OF THIS, and an
* audit will find them again: /api/aggregate and /api/sitemap-data serve the
* worker's blobs verbatim, so on production both carry every dev-only slug
* with its editorial fields, including an seo_title naming a leader for a
* bench whose page 404s. Flagged 2026-09-30. They are transport, not a public
* surface: every Vercel deployment including staging fetches those two routes
* on the production domain (src/lib/aggregate-blob.ts, src/lib/sitemap-blob.ts),
* and staging is the only place these benches render, so filtering them there
* would empty the staging pipeline of all of them. Both routes carry that
* warning at the top. What bounds the exposure: noindex via the /api/:path*
* X-Robots-Tag, linked from no page, absent from llms.txt and the OpenAPI
* document, and no secret in the payload (no keyed URL shape, checked).
*/
/**
* Bench slugs renamed / split, mapped to their canonical successor.
* Middleware issues a 301 (permanent) redirect on prod so external
* backlinks and previously-indexed URLs keep their PageRank pointing
* at the current page instead of hitting a 410 / 404.
*
* Enforced in src/middleware.ts BEFORE the REMOVED_BENCH_SLUGS check
* so a slug listed here always wins the 301 over a 410. Only list a
* slug here when the successor bench genuinely covers the same reader
* intent — do not redirect to unrelated pages.
*/
export const RENAMED_BENCH_SLUGS: Record<string, string> = {
// network-coverage split (2026-07-24) into 2 apple-to-apple benches:
// - asset-registry-coverage (which chains a data API knows tokens on)
// - dex-network-coverage (which chains a data API indexes DEX pools on)
// The original bench mixed the two definitions, flagged on Twitter by
// @sooneggg after CoinPaprika #1 with 307 (asset registry via
// /v1/contracts) landed next to GeckoTerminal 265 (DEX indexing via
// /networks). CoinPaprika's #1 claim reflects the asset-registry
// framing, so 301 the legacy URL there; DEX-only readers reach the
// dex-network-coverage bench via the cross-link at the top of the
// successor page.
// Bench 200 covered Robinhood Chain and Arc pads from 2026-10-07, so a slug
// promising Solana became false. This one WAS served on production, unlike
// the two dev-only renames the same week, so it owes a 301 and not a 404.
//
// Bench 201 is the same story a day later. It opens on all chains and
// carries tabs for Solana, BNB, Robinhood, Base, Arc and more, so
// "solana-trading-platform-wars" named one tab of seven. Served on
// production and the site's highest-impression page, so it owes a 301.
// The solana-dex-volume entry below points at the new slug: a chain of two
// redirects would resolve, but it would drop the ?chain=solana that entry
// exists to carry.
// Bench 205 retired 2026-10-07. Once every bench on the hub read one
// source it stopped being a second measurement and became the same one:
// 201 pinned to Solana, same cohort bar a row, same definition, values
// identical to the millionth. It was the weakest of the three overlapping
// pages on every axis that matters, with no chain tabs against their eight,
// one internal reference against three, and a slug promising DEX volume
// while measuring terminal-routed volume.
//
// A 301 to 201's Solana tab rather than a 410, because "solana-dex-volume"
// is a keyword slug worth consolidating into the page that now answers it,
// and the reader lands on exactly the view they were looking for.
"solana-trading-platform-wars": "trading-platform-wars",
"solana-dex-volume": "trading-platform-wars?chain=solana",
"solana-launchpad-wars": "launchpad-wars",
"network-coverage": "asset-registry-coverage",
// Keyed RPC cohort folded into the per-chain RPC pages (2026-09-21):
// one page per chain, the private (API-key) providers behind the
// Endpoints selector. The target is the clean canonical URL; the
// `#tier=keyed` fragment opens the Private tab client-side and is not
// a distinct document for crawlers. A value may carry a fragment. Only robinhood was ever on production, the
// other eight were dev-only, but their URLs were shared.
"keyed-rpc-ethereum": "ethereum-rpc#tier=keyed",
"keyed-rpc-arbitrum": "arbitrum-rpc#tier=keyed",
"keyed-rpc-base": "base-rpc#tier=keyed",
"keyed-rpc-bnb": "bnb-rpc#tier=keyed",
"keyed-rpc-polygon": "polygon-rpc#tier=keyed",
"keyed-rpc-solana": "solana-rpc#tier=keyed",
"keyed-rpc-hyperliquid": "hyperliquid-rpc#tier=keyed",
"keyed-rpc-robinhood": "robinhood-rpc#tier=keyed",
"keyed-rpc-arc": "arc-rpc#tier=keyed",
};
/**
* Answer pages (answers/<slug>.yml) whose referenced benchmark is in
* REMOVED_BENCH_SLUGS. Same treatment: 410 on prod direct hits, dropped
* from the answers listing and sitemap on prod, normal on staging.
*/
export const REMOVED_ANSWER_SLUGS = new Set([
"which-evm-aggregator-has-the-fastest-quote",
"which-solana-rpc-lands-the-most-transactions",
// References solana-dex-quote-latency (staging-only, in
// REMOVED_BENCH_SLUGS). Same pattern.
"which-solana-dex-aggregator-is-the-fastest",
// References pm-data-freshness (bench 113, retired 2026-07). Bench
// removed; answer returns 404 without this guard.
"which-prediction-market-data-api-is-the-freshest",
// References pm-fee-comparison (dropped 2026-07). The YAML also
// hand-types "2% fee" and "vig roughly 4-10%", so it must not be
// revived as written. 410 instead of 404 (SEO audit 2026-09-22).
"polymarket-fees-explained",
// Same class, found by the next audit: references pm-fee-comparison too,
// and hand-types "flat 2%", "roughly $0.07" and a "$0.20 / $0.80"
// crossover. 410 instead of 404 (SEO audit 2026-09-23).
"polymarket-vs-kalshi-fees",
]);
/**
* Benches that stay on dev / staging / preview and never reach production
* (VERCEL_ENV === "production"): still being validated, or held back on
* purpose. Enforced generically, so a release needs no per-file surgery:
* 1. src/lib/materialize/load.ts drops the specs at loader level on prod,
* so pages 404, and hubs, category pages, /rpc, compare pairs,
* /api/citable, llms.txt, MCP and RSS never list or cite them.
* 2. src/lib/sitemap-builder.ts drops them from the worker's blob (the
* worker runs from dev and publishes every bench) and from the
* product recount.
* 3. Components tied to one of these benches check that the bench is
* served by this deployment before rendering (TerminalFillSection).
* Moving a bench to production = remove its slug here.
*/
export const DEV_ONLY_BENCH_SLUGS = new Set([
// 306 privacy round trip: the spec exists and the harness exists, but the
// harness is not deployed, so Prometheus holds no privacy_round_trip_bps
// series yet. A metric_panel with no value DELETES its row rather than
// marking it, so shipping this to production today would publish an empty
// table under a confident title. Staging still renders it, which is the
// point of this set: the copy, the JSON-LD and the size selector can be
// reviewed there before any reader sees the board.
//
// Un-gate condition: the harness running in at least one region with 24h
// of data, both rails answering, and the bucket selector returning rows on
// all three rungs. Verified on 2026-10-26 by hand at 325.0 bps and 759 s
// for ZEC at 0.1 BTC, so the numbers are known, just not collected.
"privacy-round-trip",
// 208 perp liquidation rate: gated 2026-09-28 while the metric is rebuilt.
// The sources are right (the Gains decode reproduces to 0.02% against an
// independent scan, Lighter, GMX, Aster, Ostium, Nado and Orderly read
// their feeds) and the headline is not: a 24h window is meaningless on a
// venue whose nine-day total sits in three days, a book liquidated away
// inside the window makes the rate exceed 100% on any open-interest
// denominator, and notional over notional open interest mostly reports a
// venue's leverage policy (Gains: $39.5M of notional on $423k of
// collateral on 2026-09-28, median 73x). Un-gate condition: the headline
// is a 30-day flow over flow (liquidated notional over traded notional,
// 7-day companion) with collateral lost and median leverage published per
// venue where the source exposes them, open interest as context only,
// the page saying plainly that a high rate on a high-leverage venue
// reflects the leverage it offers, and an audit round on that board.
"perp-liq-rate",
// Bench 284 trading-agent-alpha was gated here on 2026-10-06 and released on
// 2026-10-07 with /trading-agents. The condition was a clean bench audit, a
// clean SEO audit and a second weekly round observed; all three were met,
// and a fourth was added along the way and met too: the table had to stop
// reading as a ranking, because zero of its 28 pairwise comparisons clears
// significance and the copy saying so could not outvote a sorted leaderboard
// with a bold first place. It is now grouped by lab, ordered alphabetically,
// and banners the tie above the table.
// Released 2026-09-23: bridges 261 (on-chain execution), 263 (realized
// cost), 264 (SOL->X quotes) and 268 terminal-fill-quality left this
// list with release/2026-09-23.
// 262 fiat on-ramp cost: two providers (MoonPay, Transak) with keys; the
// release condition is more than two keyed providers. Was held off main
// by its spec's absence there until release/2026-09-23 brought it.
"fiat-onramp-cost",
// 273 chain-bridged-tvl, 274 protocol-pf-ratio and 275 chain-stablecoin-flow
// left this list on 2026-09-25 (windows full, audit round clean).
// 280 chain fees and revenue: new gauges on the chain-kpis harness
// (2026-09-25), no 24h window yet and no audit round. Un-gate after both.
"chain-fees-revenue",
// 281 USDC corridor flows: first deploy of the bridge-flows harness
// (CCTP burns over public RPCs), the 7d window fills over its first
// week and no audit round yet. Un-gate after both.
"usdc-corridor-flows",
// 276 perp fee disclosure: the maker gauge is one deploy old and three
// of the eight rows have no maker rate at all. Un-gate after a 24h
// window and an audit round.
"perp-fee-disclosure",
// 310 server-wallet-cost: new 2026-10-29, server and agent wallet
// pricing. Un-gate after a harness cycle and its audit rounds.
"server-wallet-cost",
// 309 wallet-cost left this list on 2026-10-29, after its harness had
// run all day and three audit rounds (data and code twice, SEO once) had
// their findings fixed (#3361, #3365, #3367, #3369).
// Benches 203, 206, 207 and 232 left this list on 2026-10-07.
//
// They were gated on 2026-10-02 when the Dune trial ended, under a note
// saying they "have no free equivalent for what they measure". They were
// re-sourced the same week to the public tehcscreener API (Allium-backed,
// no key) via harnesses/terminal-activity: a different vendor, not a
// cheaper route to the same one. Bench 201 had already moved to DeFiLlama.
//
// Un-gated after the audit round rather than after a 24h window, because
// these four read instant gauges and declare no range selector: the only
// thing a day buys them is a complete chart, which is cosmetic. What the
// audit round caught is in #2843, #2844, #2846, #2848 and #2849.
//
// 206 and 207 were renamed on the way out, from solana-avg-trade-size and
// solana-unique-traders. Neither was ever served on production, so there is
// no signal to preserve and no redirect is owed: their default view is
// all-chains now and the old slugs claimed otherwise.
]);
/**
* Routes (whole pages, with their API) that stay off production the same
* way: the page renders notFound() on prod, the sitemap, the footer,
* llms.txt and the /rpc hub stop linking them there. Staging shows them.
*/
export const DEV_ONLY_ROUTES = new Set<string>([
// The map waits for its data; the speed test that produces it does not.
//
// Both shipped on 2026-09-30 to break the deadlock that had kept them
// off production since 2026-09-21: the speed test is the only source of
// contributions, so gating it guaranteed the map would never fill, and
// nine gated days had produced exactly zero samples. Publishing the
// test was the half that mattered. The map went with it and should not
// have: an honest empty state still asks a reader to look at a world
// map with nothing on it, which is a worse first impression than not
// offering the page at all.
//
// So /speedtest-rpc stays on production and keeps collecting, and the
// map comes back once there is something to draw. Collection does NOT
// depend on this line: /api/speedtest/contribute is gated on
// "/speedtest-rpc", and it derives the city cell server-side from
// Vercel's IP headers, so it needs neither the map page nor
// /api/speedtest/whereami (which only serves the map's "near me" pin).
//
// Un-gate condition: enough cells that the map reads as a map. Check
// with `curl .../api/speedtest/map?chain=ethereum` on staging, which
// reports `total` (every contribution ever) and `cells`. It was 0 and 0
// on 2026-09-30.
"/rpc-map",
// /trading-agents was gated here on 2026-10-06 and released on 2026-10-07
// together with its bench, which was the point: the aggregate blob is shared
// between environments, so an un-gated hub would have rendered a full table
// on production whose every row linked to a 404.
]);
export const IS_PRODUCTION = process.env.VERCEL_ENV === "production";
/** True when this deployment must not serve the bench. */
export function isDevOnlyBench(slug: string): boolean {
return IS_PRODUCTION && DEV_ONLY_BENCH_SLUGS.has(slug);
}
/** True when this deployment must not serve the route. */
export function isDevOnlyRoute(path: string): boolean {
return IS_PRODUCTION && DEV_ONLY_ROUTES.has(path);
}
export const REMOVED_BENCH_SLUGS = new Set([
// Thirteen chain RPC pages retired 2026-11-06. Each had no human visitor
// in PostHog between 2026-09-20 and 2026-11-06 (devices that clicked,
// viewed two pages or stayed over ten seconds; JS-running crawlers and
// our own device excluded), and nothing outside the site pointed at it:
//
// refused celo, taiko, kaia, bob, bitlayer, gravity, axelar, hedera,
// litecoin: a docs PR linking the page was closed unmerged
// no venue soneium, zircuit, merlin, comdex: no public docs repo and
// no issue tracker where a docs request belongs (comdex's
// org has not pushed since 2025-01)
//
// The probes were healthy (gravity aside, silent since 11-05), so this is
// a reach decision, not a data one. Specs and harness entries go; the
// chains stay in the registry wherever another bench measures them
// (bitlayer, merlin and comdex had nothing else and leave it). The slugs
// stay here so indexed URLs answer 410 Gone.
"celo-rpc",
"taiko-rpc",
"kaia-rpc",
"bob-rpc",
"bitlayer-rpc",
"gravity-rpc",
"axelar-rpc",
"hedera-rpc",
"litecoin-rpc",
"soneium-rpc",
"zircuit-rpc",
"merlin-rpc",
"comdex-rpc",
// Two chain RPC benches retired 2026-10-19: no keyless endpoint answers
// any more, re-tested by hand on the day.
//
// swellchain 1 of 4 alive: Ankr now requires a key (403), Sentio 404,
// Thirdweb refuses; only dRPC answers. Expired since 08-23.
// superseed 0 of 3: the official RPC and Thirdweb both front Conduit,
// which now demands a key (-32403); dRPC no longer serves
// the chain (-32601). Stale since 10-14.
//
// A second keyless provider was searched for on both (PublicNode,
// Tenderly, OnFinality, Alchemy public, the chains' own hosts) and none
// answered. Specs, harness entries and /chains pages go; the slugs stay
// here so indexed URLs answer 410 Gone. Un-gate condition: two public
// endpoints on the chain that answer us.
"swellchain-rpc",
"superseed-rpc",
// Blast (the L2) is being shut down, 2026-10-13. Its RPC bench goes,
// and so does every row the chain held elsewhere: l2-block-time,
// network-fees and chain-bridged-tvl, the /chains/blast page, the
// harness entries and the logo. The slug stays so an indexed URL
// answers 410 Gone. (Blast API, the RPC provider, was a separate
// company and left the benches in September.)
"blast-rpc",
// Six chain RPC benches retired 2026-10-02 after an audit of all 161.
// Each was probed on the usual schedule and produced nothing rankable:
// every declared endpoint was re-tested by hand on the day, and the
// chains below have no public RPC that answers us at all.
//
// quicksilver 0 of 3 endpoints alive, last sample 29 days old
// thundercore 0 of 3 (two answer 503), 24 days
// canto 0 of 1 (connection times out), 24 days
// neon 0 of 3, 8 days
// plume 0 of 1 (drpc answers 400), probe fresh
// zetachain 1 endpoint alive, 0.37 % success, probe fresh
//
// The last two are the interesting pair: the probe is running and the
// data is current, and what it says is that nobody answers. zetachain's
// one endpoint is Thirdweb, which serves browsers and refuses our probe
// hosts everywhere (0.3 % to 1.5 % across 29 chains, see #2779).
//
// Specs and harness entries deleted; the slugs stay here so an indexed
// URL answers 410 Gone rather than 404. Un-gate condition: a public
// endpoint on that chain that answers us. plume keeps its /chains page,
// which carries chain-bridged-tvl and chain-fees-revenue; the other five
// had nothing but the RPC bench and leave the chain registry with it.
"quicksilver-rpc",
"thundercore-rpc",
"canto-rpc",
"neon-rpc",
"plume-rpc",
"zetachain-rpc",
// retired for good
"bridge-revenue",
// duplicate of solana-tx-landing (bench 016); the 027 active-probe
// variant never got data on prod and shows an empty placeholder
"solana-tx-landing-latency",
// indexer-latency (084) dropped entirely 2026-07-16: HyperSync + The
// Graph providers require paid credentials for the sustained cadence
// (Mobula alone left the leaderboard single-provider). Spec + harness
// removed; kept in the 410 list so any indexed URL returns Gone
// instead of 404.
"indexer-latency",
// oracle-freshness (082) spec dropped 2026-07-16: apples vs oranges
// (push oracle Chainlink vs pull oracles Pyth/RedStone measure
// different things; splitting into 2 sub-benches would leave each
// with 1-2 providers). Redundant with 025 oracle-deviation which
// measures the same feeds via CEX deviation, more actionable signal.
// Harness code retained in oracle-deviation (metrics still emit, no
// reader on the site).
"oracle-freshness",
// tokenized-stock-arb-latency (080) dropped 2026-07-16 after ship-
// then-revert: Robinhood Chain tokenized equity pools are too
// illiquid (5 of 11 tickers had frozen pool prices, remaining 6 had
// p99 pinned at the 32min histogram cap because arbs rarely close
// within the settle window). Rob Chain launched Mar 2026, market
// still too young for an arb-latency bench. Spec deleted + arb_tracker
// removed from tokenized-stock-peg harness. Kept in 410 list for any
// indexed URL. Bench 077 tokenized-stock-peg + 079 weekend-drift
// (static peg measurements) stay on prod as the honest signal.
"tokenized-stock-arb-latency",
// token-trade-coverage (090) dropped 2026-07-24: self-baseline bias
// (Mobula pinned at 100% because it returned the highest raw counts).
// Spec + harness removed; rebuild needs RPC-derived ground truth.
"token-trade-coverage",
// cross-chain-messaging-latency dropped 2026-07-27: apples-to-oranges
// by construction. Each protocol self-reports via its own tracker
// (LZ Scan, Axelarscan, Hyperlane Nexus, CCIP Explorer) so there's
// no shared methodology, no independent ground truth. On top of that
// they don't measure the same thing (Hyperlane instant attestation
// vs CCIP structural finality wait) and rolling every source→dest
// pair into one p50 hides the story entirely. Spec deleted; the four
// per-protocol benches (axelar-gmp-latency, chainlink-ccip-latency,
// hyperlane-message-latency, layerzero-message-latency) + wormhole
// stay on prod as the honest signal.
"cross-chain-messaging-latency",
// solana-dex-quote-latency (029) held back 2026-07-24: OpenOcean 403s on
// Railway ASN (Cloudflare block, permanent), Raydium single-venue no-routes
// on the Pulse V2 bonded-token rotation. Board shows 2 of 4 providers as
// Unavailable which reads as "half broken" to visitors even though it's
// honest signal. Kept on dev/staging while we decide whether to swap in
// DFlow (needs partnership key) + drop the two dead providers.
"solana-dex-quote-latency",
// staging pipeline, held back until validated / announced
"explorer-chain-coverage",
"portfolio-chain-coverage",
// pm-data-freshness (bench 113) retired 2026-07: Predexon (the only
// measured data relay) discontinued. Spec + harness removed; kept in
// the 410 list so any indexed URL returns Gone instead of 404.
// Per-venue WS freshness now lives in pm-ws-latency (bench 114).
"pm-data-freshness",
// perp-open-interest retired 2026-07: multi-chain OI aggregation was
// structurally biased (each venue self-reports; no independent
// ground truth). Spec deleted; kept for indexed URL cleanup.
"perp-open-interest",
// pm-fee-comparison and pm-geographic-access dropped 2026-07
// (see PR #1663/#1664): fee-comparison was apples-to-oranges across
// venue types; geographic-access relied on ForecastEx geo blocks that
// changed without notice. Specs deleted.
"pm-fee-comparison",
"pm-geographic-access",
// polymarket-resolution-delay was drafted in a worktree but never merged
// to main. Answer pages originally referenced it; those were updated to
// pm-resolution-delay (2026-08-04). A 308 redirect covers inbound links.
// Adding here prevents stale Redis data from re-appearing in the sitemap.
"polymarket-resolution-delay",
// indexing-freshness (070) retired 2026-08-05: cohort reduced to 3
// providers (Zerion, Mobula, Allium) after GoldRush 402s and Moralis
// removal; a 3-provider bench is not strong enough signal for a
// standalone page. Spec kept for carry-forward; 410 on prod.
"indexing-freshness",
]);
/**
* Provider slugs whose /products/<slug> route should return 410 Gone
* rather than 404. Populated when a provider that once had a product
* page loses ALL its bench appearances.
*
* Enforced only in src/middleware.ts. The /products/[slug] page
* already calls notFound() when getProvider() returns null; this set
* exists purely to swap the resulting 404 for a 410 on prod.
*/
/**
* Alternatives pages whose /alternatives/<slug> route should return 410 Gone
* rather than 404.
*
* An alternatives page ranks the rows of the benchmark it declares, so it can
* only exist where those rows are providers.
*
* Enforced only in src/middleware.ts, like the sets below: the route already
* 404s once the spec file is gone, and this set swaps that for a 410 on prod.
*/
export const REMOVED_ALTERNATIVE_SLUGS = new Set([
// chainlink and pyth declared oracle-deviation, which does measure them but
// whose rows are the ten asset pairs it compares the oracles on. Both pages
// served "Top 5 Chainlink alternatives: XRP/USD, POL/USD, AVAX/USD, ..." on
// production. No other live bench carries a row for either, so there was
// nothing to repoint to. Both answered 200 and sat in the sitemap, so the
// URLs are indexed and need the 410.
"chainlink",
"pyth",
// jupiter declared solana-dex-quote-latency, dropped from the site in a
// hotfix, so the page already 404d. Jupiter is a row in
// token-quote-coverage, but four of that bench's ten rows are chains, so
// reviving it there would have listed "Solana" as a Jupiter alternative.
"jupiter",
]);
export const REMOVED_PRODUCT_SLUGS = new Set([
// Blast (the L2) left every bench on 2026-10-13. /products/blast used
// to 308 to /chains/blast; with the chain gone it rendered an
// indexable "Blast: chain benchmark" page from the worker's last blob.
"blast",
// bitquery was only referenced in bench 090 token-trade-coverage,
// dropped 2026-07-24. Product page was live briefly, so Google
// likely indexed the URL. 410 speeds de-indexing.
"bitquery",
// goldrush (Covalent) was removed from indexing-freshness bench in
// 2026-08-04 data-api report (PR #1758). Stale Redis data can keep
// the provider in getProviders() output while the page 404s; 410 guard
// + sitemap exclusion stop the smoke-gate rollback until Redis flushes.
"goldrush",
// enso left bench 033 on 2026-10-25, its only board, for the same reason
// as 0x below: a free-plan key out of credits (429 credit_quota_exceeded).
// It is measured nowhere now, so getProvider returns nothing and
// /products/enso 404s; it was a 200 in the sitemap. A registry entry is
// NOT enough to keep a product page alive: only PERP_VENUE_SEED and
// REGISTRY_STUB_SEED do that, and enso is in neither.
"enso",
// 0x left benches 304 and 033 on 2026-10-25, so it is measured nowhere
// and getProvider("0x") returns nothing: the page 404s instead of 410ing,
// and /products/0x was a 200 listed in the sitemap. Same shape as the
// goldrush note above and the reason it matters twice: the worker's blob
// keeps the provider in its product list for a sweep or two after the
// spec changes, so without this the sitemap keeps advertising a URL that
// has started 404ing, which is what rolled the Blast deploy back.
"0x",
// zerion and routescan appear in stale Redis results from retired benches
// (indexing-freshness for zerion, explorer-chain-coverage for routescan)
// but have no /products/<slug> page. 410 guard prevents smoke-gate failures.
"zerion",
"routescan",
]);