diff --git a/src/lib/removed-benches.ts b/src/lib/removed-benches.ts index 4e653817..367823bb 100644 --- a/src/lib/removed-benches.ts +++ b/src/lib/removed-benches.ts @@ -81,9 +81,30 @@ export const REMOVED_BENCH_SLUGS = new Set([ // 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", // staging pipeline, held back until validated / announced "indexing-freshness", "rpc-keyed-latency", "explorer-chain-coverage", "portfolio-chain-coverage", ]); + +/** + * Provider slugs whose /products/ 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. + */ +export const REMOVED_PRODUCT_SLUGS = new Set([ + // 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", +]); + diff --git a/src/middleware.ts b/src/middleware.ts index ef9a4715..6c940da7 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -51,12 +51,14 @@ const CANONICAL_NO_QUERY = new Set([ import { REMOVED_ANSWER_SLUGS, REMOVED_BENCH_SLUGS, + REMOVED_PRODUCT_SLUGS, RENAMED_BENCH_SLUGS, } from "@/lib/removed-benches"; export { REMOVED_BENCH_SLUGS }; const BENCH_PATH = /^\/benchmarks\/([a-z0-9][a-z0-9-]{0,79})\/?$/; const ANSWER_PATH = /^\/answers\/([a-z0-9][a-z0-9-]{0,79})\/?$/; +const PRODUCT_PATH = /^\/products\/([a-z0-9][a-z0-9-]{0,79})\/?$/; // `/compare/-vs-` with both sides as standard provider slug // shapes (lowercase alphanumeric + hyphens). The `-vs-` delimiter is // matched literally; provider slugs themselves can contain hyphens @@ -93,6 +95,13 @@ export function middleware(req: NextRequest) { { status: 410, headers: { "Content-Type": "text/html; charset=utf-8" } }, ); } + const p = pathname.match(PRODUCT_PATH); + if (p && REMOVED_PRODUCT_SLUGS.has(p[1])) { + return new NextResponse( + `410 Gone

410 Gone

This product page has been retired because the provider is no longer measured in any active benchmark. See the current catalog.

`, + { status: 410, headers: { "Content-Type": "text/html; charset=utf-8" } }, + ); + } } const compareMatch = pathname.match(COMPARE_PATH); @@ -130,5 +139,6 @@ export const config = { "/benchmarks/:slug*", "/answers/:slug*", "/compare/:slug*", + "/products/:slug*", ], };