Skip to content

feat(sentry): Phase 11 toggle rework, metrics layer + PII scrubbers#111

Open
gmaclennan wants to merge 2 commits into
mainfrom
feat/sentry-metrics-phase11
Open

feat(sentry): Phase 11 toggle rework, metrics layer + PII scrubbers#111
gmaclennan wants to merge 2 commits into
mainfrom
feat/sentry-metrics-phase11

Conversation

@gmaclennan

@gmaclennan gmaclennan commented Jun 22, 2026

Copy link
Copy Markdown
Member

Implements the Sentry Phase 11 workblock (tracking #74) in one branch / one PR. Spec: docs/sentry-integration-plan.md §11.1–§11.8, §9b.1, §9b.5, Phase 5.

Part of #74 (tracking umbrella — remaining children #78#83 stay open)
Closes #75
Closes #76
Closes #77


#75 — Toggle rework (§11.1, §11.5, §11.6, §11.7, §11.2.b)

  • Rename captureApplicationDataapplicationUsageData everywhere: JS get/set, native bridge methods, the on-device stored key, the Expo plugin field, and the Node CLI flags.
  • Deprecated aliases kept for one minor release (JS get/setCaptureApplicationData, native setCaptureApplicationData, --captureApplicationData argv, plugin captureApplicationDataDefault with a warn-don't-error path).
  • One-shot stored-key migration (old → new, runs once on first prefs open) on both platforms.
  • New debug toggle: get/setDebugEnabled (JS), setDebugEnabled (native), sentry.debug + sentry.debugEnabledAtMs slots, --debug argv, debugDefault plugin field.
  • 24h auto-off (§11.5): at process start the debug reader flips debug=false if switched on >24h ago and queues a comapeo.debug.auto_disabled breadcrumb; re-enable refreshes the window. Both platforms.
  • Device classification (§11.2.b): new DeviceTags.{kt,swift} bucket the device low/mid/high by RAM + cores and compute <platform>.<major>. Passed to JS via sentryConfig.deviceTags and to Node via --deviceClass / --osMajor / --platformTag.
  • tracesSampleRate now derived from debug (1.0/0).

#76 — Metrics layer (§11.2, §11.3, §11.6, §11.8)

  • New backend/lib/metrics.js + src/sentry-metrics.ts: wrappers around Sentry.metrics.* injecting platform on every metric + units, attaching device_class/os_major only on the .by_device mirrors, no-op when Sentry is off.
  • Inventory recorded: RPC durations + error counts (client + server), boot-phase timings + outcome, sync-session metrics, a 60s backend memory + event-loop-delay sampler, state transitions, storage size bucket. (Sync-session / IPC-error / telemetry-forwarding / OS-low-memory helpers are present in the metrics module; see deferral note below for the call sites not yet wired.)
  • RPC hooks split on both sides: always record the metric; create a span only under debug, recording the metric while the span is active so it links to the trace (§11.3). src/ComapeoCoreModule.ts (onRequestHook) + backend/lib/sentry.js (rpcHook).
  • tracesSampleRate driven by debug; backend consoleIntegration moved behind debug.
  • beforeSendMetric forbidden-tag filter on the JS + Node metrics paths (shared regex list). Native SDKs: see deferral note.

#77 — PII scrubbers (§9b.1, §9b.5, Phase 5)

  • One shared regex list (rootKey markers, 22-char base64, lat/lng markers) used by both RN (src/sentry-scrub.ts) and Node (backend/before-send.js), each pointing at the other.
  • RN: real scrubber registered as beforeSend before the host's chain; URL-scrubbing beforeBreadcrumb.
  • Node: backend/before-send.js registered as a Sentry.addEventProcessor in lib/sentry.js's init.
  • Scrubs every text field: message, exception text, extra, contexts, breadcrumb message + data, span description + data (§9b.1).
  • HTTP breadcrumb URLs reduced to host-only (§9b.5).

Scrubber false-positive trade-off

The substring scrubber over-redacts by design — leaking a real project secret costs far more than a stray [redacted]:

  • 22-char base64 matches CoMapeo rootKey / hashed-project-id shapes but also any unrelated 22-char URL-safe base64 token (some JWT segments, git blob fragments, nonces).
    • aGVsbG8td29ybGQtMTIzNA[redacted] (real rootkey shape)
    • bm90LWEtcmVhbC1rZXktMQ[redacted] (harmless, false positive)
  • lat/lng markers redact the trailing number: latitude: -12.34latitude: [redacted]; even longitude: unknown-style prose loses its value.
  • HTTP URL host-only: https://cloud.comapeo.app/projects/abc?token=xhttps://cloud.comapeo.app — path/query detail lost, "all requests to host X failing" diagnosability kept.

The same patterns gate the metrics beforeSendMetric filter (forbidden tag names + base64-22 / lat-lng tag values).


Checks run locally

  • npm run lintpass (0 errors, 0 warnings)
  • npx tsc --noEmit (src) — pass
  • npm test (jest, src) — pass (18/18)
  • npm --prefix backend ci --ignore-scripts then node --test 'lib/**/*.test.mjs'pass (47/47)
  • backend rolldown build — pass; verified loader.mjs keeps @sentry/node-core behind the gated dynamic import.

Could NOT run locally (rely on CI)

  • Kotlin unit tests (ComapeoPrefsTest, SentryConfigTest, new DeviceTagsTest) — no Android SDK / Gradle here. Cover the stored-key migration, 24h auto-off boundaries, and device-classification boundaries (exactly 3 GB RAM, exactly 4 cores). Need the CI emulator/Gradle to execute.
  • Swift unit tests (ComapeoPrefsTests, SentryConfigTests, new DeviceTagsTests) — no Xcode here. Same coverage. Need CI/Xcode to execute.
  • backend npm run types is red on main already (pre-existing polywasm declaration gap, unrelated); the new production files type-clean.

Deferred (called out explicitly)

  • beforeSendMetric on the native (Android/iOS) SDKs is not yet wired — only the JS + Node metric paths run the forbidden-tag filter today. The native exit metric is the only native metric currently emitted and is already low-cardinality by construction; the native hook is a small follow-up.
  • Sync-session / IPC-error / telemetry-forwarding / OS-low-memory metric call sites are not all wired yet (the metrics.js helpers exist; sync-session lifecycle plumbing is a Phase 5 item). The always-on RPC, boot, memory, state, and storage metrics are wired end-to-end.

🤖 Generated with Claude Code

gmaclennan and others added 2 commits June 22, 2026 12:34
Implements the Sentry Phase 11 workblock (plan §11, §9b.1, §9b.5):

#75 toggle rework
- Rename captureApplicationData -> applicationUsageData across the JS
  API, native bridge methods, on-device stored key, Expo plugin field,
  and Node CLI flags. Deprecated aliases forward for one minor release;
  a one-shot stored-key migration runs on first prefs open (both
  platforms).
- New `debug` toggle (get/setDebugEnabled, sentry.debug +
  sentry.debugEnabledAtMs slots, --debug argv, debugDefault plugin
  field) with a 24h auto-off enforced in the native debug reader.
- Device classification (DeviceTags.{kt,swift}): low/mid/high by
  RAM + cores plus <platform>.<major>, plumbed to RN via
  sentryConfig.deviceTags and to Node via --deviceClass/--osMajor/
  --platformTag.
- tracesSampleRate now derives from debug (1.0/0).

#76 metrics layer
- New backend/lib/metrics.js + src/sentry-metrics.ts: wrappers that
  inject `platform` on every metric, attach device tags only on the
  .by_device mirrors, no-op when Sentry is off, and drop forbidden
  tags. RPC hooks split: always record the metric, span only under
  debug (recorded while active so it links to the trace). console
  integration moved behind debug; 60s memory/event-loop sampler,
  boot-phase durations, state transitions, storage-size bucket.

#77 PII scrubbers
- Shared regex list (rootKey, 22-char base64, lat/lng) in
  src/sentry-scrub.ts (RN) and backend/before-send.js (Node). RN wires
  the real beforeSend ahead of the host chain plus a host-only URL
  beforeBreadcrumb; Node registers the same scrub as an event
  processor. Walks message, exception, extra, contexts, breadcrumb
  message+data, span description+data; HTTP breadcrumb URLs reduce to
  host-only.

Tests: backend metrics/before-send suites, extended sentry suites
(debug branching + scrubber), native migration/24h-auto-off/device
boundary tests. npm lint, tsc, jest (18), backend node --test (47)
all green locally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gmaclennan gmaclennan marked this pull request as ready for review June 22, 2026 12:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant