Skip to content

feat(controlplane): add service-level tracing spans to Connect-RPC handlers#2771

Merged
thisisnithin merged 5 commits intomainfrom
nithin/eng-9385-controlplane-add-service-level-tracing-spans-to-connect-rpc
Apr 17, 2026
Merged

feat(controlplane): add service-level tracing spans to Connect-RPC handlers#2771
thisisnithin merged 5 commits intomainfrom
nithin/eng-9385-controlplane-add-service-level-tracing-spans-to-connect-rpc

Conversation

@thisisnithin
Copy link
Copy Markdown
Member

@thisisnithin thisisnithin commented Apr 16, 2026

Summary

  • Add @traced class decorator that wraps all repository and service methods with Sentry.startSpan() for automatic span creation
  • Add Connect interceptor that bridges Sentry's span context from Fastify's preHandler into Connect's handler pipeline, fixing async context loss between Fastify hooks and Connect route handlers
  • Attach user/org context (userId, displayName, orgId, orgSlug) to root spans for filtering in Sentry
  • Add Sentry Spotlight support for local dev tracing

Test plan

  • Run pnpm sentry:spotlight and pnpm dev with SENTRY_ENABLED=true and a valid DSN
  • Verify Connect-RPC traces show nested spans for repository/service methods under request-handler.fastify
  • Verify regular Fastify routes (e.g. /v1/auth/session) still show spans correctly
  • Verify user/org attributes appear on root spans in Sentry
  • Verify no performance regression when Sentry is disabled

Resolves ENG-9385

Summary by CodeRabbit

  • New Features

    • Platform-wide tracing/instrumentation added for improved observability and debugging.
    • Sentry "spotlight" enabled for non-production/local debugging.
    • Structured error logging improved for webhook failures.
  • Chores

    • TypeScript decorator support enabled; lint rule added to enforce traced patterns.
    • Dev tooling updated with Spotlight and local ESLint plugin; npm script added for Spotlight.
  • Tests

    • Added tests validating tracing instrumentation and span helpers.

…ndlers

Add @Traced decorator and Connect interceptor to propagate Sentry spans
through Connect-RPC handlers for full visibility into repository and
service method timings.

Resolves ENG-9385
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5c2f6569-6df4-43d1-8217-2751ac40f13f

📥 Commits

Reviewing files that changed from the base of the PR and between de4e304 and 26d8747.

📒 Files selected for processing (1)
  • controlplane/eslint-local-rules.cjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • controlplane/eslint-local-rules.cjs

Walkthrough

Adds Sentry tracing primitives and integration: a new traced decorator and withSpan, Sentry span propagation into request handling, widespread application of @traced to many classes (with a few method-declaration conversions), Spotlight dev script, new ESLint local rule banning arrow properties in traced classes, and tests for tracing behavior.

Changes

Cohort / File(s) Summary
Package & TS config
controlplane/package.json, controlplane/tsconfig.json, controlplane/src/core/sentry.config.ts
Added sentry:spotlight script and devDeps; enabled experimentalDecorators; toggled Spotlight option in Sentry init for non-production.
Tracing core & util
controlplane/src/core/tracing.ts, controlplane/src/core/util.ts
Added traced decorator and withSpan; exported sentrySpanId; enrichLogger now sets Sentry user/context attributes on active root spans.
Request/span propagation
controlplane/src/core/build-server.ts
Captures active Sentry span in Fastify preHandler, injects into Connect contextValues, and adds interceptor to run handlers under the captured parent span.
Class instrumentation (bulk)
controlplane/src/core/repositories/..., controlplane/src/core/repositories/analytics/..., controlplane/src/core/services/..., controlplane/src/core/auth-utils.ts, controlplane/src/core/blobstorage/..., controlplane/src/core/clickhouse/client/..., controlplane/src/core/composition/composer.ts, controlplane/src/core/webhooks/...
Imported/apply traced across many exported classes (repositories, services, authenticators, blob storage, ClickHouse client, composer, webhooks). Mostly decorator additions; a few files convert arrow-property members to standard methods (binding/initialization change). AuthUtils wrapped via traced(AuthUtils).
Notable method-signature/form changes
controlplane/src/core/repositories/FederatedGraphRepository.ts, .../SchemaCheckRepository.ts, .../analytics/AnalyticsRequestViewRepository.ts, .../services/BillingService.ts, .../services/SchemaGraphPruner.ts, .../services/SchemaLinter.ts
Converted several class field arrow functions to prototype/async methods; these change binding/initialization but keep parameter and return shapes.
Webhooks logging tweak
controlplane/src/core/webhooks/OrganizationWebhookService.ts
Replaced child-then-error logging with structured logger.error(e, 'Could not send webhook event').
ESLint local rule & config
controlplane/.eslintrc, controlplane/eslint-local-rules.cjs
Added local-rules plugin and enabled local-rules/no-arrow-in-traced; implemented no-arrow-in-traced rule to report arrow-function property members inside traced classes.
Tests
controlplane/test/tracing.test.ts
Added Vitest suite for traced and withSpan: verifies span naming, sync/async wrapping, this preservation, skipping constructors, and decorator-call usage.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding service-level tracing spans to Connect-RPC handlers. It directly reflects the primary objective of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 16, 2026

Codecov Report

❌ Patch coverage is 65.56017% with 83 lines in your changes missing coverage. Please review.
✅ Project coverage is 47.36%. Comparing base (74f44a1) to head (26d8747).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
controlplane/eslint-local-rules.cjs 0.00% 70 Missing and 1 partial ⚠️
controlplane/src/core/build-server.ts 78.57% 6 Missing ⚠️
...tories/analytics/AnalyticsRequestViewRepository.ts 60.00% 2 Missing ⚠️
controlplane/src/core/services/BillingService.ts 60.00% 2 Missing ⚠️
controlplane/src/core/sentry.config.ts 0.00% 1 Missing ⚠️
controlplane/src/core/tracing.ts 96.29% 1 Missing ⚠️

❌ Your patch check has failed because the patch coverage (65.56%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2771      +/-   ##
==========================================
+ Coverage   40.72%   47.36%   +6.64%     
==========================================
  Files         985     1062      +77     
  Lines      123243   143591   +20348     
  Branches     5639     9759    +4120     
==========================================
+ Hits        50187    68008   +17821     
- Misses      71381    73822    +2441     
- Partials     1675     1761      +86     
Files with missing lines Coverage Δ
controlplane/src/core/auth-utils.ts 36.03% <100.00%> (+0.12%) ⬆️
controlplane/src/core/blobstorage/dual.ts 100.00% <100.00%> (ø)
controlplane/src/core/blobstorage/s3.ts 14.81% <100.00%> (+0.63%) ⬆️
...ane/src/core/clickhouse/client/ClickHouseClient.ts 10.76% <100.00%> (+0.34%) ⬆️
controlplane/src/core/composition/composer.ts 66.93% <100.00%> (+0.06%) ⬆️
...rolplane/src/core/repositories/ApiKeyRepository.ts 83.49% <100.00%> (+0.07%) ⬆️
...lplane/src/core/repositories/AuditLogRepository.ts 78.40% <100.00%> (+0.24%) ⬆️
...olplane/src/core/repositories/BillingRepository.ts 82.97% <100.00%> (+0.18%) ⬆️
...ane/src/core/repositories/CacheWarmerRepository.ts 87.12% <100.00%> (+0.02%) ⬆️
...lplane/src/core/repositories/ContractRepository.ts 95.00% <100.00%> (+0.06%) ⬆️
... and 56 more

... and 89 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 16, 2026

Router-nonroot image scan passed

✅ No security vulnerabilities found in image:

ghcr.io/wundergraph/cosmo/router:sha-8b62531b93a90f74456400451ab0779ecdbd2451-nonroot

Copy link
Copy Markdown
Contributor

@wilsonrivera wilsonrivera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (1)
controlplane/src/core/services/RBACEvaluator.ts (1)

3-26: Consider not tracing RBACEvaluator to avoid span explosion on hot permission checks.

This class has many tiny synchronous methods; decorating the whole class can produce noisy traces and unnecessary overhead.

♻️ Suggested adjustment
 import { OrganizationRole } from '../../db/models.js';
 import { OrganizationGroupDTO } from '../../types/index.js';
-import { traced } from '../tracing.js';

@@
-@traced
 export class RBACEvaluator {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controlplane/src/core/services/RBACEvaluator.ts` around lines 3 - 26, The
RBACEvaluator class is fully decorated with `@traced` which causes span explosion
for many tiny synchronous permission-check methods; remove the class-level
`@traced` decorator from the RBACEvaluator declaration and instead add tracing
only to the handful of genuinely heavy or async methods (if any) by applying
traced to specific methods (e.g., longRunningCheck, evaluatePolicy, or any async
entrypoints) or wrapping their bodies with traced() calls so hot-path sync
helpers remain uninstrumented.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@controlplane/src/core/repositories/FederatedGraphRepository.ts`:
- Line 77: composeAndDeployGraphs is currently defined as a class-field arrow
function so the traced decorator (imported as traced) cannot wrap it; change
composeAndDeployGraphs from an instance arrow property to a normal prototype
method (e.g., remove the "composeAndDeployGraphs = async (...) => { ... }"
class-field form and declare "async composeAndDeployGraphs(...) { ... }"),
ensure any uses relying on lexical this remain valid (bind callers if needed)
and keep the traced decorator application logic unchanged so traced will now
instrument the method on the prototype.

In `@controlplane/src/core/services/ApiGenerator.ts`:
- Around line 4-7: The traced decorator is only wrapping prototype methods so
the static ApiKeyGenerator.generate() is never instrumented; update the
decorator to also iterate Object.getOwnPropertyNames(target) (the constructor)
in addition to Object.getOwnPropertyNames(target.prototype), skipping
"prototype" and "constructor" and only wrapping function-valued properties,
preserving property descriptors and not re-wrapping already-wrapped functions;
this will ensure static methods like ApiKeyGenerator.generate are traced without
changing the class API.

In `@controlplane/src/core/services/BillingService.ts`:
- Around line 14-15: BillingService contains arrow-function class fields
(notably upsertStripeCustomerId and cancelSubscription) that are instance
properties and therefore not covered by the `@traced` decorator; convert these
arrow-field definitions into standard prototype methods so they are
instrumented. Specifically, change declarations like "upsertStripeCustomerId =
async (...) => { ... }" to "async upsertStripeCustomerId(...) { ... }" (and
similarly for cancelSubscription), keep the same parameter list and body, and if
any callers rely on function identity as a bound callback, bind the methods in
the constructor (e.g., this.upsertStripeCustomerId =
this.upsertStripeCustomerId.bind(this)) or update call sites accordingly. Ensure
no other arrow-function class fields remain that should be traced so `@traced` can
instrument the prototype methods.

In `@controlplane/src/core/services/SchemaGraphPruner.ts`:
- Around line 20-22: The `@traced` decorator is ineffective because it only
instruments prototype methods but SchemaGraphPruner defines methods as
class-field arrow functions (e.g., getAllFields = (...) => { ... }), so either
remove the `@traced` decorator or convert those arrow functions to prototype
methods; locate the SchemaGraphPruner class and either delete the `@traced`
import/annotation or refactor instance properties like getAllFields (and any
other arrow methods) into standard method declarations (e.g., getAllFields(...)
{ ... }) so the tracer can wrap them.

In `@controlplane/src/core/services/SchemaLinter.ts`:
- Line 13: The methods getRuleModule, createRulesConfig, and schemaLintCheck are
defined as class field arrow functions so the `@traced` decorator (which wraps
prototype methods by iterating Object.getOwnPropertyNames(proto)) cannot wrap
them; change each from an instance property arrow (e.g., getRuleModule = () => {
... }) to a prototype method (e.g., getRuleModule(...) { ... }) so they live on
the prototype and will be instrumented by traced; if any of these relied on
lexical this-binding, add explicit binding in the constructor or refactor
callers to call the prototype methods directly, and keep the traced import/usage
intact.

In `@controlplane/src/core/tracing.ts`:
- Around line 34-35: withSpan currently declares Promise<T> return but calls
Sentry.startSpan which may return the callback's raw value; this can return a
non-Promise at runtime. Change withSpan to be async (export async function
withSpan<T>(...)) so it always returns a Promise, remove the unsafe cast to
Promise<T>, and return the result of await Sentry.startSpan({ name }, () =>
fn()) (or simply await the callback inside the async function) so the signature
and runtime behavior match; update any usages if necessary.

In `@controlplane/src/core/util.ts`:
- Around line 100-113: The current code builds a single sentryContext with
namespaced keys and passes it to Sentry.setUser, which prevents Sentry from
recognizing canonical user fields; instead create two objects: a flat
userContext using authContext.userId -> id, authContext.userDisplayName ->
username (or displayName), and any email/ip fields, and pass that to
Sentry.setUser(userContext); keep the namespaced sentryAttributes (e.g.,
'user.id', 'user.displayName', 'organization.id', 'organization.slug') and pass
those to Sentry.getRootSpan(activeSpan).setAttributes(sentryAttributes); update
the code around sentryContext, authContext, Sentry.setUser, Sentry.getActiveSpan
and Sentry.getRootSpan accordingly.

---

Nitpick comments:
In `@controlplane/src/core/services/RBACEvaluator.ts`:
- Around line 3-26: The RBACEvaluator class is fully decorated with `@traced`
which causes span explosion for many tiny synchronous permission-check methods;
remove the class-level `@traced` decorator from the RBACEvaluator declaration and
instead add tracing only to the handful of genuinely heavy or async methods (if
any) by applying traced to specific methods (e.g., longRunningCheck,
evaluatePolicy, or any async entrypoints) or wrapping their bodies with traced()
calls so hot-path sync helpers remain uninstrumented.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 50eb046c-fa82-4c99-9c7d-0b3ac59cd1b9

📥 Commits

Reviewing files that changed from the base of the PR and between 256913a and a321b8e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (67)
  • controlplane/package.json
  • controlplane/src/core/auth-utils.ts
  • controlplane/src/core/blobstorage/dual.ts
  • controlplane/src/core/blobstorage/s3.ts
  • controlplane/src/core/build-server.ts
  • controlplane/src/core/clickhouse/client/ClickHouseClient.ts
  • controlplane/src/core/composition/composer.ts
  • controlplane/src/core/repositories/ApiKeyRepository.ts
  • controlplane/src/core/repositories/AuditLogRepository.ts
  • controlplane/src/core/repositories/BillingRepository.ts
  • controlplane/src/core/repositories/CacheWarmerRepository.ts
  • controlplane/src/core/repositories/ContractRepository.ts
  • controlplane/src/core/repositories/FeatureFlagRepository.ts
  • controlplane/src/core/repositories/FederatedGraphRepository.ts
  • controlplane/src/core/repositories/GitHubRepository.ts
  • controlplane/src/core/repositories/GraphCompositionRepository.ts
  • controlplane/src/core/repositories/NamespaceRepository.ts
  • controlplane/src/core/repositories/OidcRepository.ts
  • controlplane/src/core/repositories/OperationsRepository.ts
  • controlplane/src/core/repositories/OrganizationGroupRepository.ts
  • controlplane/src/core/repositories/OrganizationInvitationRepository.ts
  • controlplane/src/core/repositories/OrganizationRepository.ts
  • controlplane/src/core/repositories/PlaygroundScriptsRepository.ts
  • controlplane/src/core/repositories/PluginRepository.ts
  • controlplane/src/core/repositories/ProposalRepository.ts
  • controlplane/src/core/repositories/SchemaCheckRepository.ts
  • controlplane/src/core/repositories/SchemaGraphPruningRepository.ts
  • controlplane/src/core/repositories/SchemaLintRepository.ts
  • controlplane/src/core/repositories/SubgraphCheckExtensionsRepository.ts
  • controlplane/src/core/repositories/SubgraphRepository.ts
  • controlplane/src/core/repositories/TargetRepository.ts
  • controlplane/src/core/repositories/UserRepository.ts
  • controlplane/src/core/repositories/analytics/AnalyticsDashboardViewRepository.ts
  • controlplane/src/core/repositories/analytics/AnalyticsRequestViewRepository.ts
  • controlplane/src/core/repositories/analytics/MetricsRepository.ts
  • controlplane/src/core/repositories/analytics/MonthlyRequestViewRepository.ts
  • controlplane/src/core/repositories/analytics/RouterMetricsRepository.ts
  • controlplane/src/core/repositories/analytics/SubgraphMetricsRepository.ts
  • controlplane/src/core/repositories/analytics/TraceRepository.ts
  • controlplane/src/core/repositories/analytics/UsageRepository.ts
  • controlplane/src/core/sentry.config.ts
  • controlplane/src/core/services/AccessTokenAuthenticator.ts
  • controlplane/src/core/services/AdmissionWebhookController.ts
  • controlplane/src/core/services/ApiGenerator.ts
  • controlplane/src/core/services/ApiKeyAuthenticator.ts
  • controlplane/src/core/services/ApolloMigrator.ts
  • controlplane/src/core/services/Authentication.ts
  • controlplane/src/core/services/Authorization.ts
  • controlplane/src/core/services/BillingService.ts
  • controlplane/src/core/services/GraphApiTokenAuthenticator.ts
  • controlplane/src/core/services/Keycloak.ts
  • controlplane/src/core/services/Mailer.ts
  • controlplane/src/core/services/OidcProvider.ts
  • controlplane/src/core/services/RBACEvaluator.ts
  • controlplane/src/core/services/SchemaGraphPruner.ts
  • controlplane/src/core/services/SchemaLinter.ts
  • controlplane/src/core/services/SchemaUsageTrafficInspector.ts
  • controlplane/src/core/services/Slack.ts
  • controlplane/src/core/services/UserInviteService.ts
  • controlplane/src/core/services/WebSessionAuthenticator.ts
  • controlplane/src/core/services/WorkspaceService.ts
  • controlplane/src/core/tracing.ts
  • controlplane/src/core/util.ts
  • controlplane/src/core/webhooks/OrganizationWebhookService.ts
  • controlplane/src/core/webhooks/PlatformWebhookService.ts
  • controlplane/src/core/webhooks/RedeliverWebhookService.ts
  • controlplane/tsconfig.json

Comment thread controlplane/src/core/repositories/FederatedGraphRepository.ts
Comment thread controlplane/src/core/services/ApiGenerator.ts
Comment thread controlplane/src/core/services/BillingService.ts
Comment thread controlplane/src/core/services/SchemaGraphPruner.ts
Comment thread controlplane/src/core/services/SchemaLinter.ts
Comment thread controlplane/src/core/tracing.ts
Comment thread controlplane/src/core/util.ts Outdated
- Fix @Traced decorator to also wrap arrow-function class fields
- Fix Sentry.setUser to use canonical fields (id, username)
- Keep span attributes with dotted names for trace filtering
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
controlplane/src/core/util.ts (2)

78-78: Rename the exported symbol constant to UPPER_SNAKE_CASE.

The new symbol follows the existing local pattern, but it still violates the repo rule for constants. Prefer SENTRY_SPAN_ID here to avoid baking in more mixed naming.

As per coding guidelines, **/*.{js,jsx,ts,tsx}: Use UPPER_SNAKE_CASE for constants.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controlplane/src/core/util.ts` at line 78, Rename the exported constant
symbol from sentrySpanId to SENTRY_SPAN_ID: change the export declaration
(export const sentrySpanId = Symbol('sentrySpan')) to export const
SENTRY_SPAN_ID = Symbol('sentrySpan') and update every usage/import that
references sentrySpanId to use SENTRY_SPAN_ID instead (search for sentrySpanId
in references, tests, and consumers). Ensure TypeScript types and any
destructuring or re-exports adapt to the new identifier so builds and imports
continue to work.

84-88: Add an explicit return type to enrichLogger.

This helper is now doing more than simple logger decoration. Locking the return type to FastifyBaseLogger keeps the utility contract stable if this body changes again.

Suggested change
 export const enrichLogger = (
   ctx: HandlerContext,
   logger: FastifyBaseLogger,
   authContext: Partial<AuthContext & GraphKeyAuthContext>,
-) => {
+): FastifyBaseLogger => {

As per coding guidelines, **/*.{ts,tsx}: Use explicit type annotations for function parameters and return types in TypeScript.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controlplane/src/core/util.ts` around lines 84 - 88, The enrichLogger
function lacks an explicit return type; update its signature to declare the
return type as FastifyBaseLogger to satisfy the typing guideline and lock the
utility contract (i.e., change the function declaration of enrichLogger(ctx:
HandlerContext, logger: FastifyBaseLogger, authContext: Partial<AuthContext &
GraphKeyAuthContext>): FastifyBaseLogger) so consumers and future refactors
cannot accidentally change the exposed type; ensure the signature uses the
existing symbol names (enrichLogger, HandlerContext, FastifyBaseLogger,
AuthContext, GraphKeyAuthContext) and that any related exports still compile.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@controlplane/src/core/util.ts`:
- Around line 100-117: Wrap the Sentry enrichment block in a try-catch so
failures don't bubble to the request path; inside the try, build a user object
by picking/filtering defined fields from authContext.userId and
authContext.userDisplayName and only call Sentry.setUser(user) if that object
has keys, otherwise call Sentry.setUser(null) to clear user context; similarly
build spanAttributes by filtering undefined values (as currently done) and only
call
Sentry.getActiveSpan()/Sentry.getRootSpan(activeSpan).setAttributes(spanAttributes)
if an active span exists; in the catch, log the error as a best-effort telemetry
enrichment and do not rethrow.

---

Nitpick comments:
In `@controlplane/src/core/util.ts`:
- Line 78: Rename the exported constant symbol from sentrySpanId to
SENTRY_SPAN_ID: change the export declaration (export const sentrySpanId =
Symbol('sentrySpan')) to export const SENTRY_SPAN_ID = Symbol('sentrySpan') and
update every usage/import that references sentrySpanId to use SENTRY_SPAN_ID
instead (search for sentrySpanId in references, tests, and consumers). Ensure
TypeScript types and any destructuring or re-exports adapt to the new identifier
so builds and imports continue to work.
- Around line 84-88: The enrichLogger function lacks an explicit return type;
update its signature to declare the return type as FastifyBaseLogger to satisfy
the typing guideline and lock the utility contract (i.e., change the function
declaration of enrichLogger(ctx: HandlerContext, logger: FastifyBaseLogger,
authContext: Partial<AuthContext & GraphKeyAuthContext>): FastifyBaseLogger) so
consumers and future refactors cannot accidentally change the exposed type;
ensure the signature uses the existing symbol names (enrichLogger,
HandlerContext, FastifyBaseLogger, AuthContext, GraphKeyAuthContext) and that
any related exports still compile.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 73af4442-8f40-452b-a090-31118770caed

📥 Commits

Reviewing files that changed from the base of the PR and between a321b8e and fc7701f.

📒 Files selected for processing (2)
  • controlplane/src/core/tracing.ts
  • controlplane/src/core/util.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • controlplane/src/core/tracing.ts

Comment thread controlplane/src/core/util.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
controlplane/test/tracing.test.ts (1)

136-147: Strengthen the traced() function-call test by using the returned class.

The current test passes even if only prototype mutation works. Assign and instantiate the returned class so this case validates function-call behavior more directly (especially useful for constructor-time wrapping semantics).

Suggested diff
-    traced(ManualService);
-
-    const svc = new ManualService();
+    const TracedManualService = traced(ManualService);
+    const svc = new TracedManualService();
     expect(svc.doWork()).toBe('done');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controlplane/test/tracing.test.ts` around lines 136 - 147, The test currently
calls traced(ManualService) but doesn't use its return value, which misses
validating the function-call form; update the test to capture the returned class
from traced (e.g., const Wrapped = traced(ManualService)) and instantiate that
returned class (new Wrapped()) instead of the original ManualService, then
assert the instance.doWork() result and that startSpanMock was called with {
name: 'ManualService.doWork' } and a function; this ensures traced()'s
returned-class wrapping (constructor-time semantics) is exercised rather than
relying on prototype mutation alone.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@controlplane/test/tracing.test.ts`:
- Around line 21-23: Several class methods in controlplane/test/tracing.test.ts
(for example the greet(name: string) method) are missing explicit return type
annotations; update each class method declaration to include an explicit return
type (e.g., greet(name: string): string) so every method in the class has a
declared return type for TypeScript consistency—locate methods such as greet and
the other methods referenced in the review and add the appropriate return types
(string, void, Promise<...>, etc.) matching their returned values or promises.
- Line 7: The mock for startSpan should stop using any and match Sentry's API:
change the mock signature in the startSpan vi.fn to use unknown types and a
no-argument callback—e.g., replace (opts: { name: string }, cb: (span: any) =>
any) => cb({ name: opts.name }) with a signature using unknown like (opts: {
name: string }, cb: () => unknown) => cb() so the callback takes no parameters
and the types avoid any.

---

Nitpick comments:
In `@controlplane/test/tracing.test.ts`:
- Around line 136-147: The test currently calls traced(ManualService) but
doesn't use its return value, which misses validating the function-call form;
update the test to capture the returned class from traced (e.g., const Wrapped =
traced(ManualService)) and instantiate that returned class (new Wrapped())
instead of the original ManualService, then assert the instance.doWork() result
and that startSpanMock was called with { name: 'ManualService.doWork' } and a
function; this ensures traced()'s returned-class wrapping (constructor-time
semantics) is exercised rather than relying on prototype mutation alone.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7ad46991-75bd-4625-ade2-0df7a6c6101a

📥 Commits

Reviewing files that changed from the base of the PR and between fc7701f and 177bbe8.

📒 Files selected for processing (1)
  • controlplane/test/tracing.test.ts

Comment thread controlplane/test/tracing.test.ts
Comment thread controlplane/test/tracing.test.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
controlplane/test/tracing.test.ts (2)

7-7: ⚠️ Potential issue | 🟡 Minor

Replace any in the Sentry mock signature.

Use unknown-based types to keep the mock type-safe.

Suggested diff
-    startSpan: vi.fn((opts: { name: string }, cb: (span: any) => any) => cb({ name: opts.name })),
+    startSpan: vi.fn(
+      (opts: { name: string }, cb: (span: unknown) => unknown): unknown => cb({ name: opts.name }),
+    ),

As per coding guidelines, "Avoid any type in TypeScript; use specific types or generics."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controlplane/test/tracing.test.ts` at line 7, The test Sentry mock uses `any`
in the startSpan signature; update the mock in the startSpan vi.fn to use
unknown-based types for safety: change the callback type from `(span: any) =>
any` to `(span: unknown) => unknown` (or a more specific generic/opaque type if
available) and cast the object passed to the callback (`{ name: opts.name }`) to
unknown when invoking cb; this keeps startSpan (the vi.fn mock) type-safe while
preserving behavior in tracing.test.ts.

21-23: ⚠️ Potential issue | 🟡 Minor

Add explicit return types to test class methods.

These methods currently rely on inference; add explicit returns to comply with TS guidelines.

Suggested diff (examples)
-      greet(name: string) {
+      greet(name: string): string {
         return `hello ${name}`;
       }

-      findById(id: string) {
+      findById(id: string): Promise<{ id: string; name: string }> {
         return Promise.resolve({ id, name: 'test' });
       }

-      increment() {
+      increment(): number {
         this.count += 1;
         return this.count;
       }

-      getValue() {
+      getValue(): string {
         return this.name;
       }

-      doWork() {
+      doWork(): string {
         return 'done';
       }

As per coding guidelines, "Use explicit type annotations for function parameters and return types in TypeScript."

Also applies to: 36-38, 53-56, 70-72, 92-94

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controlplane/test/tracing.test.ts` around lines 21 - 23, Add explicit return
type annotations for the test class methods (e.g., change greet(name: string) {
... } to include a return type like greet(name: string): string { ... }) and do
the same for the other methods flagged in this file (the methods at the other
ranges referenced in the review). Locate the methods by their names (e.g., greet
and the other test helpers/assertions in the same test class) and annotate each
function with an explicit return type consistent with the returned value
(string, void, boolean, Promise<...>, etc.) to satisfy the TypeScript guideline.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@controlplane/eslint-local-rules.cjs`:
- Around line 8-13: The isTraced helper currently assumes node.parent.body
exists and therefore misses classes wrapped in ExportDefaultDeclaration (e.g.,
"export default class ...; traced(Class)"). Update isTraced to detect when the
node's parent is an ExportDefaultDeclaration and, in that case, examine
parent.parent.body (or the nearest ancestor with a body array) for siblings;
otherwise continue using parent.body. Specifically modify the sibling lookup in
isTraced (the parent/body/siblings/indexOf logic) to fall back to the export's
parent body so exported classes are included in the traced-class sibling scan.

In `@controlplane/src/core/tracing.ts`:
- Around line 3-5: The decorator helper wrapMethod currently uses weak types
(Function, any) — change its signature to be generic and unknown-safe: make
wrapMethod a generic function (e.g., <TArgs extends unknown[], TResult>) and
type the original parameter as (...args: TArgs) => TResult and the returned
wrapper as (this: any, ...args: TArgs) => TResult (also replace any[]/any in the
rest of the function with TArgs and unknown/ TResult accordingly); update the
other similar helper at the noted location (line ~17) to follow the same pattern
so that arguments and return values are strongly typed without using any or
Function.

---

Duplicate comments:
In `@controlplane/test/tracing.test.ts`:
- Line 7: The test Sentry mock uses `any` in the startSpan signature; update the
mock in the startSpan vi.fn to use unknown-based types for safety: change the
callback type from `(span: any) => any` to `(span: unknown) => unknown` (or a
more specific generic/opaque type if available) and cast the object passed to
the callback (`{ name: opts.name }`) to unknown when invoking cb; this keeps
startSpan (the vi.fn mock) type-safe while preserving behavior in
tracing.test.ts.
- Around line 21-23: Add explicit return type annotations for the test class
methods (e.g., change greet(name: string) { ... } to include a return type like
greet(name: string): string { ... }) and do the same for the other methods
flagged in this file (the methods at the other ranges referenced in the review).
Locate the methods by their names (e.g., greet and the other test
helpers/assertions in the same test class) and annotate each function with an
explicit return type consistent with the returned value (string, void, boolean,
Promise<...>, etc.) to satisfy the TypeScript guideline.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dc589b3c-2752-45b5-888c-ab711a5bdf51

📥 Commits

Reviewing files that changed from the base of the PR and between 177bbe8 and de4e304.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • controlplane/.eslintrc
  • controlplane/eslint-local-rules.cjs
  • controlplane/package.json
  • controlplane/src/core/repositories/FederatedGraphRepository.ts
  • controlplane/src/core/repositories/SchemaCheckRepository.ts
  • controlplane/src/core/repositories/analytics/AnalyticsRequestViewRepository.ts
  • controlplane/src/core/services/BillingService.ts
  • controlplane/src/core/services/SchemaGraphPruner.ts
  • controlplane/src/core/services/SchemaLinter.ts
  • controlplane/src/core/tracing.ts
  • controlplane/src/core/webhooks/OrganizationWebhookService.ts
  • controlplane/test/tracing.test.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • controlplane/package.json
  • controlplane/src/core/repositories/SchemaCheckRepository.ts
  • controlplane/src/core/webhooks/OrganizationWebhookService.ts
  • controlplane/src/core/services/SchemaLinter.ts
  • controlplane/src/core/services/BillingService.ts
  • controlplane/src/core/repositories/analytics/AnalyticsRequestViewRepository.ts
  • controlplane/src/core/repositories/FederatedGraphRepository.ts

Comment thread controlplane/eslint-local-rules.cjs Outdated
Comment thread controlplane/src/core/tracing.ts
@thisisnithin thisisnithin merged commit 9cf421a into main Apr 17, 2026
56 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants