Skip to content

Attach user context to traces and Sentry errors - #908

Merged
kody-bot merged 2 commits into
mainfrom
cursor/trace-user-context-837c
Jul 24, 2026
Merged

kody-bot merged 2 commits into
mainfrom
cursor/trace-user-context-837c

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 24, 2026 •

Copy link
Copy Markdown
Member

What

Makes traces and error reports attributable to users and app-level features, following up on the OTel tracing rollout (#905, #906).

  • Usage spans: recordUsage (packages/worker/src/usage/record-usage.ts) now emits a kody.usage.{eventType} trace span per metered event, nested under the active platform span, with kody.user_id, kody.event_type, kody.outcome, and optional kody.entity_id / kody.duration_ms / kody.bytes attributes. The metering chokepoints (execute, package export, job run, workflow run, service runtime, outbound fetch, email send/receive) are exactly the app-level units worth finding in traces, so this single funnel makes every trace searchable by user and feature without touching the chokepoints. Emission follows the same never-throws contract as metering, and guards for runtimes without tracing.
  • Sentry user on errors (id only, no PII; sendDefaultPii stays false):
    • MCP failures: McpObservabilityPayload gains userId, callerContextFields supplies it from the caller context, and reportMcpFailureToSentry sets scope.setUser({ id }). The userId also lands on the structured mcp-event log lines. Call sites in define-capability.ts, execute.ts, and search-tool-runner.ts pass it through.
    • App requests: resolveRequestAuth (packages/worker/src/app/request-auth-cache.ts) calls Sentry.setUser({ id: stableUserId }) once per request after auth resolution, so uncaught app-route errors are user-attributed.
  • Test stubs: cloudflare-workers-stub.ts gains a tracing stub; the Sentry stub gains setUser; package-service.node.test.ts's module mock now spreads the original module.
  • Docs: usage-metering.md documents the span contract; request-lifecycle.md points at both hooks.

Why

Cloudflare's automatic tracing only knows platform operations — traces had no user or feature identity, and Sentry errors (reporting now enabled in production) had none either. Per-user isolation is the core invariant of this repo, which makes per-user traceability the natural debugging axis.

Verification

  • New record-usage.node.test.ts covers span emission, attribute shape, skip-on-missing-user, and optional-attribute omission (3 tests).
  • observability.workers.test.ts extended for callerContextFields user id and payload serialization.
  • Full pre-push suite green: 386 test files passed + all 18 Playwright E2E.
  • npm run typecheck passes; real-workerd usage/observability suites pass (the cloudflare:workers namespace import with tracing access works in vitest-pool-workers).
System recap — extends usage metering and MCP observability (medium risk)

Mode: recap · Base: main @ 66d6e32d · Head: branch tip

Classification: extends — the usage-metering helper contract gains a span-emission side effect and the MCP observability payload gains a field; no new primitives.

Primitives touched

Primitive Group Impact
usage-metering platform extends — recordUsage emits kody.usage.* spans
mcp-server surfaces extends — failure reports carry scope.setUser; mcp-event logs gain userId
app-sessions auth composes — per-request Sentry.setUser after auth resolution

System map

User identity flows from auth/caller context into trace spans and Sentry error scopes because of this PR.

Legend: green = composes (wiring only) · amber = extended by this PR · red = new primitive · gray = context (unchanged).

flowchart LR
	appSessions["app-sessions<br/>Browser sessions"]:::touched
	mcpServer["mcp-server<br/>MCP endpoint"]:::extended
	usageMetering["usage-metering<br/>recordUsage()"]:::extended
	tracing["Workers tracing<br/>(platform)"]:::untouched
	sentry["Sentry<br/>(errors)"]:::untouched
	appSessions -->|"setUser({id}) after auth"| sentry
	mcpServer -->|"userId on mcp-event + failure scope"| sentry
	usageMetering -->|"kody.usage.* span with kody.user_id"| tracing
	classDef touched fill:#1a7f37,color:#fff
	classDef extended fill:#9a6700,color:#fff
	classDef added fill:#cf222e,color:#fff
	classDef untouched fill:#57606a,color:#fff
Loading

Invariants

Per-user isolation is unaffected: user ids flow only into Kody's own telemetry (first-party spans/logs/Sentry), never across users. Only the stable user id is sent to Sentry — never email or display name.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • Observability
    • Improved tracing for usage events, including user, outcome, entity, duration, and byte details.
    • Added signed-in user context to error reports and MCP activity logs.
    • Usage tracking and observability continue working safely when tracing or error reporting is unavailable.
  • Documentation
    • Clarified request tracing, usage metering, and error-reporting behavior.
  • Tests
    • Added coverage for usage tracing, user context, and Cloudflare runtime stubs.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d1b562ce-adb0-4299-a088-d3413b8fd4c9

📥 Commits

Reviewing files that changed from the base of the PR and between fd9bd8a and e905d69.

📒 Files selected for processing (13)
  • docs/contributing/architecture/request-lifecycle.md
  • docs/contributing/architecture/usage-metering.md
  • packages/worker/src/app/request-auth-cache.ts
  • packages/worker/src/mcp/capabilities/define-capability.ts
  • packages/worker/src/mcp/observability.ts
  • packages/worker/src/mcp/observability.workers.test.ts
  • packages/worker/src/mcp/tools/execute.ts
  • packages/worker/src/mcp/tools/search-tool-runner.ts
  • packages/worker/src/package-runtime/package-service.node.test.ts
  • packages/worker/src/test-support/cloudflare-workers-stub.ts
  • packages/worker/src/test-support/sentry-cloudflare-stub.ts
  • packages/worker/src/usage/record-usage.node.test.ts
  • packages/worker/src/usage/record-usage.ts

📝 Walkthrough

Walkthrough

Changes

Observability instrumentation

Layer / File(s) Summary
Authenticate and associate Sentry users
packages/worker/src/app/request-auth-cache.ts, packages/worker/src/test-support/sentry-cloudflare-stub.ts, docs/contributing/architecture/request-lifecycle.md
Request authentication sets the resolved stable user id in Sentry when initialized, with guarded failure handling and matching test stubs and documentation.
Propagate user ids through MCP observability
packages/worker/src/mcp/observability.ts, packages/worker/src/mcp/capabilities/define-capability.ts, packages/worker/src/mcp/tools/*, packages/worker/src/mcp/observability.workers.test.ts
MCP caller context and capability/tool outcomes now carry userId; MCP failure reporting associates it with the Sentry scope, with coverage for context and serialized event payloads.
Emit usage event spans
packages/worker/src/usage/record-usage.ts, packages/worker/src/usage/record-usage.node.test.ts, packages/worker/src/test-support/cloudflare-workers-stub.ts, packages/worker/src/package-runtime/package-service.node.test.ts, docs/contributing/architecture/usage-metering.md
recordUsage emits optional kody.usage.{eventType} spans with usage attributes while preserving its non-throwing behavior; tracing tests, runtime stubs, and the helper contract are updated.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant resolveRequestAuth
  participant callerContextFields
  participant MCPTool
  participant logMcpEvent
  participant Sentry
  resolveRequestAuth->>Sentry: setUser({ id: stableUserId })
  callerContextFields->>MCPTool: provide userId
  MCPTool->>logMcpEvent: include userId in outcome payload
  MCPTool->>Sentry: report failure with userId
Loading
sequenceDiagram
  participant recordUsage
  participant WorkersTracing
  participant UsageSink
  recordUsage->>WorkersTracing: enterSpan(kody.usage.{eventType})
  recordUsage->>UsageSink: persist usage event
Loading

Possibly related PRs

  • kentcdodds/kody#616: Introduced the recordUsage() metering implementation that now receives per-usage tracing spans.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main observability change: attaching user context to traces and Sentry errors.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/trace-user-context-837c

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kody-bot
kody-bot marked this pull request as ready for review July 24, 2026 14:06
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-908.kody-a99.workers.dev

Worker: kody-pr-908
D1: kody-pr-908-db
KV: kody-pr-908-oauth-kv

Mocks:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants