Skip to content

feat(telemetry): auth flow events#239

Merged
LorrisSaintGenez merged 7 commits into
feat/events-flowfrom
feat/auth-flow-events
Jun 11, 2026
Merged

feat(telemetry): auth flow events#239
LorrisSaintGenez merged 7 commits into
feat/events-flowfrom
feat/auth-flow-events

Conversation

@LorrisSaintGenez

@LorrisSaintGenez LorrisSaintGenez commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

What

Step 2 of GROUT-349 — instruments the browser-based OAuth flow with funnel events. Stacked on #238

  • RunOAuthFlow emits CLI Auth Started at entry (flow: login|signup, no_browser), then exactly one terminal event: CLI Auth Completed (duration_ms), CLI Auth Aborted (step) on user cancellation, or CLI Auth Failed (step, duration_ms, error_class).
  • Steps recorded along the flow to locate drop-offs: browser_wait, code_exchange (inside auth.RunOAuth, which now takes an optional nil-safe FlowTracker), then apps_fetch, app_create/app_select, profile_configure.
  • Automatic re-authentications (EnsureAuthenticated, ReauthenticateIfExpired) pass a nil tracker: they belong to the calling flow, not to an auth login funnel.
  • New Event struct + typed constructors (AuthStarted, …) + nil-safe TrackEvent(ctx, Event) helper: call sites are one line and properties are compile-time consistent.
  • identifyAuthenticatedUser uses the context's telemetry client; telemetry.IdentifyOnce is removed — it only existed because the client used to be closed before the command ran (fixed in feat(telemetry): flow events foundations #238).
  • telemetrytest.RecordingClient: shared recording fake for flow event tests.

Included GROUT-351 — logout telemetry flow. Stacked on #239 (feat/auth-flow-events): it only needs the event catalog and TrackEvent helper from the auth step, nothing from the create/plan-change work.

  • auth logout emits CLI Auth Logout (flow: logout) before auth.ClearToken(), while the user identifier is still attached to the telemetry metadata — the event is attributed to the user signing out.
  • No event when already signed out (no logout actually happened).
  • No Identify at logout time: Segment's identity graph has no concept of un-identifying — once an anonymousId is aliased to a userId, the mapping persists by design.
  • Subsequent events automatically stop carrying userId: Track/Identify only set the field when the metadata has one, and after ClearToken() the next invocations load no token. Events fall back to anonymousId attribution, like a fresh install.

Test

# full flow: CLI Auth Started → CLI Auth Completed (+ Command Completed)
DEBUG=1 go run ./cmd/algolia auth login

# abort: Esc/Ctrl-C in the application selection prompt
# → CLI Auth Aborted {step: app_select}
DEBUG=1 go run ./cmd/algolia auth login

# signup variant: same events with flow=signup
DEBUG=1 go run ./cmd/algolia auth signup

# signed in: the final batch contains CLI Auth Logout {flow: logout}
DEBUG=1 go run ./cmd/algolia auth logout

# already signed out: no flow event
DEBUG=1 go run ./cmd/algolia auth logout

GROUT-351

GROUT-349

LorrisSaintGenez and others added 5 commits June 10, 2026 11:27
- go telemetryClient.Close() ran in PersistentPreRunE, closing the
  client before the command executed and racing with process exit
- close the client in Execute() via defer, bounded by a 3s timeout so
  an unreachable telemetry endpoint never delays exit
- fall back to NoOpTelemetryClient when the analytics client cannot be
  created instead of storing a nil interface in the context
- enable analytics-go verbose logging in debug mode so successful
  flushes are visible with DEBUG=1

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…umber

- Track now takes a properties map, merged with the base properties;
  base properties are written last so call sites cannot override them
- each Track event carries a monotonic sequence number (atomic counter)
  so the exact order of one invocation can be reconstructed downstream:
  Segment stores timestamps with millisecond precision, so back-to-back
  events can tie

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- events.go: typed catalog for the flow events (event name constants,
  Flow/Step/Direction enums), FlowTracker helper (current step and
  flow duration) and ErrorClass (root cause type only, never the
  message, which could contain user data)
- Execute() reports a Command Completed event with succeeded,
  exit_code, duration_ms, and error_class/user_cancelled on failure,
  through a deferred read of the named return value

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- don't emit an orphan Command Completed when PersistentPreRunE never
  ran (--help, --version, unknown flag/command, failed auth check):
  no Command Invoked was sent, and the command property would be empty
- measure the command duration right after execution, so duration_ms
  never includes the update-notifier wait (which only happens on the
  success path and would bias the metric)
- ErrorClass keeps the first informative type of the error chain
  instead of unwrapping to the root, which collapsed every CLI error
  into *errors.errorString
- tests: trackCommandCompleted (skip/success/failure), sequence
  uniqueness under concurrency, informative wrapper type

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- RunOAuthFlow emits CLI Auth Started at entry, then exactly one
  terminal event: Completed, Aborted (user cancellation) or Failed,
  with the step the user stopped at
- RunOAuth takes an optional nil-safe FlowTracker and records the
  browser_wait and code_exchange steps; automatic re-authentications
  (EnsureAuthenticated, ReauthenticateIfExpired) pass nil so they are
  not counted as auth funnels
- new Event struct, typed constructors and TrackEvent helper: one-line
  call sites, compile-time consistent properties
- identifyAuthenticatedUser uses the context client; IdentifyOnce is
  removed (it only existed because the client used to be closed before
  the command ran)
- telemetrytest.RecordingClient: shared recording fake for flow tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codacy-production

codacy-production Bot commented Jun 10, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 24 complexity · 0 duplication

Metric Results
Complexity 24
Duplication 0

View in Codacy

TIP This summary will be updated as you push new changes.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Base automatically changed from fix/telemetry-client-lifecycle to feat/events-flow June 11, 2026 19:45
@LorrisSaintGenez LorrisSaintGenez merged commit ce4111e into feat/events-flow Jun 11, 2026
@LorrisSaintGenez LorrisSaintGenez deleted the feat/auth-flow-events branch June 11, 2026 19:47
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.

2 participants