Skip to content

feat(sentry): usage-tier sync-session transaction, sync metrics wiring, bg/fg breadcrumbs#199

Open
gmaclennan wants to merge 2 commits into
mainfrom
claude/sentry-sync-session
Open

feat(sentry): usage-tier sync-session transaction, sync metrics wiring, bg/fg breadcrumbs#199
gmaclennan wants to merge 2 commits into
mainfrom
claude/sentry-sync-session

Conversation

@gmaclennan

Copy link
Copy Markdown
Member

Closes #80.

Sync-session transaction + metrics

@comapeo/core exposes two usable sync lifecycle signals: each project's $sync emits sync-state (with data.isSyncEnabled and a per-peer map of remaining want/wanted block counts), and MapeoManager emits local-peers. There is no project-opened event and no per-phase events, so the new backend/lib/sync-observer.js wraps manager.getProject (the only project-open hook) and derives a session from the data.isSyncEnabled edges: false→true starts it, true→false (manual stop or autostop-after-synced) ends it. Outcome is completed when the last peer-bearing state had nothing left to send or receive in either namespace group, else stopped.

The comapeo.sync.session transaction is usage-tier: it is only created when applicationUsageData is on, and a name-matched branch in a new tracesSampler (backend Sentry.init) samples it at 1 so it records while the base trace rate is 0; all other spans keep the previous parent-based / native-resolved-rate behaviour. Its attributes are restricted to outcome, peers_bucket, bytes_bucket — no peer identities, no project IDs (asserted in tests against the serialized envelope).

Two honest limitations, from what the core API actually exposes:

  • Child spans are sync.discover (session start until the first peer appears; skipped when peers are already connected) and sync.replicate. A handshake phase is not derivable — the noise/protomux handshake is internal to core and surfaces no event.
  • Bytes are not derivable: the sync state carries remaining block counts, not byte counters, so bytes_bucket reports unknown (on both the transaction and the counter) until core exposes bytes. The §9.2 table row notes this.

The same session end wires the previously call-site-less metrics.syncSession emitter: comapeo.sync.session.duration_ms stays diagnostic-tier, the peers/bytes bucket counters stay usage-gated inside the helper. peersBucket gains a 0 bucket for sessions where no peer ever connected.

RN bg/fg breadcrumbs

src/sentry.ts attaches an AppState change listener at module load (same pattern as the existing state listeners): transitions to background/active add comapeo.app.background / comapeo.app.foreground breadcrumbs so an error reads as "fired N seconds after backgrounding" from crumb timestamps. Gated on sentryReady plus a snapshot-at-launch applicationUsageData read; iOS transient inactive and repeated same-direction events are ignored. No dependency change — @sentry/react-native remains a peer dependency.

Docs

§9.2 tier table: removed the "not yet wired (#80)" markers from the three sync rows only (the shutdown/ipc/telemetry rows belong to #190) and documented the bucket sets / unknown bytes limitation.

Tests

Backend (sync-observer.test.mjs, real SDK + OTel wiring like sentry.test.mjs): usage on ⇒ transaction envelope reaches the sink with only the allowed attributes and the derived child spans; usage off ⇒ no envelope, duration metric still records, bucket counters absent; stopped outcome; zero-peer bucket; watcher seeded mid-session. RN (sentry.test.js): crumbs added when usage tier on, deduped, absent when tier off or Sentry never initialised. npm run lint, npm run build, npm run test (72) and npm run backend:test (78) all pass. Not verified on-device; the backend tests drive the real Sentry SDK end to end.

…g, bg/fg breadcrumbs

Derive sync sessions from the data.isSyncEnabled edges of each project's
$sync sync-state events: a comapeo.sync.session transaction (usage-tier,
sampled via a name-matched tracesSampler so it records while the base
trace rate is 0) with discover/replicate child spans, carrying only
bucketed peer count, bucketed bytes, and outcome. The same lifecycle
wires the previously call-site-less metrics.syncSession emitter
(duration at diagnostic tier, peers/bytes buckets usage-gated). RN side
adds comapeo.app.background/foreground breadcrumbs from AppState
changes, usage-gated. Closes #80.
@github-actions github-actions Bot added the feature New feature (changelog) label Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature (changelog)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sentry: sync-session transaction + bg/fg breadcrumbs (usage tier)

1 participant