Skip to content

Promote dev to main: Serialized onboarding, bench scoring fixes, 001 node reference - #2269

Open
Flotapponnier wants to merge 313 commits into
mainfrom
dev
Open

Flotapponnier wants to merge 313 commits into
mainfrom
dev

Conversation

@Flotapponnier

Copy link
Copy Markdown
Collaborator

Staging state on dev since 2026-09-05, reviewed at https://staging-openchainbench.vercel.app.

What this promotes

Serialized (serialized.xyz) as a provider

Bench integrity fixes, all as separate series so history is preserved

Audit doc docs/methodology/serialized-onboarding-audit.md v1.3 (#2264, #2265): every number, every correction, two methodology defects in our own benches, a verified 5.2x BONK mispricing traced to a pool-ranking unit bug on their side.

What merging to main does beyond the site

The three Railway head-lag services (Aggregator east usa, Agg eu west, agg sgp) build from main, root harnesses/aggregator-head-lag. After this merge, trigger a fresh git build on each (serviceInstanceDeployV2); SERIALIZED_API_KEY is already set on all three. Agg eu west has three failed snapshot-upload deploys since 2026-09-05 14:32 (lstat …/harnesses: no such file or directory), a railway up from a directory without the harness path; a git build replaces it.

Known state at promotion time

  • 004: Serialized is producing (p50 53.3% on the spec query) but the leaderboard still shows the pre-outage snapshot because Mobula/Codex/Jupiter quantiles are NaN while the dead hours (webshare proxy quota, 429) remain in the 24h window; quorum fails 1/4 and the worker keeps the previous render. Self-heals once those hours roll out.
  • 008: Serialized 3rd at 76.75% (n=1,188). 005: last at 19. 090: 4th of 5 at 19 (Sim by Dune is dead: api.sim.dune.com no longer resolves).

🤖 Generated with Claude Code

https://claude.ai/code/session_01CpArutAtXuBb1BVNUDXoYA

Flotapponnier and others added 30 commits September 4, 2026 00:52
feat(speedtest): prefill validation + logos polish
feat(speedtest): pro live dial (concurrent probes + gradient gauge)
…lish

feat(speedtest): responsive + design polish
feat(speedtest): SEO/GEO findability pass
feat(speedtest): red stop button at section bottom
feat(speedtest): dedicated social card
fix(speedtest): satori-compatible OG card
feat: crowdsourced RPC latency world map
feat(map): search + compare + smart viewport
feat(map): clickable areas + history panel
feat(map): near me + pin with nearest results
fix(speedtest): fail-open prefill check
fix(bench-205): apples-to-apples Solana scoping
Wires serialized.xyz into metadata-coverage (004) and wallet-labels (008),
the two benches where their endpoints map 1:1 to the existing scoring rule.

Both providers throttle client-side at ~16 rps: Serialized enforces a hard
40 req/s burst cap and an unthrottled worker pool turns coverage into a
rate-limit artifact (measured 77% -> 37%).

Adds the registry entry, logo and a full onboarding audit documenting the
apples-to-apples numbers and two scoring flaws the tests exposed in our
own benches (logo presence vs resolution on 004, name-service strings
counted as entity labels on 008).


Claude-Session: https://claude.ai/code/session_01CpArutAtXuBb1BVNUDXoYA

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The harnesses emit provider="serialized" but the leaderboards are
driven by the explicit providers block in each spec, so the series
never rendered. Adds the block for both benches, same query shape as
the incumbents.

Validated with SpecSchema.safeParse across all 218 specs; every
formula stays under the 240-char cap that silently drops a spec.


Claude-Session: https://claude.ai/code/session_01CpArutAtXuBb1BVNUDXoYA

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Flotapponnier and others added 30 commits September 19, 2026 18:36
…nsfer through a hop vault discarded every leg and sent the 2 % fee into pool on routed swaps); the Relay column only where a bridge was used; pooled components over the rows that carry them, published when they hold half the flow; applyLearned honours DISCOVER_DENY; copy and tooltips (#2514)

Claude-Session: https://claude.ai/code/session_01L4rjxemTvgRwrCG6D2iK5D

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…g: noindex (#2515)

Search Console "Crawled, currently not indexed" (326 URLs, 2026-09-19):
about 200 are opengraph-image / twitter-image / icon URLs fetched from
og:image meta tags (compare pairs, benches, products, chains), about 60
are /api/stat, /api/badge, /api/og and /api/llm-context, a handful are
compare pages already noindex, static chunks and feeds. Google fetched
each and had to decide; none is a page.

- src/lib/og-response.tsx wraps ImageResponse with X-Robots-Tag: noindex;
  the 30 construction sites in 17 files (metadata image routes, /api/og,
  share cards, icons) go through it. Metadata routes ignore next.config
  headers(), hence the wrapper.
- next.config headers(): /api/:path* carries X-Robots-Tag: noindex.
  robots.txt stays fully open, so GPTBot, ClaudeBot and PerplexityBot
  keep fetching the citable JSON; noindex is not a fetch block.

The remaining entries of the report are the compare pairs (noindex by
design, they move to "Excluded by noindex"), /benchmarks/perp-fees/SOL
(already 308 to lowercase), and two indexable pages Google judged thin
on the old template (/products/cow, /benchmarks/bitcoin-rpc).

Verified locally: /api/stat, /api/badge, /compare/x/opengraph-image,
/benchmarks/x/opengraph-image/default, /products/x/opengraph-image,
/icon, /opengraph-image all answer the header. tsc, eslint, bun test.


Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e parent bench instead of 404; a missing bench stays 404 (Search Console 2026-09-19: network-fees/{gram,blast,optimism,stellar}) (#2516)

Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…Gram, Optimism, Blast and Scroll back in the cohort, Sui on GraphQL; harness source in the repo (#2517)

The six chains were pulled on 2026-07-02 (#828) because their USD figures
looked 100 to 1000x too low. Reading the fetchers: the arithmetic was
right, the figures were real. Stellar is 100 stroops (0.00001 XLM), and an
OP Stack transfer's L2 execution is a few thousand wei. What made the
rollup numbers misleading was the documented omission of the L1 data
posting fee, which on Optimism, Base and Blast is the larger of the two
components a wallet charges. That omission also understated Base and
Mantle, which stayed in the table.

Harness (harnesses/transaction-fee, previously only on the VPS under
/opt/ocb, now versioned here where the spec's source link already
pointed):
- ChainConfig.L1Fee: "opstack" (GasPriceOracle 0x42..0F getL1Fee on a
  serialized 113 byte EIP-1559 transfer: Optimism, Base, Blast, Mantle),
  "scroll" (L1GasPriceOracle 0x53..02), "arbitrum" (eth_estimateGas on a
  native transfer returns 21000 plus the L1 calldata component; each tier
  is scaled by estimated / 21000). zkSync Era, Linea, Taiko and Robinhood
  Chain embed the data cost in the gas price and declare none. An L1
  call failure fails the sample instead of publishing execution only.
- Avalanche (C-Chain, plain EVM), Stellar (horizon fee_stats), Gram
  (0.005 GRAM observed) and the three rollups re-declared.
- Sui: the public fullnodes retired JSON-RPC ("migrate to gRPC or
  GraphQL"); reference gas price now from graphql.mainnet.sui.io. Sui had
  been silent (120 parse errors an hour).
- PORT env for local runs.

Spec: 21 providers, per-chain explainers for the six, formulas and
methodology describe the L1 fee per rollup family, the "Are the L2
numbers complete? Not yet" FAQ now says what is included where, counts
are {{count}}, description mentions the L1 fee. per_chain_explainer cap
20 -> 30.

Deployed on the VPS (ocb-transaction-fee, env kept in
/run/ocb/.env.transaction-fee): 22 chains scraped, no fetch errors.
Values at deploy: Stellar $0.000002, Blast $0.000004, Optimism $0.00002,
Avalanche $0.00015, Base $0.00035, Arbitrum $0.0013, Scroll $0.0059,
Gram $0.007, Sui $0.0066, Ethereum $0.036, TRON $0.099.


Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…-user account takes it on part of them: terminal read 0, other 100); stale component gauges deleted per entry; product KPIs gated on the headline; value in and value out in USD on the audit table; Relay page budget 60 for a deploy's gap; copy (#2518)

Claude-Session: https://claude.ai/code/session_01L4rjxemTvgRwrCG6D2iK5D

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…k minus source block), not the 5 s status poll (#2520)

* bridge-execution-latency (261): settlement latency read on-chain (destination block timestamp minus source block timestamp) instead of the wall clock to a 5-second status poll

Every provider's execution latency was time.Now() after a loop that slept
5 s between status calls, plus the provider's indexing lag: a fill under
5 s always read 5.x s. The table showed Mobula 5.29 s, Relay 5.53 s,
LI.FI 5.82 s, which is the poll cadence, not the bridges.

- onchain_latency.go: TxBlockTime(chain, hash) reads the including
  block's timestamp (EVM receipt + header, Solana getTransaction
  blockTime, 6 short retries for RPC lag); settlementLatency() replaces
  ExecutionLatencyMs on a settled result with destination minus source
  block time when both hashes resolve, keeps the wall clock in
  ObservedLatencyMs, and reports the method.
- Destination hashes: Relay v3 txHashes (inTxHashes as the source
  fallback), LI.FI receiving.txHash (received kept as fallback), Mobula
  toTxHash (already parsed), 1Click swapDetails.destinationChainTxHashes.
- Metrics: bridge_exec_latency_ms carries the on-chain value;
  bridge_exec_observed_ms keeps the old figure for comparison;
  bridge_execution_latency_fallback_total counts settled executions that
  had to keep the wall clock.
- Spec: methodology, subtitle, description, formulas and findings say
  "source block to destination block"; the history bullet documents the
  change and the fallback.

go vet, go build, go test ./... pass. To deploy: rebuild
ocb-bridge-monitor on the VPS between two scheduled executions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

* bridge-monitor: Mobula's settled payload names the destination fill `fillTxHash` (toTxHash kept as fallback); checked on today's two settlements: SOL->Base deposit block 10:00:03, fill block 10:00:05 = 2 s on-chain against 5.3 s from the poll; ARB->SOL same second

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

---------

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…cap 10); the purge log names its variables; pump.fun fee vaults out of the unattributed list; In $ on EVM sells includes the gas paid apart; hub per-chain badge on every pooled row; copy (gas coins at Coinbase spot, USDC deposits on FOMO, intervals overlap, thresholds, purge and deny variables documented) (#2521)

Claude-Session: https://claude.ai/code/session_01L4rjxemTvgRwrCG6D2iK5D

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…00 ms watch), block delta as cross-check, EXEC_RUN_ON_START (#2522)

* bridge-execution-latency: millisecond settlement latency from a two-ended 100 ms watch (destination credit observed minus source inclusion observed), block-timestamp delta kept as the cross-check; EXEC_RUN_ON_START for a one-off validation cycle

Block timestamps (previous commit) are honest but whole-second: a
sub-second fill reads 0 s and Base moves in 2 s steps. The harness now
observes both ends itself, on one clock, every 100 ms on the keyed RPCs:
the recipient balance from before the broadcast (first read above the
pre-execution balance = creditAt) and the deposit's inclusion from the
broadcast (receipt on EVM, signature status on Solana = confirmedAt).
bridge_exec_latency_ms = creditAt - confirmedAt, detection lag at most
one interval plus one RPC round-trip on each end.

Order of preference in settlementLatency: watch, watch-broadcast (source
watcher missed), blocks (timestamp delta), poll (old wall clock). The
block delta is always published as bridge_exec_onchain_ms and must agree
with the watch to within one destination block; bridge_exec_observed_ms
keeps the poll figure; the fallback counter now counts only "poll".

EXEC_RUN_ON_START=3 fires one $3 tier 20 s after start, for validation
and for repopulating the 24h window after the polluted series are
deleted from Prometheus; unset in normal operation.

go vet, go build, go test pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

* bridge-execution-latency spec: methodology describes the 100 ms two-ended watch as the published figure, the block delta as cross-check, and the Prometheus reset of the poll-era series

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

---------

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…mily, same swap event with the sender in topic 1, filtered on the wallets it funded through Relay); HyperEVM deliveries valued at Hyperliquid's HYPE mid and a HyperEVM tab (#2524)

Claude-Session: https://claude.ai/code/session_01L4rjxemTvgRwrCG6D2iK5D

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…racters (validate was red on dev after c17b354) (#2523)

Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… other, 138 bps); pump.fun's A7hAgCz vault listed; Axiom's tip on ERC20-paid buys (value equal to the tip) no longer in terminal; a pool under -100 bps on a multi-pool route is an implausible split; discovery never adopts a wallet seen on two platforms; /metrics served before the Relay seed; hop cost on four.meme; metadata failures not cached; product page keeps its own row; copy (#2525)

Claude-Session: https://claude.ai/code/session_01L4rjxemTvgRwrCG6D2iK5D

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…zed-cost dropped the two bridges that beat their quote and crowned the wrong leader); negative USD reads "-$0.0038" (#2526)

liveResults() kept a row only when p50 > 0, a guard meant for legacy
zero placeholders. On bridge-realized-cost (slippage vs quote, where a
bridge that settles better than it quoted is negative by design, and
the FAQ says so) Mobula at -$0.0038 and LI.FI at -$0.00008 vanished from
the ranking, the API and the TL;DR, and Relay at $0.000003 was crowned.

- load.ts marks every row built from real aggregates availability: "live".
- liveResults(): a "live" row passes on any finite p50; rows without the
  flag (older blobs) keep the > 0 rule, so nothing regresses until the
  worker republishes.
- fmtUnit: negative USD formats as -$0.0038 (was $-0.0038).

Local render: Mobula leads at -$0.00381, then LI.FI, Relay, Near
Intents. tsc, bun test 255.


Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nch recurses; typecheck was red on dev after #2526) (#2527)

Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…te, hub tooltip) instead of reading as unresponsive; the HyperEVM tab waits for a product priced there; EVM_DAILY_TARGET default 1000; copy on which rows price the gas coin where (#2528)

Claude-Session: https://claude.ai/code/session_01L4rjxemTvgRwrCG6D2iK5D

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…se gauges and a 7-day window (p50/p90/p99 were one execution), method label and full fallback accounting, real freshness from a persisted last-execution time, RPC keys out of the log, Near Intents quoted fee, stuck deposits in the success denominator, ticket dimension the site could not render removed, realized fee panel (#2529)

ocb-bench-audit on bridge-execution-latency (staging, 9135212): NOT
READY, 4 blockers, 5 majors.

Blocker 1 (and major 4): bridge_exec_latency_ms, slippage, gas, realized
output and fees were last-value gauges that persisted for days;
quantile_over_time over them returned the last execution (p50 = p90 =
p99 on every row) and the "24h" panels averaged Thursday's $30 legs into
Saturday. They are now pulses: set once per execution, deleted after
75 s (2 to 3 scrapes), so every execution weighs the same in a range
query. The recording rules move to a 7-day window (ocb:*:p50_7d ...,
plus :last, fees and onchain), and the specs read them: one execution
per corridor per day makes a 24h quantile meaningless. n =
round(increase(success + reverts + stuck)[7d]).

Blocker 2: the amount_usd dimension was in the specs but the variant API
and the tab strip never carried it, so the "$30" view was the pooled
view under a formula that claimed a selection. Dimension removed from
both specs; copy says $3 and $30 are pooled (label kept in Prometheus).

Blocker 3: freshness_metric pointed at a histogram family (no bare
series) and the loader fell back to "now", so a dead harness read
"updated 4 min ago" forever. New prometheus.freshness_timestamp_metric
(schema + load.ts): a persistent gauge whose value is the unix time of
the last run; bridge_last_execution_timestamp_seconds is set on every
terminal execution and persisted in /state/last-execution.json so a
restart re-exposes it (seeded on the VPS with today's 18:36 cycle).
With no run recorded the bench reads epoch, never "now".

Blocker 4: tx_executor logged the three keyed RPC URLs at start; hosts
only now. The keys themselves stay valid until rotated (Alchemy
dashboard, owner action: docker log history holds them).

Major 1: bridge_exec_latency_ms carries a method label (watch,
watch-broadcast, blocks, poll); the fallback counter counts every
non-watch method with the same label; the spec says so. Solana source
inclusion is stamped from `processed` so a relayer acting on processed
cannot credit before our stamp and push the leg to the broadcast
fallback.
Major 2: stuck deposits enter the success denominator and n; FAQ and
outcome bullet updated.
Major 3: Near Intents sets QuoteFeeUSD from the 1Click quote, and the
slippage gauge is published only when a quoted fee exists (it was the
whole realized fee before).
Major 5: "Realized fee" panel (ocb:bridge_fees_usd:avg_7d) on both
benches, amount sent minus amount received on-chain.
Minors: cohort named as four in title, description and intro; findings
wording; shortHash guard on the success log line; histogram help text.

Deployed: rules reloaded on ocb-prom (promtool: 13 rules), harness
rebuilt (log shows hosts only, last-execution times restored), 7-day
recording series present for the 12 corridors. validate 236, tsc, bun
test 255, go vet/build/test.


Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…x), not the raw unix time; prom.scalar keeps 6 significant digits and rounded 18:36:50 to 17:46:40 (#2530)

Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…sell straight through Uniswap, 2 of 2 sellers among 14 recent buyers, the rest still holding): the hold is permanent, the copy says so (#2531)

Claude-Session: https://claude.ai/code/session_01L4rjxemTvgRwrCG6D2iK5D

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ies now aggregate the recorded cells, region pinned to EU-West, meme route and execution-path quotes excluded, mean fixed, Mobula timed like the others and keyed by header, Near Intents' fixed 3 s wait disclosed (#2532)

ocb-bench-audit on bridge-quote-latency-solana (and confirmed on the
production bridge-quote-latency page):

- Blocker: the recording rules keep (bridge, region, chain, amount_usd)
  and the spec queries selected on bridge only, so
  histogram_quantile(...{bridge="mobula"}) returned 39 series and
  prom.scalar took result[0], which Prometheus orders by Go map
  iteration. The live production page read Mobula p50 31 / p90 57 /
  p99 4172 ms and Near Intents p99 108 below p90 4700: a different cell
  on every materialization. Every p50/p90/p99 query is now
  histogram_quantile(q, sum by (le) (...)), mean is
  sum(rate_sum)/sum(rate_count) (the previous clamp_min(count_rate, 1)
  floored a per-second rate to 1 and printed ms per second, 300x too
  small), success is avg(...), n is round(sum(increase)). Verified on
  the VPS Prometheus: one series, Mobula 43.7 / 345.8 / 982.6 ms, mean
  118.3.
- Region pinned to eu-west on every headline query: the us-east probe is
  live (the copy said paused) and was part of the random draw; sgp is
  down. Copy corrected on both specs.
- Rules (infrastructure/monitoring/prometheus/recording_rules/
  ocb_bridge_quote.yml, source of truth for the VPS file that was only
  on the host, and ocb_bridge_quote_solana.yml) exclude the R4 TRUMP to
  BRETT meme route the same loop quotes (it pooled a cross-asset swap
  into the Base USDC cells: Mobula 34.6 ms USDC-only vs 139.3 pooled)
  and the $3 / $30 execution-path quotes.
- Harness: execution-path quote latency goes to its own histogram
  (bridge_exec_quote_latency_ms); Mobula's stopwatch stops after the
  body is read like the five other providers; the Mobula key travels in
  the Authorization header instead of the query string (a transport
  error wrapped the full URL into the log and Slack); the quote
  histogram gains 500 ms buckets between 1 and 5 s.
- Near Intents: its dry quote waits a fixed 3 s solver window
  (quoteWaitingTimeMs: 3000), so its row measures that wait; disclosed
  in the methodology and the finding, the "bimodal, sub-100 ms" claim
  removed. Robinhood coverage bullet (four providers quote it now) and
  the Across / Near Intents coverage (Base and Arbitrum only, our maps)
  corrected.

Deployed: rules reloaded (promtool 6 + 5), harness rebuilt, Mobula
quotes verified with header auth. validate 236, go vet/build/test.


Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…finition (ticket minus quoted output), realized cost published only from the on-chain read, realized fee in bps of the ticket from an execution-only metric, stale threshold and window wording follow the spec, pre-pulse history purged (#2533)

ocb-bench-audit on bridge-realized-cost: NOT READY, 4 blockers, 7 majors.

- Blocker 4: Mobula's slippage was a constant negative offset at every
  ticket (-$0.0015 on Base at $3 and at $30) because its quoted fee summed
  TotalFeeUsd + GasFeeUsd, gas the realized fee (ticket minus landed) can
  never contain; Relay and LI.FI derived theirs from the output. Every
  bridge now uses ticket minus the output the quote promised
  (QuotedOutputUSD), so both sides of the subtraction are defined the same
  way. Gas we pay stays its own panel.
- Blocker 3 and major 2: the "Realized fee" panel read bridge_fees_usd,
  which the quote loop also writes at $5/$50/$300 and on off-triangle
  routes (LI.FI $0.417 shown against $0.032 executed), and the realized
  output panel was a ticket-mix number. New execution-only pulses
  bridge_exec_realized_fee_usd and bridge_exec_realized_fee_bps; the panel
  is "Realized fee (bps of ticket)"; the output panel is gone.
- Major 1 and 3: fee, output and slippage pulses are published only when
  the destination balance delta was read (RealizedOnChain); a failed leg
  no longer publishes the quote's projection as "landed" and a fallback
  is counted in bridge_realized_fallback_total instead of an exact zero.
- Blocker 1: the 7-day window still held the pre-pulse persistent samples
  (about 2,880 per old execution against 3 per new one), so no new
  execution could move a median before 2026-09-26. Deleted from
  Prometheus for the execution cost series and the retired 24h rules;
  the benches read empty until the 10:00 UTC cycle tomorrow.
- Major 4: LiveIndicator takes staleAfterSec from the bench
  (prometheus.expected_freshness_seconds, carried on Benchmark as
  expectedFreshnessSec), so a daily bench is not "Stale" 23 hours a day.
- Major 5: Benchmark.window (prometheus.window) drives the Results
  caption, the infobox "Leader (7d)" and the citation suffix instead of a
  hardcoded 24h.
- Copy: quoted-fee definition, gating, cohort of four, 7-day findings.

Rules reloaded (14), harness redeployed. validate 236, tsc, eslint, bun
test 255, go vet/build/test.


Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…LANA_RPC comma-separated, Helius appended, public node last; the next endpoint on a rate limit or a transport error instead of a sleep): production runs Chainstack's shared node first, Alchemy's free app for the overflow, Helius third; Robinhood Chain gets Chainstack behind QuickNode (#2535)

Claude-Session: https://claude.ai/code/session_01L4rjxemTvgRwrCG6D2iK5D

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ghbour screen, no neighbourhood read when the exact mid is known), FAIL_SCAN_BLOCKS per chain, NATIVE_POLL_EVERY ticks; production moves to 150 draws a day per row, no sandwich, fail-rate blocks bnb 3 / base 2 / ethereum 1 / robinhood 0, EVM logs every 3 ticks: about 27,000 calls a day instead of 146,000 (#2536)

Claude-Session: https://claude.ai/code/session_01L4rjxemTvgRwrCG6D2iK5D

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…te, not on a positive quoted fee (Mobula Sol to Base quoted the full ticket back and its +$0.003 slippage was skipped) (#2537)

Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…03 name the live leader and number; the fee FAQ and the three bridge answers drop the claims the harness never measured ($1000/$10000 buckets, 10x, 100 to 400 ms, three regions, Ethereum to Base); the USDC-to-Base answer reads the Sol to Base cell; answers get compare links and citation meta, bench pages and the /bridge hub list their answers; the hub hides region columns whose variant is stale (US/SGP showed 2026-09-09 figures) and shows an as-of line; products meta uses short bench labels; compare pages dedupe the FAQ, date from the newest run and carry the count in the title; ad hoc compare pairs enter the sitemap; validator lints answers placeholders and typed cohorts (#2538)

Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… metric ("faster on quote latency") instead of the lowercased bench title (#2539)

Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…channel, bench and harness health, Dune) (#2540)

* crm: internal dashboard on Railway (traffic from PostHog with an AI-referral channel, bench and harness health, Dune credits); a fixed list of 11 HogQL queries per hourly refresh writes a snapshot the pages read, so the PostHog query budget stays under 1 % of the organisation's 2400/hour

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

* crm, review round 1: crm/ excluded from the site's tsconfig and eslint (the root typecheck pulled it into the Vercel build) with its own CI job; sessions are random, signed with a separate secret, listed on the volume and revoked on logout, login limited per client; snapshot cache, refresh mutex and PostHog budget on globalThis with mtime re-reads (instrumentation and routes are separate bundler layers); history append-only and tolerant of a torn line; bench health from index.json so expired chain RPC benches show instead of vanishing; exact AI/search 7 d uniques in the KPIs; page and referrer rows ranked on either week so losses survive the LIMIT

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

* crm, review round 2: the login limiter keys on the last forwarded hop with a global cap and evicts idle keys; session writes serialised with unique temp files; one referrer rule for the SQL KPIs and the TS channel table (Google and Bing country hosts count as search on both sides); sitemap body parse guarded; Dune sub text keys on the recorded error

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

---------

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
)

* posthog: three custom events (outbound_click by delegated listener, copy with kind/bench, search with the query and the result picked) so the CRM measures what the traffic turns into; crm: Actions page (outbound hosts, copies per bench, search queries), four more HogQL queries per hourly refresh (15 total)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

* posthog events, review: config snippets on /mcp tagged mcp_config with their name, the badges catalog copy tagged embed with format and bench, track() typed per event, action labels rendered

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

---------

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ariable; vercel pull hands sensitive env vars back as the literal "[SENSITIVE]" and that string shipped as the PostHog token since 2026-08-24 (#2542)

Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… set (#2544)

Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
)

Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…5 % of the org budget), manual cooldown 5 min, next refresh shown in the header (#2546)

Claude-Session: https://claude.ai/code/session_01HJgbZCqjR4nvCfcJSzofbw

Co-authored-by: Flotapponnier <florent@mobula.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant