feat(replay-vision): chart scorer scores as a distribution bar histogram#61039
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
products/replay_vision/frontend/replay_scanners/replayScannerLogic.ts:475-478
The last bucket's label may over-extend past the actual `hi` bound when `bucketWidth > 1`. For example, with `scale = { min: 0, max: 100 }`: `bucketWidth = 5`, `bucketCount = 21`, and the final label is rendered as `"100–104"` even though the scale ends at 100. Capping the upper bound to `min(start + bucketWidth - 1, hi)` keeps every label within the configured range.
```suggestion
const labels = counts.map((_, i) => {
const start = lo + i * bucketWidth
return bucketWidth === 1 ? String(start) : `${start}–${Math.min(start + bucketWidth - 1, hi)}`
})
```
Reviews (1): Last reviewed commit: "feat(replay-vision): chart scorer scores..." | Re-trigger Greptile |
|
Size Change: -15.2 kB (-0.02%) Total Size: 80.9 MB 📦 View Changed
ℹ️ View Unchanged
|
There was a problem hiding this comment.
The bot reviewer raised a valid, unresolved concern: the last histogram bucket label can display a range that exceeds the configured scale maximum (e.g. "100–104" when max is 100). The bucketing math itself is correct, but the label string is inaccurate and the suggested one-line fix (Math.min(start + bucketWidth - 1, hi)) was not applied.
There was a problem hiding this comment.
An unresolved bot reviewer comment explicitly identifies a label bug in the histogram: the last bucket's upper bound label can exceed the configured scale maximum (e.g. "100–104" when max is 100). A one-line fix was suggested (Math.min(start + bucketWidth - 1, hi)) but was not applied.
There was a problem hiding this comment.
A bot reviewer (greptile-apps, current head) identified a real label bug in the histogram selector: the last bucket's upper-bound label can exceed the configured scale maximum (e.g. "100–104" when max is 100) because start + bucketWidth - 1 is not capped at hi. A concrete one-line fix was suggested but was not applied in the current diff.
There was a problem hiding this comment.
The new scorerHistogram selector has a confirmed label bug: when the configured scale is e.g. {min: 0, max: 100}, the last bucket's upper-bound label exceeds the scale maximum (renders "100–104" instead of "100"). The greptile-apps bot raised this as a P2 inline comment on the current head with a concrete one-line fix (Math.min(start + bucketWidth - 1, hi)), and it was not addressed in the current diff.
The scorer "Score distribution" panel rendered a single horizontal box plot. For the small, low-volume samples these scanners produce, a box-and-whisker is hard to read — the IQR box spans almost the whole scale and it implies a continuous distribution from a handful of points, so you can't tell how many sessions landed on each score. Replace it with a bar histogram: count of observations per score bucket across the scanner's configured scale (falling back to the observed range). Buckets are per-integer, widening automatically for large scales so the bar count stays bounded. The min/median/avg/max footer is kept. The bucketing lives in a new `scorerHistogram` selector on replayScannerLogic so the component stays presentational. Generated-By: PostHog Code Task-Id: fb62321a-5c49-4102-b367-6af893652809
eec0b92 to
5dc7896
Compare
There was a problem hiding this comment.
The bot review comments flag a label-capping bug, but they're all from an older commit — the current diff already applies the suggested fix (Math.min(start + bucketWidth - 1, hi)) on the label line. This is a low-risk, purely frontend visualization change swapping BoxPlot for a histogram BarChart within the replay_vision product.

Problem
The scorer Score distribution panel rendered a single horizontal box-and-whisker plot. For the small, low-volume samples these scanners produce (often a handful of observations), a box plot is hard to read: the IQR box spans nearly the whole scale, and it implies a smooth continuous distribution from a few points — so you can't tell how many sessions actually landed on each score. (Reported as confusing during dogfooding.)
Changes
Replace the box plot with a bar histogram — count of observations per score bucket — which is the intuitive "scorer" view ("3 sessions scored 0, 1 scored 10").
start–endlabels).min / median / avg / maxfooter is kept.scorerHistogramselector onreplayScannerLogic, keepingScorerOverviewpresentational (per the kea-logic convention).Note: the separate "Score percentiles over time" line graph (
ScannerInsightsChart) is unchanged — this PR only swaps the distribution panel.How did you test this code?
Visual Test:

I'm an agent (PostHog Code), so automated checks only:
pnpm --filter=@posthog/frontend format— cleanpnpm --filter=@posthog/frontend typescript:check— no errors inreplay_vision(kea types regenerated)🤖 Agent context
Authored with PostHog Code (Claude) during a Replay Vision dogfooding session, after the box plot was flagged as confusing on a 4-observation scorer. Considered
BoxPlot(kept, but it was the problem),BoldNumber, and a distribution bar; the bar histogram was chosen as the clearest for low-volume score data. Uses the existingBarChartfromlib/hog-charts. Requires human review.Created with PostHog Code