Skip to content

Ale/eng 8365 enable email level breakdown for custom events in posthog#2672

Closed
alepane21 wants to merge 3 commits intomainfrom
ale/eng-8365-enable-email-level-breakdown-for-custom-events-in-posthog
Closed

Ale/eng 8365 enable email level breakdown for custom events in posthog#2672
alepane21 wants to merge 3 commits intomainfrom
ale/eng-8365-enable-email-level-breakdown-for-custom-events-in-posthog

Conversation

@alepane21
Copy link
Copy Markdown
Contributor

@alepane21 alepane21 commented Mar 20, 2026

Summary by CodeRabbit

  • New Features

    • Enhanced user telemetry tracking with improved organization identification and user context capture for better analytics insights.
  • Tests

    • Added test coverage for identity synchronization in telemetry collection.

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.
  • Documentation has been updated on https://github.com/wundergraph/docs-website.
  • I have read the Contributors Guide.

Open Source AI Manifesto

This project follows the principles of the Open Source AI Manifesto. Please ensure your contribution aligns with its principles.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 20, 2026

Walkthrough

The changes refactor identity and telemetry tracking across CLI and studio packages. The CLI now extracts email and organization identifiers from JWT tokens to support richer identity resolution in PostHog. The studio's track module refactors PostHog identity syncing into a dedicated, testable function and updates its type signatures.

Changes

Cohort / File(s) Summary
CLI Telemetry
cli/src/core/telemetry.ts
Changed from string-based to object-based TelemetryIdentity model. Added JWT decoding to extract email, organizationSlug, and alias history. Introduced module-level state for persistent identity tracking and a syncIdentity function that manages PostHog alias, identify, and groupIdentify calls based on state changes. Updated capture to send identity and organization group data.
Studio Track Refactoring
studio/src/lib/track.ts
Extracted PostHog identity syncing into a new exported syncPostHogIdentity function. Changed identify to accept IdentifyUserInput object type instead of destructured parameters. Updated resetTracking to use PostHogClient() instead of previously imported posthog variable.
Studio Track Tests
studio/src/__tests__/track.test.ts
Added Vitest test suite for syncPostHogIdentity with two test cases covering scenarios with and without a plan. Tests verify correct behavior of alias, identify, and group calls under different distinct id conditions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main change: enabling email-level breakdown for custom events in PostHog. The changeset implements this by refactoring telemetry to use email as the distinct ID instead of a generic string.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
📝 Coding Plan
  • Generate coding plan for human review comments

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

Tip

You can generate walkthrough in a markdown collapsible section to save space.

Enable the reviews.collapse_walkthrough setting to generate walkthrough in a markdown collapsible section.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 20, 2026

Codecov Report

❌ Patch coverage is 23.57724% with 94 lines in your changes missing coverage. Please review.
✅ Project coverage is 9.13%. Comparing base (6936d4d) to head (a883570).
⚠️ Report is 23 commits behind head on main.

Files with missing lines Patch % Lines
cli/src/core/telemetry.ts 8.08% 91 Missing ⚠️
studio/src/lib/track.ts 87.50% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #2672       +/-   ##
==========================================
- Coverage   63.01%   9.13%   -53.89%     
==========================================
  Files         245     425      +180     
  Lines       26260   53349    +27089     
  Branches        0     894      +894     
==========================================
- Hits        16549    4872    -11677     
- Misses       8366   48191    +39825     
+ Partials     1345     286     -1059     
Files with missing lines Coverage Δ
studio/src/lib/track.ts 57.50% <87.50%> (ø)
cli/src/core/telemetry.ts 8.62% <8.08%> (ø)

... and 668 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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cli/src/core/telemetry.ts (1)

160-203: ⚠️ Potential issue | 🟠 Major

Cache telemetry identity instead of calling whoAmI on every event.

With an API key, every capture() now awaits apiClient.platform.whoAmI(...) before enqueueing PostHog. That puts extra network latency on the hot path and can slow commands that emit several events. Memoize the resolved identity (or resolve it once during initTelemetry) and keep a timeout if this lookup remains network-backed.

Also applies to: 205-211, 263-265

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

In `@cli/src/core/telemetry.ts` around lines 160 - 203, getIdentityFromApiKey
currently calls apiClient.platform.whoAmI each time (used by capture), adding
network latency; change it to cache/memoize the resolved TelemetryIdentity (or
call once from initTelemetry) and return the cached value until a configurable
TTL expires, and on cache miss asynchronously call apiClient.platform.whoAmI to
refresh; update getIdentityFromApiKey to read/write the in-memory cache and
ensure capture uses the cached identity, and apply the same caching pattern for
the other callers referenced (the blocks around the code that use
getIdentityFromApiKey at the other sites).
🧹 Nitpick comments (3)
studio/src/lib/track.ts (1)

21-33: Please convert IdentifyUserInput to an interface and add the missing : void annotations.

The new shape and helpers are otherwise clear; this just keeps the file aligned with the repo's TypeScript rules.

As per coding guidelines, "Prefer interfaces over type aliases for object shapes in TypeScript" and "Use explicit type annotations for function parameters and return types in TypeScript."

Also applies to: 54-70

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

In `@studio/src/lib/track.ts` around lines 21 - 33, Convert the type alias
IdentifyUserInput to an interface (interface IdentifyUserInput { ... }) and add
explicit void return annotations to the relevant functions (e.g., annotate
syncPostHogIdentity(...): void and any other functions in the same file
referenced in the comment range around lines 54-70) so the function parameter
and return types follow the repo rules; leave the existing parameter
destructuring and implementation unchanged, only change the type declaration and
add the : void return type annotations where missing.
studio/src/__tests__/track.test.ts (1)

6-11: Use a typed mock instead of as any.

as any removes the contract this suite is supposed to pin, so drift in get_distinct_id / alias / identify / group won't be caught at compile time. A narrow local interface or a satisfies check keeps these tests strict without much extra code.

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

Also applies to: 35-40

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

In `@studio/src/__tests__/track.test.ts` around lines 6 - 11, Replace the untyped
test mock that uses "as any" with a properly typed mock of the PostHog client:
declare a narrow local interface (or use the PostHog client type with
vi.Mocked<...> / "satisfies") that includes get_distinct_id, alias, identify,
and group, and update the posthogClient fixture (and the similar mock at lines
35-40) to implement that interface so the compiler enforces the method
signatures instead of silencing them with any.
cli/src/core/telemetry.ts (1)

47-52: Use an interface for TelemetryIdentity and annotate syncIdentity() explicitly.

The new object shape is a better fit for an interface, and syncIdentity is the only new helper in this block still relying on an inferred void.

As per coding guidelines, "Prefer interfaces over type aliases for object shapes in TypeScript" and "Use explicit type annotations for function parameters and return types in TypeScript."

Also applies to: 214-252

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

In `@cli/src/core/telemetry.ts` around lines 47 - 52, Replace the
TelemetryIdentity type alias with an interface named TelemetryIdentity and add
explicit type annotations to the syncIdentity helper: annotate its parameter(s)
with TelemetryIdentity (or partial/nullable variants if applicable) and give the
function an explicit return type (e.g., void or Promise<void> as appropriate);
apply the same conversion and explicit annotation to the other occurrence of
TelemetryIdentity and syncIdentity in the 214-252 block so both object shapes
use interface and both functions have explicit parameter and return type
declarations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/src/core/telemetry.ts`:
- Around line 152-157: Remove the problematic aliasing by deleting the
previousDistinctId assignment that uses organizationSlug in both
getIdentityFromLoginDetails and getIdentityFromApiKey: stop setting
previousDistinctId = organizationSlug (and any conditional variants) so no alias
is created from the shared org slug to the user email; only set
previousDistinctId when you have a true per-user legacy ID to map from.

---

Outside diff comments:
In `@cli/src/core/telemetry.ts`:
- Around line 160-203: getIdentityFromApiKey currently calls
apiClient.platform.whoAmI each time (used by capture), adding network latency;
change it to cache/memoize the resolved TelemetryIdentity (or call once from
initTelemetry) and return the cached value until a configurable TTL expires, and
on cache miss asynchronously call apiClient.platform.whoAmI to refresh; update
getIdentityFromApiKey to read/write the in-memory cache and ensure capture uses
the cached identity, and apply the same caching pattern for the other callers
referenced (the blocks around the code that use getIdentityFromApiKey at the
other sites).

---

Nitpick comments:
In `@cli/src/core/telemetry.ts`:
- Around line 47-52: Replace the TelemetryIdentity type alias with an interface
named TelemetryIdentity and add explicit type annotations to the syncIdentity
helper: annotate its parameter(s) with TelemetryIdentity (or partial/nullable
variants if applicable) and give the function an explicit return type (e.g.,
void or Promise<void> as appropriate); apply the same conversion and explicit
annotation to the other occurrence of TelemetryIdentity and syncIdentity in the
214-252 block so both object shapes use interface and both functions have
explicit parameter and return type declarations.

In `@studio/src/__tests__/track.test.ts`:
- Around line 6-11: Replace the untyped test mock that uses "as any" with a
properly typed mock of the PostHog client: declare a narrow local interface (or
use the PostHog client type with vi.Mocked<...> / "satisfies") that includes
get_distinct_id, alias, identify, and group, and update the posthogClient
fixture (and the similar mock at lines 35-40) to implement that interface so the
compiler enforces the method signatures instead of silencing them with any.

In `@studio/src/lib/track.ts`:
- Around line 21-33: Convert the type alias IdentifyUserInput to an interface
(interface IdentifyUserInput { ... }) and add explicit void return annotations
to the relevant functions (e.g., annotate syncPostHogIdentity(...): void and any
other functions in the same file referenced in the comment range around lines
54-70) so the function parameter and return types follow the repo rules; leave
the existing parameter destructuring and implementation unchanged, only change
the type declaration and add the : void return type annotations where missing.
🪄 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: ed20633c-ae93-4441-bdf3-b8a9f5fa6965

📥 Commits

Reviewing files that changed from the base of the PR and between 6936d4d and a883570.

📒 Files selected for processing (3)
  • cli/src/core/telemetry.ts
  • studio/src/__tests__/track.test.ts
  • studio/src/lib/track.ts

Comment thread cli/src/core/telemetry.ts
Comment on lines +152 to +157
return {
distinctId: email ?? organizationSlug ?? 'anonymous',
email,
organizationSlug,
previousDistinctId: email && organizationSlug ? organizationSlug : undefined,
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -path "*/cli/src/core/telemetry.ts" -type f

Repository: wundergraph/cosmo

Length of output: 88


🏁 Script executed:

cat -n ./cli/src/core/telemetry.ts

Repository: wundergraph/cosmo

Length of output: 11256


Remove previousDistinctId assignment using shared organizationSlug.

When previousDistinctId is set to organizationSlug (lines 156, 189), the syncIdentity function at line 219 creates an alias from the organization slug to the user's email. Since organizationSlug is shared across all organization members, this causes a conflict: the first user to log in gets aliased from the org slug, consuming all pre-login org-wide telemetry. When subsequent users from the same organization log in, they create conflicting aliases for an already-mapped distinct ID.

Remove the previousDistinctId assignment in both getIdentityFromLoginDetails() and getIdentityFromApiKey() unless you have a true per-user legacy ID to alias from.

Suggested direction
   return {
     distinctId: email ?? organizationSlug ?? 'anonymous',
     email,
     organizationSlug,
-    previousDistinctId: email && organizationSlug ? organizationSlug : undefined,
   };

Apply the same change at both locations.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return {
distinctId: email ?? organizationSlug ?? 'anonymous',
email,
organizationSlug,
previousDistinctId: email && organizationSlug ? organizationSlug : undefined,
};
return {
distinctId: email ?? organizationSlug ?? 'anonymous',
email,
organizationSlug,
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/src/core/telemetry.ts` around lines 152 - 157, Remove the problematic
aliasing by deleting the previousDistinctId assignment that uses
organizationSlug in both getIdentityFromLoginDetails and getIdentityFromApiKey:
stop setting previousDistinctId = organizationSlug (and any conditional
variants) so no alias is created from the shared org slug to the user email;
only set previousDistinctId when you have a true per-user legacy ID to map from.

@alepane21 alepane21 closed this Mar 27, 2026
@alepane21 alepane21 deleted the ale/eng-8365-enable-email-level-breakdown-for-custom-events-in-posthog branch March 27, 2026 14:54
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.

1 participant