Skip to content

fix(desktop): record an onboarding step view once the step is settled - #89594

Draft
adboio wants to merge 2 commits into
masterfrom
fix/desktop-onboarding-step-viewed
Draft

fix(desktop): record an onboarding step view once the step is settled#89594
adboio wants to merge 2 commits into
masterfrom
fix/desktop-onboarding-step-viewed

Conversation

@adboio

@adboio adboio commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Problem

The desktop onboarding funnel reports two steps wrong, so the canvas the team reads gives a false picture of where people drop.

  • project-select records 439 people viewing and 122 advancing over 3 days for non-staff, against roughly 98% on every other step.
  • consent records 110 viewing and 171 advancing, which is more completions than views.
  • The flow shows the project picker before it knows your project count. Everyone records a view on mount, then the step is dropped for anyone holding one project.
  • The self-heal that moves a person off a dropped step emitted nothing, so anyone it moved into consent advanced with no matching view.
  • A retired welcome step id from an older build reaches analytics the same way, which is where the report behind this PR started.

Changes

  • Nothing about the flow looks or behaves differently. The steps, their order, and the copy are unchanged.
  • One effect records the view, once no pending lookup can still drop the step. stepGatePending in packages/core/src/onboarding/steps.ts answers that per step, so a step no lookup can drop is never held.
  • handleNext and handleBack no longer record views. They record the completion and move the step, and the effect follows.
  • handleNext previously recorded the next step's view before next() ran, which named the wrong step whenever the step set shifted in between. That path is gone.
  • A completion can never precede its view. handleNext and handleComplete record the view first, which covers a person who leaves a step before its gate answers, through the button or the right-arrow hotkey.
  • A failed consent or GitHub integrations lookup now answers its gate instead of holding it open. Both still keep the step, as an unanswered lookup did, so a dead query cannot silence that step's view. The integrations query retries three times and then leaves data undefined, which would otherwise hold install-cli pending for the rest of the session.
  • Step entry is tracked on step change, separately from the view, so a delayed view no longer measures duration_seconds from the previous step.
  • A person who rehydrates onto a step retired in an older build lands on the start of the flow instead of an empty card. The invite-code mapping stays ahead of that reset so a person mid-flow still moves forward to consent.
  • The store version goes to 2, because version 1 shipped alongside that mapping in 5d54be6 and a state already saved at version 1 never called migrate.
  • The computeActiveSteps options object becomes a named StepGates type. Mechanical.

Note

Step view counts change the day this ships. project-select views drop by roughly the number of people who hold one project. consent views rise to meet its completions. Treat pre-merge and post-merge funnel numbers as separate series.

How did you test this code?

  • Added stepGatePending cases to packages/core/src/onboarding/steps.test.ts. They catch a step wired to the wrong lookup, or a lookup added to computeActiveSteps and forgotten here, which would record a view for a step that is then dropped.
  • Extended packages/ui/src/features/onboarding/onboardingStore.test.ts with retired-step and current-step cases. They catch a migration that drops the invite-code mapping, and one that resets a valid step.
  • Extended both existing test files rather than adding new ones, since each behavior sits beside coverage that already existed.
  • Ran the @posthog/core and @posthog/ui vitest suites locally.
  • Not covered: the two lookup-error paths, which live in useOnboardingFlow and would need a component render with mocked query sources. Poor trade at that level; worth a reviewer's eye.
  • Not run: the app itself. The corrected counts are a prediction from the code paths, not a measurement.

Automatic notifications

  • Publish to changelog?

Docs update

None.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Written with Claude Code (Opus 5). Skills invoked: /writing-tests, /writing-code-comments, /writing-pr-descriptions.

The work started from a self-driving inbox report about a single retired welcome step id. Investigating why that report cleared the scout's bar surfaced the two funnel numbers above, which share one cause with it.

This replaces #89543, which grew a spinner, a global wait on every lookup, and a timeout to bound that wait. Each of those existed only to contain the previous one, and the spinner made everyone wait on gh auth status, a network call that cannot affect which step comes first. Waiting per step removes all of it. #89463 was closed earlier as superseded; its rehydration guard is carried here.

ReviewHog found both error paths after the first push: the consent gate was fixed and the integrations gate was not, and a pending step could still be completed through the hotkey. Recording the view from the navigation handlers closes that for every step and every path, rather than disabling a button with no feedback.

The funnel numbers in Problem come from queries against project 2 in this session. No customer data, session content, or internal material is quoted anywhere in this PR.

`Onboarding step viewed` fired from a mount effect that ran before the lookups
choosing the step set had answered, so every person recorded a `project-select`
view including those with one project, whose step was then dropped. The
self-heal that moves a person off a dropped step emitted nothing, so anyone it
moved into `consent` advanced with no matching view.

Record the view from one effect, once no pending lookup can still drop the
step. Reset a persisted step id from a retired set at rehydration, which the
old flow could otherwise show as an empty card.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Aug 26, 2026

Copy link
Copy Markdown

Merging to master in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

React Doctor found 6 issues in 1 file · 6 warnings.

6 warnings

packages/ui/src/features/onboarding/components/OnboardingFlow.tsx

Reviewed by React Doctor for commit c4e54e9.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 CI report

Trunk lane — non-backend lane

This PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.

@hosthog

hosthog Bot commented Aug 26, 2026

Copy link
Copy Markdown

HostHog preview — posthog-desktop-web

Latest build (c4e54e9): https://c3012a0b705b48f7995eec7ff521bac1.hosthog.dev

Earlier builds of this PR, still serving:

Employee-gated; every push gets a fresh URL whose content never changes. All previews stop serving when the PR closes.

@posthog

posthog Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

🦔 ReviewHog reviewed this pull request

Found 0 must fix, 2 should fix, 0 consider.

Published 2 findings (view the review).

@posthog

posthog Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

ReviewHog Alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReviewHog Report

Found 2 should fix.

Two paths could still emit `Onboarding step completed` for a step that
recorded no view. A failed GitHub integrations lookup left its gate unanswered
for the session, holding `install-cli` pending while the step rendered and its
Continue button worked. A person could also leave any pending step before its
gate answered, through the button or the right-arrow hotkey.

Read the query's pending state rather than its data, so a failed lookup answers
the gate and keeps the step. Record the view from `handleNext` and
`handleComplete` as well as the effect, so a completion never precedes one.
Track step entry separately from the view, so a delayed view no longer measures
`duration_seconds` from the previous step.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Aug 26, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature/desktop Feature Tag: Desktop

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant