From a3137d6c65eee50a431ca171e608dd52278f50f9 Mon Sep 17 00:00:00 2001
From: Florent Tapponnier
Date: Fri, 10 Jul 2026 18:42:22 +0200
Subject: [PATCH 1/5] mev-protect: coverage panel query needs a selector for
the loader splice (bare function call produced invalid promql)
---
benchmarks/mev-protect-rpc.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/benchmarks/mev-protect-rpc.yml b/benchmarks/mev-protect-rpc.yml
index e490e236..683b7098 100644
--- a/benchmarks/mev-protect-rpc.yml
+++ b/benchmarks/mev-protect-rpc.yml
@@ -84,7 +84,7 @@ dimensions:
metric_panels:
- id: coverage
label: Method coverage
- metric: avg(mev_rpc_methods_supported)
+ metric: avg(mev_rpc_methods_supported{benchmark="mev-protect-rpc"})
label_key: provider
unit: count
higher_is_better: true
From c935e5b2f54ffffdb98c0b6238c50265071e2aa8 Mon Sep 17 00:00:00 2001
From: Flotapponnier <160007691+Flotapponnier@users.noreply.github.com>
Date: Fri, 10 Jul 2026 18:45:11 +0200
Subject: [PATCH 2/5] infobox: collapsible card design with one-line summary
(#1092)
Replaces the flat wide table with a native card that
collapses to a one line summary (label + current leader) and expands
to a compact two-column key/value grid. Fixes the visual weight problem
where the original table dominated the page above the fold.
Design details:
- Default open so first-time readers see the facts without interacting
- Summary shows the leader claim so the quick answer never requires a
click to reveal
- Two-column grid on desktop, single column on mobile
- Custom chevron rotates 180 degrees when open (native marker hidden)
- All microdata + itemProp attributes preserved so LLM crawlers see
the content whatever the visual state
- Same schema.org Dataset itemtype so Google Rich Results still parses
No behaviour change for JSON-LD or the visible TL;DR block. Only the
infobox component and its call-site comment change.
Co-authored-by: Florent Tapponnier
---
src/app/benchmarks/[slug]/page.tsx | 15 +--
src/components/bench-infobox.tsx | 168 +++++++++++++++++++----------
2 files changed, 118 insertions(+), 65 deletions(-)
diff --git a/src/app/benchmarks/[slug]/page.tsx b/src/app/benchmarks/[slug]/page.tsx
index 1ed970be..80f60996 100644
--- a/src/app/benchmarks/[slug]/page.tsx
+++ b/src/app/benchmarks/[slug]/page.tsx
@@ -463,12 +463,15 @@ export default async function BenchmarkPage({
{benchmark.subtitle}
- {/* Wikipedia-style infobox. Floats right on desktop next to the
- TL;DR and the intro copy, stacks above on mobile. Table markup
- + microdata make the key/value pairs extractable by LLM
- crawlers verbatim (Perplexity, Gemini, ChatGPT-with-web all
- hoist this format from Wikipedia pages when composing answers)
- while giving readers a two second scan of the headline facts. */}
+ {/* Compact "At a glance" card. Rendered as a native
+ element so it collapses to a one line summary on click while
+ still shipping the full microdata + key/value pairs inside the
+ collapsed body (LLM crawlers see the content whatever the
+ visual state). Sits between the subtitle and the TL;DR
+ grounding trace so a reader has: headline claim (H1) → context
+ (subtitle) → at-a-glance facts (this card) → canonical
+ grounding sentence (TL;DR) before entering the leaderboard
+ body. */}
{/* Visible grounding-trace TL;DR. Renders the same canonical line
diff --git a/src/components/bench-infobox.tsx b/src/components/bench-infobox.tsx
index 78697e08..d1f45286 100644
--- a/src/components/bench-infobox.tsx
+++ b/src/components/bench-infobox.tsx
@@ -4,26 +4,24 @@ import { fmtUnit } from "@/lib/format";
import { SITE } from "@/data/site";
/**
- * Wikipedia-style infobox for benchmark pages. A compact `
` of
- * key/value pairs that sits directly under the H1/subtitle and above the
- * TL;DR grounding trace.
+ * Compact "At a glance" card that sits under the H1/subtitle on every
+ * benchmark page. Wrapped in a native element so it collapses
+ * to a one-line summary and expands to the full key/value grid on click.
*
* Why this shape:
- * - LLM crawlers (Perplexity, Gemini, ChatGPT-with-web) extract Wikipedia
- * infoboxes almost verbatim because they are `
` markup with
- * `
`/`
` label/value pairs sitting above the fold, before any
- * prose. Copying the shape is the single highest-leverage change
- * identified in the July 2026 GEO deep-dive.
- * - Users get a two-second scan of the key facts (leader, metric, last
- * measured, license) without scrolling into the leaderboard body, so
- * the UX gain is real and not just an SEO trick.
- * - `itemscope` + `itemtype="https://schema.org/Dataset"` layers a
- * microdata graph over the DOM in addition to the JSON-LD block, which
- * some crawlers prefer.
+ * - Language models parse the content inside whether it is
+ * visually expanded or not, so the LLM-grounding pattern (Wikipedia
+ * infobox-style key/value pairs directly under the H1) is preserved
+ * in either state.
+ * - Human readers get a scannable one-line teaser that a click reveals
+ * into a compact card. The default is expanded so first-time visitors
+ * see the facts without having to interact.
+ * - itemscope + itemtype layer a schema.org Dataset microdata graph
+ * over the DOM in addition to the JSON-LD block so crawlers that
+ * parse microdata pick up the same facts.
*
- * Hidden gracefully when the bench has no defensible leader (draft,
- * insufficient, awaiting first run) so the rendered box never publishes
- * a fabricated leader row.
+ * Renders nothing when the bench has no defensible leader (draft,
+ * insufficient, awaiting) so we never publish a fabricated leader row.
*/
export function BenchInfobox({ benchmark }: { benchmark: Benchmark }) {
const top = leader(benchmark);
@@ -33,54 +31,103 @@ export function BenchInfobox({ benchmark }: { benchmark: Benchmark }) {
const lastRunIso = benchmark.lastRunAt
? new Date(benchmark.lastRunAt).toISOString()
: null;
- const lastRunDisplay = lastRunIso ? lastRunIso.replace("T", " ").slice(0, 19) + " UTC" : "n/a";
+ const lastRunDisplay = lastRunIso
+ ? lastRunIso.replace("T", " ").slice(0, 19) + " UTC"
+ : "n/a";
return (
);
}
-function InfoRow({
+function InfoPair({
label,
children,
+ className,
}: {
label: string;
children: React.ReactNode;
+ className?: string;
}) {
return (
-
-
+
{label}
-
-
{children}
-
+
+ {children}
+
);
}
From 2a593b4f3d35be1579a6fcac06407034d86e1d27 Mon Sep 17 00:00:00 2001
From: Florent Tapponnier
Date: Fri, 10 Jul 2026 19:00:58 +0200
Subject: [PATCH 3/5] mev-protect: success rate excludes policy-refused methods
(coverage is the panel, reliability is the column)
---
benchmarks/mev-protect-rpc.yml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/benchmarks/mev-protect-rpc.yml b/benchmarks/mev-protect-rpc.yml
index 683b7098..cd4751a4 100644
--- a/benchmarks/mev-protect-rpc.yml
+++ b/benchmarks/mev-protect-rpc.yml
@@ -46,7 +46,7 @@ methodology:
- "Headline: median latency across the methods the provider served that tick, aggregated over 24h with quantile_over_time. A rejected method does not poison the latency; it lowers the coverage panel instead."
- "Coverage: mev_rpc_methods_supported counts the wallet methods served on the last tick (max 7). Flashbots rejects eth_call on the public endpoint; Blink blocks full-node reads like eth_getBlockByNumber, which keeps it off the general RPC benches but not off this one."
- "Out of scope, disclosed: inclusion rate, refund economics and sandwich protection efficacy are the write path and require funded transactions. See the arXiv study Private MEV Protection RPCs (2505.19708) for a one-off execution-quality comparison."
- - "Failures (timeouts, 403, 429) increment mev_rpc_call_total{result} and count against the success rate; the gauge keeps its last value so the chart shows the outage in the success column rather than a fake zero."
+ - "Success rate counts transport failures only (timeouts, throttling, network); a method a gateway refuses by policy is a coverage gap shown in the coverage panel, not an outage. Failures increment mev_rpc_call_total{result}; the gauge keeps its last value so the chart shows the outage in the success column rather than a fake zero."
findings:
- "{{best_name}} leads at {{best_p50}} (p50, 24h) on the cross-region wallet call median over {{count}} measured gateways."
@@ -100,7 +100,7 @@ providers:
p90: quantile_over_time(0.90, mev_rpc_wallet_latency_milliseconds{provider="flashbots"}[24h])
p99: quantile_over_time(0.99, mev_rpc_wallet_latency_milliseconds{provider="flashbots"}[24h])
mean: avg_over_time(mev_rpc_wallet_latency_milliseconds{provider="flashbots"}[24h])
- success: sum(increase(mev_rpc_call_total{provider="flashbots",result="ok"}[24h])) / clamp_min(sum(increase(mev_rpc_call_total{provider="flashbots"}[24h])), 1)
+ success: sum(increase(mev_rpc_call_total{provider="flashbots",result="ok"}[24h])) / clamp_min(sum(increase(mev_rpc_call_total{provider="flashbots",result!~"blocked|method_not_found"}[24h])), 1)
sample_size: sum(increase(mev_rpc_call_total{provider="flashbots"}[24h]))
series: avg(avg_over_time(mev_rpc_wallet_latency_milliseconds{provider="flashbots"}[1h]))
regions:
@@ -123,7 +123,7 @@ providers:
p90: quantile_over_time(0.90, mev_rpc_wallet_latency_milliseconds{provider="mevblocker"}[24h])
p99: quantile_over_time(0.99, mev_rpc_wallet_latency_milliseconds{provider="mevblocker"}[24h])
mean: avg_over_time(mev_rpc_wallet_latency_milliseconds{provider="mevblocker"}[24h])
- success: sum(increase(mev_rpc_call_total{provider="mevblocker",result="ok"}[24h])) / clamp_min(sum(increase(mev_rpc_call_total{provider="mevblocker"}[24h])), 1)
+ success: sum(increase(mev_rpc_call_total{provider="mevblocker",result="ok"}[24h])) / clamp_min(sum(increase(mev_rpc_call_total{provider="mevblocker",result!~"blocked|method_not_found"}[24h])), 1)
sample_size: sum(increase(mev_rpc_call_total{provider="mevblocker"}[24h]))
series: avg(avg_over_time(mev_rpc_wallet_latency_milliseconds{provider="mevblocker"}[1h]))
regions:
@@ -146,7 +146,7 @@ providers:
p90: quantile_over_time(0.90, mev_rpc_wallet_latency_milliseconds{provider="blinklabs"}[24h])
p99: quantile_over_time(0.99, mev_rpc_wallet_latency_milliseconds{provider="blinklabs"}[24h])
mean: avg_over_time(mev_rpc_wallet_latency_milliseconds{provider="blinklabs"}[24h])
- success: sum(increase(mev_rpc_call_total{provider="blinklabs",result="ok"}[24h])) / clamp_min(sum(increase(mev_rpc_call_total{provider="blinklabs"}[24h])), 1)
+ success: sum(increase(mev_rpc_call_total{provider="blinklabs",result="ok"}[24h])) / clamp_min(sum(increase(mev_rpc_call_total{provider="blinklabs",result!~"blocked|method_not_found"}[24h])), 1)
sample_size: sum(increase(mev_rpc_call_total{provider="blinklabs"}[24h]))
series: avg(avg_over_time(mev_rpc_wallet_latency_milliseconds{provider="blinklabs"}[1h]))
regions:
From b58a5f8d21ac718b33a6df15516ef43aa96b6197 Mon Sep 17 00:00:00 2001
From: Florent Tapponnier
Date: Fri, 10 Jul 2026 22:36:59 +0200
Subject: [PATCH 4/5] mev-protect-rpc: gate via REMOVED_BENCH_SLUGS (the house
staging mechanism), redirect aligned, bench-set cache bumped
---
src/app/products/[slug]/page.tsx | 8 ++++----
src/lib/removed-benches.ts | 1 +
src/lib/spec.ts | 6 +++---
3 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/src/app/products/[slug]/page.tsx b/src/app/products/[slug]/page.tsx
index 1ce586d2..87c6d1a5 100644
--- a/src/app/products/[slug]/page.tsx
+++ b/src/app/products/[slug]/page.tsx
@@ -69,11 +69,11 @@ export async function generateMetadata({
// crawlers that peek at the response before the 308 fires still see the
// right canonical target.
// Merkle rebranded to Blink Labs and went keyed-only; the provider was
- // fully delisted 2026-07-10 from the keyless RPC benches. 308 to the
- // Blink Labs product page (bench 074 lists them under the new name) so
- // the old URL's link equity lands on the successor.
+ // fully delisted 2026-07-10 so this page has no data left. 308 to the
+ // capabilities bench for now; flip to /products/blinklabs in the same PR
+ // that removes mev-protect-rpc from REMOVED_BENCH_SLUGS.
if (slug === "merkle") {
- permanentRedirect("/products/blinklabs");
+ permanentRedirect("/benchmarks/rpc-capabilities");
}
if (await isHlBuilderWithHistory(slug)) {
const canonicalUrl = `${SITE.url}/hyperliquid/${slug}`;
diff --git a/src/lib/removed-benches.ts b/src/lib/removed-benches.ts
index 32de4dca..84bca2c9 100644
--- a/src/lib/removed-benches.ts
+++ b/src/lib/removed-benches.ts
@@ -37,6 +37,7 @@ export const REMOVED_BENCH_SLUGS = new Set([
"monad-rpc",
"megaeth-rpc",
"rpc-keyed-latency",
+ "mev-protect-rpc",
"explorer-chain-coverage",
"portfolio-chain-coverage",
]);
diff --git a/src/lib/spec.ts b/src/lib/spec.ts
index d2a59e88..c68633d0 100644
--- a/src/lib/spec.ts
+++ b/src/lib/spec.ts
@@ -267,7 +267,7 @@ const loadBenchmarkUnfilteredCached = unstable_cache(
// level on VERCEL_ENV=production). Bench SET now differs per env, so
// the env is part of the cache key to keep prod and preview entries
// from colliding.
- ["bench-unfiltered-v23", process.env.VERCEL_ENV === "production" ? "prod" : "all"],
+ ["bench-unfiltered-v24", process.env.VERCEL_ENV === "production" ? "prod" : "all"],
{ revalidate: 300, tags: ["benchmarks"] },
);
@@ -416,7 +416,7 @@ const loadAllBenchmarksCached = unstable_cache(
// 055-066; sitemap/citable/products must pick up the new slugs).
// v25: bumped with bench-unfiltered-v21 (+bench 067 portfolio-chain-coverage).
// v26: bumped with bench-unfiltered-v22 (+bench 068 explorer-chain-coverage).
- // v27: bumped with bench-unfiltered-v23 (prod-only bench gate); env in key.
+ // v27: bumped with bench-unfiltered-v24 (prod-only bench gate); env in key.
["all-benchmarks-v27", process.env.VERCEL_ENV === "production" ? "prod" : "all"],
{ revalidate: 300, tags: ["benchmarks"] },
);
@@ -492,7 +492,7 @@ const loadBenchmarkFiltered = unstable_cache(
// 055-066).
// v13: bumped with bench-unfiltered-v21 (+bench 067 portfolio-chain-coverage).
// v14: bumped with bench-unfiltered-v22 (+bench 068 explorer-chain-coverage).
- // v15: bumped with bench-unfiltered-v23 (prod-only bench gate); env in key.
+ // v15: bumped with bench-unfiltered-v24 (prod-only bench gate); env in key.
["bench-filters-v15", process.env.VERCEL_ENV === "production" ? "prod" : "all"],
{ revalidate: 300, tags: ["benchmarks"] }
);
From 0779c936b378b0a6c425e9495bb584d58116749f Mon Sep 17 00:00:00 2001
From: Florent Tapponnier
Date: Sat, 11 Jul 2026 20:47:25 +0200
Subject: [PATCH 5/5] audit follow-ups: OI convention footnote (defillama
doubles lighter/ostium, adds paradex options and HL HIP-3), PM anchor rows
documented, resolution-delay mean aligned to ms
---
benchmarks/perp-open-interest.yml | 1 +
benchmarks/pm-data-freshness.yml | 1 +
benchmarks/polymarket-resolution-delay.yml | 10 +++++-----
3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/benchmarks/perp-open-interest.yml b/benchmarks/perp-open-interest.yml
index 6b07347f..64affdb5 100644
--- a/benchmarks/perp-open-interest.yml
+++ b/benchmarks/perp-open-interest.yml
@@ -38,6 +38,7 @@ abstract: |
Higher is better.
methodology:
+ - "Convention: open interest counts each contract once (one side), the standard used by CME, Binance and Coinglass, and the only convention comparable across venues. Aggregators can differ: DefiLlama doubles Lighter and Ostium (long plus short), folds 1,682 options markets into Paradex, and adds HIP-3 sub-dex OI to Hyperliquid. Where our number is about half of theirs, that is the convention gap, not missing data; five venues where conventions align match DefiLlama within 2 percent."
- "Cadence: every 5 minutes per venue in parallel, 10 second timeout per request."
- "Hyperliquid: info metaAndAssetCtxs, openInterest summed across all assets and priced in USD using the venue's own mark price."
- "Aster: fapi openInterest endpoint per instrument, summed across all listed USDT perps."
diff --git a/benchmarks/pm-data-freshness.yml b/benchmarks/pm-data-freshness.yml
index ffbb7602..8f6836af 100644
--- a/benchmarks/pm-data-freshness.yml
+++ b/benchmarks/pm-data-freshness.yml
@@ -45,6 +45,7 @@ abstract: |
yet cover Kalshi venue data).
methodology:
+ - "Anchor rows: on each venue tab the venue itself (Polymarket, Kalshi) is the canonical T0, so its row reads as the harness network round trip, near zero by construction. It is kept on the board to document the reference point, not as a competing feed; the comparison rows are the data providers measured against it."
- "Polymarket T0. `wss://ws-subscriptions-clob.polymarket.com/ws/market` is public, no auth, sub 50ms gateway publish latency from EU West. Cross correlation uses (conditionId, priceUSD rounded to 3 decimals, sizeUSD micros, 5s time bucket)."
- "Kalshi T0. `https://api.elections.kalshi.com/v1/social/trades` (REST), polled every 5s with cursor pagination. Every trade carries `create_date` at microsecond precision; that timestamp is the canonical T0. Poll cadence affects only correlation timing, not the freshness number. The official Kalshi WebSocket needs RSA PSS signed headers from a US KYC account and 403s from non US IPs, not viable for a public benchmark."
- "Mobula PM WebSocket. `wss://pm-api-prod-eu.mobula.io`. Auth via API key in the subscribe payload. Cloudflare on the gateway requires a browser User Agent on the upgrade request, default Go HTTP UA is silently filtered. Covers Polymarket today, Kalshi coverage is not yet shipped."
diff --git a/benchmarks/polymarket-resolution-delay.yml b/benchmarks/polymarket-resolution-delay.yml
index 432c2e98..9c058e1c 100644
--- a/benchmarks/polymarket-resolution-delay.yml
+++ b/benchmarks/polymarket-resolution-delay.yml
@@ -132,7 +132,7 @@ providers:
p50: 1000 * histogram_quantile(0.50, sum by (le) (pmres_resolution_delay_seconds_bucket))
p90: 1000 * histogram_quantile(0.90, sum by (le) (pmres_resolution_delay_seconds_bucket))
p99: 1000 * histogram_quantile(0.99, sum by (le) (pmres_resolution_delay_seconds_bucket))
- mean: sum(pmres_resolution_delay_seconds_sum) / sum(pmres_resolution_delay_seconds_count)
+ mean: 1000 * sum(pmres_resolution_delay_seconds_sum) / sum(pmres_resolution_delay_seconds_count)
success: clamp_max(sum(pmres_resolution_delay_seconds_bucket{le="7200"}) / sum(pmres_resolution_delay_seconds_count), 1)
sample_size: sum(pmres_resolutions_total)
series: 1000 * histogram_quantile(0.50, sum by (le) (pmres_resolution_delay_seconds_bucket))
@@ -145,7 +145,7 @@ providers:
p50: 1000 * histogram_quantile(0.50, sum by (le) (pmres_resolution_delay_seconds_bucket{category="sports"}))
p90: 1000 * histogram_quantile(0.90, sum by (le) (pmres_resolution_delay_seconds_bucket{category="sports"}))
p99: 1000 * histogram_quantile(0.99, sum by (le) (pmres_resolution_delay_seconds_bucket{category="sports"}))
- mean: sum(pmres_resolution_delay_seconds_sum{category="sports"}) / sum(pmres_resolution_delay_seconds_count{category="sports"})
+ mean: 1000 * sum(pmres_resolution_delay_seconds_sum{category="sports"}) / sum(pmres_resolution_delay_seconds_count{category="sports"})
success: clamp_max(sum(pmres_resolution_delay_seconds_bucket{le="7200",category="sports"}) / sum(pmres_resolution_delay_seconds_count{category="sports"}), 1)
sample_size: sum(pmres_resolutions_total{category="sports"})
series: 1000 * histogram_quantile(0.50, sum by (le) (pmres_resolution_delay_seconds_bucket{category="sports"}))
@@ -158,7 +158,7 @@ providers:
p50: 1000 * histogram_quantile(0.50, sum by (le) (pmres_resolution_delay_seconds_bucket{category="crypto"}))
p90: 1000 * histogram_quantile(0.90, sum by (le) (pmres_resolution_delay_seconds_bucket{category="crypto"}))
p99: 1000 * histogram_quantile(0.99, sum by (le) (pmres_resolution_delay_seconds_bucket{category="crypto"}))
- mean: sum(pmres_resolution_delay_seconds_sum{category="crypto"}) / sum(pmres_resolution_delay_seconds_count{category="crypto"})
+ mean: 1000 * sum(pmres_resolution_delay_seconds_sum{category="crypto"}) / sum(pmres_resolution_delay_seconds_count{category="crypto"})
success: clamp_max(sum(pmres_resolution_delay_seconds_bucket{le="7200",category="crypto"}) / sum(pmres_resolution_delay_seconds_count{category="crypto"}), 1)
sample_size: sum(pmres_resolutions_total{category="crypto"})
series: 1000 * histogram_quantile(0.50, sum by (le) (pmres_resolution_delay_seconds_bucket{category="crypto"}))
@@ -171,7 +171,7 @@ providers:
p50: 1000 * histogram_quantile(0.50, sum by (le) (pmres_resolution_delay_seconds_bucket{category="politics"}))
p90: 1000 * histogram_quantile(0.90, sum by (le) (pmres_resolution_delay_seconds_bucket{category="politics"}))
p99: 1000 * histogram_quantile(0.99, sum by (le) (pmres_resolution_delay_seconds_bucket{category="politics"}))
- mean: sum(pmres_resolution_delay_seconds_sum{category="politics"}) / sum(pmres_resolution_delay_seconds_count{category="politics"})
+ mean: 1000 * sum(pmres_resolution_delay_seconds_sum{category="politics"}) / sum(pmres_resolution_delay_seconds_count{category="politics"})
success: clamp_max(sum(pmres_resolution_delay_seconds_bucket{le="7200",category="politics"}) / sum(pmres_resolution_delay_seconds_count{category="politics"}), 1)
sample_size: sum(pmres_resolutions_total{category="politics"})
series: 1000 * histogram_quantile(0.50, sum by (le) (pmres_resolution_delay_seconds_bucket{category="politics"}))
@@ -184,7 +184,7 @@ providers:
p50: 1000 * histogram_quantile(0.50, sum by (le) (pmres_resolution_delay_seconds_bucket{category="other"}))
p90: 1000 * histogram_quantile(0.90, sum by (le) (pmres_resolution_delay_seconds_bucket{category="other"}))
p99: 1000 * histogram_quantile(0.99, sum by (le) (pmres_resolution_delay_seconds_bucket{category="other"}))
- mean: sum(pmres_resolution_delay_seconds_sum{category="other"}) / sum(pmres_resolution_delay_seconds_count{category="other"})
+ mean: 1000 * sum(pmres_resolution_delay_seconds_sum{category="other"}) / sum(pmres_resolution_delay_seconds_count{category="other"})
success: clamp_max(sum(pmres_resolution_delay_seconds_bucket{le="7200",category="other"}) / sum(pmres_resolution_delay_seconds_count{category="other"}), 1)
sample_size: sum(pmres_resolutions_total{category="other"})
series: 1000 * histogram_quantile(0.50, sum by (le) (pmres_resolution_delay_seconds_bucket{category="other"}))