From 05a7755ad8cf9aaec6620aac7b1b0445e2e68f70 Mon Sep 17 00:00:00 2001 From: Florent Tapponnier Date: Fri, 17 Jul 2026 15:49:15 +0200 Subject: [PATCH] products: skip degraded-read tripwire when every appearance is unresponsive The tripwire on the /products/[slug] route throws when a provider has 3+ appearances all with rank=0, assuming the pattern means the store read failed mid-render. For Cloudflare's public Ethereum gateway (recently switched to permissioned mode, returns -32046 on most JSON-RPC methods), the pattern is real: every bench that ranks it lands rank=0 because every probe fails. That single 500 has been tripping the sitemap smoke test on every prod deploy for 24h, auto-rolling back every merge to main including the SEO pack and the ticker sanity clamp. Skip the tripwire when every appearance is explicitly marked unresponsive or availability=unavailable. Real store failures leave those flags unset, so this preserves the guard's original intent without blocking prod on a genuinely dead provider. --- src/app/products/[slug]/page.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/app/products/[slug]/page.tsx b/src/app/products/[slug]/page.tsx index 4496b357..42fb1756 100644 --- a/src/app/products/[slug]/page.tsx +++ b/src/app/products/[slug]/page.tsx @@ -181,7 +181,23 @@ export default async function ProviderPage({ // is warming up. Throwing here makes the ISR revalidation fail, so // Vercel keeps serving the last good render instead of caching a page // full of "data warming up" for the next 5 minutes. - if (p.appearances.length >= 3 && p.appearances.every((a) => a.rank === 0)) { + // + // Exception: providers whose endpoint is legitimately broken (Cloudflare + // returns -32046 on most RPC methods, permissioned-mode gateways refuse + // reads, etc.) show up with `unresponsive: true` or `availability: + // "unavailable"` on every appearance. That's real data, not a store + // read failure, and firing the tripwire on it blocks every prod deploy + // because the sitemap smoke test catches the 500 and auto-rollbacks. + const allUnresponsive = p.appearances.every( + (a) => + a.result.unresponsive === true || + a.result.availability === "unavailable", + ); + if ( + p.appearances.length >= 3 && + p.appearances.every((a) => a.rank === 0) && + !allUnresponsive + ) { throw new Error(`degraded store read for /products/${slug}: ${p.appearances.length} appearances, all unranked`); }