fix(analytics): address review findings on activation-funnel events
- app_opened now also fires on the consent-grant transition (modal Allow /
Settings toggle), not just cold start with prior consent — the true first
session was emitting nothing and session 2 got mislabeled is_first_open.
trackAppOpened() is guarded once-per-JS-session so revoke->regrant cannot
double-count.
- testConnection() takes a source ('onboarding' | 'edit_test') carried on
connection_attempted/succeeded/failed so the funnel can filter out the
edit screen's repeat-tester noise.
- Aborted runs no longer count: abortedSessions set (in sessions.ts, read by
events.ts which already imports it — no new import cycle), marked after a
successful abort call, cleared on busy, and checked on busy->idle for BOTH
response_received and recordSuccessfulSession().
- Consent revocation now DROPS buffered events instead of flushing them:
PostHog's optOut() only blocks new captures and shutdown() drains the queue
over the network, so ConsentGatedPostHog overrides the public fetch()
transport to answer with a synthetic 200 post-revoke — shutdown clears the
persisted queue and timers with zero bytes leaving the device. Re-grant
calls optIn() to clear the persisted SDK opt-out flag.
- classifyConnectionError extracted to pure analytics-classify.ts with
node --test coverage (same pattern as store-review-policy).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NJKAQ6HAikWGQK7PGZ5Y4E
This commit is contained in:
@@ -4,7 +4,7 @@ import * as Crypto from "expo-crypto"
|
||||
import type { ServerConnection, ConnectionType } from "../lib/types"
|
||||
import { createClient, type Client, type Project } from "../lib/sdk"
|
||||
import { addBreadcrumb } from "../lib/sentry"
|
||||
import { AnalyticsEvent, classifyConnectionError, track } from "../lib/analytics"
|
||||
import { AnalyticsEvent, classifyConnectionError, track, type ConnectionTestSource } from "../lib/analytics"
|
||||
import { buildAuth } from "../lib/auth"
|
||||
|
||||
const CONNECTIONS_KEY = "opencode_connections"
|
||||
@@ -34,7 +34,13 @@ interface ConnectionsState {
|
||||
addConnection: (connection: Omit<ServerConnection, "id">, password?: string) => Promise<void>
|
||||
removeConnection: (id: string) => Promise<void>
|
||||
setActiveConnection: (id: string) => Promise<void>
|
||||
testConnection: (connection: ServerConnection, password?: string) => Promise<{ ok: boolean; error?: string }>
|
||||
// `source` distinguishes the activation funnel (onboarding) from the edit
|
||||
// screen's Test button (edit_test) in analytics.
|
||||
testConnection: (
|
||||
connection: ServerConnection,
|
||||
source: ConnectionTestSource,
|
||||
password?: string,
|
||||
) => Promise<{ ok: boolean; error?: string }>
|
||||
updateConnection: (id: string, updates: Partial<ServerConnection>) => Promise<void>
|
||||
refreshProject: () => Promise<void>
|
||||
// Create a one-off client pointing at a specific directory (for cross-project operations)
|
||||
@@ -243,8 +249,8 @@ export const useConnections = create<ConnectionsState>((set, get) => ({
|
||||
})
|
||||
},
|
||||
|
||||
testConnection: async (connection, password) => {
|
||||
track(AnalyticsEvent.ConnectionAttempted)
|
||||
testConnection: async (connection, source, password) => {
|
||||
track(AnalyticsEvent.ConnectionAttempted, { source })
|
||||
try {
|
||||
const client = createClient({
|
||||
baseUrl: connection.url,
|
||||
@@ -253,11 +259,11 @@ export const useConnections = create<ConnectionsState>((set, get) => ({
|
||||
})
|
||||
|
||||
await client.global.health()
|
||||
track(AnalyticsEvent.ConnectionSucceeded)
|
||||
track(AnalyticsEvent.ConnectionSucceeded, { source })
|
||||
return { ok: true }
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
track(AnalyticsEvent.ConnectionFailed, { error_class: classifyConnectionError(message) })
|
||||
track(AnalyticsEvent.ConnectionFailed, { source, error_class: classifyConnectionError(message) })
|
||||
return { ok: false, error: message }
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user