Skip to content

fix(metrics): chart histogram metrics as bucket percentiles by default - #116674

Merged
trunk-io[bot] merged 3 commits into
masterfrom
posthog/metrics-histogram-p95-builder
Oct 14, 2026
Merged

trunk-io[bot] merged 3 commits into
masterfrom
posthog/metrics-histogram-p95-builder

Conversation

@DanielVisca

Copy link
Copy Markdown
Contributor

Problem

  • Metrics users who chart a histogram, such as request duration, see a line that grows without bound and never matches the latency in traces.
  • Ingest stores the histogram's running sum of observations in the scalar value column. The distribution lives in the bucket columns.
  • The builder plots value by default, and its aggregations (sum, avg, p95 across series) all read value too.
  • The backend already computes bucket percentiles with histogram_quantile, but the builder cannot express it.

Changes

  • Picking a histogram metric now charts histogram p95, read from the bucket distribution.
  • The aggregation menu offers "Histogram p50 / p95 / p99" for histogram metrics only. They map to histogram_quantile with quantile 0.5, 0.95 or 0.99.
  • Grouping a histogram with no aggregation picks histogram p95 instead of sum.
  • A histogram percentile and a range function cannot combine, so the later pick replaces the other.
  • Saved insights, links and the anomaly badge carry the quantile through.

Note

#113473 removed type-based defaults because remote write can mistype counters and gauges. This PR restores a default for histogram only. Ingest writes that type only on rows that carry bucket data.

Left out on purpose:

  • Exponential histograms. Ingest stores each bucket's lower edge, and _histogram_quantile reads every bound as an upper edge, so the percentile would be wrong.
  • Raw-value aggregations stay in the menu for histograms. They are only no longer the default.
  • Old links to a histogram with no aggregation still open as saved.

How did you test this code?

  • Jest: metricsViewerLogic.test.ts and queryLanguages.test.ts. The new assertions failed before the fix (aggregation null instead of histogram_p95, and "The builder cannot edit this query").
  • Not done: no render in the running app or Storybook, so no screenshot of the menu.

Test rationale: The logic tests catch a histogram clause that falls back to the raw sum, and a saved histogram_quantile node that reopens outside the builder. The PromQL round-trip cases catch a lossy conversion. The closest existing tests covered only the cross-series p95.

Release status

  • No feature flag controls this change

Docs update

None.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: PostHog Slack app (Claude Code), claude-opus-5-5

  • Raised from Metrics survey feedback, Slack thread.
  • Skills: /writing-kea-logics, /writing-tests, /writing-code-comments, /writing-user-facing-copy, /writing-pr-descriptions.
  • No duplicate: #101244 attempted the same fix and closed as stale. Master moved since, so this PR reimplements it on current code. Its backend type check is not ported.

Created with PostHog from a Slack thread

🤖 Generated with Claude Code

A histogram's scalar value holds the running sum of observations, so the builder charted an ever-growing total instead of a latency. Add histogram p50/p95/p99 aggregations that map to the API's histogram_quantile, offer them only for histogram metrics, and default a histogram clause without operations to histogram p95. Exponential histograms stay out until the backend reads their lower-edge bucket bounds correctly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 28e82888-d17f-491f-8aa4-4ba0138e92be
@DanielVisca DanielVisca self-assigned this Oct 13, 2026
@trunk-io

trunk-io Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

😎 Merged successfully - details.

@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

✅ Trunk lane — non-backend lane (fe:product:metrics)

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

⚠️ Complexity (TypeScript) — 6 functions above the limit (max 22)

Cyclomatic complexity above the limit in changed typescript files (10 for production files, 15 for test files). Warn only: worth simplifying when you next touch these functions.

Function Location Complexity Limit
convertMetricsQuery products/metrics/frontend/queryLanguages/convert.ts:183 22 10
propertyFilterToMetricFilter products/metrics/frontend/components/metricsViewerLogic.tsx:279 13 10
builderEditorLimits products/metrics/frontend/queryLanguages/convert.ts:31 12 10
stripParens products/metrics/frontend/queryLanguages/convert.ts:108 12 10
<anonymous> products/metrics/frontend/components/metricsViewerLogic.tsx:472 11 10
<anonymous> products/metrics/frontend/components/metricsViewerLogic.tsx:1013 11 10
✅ Duplication (Python) — clean

New Python code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

✅ Duplication (TypeScript) — clean

New TypeScript code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

🚨 Comment density — 7% of added code lines are comments (21 of 305)

This section warns when comments are more than 3% of the code lines a PR adds, and alerts above 6%. Before agent-assisted PRs, the typical share was about 2%. Only full-line comments count. Docstrings, generated files, snapshots, migrations, and workflow files are left out.

Comments that restate the code, record how the change came about, or narrate the next line add noise for the next reader. Keep the comments that explain a reason the code cannot show, and remove the rest. See .agents/skills/writing-code-comments/SKILL.md for the house rules.

Files with the most added comment lines:

File Comment lines Added lines
products/metrics/frontend/components/metricsViewerLogic.tsx 13 114
products/metrics/frontend/components/metricsViewerLogic.test.ts 4 98
products/metrics/frontend/components/MetricsOperations.tsx 3 42
products/metrics/frontend/components/MetricsOperations.test.tsx 1 37

This check does not block merging. It updates on every push and clears when the share drops.

⚠️ Bundle size — 🔺 +2.2 KiB (+0.0%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 75.88 MiB · 🔺 +2.2 KiB (+0.0%)

File Size Δ vs base
render-query/src/render-query/render-query.js 24.41 MiB 🔺 +1.3 KiB (+0.0%)

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

✅ Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1005.7 KiB · 23 files 🟢 -52 B (-0.0%) █████████░ 85.8% of 1.14 MiB
logged-out boot: index + App + bootApp (preloaded by every page, including /login)
src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
2.87 MiB · 606 files 🟢 -52 B (-0.0%) █████████░ 94.5% of 3.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.33 MiB · 2,533 files 🔺 +4 B (+0.0%) ██████████ 95.9% of 7.64 MiB
dashboard scene
src/scenes/dashboard/Dashboard.tsx
9.57 MiB · 3,617 files 🔺 +1.4 KiB (+0.0%) █████████░ 93.0% of 10.30 MiB
today home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
7.35 MiB · 2,543 files 🔺 +4 B (+0.0%) █████████░ 93.2% of 7.89 MiB
events scene
src/scenes/activity/explore/EventsScene.tsx
9.15 MiB · 3,446 files 🔺 +1.4 KiB (+0.0%) █████████░ 92.7% of 9.88 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
11.93 MiB · 4,285 files 🔺 +43 B (+0.0%) ████████░░ 79.3% of 15.05 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/zod/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/billing/billingLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/ProductEmptyState/productSetupPreloadLogic.ts stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/dashboards/frontend/widgets/previews/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 zod/v4/locales/de.js stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/project-homepage/today/TodayReportPage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/activity/explore/EventsScene.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
1.3 KiB src/index.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
839 B src/scenes/ChunkLoadErrorBoundary.tsx
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
Size File
319.8 KiB ../node_modules/.pnpm/posthog-js@1.438.8_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
220.8 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
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
103.2 KiB src/products.tsx
99.6 KiB src/lib/api.ts
69.0 KiB src/lib/lemon-ui/icons/icons.tsx
38.7 KiB ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js
33.9 KiB ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js
28.7 KiB src/scenes/scenes.ts
27.6 KiB src/lib/constants.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
319.8 KiB ../node_modules/.pnpm/posthog-js@1.438.8_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.8 KiB src/taxonomy/core-filter-definitions-by-group.json
220.8 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
153.7 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
113.2 KiB ../packages/quill/packages/quill/dist/index.js
103.2 KiB src/products.tsx
99.6 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
Size File
319.8 KiB ../node_modules/.pnpm/posthog-js@1.438.8_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.8 KiB src/taxonomy/core-filter-definitions-by-group.json
220.8 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
181.9 KiB src/queries/validators.js
153.7 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
113.2 KiB ../packages/quill/packages/quill/dist/index.js
103.2 KiB src/products.tsx
99.6 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
Size File
319.8 KiB ../node_modules/.pnpm/posthog-js@1.438.8_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.8 KiB src/taxonomy/core-filter-definitions-by-group.json
220.8 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
153.7 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
113.2 KiB ../packages/quill/packages/quill/dist/index.js
103.2 KiB src/products.tsx
99.6 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
Largest files eagerly shipped from src/scenes/activity/explore/EventsScene.tsx
Size File
319.8 KiB ../node_modules/.pnpm/posthog-js@1.438.8_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.8 KiB src/taxonomy/core-filter-definitions-by-group.json
220.8 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
181.9 KiB src/queries/validators.js
153.7 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
113.2 KiB ../packages/quill/packages/quill/dist/index.js
103.2 KiB src/products.tsx
99.6 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
Size File
319.8 KiB ../node_modules/.pnpm/posthog-js@1.438.8_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
316.0 KiB ../node_modules/.pnpm/posthog-js@1.438.8_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
280.8 KiB src/taxonomy/core-filter-definitions-by-group.json
220.8 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
181.9 KiB src/queries/validators.js
153.7 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
113.2 KiB ../packages/quill/packages/quill/dist/index.js
103.2 KiB src/products.tsx
99.6 KiB src/lib/api.ts

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479

✅ Toolbar bundle — eager 2.23 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.23 MiB · 19 files 🟢 -52 B (-0.0%) ████░░░░░░ 39.0% of 5.72 MiB
Deferred (lazy) 2.10 MiB · 40 files no change n/a — loads on demand
Loader dist/toolbar.js 1.2 KiB no change █░░░░░░░░░ 6.0% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
874.8 KiB dist/toolbar/toolbar-app-ZPOT7W43.css
664.0 KiB dist/toolbar/chunk-chunk-HI6MPXRL.js
257.8 KiB dist/toolbar/chunk-chunk-IVAG7WAO.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
129.6 KiB dist/toolbar/chunk-chunk-JLOIU7PO.js
74.7 KiB dist/toolbar/toolbar-app-KOHPHDJ6.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-6X4NN5IR.js
21.7 KiB dist/toolbar/chunk-chunk-WHIESAEG.js
6.8 KiB dist/toolbar/chunk-chunk-DV7IWQNF.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

✅ Dist folder size — 🟢 -64.0 KiB (-0.0%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 1009.76 MiB · 🟢 -64.0 KiB (-0.0%)

⚠️ Playwright — 1 flaky

🎭 Playwright report · View test results →

⚠️ 1 flaky test:

  • Logout in another tab results in logout in the current tab too (chromium)

These issues are not necessarily caused by your changes.
Annoyed by this section? Help fix flakies and failures and it will go green!

✅ Hogbox preview — ready, open the preview

▶ Open the preview

🔑 Login test@posthog.com / 12345678 (demo data)
🧩 Running this PR's backend and frontend, on the PostHog :master base
🔗 Link stable across rebuilds: a re-push swaps the box underneath, the URL stays
🔒 Access tailnet only (PostHog VPN)
🛠️ Admin inspect & debug state in hogland
💤 Idle sleeps after ~30 min idle (snapshot to S3, zero node cost) and wakes on your next visit in ~30s, behind a brief "waking up" screen

commit 8157405 · box box-d95ac7d0b1bf · ready in 1247s (push → usable) · build log · rebuilds on every push, torn down on close

@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.

PostHog Review · Standard · reviewed 2478b68: 1 Should fix.

Comment on lines +1068 to +1070
(groupByKeys.length && supportsHistogramQuantile(clause.selectedMetricType)
? DEFAULT_HISTOGRAM_AGGREGATION
: fallbackAggregation(groupByKeys)),

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.

P2 · Respect the active range function when defaulting grouped histograms

Selecting rate or increase on an ungrouped histogram clears its percentile aggregation. Adding a group-by then makes setGroupByKeys restore histogram_p95 while retaining the range function. MetricQueryRunner rejects this combination, so the chart fails instead of showing grouped rates. Use the sum fallback when a range function is active.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 318d7a0. A clause with an active range function now never defaults to a histogram percentile: grouping falls back to sum, and metric selection uses the same check. The grouping test has a new rate row that failed before the fix.

@trunk-io

trunk-io Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
Scenes-Other/Startup program NeedsBillingDetails smoke-test The test timed out while waiting for loading indicators or spinners to disappear. Logs ↗︎
Replay/Scenes/Activity Modal EventExplorerWithModalNotFound smoke-test The test timed out while waiting for loading indicators or spinners to disappear. Logs ↗︎
Scenes-App/Project Homepage ProjectHomepage smoke-test The test timed out while waiting for loading indicators or spinners to disappear. Logs ↗︎
Scenes-App/Notebooks/Nodes/Customer Journey AllStepsCompleted smoke-test The test timed out while waiting for an element with the class '.react-flow__node' to become visible. Logs ↗︎

... and 4 more

View Full Report ↗︎ ⋅ Docs

…s on

The backend rejects histogram_quantile together with rate or increase. Adding a group-by to a histogram clause with a range function restored histogram p95 and the query failed. A clause with a range function now never defaults to a histogram percentile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 28e82888-d17f-491f-8aa4-4ba0138e92be
@DanielVisca
DanielVisca marked this pull request as ready for review October 14, 2026 03:29
@parameterai

parameterai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Risk: No findings

This increment only adjusts the aggregation menu in the Metrics viewer UI so histogram percentile options remain available for clauses whose histogram quantile came from a saved PromQL conversion (no metric type yet), and adds tests. No security-relevant surface is touched: options map to typed constants, reducers keep combinations valid before any request is built, and no auth, tenancy, or injection paths are involved.

Sentinel reviewed 8157405 · Review settings

@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.

PostHog Review · Standard · reviewed 318d7a0: 1 Should fix.

Comment on lines +60 to +62
supportsHistogramQuantile(metricType)
? [...HISTOGRAM_AGGREGATION_OPTIONS, ...AGGREGATION_OPTIONS]
: AGGREGATION_OPTIONS

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.

P2 · Keep percentile choices available for converted histogram clauses

Switching a PromQL histogram percentile to Builder produces a clause without metricType, and applyQuery does not backfill it from the loaded picker. aggregationOptionsFor(null) therefore gives the Histogram p95 chip only scalar alternatives, preventing selection of p50 or p99. Include histogram choices when the current aggregation is a histogram percentile.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 8157405. The aggregation chip now offers the histogram percentiles when the current aggregation is a histogram percentile, so a converted clause without a metric type can switch between p50, p95 and p99. New test MetricsOperations.test.tsx: the case with no metric type failed before the fix.

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Not approved — this change needs a human reviewer.

Re-add the stamphog label to request another review once you have addressed this.

@PostHog's current concern about percentile choices remains unaddressed; the older range-function concern is fixed. Update MetricsOperations.tsx to include histogram choices when the active aggregation is a histogram percentile, add a regression test for converted clauses without metricType, and re-request review.

  • Author wrote 0% of the modified lines and has 18 merged PRs in these paths (familiarity MODERATE).
  • PostHog Review (Standard) reviewed the current head: 1 finding, posted on the PR.
  • posthog[bot] reviewed the current head.
  • @PostHog on products/metrics/frontend/components/MetricsOperations.tsx: Converted histogram-percentile clauses without metricType still receive only scalar aggregation choices. The menu checks selectedMetricType alone, viewerClauseFromNode leaves missing types null, and applyQuery does not backfill from the already-loaded picker; users cannot switch the percentile to p50 or p99.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 192L, 4F substantive, 320L/6F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1d-complex (320L, 6F, single-area, fix)
stamphog 2.5.0 .stamphog/policy.yml @ 318d7a0 · reviewed head 318d7a0

A PromQL histogram percentile switched to the builder has no metric type until the picker loads, so its aggregation chip offered only scalar choices. The chip now also offers p50, p95 and p99 when the current aggregation is a histogram percentile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 28e82888-d17f-491f-8aa4-4ba0138e92be

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approved.

Contained frontend change using existing backend capabilities, with owning-team authorship and current-head review assurance. Both earlier substantive review concerns are addressed in the current code; no remaining showstoppers were identified.

  • Author wrote 0% of the modified lines and has 18 merged PRs in these paths (familiarity MODERATE).
  • PostHog Review (Standard) reviewed the current head: no findings.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 196L, 4F substantive, 369L/7F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1d-complex (369L, 7F, single-area, fix)
stamphog 2.5.0 .stamphog/policy.yml @ 8157405 · reviewed head 8157405

Copy link
Copy Markdown
Contributor Author

/trunk merge

@trunk-io
trunk-io Bot merged commit 80e5f9b into master Oct 14, 2026
235 checks passed
@trunk-io
trunk-io Bot deleted the posthog/metrics-histogram-p95-builder branch October 14, 2026 14:43
@deployment-status-posthog

deployment-status-posthog Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-10-14 15:14 UTC Run
prod-us ✅ Deployed 2026-10-14 15:28 UTC Run
prod-eu ✅ Deployed 2026-10-14 15:31 UTC Run

This branch was successfully deployed

1 active deployment
hogbox-preview — 8157405c Deployed Oct 14, 2026 by github-actions[bot]
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