feat(telemetry): application create and plan change flow events#240
Merged
LorrisSaintGenez merged 11 commits intoJun 11, 2026
Merged
Conversation
- 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>
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 58 |
| Duplication | 18 |
TIP This summary will be updated as you push new changes.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- 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>
9ba4053 to
8d68011
Compare
8bittitan
approved these changes
Jun 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Steps 3 of GROUT-349 — instruments the application creation and plan change flows.
application createemitsCLI Application Create Startedat entry, then exactly one terminal event:Completed(region,plan,duration_ms),Aborted(step,reason) orFailed(step,error_class). Steps along the flow:name→auth→plan→terms→region→api_call→api_key→apply_plan→profile_configure. Dry runs are not tracked (not a funnel).application upgrade/downgradeemit the same funnel asCLI Application Plan Change *events, withdirection(upgrade|downgrade),from_planandto_plan.Accepted Terms/Declined Termsevents around both terms confirmations, with the targetplan.Abortedcarries areason—declined_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.CreateAndFetchApplicationtakes an optional nil-safeFlowTracker(records theregion,api_callandapi_keysteps) 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_createstep).Completedeven when a post-success step (cost-management courtesy prompt, output printing) fails or is cancelled;from_plan/to_plan/planshare one vocabulary (plan ID, free tier always"free"even though its template id can be"build"); billing walls land inAborted{reason: billing_required}in both flows and both modes; the outcome switches are extracted and unit-tested with the recording client.Test
GROUT-349