Skip to content

feat(telemetry): make IdentifyUser idempotent and lazy via persisted LastIdentifiedEmail#196

Open
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1777324232-lazy-identify-user
Open

feat(telemetry): make IdentifyUser idempotent and lazy via persisted LastIdentifiedEmail#196
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1777324232-lazy-identify-user

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented Apr 27, 2026

Description 📣

Follow-up to #146. PostHog person records for users who were already logged in before they upgraded to a CLI version with IdentifyUser (v0.43.59+) are never enriched with the email property. Their persisted LoggedInUserEmail is used as the PostHog distinctId on every cli-command:* event, so PostHog auto-creates a person — but IdentifyUser only fires inside the user-auth branch of infisical login, which they don't re-enter on subsequent CLI invocations. The same gap exists for infisical user switch, which rewrites LoggedInUserEmail in the config without going through the login flow.

Concrete symptom seen in PostHog: a person like automation@beauty-crm.local shows up keyed by email distinctId, with cli-command:secrets events flowing in, but no email property on the person record (only PostHog auto-captured GeoIP/location).

This PR fixes that by making the Identify/Alias call idempotent and lazy:

  • Replace Telemetry.IdentifyUser(email) with Telemetry.IdentifyUserIfNeeded() (no args). It reads LoggedInUserEmail from the config and compares it against a new LastIdentifiedEmail field. Identify+Alias are only enqueued when the two differ; on success it persists LastIdentifiedEmail = LoggedInUserEmail so the next call is a no-op.
  • Call IdentifyUserIfNeeded() from CaptureEvent before every Capture, so the first telemetry event after a CLI upgrade (or a profile switch) lazily enriches the PostHog person record. The cost is one extra config read per CLI command and, in the steady state, zero PostHog enqueues.
  • Keep the call in the user-auth login path for clarity. It is now redundant-but-safe because of the persistence guard — re-logins on the same email don't double-fire.
  • Preserve LastIdentifiedEmail through WriteInitalConfig so a re-login on the same email doesn't re-Identify, while a fresh login on a different email correctly does (because LoggedInUserEmail != LastIdentifiedEmail after the write).

What this PR does not address (intentionally — separate design call worth its own PR):

  • Machine-identity logins (--method=universal-auth|kubernetes|aws-iam|gcp-iam|gcp-id-token|azure|oidc-auth|jwt-auth|ldap-auth) still fire zero PostHog events from the infisical login command itself, and subsequent commands run with a machine-identity token still resolve to anonymous_cli_<machineId> because the token is never persisted to LoggedInUserEmail. That is the dominant source of residual anonymous_cli_* persons in PostHog and is best addressed with $process_person_profile: false + groups, not by extending IdentifyUser.
  • Pre-v0.43.59 CLIs in the wild are unfixable from code — they don't contain the IdentifyUser path at all and will only stop generating anonymous events as users upgrade organically.

Type ✨

  • Bug fix
  • New feature
  • Improvement
  • Breaking change
  • Documentation

Tests 🛠️

Manual reasoning-through of the state transitions (no automated tests for telemetry exist today; the package is mock-free and tightly coupled to PostHog + filesystem).

Scenario LoggedInUserEmail LastIdentifiedEmail Behavior on CaptureEvent
Anonymous CLI (never logged in) "" "" No Identify, distinctId = anonymous_cli_<machineId>. Unchanged.
Fresh login on v0.43.59+ a@x.com (new) "" (new) Identify+Alias enqueued, LastIdentifiedEmail = a@x.com persisted. Unchanged from #146.
Already logged in pre-v0.43.59, just upgraded a@x.com "" Identify+Alias enqueued (the bug fix), LastIdentifiedEmail = a@x.com persisted.
Subsequent commands after Identify a@x.com a@x.com No Identify, just Capture.
infisical user switch to b@x.com b@x.com a@x.com Identify+Alias enqueued for b@x.com, LastIdentifiedEmail = b@x.com persisted.
Re-login as same email after logout a@x.com a@x.com No Identify, just Capture.
Telemetry disabled any any Early return — no config reads, no enqueues, no writes.

Build verified locally:

go build ./...
go vet ./packages/telemetry/... ./packages/cmd/login.go ./packages/util/... ./packages/models/...
# (Pre-existing run.go vet warnings are unrelated and present on main)

Link to Devin session: https://app.devin.ai/sessions/6363c6181d1641f8a564bc8161e4270f
Requested by: @0xArshdeep


Open in Devin Review

…LastIdentifiedEmail

PostHog person records for users who logged in on a CLI version older
than v0.43.59 (which introduced IdentifyUser) were never enriched with
the `email` property, because IdentifyUser only fired inside the user
auth branch of `infisical login`. Once those users upgraded the CLI,
their persisted `LoggedInUserEmail` was used as the PostHog distinctId
on every event, but no Identify/Alias was ever sent for them. The same
gap existed for `infisical user switch`, which mutates the active email
in the config without going through the login flow.

Replace IdentifyUser(email) with IdentifyUserIfNeeded() (no args). It
reads LoggedInUserEmail from the config, compares against a new
LastIdentifiedEmail field, and only enqueues Identify+Alias when the
two differ. After enqueueing, it persists LastIdentifiedEmail so the
call is a no-op on subsequent invocations.

Call IdentifyUserIfNeeded() from CaptureEvent before each Capture so
that the very first telemetry event after a CLI upgrade (or a profile
switch) lazily enriches the PostHog person record. Also call it from
the user-auth login path for clarity, which is now redundant-but-safe
because of the persistence guard.

Preserve LastIdentifiedEmail in WriteInitalConfig so a fresh login on
the same email does not re-fire Identify, while a fresh login on a
different email does.
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0de21605ed

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/telemetry/telemetry.go
…ueue

Addresses Codex review on #196. If posthogClient.Enqueue returns an
error (closed client, malformed message, etc.) and we still write
LastIdentifiedEmail = email, the guard at the top of
IdentifyUserIfNeeded would skip Identify/Alias forever for that
email — locking the user out of person enrichment.

Capture the error from each Enqueue call. On Identify failure, bail
out early without persisting. On Alias failure, also bail out (the
anonymous-to-email link is part of the Identify story; we want the
next invocation to retry). Only persist LastIdentifiedEmail when
both enqueues succeed, so transient failures self-heal on the next
CLI invocation.
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.

1 participant