Skip to content

feat(telemetry): application create and plan change flow events#240

Merged
LorrisSaintGenez merged 11 commits into
feat/events-flowfrom
feat/create-planchange-flow-events
Jun 11, 2026
Merged

feat(telemetry): application create and plan change flow events#240
LorrisSaintGenez merged 11 commits into
feat/events-flowfrom
feat/create-planchange-flow-events

Conversation

@LorrisSaintGenez

@LorrisSaintGenez LorrisSaintGenez commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

What

Steps 3 of GROUT-349 — instruments the application creation and plan change flows.

  • application create emits CLI Application Create Started at entry, then exactly one terminal event: Completed (region, plan, duration_ms), Aborted (step, reason) or Failed (step, error_class). Steps along the flow: nameauthplantermsregionapi_callapi_keyapply_planprofile_configure. Dry runs are not tracked (not a funnel).
  • application upgrade/downgrade emit the same funnel as CLI Application Plan Change * events, with direction (upgrade|downgrade), from_plan and to_plan.
  • Accepted Terms / Declined Terms events around both terms confirmations, with the target plan.
  • Every Aborted carries a reasondeclined_terms, cancelled (Ctrl-C in a prompt), billing_required, already_on_plan, no_candidates — so a single Amplitude breakdown answers why users stop, without cross-event joins.
  • apputil.CreateAndFetchApplication takes an optional nil-safe FlowTracker (records the region, api_call and api_key steps) and now returns the region actually used (it can differ from the requested one after a cluster-unavailable retry). The login call site passes nil so app creation during auth stays on the auth funnel (app_create step).
  • Independent review fixes (2nd commit): a successful plan change reports Completed even when a post-success step (cost-management courtesy prompt, output printing) fails or is cancelled; from_plan/to_plan/plan share one vocabulary (plan ID, free tier always "free" even though its template id can be "build"); billing walls land in Aborted{reason: billing_required} in both flows and both modes; the outcome switches are extracted and unit-tested with the recording client.

Test

# full create funnel; region/plan visible on Completed
DEBUG=1 go run ./cmd/algolia application create

# decline the terms → Declined Terms + Aborted {step: terms, reason: declined_terms}
DEBUG=1 go run ./cmd/algolia application create

# dry run → no flow events at all
DEBUG=1 go run ./cmd/algolia application create --dry-run

# plan change funnel with direction/from_plan/to_plan;
# on an app already at the top → Aborted {reason: no_candidates}
DEBUG=1 go run ./cmd/algolia application upgrade
DEBUG=1 go run ./cmd/algolia application downgrade

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 58 complexity · 18 duplication

Metric Results
Complexity 58
Duplication 18

View in Codacy

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

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
LorrisSaintGenez and others added 4 commits June 11, 2026 12:46
- runCreateCmd emits CLI Application Create Started, then exactly one
  terminal event: Completed (region, plan, duration_ms), Aborted (step,
  reason) or Failed (step, error_class); dry runs are not tracked
- planchange.Run emits the same funnel as CLI Application Plan Change
  events, with direction, from_plan and to_plan
- Accepted/Declined Terms events around both terms confirmations
- every Aborted carries a reason (declined_terms, cancelled,
  billing_required, already_on_plan, no_candidates) so a single
  breakdown answers why users stop
- apputil.CreateAndFetchApplication takes an optional nil-safe tracker
  (region and api_call steps) and returns the region actually used;
  the login call site passes nil to stay on the auth funnel

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- a successful plan change is reported Completed even when a
  post-success step (cost-management prompt, output printing) fails
  or is cancelled
- from_plan/to_plan/plan properties share one vocabulary: the plan ID,
  with the free tier always reported as "free" (its template id can be
  "build"); the current plan label is resolved against the self-serve
  plan list
- billing walls are Aborted{reason: billing_required} in both flows
  and both modes, instead of being split across Aborted and Failed
- new auth and api_key steps, so pre-flow failures and API key
  generation failures are located correctly
- the outcome switches are extracted (trackCreateOutcome,
  trackPlanChangeOutcome) and unit-tested with the recording client,
  including the post-success cancellation regression

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

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@LorrisSaintGenez LorrisSaintGenez force-pushed the feat/create-planchange-flow-events branch from 9ba4053 to 8d68011 Compare June 11, 2026 19:46
Base automatically changed from feat/auth-flow-events to feat/events-flow June 11, 2026 19:47
@LorrisSaintGenez LorrisSaintGenez merged commit dfa73ea into feat/events-flow Jun 11, 2026
2 checks passed
@LorrisSaintGenez LorrisSaintGenez deleted the feat/create-planchange-flow-events branch June 11, 2026 19:56
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