fix(funnels): correct breakdown bar widths in top-to-bottom layout - #71816
Conversation
The top-to-bottom (horizontal bar) funnel recomputed breakdown segment widths from the neighboring step's count, ignoring optional steps. With "relative to previous step" set, the precomputed conversion rates treat the last non-optional step as previous, so an optional step that out-counts its immediate predecessor rendered a bar clamped to full width while the footer showed the correct (much smaller) percentage. Size breakdown stacks from the step's precomputed aggregate rate instead, so the bar always matches the footer. Generated-By: PostHog Code Task-Id: f8598b0d-a131-4a04-815b-d57d0f976912
🤖 CI report
|
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.22 MiB · 22 files | no change | ███░░░░░░░ 28.4% of 4.29 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
8.14 MiB · 2,987 files | 🔺 +62 B (+0.0%) | █████████░ 88.0% of 9.25 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
Largest files eagerly shipped from src/index.tsx
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 789 B | src/scenes/ChunkLoadErrorBoundary.tsx |
| 762 B | src/index.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 281.3 KiB | ../node_modules/.pnpm/posthog-js@1.404.0/node_modules/posthog-js/dist/rrweb.js |
| 267.7 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 235.5 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 223.2 KiB | ../node_modules/.pnpm/posthog-js@1.404.0/node_modules/posthog-js/dist/module.js |
| 164.0 KiB | src/queries/validators.js |
| 154.3 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 105.8 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 92.7 KiB | ../packages/quill/packages/quill/dist/index.js |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
✅ Dist folder size — 🔺 +5.2 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1327.31 MiB · 🔺 +5.2 KiB (+0.0%)
Generated-By: PostHog Code Task-Id: f8598b0d-a131-4a04-815b-d57d0f976912
🦔 Hogbox preview · ✅ ready▶ Open the preview
commit |
|
Reviews (1): Last reviewed commit: "chore(funnels): tighten comments in hori..." | Re-trigger Greptile |
sampennington
left a comment
There was a problem hiding this comment.
🤖 sp-ship · 💬 Suggestions only
Nothing blocks merge: the fix is arithmetically sound (distributing the precomputed rate by count share exactly reconstructs the footer percentage), the stepReference removal is complete, and the regression test verifiably fails against the old neighboring-step basis. Two small cleanups are suggested inline — reusing the existing funnelConversionRate guard and renaming a now-stale describe block.
There was a problem hiding this comment.
Contained frontend fix to funnel breakdown bar-width math with a solid regression test; author owns this area with strong familiarity, and the bot review's two suggestions are explicitly non-blocking follow-ups.
- Author wrote 90% of the modified lines and has 12 merged PRs in these paths (familiarity STRONG).
- 👍 on the PR from greptile-apps[bot], hex-security-app[bot].
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 17L, 2F substantive, 79L/3F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1b-small (79L, 3F, single-area, fix) |
| stamphog 2.0.0b3 | .stamphog/policy.yml @ a2e125e · reviewed head 338d54c |
Problem
In a funnel with optional steps and "conversion rate relative to previous step", the top-to-bottom (horizontal bars) layout rendered breakdown bar widths that contradicted the percentages printed under each step: a step with a ~5% conversion could render a full-width bar. The left-to-right layout of the same insight rendered correctly.
Why: the breakdown path in the top-to-bottom chart recomputed each segment's basis from the immediately preceding step's count. The precomputed conversion rates treat the last non-optional step as "previous", so an optional step that out-counts its immediate (optional) predecessor produced fractions above 100%, clamped to a full bar.
Changes
buildBreakdownSegmentsnow distributes the step's precomputed aggregate rate (conversionRates.fromBasisStep) across breakdown variants by count, so the stacked bar total always equals the rate shown in the step footer — for any step reference, with or without optional steps.stepReferencebuild option (the precomputed rate already encodes it).How did you test this code?
fromBasisStep.stepReferenceoption.funnelBarHorizontalTransformsJest suite (32 passed) and the frontend TypeScript check (remaining errors are pre-existing and unrelated).Automatic notifications
Docs update
Not needed — rendering bug fix, no behavior/API/config change.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Diagnosed from two screenshots of the same funnel in both layouts: bar widths in the top-to-bottom view matched count-over-immediately-preceding-step while the footers matched count-over-last-non-optional-step, which pointed at
buildBreakdownSegmentsrecomputing the basis viagetReferenceStepinstead of using the precomputedconversionRates. Considered threading the optional-steps list into the transform, but deriving segment widths from the already-correctfromBasisStepis simpler and keeps the bar consistent with the footer by construction. Skills invoked: /writing-tests.Created with PostHog Code