feat: Adds observability domain with Sentry, Tempo, telemetry cost control skills - #76
Conversation
sentry-mcp-queries: document data-fidelity loss on older releases for longer-range (30D+) queries (sample-rate drift, extrapolation hiding thin samples, retention downsampling) and percentile (p75+) sample-size/quality filtering; add table rows + pitfalls for stored-span-count and superseded-patch releases. performance-attribution: new skill for attributing release-over-release p75/p95 movements to code changes via black-box diff analysis, with an extension repo file (Trace Explorer queries, key transactions, highest-sample-patch version selection, 90d-vs-30d empirics, hot-path files, core-package changelog analysis, worked v13.11->v13.15 catalogue). analytics-instrumentation: cross-link volume-estimation caveats to the new fidelity guidance. CHANGELOG updated.
…n-out, latent trace? param, trace-arg PR-review scan, per-name budget
…cidental instrumentation)
CHANGELOG.md tracks consumer-facing changes to the `@metamask/skills` package, per CONTRIBUTING's "CLI / tooling changes" section. No merged skill-only PR adds an entry (#80, #78, #70, #62, #61 all touch zero changelog lines). Carrying one here bought nothing and was the sole source of this branch's conflict with `main`, since every skill PR edits the same `[Unreleased]` block. Restoring the file to its merge-base state makes the branch conflict-free without a merge commit.
Context budgetWhat this PR costs an agent, measured from an install, with tokens estimated as UTF-8 bytes/4. All six are
Description is the only tier an opted-in install pays unconditionally. The Selected is the whole installed Method
The squash commit a31f624 carries the same six skill files, overlays, knowledge file and |
The skill lives in the `analytics` domain, so the prefix repeated what the path and every discovery surface already show. Installed as `mms-instrumentation`.
"Cross-ref" describes the mechanism and reads as a generic pointer. The skill produces a correlation: one trace joined across two stores by `trace_id`, plus a reading of which absences are expected. The vendor names stay. They are load-bearing here rather than incidental — the skill is about the split between Sentry and Grafana Tempo specifically, and is not source-agnostic.
The setup block asked for `grafana_session` from an authenticated browser and offered no alternative, so following the skill as written meant extracting a session credential and exporting it into a shell. Sentry in the neighbouring skill already uses a scoped bearer token, which is the shape this should have had. A service account token, Viewer role, covers every query here. It is scoped to what the skill needs, revocable on its own, and attributable in an audit log to a purpose rather than to a person. The cookie stays as a documented fallback for instances that disallow service accounts, with the cost stated where someone deciding between them will read it: a session carries the whole of your Grafana authority rather than one datasource's read access, expires on a schedule you do not control, cannot be revoked without ending your own session, and is indistinguishable from you afterwards. The correlation skill's credential note said "an expired Grafana session"; it now names a token without datasource scope, so the two skills describe the same auth path.
analytics domain - Sentry, MetaMetrics, Segment, Tempo query, instrumentation, quota skills
analytics domain - Sentry, MetaMetrics, Segment, Tempo query, instrumentation, quota skillsanalytics domain - /sentry-mcp-queries, /sentry-grafana-correlation, /grafana-tempo-queries, /instrumentation, /performance-attribution, /sentry-quota skills
analytics domain - /sentry-mcp-queries, /sentry-grafana-correlation, /grafana-tempo-queries, /instrumentation, /performance-attribution, /sentry-quota skillsanalytics domain - Sentry, Tempo, MetaMetrics, Segment skills and knowledges
## Summary - Adds `privacy-egress-diligence` to `security` — review for changes to what user data leaves the device. - Fills the one proof-standard domain with no lane today. Raised during [ADR-0058 review](MetaMask/decisions#173): security, observability/data, and ci/devex/build all have coverage; compliance/privacy had none. ## Why this surface `app/scripts/constants/sentry-state.ts` decides what egresses. Measured on `metamask-extension` at the current head: - **116 fields set to `true`** — the real value is copied and sent to Sentry. - Edited inside **ordinary feature PRs** — recent changes ride onboarding, swaps, rewards, and analytics-controller work. - **No CODEOWNERS entry**, so no privacy reviewer is automatically tagged. A file governing data egress, changed casually, reviewed by whoever happened to review the feature. ## Shape Deliberately the same as `lavamoat-policy`: detection is mechanical, judgement is not. `maskObject` (`shared/lib/object.utils.ts`) makes the risk one-way — unlisted fields degrade to a `typeof` string, so only a field promoted to `true` widens egress, and `git diff` finds those exactly. **The trap it names:** "the field is in the mask, so someone decided it was fine." The mask *is* the decision. Presence proves authorship, not review. So the deliverable is what each field holds at runtime — a mask path cannot distinguish `selectedTab` from `selectedAddress` — sorted into: | Bucket | Action | |---|---| | Safe | note the type that makes it safe (bounded enum, boolean, count) | | Needs narrowing | propose a nested mask keeping the shape, dropping the leaves | | Must not egress | propose `false` or a non-identifying substitute | It also covers the sibling pipes a PR widens at the same time: new MetaMetrics/Segment properties, and error strings interpolating runtime values, both of which leak regardless of the mask. **No accept/reject verdict.** Whether a field is acceptable to collect belongs to privacy and legal; a confident reviewer "this is fine" is exactly the artifact that lets an unreviewed field through. ## Notes - Experimental. One skill, no knowledge files. - Lands in `security` rather than a new `privacy` domain — a one-skill domain is premature, and the diligence pattern already lives there. Say the word if you'd rather it were separate. - Complements `instrumentation` (#76), which covers whether an event is correctly *identified* and consent-*gated*. This covers whether its payload is *sendable*. - No `CHANGELOG.md` entry: skill-only, no CLI change. --------- Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com> Co-authored-by: behroozreview <behrooz.aghakhanian@gmail.com>
…o `data` `analytics` covered two subjects under one name. Five of the six skills and `span-sub-sampling` are Sentry, Tempo and Grafana — traces, errors and the span budget, which is observability. The MetaMetrics and Segment material is product analytics, and with MetaMetrics migrating to `AnalyticsController` in both clients it needs a name that survives that. `instrumentation` stays in `observability`: it names Sentry spans alongside MetaMetrics and Segment events, but the body runs about three to one on spans. Known consequence, not yet resolved. `instrumentation` cites `metrametrics-identity` and `segment-governance`, and `sentry-quota` cites `segment-governance` — all three now cross a domain boundary. The installer copies domain knowledge per skill, so `data` shipping no skill of its own means that knowledge installs nowhere until it gains one.
analytics domain - Sentry, Tempo, MetaMetrics, Segment skills and knowledgesobservability and data domains - Sentry, Tempo, Grafana skills; product-analytics knowledge
`span-sub-sampling` still declared `domain: analytics` after the rename. `lint-skill-entry` requires `domain` to match the parent directory, so the rename shipped a lint error — caught by checking the merge into `main`, not by checking this branch, which predates `tools/skill-schema.mjs` and cannot run the linter at all. `domains/data/` moves to #143 with the same fix applied.
observability and data domains - Sentry, Tempo, Grafana skills; product-analytics knowledgeobservability domain — Sentry, Tempo and span-budget skills
observability domain — Sentry, Tempo and span-budget skillsobservability domain with Sentry, Tempo, telemetry cost control skills
observability domain with Sentry, Tempo, telemetry cost control skillsobservability domain - /sentry-quota, /sentry-mcp-queries, /grafana-tempo-queries, /sentry-grafana-correlation, /instrumentation, /performance-attribution skills
observability domain - /sentry-quota, /sentry-mcp-queries, /grafana-tempo-queries, /sentry-grafana-correlation, /instrumentation, /performance-attribution skillsobservability domain with Sentry, Tempo, span-budget skills
observability domain with Sentry, Tempo, span-budget skillsobservability domain with Sentry, Tempo, telemetry cost control skills
Both platform teams co-own the domain, as they do `coding`, `general`, `performance` and `pr-workflow`. A client's overlay is owned by that client's platform team, placed directly under the domain line so it wins on last-match and so each domain PR inserts at its own anchor.
metamask-extension#44451 (reduce Sentry trace sampling) lowered the fallback `tracesSampleRate` from 0.0075 to 0.005, and `tracesSampler` takes precedence over it. Span `count()` is already extrapolated, so multiplying it by the inverse rate counted twice. The Sentry project is `metamask`. A backend span that starts after its supposed parent ended is not its child. Routing to Sentry is decided per trace, and the background continues UI contexts as sampled. The removed `isOptIn` rule is replaced by the `excludeMetaMetricsId` behavior, and knowledge that moved to the `data` domain is named by its path there.
Check the stored `count_sample()` before trusting an extrapolated count, run an unfiltered control before reading a zero, and treat an issue as a grouping bucket rather than a fault. The serialized trace context carries no sampled flag, UI and background clocks can disagree by an hour, and a dependency or SDK-integration change can add span volume with no `trace(` in the diff. Release filters, ingestion lag and error metering get their limits stated, and the correlation skill names phantom parents, window traps and the time a CDN or queued connection adds.
A trace name a PR adds or reroutes may already be live in the target project, and then the review is a change to measured volume. For a name new to the target, the other client where it already ships is the reference class, and only the names the diff can actually start there carry over.
…-description-over-1024 * origin/main: feat: add navigation skill with MetaMask Mobile overlay (#148) feat: add feature-flags skill with MetaMask Mobile overlay (#147) feat: add analytics skill with MetaMask Mobile overlay (#140) feat: Adds `observability` domain with Sentry, Tempo, telemetry cost control skills (#76) refactor(perps): review skill composes the perps library instead of carrying knowledge copies (#159) # Conflicts: # README.md
…-description-over-1024 * origin/main: feat: add navigation skill with MetaMask Mobile overlay (#148) feat: add feature-flags skill with MetaMask Mobile overlay (#147) feat: add analytics skill with MetaMask Mobile overlay (#140) feat: Adds `observability` domain with Sentry, Tempo, telemetry cost control skills (#76) refactor(perps): review skill composes the perps library instead of carrying knowledge copies (#159) # Conflicts: # README.md
Motivation
The
observabilitydomain covers a) system telemetry via Sentry, Grafana Tempo, and b) traffic control for span volume.Overview
Adds the
observabilitydomain with six skills on Sentry, Grafana Tempo, the Sentry span quota and release performance attribution.sentry-quotareviews code and PRs for span instrumentation that risks the quota. It checks each span for three problems: a) fan-outs (loop, poller, selector, ortracecallback forwarded into aMetaMask/corecontroller that emits multiple spans per trace), b) always-on with no per-trace sub-sampling gate, and c) no env-flag kill switch. All three together form an anti-pattern that causes anomalous span volume and quota breach.domains/observability/knowledge/span-sub-sampling.md: Knowledge file on the per-trace sub-sampling gate: a sub-rate keyed on the trace id and applied to a high-frequency custom span, so every gated span in a trace is kept or dropped together.sentry-mcp-queriesqueries Sentry via MCP for triage, volume, release comparison and replay.grafana-tempo-queriesqueries backend traces with TraceQL. Before trusting a result, it runs two checks. It confirms the Grafana session is live, because an expired session returns an empty body that reads as "no traces". It confirms the TraceQL filter is actually applied, by running a query whose filter can match no trace: if traces come back, the filter was ignored.sentry-grafana-correlationjoins a trace across Sentry and Tempo, and diagnoses why a trace appears in only one of them.instrumentationcreates and updates Sentry spans, MetaMetrics and Segment events.performance-attributionattributes release-over-release p75/p95 movement in Sentry transactions, such asUI Startup, to specific code changes.Public repo: hosts, datasource uids, org slugs and project ids are read from environment variables (
GRAFANA_HOST,GRAFANA_ORG,TEMPO_UID,SENTRY_ORG,SENTRY_PROJECT_ID), not hardcoded.