feat(sentry): trim native scope per privacy tier and filter native metrics#200
Merged
Conversation
…trics Implements the native-scope field split (§9b.3), boot-transaction slimming (§9b.4), and backend free-memory/disk refresh (§9b.6) from issue #79, plus the forbidden-tag filter for native metric emissions from issue #191. - Android: TierScopeEventProcessor rebuilds device/os/app contexts from a per-tier allowlist, drops culture at diagnostic, buckets storage size, and slims comapeo.boot transactions (boot.kind tag + span data) at diagnostic. Wired via SentryFgsBridge.init. - iOS: SentryScopeTier does the same via beforeSend/beforeSendSpan in SentryNativeBridge.initFromConfig. - Both countMetric paths now run a hand-mirrored isForbiddenMetric check matching src/sentry-scrub.ts and backend/before-send.js. - Backend: node-resources event processor re-reads os.freemem/statfs on every capture, usage tier only, wired from loader.mjs positionals. Closes #79 Closes #191
gmaclennan
commented
Jul 8, 2026
…s, quieter metric-drop log Addresses the review comments on the native-scope-tier work: - Error/fatal events now keep the SDK's full device/os/app scope instead of the per-tier allowlist — device context is most valuable exactly when something crashed. Only `culture` (locale + timezone), a fingerprint surface with no debugging value, is still dropped from them at the diagnostic tier. Transactions and non-error events are unchanged. (Android + iOS) - Storage-size buckets now start at 8 GB (8/16/32/…/1024) so devices with 8/16 GB of storage, which are still in the field, aren't rounded up to 32. - The "countMetric dropped: forbidden attribute" log drops from warn to debug on both platforms — an innocuous, expected drop that can recur often. Also inlines a redundant local in backend/lib/sentry.js and updates the per-tier field tables in the plan/integration docs. Adds per-platform tests for the error-scope exemption and the new low-end buckets. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XwJPDuhUABN1VftbXVZAb5
Inside the `SentryNativeBridge` enum an unqualified `log(...)` binds to the enum's own static `log(level:message:)` member, which shadows the global `Log.swift` helper and doesn't match the `(_ message:, level:)` labels — a pre-existing compile error in the metric-scrub drop path that broke the Swift Package Tests. Module-qualify the call as `ComapeoCore.log(...)`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XwJPDuhUABN1VftbXVZAb5
gmaclennan
enabled auto-merge
July 8, 2026 15:52
`compileDebugUnitTestKotlin` rejected `mutableMapOf("k" to <literal>)` passed
to sentry-java's `SentrySpan(..., data: Map<String, Object>?)` — the inferred
`MutableMap<String, Boolean>` / `<String, String>` don't match the platform
type's invariant lower bound, so Kotlin demands an explicit type. Annotate both
call sites as `mutableMapOf<String, Any>(...)`. Pre-existing in the new test
file; surfaced once the Swift build stopped short-circuiting the run.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XwJPDuhUABN1VftbXVZAb5
`SentryFgsBridgeTest.countMetricWithForbiddenAttributeIsDropped` throws because the forbidden-attribute drop path calls `android.util.Log`, whose android.jar stub throws in JVM unit tests (and the bridge's catch then re-throws via a second Log call). The module never set `returnDefaultValues`, so this only passed while a sibling test file's compile error kept the suite from running. Enable `testOptions.unitTests.returnDefaultValues` so Log no-ops; the real org.json / sentry-android test deps still take precedence. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XwJPDuhUABN1VftbXVZAb5
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Jul 8, 2026
The forbidden-attribute gate in `countMetric` fires on an expected, innocuous condition, so the drop doesn't warrant a log — and on iOS the global `log()` helper forwarded it to Sentry's log pipeline, adding noise on a path whose job is to keep data off the wire. Drop it silently on both platforms. This also removes the need for the earlier test-config change: with no `android.util.Log` call on the drop path, `SentryFgsBridgeTest`'s forbidden-metric test no longer trips the unmocked-stub throw, so the `testOptions.unitTests.returnDefaultValues` addition is reverted. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XwJPDuhUABN1VftbXVZAb5
gmaclennan
enabled auto-merge
July 8, 2026 16:22
…rformance-tohz1o # Conflicts: # docs/sentry-integration-plan.md
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.
Closes #79
Closes #191
The Android and iOS Sentry SDKs attach a lot of device detail to every event by default. This trims that to what each privacy tier promises (plan §9b.3), slims the boot transaction (§9b.4), keeps the backend's free-memory/free-disk numbers fresh on every event at the usage tier (§9b.6), and adds the forbidden-tag metric filter the JS/Node paths already have to the native
countMetricpaths.On Android a new
TierScopeEventProcessor(registered inSentryFgsBridge.init, which now receives theapplicationUsageDataflag) rebuilds the device/os/app contexts from a per-tier allowlist — diagnostic keeps manufacturer/brand/model/model id/family/arch/simulator/core count/memory size plus OS name+version and app id/version/build; the usage tier adds back kernel version,Build.DISPLAY, app name, the culture block, and screen metrics. Storage size is bucketed to standard marketed sizes (32–1024 GB) at both tiers, andcomapeo.boottransactions at diagnostic lose theboot.kindtag and all span data while keeping phase spans, timings, and bare phase-name descriptions. iOS mirrors this withSentryScopeTier, wired asbeforeSend/beforeSendSpaninSentryNativeBridge.initFromConfigand operating on the dictionary-shaped cocoa contexts. Rebuilding from an allowlist (rather than nulling a denylist) means fields added by future SDK versions are dropped by default.For #191,
SentryFgsBridge.countMetricandSentryNativeBridge.countMetricnow run a hand-mirroredisForbiddenMetriccheck (SentryMetricScrub.kt/SentryMetricScrub.swift) before reaching the SDK, matching the shared list insrc/sentry-scrub.tsandbackend/before-send.js; all four copies now point at each other.On the backend, a
node_resourcesevent processor (backend/lib/node-resources.js) re-readsos.freemem/os.totalmemandfs.statfsSyncof the private storage dir on every capture. It is usage-tier-only (read-at-capture frequency is itself usage-shape data) and checks the live tier state per event so repeatedinit()in tests stays order-independent.loader.mjsnow forwards the storage-dir positional toinitSentry.Tests: per-tier field assertions on both platforms (
SentryScopeTierTest.kt,SentryScopeTierTests.swift), boot-transaction slimming both tiers, forbidden-metric drop vs. ordinary exit-metric pass on both platforms (including an SDK-level check on Android via the metricsbeforeSendseam), and backend tests for freshness, statfs failure tolerance, and the usage-tier gating end-to-end through the envelope sink. Docs updated where they described the old fatal-only freemem behaviour.