MetaMask / MetaMask/metamask-extension
[P1] Add Sentry quota monitors/alerts for rate-limited and discarded telemetry
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 13.2k
- Forks
- 5.6k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 451
Description
**Parent Epic:** [#43410 - Sentry Quota Breach Incident — Extension Telemetry](https://github.com/MetaMask/metamask-extension/issues/43410)
**Labels:** `team-extension-platform`
**Priority:** P1
---
## 🎯 Goal
Add Sentry monitors/alerts so that quota exhaustion, rate limiting, and discarded telemetry on the `metamask` project trigger an alert within hours, not days.
---
## 📝 Context
During the May 28 – Jun 2026 quota breach, the `metamask` project was rate-limited and dropping incoming telemetry for **6 days before anyone noticed** — the incident coordinator confirmed no alerts fired because none are configured for this scenario ([alert list](https://sentry.io/organizations/metamask/monitors/alerts/?project=273505)). The discarded data was only visible by manually checking [Stats & Usage](https://metamask.sentry.io/settings/stats/?clientDiscard=false&dataCategory=transactions&project=273505&statsPeriod=14d&transform=periodic).
**Discarded-volume alerting is necessary but not sufficient.** It fires only once the project is already over budget and shedding data. A second class of incident precedes that state: a single instrumentation source growing to dominate volume *before* the quota is breached. `AssetsDataSourceTiming`/`AssetsUpdatePipeline` (#43211) and `AggregatedBalanceSelector` (#44447) each ran for roughly a week undetected, the second reaching 91% of all transaction volume, because nothing alerts on per-transaction-name share. Volume anomaly detection has to be per-name, not on aggregate totals.
**Measured 2026-08-16: the discarded-volume alert would not have fired once in the last ten weeks.** `rate_limited` for the `metamask` project ran 3,789,783/day (May 24–30) and 1,598,470/day (May 31–Jun 6), then **0 for every week from Jun 7 to Aug 15** — while accepted transactions ran 200M/month against a 13M/month pre-May baseline, a sustained 15x overrun. The trial absorbs the excess, so nothing is discarded and criterion 1 stays silent throughout. Under a trial or an overage arrangement, discard-based alerting is not merely insufficient, it is inert; criteria 2 and 3 are the only ones that fire.
**Per-name share has a structural blind spot: fanned-out families.** `Background RPC:*` is 36.3% of all billed transactions (231,879 of 641,094 raw, 2d) but is spread across ~100 distinct names — `Background RPC: trackMetaMetricsPage`, `: tokenListStartPolling`, `: lookupSelectedNetworks` and so on — each individually ~2.5% or less. A per-name threshold tuned to catch `AggregatedBalanceSelector` at 91% share will never fire on a family that is a third of all volume. Per-name alerting therefore needs a **family-prefix aggregation** alongside it (`Background RPC:*`, `Messenger Call:*`, `Perps *`), or the largest single contributor found to date is invisible to it.
There is also no server-side backstop to lean on: server-side rate limits apply to errors only, so alerting is the primary guard for transactions/spans. Sentry metric alerts support absolute, % change, and anomaly-detection types (confirmed in the 2026-07-21 account meeting; documentation and a deep-dive session on 2026-07-28 to follow) — anomaly detection is the candidate for the new-name/ramp incident shape, but must be validated against a release-adoption ramp before being relied on, since spike protection re-baselines through exactly that shape.
---
## ✅ Acceptance Criteria
- [ ] Alert on server-side discarded/rate-limited event volume exceeding a threshold (transactions/spans and errors).
- [ ] Alert on spend-allocation / performance-unit consumption rate that projects to exhausting the monthly budget early (e.g. >X% of the monthly slice consumed in 24h).
- [ ] **Alert on per-transaction-name volume anomaly:** a transaction name exceeding a threshold share of total transaction/span volume, and a previously-unseen transaction name appearing with material volume. This is the alert that would have caught #43211 and #44447 within hours rather than a week. Aggregate-total alerts do not, because a single name reaching 91% share does not necessarily breach the total budget on its own.
- **BLOCKED on a prerequisite — the intended data source does not work for this org.** The plan was the legacy Discover "Transactions" (metrics-enhanced) dataset, whose per-name `count()` is extracted before dynamic sampling. Generic metrics extraction is **disabled for this organisation**, and the API does not error: it returns HTTP 200 with plausible per-name numbers and marks the fallback only in the response metadata.
```
"isMetricsData": false,
"isMetricsExtractedData": false,
"datasetReason": "generic metrics performance queries are disabled"
```
The numbers it returns are the *retained sample*, not pre-sampling volume — `AggregatedBalanceSelector` came back as 488,213 against a `count_unique(id)` of 485,234 for the same window. An alert built on it would silently threshold the wrong quantity.
- **No available instrument measures per-name billed volume.** Measured 2026-08-16, project 273505, 7d: EAP `count()` (extrapolated) 285,388,043 — **5.06x above** billed; `stats_v2` accepted 56,459,664 — authoritative but **category-only, never per name**; EAP `count_unique(id)` (retained) 2,688,733 — **21.0x below** billed. Retention is also non-uniform per name (0.212% for `Provider Create Accounts (v2 - batched)` against 7.424% for `Publish`, a 35x spread inside the top 40), so retained shares cannot be rescaled to billed shares either.
- [ ] **Prerequisite: ask Sentry to enable generic metrics extraction for the org**, then re-run the check below. Until that lands, this criterion cannot be implemented as written, and a share-based alert should not be built on Explore data.
- [ ] Verification check, once enabled — and it must assert `isMetricsExtractedData: true` rather than assuming a 200 means extraction ran: compare a Discover per-name sum against [Stats & Usage](https://metamask.sentry.io/settings/stats/?clientDiscard=false&dataCategory=transactions&project=273505&statsPeriod=14d&transform=periodic) accepted volume for the same window, then define the per-name metric alerts on that dataset.
- [ ] **Alert on transactions-per-trace ratio, per transaction-name family.** This is the detector that catches fan-out defects, which the share-based alerts structurally cannot. Measured 2026-08-16: healthy families sit at 1.0-1.4 transactions per trace (`/service-worker.js` 1.0, `Perps Funding Fetch` 1.0, `Publish` 1.1, `Transaction` 1.4), while defective ones stand out unambiguously — `Background RPC:*` **11.5**, `Provider Create Accounts (v2 - batched)` **4.3**, `Messenger Call:*` **3.7**, `Perps *` (siblings combined) **2.94**. Each is the same defect: `resolveParentSpan` returns null cross-process, `startSpan` falls to `sentryContinueTrace(..., parentSpan: undefined)`, and every call becomes its own root.
- The ratio is dimensionless, so unlike absolute or share thresholds it does not need re-tuning against release-adoption ramps — the shape that spike protection re-baselines through.
- **It is also the only detector here that survives the sampling problem above.** Retention is decided per trace and is constant within one, so transactions-per-trace is measured correctly in the retained sample even though per-name *shares* are not. That makes this criterion implementable today, on Explore data, while the share-based criterion stays blocked.
- It identifies the defect class, not just the volume, so the alert points at a fix rather than at a sampling decision.
- Query shape: `count_unique(id) / count_unique(trace)` grouped by transaction name over `is_transaction:true`.
- [ ] **Alert on aggregate accepted volume against the allocation, independent of discard.** Given the finding above, a monitor on accepted transactions/month vs the project's 30M allocation is the only aggregate signal that works while a trial or overage arrangement is absorbing the excess.
- [ ] Alerts route to the owning team's Slack channel and on-call, not just email.
- [ ] Investigate whether Sentry monitors can trigger automated responses beyond alerting/issue creation (open question already posed to the Sentry team in [ext-consensys-sentry](https://consensys.slack.com/archives/CTQAGKY5V/p1780657942902159?thread_ts=1780569185.918889&cid=CTQAGKY5V)).
- [ ] Alert configuration documented in the telemetry-quota runbook.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the Sentry Stats & Usage and Discover checks described in the acceptance criteria, verifying isMetricsExtractedData before trusting per-name data. Confirm the generic metrics extraction prerequisite with Sentry, then evaluate the transactions-per-trace query, accepted-volume and discard signals, and alert routing. Done means validated monitors for the feasible criteria, documented configuration in the telemetry-quota runbook, and clear handling of blocked share-based alerts.
Written by the indexing model from the issue text.
Assessment
- Domain
- observability-sre
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100