MetaMask / MetaMask/metamask-extension

[P1] Add Sentry quota monitors/alerts for rate-limited and discarded telemetry

Open
#43,411 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

INVALID-ISSUE-TEMPLATE team-extension-platform
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.