ship: dev → main (share-card UX + GSC Dataset fixes + share-modal dimension pickers) - #1298
Closed
Flotapponnier wants to merge 132 commits into
Closed
ship: dev → main (share-card UX + GSC Dataset fixes + share-modal dimension pickers)#1298Flotapponnier wants to merge 132 commits into
Flotapponnier wants to merge 132 commits into
Conversation
solana cohort: provider pages polish
…#1136) Co-authored-by: Florent Tapponnier <contact@mobula.io>
Co-authored-by: Florent Tapponnier <contact@mobula.io>
…ll mode), network-fees
Robinhood Chain: hub entry + 3 bench integrations
…fix tracker reset
…cution mutex primitive DailySpentUSD only ever incremented and was zeroed by every restart, so a crash-loop minted a fresh budget each time. The tracker resets exactly at UTC midnight, persists (date, spent) to SPEND_STATE_PATH (default ./spend-state.json, not /tmp) and is mutex-guarded. Also declares the package-level single-flight lock and the FAILED_TX_FEE_ESTIMATE_USD (default 0.50) helper for gas bled by failed broadcasts.
…get, single-flight lock Fund-loss fixes from hostile review: - a corrective transfer whose deposit broadcast but whose bridge status never resolved is now TERMINAL for the scheduler slot (funds are likely still in flight, a retry double-sends); only pre-broadcast failures may consume another attempt. executeOnBridge keeps TxHash on error paths so callers can tell the two apart. - ONE corrective-transfer budget (max 2) per scheduler slot, shared across all downgrade-ladder rungs (was per rung: up to 6 transfers per slot). - package-level execution mutex: scheduler slots own the wallets end to end, the reaper TryLocks and skips its tick instead of queueing. - broadcasts that failed or timed out after getting a TxHash book a flat FAILED_TX_FEE_ESTIMATE_USD against the daily cap instead of bleeding unaccounted gas; all spend goes through the persisted UTC-day tracker. - gas top-up now honors MaxDailySpendUSD before broadcasting.
The reaper (and any other consumer) used to accept simulated balances even in production with broadcast-capable keys, so phantom numbers could green-light real transfers. SimulateBalances now takes the execution mode and returns nil outside dry-run; startup logs a warning when the flag is set in a broadcast-capable mode.
bridge-monitor: self-healing execution loop (dormant)
…st-fill (#1141) Co-authored-by: Florent Tapponnier <contact@mobula.io>
Co-authored-by: Florent Tapponnier <contact@mobula.io>
…reference (staging gated)
tokenized-stock-peg: bench 076, first onchain equity pricing bench
…he miss (bnb-rpc awaiting incident) (#1144) Co-authored-by: Florent Tapponnier <contact@mobula.io>
tokenized-stock-peg: fix spark parser for the flat response shape
… USDG methodology notes
tokenized-stock-peg: spec validation fix + methodology hardening
…ation (#1257) GSC flagged 'Missing field name' on aggregator-head-lag JSON-LD (and by extension every bench slug page + every per-chain page + the methodology hub — all TechArticle nodes shipped only 'headline'). Schema.org Article inherits 'name' from CreativeWork; Google's Rich Results validator treats it as required even when 'headline' is present. Add 'name' alongside 'headline' with the same value on all three affected builders. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…le (#1260) Feedback from Maxime: exported images do not adapt to the active filters on the bench page. A share-card exported from /benchmarks/rpc-capabilities?chain=ethereum®ion=sgp used to render just 'Fastest free public RPC ...' with cross-chain data; now the loader picks up the region filter and the title reads 'Fastest free public RPC ... Ethereum · Singapore' with the correctly scoped data. Change: * share-card route reads region, kind, venue URL params (symmetric with the existing chain param). Each maps to a spec dimension and forwards to the materialize loader so the data is filtered too, not just the title. * A composed contextParts string is built from the resolved dimension labels and appended to the aggregate title. Empty when no filter is active, no trailing separator on the default view. * The composed title is overlaid onto the benchmark passed to each render (spread with {...b, title: displayTitle}) so all 5 templates (ranking, leaderboard, snapshot, headline, compare) pick it up without any render-signature changes. * share-section + share-section-modal read live URL params for region/kind/venue in addition to chain when composing the card URL, so a modal opened from a scoped bench page passes the same scope to the exported PNG. Follow-up (not in this PR): view / range / topN selectors, per-bench UI in the modal to expose the dimension pickers explicitly. This PR is the plumbing; the modal UX for exposing new pickers is next. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…l-silent false positives (#1265) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…enches) (#1266) Commit c03c599 relaxed the sortByP50 filter from `p50 > 0` to `p50 !== 0` to support the negative-p50 'warming up' sentinel introduced for funding benches on the /products page. The relaxation leaked into the share-card render path, where negatives crash Satori: negative p50 values fed to Math.max produce a negative maxP50, which inverts every bar height ratio and blows up the JSX with an opaque 'Spread syntax' error mid-render. Symptoms observed: /benchmarks/{rpc-capabilities,polkadot-rpc,ws-head-latency-ethereum,evm-block-builders}/share-card?template=ranking all returning HTTP 500. Working benches (network-coverage, perp-fees, oracle-deviation) had no negative sentinel values in their data. Fix restores `p50 > 0` in the share-card filter. The negative sentinel handling stays on the /products page where it was designed to render (as 'warming up'). Share-card treats negatives as noise and drops them, same as zeros. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…e) (#1267) Feedback from Maxime: user needs to be able to pick chain/region/kind/venue from within the share modal, not just inherit whatever the URL had when opening. Also the composed card title must reflect the pick in real-time. Adds a DimensionRow chip component rendered above the template tabs. One row per dimension the bench declares (chainDims / regionDims / kindDims / venueDims). Each row: 'Label' + 'All' chip + one chip per option. Clicking a chip toggles state; clicking the active pick clears back to All. State is seeded from the live URL on mount so the modal opened from a scoped bench page starts on the same scope (unchanged behaviour). User can override in-modal by clicking a different chip; state updates re-render the card preview with the new filter forwarded to the loader. The cardSrc URL builder now reads from picker state instead of the live URL - previous implementation re-read the URL every render which meant the modal's own state changes couldn't propagate. Same URL param names on the share-card route: no server-side change needed. Bench without dimensions: block hidden entirely, modal looks unchanged. Co-authored-by: Florent Tapponnier <contact@mobula.io>
… false positives (#1269) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…lay (#1270) The region/kind/venue param plumbing (added via #1260 → reverted via #1261 → re-added via #1263) and the display-title overlay via {...b, title: displayTitle} still cause HTTP 500 on rpc-capabilities share-card and other benches with dimensions. My sortByP50 fix (#1266) turned out not to be the actual root cause; the runtime error persists after that fix + the modal picker PR (#1267). Reverts the route.tsx changes only: - Restore original getBenchmark({chain}) call (no region/kind/venue forwarding) - Restore original switch that passes plain benchmark/filteredSafe to renders (no {...b, title: displayTitle} spread) - chainLabel still passed through (unchanged from pre-Maxime-feedback) Keeps the modal DimensionRow pickers (#1267) intact for a future retry once the true root cause is found. They currently look for matching URL params but the server-side won't act on them until the route.tsx re-adds forwarding safely. Bug still open on rpc-capabilities/polkadot-rpc/ws-head-latency-*/ evm-block-builders share-cards, but now user-visible functionality (chain filter, existing templates on non-broken benches) is fully restored to pre-Maxime-feedback behaviour. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…ST-only, no ws metric) (#1272) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…rashes) (#1273) Two independent bugs causing pre-existing HTTP 500 on rpc-capabilities, polkadot-rpc, ws-head-latency-*, evm-block-builders share-card endpoints. Reproduced locally with bun dev + shimmed try/catch to unmask the mid-stream Satori errors. Bug 1: Satori (the JSX-to-SVG renderer next/og uses) only decodes PNG / JPEG / SVG. Feed it AVIF or WebP bytes and it throws 'TypeError: u2 is not iterable' mid-render, surfacing as opaque HTTP 500. publicnode.avif, drpc.webp, lava.webp all trigger this on the RPC benches. Fix: skip AVIF/WebP extensions in getProviderLogoDataUrl, fall back to the initials chip. Bug 2: chipBackground / chipTextColor from src/lib/brand.ts return CSS var references (e.g. 'var(--color-ink-soft)') when the provider has no registered brand color. Satori evaluates var(...) to the CSS-wide 'initial' keyword and rejects 'background: initial', crashing the whole PNG. evm-block-builders is a full-cohort case (Titan, BuilderNet, Quasar, Eureka, Builder+, Vanilla — none have brand colors or logos). Fix: resolve var(...) fallbacks to the concrete INK_SOFT / PAPER hex from the route's own palette. Both fixes scoped to share-card route.tsx. src/lib/brand.ts untouched (still used by the HTML surfaces where CSS variables resolve at browser render time). Verified locally: 40/40 renders (8 slugs x 5 templates) return HTTP 200 with valid 1200x630 PNGs. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…h re-fetches (#1274) * TimeSeriesChart: forward chain prop to /api/series so chain switch re-fetches * chore: unstage branch-purge archive committed by mistake from another agent's untracked file --------- Co-authored-by: Florent Tapponnier <contact@mobula.io>
…itles) (#1275) Screenshot from user: rpc-capabilities leaderboard template renders the 101-char title 'Fastest free public RPC for Ethereum, BNB, Polygon and 23 more chains (plus Solana and Polkadot)' at fontSize=50 which wraps to 4 lines and overlaps the leaderboard rows underneath. Same crash on snapshot (fontSize=48 title overflows into the time-series chart). Fix: scaledTitleSize(base, title) helper ramps font size down for long titles. <=60 chars stays at base, >100 chars shrinks to 50% base. Keeps short titles at the original design size and only touches long ones. Applied to 4 templates: ranking 44/56 base leaderboard 50 base snapshot 48 base compare 36 base Headline stays untouched (title font is already 18 px because the template features the winner's big number, not the bench title). No layout math change, no CSS variable, no schema change. Just the one font-size call per template swapped for the helper. Co-authored-by: Florent Tapponnier <contact@mobula.io>
…them under sibling flex:1 (#1276) Co-authored-by: Florent Tapponnier <contact@mobula.io>
Co-authored-by: Florent Tapponnier <contact@mobula.io>
…ly (#1279) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…les) (#1280) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…orts) (#1281) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…s legend was still bleeding into footer) (#1283) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…oter) (#1284) Co-authored-by: Florent Tapponnier <contact@mobula.io>
… → header pills (#1285) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…1286) Co-authored-by: Florent Tapponnier <contact@mobula.io>
… for themselves (#1290) Co-authored-by: Florent Tapponnier <contact@mobula.io>
… on products, alternatives, compare) (#1291) Co-authored-by: Florent Tapponnier <contact@mobula.io>
…laude local state (#1293) Audit findings verified via grep (0 imports each): - src/components/back-link.tsx - src/components/hl-frontend-grid.tsx - src/components/hl-history-chart.tsx - src/components/logo-card-link.tsx - src/components/report-section-modal.tsx - src/components/share-section-modal.tsx Untrack Claude harness per-session/per-user files that change on every session and shouldn't be in VCS: - .claude/scheduled_tasks.lock (agent runtime lock) - .claude/settings.local.json (per-machine perms) Adds matching .gitignore rules so they never come back. .claude/skills/* stays tracked — those are intentional shared skill definitions. Co-authored-by: Florent Tapponnier <contact@mobula.io>
… missing) (#1294) Co-authored-by: Florent Tapponnier <contact@mobula.io>
Deep-audit confirmed via grep across the full repo (src/, harnesses/, worker/, scripts/, packages/): Fully deleted (0 refs anywhere): - src/lib/time-constants.ts: MS_PER_SECOND, MS_PER_MINUTE, MS_PER_HOUR, MS_PER_DAY — never imported. SECONDS_PER_* stay (used by scales.ts). Un-exported (only used internally in their own file): - src/lib/search-featured.ts: FEATURED_SLUGS re-exported ALL_SLUGS but the alias itself had no external consumer. - src/lib/categories.ts: CATEGORY_SLUG_BY_LABEL feeds only categorySlugFromLabel() one line below. - src/lib/dataset-jsonld.ts: ZENODO_CONCEPT_DOI and ZENODO_CONCEPT_URL are only used to compose GLOBAL_DATASET_JSONLD and buildBenchDatasetJsonLd() in the same file. - src/lib/materialize/schema.ts: SeriesRingSchema is only referenced by WorkerStateSchema's type inference (the SeriesRing type export stays — worker/index.ts imports it). Co-authored-by: Florent Tapponnier <contact@mobula.io>
Collaborator
Author
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.
Promoting dev to prod. Highlights over the last cycle:
Share-card (image generator) — Maxime UX pass
flexShrink: 0so long titles stop overlapping content (share-card: scale title font by length (fix overflow on long titles) #1275, share-card: flexShrink:0 on title/subtitle (fix Satori collapse under flex:1 sibling) #1276)GSC Dataset structured-data warnings — closed the 3 non-critical flags
creator/publisheron /products, /alternatives, /compare (seo: fix GSC Dataset warnings (embed creator + add distribution) #1291)@id-only override on /benchmarks/[slug] that GSC read as missing-creator (seo: keep inline creator on bench Dataset (unblocks GSC validation) #1294)distributionwithencodingFormat+contentUrlto all Dataset emittersPlus TimeSeriesChart tweaks (#1279, #1290) and small chore batches. Full log:
git log main..dev.