Skip to content

[HDX-5077] Fix multi-series metric charts mixing float and int aggregations - #2916

Open
wrn14897 wants to merge 1 commit into
mainfrom
warren/fix-multi-series-chart-type-issue
Open

[HDX-5077] Fix multi-series metric charts mixing float and int aggregations#2916
wrn14897 wants to merge 1 commit into
mainfrom
warren/fix-multi-series-chart-type-issue

Conversation

@wrn14897

@wrn14897 wrn14897 commented Aug 14, 2026

Copy link
Copy Markdown
Member

Why

Fixes a regression introduced by HDX-5077 (#2859). Any multi-series metric tile mixing float- and integer-producing aggregations — e.g. histogram quantile (Float64) + histogram count (Int64) — fails to render with:

No value columns found in result column metadata. Make sure a numeric column exists in the result set.
Result column metadata: [{"name":"Op p95 (ms)","type":"Variant(Float64, Int64)"}, ...]

Root cause

The composed UNION ALL + pivot query funnels every series through the shared __hdx_value column without normalizing its type. Int64/UInt64 have no least supertype with Float64, so a mixed-type UNION either:

  • fails with NO_COMMON_TYPE (error 386) when use_variant_as_common_type = 0, or
  • silently unifies as Variant(Float64, Int64) (the modern ClickHouse default), which the anyOrNullIf pivot propagates to every output column. convertCHDataTypeToJSType had no Variant(...) case, so inferValueColumns found no numeric columns in both the app and CLI.

The HDX-5076 regression baseline only covered same-typed series (all branches Float64), so this combination slipped through.

What

Primary fix (renderMultiSeriesMetricChartConfig): every branch wrapper normalizes the value column to Float64 —

  • scalar branches: SELECT * REPLACE (toFloat64(`__hdx_value`) AS `__hdx_value`), … (preserves group-column names/positions)
  • histogram branches: toFloat64(`__hdx_value`) AS `__hdx_value`

The merged type is now deterministically Float64/Nullable(Float64) regardless of server settings, matching the JS-number semantics of the old node-side merge.

Defensive layer (convertCHDataTypeToJSType): all-numeric Variant(...) columns are now classified as numeric, so raw-SQL charts hitting the same server behavior still render. Mixed variants stay unclassified.

Tests

  • Two new integration tests in the multi-series regression baseline: histogram quantile + histogram count (the exact production repro) and gauge avg + histogram count (covers the scalar * REPLACE wrapper path). Meta assertions pin the type to Float64/Nullable(Float64) directly — deliberately not just via convertCHDataTypeToJSType, since the Variant fallback would otherwise mask a normalization regression on servers running use_variant_as_common_type = 0. Both fail without the fix and pass with it.
  • Unit tests for numeric / mixed / empty Variant(...) classification.
  • 3 SQL snapshots regenerated; snapshot-adjacent assertions updated.
  • make ci-lint, make ci-unit, and the full queryChartConfig int suite (30 tests) all green.

The HDX-5077 UNION ALL + pivot merge composed per-series value columns
without normalizing their types. Series with no least supertype — e.g.
histogram quantile (Float64) + histogram count (Int64) — either failed
with NO_COMMON_TYPE (use_variant_as_common_type = 0) or produced
Variant(Float64, Int64) output columns (the modern default), which no
consumer classifies as numeric, surfacing as "No value columns found in
result column metadata" in the app and CLI.

Normalize every branch's __hdx_value to Float64 in the UNION wrappers so
the merged type is deterministic regardless of server settings, matching
the JS-number semantics of the old node-side merge. As a defensive
second layer, convertCHDataTypeToJSType now classifies all-numeric
Variant(...) columns as numeric (also helps raw-SQL charts).
@vercel

vercel Bot commented Aug 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview Aug 14, 2026 11:09pm
hyperdx-storybook Ready Ready Preview Aug 14, 2026 11:09pm

Request Review

@changeset-bot

changeset-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: af180d7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@hyperdx/common-utils Patch
@hyperdx/app Patch
@hyperdx/api Patch
@hyperdx/otel-collector Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added the review/tier-2 Low risk — AI review + quick human skim label Aug 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔵 Tier 2 — Low Risk

Small, isolated change with no API route or data model modifications.

Why this tier:

  • Standard feature/fix — introduces new logic or modifies core functionality

Additional context: touches the query rendering engine lightly (32 lines, under the 150-line bar for Tier 4)

Review process: AI review + quick human skim (target: 5–15 min). Reviewer validates AI assessment and checks for domain-specific concerns.
SLA: Resolve within 4 business hours.

Stats
  • Production files changed: 2
  • Production lines changed: 32 (+ 161 in test files, excluded from tier calculation)
  • Branch: warren/fix-multi-series-chart-type-issue
  • Author: wrn14897

To override this classification, remove the review/tier-2 label and apply a different review/tier-* label. Manual overrides are preserved on subsequent pushes.

@greptile-apps

greptile-apps Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes mixed integer/float multi-series metric queries by normalizing each UNION branch to Float64 and adds defensive handling for numeric ClickHouse Variant metadata.

  • Normalizes scalar and histogram metric branch values before UNION and pivoting.
  • Adds integration coverage for histogram quantile/count and gauge/count combinations.
  • Adds recursive Variant classification, though valid Decimal members remain unsupported.

Confidence Score: 4/5

The primary multi-series normalization appears sound, but the advertised raw-SQL fallback should recognize Decimal-containing numeric Variants before merging.

Mixed metric branches are normalized and exercised end to end, while the new Variant fallback still rejects valid all-numeric metadata whenever one member belongs to ClickHouse’s Decimal family.

Files Needing Attention: packages/common-utils/src/clickhouse/index.ts, packages/common-utils/src/clickhouse/tests/index.test.ts

Important Files Changed

Filename Overview
packages/common-utils/src/core/renderChartConfig.ts Normalizes scalar and histogram branch values to Float64 while preserving the positional schema required by the UNION and pivot.
packages/common-utils/src/clickhouse/index.ts Adds numeric Variant handling, but valid Decimal members cause an otherwise all-numeric Variant to remain unclassified.
packages/common-utils/src/tests/queryChartConfig.int.test.ts Adds end-to-end coverage for mixed native numeric types across histogram-only and scalar-plus-histogram branch combinations.
packages/common-utils/src/clickhouse/tests/index.test.ts Covers integer/float, mixed, and empty Variants but omits Decimal-containing numeric Variants.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Metric series branches] --> B[toFloat64 normalization]
  B --> C[UNION ALL]
  C --> D[anyOrNullIf pivot]
  D --> E[Float64 chart value columns]
  F[Raw SQL Variant metadata] --> G[Recursive member classification]
  G -->|Int UInt Float| H[Numeric value column]
  G -->|Decimal member| I[Column remains unclassified]
Loading

Fix all with Greploop

Fix All in Claude Code Fix All in Conductor Fix All in Cursor Fix All in Codex

Reviews (1): Last reviewed commit: "fix: multi-series metric charts mixing f..." | Re-trigger Greptile

Comment on lines +107 to +110
memberType =>
convertCHDataTypeToJSType(memberType) === JSDataType.Number,
)
) {

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.

P1 Decimal Variants Remain Unclassified

If a raw-SQL result has an all-numeric type such as Variant(Float64, Decimal(10, 2)), the recursive check returns null for the Decimal member and rejects the entire Variant, causing value-column inference to omit the column and the chart to report that no numeric value column exists.

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

@github-actions

Copy link
Copy Markdown
Contributor

E2E Test Results

All tests passed • 296 passed • 1 skipped • 1026s

Status Count
✅ Passed 296
❌ Failed 0
⚠️ Flaky 0
⏭️ Skipped 1

Tests ran across 4 shards in parallel.

View full report →

@github-actions

Copy link
Copy Markdown
Contributor

Deep Review

Targeted, well-scoped bug fix for multi-series metric tiles that mix float- and integer-producing aggregations. The core change (normalizing every UNION branch's value column to Float64 via toFloat64, plus classifying all-numeric Variant(...) as numeric) was traced and confirmed correct by multiple reviewers: * REPLACE preserves positional/name alignment in the UNION, toFloat64 propagates nullability, and the Variant(...) parsing (slice(8,-1), splitAndTrimWithBracket, empty-Variant() guard) handles its edge cases and is unit-tested.

✅ No critical issues found.

🟡 P2 — recommended

  • packages/common-utils/src/__tests__/queryChartConfig.int.test.ts:1727 — Both new integration tests run against the CI ClickHouse default (use_variant_as_common_type = 1), so they cover only the Variant(...) unification path; the NO_COMMON_TYPE failure mode on legacy servers (= 0) that the fix also claims to prevent is described in the test comment but never exercised.
    • Fix: Add a variant of the two regression tests that passes querySettings: [{ setting: 'use_variant_as_common_type', value: '0' }] and asserts the merged column type resolves to Float64 rather than erroring.
    • testing
🔵 P3 nitpicks (1)
  • packages/common-utils/src/clickhouse/index.ts:97 — The new all-numeric Variant(...) branch broadens convertCHDataTypeToJSType, a classifier shared by table sorting, row rendering, field suggestions, and MCP tooling, none of which are exercised for a genuine (non-UNION) numeric Variant column; no concrete failure was identified, so this is a follow-up-check note only.
    • Fix: Add a note or a single downstream test confirming a real numeric Variant column sorts and renders sensibly through one non-metrics consumer.

Reviewers (8): correctness, testing, maintainability, project-standards, performance, kieran-typescript, agent-native, learnings-researcher.

Testing gaps:

  • No integration test exercises a Nullable-valued source, so the Nullable(Float64) arm of the expectFloat64ValueColumns assertion is never actually hit.
  • No test combines 3+ mixed-type series (scalar + histogram-quantile + histogram-count) to confirm branch ordering and group-column padding hold with all shapes present.
  • The toFloat64 precision boundary at 2^53 for large Int64/UInt64 counters is undocumented (not a regression — the prior node-side merge already used JS doubles).

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

Labels

review/tier-2 Low risk — AI review + quick human skim

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant