fix(build): break circular @/lib/chains → @/lib/spec causing prod TDZ - #712
Closed
Flotapponnier wants to merge 85 commits into
Closed
fix(build): break circular @/lib/chains → @/lib/spec causing prod TDZ#712Flotapponnier wants to merge 85 commits into
Flotapponnier wants to merge 85 commits into
Conversation
rss: ship /rss.xml feed for benchmark releases
…ee (#593) (#594) Adds the Near Intents 1Click API provider to both bridge benchmarks. Metrics will start populating once the bridge-monitor harness is redeployed with the nearintents_bridge.go integration shipped on mobula-api side and the NEARINTENTS_API_KEY env var set on Railway. Includes Near Protocol logo (public/logos/near-intents.svg), provider registry entry with longDescription + docs link, and YAML provider entries on both bridge-quote-latency and bridge-fee with the post-#584 avg(...) wrapper on success queries. SEO cohort copy updated to include Near Intents in both benches.
Adds a 'dimensions.chain' block to bridge-quote-latency and bridge-fee with values matching the harness chain label (Solana / Base / Arbitrum / HyperCore). The site UI surfaces this as clickable tabs. Why: the aggregate cross-corridor view is misleading on bridges with asymmetric per-corridor performance. Near Intents in particular is bimodal (Arb to HyperCore ~30ms via solver-cached bid, Sol to Base ~3000ms full auction wait), and the aggregate histogram quantile produced 175ms p50 which represents neither corridor. Requires the matching mobula-api PR (chain label emission in the bridge-monitor harness).
) (#598) Each destination chain in the current route set has exactly one source chain, so we can surface the full corridor (Sol to Base, Arb to HyperCore, etc.) in the tab label without changing the underlying dimension (still chain = destination, Prom label intact). User scans the tabs and knows immediately which route each tab represents instead of having to remember the route set.
…tab (#599) (#600) Two small UX fixes on the chain dimension: 1. Add a hypercore -> hyperliquid alias in logo-manifest.ts so the 'Arb to HyperCore' tab renders with the Hyperliquid logo. HyperCore is the trading engine of Hyperliquid, same brand. No new asset needed. 2. Drop the 'All routes' default tab. The aggregated cross-corridor view is mathematically valid but conceptually meaningless on these benches (Sol to Base ~3000ms and Arb to HyperCore ~30ms produce a histogram_quantile that lands at neither corridor). Per-corridor tabs are the honest default.
…#603) The route was redirecting to /api/llm-context, which is fine for permissive clients but breaks: - llms.txt validators (llmstxt-checker fails on non-200) - stricter AI crawlers (Perplexity, some Bing AI variants) that mark non-standard paths returning a redirect as no-content and skip - canonical attribution (AI engines citing the body now point at the internal /api/llm-context path instead of the public /llms-full.txt) Re-exports the GET handler from /api/llm-context so there is a single source of truth for the markdown body. No content change.
…#605) * fix(sitemap): pin <lastmod> to deploy time, not request time (#604) Sitemap runs on force-dynamic (to bypass Next's 2 MB Data Cache limit on the rendered output), which means `new Date()` at module init re-evaluates on every Google crawl. Effect: every URL had a freshly updated <lastmod> each visit, Google flagged the signal as unreliable sitewide and stopped using lastmod for recrawl prioritisation (confirmed behaviour, documented by Gary Illyes publicly). Fix: bake a build-time timestamp via next.config env injection, read it from process.env.NEXT_PUBLIC_BUILD_TIME in sitemap.ts. Stable per deploy, fresh per deploy. Per-bench <lastmod> still uses live bench.lastRunAt as before — that path was already correct. * release: hold solana-tx-landing-latency off main Bench and its dependent /alternatives + /answers pages held off main while the harness data quality / methodology is iterated on dev. Matches the existing release-hold pattern (see 12bb8a7). Files stay on dev untouched; dev to main merges will need to re-delete or skip. Removed: - benchmarks/solana-tx-landing-latency.yml - alternatives/jito.yml (benchmark: solana-tx-landing-latency) - alternatives/helius.yml (benchmark: solana-tx-landing-latency) - answers/which-solana-rpc-lands-the-most-transactions.yml
Fixes /api/citable returning all benchmarks as draft when /api/stat/<slug> for the same bench returns live data. Root cause: loadAllBenchmarksCached returned an all-draft set whenever per-bench fetches threw at cold start, and the cache then served that poisoned set for the rest of the 60s revalidate window. Restores the throw-on-all-draft behaviour at the cache boundary so unstable_cache keeps the previous good value during a Prom blackout. Adds an AllBenchmarksDraftError sentinel and a getBenchmarksSafe wrapper. Call sites split: - API endpoints and feeds (citable, llm-context, llms.txt, rss.xml) catch the sentinel and return 503 with retry-after, so downstream consumers do not treat the placeholder set as ground truth. - Pages (home, benchmarks index, bench slug, category, mcp page) and shared loaders (chains, providers) use getBenchmarksSafe which catches the sentinel and renders draft placeholders so the build and the page render still succeed. - Sitemap already uses safeLoad which catches and falls back. Cache key bumped from v12 to v13 to flush any poisoned snapshot already stored in Upstash KV. Adds a regression test that asserts the aggregator never returns a stable all-draft list. Extracted aggregateBenchmarks as a pure function so the test does not need Prometheus or unstable_cache.
…) (#617) * feat(rate-limit): bypass per-IP throttle for known AI crawler user agents * rate-limit: expand AI bot allowlist to match robots.txt Adds Meta-ExternalAgent, Meta-ExternalFetcher, cohere-ai, Perplexity-User (all already in robots.txt), plus AI2Bot, Ai2Bot-Dolma, Kagibot, FacebookBot, MistralAI-User, TimpiBot, Webzio-Extended for completeness. Comment now states the regex must stay in sync with src/app/robots.ts. Western LLM coverage is at ~95 percent after this. Chinese models other than ByteDance (Bytespider) do not publish a documented bot UA, so they fetch via generic browser UAs and stay throttled by design.
…#621) (#622) PR #613 left valid ad-hoc /compare/<a>-vs-<b> URLs serving HTTP 200 + a loading skeleton + noindex meta. With loading.tsx in place, Next 16 streams the skeleton with 200 before the page body's notFound() can demote the status. Plus generateMetadata only checked that both providers exist, missing the no-shared-bench case. This hotfix lands the same fix as PR #621 (dev) but inline on main's older file structure (no extracted compare-compute helper module yet). hasSharedBenches() is a pure set arithmetic helper on appearances, no Prom fan out. loading.tsx removal lets notFound() ship a real 404. Verified locally: /compare/alchemy-vs-quicknode -> 404 (quicknode missing) /compare/mobula-vs-coingecko -> 308 then 404 (coingecko missing) /compare/alchemy-vs-helius -> 404 (no shared bench) /compare/quicknode-vs-alchemy -> 308 to canonical /compare/binance-vs-bybit -> 200 real h1 (valid ad-hoc) /compare/ethereum-vs-solana -> 200 real h1 (curated)
) Live audit on prod showed /api/citable marking 25 of 26 benches as status=insufficient while /api/stat for the same slugs returned status=live with real leader values. Root cause: the per-bench loader and the aggregator loader compute sampleSize differently; when the aggregator falls back to a draft placeholder due to a cold Prom hit, the bench appears with sampleSize=0 even though per-bench cache holds fresh data. The check b.sampleSize===0 was then mass-flagging these benches as insufficient in /api/citable, /api/llm-context, /api/mcp. The other checks already catch the genuine empty case (liveResults length and p50 finiteness). Dropping the sampleSize check restores the 12 to 14 healthy benches that surfaced pre-regression.
- Aggregator throws AllBenchmarksDraftError when <50% of live specs produce a live bench (was: only when 0/N live). Prevents a mixed set like 2/26 live being cached for 60s while /api/stat returns live for the same slugs. - Bumped all-benchmarks cache key v13 to v14 to flush the current poisoned snapshot on prod. - Warm /api/citable, /api/llm-context, /api/mcp explicitly on prod deploy so the aggregator cache starts hot. - Added tests for the new quorum threshold.
Same files as #632 on dev, brought to main so the GitHub Actions cron schedule can fire (workflow_dispatch and on.schedule both require the workflow file to live on the default branch). No runtime code change. Only adds: - scripts/hf_publisher/* (Python daily snapshot script + tests) - .github/workflows/hf-publish.yml (cron + manual dispatch) - .gitignore (.venv exclusion)
…iders feat(pm): aggregator providers (Mobula, Predexon, Codex) on pm-api-latency
…n-bundle fix(build): trace YAML spec dirs so Vercel ships latest dev specs
…or-providers-prod chore: cherry-pick PM aggregator providers + YAML file tracing to prod
…gregators feat(pm): collapse aggregator providers + add venue filter
…m-prod chore: cherry-pick venue dimension + collapsed aggregators to prod
Brings the full /perps hub from dev to main: - /perps hub page with cohort summary, leaderboard, By asset tab, age badge - 3 new bench specs (perp-volume-share #41, perp-open-interest #42, perp-funding-stability #43) - Per-product PerpVenueSection wired into /products/<slug> for 16 perp DEX venues - 9 new perp DEX registry entries (drift, vertex, edgex, extended, aevo, pacifica, variational, ostium, grvt) - 13 logo assets, SVG-first - Footer + sitemap entries for /perps - Hub pill on per-product pages Backed by perp-cohort-stats harness on Railway (volume, OI, fees, active markets, funding via Mobula aggregator across 12 venues).
…r-prod feat(perps): cherry-pick perp cluster sprint 1+2 to prod
- perp-volume-share + perp-open-interest: query venue=gmx-v2 (harness label) instead of venue=gmx, so the GMX row stops returning /bin/zsh. - perp-funding-stability: replace 8 venues that have no funding source (dydx, paradex, aster, drift, vertex, edgex, extended, aevo) with the 8 Mobula funding cohort venues that DO publish perp_venue_funding_24h_bps (gate, lighter, kucoin, mexc, bitget, kraken, coinbase, deribit). The bench now has 12 real venues with data, was 4 of 12 with the rest blank.
…fixes-prod chore(prod): cherry-pick perp bench fixes (gmx slug + funding-stability cohort)
…cohort copy - src/lib/providers.ts: seed stub profiles for 9 perp cohort venues (drift, vertex, edgex, extended, aevo, pacifica, variational, ostium, grvt) that have no bench appearance. Without this, getProvider() returned undefined and /products/<slug> rendered 404 for every venue the cohort harness tracks but no bench specifically ranks. - benchmarks/perp-funding-stability.yml: fix cohort copy to honestly describe the Mobula funding aggregator scope (HL onchain + 11 CEX), not the onchain-perp cohort the original draft promised. - src/data/provider-registry.ts: vertex URL updated to www.nado.xyz after the rebrand (vertexprotocol.com returns 404). - src/app/perps/page.tsx: description says 16 perpetual DEXes, not 15 (off-by-one).
…3-fixes-prod chore(prod): cherry-pick perp Sprint 3 fixes (product pages + funding cohort copy)
- Bump providers cache key v1 to v2 so the PERP_VENUE_SEED added in PR #683 actually surfaces (Vercel ISR was serving the pre-seed cached profile list, which is why /products/drift etc. kept 404ing). - Loosen Vol/OI bands from 50/200 to 80/300 so zero-fee venues like Lighter (~115x today) read as elevated rather than wash-traded. Tooltip copy updated to explain the new thresholds. - Document the PromQL or-fallback mask risk on the perp funding query (P1 audit item, no behavior change today).
…bump-prod chore(prod): cherry-pick providers cache bump + vol/OI bands
Adds an Upstash-backed cohort snapshot layer so the two hub pages serve last-known-good data even when Prom blips. A Vercel cron writes a fresh JSON snapshot every minute; the readers (fetchPerpCohort, fetchHlCohort, fetchHlHip3Cohort) prefer the snapshot, fall through to live Prom on stale or missing blobs, and write back on success.
…rialize-prod chore(prod): cherry-pick cohort materialize for /perps + /hyperliquid
…loitte acquisition)
…ative chore(gas-estimation): drop Blocknative provider (cherry-pick from dev #693)
…ts (#695) PR #690 cherry-picked the cron route + the helper file but the helper shipped to main at src/lib/hl-builder-stats.ts while the route still imported from the dev-only path @/lib/benches/hyperliquid/builder-stats, which broke every prod build since (Turbopack module-not-found). Aligning the import path with the actual file location on main.
…ce (12 venues) + correct shuffled tags
success query: switched from perp_venue_health{venue} (only published
for cohort onchain venues, returned null for 11 CEX) to clamp_max(
count_over_time(perp_venue_funding_24h_bps{venue,asset=ETH}[1h]), 1).
Now returns 1 if any funding sample landed in the last hour for that
venue, works for all 12 venues. Bench was returning unknown_slug from
/api/stat because the missing health metric was failing the data
confidence check.
tags + formulas: 8 venues (gate, lighter, kucoin, mexc, bitget, kraken,
coinbase, deribit) had tags + formula venue references copied from the
onchain cohort by mistake (Lighter tagged 'Starknet L2', KuCoin 'BNB
Chain', MEXC 'Solana perp DEX', etc.). Restored to honest descriptions
matching each CEX's actual cadence.
…bility-fix-prod chore(prod): cherry-pick perp-funding-stability success query + tags fix
Bundles the search-experience work merged on dev into a single
cherry-pick to main. Includes:
- Cmd+K / Ctrl+K / '/' to open; ESC to close
- Wide input-pill trigger in the header (Linear-style, no shortcut badge)
- cmdk + Fuse.js fuzzy search over ~400-doc index (benchmarks, products,
alternatives, answers, chains, compare pairs, pages)
- Modal redesign: hairline border, single shadow, no accent focus ring
(opt-out from the global :focus-visible accent rule)
- Idle state: Recent (localStorage chips, X-to-remove, Clear) + Live
leaders (horizontal snap cards with leader logo + p50 from /api/citable)
+ Trending list (vertical, same data shape)
- Search state: results grouped by kind, each row gets the leader's
logo (benches) / entity logo (products/chains) / kind icon fallback
- Mobile: full-bleed sheet, footer hidden, X close button
- Open animation: handcrafted CSS keyframes (fade + 4px slide-down,
150ms ease-out), reduced-motion fallback
Template fix bundled (search-adjacent — surfaces description tokens):
- renderBenchmarkText now resolves seoTitle / seoDescription / subtitle /
methodology / disclaimer (Featured / Trending cards in the search
dialog were showing raw '{{best_name}}' tokens in description previews)
- Chain stash lookup case-insensitive (fixes perp-fees uppercase chain
values ETH/BTC/SOL)
- Bumped bench-unfiltered v11→v12 + all-benchmarks v15→v16 so the
cached snapshots regenerate through the wider resolver instead of
serving raw tokens for up to 300s after deploy
Deps:
- cmdk@^1.1.1, fuse.js@^7.4.2 (lockfile synced from dev)
Header redesign:
- Removed | separator between Contribute and GitHub
- 15px nav, h-16 desktop, backdrop-blur on the sticky
- GitHub icon-only, gap-spaced utilities
) The Toncoin → Gram (ticker TON → GRAM) rename took effect on 2026-06-15 via TON Vote (81% community support). The network itself stays branded TON / The Open Network; only the native token rebranded. We render 'Gram' everywhere visible (chain label, ticker, native symbol, copy) while keeping internal identifiers stable. Display layer (TON → Gram everywhere visible): - chains.ts: label 'TON' → 'Gram', nativeSymbol 'TON' → 'GRAM', description updated with 'formerly TON / Toncoin' continuity line. - provider-registry.ts: ton + tonapi descriptions updated. - benchmarks/l1-finality.yml: SEO + FAQ + per-chain explainer + provider entry display + abstract + methodology. - benchmarks/network-fees.yml: editorial + FAQ + per-chain explainer + fee tier copy + provider entry display (0.005 TON → 0.005 GRAM). - benchmarks/wallet-labels-coverage.yml: editorial + FAQ + per-chain explainer + chain dimension label + TonAPI provider tag. - answers/{cheapest-fees,fastest-finality}.yml: intro / FAQ / limitations. - l1-finality.md + harness READMEs: chain table + confidence audit copy. Logo + brand: - public/logos/ton.svg replaces ton.png (new Gram circular badge from ton.org/media; logo-manifest now points at the .svg). - brand.ts: ton color #0098EA → #30A1F5 to match the new mark. Kept stable on purpose (technical identifiers, ops contract): - slug 'ton' everywhere (URL, Prom queries, harness contract). - Prometheus label chain="ton" in all queries. - DefiLlama chain mapping ton → 'TON' (their API still uses 'TON'; tokenSymbol is already 'GRAM'). - API endpoints (tonapi.io, ton.org), twitter handles (@ton_blockchain, @tonapi_io) - all unchanged upstream. - Go function/type names (StartTONWallClock, tonState) and TON_API_KEY env var - renaming would require ops coordination + redeploy. SEO continuity: 'Gram (formerly TON)' phrasing in 1-2 anchor spots per page so search engines bridge the rename for 30+ days.
Privacy-friendly analytics (no cookies, no PII). Loaded async so it never blocks paint. Key is exposed as NEXT_PUBLIC_AHREFS_KEY (public by design, identifies the property not an account secret). Skipped entirely when the env var is unset so staging and preview deploys do not pollute the prod analytics graph.
chore(prod): cherry-pick Ahrefs Web Analytics
Follow-up to the TON → Gram display rebrand (#697). The 'Ton' label was still leaking into search results and the URL /chains/ton was visible to users. This PR renames the chain slug ton → gram with 301 redirects so inbound links + SEO rank signal consolidate onto the new canonical, and adds a Prom regex straddle so the existing harness keeps feeding live data through the transition. ## Slug rename (TS layer) - src/lib/chains.ts: slug 'ton' → 'gram' (label/description/native unchanged) - src/data/provider-registry.ts: rekey ton → gram - src/lib/logo-manifest.ts: gram → /logos/ton.svg (file kept, slug renamed) - src/lib/brand.ts: rekey color entry - src/lib/chain-kpis.ts: rekey to gram, DefiLlama API string stays 'TON' (verified live) - src/lib/providers.ts: - CANONICAL_NAMES: gram → 'Gram', tonapi → 'TonAPI' (was title-casing to 'Tonapi') - PRODUCT_ALIASES: ton → gram (stale inbound references resolve to canonical) ## Redirects (next.config.ts) - /chains/ton → /chains/gram (308 permanent) - /products/ton → /chains/gram (308 permanent) - /benchmarks/:slug/ton → /benchmarks/:slug/gram (308 permanent) - CHAIN_REDIRECT_SLUGS: ton → gram so /products/gram keeps redirecting to /chains/gram ## Bench YAMLs - per_chain_explainer.slug: ton → gram (matches the new /benchmarks/<bench>/gram URL) - provider entry slug: ton → gram (matches CHAINS new slug for surfaces that ref by slug) - Template refs {{p50:ton}} → {{p50:gram}} - Prom queries: chain="ton" → chain=~"ton|gram" (straddle during harness relabel window; the regex matches the current chain="ton" labels and the future chain="gram" labels, so the bench keeps rendering live data with no gap) - wallet-labels-coverage dimension value stays 'ton' (Prom label the harness emits at runtime; flip to 'gram' once the harness redeploys) ## Out of scope (separate harness PR) The harness Go code in harnesses/l1-finality/ and harnesses/network-fees/ emits chain="ton" labels. Updating those is a separate Railway redeploy. The straddle regex covers the transition with zero data gap. ## Test plan - [ ] Cmd+K, type 'gram' → top result reads 'Gram' chain (no more 'Ton'). - [ ] /chains/ton → 308 → /chains/gram (page renders with Gram badge, leader, p50). - [ ] /products/ton → 308 → /chains/gram. - [ ] /benchmarks/l1-finality/gram → renders per-chain explainer. - [ ] /benchmarks/l1-finality leaderboard row Gram still has live p50 (Prom straddle works). - [ ] No regression on other chains in same benches.
rename chain slug ton → gram + 301 redirects + Prom straddle
…benchmarks payload) (#706) * chore(benchmarks): drop solana-tx-landing-latency (harness offline, 404 bleeding SEO) (#701) * perf(benchmarks): slim card projection cuts /benchmarks payload 3.2MB to 280KB (#704) * fix(types): widen isInsufficient to accept BenchmarkCardData slim shape Cherry-pick fallout: #704 introduced BenchmarkCardData (slim projection for the hub) but main's isInsufficient still required full Benchmark. The hub card calls isInsufficient(b) where b is the slim type, which typecheck rejected. Widening the predicate input to a structural subset lets both Benchmark and BenchmarkCardData pass without losing the runtime behavior.
Fixes the slow Live Leaders skeleton: dialog used to fetch /api/citable
on every open (~50 KB, full benchmark assembly server-side, frequently
visible 1-2 s skeleton). Now a Vercel cron pre-builds a 12-card subset
every minute, persists it as a single Upstash KV blob, and the dialog
opens with data already prefetched at page load.
Architecture:
- src/lib/search-featured.ts: builds the slim blob (featured + trending
cards: slug, title, category, unit, value, leader). Single source of
truth for the dialog's hardcoded slug lists.
- src/app/api/cron/warm-search-featured/route.ts: every minute, calls
buildFeaturedLeaders + writeCohortSnapshot('search-featured'). Same
CRON_SECRET gate + soft-no-op-on-missing-creds pattern as the existing
cohort cron jobs.
- src/app/api/search/featured/route.ts: KV-first reader with live-build
fallback (cold-start safety). Aggressive edge cache (s-maxage=60,
swr=300) — most requests served by Vercel edge with zero origin hit.
- SearchProvider: prefetches /api/search/featured at mount (idempotent)
and exposes featured + prefetchFeatured via context. Re-fetch hook on
trigger hover/focus.
- SearchTrigger: onMouseEnter + onFocus call prefetchFeatured. Dialog
almost always opens with the blob in memory; the brief 'skeleton'
state is now invisible to the user.
- SearchDialog: consumes featured/trending arrays from context (zipped
against the search index), drops the per-mount /api/citable fetch.
Search-results rows still get leader logos via the same warmed blob
when the bench appears in featured/trending; otherwise fall back to
the kind-icon (no extra API calls).
- vercel.json: cron schedule * * * * * for warm-search-featured.
Graceful degradation:
- No CRON_SECRET / no Upstash creds → cron 200s with configured:false,
endpoint falls through to live build path, dialog still works.
- Upstash unreachable → endpoint falls through to live build, same UX
as the old /api/citable path (slow but functional).
- Worker dies → endpoint serves last-good KV until 24h safety TTL
expires, then falls through to live build.
Payload size: ~50 KB (/api/citable, full index) → ~2 KB
(/api/search/featured, 12 cards).
TTFB: ~1-2 s server-side assembly → ~5-10 ms KV GET (edge-hit: ~0 ms).
Diagnostic: after PR #705 (chain slug ton → gram), /chains/gram 404s and /benchmarks/network-fees still renders 'TON' in chain headings. Two root causes: 1. getBenchmarksForChain('gram') filters results[].slug === 'gram', but the materialize worker's KV snapshots still hold the legacy results[].slug === 'ton' (worker on Railway runs from the private mobula-api repo; it hasn't redeployed with the renamed YAML yet). → 0 matches → notFound() at chains/[slug]/page.tsx:90. 2. ChainHeadingsSummary renders r.name verbatim. Stored snapshots still carry name='TON', so the heading reads 'TON native transfer fee usd' even though chains.ts now says label='Gram'. Fix: introduce a chain-slug alias system so the canonical layer absorbs the rebrand without waiting on the harness. - src/lib/chains.ts: - CHAIN_SLUG_ALIASES { ton: 'gram' } — single source of truth. - canonicalChainSlug(slug) and chainLabelForSlug(slug) helpers. - getBenchmarksForChain now matches on the canonical slug + any legacy alias, so /chains/gram surfaces benches whose stored results still carry slug='ton'. - src/lib/spec.ts: - overlayEditorial reconciles stale stored results against the current spec. For each result whose slug is a known legacy alias (e.g. 'ton'), look up the spec provider by canonical slug ('gram'), rewrite result.slug + result.name to match. Downstream surfaces (leaderboard table, search dialog, ChainHeadings) all see the canonical identity without any per-component patch. - Cache keys bumped bench-unfiltered v12 → v13 and all-benchmarks v16 → v17 so the unstable_cache regenerates through the new reconciliation path on deploy. - src/components/chain-headings-summary.tsx: - Anchor id, link URL, and explainer lookup go through canonicalChainSlug so a stale 'ton' result still hits the renamed 'gram' explainer + lands at /benchmarks/<bench>/gram. - Display name resolves through chainLabelForSlug, with the bench result name as a fallback. Renders 'Gram' the moment chains.ts is updated — no wait on the materialize worker. Test plan: - /chains/gram → 200 with l1-finality + network-fees in the list. - /benchmarks/network-fees → chain heading reads 'Gram transaction fee usd', anchor id='gram', link to /benchmarks/network-fees/gram. - /api/citable still returns rows for both old + new slug surfaces (no impact on machine-readable consumers). - Harness on Railway can stay on chain='ton' label; the existing Prom regex straddle (PR #705) keeps queries hitting both labels.
…h 036 metric) perp_venue_funding_24h_bps from the new perp-cohort-stats harness was not reaching OCB Prom reliably after the recent harness redeploys, so the bench returned all-null. The bench now uses perp_funding_hold_24h_bps which the established perp-funding bench 036 already publishes for 7 venues (Hyperliquid, Binance, Bybit, OKX, dYdX v4, Paradex, Aster). Cohort trimmed to those 7 to match the data that actually exists in Prom. Drops the 5 venues that only had Mobula-sourced funding (gate, lighter, kucoin, mexc, bitget, kraken, coinbase, deribit) since the new metric was not reliably scraped. Future revision can re-add them once the perp_venue_funding_24h_bps scrape is verified end-to-end.
spec.ts imported canonicalChainSlug from @/lib/chains. chains.ts in
turn imports getBenchmarksSafe from @/data/benchmarks which imports
loadBenchmark from @/lib/spec. Webpack collapsed the cycle into a
chunk whose init order tripped a TDZ on the /alternatives/[slug]/
opengraph-image route ('Cannot access ec before initialization'),
breaking every prod deploy since PR #708.
Fix: extract CHAIN_SLUG_ALIASES + canonicalChainSlug into a tiny
@/lib/chain-aliases module with zero external imports. spec.ts now
imports from there. chains.ts re-exports for backward compatibility
so no consumer needs a path change.
Collaborator
Author
|
Superseded by #711 (same fix landed independently). Closing. |
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.
PR #708 introduced spec.ts → chains.ts → data/benchmarks → spec.ts cycle, hitting Cannot access 'ec' before initialization on /alternatives OG image and blocking every Vercel prod deploy since. Extract the slug-alias helpers to a standalone module with no deps.