Skip to content

feat(wizard): name the workspace group, and stamp events on capture - #74

Merged
itelo merged 1 commit into
mainfrom
itelo/wizard-workspace-groups
Sep 3, 2026
Merged

itelo merged 1 commit into
mainfrom
itelo/wizard-workspace-groups

Conversation

@itelo

@itelo itelo commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Two fixes found by reading a real run's events in PostHog, both in analytics.ts.

1. The workspace group had no name

Events already join a workspace group, but nothing ever called groupIdentify, so every workspace showed as a bare UUID in exactly the breakdowns the funnel dashboard is built on:

workspace_id                          runs
1579fa6a-1496-4c15-a952-b77b57633995     7

Now, when a run settles on a workspace:

client.groupIdentify({
  groupType: 'workspace',
  groupKey: workspace.workspace_id,
  distinctId: current.distinct_id,
  properties: { name: workspace.name, is_sandbox: workspace.is_sandbox },
})

Two deliberate choices:

  • Only name and is_sandbox. Group properties are shared with everything else that reports to that workspace (the Console, webviews, server events), so the wizard writes only what it knows first-hand and doesn't stomp on anyone else's fields.
  • distinctId is the install's own id. Without it, PostHog mints a synthetic person for the workspace as a side effect of the identify.

This also settles the "how many times has each workspace run the wizard" question at the group level rather than needing a property breakdown — wizard_connected broken down by workspace now reads as a name.

2. Events could be stamped out of order

The SDK assigns a timestamp inside an async path (prepareEventMessage), so two events captured in the same tick can be stamped out of order — and PostHog orders funnel steps by timestamp. A real run reported:

screen_index screen timestamp
1 init 18:27:17.181
2 method 18:27:17.045

The wizard's own ordering was right (screen_index proves it) and the stamps were inverted. That's enough to make an ordered screens funnel read a step as skipped. track now passes timestamp: new Date(), taken where the event is captured.

Testing

  • $groupidentify payload asserted against what the SDK actually sends ($group_type, $group_key, $group_set, and the install's distinct id) — verified first against a local ingest server rather than guessed.
  • A test pinning that each event's stamp falls inside the window of its capture call, and that capture order is timestamp order. It documents the invariant the funnels depend on; it can't reproduce the race deterministically, which is worth knowing when reading it.
  • One existing test selected events positionally and now picks them by name, since $groupidentify lands between the two it was checking.

npm run typecheck, npm run lint and npm test (199 tests) pass.

Note

Nothing here changes distinct_id, which stays the anonymous install. Making it the workspace was considered and rejected: the pre-connect events — wizard_run_started, the welcome/init screens, wizard_init_finished, wizard_connect_method_selected, wizard_connect_failed — happen before any workspace is known, and those are the drop-off the funnel exists to measure. Switching mid-run would split a single run across two persons and break every person-scoped funnel; alias would fix that but merges irreversibly, so one machine connecting to a sandbox and then a production workspace would permanently merge those two workspaces.

🤖 Generated with Claude Code

Two fixes found while checking a real run's events in PostHog.

Events already join a `workspace` group, but nothing ever identified it, so
every workspace read as a bare UUID in the group breakdowns the funnel
dashboard is built on. Identify it once, when the run settles on a
workspace, with the name and whether it is a sandbox — the only workspace
facts the wizard knows first-hand. Group properties are shared with
everything else that reports to that workspace, so nothing else goes in.
The call is attributed to the install's own distinct id, or PostHog mints a
person for the workspace as a side effect.

The second is an ordering bug. The SDK assigns a timestamp inside an async
path, so two events captured in the same tick can be stamped out of order,
and PostHog orders funnel steps by timestamp. A run yesterday reported its
screens as:

    screen_index 1  init      18:27:17.181
    screen_index 2  method    18:27:17.045

The wizard's own ordering was right and the stamps were inverted, which is
enough to make a screens funnel read a step as skipped. Stamp each event
where it is captured instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@itelo
itelo requested a review from razor-x as a code owner September 3, 2026 18:49
@itelo
itelo merged commit 4fe2ce2 into main Sep 3, 2026
11 checks passed
@itelo
itelo deleted the itelo/wizard-workspace-groups branch September 3, 2026 19:27
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