fix(sentry): gate non-actionable client noise before it leaves the device (AGE-105) - #169
Merged
Conversation
…vice opencode-mobile is now the org's #1 Sentry volume source (~4,500 events/mo against a 3,500/mo org quota, AGE-105). ~1,100 of those events are three non-defects: `connect timeout` (462), `connect server-unreachable` (157), and one device's `API Error: 401` token-refresh loop firing 498 times. Adds a pure, unit-tested noise gate (src/lib/sentry-noise.ts) wired into `beforeSend`, applying three layers cheapest-first: 1. Always-send allowlist — OOM/ANR/native/fatal crash classes bypass every limit. Quota is worthless if it silences real crashes. 2. Transport drop-list — hard drop for client-side network conditions. Hard, not sampled: the gate runs per-install, so "1 per device per day" would multiply by the install base straight back into thousands per month. 3. Dedup + rate cap — 6h per-fingerprint cooldown, ≤6 new fingerprints/h, ≤10 events/h, mirroring the openclaw-box-bot shim (AGE-55). Nothing is lost by the transport drop: those failures are already user-visible as connection UI and already trended, PII-free, as the PostHog `connection_failed{error_class}` event. captureDiagnostic() also short-circuits for those classifications so the event is never even built. Drops are auditable — the count since the last delivered event rides along as a `noise.dropped_since_last` tag. Replaying the observed 1,126-event hour through the gate yields 5 delivered events (1 auth report + 4 real OOMs). Tests: 18 new, 257 total passing; tsc --noEmit clean. Co-Authored-By: Paperclip <noreply@paperclip.ing>
dzianisv
pushed a commit
that referenced
this pull request
Aug 14, 2026
…users Ships 7c8bc7d (#169). Until this release, the filter exists only in main: every installed build still uploads `connect timeout` / `connect server-unreachable` and un-deduped retry loops, which is what makes opencode-mobile the org's #1 Sentry volume source (~4,500 events/month against a 3,500/month org quota). User-visible change is deliberately small — quieter crash reporting, real crashes unaffected — so the Play changelog says exactly that. Co-Authored-By: Paperclip <noreply@paperclip.ing>
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.
Why
opencode-mobileis now the #1 source of Sentry error volume in the org — ~4,500 events/month against a 3,500/month org quota. Box-bot was silenced by the AGE-55 shim (50.7 -> 0.00 events/h); mobile is what's left.~1,100 of those events are three non-defects:
The
connect ...ones arecaptureDiagnostic()reports of the user's own LAN/VPN/self-hosted box being down. The 401 storm is one device's token-refresh retry loop: 498 copies of one problem, not 498 problems.What
New pure module
src/lib/sentry-noise.ts, wired intobeforeSend. Three layers, cheapest first:IllegalStateException/NullPointerException/ fatal level / unhandled mechanismconnect timeout/server-unreachable/no-internet/malformed-url,Network request failed,Request timed out after,ECONN*/ETIMEDOUT...openclaw-box-botshim (AGE-55). Turns a retry loop into one report and caps the blast radius of any future regression.connect health-failedandconnect tls-errorare deliberately not dropped — a box that answers but is unhealthy, or a broken cert, is actionable.We don't lose the signal
Connection failures are already (a) shown to the user as connection UI and (b) counted, PII-free, in PostHog as
connection_failed{error_class}viaanalytics-classify.ts. Sentry was charging us per event for a graph we already have.captureDiagnostic()now short-circuits for those classifications so the event isn't even built.Drops stay auditable: the count since the last delivered event rides along as a
noise.dropped_since_lasttag on the next event that does go out.Verification
src/lib/sentry-noise.test.ts(pure, deterministic clock — no sleeps).npm test: 257 passing.npm run typecheck: clean.Follow-up (not in this PR)
Tracked in AGE-105.