add stakely SVG logo (bench 092)#1343
Open
Flotapponnier wants to merge 96 commits into
Open
Conversation
…ll mode), network-fees
Robinhood Chain: hub entry + 3 bench integrations (cherry-pick)
…ockstep cache keys
ship solana-rpc to prod (bench 075, first non-EVM RPC)
* fix: 3 machine-readable surface bugs surfaced by GEO audit
1. /api/citable/{date} unit scaling.
Snapshot route emitted `value: 627` for `aggregator-head-lag` while the
live /api/citable emitted `value: 0.63` on the same measurement. The
live route already wraps with valueInDeclaredUnit(raw, b.unit) but the
snapshot route was left with the raw internal-ms value. Wrap the same
way; sub-1 s benches now render in the declared `s` unit on both routes.
2. /api/stat/{slug} silently ignored ?chain= / ?region= / ?kind= / ?venue=.
getBenchmark accepted a filters object but the route never parsed the
URL. A citer asking /api/stat/rpc-capabilities?chain=ethereum got the
cross-chain aggregate. Parse the four dimension params, pass through
to the loader; unknown values fall back to unfiltered inside the
loader. Also widen getBenchmark options type to include kind and
venue — the underlying loadBenchmark already supports both.
3. Draft benches leaked a fake freshness signal.
Draft placeholder set lastRunAt to new Date for type safety
(Benchmark.lastRunAt is non-null), and both citable routes passed it
straight through as asOf. LLM crawlers treating asOf as ground truth
would think a draft bench was measured every minute. Null asOf in the
JSON when status is draft; the internal type stays intact.
* fix: propagate draft-asOf null-out to /api/stat, MCP, JSON-LD dateModified
The GEO audit review found the initial fix in commit f6f84b8 only covered
the two /api/citable JSON surfaces, but the same "draft benches spoof
freshness" class of bug lives on three more machine-readable channels
that LLM crawlers also key on:
- /api/stat/{slug} asOf field.
- MCP tool responses (list_benchmarks, get_benchmark, resource template,
and the plain-text "Last sample" line).
- JSON-LD dateModified on the bench page, per-chain sub-page, answer
page and alternatives page — Google, Bing, Perplexity all consume
dateModified as a freshness ranking signal.
Centralize the guard as citableAsOf(b) in @/lib/citation, rewire every
call site. Draft benches now uniformly omit or null the freshness
timestamp; live benches unchanged. On the visible /answers page,
the "Data as of..." line and its <time dateTime> anchor also hide for
drafts rather than displaying the wall-clock placeholder.
Follow-up to PR #1154 (commit f6f84b8) covering the surfaces the review
agent flagged as still spoofing.
---------
Co-authored-by: Florent Tapponnier <contact@mobula.io>
* feat: /api/compare/{a}/{b} + openapi.json coverage
Two GEO surfaces flagged by the audit as high-value gaps.
## /api/compare/{a}/{b}
Head-to-head comparison as a single citable payload. LLMs asked "Mobula
vs Codex head lag" would otherwise need two /api/stat calls plus their
own delta reasoning; this endpoint returns one flat structure with per
benchmark p50 for each side, the winner on the metric's
higher-is-better convention, and the absolute delta.
The intersection logic mirrors src/lib/related-providers.ts and the
HTML /compare/{slug} page: shared benchmark = both providers appear in
it. Intentionally returns flat leader-p50 only (no chain/region
breakdowns, no cache-heavy fan out) so the agent tool call stays fast.
## openapi.json coverage
Added /api/citable/{date} (was missing despite being a real API
endpoint) and /api/compare/{a}/{b} to the OpenAPI 3.1 spec. Also
documented the dimension query params (chain/region/kind/venue) on
/api/stat/{slug} that shipped in the previous PR but were undocumented.
Added Compare schema; extended Stat schema with `filters` field.
/llms.txt and /llms-full.txt stay outside the OpenAPI surface — they
are text files not RPC endpoints, and OpenAPI consumers do not handle
plain-text specs well anyway.
## citableAsOf helper widened
Type signature relaxed from full Benchmark to
`Pick<Benchmark, "status" | "lastRunAt">` so the slim
ProviderAppearance.benchmark used by the new compare route can pass
through without a downcast. No behavior change on existing callers.
## Notes on items NOT shipped in this batch
- Cache-Control on /llms.txt / /api/citable / /api/llm-context: the
audit report showed `cache-control: public` and inferred no CDN
caching, but the source already sets
`public, s-maxage=300, stale-while-revalidate=900`. Vercel strips the
`s-maxage` directive from the client-visible header while honoring it
at the edge; `x-vercel-cache: HIT` with `age: 256` confirms the CDN
cache is active. Not a real bug.
- .bib / .ris file MIME endpoints: string versions already ship inside
the /api/stat JSON via cite.bibtex / cite.apa. Marginal upside for
Zotero-style one-click imports; downgraded to P2.
- /api/stat/{slug}/sparkline.svg: sparkline data already ships as a
float array in /api/stat and the OG image at /api/og/{slug} covers
the "embed a chart in an answer" case. P2.
- JSON-LD `Dataset.variableMeasured.value`: current schema emits bare
strings; upgrading to PropertyValue objects would duplicate the
measured value already carried by the StatisticalReport node's
Observation.measuredValue. P2.
* openapi: add totalWins to Compare schema
---------
Co-authored-by: Florent Tapponnier <contact@mobula.io>
* feat: Wave 1 P2 batch — .bib/.ris/apa MIME, sparkline SVG, Dataset PropertyValue
Three GEO surface additions the audit downgraded to P2. Each one is
duplicative with an existing channel (cite.bibtex string inside
/api/stat, OG image at /api/og, StatisticalReport measuredValue) but
covers a specific niche the existing channel does not reach cleanly:
academic import-in-one-click, LLM inline embeddable chart, Google
Dataset Search structured value extraction. Ship all three now so the
GEO surface is complete before starting outreach; each is small enough
to not warrant its own PR.
## /api/cite/{slug}/{format}
Per-bench citation with the correct MIME type. Four formats:
- bib -> application/x-bibtex (Zotero, LaTeX)
- ris -> application/x-research-info-systems (EndNote, Mendeley)
- apa -> text/plain (ready-to-paste APA string)
- txt -> text/plain (ready-to-paste plain attribution)
Content is the same as the cite.* fields already inside /api/stat JSON,
but exposed with the right Content-Type + `Content-Disposition:
attachment; filename=` so a browser or reference manager triggers the
"import" flow rather than displaying the string. Added RIS to CiteBundle
in src/lib/citation.ts (TY GEN neutral fallback, AU / TI / PY / UR / Y2
/ ER fields, CRLF line endings per RFC convention).
## /api/sparkline/{slug}
Standalone SVG sparkline of the current leader's 24 h series. Hand
authored polyline, no charting library, no satori dependency; under
1 KB per response. Query params: `w` (40..1200, default 240), `h`
(20..400, default 60), `theme=light|dark`. Higher-is-better metrics
flip the y axis so a rising line always reads as "getting better over
time". Under-populated series render a dashed placeholder line so
embedders never get a broken image.
Cases this reaches that /api/og and the raw JSON sparkline array do
not: img/svg inline embeds in Perplexity Pages, ChatGPT answers, dev.to
posts, Notion pages. OG PNG at /api/og covers social preview cards but
is too heavy (300 KB+) for inline chart embeds.
## Dataset.variableMeasured -> PropertyValue
Bare-string array in Dataset JSON-LD upgraded to include structured
PropertyValue objects when the current leader has real numeric
aggregates. Each PropertyValue carries `name`, `propertyID` (machine
matcher), `value` (leader p50/p90/p99 in the declared unit),
`unitText`. sample_size stays a bare string — it labels an axis, not a
measurement. Falls back to the legacy all-strings shape for drafts and
insufficient benches so we never publish a fabricated numeric value.
New helper: buildBenchVariableMeasured() in src/lib/dataset-jsonld.ts.
BenchDatasetInput.variableMeasured now accepts
Array<string | VariableMeasuredValue>. `keywords` extraction pulls the
`.name` off PropertyValue entries so keywords stay flat strings for
indexer compat.
## openapi.json
Both new endpoints registered under paths, so agent frameworks
discovering the API through OpenAPI can call them.
* sparkline: XML-escape bench title + provider name in SVG
---------
Co-authored-by: Florent Tapponnier <contact@mobula.io>
ship tokenized-stock-peg + weekend-drift to prod
…s to /chains/robinhood strip
ship subsidy KPIs on /chains/robinhood strip
ship RWA category + equity logos + product pages to prod
* rwa: xstocks-peg (077) + usdy-nav-basis (078), issuer label on the tsp metric family * bump lockstep cache keys for xstocks + usdy ship --------- Co-authored-by: Florent Tapponnier <contact@mobula.io>
publicnode.com burst-limits the VPS on getAccountInfo, dropping ~60% of samples. Two retries with 500ms backoff bring hit rate to >95% without switching endpoints. Also add commitment=confirmed to reduce slot-miss null returns. Co-authored-by: Florent Tapponnier <contact@mobula.io>
hyperliquid frontend page: show the frontend logo (cherry-pick)
pm-api-latency: add Predexon as 6th provider
sync: cherry-pick Predexon PM provider (#1166) to main
…1183) Cherry-picked from dev (#1179), adapted to main's rpc-capabilities shape (no bench 083 consensus/hash-quorum machinery on main yet). Extends rpc-capabilities to Polkadot, the first non-EVM, non-Solana chain in the cluster. Substrate JSON-RPC via chain_getHeader (returns hex-encoded block number matching EVM's eth_getBlockByNumber shape), staleness by relay-block gap (40 blocks, ~4 min at Polkadot's ~6 s cadence). Harness changes: - Chain.Kind gains "polkadot" alongside "solana" and default (EVM). - New callSubstrateHeader: chain_getHeader POST, parses hex block number, same latency measurement + result classification as EVM. - probeOne switches on Kind (was if solana / else). polkadot uses polkadotStaleBlockGap = 40. - Archive loop skipped for polkadot alongside solana: no eth_getBalance- by-depth equivalent on Substrate public endpoints. Providers at launch (3, live-verified 2026-07-15 with 4 consecutive chain_getHeader probes each, all returning block 0x1ea223d): - polkadot-official (Parity, rpc.polkadot.io) - onfinality (public gateway, Web3 Foundation grantee) - publicnode (Allnodes) Excluded by the launch audit: - 1RPC: filters chain_getHeader as "Not Allowed" on privacy relay - Dwellir: 503 during audit sweep, revisit - Ankr / Chainstack: paid tier / key-gated on Substrate - RadiumBlock / Grove / Thirdweb: referral header / invalid chain / key-gated Spec (benchmarks/polkadot-rpc.yml, bench № 086) copied from #1179 unchanged: 3-provider cohort, same schema as moonbeam-rpc etc. Post-merge: - Railway rpc-capabilities-{us,eu,sgp} auto-rebuild on this main push and start emitting rpc_latency_milliseconds{chain="polkadot"} metrics. - The bench 083 consensus path (dev-only for now) is not wired here; when dev syncs to main naturally, the polkadot switch case in probeOne already excludes consensus.observe correctly on that path. Co-authored-by: Florent Tapponnier <contact@mobula.io>
* polkadot-rpc bench 086 + /chains/polkadot + Parity product (#1184) * add bench 086 polkadot-rpc: first Substrate chain in the RPC cluster Extends rpc-capabilities to Polkadot, the first non-EVM, non-Solana chain in the cluster. Substrate JSON-RPC via chain_getHeader (returns hex-encoded block number matching EVM's eth_getBlockByNumber shape), staleness by relay-block gap (40 blocks, ~4 min at Polkadot's ~6 s cadence). Harness changes: - Chain.Kind gains "polkadot" alongside "solana" and default (EVM). - New callSubstrateHeader: chain_getHeader POST, parses hex block number, returns parentHash as the observed hash. Same latency measurement + result classification as the EVM path. - probeOne switches on Kind (was if solana / else). polkadot uses polkadotStaleBlockGap = 40. Consensus observation is skipped because chain_getHeader returns parentHash (N-1), not the current block hash (deriving current hash needs Blake2 over the SCALE- encoded header, out of scope). - Archive loop is skipped for polkadot the same way as solana: Polkadot state accesses via state_getStorage keyed by Blake2 storage keys, no chain-agnostic depth analog for eth_getBalance-by-depth. Providers at launch (3, live-verified on 2026-07-15 with four consecutive chain_getHeader probes each): - polkadot-official (Parity, rpc.polkadot.io) - onfinality (public gateway, Web3 Foundation grantee) - publicnode (Allnodes, extends its multi-chain footprint to Substrate keyless) Audited and excluded from the launch cohort: - 1RPC: filters chain_getHeader as "Not Allowed" on the privacy relay. Revisit if they expose a Substrate-friendly method set. - Dwellir: 503 Service Unavailable during the audit sweep, revisit once the gateway stabilises. - Ankr: paid Polkadot tier only. - Chainstack: key-gated on Substrate. - RadiumBlock: rejects without referral header. - Grove / Thirdweb: invalid-chain response. Spec (benchmarks/polkadot-rpc.yml, bench № 086): - Same schema as moonbeam-rpc / avalanche-rpc etc. so the parent rpc-capabilities benchmark, chain cluster page and hub card render it identically. - Methodology documents the Substrate specifics: probe method choice, staleness scaling, why no archive-depth or hash-quorum columns. - SEO/finding tokens use the standard {{best_name}} / {{best_p50}} / {{p50:slug}} template surface, consistent with other -rpc benches. - Provider tag copy explains OnFinality and Dwellir's Web3 Foundation grantee status so the leaderboard reads correctly for someone who knows the Polkadot infra landscape. Local checks: - go build ./... clean. - go test ./... clean. - bun test src/ - 95/95 pass across 10 files, including the citation reliability floor and consistency tests added in #1175. * polkadot page + parity/onfinality/dwellir products Wires the /chains/polkadot hub page, provider profiles, and logo assets that surface once bench 086 polkadot-rpc starts feeding Prom. - chains.ts: add Polkadot to CHAINS registry (L1, nativeSymbol DOT). Auto-populates /chains/polkadot once benches referencing chain="polkadot" land. Adaptive KPI strip fills in DefiLlama TVL, DEX volume and stables when the chain-kpis harness starts sourcing Polkadot alongside the other L1s. - provider-registry.ts: three new entries for the Polkadot cohort. * parity: brand entry for Parity Technologies (Polkadot / Substrate implementation shop, operator of rpc.polkadot.io). * polkadot-official: endpoint-level entry describing the reference rpc.polkadot.io keyless endpoint; providers.ts aliases the slug to parity so the /products page collapses under the operator's brand. * dwellir: brand entry for Dwellir (Web3 Foundation grantee, keyless Substrate infra) — excluded from the 086 launch cohort due to a 503 during the audit sweep but kept in the registry for the revisit and for other places their brand might appear. - providers.ts: add polkadot-official → parity alias and canonical brand casings for polkadot / parity / onfinality / dwellir so the /products hub, badges, and OG images render the correct name without the title-case fallback butchering them. - logo-manifest.ts: polkadot.png (chain hero), parity.png (product page logo), plus polkadot-official → parity slug alias so the endpoint chip on the bench page picks up Parity's mark automatically. 95/95 pass on bun test src/. Local build clean. --------- Co-authored-by: Florent Tapponnier <contact@mobula.io> * fix: dedup onfinality key in logo-manifest (already declared line 49) (#1186) Co-authored-by: Florent Tapponnier <contact@mobula.io> --------- Co-authored-by: Florent Tapponnier <contact@mobula.io>
…regate (9 draft benches stuck via AllBenchmarksDraftError loop) (#1190) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…ub) (#1191) (#1192) Ships live KPIs on /chains/polkadot. DOT price and mcap flow through Mobula. Stables card renders via DefiLlama Asset Hub aggregate. TVL and DEX gauges stay unpublished (relay chain has zero DeFi: parachain TVL lives under Acala, Moonbeam, Hydration). Also guards defillama TVL publish to skip zero values so chains that DefiLlama tracks by name but with an all zero series (Polkadot today) hide the TVL card instead of rendering $0. Co-authored-by: Florent Tapponnier <contact@mobula.io>
… Railway) (#1194) Cherry-picks the integrity/consensus code path from #1170 to main so Railway rebuilds the rpc-capabilities image and starts emitting rpc_integrity_check_total, rpc_hash_mismatch_total and rpc_consensus_lag_blocks. Bench 083 rpc-reliability reads these; on main today the metrics do not exist so the leaderboard is empty. Includes: * integrity.go: rotating eth_getLogs + eth_getBalance vector checks * consensus.go: cross-provider tip tracking + hash quorum mismatches * config, probe, archive, metrics: wiring + label updates * consensus_test.go: quorum resolution tests Building rpc-capabilities and running its tests passes on this branch. Co-authored-by: Florent Tapponnier <contact@mobula.io>
… (#1197) Per-chain siblings of bench 081 for the WebSocket head-lag cluster. Same harness (harnesses/ws-head-latency), same race scoring, one spec per chain to avoid mixing block cadences (Ethereum 12s vs Base 2s vs Solana 400ms) in a single leaderboard. Base cohort: PublicNode + dRPC keyless endpoints. Tenderly does not expose a keyless Base WebSocket path. Solana cohort: PublicNode + Solana Foundation. slotSubscribe replaces newHeads on the harness side; metric names are shared so the queries are structurally identical to the EVM specs. Data already flows via the Paris VPS deployment (chain label carries base and solana). No harness change needed for this ship. Multi-region is a follow-up on the parent bench. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…on support to main (#1199) Consolidates 3 dev merges (#1170 harness + #1196 per-chain benches + #1198 multi-region) so main matches dev on the ws-head-latency cluster: * benchmarks/ws-head-latency.yml: parent bench 081 (Ethereum) * benchmarks/ws-head-latency-base.yml: bench 087, adds regions arrays * benchmarks/ws-head-latency-solana.yml: bench 088, adds regions arrays * harnesses/ws-head-latency/: full harness (was dev only), including region ConstLabel from OCB_REGION or RAILWAY_REPLICA_REGION * railway.toml: Railway build config so the service can be created After merge, create the Railway ws-head-latency service with 3 replicas (us-east, eu-west, sgp), set OCB_REGION on each. Railway auto-builds from main, metrics start flowing per region. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…ot OCB_REGION) (#1200) Every other multi-region harness on Railway (rpc-capabilities, aggregator-head-lag, evm-swap-quoting, pm-rate-limits, etc.) reads REGION from env. Making ws-head-latency read REGION too keeps the Railway service config uniform across the whole harness fleet. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…s fanout on any failure (kills the SRH-burst Awaiting samples pattern) (#1306) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…') (#1307) Follow-up to #1302 — the slug rename to 'solana' worked but the spec's 'name' field was left as 'Solana Labs' / 'Solana Foundation', so the ledger still displayed the old branding. - solana-rpc.yml: name Solana Labs -> Solana - ws-head-latency-solana.yml: name Solana Foundation -> Solana Site display consolidates with the /chains/solana brand. Co-authored-by: Florent Tapponnier <contact@mobula.io>
… SRH from detail + filter render paths) (#1308) Co-authored-by: Florent Tapponnier <contact@mobula.io>
* drop mobula from all PM benches + PM hub (they stopped serving 2026-07-19) (#1310) Co-authored-by: Florent Tapponnier <contact@mobula.io> * drop codex-vs-mobula compare pair (only PM data-freshness had both, mobula now gone) (#1311) Co-authored-by: Florent Tapponnier <contact@mobula.io> --------- Co-authored-by: Florent Tapponnier <contact@mobula.io>
Co-authored-by: Florent Tapponnier <contact@mobula.io>
…rpc-hub-stats) via loadSnapshotFromBlob adapter (#1314) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…, GOOGL/SPY/TSLA tightest) (#1315) Prior copy claimed 'NVDA and TSLA drift the least' — NVDA now sits at rank 8 (272 bps p50) after fee-tier/depth shift on its pool. Update finding + FAQ: - Widest drifts: MU, AMD, PLTR, MSFT, AMZN, NVDA (all 2% fee tier, thin pools) - Tightest: GOOGL, SPY, TSLA (0.3% fee tier, deep pools) Data-narrative alignment before tweet asset generation. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…#1316) Fixed 50pt title collapsed into 2 lines for long titles (weekend-drift 72 chars) and combined with 11 rows, the title overlapped the top of the row list on the 630px canvas. Adds the same dense/veryDense responsive sizing as renderRanking: - title 50 -> 40 (dense: count>=8 or title>55) or 32 (veryDense: count>=10 or title>70) - value/name/rank fonts scale down proportionally - row gap 14 -> 10 -> 8 - bar height 8 -> 7 -> 6 - logo size 28 -> 24 -> 22 - rows anchored flex-start (was center) so tall title never pushes them off canvas Standard case (<=7 providers + short title) is unchanged. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…1317) Spec was missing the sample_size query so the ledger + share-card footer showed '0 SAMPLES' regardless of actual probe count. Adds count_over_time(tsp_deviation_bps{asset=X, market_state='closed'}[7d]) per provider — counts the number of closed-market samples over the past 7 days that feed the p50/p90/p99 aggregation window. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…cards) (#1318) Missing sample_size query made ledger + share-card footer show '0 SAMPLES' regardless of actual probe count. Fixed 5 specs, 47 provider blocks in total: - network-fees (15 chains) - xstocks-peg (12 assets) - tokenized-stock-peg (11 assets) - token-deployment-cost (7 chains) - usdy-nav-basis (2 providers) Pattern used: count_over_time(<base metric>{<same labels as p50>}[7d]) — counts underlying probe samples over the 7-day window that feeds the p50/p90/p99 aggregation. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…ori flex quirk) (#1319) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…k depth reality) (#1320) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…ls unreadable 'M C G M' rows) (#1321) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…ry/Codex/Moralis on Solana/EVM/Stellar) (#1327) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…1328) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…narrow .gitignore (#1329) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…ess, transactionHash, platform.name) + skip Moralis (per Florent) (#1330) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…entDisplayType; fix empty cursor param (#1331) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…E/FLOKI/BRETT/DEGEN/yXLM/SHX), flip status→live (#1332) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…a before /benchmarks/[slug] page can render aggregate — previous deploy 404'd and rolled back) (#1333) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…en-trade-coverage) (#1335) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…ser, page caps, api_calls_total counter for observability) (#1338) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…1339) Co-authored-by: Florent Tapponnier <contact@mobula.io>
Hyperliquid HyperEVM (chain 999): 5 keyless providers audited (hyperliquid-official, drpc, stakely, purroofgroup, hypurrscan). Standard EVM JSON-RPC via eth_getBlockByNumber. TRON JSON-RPC compat surface: 3 keyless providers audited (trongrid, drpc, publicnode). Native REST API surface out of scope for the RPC cluster; can add a tron-rest bench later. Bumps bench-unfiltered v37->v38, all-benchmarks v40->v41. Co-authored-by: Florent Tapponnier <contact@mobula.io>
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.
Real SVG from stakely.io/favicon.svg. Purroof Group and Hypurrscan don't expose SVGs (SPA fallback to HTML on /favicon.svg + /logo.svg), so they stay on the initials-chip fallback.